diff --git a/.golangci.yml b/.golangci.yml index 819dead018..32d133aa09 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -11,6 +11,7 @@ linters: - dupl - errcheck - forbidigo + - forcetypeassert - gocheckcompilerdirectives - gocritic - govet diff --git a/cmd/admin_auth_ldap.go b/cmd/admin_auth_ldap.go index d3266fa48d..960535365b 100644 --- a/cmd/admin_auth_ldap.go +++ b/cmd/admin_auth_ldap.go @@ -354,13 +354,10 @@ func findLdapSecurityProtocolByName(name string) (ldap.SecurityProtocol, bool) { return 0, false } -// getAuthSource gets the login source by its id defined in the command line flags. -// It returns an error if the id is not set, does not match any source or if the source is not of expected type. -func (a *authService) getAuthSource(ctx context.Context, c *cli.Command, authType auth.Type) (*auth.Source, error) { - if err := argsSet(c, "id"); err != nil { - return nil, err - } - authSource, err := a.getAuthSourceByID(ctx, c.Int64("id")) +// getAuthSourceOfType gets the login source by id. +// It returns an error if the id does not match any source or if the source is not of the expected type. +func (a *authService) getAuthSourceOfType(ctx context.Context, id int64, authType auth.Type) (*auth.Source, error) { + authSource, err := a.getAuthSourceByID(ctx, id) if err != nil { return nil, err } @@ -372,6 +369,15 @@ func (a *authService) getAuthSource(ctx context.Context, c *cli.Command, authTyp return authSource, nil } +// getAuthSource gets the login source by its id defined in the command line flags. +// It returns an error if the id is not set, does not match any source or if the source is not of expected type. +func (a *authService) getAuthSource(ctx context.Context, c *cli.Command, authType auth.Type) (*auth.Source, error) { + if err := argsSet(c, "id"); err != nil { + return nil, err + } + return a.getAuthSourceOfType(ctx, c.Int64("id"), authType) +} + // addLdapBindDn adds a new LDAP via Bind DN authentication source. func (a *authService) addLdapBindDn(ctx context.Context, c *cli.Command) error { if err := argsSet(c, "name", "security-protocol", "host", "port", "user-search-base", "user-filter", "email-attribute"); err != nil { @@ -381,16 +387,17 @@ func (a *authService) addLdapBindDn(ctx context.Context, c *cli.Command) error { return err } + ldapConfig := &ldap.Source{ + Enabled: true, // always true + } authSource := &auth.Source{ Type: auth.LDAP, IsActive: true, // active by default - Cfg: &ldap.Source{ - Enabled: true, // always true - }, + Cfg: ldapConfig, } parseAuthSourceLdap(c, authSource) - if err := parseLdapConfig(c, authSource.Cfg.(*ldap.Source)); err != nil { + if err := parseLdapConfig(c, ldapConfig); err != nil { return err } @@ -407,9 +414,10 @@ func (a *authService) updateLdapBindDn(ctx context.Context, c *cli.Command) erro if err != nil { return err } + ldapConfig := auth.MustSourceCfg[*ldap.Source](authSource) parseAuthSourceLdap(c, authSource) - if err := parseLdapConfig(c, authSource.Cfg.(*ldap.Source)); err != nil { + if err := parseLdapConfig(c, ldapConfig); err != nil { return err } @@ -426,16 +434,17 @@ func (a *authService) addLdapSimpleAuth(ctx context.Context, c *cli.Command) err return err } + ldapConfig := &ldap.Source{ + Enabled: true, // always true + } authSource := &auth.Source{ Type: auth.DLDAP, IsActive: true, // active by default - Cfg: &ldap.Source{ - Enabled: true, // always true - }, + Cfg: ldapConfig, } parseAuthSourceLdap(c, authSource) - if err := parseLdapConfig(c, authSource.Cfg.(*ldap.Source)); err != nil { + if err := parseLdapConfig(c, ldapConfig); err != nil { return err } @@ -452,9 +461,10 @@ func (a *authService) updateLdapSimpleAuth(ctx context.Context, c *cli.Command) if err != nil { return err } + ldapConfig := auth.MustSourceCfg[*ldap.Source](authSource) parseAuthSourceLdap(c, authSource) - if err := parseLdapConfig(c, authSource.Cfg.(*ldap.Source)); err != nil { + if err := parseLdapConfig(c, ldapConfig); err != nil { return err } diff --git a/cmd/admin_auth_oauth.go b/cmd/admin_auth_oauth.go index c4a86191a1..f44327d262 100644 --- a/cmd/admin_auth_oauth.go +++ b/cmd/admin_auth_oauth.go @@ -221,12 +221,11 @@ func (a *authService) runUpdateOauth(ctx context.Context, c *cli.Command) error return err } - source, err := a.getAuthSourceByID(ctx, c.Int64("id")) + source, err := a.getAuthSourceOfType(ctx, c.Int64("id"), auth_model.OAuth2) if err != nil { return err } - - oAuth2Config := source.Cfg.(*oauth2.Source) + oAuth2Config := auth_model.MustSourceCfg[*oauth2.Source](source) if c.IsSet("name") { source.Name = c.String("name") diff --git a/cmd/admin_auth_smtp.go b/cmd/admin_auth_smtp.go index b7c1a8807e..5d99b5e1c5 100644 --- a/cmd/admin_auth_smtp.go +++ b/cmd/admin_auth_smtp.go @@ -175,12 +175,11 @@ func (a *authService) runUpdateSMTP(ctx context.Context, c *cli.Command) error { return err } - source, err := a.getAuthSourceByID(ctx, c.Int64("id")) + source, err := a.getAuthSourceOfType(ctx, c.Int64("id"), auth_model.SMTP) if err != nil { return err } - - smtpConfig := source.Cfg.(*smtp.Source) + smtpConfig := auth_model.MustSourceCfg[*smtp.Source](source) if err := parseSMTPConfig(c, smtpConfig); err != nil { return err diff --git a/modelmigration/v1_14/v156.go b/modelmigration/v1_14/v156.go index 4f66bbf118..ac2828c0cf 100644 --- a/modelmigration/v1_14/v156.go +++ b/modelmigration/v1_14/v156.go @@ -5,6 +5,7 @@ package v1_14 import ( "context" + "errors" "fmt" "strings" @@ -106,8 +107,8 @@ func FixPublisherIDforTagReleases(ctx context.Context, x base.EngineMigration) e commit, err := gitRepo.GetTagCommit(ctx, release.TagName) if err != nil { - if git.IsErrNotExist(err) { - log.Warn("Unable to find commit %s for Tag: %s in [%d]%s/%s. Cannot update publisher ID.", err.(git.ErrNotExist).ID, release.TagName, repo.ID, repo.OwnerName, repo.Name) + if errNotExist, ok := errors.AsType[git.ErrNotExist](err); ok { + log.Warn("Unable to find commit %s for Tag: %s in [%d]%s/%s. Cannot update publisher ID.", errNotExist.ID, release.TagName, repo.ID, repo.OwnerName, repo.Name) continue } log.Error("Error whilst getting commit for Tag: %s in [%d]%s/%s. Error: %v", release.TagName, repo.ID, repo.OwnerName, repo.Name, err) @@ -118,8 +119,8 @@ func FixPublisherIDforTagReleases(ctx context.Context, x base.EngineMigration) e log.Warn("Tag: %s in Repo[%d]%s/%s does not have a tagger.", release.TagName, repo.ID, repo.OwnerName, repo.Name) commit, err = gitRepo.GetCommit(ctx, commit.ID.String()) if err != nil { - if git.IsErrNotExist(err) { - log.Warn("Unable to find commit %s for Tag: %s in [%d]%s/%s. Cannot update publisher ID.", err.(git.ErrNotExist).ID, release.TagName, repo.ID, repo.OwnerName, repo.Name) + if errNotExist, ok := errors.AsType[git.ErrNotExist](err); ok { + log.Warn("Unable to find commit %s for Tag: %s in [%d]%s/%s. Cannot update publisher ID.", errNotExist.ID, release.TagName, repo.ID, repo.OwnerName, repo.Name) continue } log.Error("Error whilst getting commit for Tag: %s in [%d]%s/%s. Error: %v", release.TagName, repo.ID, repo.OwnerName, repo.Name, err) diff --git a/modelmigration/v1_8/v76.go b/modelmigration/v1_8/v76.go index d666dcef49..d90a850763 100644 --- a/modelmigration/v1_8/v76.go +++ b/modelmigration/v1_8/v76.go @@ -51,16 +51,16 @@ func AddPullRequestRebaseWithMerge(_ context.Context, x base.EngineMigration) er // Allow the new merge style if all other merge styles are allowed allowMergeRebase := true - if allowMerge, ok := unit.Config["AllowMerge"]; ok { - allowMergeRebase = allowMergeRebase && allowMerge.(bool) + if allowMerge, ok := unit.Config["AllowMerge"].(bool); ok { + allowMergeRebase = allowMergeRebase && allowMerge } - if allowRebase, ok := unit.Config["AllowRebase"]; ok { - allowMergeRebase = allowMergeRebase && allowRebase.(bool) + if allowRebase, ok := unit.Config["AllowRebase"].(bool); ok { + allowMergeRebase = allowMergeRebase && allowRebase } - if allowSquash, ok := unit.Config["AllowSquash"]; ok { - allowMergeRebase = allowMergeRebase && allowSquash.(bool) + if allowSquash, ok := unit.Config["AllowSquash"].(bool); ok { + allowMergeRebase = allowMergeRebase && allowSquash } if _, ok := unit.Config["AllowRebaseMerge"]; !ok { diff --git a/models/asymkey/ssh_key_authorized_keys.go b/models/asymkey/ssh_key_authorized_keys.go index 8eb5d24c82..1a45f5c439 100644 --- a/models/asymkey/ssh_key_authorized_keys.go +++ b/models/asymkey/ssh_key_authorized_keys.go @@ -20,6 +20,7 @@ import ( "gitea.dev/modules/util" "golang.org/x/crypto/ssh" + "xorm.io/builder" ) // AuthorizedStringCommentPrefix is a magic tag @@ -162,8 +163,8 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error { // RegeneratePublicKeys regenerates the authorized_keys file func RegeneratePublicKeys(ctx context.Context, t io.Writer) error { - if err := db.GetEngine(ctx).Where("type != ?", KeyTypePrincipal).Iterate(new(PublicKey), func(idx int, bean any) (err error) { - return WriteAuthorizedStringForValidKey(bean.(*PublicKey), t) + if err := db.Iterate(ctx, builder.Neq{"type": KeyTypePrincipal}, func(ctx context.Context, key *PublicKey) error { + return WriteAuthorizedStringForValidKey(key, t) }); err != nil { return err } diff --git a/models/auth/source.go b/models/auth/source.go index 278898e49d..9bd6ce71f3 100644 --- a/models/auth/source.go +++ b/models/auth/source.go @@ -98,20 +98,12 @@ type RegisterableSource interface { var registeredConfigs = map[Type]func() Config{} -// RegisterTypeConfig register a config for a provided type -func RegisterTypeConfig(typ Type, exemplar Config) { - if reflect.TypeOf(exemplar).Kind() == reflect.Pointer { - // Pointer: - registeredConfigs[typ] = func() Config { - return reflect.New(reflect.ValueOf(exemplar).Elem().Type()).Interface().(Config) - } - return - } - - // Not a Pointer - registeredConfigs[typ] = func() Config { - return reflect.New(reflect.TypeOf(exemplar)).Elem().Interface().(Config) - } +// RegisterTypeConfig register a config for a provided type, the exemplar argument only serves type inference +func RegisterTypeConfig[T interface { + *E + Config +}, E any](typ Type, _ T) { + registeredConfigs[typ] = func() Config { return T(new(E)) } } // Source represents an external way for authorizing users. @@ -188,6 +180,16 @@ func (source *Source) IsSSPI() bool { return source.Type == SSPI } +// MustSourceCfg returns the source's config as T. The registry populates Cfg from the +// source type, so a mismatch is a programming error the caller can't recover from. +func MustSourceCfg[T Config](source *Source) T { + cfg, ok := source.Cfg.(T) + if !ok { + panic(fmt.Errorf("auth source %q (id=%d, type=%s) has config %T, expected %s", source.Name, source.ID, source.Type, source.Cfg, reflect.TypeFor[T]())) + } + return cfg +} + // HasTLS returns true of this source supports TLS. func (source *Source) HasTLS() bool { hasTLSer, ok := source.Cfg.(HasTLSer) @@ -371,12 +373,6 @@ type ErrSourceAlreadyExist struct { Name string } -// IsErrSourceAlreadyExist checks if an error is a ErrSourceAlreadyExist. -func IsErrSourceAlreadyExist(err error) bool { - _, ok := err.(ErrSourceAlreadyExist) - return ok -} - func (err ErrSourceAlreadyExist) Error() string { return fmt.Sprintf("login source already exists [name: %s]", err.Name) } diff --git a/models/db/context_test.go b/models/db/context_test.go index 7804a15d1a..c409f5bbda 100644 --- a/models/db/context_test.go +++ b/models/db/context_test.go @@ -11,6 +11,7 @@ import ( "gitea.dev/models/unittest" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestInTransaction(t *testing.T) { @@ -107,7 +108,8 @@ func TestContextSafety(t *testing.T) { _ = db.GetEngine(ctx).Iterate(&TestModel1{}, func(i int, bean any) error { // here: db.GetEngine(ctx) is always the unclosed "Iterate" *Session with autoResetStatement=false, // and the internal states (including "cond" and others) are always there and not be reset in this callback. - m1 := bean.(*TestModel1) + m1, ok := bean.(*TestModel1) + require.True(t, ok) assert.EqualValues(t, i+1, m1.ID) // here: XORM bug, it fails because the SQL becomes "WHERE id=-1", "WHERE id=-1 AND id=-2", "WHERE id=-1 AND id=-2 AND id=-3" ... diff --git a/models/db/error.go b/models/db/error.go index e44886dcd7..b030c5ba78 100644 --- a/models/db/error.go +++ b/models/db/error.go @@ -14,12 +14,6 @@ type ErrCancelled struct { Message string } -// IsErrCancelled checks if an error is a ErrCancelled. -func IsErrCancelled(err error) bool { - _, ok := err.(ErrCancelled) - return ok -} - func (err ErrCancelled) Error() string { return "Cancelled: " + err.Message } diff --git a/models/packages/descriptor.go b/models/packages/descriptor.go index b5b8634846..e3aef90a8b 100644 --- a/models/packages/descriptor.go +++ b/models/packages/descriptor.go @@ -239,6 +239,15 @@ func GetPackageDescriptorWithCache(ctx context.Context, pv *PackageVersion, c *c }, nil } +// DescriptorMetadata returns the descriptor's metadata, which getPackageDescriptor has created from the package type +func DescriptorMetadata[T interface{ *E }, E any](pd *PackageDescriptor) T { + metadata, ok := pd.Metadata.(T) + if !ok { + panic(fmt.Errorf("package %s of type %s has metadata type %T instead of %T", pd.Package.Name, pd.Package.Type, pd.Metadata, metadata)) + } + return metadata +} + // GetPackageFileDescriptor gets a package file descriptor for a package file func GetPackageFileDescriptor(ctx context.Context, pf *PackageFile) (*PackageFileDescriptor, error) { return getPackageFileDescriptor(ctx, pf, cache.NewEphemeralCache()) diff --git a/models/repo/repo_unit.go b/models/repo/repo_unit.go index 5de5b6e4f3..dd4328648b 100644 --- a/models/repo/repo_unit.go +++ b/models/repo/repo_unit.go @@ -5,6 +5,7 @@ package repo import ( "context" + "fmt" "gitea.dev/models/db" "gitea.dev/models/perm" @@ -295,44 +296,56 @@ func (r *RepoUnit) Unit() unit.Unit { return unit.Units[r.Type] } +// unitConfig returns the unit's config, which BeforeSet has created from the unit type +func unitConfig[T interface { + *E + convert.Conversion +}, E any](r *RepoUnit) T { + config, ok := r.Config.(T) + if !ok { + panic(fmt.Errorf("repo unit %d of type %s has config type %T instead of %T", r.ID, r.Type.LogString(), r.Config, config)) + } + return config +} + // CodeConfig returns config for unit.TypeCode func (r *RepoUnit) CodeConfig() *UnitConfig { - return r.Config.(*UnitConfig) + return unitConfig[*UnitConfig](r) } // PullRequestsConfig returns config for unit.TypePullRequests func (r *RepoUnit) PullRequestsConfig() *PullRequestsConfig { - return r.Config.(*PullRequestsConfig) + return unitConfig[*PullRequestsConfig](r) } // ReleasesConfig returns config for unit.TypeReleases func (r *RepoUnit) ReleasesConfig() *UnitConfig { - return r.Config.(*UnitConfig) + return unitConfig[*UnitConfig](r) } // ExternalWikiConfig returns config for unit.TypeExternalWiki func (r *RepoUnit) ExternalWikiConfig() *ExternalWikiConfig { - return r.Config.(*ExternalWikiConfig) + return unitConfig[*ExternalWikiConfig](r) } // IssuesConfig returns config for unit.TypeIssues func (r *RepoUnit) IssuesConfig() *IssuesConfig { - return r.Config.(*IssuesConfig) + return unitConfig[*IssuesConfig](r) } // ExternalTrackerConfig returns config for unit.TypeExternalTracker func (r *RepoUnit) ExternalTrackerConfig() *ExternalTrackerConfig { - return r.Config.(*ExternalTrackerConfig) + return unitConfig[*ExternalTrackerConfig](r) } // ActionsConfig returns config for unit.ActionsConfig func (r *RepoUnit) ActionsConfig() *ActionsConfig { - return r.Config.(*ActionsConfig) + return unitConfig[*ActionsConfig](r) } // ProjectsConfig returns config for unit.ProjectsConfig func (r *RepoUnit) ProjectsConfig() *ProjectsConfig { - return r.Config.(*ProjectsConfig) + return unitConfig[*ProjectsConfig](r) } func getUnitsByRepoID(ctx context.Context, repoID int64) (units []*RepoUnit, err error) { diff --git a/models/unittest/fixtures_loader.go b/models/unittest/fixtures_loader.go index 7ad3bc9058..46c79fef1a 100644 --- a/models/unittest/fixtures_loader.go +++ b/models/unittest/fixtures_loader.go @@ -34,7 +34,8 @@ type FixtureItem struct { type fixturesLoaderInternal struct { xormEngine *xorm.Engine - tableSyncMap sync.Map + tableSyncMu sync.Mutex + tableSynced map[string]bool db *sql.DB dbType schemas.DBType fixtures map[string]*FixtureItem @@ -152,32 +153,35 @@ func (f *fixturesLoaderInternal) Load() error { ctx := context.WithValue(context.Background(), db.ContextKeyTestFixtures, true) + f.tableSyncMu.Lock() + defer f.tableSyncMu.Unlock() + for _, fixture := range f.fixtures { - synced, existing := f.tableSyncMap.Load(fixture.tableName) - if synced == true || !existing { + synced, existing := f.tableSynced[fixture.tableName] + if synced || !existing { continue } if err := f.loadFixtures(tx, fixture); err != nil { return fmt.Errorf("failed to load fixtures from %s: %w", fixture.fileFullPath, err) } - f.tableSyncMap.Store(fixture.tableName, true) + f.tableSynced[fixture.tableName] = true } if err = tx.Commit(); err != nil { return err } - f.tableSyncMap.Range(func(k, v any) bool { - tableName, synced := k.(string), v.(bool) + for tableName, synced := range f.tableSynced { if !synced && f.fixtures[tableName] == nil { _, _ = f.xormEngine.Context(ctx).Exec("DELETE FROM `" + tableName + "`") } - f.tableSyncMap.Store(tableName, true) - return true - }) + f.tableSynced[tableName] = true + } return nil } func (f *fixturesLoaderInternal) MarkTableChanged(tableName string) { - f.tableSyncMap.Store(tableName, false) + f.tableSyncMu.Lock() + defer f.tableSyncMu.Unlock() + f.tableSynced[tableName] = false } func FixturesFileFullPaths(dir string, files []string) (map[string]*FixtureItem, error) { @@ -212,7 +216,7 @@ func NewFixturesLoader(x *xorm.Engine, opts FixturesOptions) (FixturesLoader, er return nil, fmt.Errorf("failed to get fixtures files: %w", err) } - f := &fixturesLoaderInternal{xormEngine: x, db: x.DB().DB, dbType: x.Dialect().URI().DBType, fixtures: fixtureItems} + f := &fixturesLoaderInternal{xormEngine: x, db: x.DB().DB, dbType: x.Dialect().URI().DBType, fixtures: fixtureItems, tableSynced: map[string]bool{}} switch f.dbType { case schemas.SQLITE: f.quoteObject = func(s string) string { return fmt.Sprintf(`"%s"`, s) } @@ -233,7 +237,7 @@ func NewFixturesLoader(x *xorm.Engine, opts FixturesOptions) (FixturesLoader, er xormBeans, _ := db.NamesToBean() for _, bean := range xormBeans { beanTableName := x.TableName(bean) - f.tableSyncMap.Store(trimTableNameQuotes(beanTableName), false) + f.tableSynced[trimTableNameQuotes(beanTableName)] = false } return f, nil } diff --git a/modules/actions/scoped_workflows.go b/modules/actions/scoped_workflows.go index 3e3cd47da9..376faecace 100644 --- a/modules/actions/scoped_workflows.go +++ b/modules/actions/scoped_workflows.go @@ -64,7 +64,7 @@ func MatchScopedWorkflows( parsed []*ParsedScopedWorkflow, consumerGitRepo *git.Repository, consumerCommit *git.Commit, - triggedEvent webhook_module.HookEventType, + inputEvent webhook_module.HookEventType, payload api.Payloader, ) (matched, filtered []*DetectedWorkflow) { for _, p := range parsed { @@ -78,7 +78,7 @@ func MatchScopedWorkflows( TriggerEvent: evt, Content: p.Content, } - switch detectWorkflowMatch(ctx, consumerGitRepo, consumerCommit, triggedEvent, payload, evt) { + switch detectWorkflowMatch(ctx, consumerGitRepo, consumerCommit, inputEvent, payload, evt) { case detectMatched: matched = append(matched, dwf) case detectFilteredOut: diff --git a/modules/actions/workflows.go b/modules/actions/workflows.go index 87fa51de33..6b26840043 100644 --- a/modules/actions/workflows.go +++ b/modules/actions/workflows.go @@ -266,12 +266,22 @@ func DetectScheduledWorkflows(ctx context.Context, gitRepo *git.Repository, comm return wfs, nil } -func detectWorkflowMatch(ctx context.Context, gitRepo *git.Repository, commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader, evt *jobparser.Event) detectResult { - if !canGithubEventMatch(evt.Name, triggedEvent) { +// payloadAs returns the payload as the type the event is expected to carry +func payloadAs[T api.Payloader](payload api.Payloader, inputEvent webhook_module.HookEventType) T { + typedPayload, ok := payload.(T) + if !ok { + // the event type determines the payload type, so a mismatch can only be a programming error + panic(fmt.Errorf("event %q was triggered with payload type %T instead of %T", inputEvent, payload, typedPayload)) + } + return typedPayload +} + +func detectWorkflowMatch(ctx context.Context, gitRepo *git.Repository, commit *git.Commit, inputEvent webhook_module.HookEventType, payload api.Payloader, evt *jobparser.Event) detectResult { + if !canGithubEventMatch(evt.Name, inputEvent) { return detectNotApplicable } - switch triggedEvent { + switch inputEvent { case // events with no activity types webhook_module.HookEventCreate, webhook_module.HookEventDelete, @@ -279,21 +289,23 @@ func detectWorkflowMatch(ctx context.Context, gitRepo *git.Repository, commit *g webhook_module.HookEventWiki, webhook_module.HookEventSchedule: if len(evt.Acts()) != 0 { - log.Warn("Ignore unsupported %s event arguments %v", triggedEvent, evt.Acts()) + log.Warn("Ignore unsupported %s event arguments %v", inputEvent, evt.Acts()) } // no special filter parameters for these events, just return true if name matched return detectMatched case // push webhook_module.HookEventPush: - return matchPushEvent(ctx, gitRepo, commit, payload.(*api.PushPayload), evt) + pushPayload := payloadAs[*api.PushPayload](payload, inputEvent) + return matchPushEvent(ctx, gitRepo, commit, pushPayload, evt) case // issues webhook_module.HookEventIssues, webhook_module.HookEventIssueAssign, webhook_module.HookEventIssueLabel, webhook_module.HookEventIssueMilestone: - if matchIssuesEvent(payload.(*api.IssuePayload), evt) { + issuePayload := payloadAs[*api.IssuePayload](payload, inputEvent) + if matchIssuesEvent(issuePayload, evt) { return detectMatched } return detectNotApplicable @@ -303,7 +315,8 @@ func detectWorkflowMatch(ctx context.Context, gitRepo *git.Repository, commit *g // `pull_request_comment` is same as `issue_comment` // See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_comment-use-issue_comment webhook_module.HookEventPullRequestComment: - if matchIssueCommentEvent(payload.(*api.IssueCommentPayload), evt) { + issueCommentPayload := payloadAs[*api.IssueCommentPayload](payload, inputEvent) + if matchIssueCommentEvent(issueCommentPayload, evt) { return detectMatched } return detectNotApplicable @@ -315,46 +328,52 @@ func detectWorkflowMatch(ctx context.Context, gitRepo *git.Repository, commit *g webhook_module.HookEventPullRequestLabel, webhook_module.HookEventPullRequestReviewRequest, webhook_module.HookEventPullRequestMilestone: - return matchPullRequestEvent(ctx, gitRepo, commit, payload.(*api.PullRequestPayload), evt) + pullRequestPayload := payloadAs[*api.PullRequestPayload](payload, inputEvent) + return matchPullRequestEvent(ctx, gitRepo, commit, pullRequestPayload, evt) case // pull_request_review webhook_module.HookEventPullRequestReviewApproved, webhook_module.HookEventPullRequestReviewRejected: - if matchPullRequestReviewEvent(payload.(*api.PullRequestPayload), evt) { + reviewPayload := payloadAs[*api.PullRequestPayload](payload, inputEvent) + if matchPullRequestReviewEvent(reviewPayload, evt) { return detectMatched } return detectNotApplicable case // pull_request_review_comment webhook_module.HookEventPullRequestReviewComment: - if matchPullRequestReviewCommentEvent(payload.(*api.PullRequestPayload), evt) { + reviewCommentPayload := payloadAs[*api.PullRequestPayload](payload, inputEvent) + if matchPullRequestReviewCommentEvent(reviewCommentPayload, evt) { return detectMatched } return detectNotApplicable case // release webhook_module.HookEventRelease: - if matchReleaseEvent(payload.(*api.ReleasePayload), evt) { + releasePayload := payloadAs[*api.ReleasePayload](payload, inputEvent) + if matchReleaseEvent(releasePayload, evt) { return detectMatched } return detectNotApplicable case // registry_package webhook_module.HookEventPackage: - if matchPackageEvent(payload.(*api.PackagePayload), evt) { + packagePayload := payloadAs[*api.PackagePayload](payload, inputEvent) + if matchPackageEvent(packagePayload, evt) { return detectMatched } return detectNotApplicable case // workflow_run webhook_module.HookEventWorkflowRun: - if matchWorkflowRunEvent(payload.(*api.WorkflowRunPayload), evt) { + workflowRunPayload := payloadAs[*api.WorkflowRunPayload](payload, inputEvent) + if matchWorkflowRunEvent(workflowRunPayload, evt) { return detectMatched } return detectNotApplicable default: - log.Warn("unsupported event %q", triggedEvent) + log.Warn("unsupported event %q", inputEvent) return detectNotApplicable } } diff --git a/modules/assetfs/embed_test.go b/modules/assetfs/embed_test.go index 06598da4c4..5c3db3672e 100644 --- a/modules/assetfs/embed_test.go +++ b/modules/assetfs/embed_test.go @@ -37,7 +37,9 @@ func TestEmbed(t *testing.T) { assert.Equal(t, "a", string(content)) fi, err := fs.Stat(efs, "a.txt") require.NoError(t, err) - _, ok := fi.(EmbeddedFileInfo).GetGzipContent() + fiEmbedded, ok := fi.(EmbeddedFileInfo) + require.True(t, ok) + _, ok = fiEmbedded.GetGzipContent() assert.False(t, ok) // test a compressed file @@ -48,7 +50,9 @@ func TestEmbed(t *testing.T) { require.NoError(t, err) assert.False(t, fi.Mode().IsDir()) assert.True(t, fi.Mode().IsRegular()) - gzipContent, ok := fi.(EmbeddedFileInfo).GetGzipContent() + fiEmbedded, ok = fi.(EmbeddedFileInfo) + require.True(t, ok) + gzipContent, ok := fiEmbedded.GetGzipContent() assert.True(t, ok) assert.Greater(t, len(gzipContent), 1) assert.Less(t, len(gzipContent), 1000) @@ -82,7 +86,7 @@ func TestEmbed(t *testing.T) { require.NoError(t, err) hi, err := hf.Stat() require.NoError(t, err) - fiEmbedded, ok := hi.(EmbeddedFileInfo) + fiEmbedded, ok = hi.(EmbeddedFileInfo) require.True(t, ok) gzipContent, ok = fiEmbedded.GetGzipContent() assert.True(t, ok) diff --git a/modules/base/tool.go b/modules/base/tool.go index bab2c57e95..1e4db2b977 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -64,15 +64,17 @@ func CreateTimeLimitCode[T time.Time | string](data string, minutes int, startTi const format = "200601021504" var start time.Time - var startTimeAny any = startTimeGeneric - if t, ok := startTimeAny.(time.Time); ok { - start = t - } else { + switch startTime := any(startTimeGeneric).(type) { + case time.Time: + start = startTime + case string: var err error - start, err = time.ParseInLocation(format, startTimeAny.(string), time.Local) + start, err = time.ParseInLocation(format, startTime, time.Local) if err != nil { return "" // return an invalid code because the "parse" failed } + default: + panic(fmt.Sprintf("unsupported start time type %T", startTime)) // it shouldn't happen } startStr := start.Format(format) end := start.Add(time.Minute * time.Duration(minutes)) diff --git a/modules/cache/context_test.go b/modules/cache/context_test.go index 1eee11836e..dc27f32ea9 100644 --- a/modules/cache/context_test.go +++ b/modules/cache/context_test.go @@ -25,7 +25,7 @@ func TestWithCacheContext(t *testing.T) { c.Put(field, "my_config1", 1) v, _ = c.Get(field, "my_config1") assert.NotNil(t, v) - assert.Equal(t, 1, v.(int)) + assert.Equal(t, 1, v) c.Delete(field, "my_config1") c.Delete(field, "my_config2") // remove a non-exist key diff --git a/modules/git/commit_info_gogit.go b/modules/git/commit_info_gogit.go index 7c578580c8..13ad029cc5 100644 --- a/modules/git/commit_info_gogit.go +++ b/modules/git/commit_info_gogit.go @@ -82,7 +82,7 @@ func getLastCommitForPathsByCommitNode(ctx context.Context, gitRepo *Repository, // We do a tree traversal with nodes sorted by commit time heap := binaryheap.NewWith(func(a, b any) int { - if a.(*commitAndPaths).commit.CommitTime().Before(b.(*commitAndPaths).commit.CommitTime()) { + if a.(*commitAndPaths).commit.CommitTime().Before(b.(*commitAndPaths).commit.CommitTime()) { //nolint:forcetypeassert // this heap only ever holds *commitAndPaths return 1 } return -1 @@ -110,7 +110,7 @@ heaploop: if !ok { break } - current := cIn.(*commitAndPaths) + current := cIn.(*commitAndPaths) //nolint:forcetypeassert // this heap only ever holds *commitAndPaths // Load the parent commits for the one we are currently examining numParents := current.commit.NumParents() diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index dde15602bb..871a3db68e 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -144,7 +144,7 @@ func (repo *Repository) GetTagInfos(ctx context.Context, page, pageSize int) ([] sortTagsByTime(tags) tagsTotal = len(tags) if page != 0 { - tags = util.PaginateSlice(tags, page, pageSize).([]*Tag) + tags = util.PaginateSlice(tags, page, pageSize) } return nil }). diff --git a/modules/glob/glob_test.go b/modules/glob/glob_test.go index 8467895252..0eb101fa14 100644 --- a/modules/glob/glob_test.go +++ b/modules/glob/glob_test.go @@ -174,8 +174,10 @@ func TestGlob(t *testing.T) { } { g, err := Compile(test.pattern, test.delimiters...) require.NoError(t, err) + compiler, ok := g.(*globCompiler) + require.True(t, ok) result := g.Match(test.match) - assert.Equal(t, test.should, result, "pattern %q matching %q should be %v but got %v, compiled=%s", test.pattern, test.match, test.should, result, g.(*globCompiler).regexpPattern) + assert.Equal(t, test.should, result, "pattern %q matching %q should be %v but got %v, compiled=%s", test.pattern, test.match, test.should, result, compiler.regexpPattern) } } diff --git a/modules/globallock/globallock_test.go b/modules/globallock/globallock_test.go index e6cedb67c0..39f58848a4 100644 --- a/modules/globallock/globallock_test.go +++ b/modules/globallock/globallock_test.go @@ -21,7 +21,9 @@ func TestLockAndDo(t *testing.T) { locker := newTestRedisLocker(t) defaultLocker.Store(new(locker)) testLockAndDo(t) - require.NoError(t, locker.(*redisLocker).Close()) + rl, ok := locker.(*redisLocker) + require.True(t, ok) + require.NoError(t, rl.Close()) }) t.Run("memory", func(t *testing.T) { defaultLocker.Store(new(NewMemoryLocker())) diff --git a/modules/globallock/locker_test.go b/modules/globallock/locker_test.go index 1ade24dfa9..6f186fae9d 100644 --- a/modules/globallock/locker_test.go +++ b/modules/globallock/locker_test.go @@ -26,13 +26,17 @@ func TestLocker(t *testing.T) { defer test.MockVariableValue(&redisLockExpiry, 5*time.Second)() // make it shorter for testing locker := newTestRedisLocker(t) testLocker(t, locker) - testRedisLocker(t, locker.(*redisLocker)) - require.NoError(t, locker.(*redisLocker).Close()) + rl, ok := locker.(*redisLocker) + require.True(t, ok) + testRedisLocker(t, rl) + require.NoError(t, rl.Close()) }) t.Run("memory", func(t *testing.T) { locker := NewMemoryLocker() testLocker(t, locker) - testMemoryLocker(t, locker.(*memoryLocker)) + ml, ok := locker.(*memoryLocker) + require.True(t, ok) + testMemoryLocker(t, ml) }) } @@ -162,7 +166,8 @@ func testRedisLocker(t *testing.T, locker *redisLocker) { // It simulates that there are some problems with extending like network issues or redis server down. v, ok := locker.mutexM.Load("test") require.True(t, ok) - m := v.(*redsync.Mutex) + m, ok := v.(*redsync.Mutex) + require.True(t, ok) _, _ = m.Unlock() // release it to make it impossible to extend // In current design, callers can't know the lock can't be extended. diff --git a/modules/globallock/redis_locker.go b/modules/globallock/redis_locker.go index 6c9fa80a7f..1883b3bb52 100644 --- a/modules/globallock/redis_locker.go +++ b/modules/globallock/redis_locker.go @@ -52,11 +52,10 @@ func (l *redisLocker) Lock(ctx context.Context, key string) (ReleaseFunc, error) func (l *redisLocker) TryLock(ctx context.Context, key string) (bool, ReleaseFunc, error) { f, err := l.lock(ctx, key, 1) - var ( - errTaken *redsync.ErrTaken - errNodeTaken *redsync.ErrNodeTaken - ) - if errors.As(err, &errTaken) || errors.As(err, &errNodeTaken) { + if _, taken := errors.AsType[*redsync.ErrTaken](err); taken { + return false, f, nil + } + if _, nodeTaken := errors.AsType[*redsync.ErrNodeTaken](err); nodeTaken { return false, f, nil } return err == nil, f, err @@ -112,7 +111,7 @@ func (l *redisLocker) startExtend() { toExtend := make([]*redsync.Mutex, 0) l.mutexM.Range(func(_, value any) bool { - m := value.(*redsync.Mutex) + m := value.(*redsync.Mutex) //nolint:forcetypeassert // mutexM only ever holds *redsync.Mutex // Extend the lock if it is not expired. // Although the mutex will be removed from the map before it is released, diff --git a/modules/graceful/net_unix.go b/modules/graceful/net_unix.go index 048cb99378..6650090f18 100644 --- a/modules/graceful/net_unix.go +++ b/modules/graceful/net_unix.go @@ -177,13 +177,15 @@ func GetListenerTCP(network string, address *net.TCPAddr) (*net.TCPListener, err // look for a provided listener for i, l := range providedListeners { if isSameAddr(l.Addr(), address) { + tcpListener := l.(*net.TCPListener) //nolint:forcetypeassert // a listener matching a *net.TCPAddr is a *net.TCPListener + providedListeners = append(providedListeners[:i], providedListeners[i+1:]...) needsUnlink := providedListenersToUnlink[i] providedListenersToUnlink = append(providedListenersToUnlink[:i], providedListenersToUnlink[i+1:]...) activeListeners = append(activeListeners, l) activeListenersToUnlink = append(activeListenersToUnlink, needsUnlink) - return l.(*net.TCPListener), nil + return tcpListener, nil } } @@ -211,13 +213,14 @@ func GetListenerUnix(network string, address *net.UnixAddr) (*net.UnixListener, // look for a provided listener for i, l := range providedListeners { if isSameAddr(l.Addr(), address) { + unixListener := l.(*net.UnixListener) //nolint:forcetypeassert // a listener matching a *net.UnixAddr is a *net.UnixListener + providedListeners = append(providedListeners[:i], providedListeners[i+1:]...) needsUnlink := providedListenersToUnlink[i] providedListenersToUnlink = append(providedListenersToUnlink[:i], providedListenersToUnlink[i+1:]...) activeListenersToUnlink = append(activeListenersToUnlink, needsUnlink) activeListeners = append(activeListeners, l) - unixListener := l.(*net.UnixListener) if needsUnlink { unixListener.SetUnlinkOnClose(true) } diff --git a/modules/graceful/restart_unix.go b/modules/graceful/restart_unix.go index 98d5c5cc20..831bebab92 100644 --- a/modules/graceful/restart_unix.go +++ b/modules/graceful/restart_unix.go @@ -44,10 +44,14 @@ func RestartProcess() (int, error) { // Extract the fds from the listeners. files := make([]*os.File, len(listeners)) for i, l := range listeners { - var err error // Now, all our listeners actually have File() functions so instead of // individually casting we just use a hacky interface - files[i], err = l.(filer).File() + lf, ok := l.(filer) + if !ok { + return 0, fmt.Errorf("listener %T does not provide a File", l) + } + var err error + files[i], err = lf.File() if err != nil { return 0, err } diff --git a/modules/graceful/server.go b/modules/graceful/server.go index 4cd138458f..a12b5aefcb 100644 --- a/modules/graceful/server.go +++ b/modules/graceful/server.go @@ -7,6 +7,7 @@ package graceful import ( "crypto/tls" + "fmt" "net" "os" "strings" @@ -260,7 +261,11 @@ func (wl *wrappedListener) Accept() (c net.Conn, err error) { func (wl *wrappedListener) File() (*os.File, error) { // returns a dup(2) - FD_CLOEXEC flag *not* set so the listening socket can be passed to child processes - return wl.Listener.(filer).File() + lf, ok := wl.Listener.(filer) + if !ok { + return nil, fmt.Errorf("listener %T does not provide a File", wl.Listener) + } + return lf.File() } type wrappedConn struct { diff --git a/modules/gtprof/trace_builtin.go b/modules/gtprof/trace_builtin.go index 76b2dae4b0..23fd82be9c 100644 --- a/modules/gtprof/trace_builtin.go +++ b/modules/gtprof/trace_builtin.go @@ -63,7 +63,7 @@ func (t *traceBuiltinSpan) toString(out *strings.Builder, indent int) { } out.WriteString("\n") for _, c := range t.ts.children { - span := c.internalSpans[t.internalSpanIdx].(*traceBuiltinSpan) + span := c.internalSpans[t.internalSpanIdx].(*traceBuiltinSpan) //nolint:forcetypeassert // this tracer only stores its own spans span.toString(out, indent+2) } } diff --git a/modules/gtprof/trace_test.go b/modules/gtprof/trace_test.go index 0f4e3facba..25bfddcb73 100644 --- a/modules/gtprof/trace_test.go +++ b/modules/gtprof/trace_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) // "vendor span" is a simple demo for a span from a vendor library @@ -82,7 +83,9 @@ func TestTraceStarter(t *testing.T) { collectSpanNames(fullName, c) } } - collectSpanNames("", span.internalSpans[0].(*testTraceSpan).vendorSpan) + rootSpan, ok := span.internalSpans[0].(*testTraceSpan) + require.True(t, ok) + collectSpanNames("", rootSpan.vendorSpan) assert.Equal(t, []string{ "/root", "/root/span1", diff --git a/modules/indexer/code/bleve/bleve.go b/modules/indexer/code/bleve/bleve.go index a5f326cd06..6e78e42efb 100644 --- a/modules/indexer/code/bleve/bleve.go +++ b/modules/indexer/code/bleve/bleve.go @@ -21,6 +21,7 @@ import ( "gitea.dev/modules/indexer/code/internal" indexer_internal "gitea.dev/modules/indexer/internal" inner_bleve "gitea.dev/modules/indexer/internal/bleve" + "gitea.dev/modules/json" "gitea.dev/modules/setting" "gitea.dev/modules/timeutil" "gitea.dev/modules/typesniffer" @@ -330,6 +331,17 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int searchResults := make([]*internal.SearchResult, len(result.Hits)) for i, hit := range result.Hits { + content, okContent := hit.Fields["Content"].(string) + language, okLanguage := hit.Fields["Language"].(string) + commitID, okCommitID := hit.Fields["CommitID"].(string) + updatedAt, okUpdatedAt := hit.Fields["UpdatedAt"].(string) + repoID, okRepoID := hit.Fields["RepoID"].(float64) + if !okContent || !okLanguage || !okCommitID || !okUpdatedAt || !okRepoID { + hitFieldsJson, _ := json.Marshal(hit.Fields) + setting.PanicInDevOrTesting("unexpected field types in search hit %q: %s", hit.ID, string(hitFieldsJson)) + return 0, nil, nil, fmt.Errorf("unexpected field types in search hit %q", hit.ID) + } + startIndex, endIndex := -1, -1 for _, locations := range hit.Locations["Content"] { location := locations[0] @@ -343,21 +355,20 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int } } if len(hit.Locations["Filename"]) > 0 { - startIndex, endIndex = internal.FilenameMatchIndexPos(hit.Fields["Content"].(string)) + startIndex, endIndex = internal.FilenameMatchIndexPos(content) } - language := hit.Fields["Language"].(string) var updatedUnix timeutil.TimeStamp - if t, err := time.Parse(time.RFC3339, hit.Fields["UpdatedAt"].(string)); err == nil { + if t, err := time.Parse(time.RFC3339, updatedAt); err == nil { updatedUnix = timeutil.TimeStamp(t.Unix()) } searchResults[i] = &internal.SearchResult{ - RepoID: int64(hit.Fields["RepoID"].(float64)), + RepoID: int64(repoID), StartIndex: startIndex, EndIndex: endIndex, Filename: internal.FilenameOfIndexerID(hit.ID), - Content: hit.Fields["Content"].(string), - CommitID: hit.Fields["CommitID"].(string), + Content: content, + CommitID: commitID, UpdatedUnix: updatedUnix, Language: language, Color: enry.GetColor(language), diff --git a/modules/indexer/code/elasticsearch/elasticsearch.go b/modules/indexer/code/elasticsearch/elasticsearch.go index c0b20735b1..74d749cd1d 100644 --- a/modules/indexer/code/elasticsearch/elasticsearch.go +++ b/modules/indexer/code/elasticsearch/elasticsearch.go @@ -261,12 +261,21 @@ func convertResult(searchResult *es.SearchResponse, kw string, pageSize int) (in return 0, nil, nil, err } + content, okContent := res["content"].(string) + language, okLanguage := res["language"].(string) + commitID, okCommitID := res["commit_id"].(string) + updatedAt, okUpdatedAt := res["updated_at"].(float64) + if !okContent || !okLanguage || !okCommitID || !okUpdatedAt { + setting.PanicInDevOrTesting("unexpected field types in search hit %q: %s", hit.ID, string(hit.Source)) + return 0, nil, nil, fmt.Errorf("unexpected field types in search hit %q", hit.ID) + } + // FIXME: There is no way to get the position the keyword on the content currently on the same request. // So we get it from content, this may made the query slower. See // https://discuss.elastic.co/t/fetching-position-of-keyword-in-matched-document/94291 var startIndex, endIndex int if c, ok := hit.Highlight["filename"]; ok && len(c) > 0 { - startIndex, endIndex = internal.FilenameMatchIndexPos(res["content"].(string)) + startIndex, endIndex = internal.FilenameMatchIndexPos(content) } else if c, ok := hit.Highlight["content"]; ok && len(c) > 0 { // FIXME: Since the highlighting content will include and for the keywords, // now we should find the positions. But how to avoid html content which contains the @@ -279,14 +288,12 @@ func convertResult(searchResult *es.SearchResponse, kw string, pageSize int) (in panic(fmt.Sprintf("2===%#v", hit.Highlight)) } - language := res["language"].(string) - hits = append(hits, &internal.SearchResult{ RepoID: repoID, Filename: fileName, - CommitID: res["commit_id"].(string), - Content: res["content"].(string), - UpdatedUnix: timeutil.TimeStamp(res["updated_at"].(float64)), + CommitID: commitID, + Content: content, + UpdatedUnix: timeutil.TimeStamp(updatedAt), Language: language, StartIndex: startIndex, EndIndex: endIndex, diff --git a/modules/log/event_writer_conn.go b/modules/log/event_writer_conn.go index 022206aa4d..fcb18bc14f 100644 --- a/modules/log/event_writer_conn.go +++ b/modules/log/event_writer_conn.go @@ -24,7 +24,7 @@ var _ EventWriter = (*eventWriterConn)(nil) func NewEventWriterConn(writerName string, writerMode WriterMode) EventWriter { w := &eventWriterConn{EventWriterBaseImpl: NewEventWriterBase(writerName, "conn", writerMode)} - opt := writerMode.WriterOption.(WriterConnOption) + opt := writerMode.WriterOption.(WriterConnOption) //nolint:forcetypeassert // a conn writer is only created with WriterConnOption w.connWriter = connWriter{ ReconnectOnMsg: opt.ReconnectOnMsg, Reconnect: opt.Reconnect, diff --git a/modules/log/event_writer_console.go b/modules/log/event_writer_console.go index 8a3e43710a..778ec1dc46 100644 --- a/modules/log/event_writer_console.go +++ b/modules/log/event_writer_console.go @@ -21,7 +21,7 @@ var _ EventWriter = (*eventWriterConsole)(nil) func NewEventWriterConsole(name string, mode WriterMode) EventWriter { w := &eventWriterConsole{EventWriterBaseImpl: NewEventWriterBase(name, "console", mode)} - opt := mode.WriterOption.(WriterConsoleOption) + opt := mode.WriterOption.(WriterConsoleOption) //nolint:forcetypeassert // a console writer is only created with WriterConsoleOption if opt.Stderr { w.OutputWriteCloser = util.NopCloser{Writer: os.Stderr} } else { diff --git a/modules/log/event_writer_file.go b/modules/log/event_writer_file.go index c4b8183c2a..5584657f61 100644 --- a/modules/log/event_writer_file.go +++ b/modules/log/event_writer_file.go @@ -29,7 +29,7 @@ var _ EventWriter = (*eventWriterFile)(nil) func NewEventWriterFile(name string, mode WriterMode) EventWriter { w := &eventWriterFile{EventWriterBaseImpl: NewEventWriterBase(name, "file", mode)} - opt := mode.WriterOption.(WriterFileOption) + opt := mode.WriterOption.(WriterFileOption) //nolint:forcetypeassert // a file writer is only created with WriterFileOption var err error w.fileWriter, err = rotatingfilewriter.Open(opt.FileName, &rotatingfilewriter.Options{ Rotate: opt.LogRotate, diff --git a/modules/log/manager_test.go b/modules/log/manager_test.go index beddbccb73..59e5496bfa 100644 --- a/modules/log/manager_test.go +++ b/modules/log/manager_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestSharedWorker(t *testing.T) { @@ -37,6 +38,8 @@ func TestSharedWorker(t *testing.T) { m.Close() - logs := w.(*dummyWriter).FetchLogs() + dw, ok := w.(*dummyWriter) + require.True(t, ok) + logs := dw.FetchLogs() assert.Equal(t, []string{"msg-1\n", "msg-2\n", "msg-3\n"}, logs) } diff --git a/modules/markup/common/footnote.go b/modules/markup/common/footnote.go index e552a28237..2c47ea1385 100644 --- a/modules/markup/common/footnote.go +++ b/modules/markup/common/footnote.go @@ -237,10 +237,8 @@ func (b *footnoteBlockParser) Continue(node ast.Node, reader text.Reader, pc par } func (b *footnoteBlockParser) Close(node ast.Node, reader text.Reader, pc parser.Context) { - var list *FootnoteList - if tlist := pc.Get(footnoteListKey); tlist != nil { - list = tlist.(*FootnoteList) - } else { + list, _ := pc.Get(footnoteListKey).(*FootnoteList) + if list == nil { list = NewFootnoteList() pc.Set(footnoteListKey, list) node.Parent().InsertBefore(node.Parent(), node, list) @@ -295,17 +293,14 @@ func (s *footnoteParser) Parse(parent ast.Node, block text.Reader, pc parser.Con value := block.Value(text.NewSegment(segment.Start+open, segment.Start+closes)) block.Advance(closes + 1) - var list *FootnoteList - if tlist := pc.Get(footnoteListKey); tlist != nil { - list = tlist.(*FootnoteList) - } + list, _ := pc.Get(footnoteListKey).(*FootnoteList) if list == nil { return nil } index := 0 name := []byte{} for def := list.FirstChild(); def != nil; def = def.NextSibling() { - d := def.(*Footnote) + d := def.(*Footnote) //nolint:forcetypeassert // a FootnoteList only holds *Footnote children if bytes.Equal(d.Ref, value) { if d.Index < 0 { list.Count++ @@ -339,10 +334,8 @@ func NewFootnoteASTTransformer() parser.ASTTransformer { } func (a *footnoteASTTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) { - var list *FootnoteList - if tlist := pc.Get(footnoteListKey); tlist != nil { - list = tlist.(*FootnoteList) - } else { + list, _ := pc.Get(footnoteListKey).(*FootnoteList) + if list == nil { return } pc.Set(footnoteListKey, nil) @@ -352,18 +345,16 @@ func (a *footnoteASTTransformer) Transform(node *ast.Document, reader text.Reade if fc := container.LastChild(); fc != nil && ast.IsParagraph(fc) { container = fc } - footnoteNode := footnote.(*Footnote) - index := footnoteNode.Index - name := footnoteNode.Name - if index < 0 { + footnoteNode := footnote.(*Footnote) //nolint:forcetypeassert // a FootnoteList only holds *Footnote children + if footnoteNode.Index < 0 { list.RemoveChild(list, footnote) } else { - container.AppendChild(container, NewFootnoteBackLink(index, name)) + container.AppendChild(container, NewFootnoteBackLink(footnoteNode.Index, footnoteNode.Name)) } footnote = next } list.SortChildren(func(n1, n2 ast.Node) int { - if n1.(*Footnote).Index < n2.(*Footnote).Index { + if n1.(*Footnote).Index < n2.(*Footnote).Index { //nolint:forcetypeassert // a FootnoteList only holds *Footnote children return -1 } return 1 @@ -403,7 +394,7 @@ func (r *FootnoteHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegist func (r *FootnoteHTMLRenderer) renderFootnoteLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { if entering { - n := node.(*FootnoteLink) + n := node.(*FootnoteLink) //nolint:forcetypeassert // registered for KindFootnoteLink only is := strconv.Itoa(n.Index) _, _ = w.WriteString(``) @@ -429,7 +420,7 @@ func (r *FootnoteHTMLRenderer) renderFootnoteBackLink(w util.BufWriter, source [ } func (r *FootnoteHTMLRenderer) renderFootnote(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { - n := node.(*Footnote) + n := node.(*Footnote) //nolint:forcetypeassert // registered for KindFootnote only if entering { _, _ = w.WriteString(`
  • `) + `` _, _ = w.WriteString(string(r.renderInternal.ProtectSafeAttrs(codeHTML))) diff --git a/modules/markup/markdown/math/inline_node.go b/modules/markup/markdown/math/inline_node.go index 1e4034d54b..d4dd06dfc0 100644 --- a/modules/markup/markdown/math/inline_node.go +++ b/modules/markup/markdown/math/inline_node.go @@ -19,8 +19,8 @@ func (n *Inline) Inline() {} // IsBlank returns if this inline node is empty func (n *Inline) IsBlank(source []byte) bool { for c := n.FirstChild(); c != nil; c = c.NextSibling() { - text := c.(*ast.Text).Segment - if !util.IsBlank(text.Value(source)) { + text := c.(*ast.Text) //nolint:forcetypeassert // an inline math node only holds text children + if !util.IsBlank(text.Segment.Value(source)) { return false } } diff --git a/modules/markup/markdown/math/inline_parser.go b/modules/markup/markdown/math/inline_parser.go index 564861df90..111e403834 100644 --- a/modules/markup/markdown/math/inline_parser.go +++ b/modules/markup/markdown/math/inline_parser.go @@ -160,12 +160,12 @@ func trimBlock(node *Inline, block text.Reader) { } // trim first space and last space - first := node.FirstChild().(*ast.Text) + first := node.FirstChild().(*ast.Text) //nolint:forcetypeassert // an inline math node only holds text children if !(!first.Segment.IsEmpty() && block.Source()[first.Segment.Start] == ' ') { return } - last := node.LastChild().(*ast.Text) + last := node.LastChild().(*ast.Text) //nolint:forcetypeassert // an inline math node only holds text children if !(!last.Segment.IsEmpty() && block.Source()[last.Segment.Stop-1] == ' ') { return } diff --git a/modules/markup/markdown/math/inline_renderer.go b/modules/markup/markdown/math/inline_renderer.go index d438af1a24..a72dd798e4 100644 --- a/modules/markup/markdown/math/inline_renderer.go +++ b/modules/markup/markdown/math/inline_renderer.go @@ -30,7 +30,7 @@ func (r *InlineRenderer) renderInline(w util.BufWriter, source []byte, n ast.Nod if entering { _, _ = w.WriteString(string(r.renderInternal.ProtectSafeAttrs(``))) for c := n.FirstChild(); c != nil; c = c.NextSibling() { - segment := c.(*ast.Text).Segment + segment := c.(*ast.Text).Segment //nolint:forcetypeassert // an inline math node only holds text children value := util.EscapeHTML(segment.Value(source)) if bytes.HasSuffix(value, []byte("\n")) { _, _ = w.Write(value[:len(value)-1]) diff --git a/modules/markup/markdown/transform_blockquote.go b/modules/markup/markdown/transform_blockquote.go index 2ec7cec9d5..ce39d4acfa 100644 --- a/modules/markup/markdown/transform_blockquote.go +++ b/modules/markup/markdown/transform_blockquote.go @@ -18,7 +18,7 @@ import ( // renderAttention renders a quote marked with i.e. "> **Note**" or "> [!Warning]" with a corresponding svg func (r *HTMLRenderer) renderAttention(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { if entering { - n := node.(*Attention) + n := node.(*Attention) //nolint:forcetypeassert // registered for KindAttention only var octiconName string switch n.AttentionType { case "tip": diff --git a/modules/markup/markdown/transform_list.go b/modules/markup/markdown/transform_list.go index 999738790c..05054a4687 100644 --- a/modules/markup/markdown/transform_list.go +++ b/modules/markup/markdown/transform_list.go @@ -15,7 +15,7 @@ import ( ) func (r *HTMLRenderer) renderTaskCheckBoxListItem(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { - n := node.(*TaskCheckBoxListItem) + n := node.(*TaskCheckBoxListItem) //nolint:forcetypeassert // registered for KindTaskCheckBoxListItem only if entering { if n.Attributes() != nil { _, _ = w.WriteString("= listValue.Len() { - return listValue.Slice(listValue.Len(), listValue.Len()).Interface() + if page*pageSize >= len(list) { + return list[len(list):] } - listValue = listValue.Slice(page*pageSize, listValue.Len()) + list = list[page*pageSize:] - if listValue.Len() > pageSize { - return listValue.Slice(0, pageSize).Interface() + if len(list) > pageSize { + return list[:pageSize] } - return listValue.Interface() + return list } diff --git a/modules/util/paginate_test.go b/modules/util/paginate_test.go index 3dc5095071..010b99985a 100644 --- a/modules/util/paginate_test.go +++ b/modules/util/paginate_test.go @@ -11,24 +11,19 @@ import ( func TestPaginateSlice(t *testing.T) { stringSlice := []string{"a", "b", "c", "d", "e"} - result, ok := PaginateSlice(stringSlice, 1, 2).([]string) - assert.True(t, ok) + result := PaginateSlice(stringSlice, 1, 2) assert.Equal(t, []string{"a", "b"}, result) - result, ok = PaginateSlice(stringSlice, 100, 2).([]string) - assert.True(t, ok) + result = PaginateSlice(stringSlice, 100, 2) assert.Equal(t, []string{}, result) - result, ok = PaginateSlice(stringSlice, 3, 2).([]string) - assert.True(t, ok) + result = PaginateSlice(stringSlice, 3, 2) assert.Equal(t, []string{"e"}, result) - result, ok = PaginateSlice(stringSlice, 1, 0).([]string) - assert.True(t, ok) + result = PaginateSlice(stringSlice, 1, 0) assert.Equal(t, []string{"a", "b", "c", "d", "e"}, result) - result, ok = PaginateSlice(stringSlice, 1, -1).([]string) - assert.True(t, ok) + result = PaginateSlice(stringSlice, 1, -1) assert.Equal(t, []string{"a", "b", "c", "d", "e"}, result) type Test struct { @@ -36,11 +31,9 @@ func TestPaginateSlice(t *testing.T) { } testVar := []*Test{{Val: 2}, {Val: 3}, {Val: 4}} - testVar, ok = PaginateSlice(testVar, 1, 50).([]*Test) - assert.True(t, ok) + testVar = PaginateSlice(testVar, 1, 50) assert.Equal(t, []*Test{{Val: 2}, {Val: 3}, {Val: 4}}, testVar) - testVar, ok = PaginateSlice(testVar, 2, 2).([]*Test) - assert.True(t, ok) + testVar = PaginateSlice(testVar, 2, 2) assert.Equal(t, []*Test{{Val: 4}}, testVar) } diff --git a/modules/util/util.go b/modules/util/util.go index 87188b1018..0184ec3da9 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -107,7 +107,7 @@ func FastCryptoRandomBytes(length int) []byte { // ChaCha8 is about 20x times faster than system's crypto/rand. // It is suitable for UUIDs, session IDs, etc pool := chaCha8RandPool() - chaCha8Rand := pool.Get().(*rand2.ChaCha8) + chaCha8Rand := pool.Get().(*rand2.ChaCha8) //nolint:forcetypeassert // the pool's New only ever makes *rand2.ChaCha8 defer pool.Put(chaCha8Rand) buf := make([]byte, length) _, _ = chaCha8Rand.Read(buf) @@ -270,15 +270,16 @@ func OptionalArg[T any](optArg []T, defaultValue ...T) (ret T) { } type EnumConst[T comparable] interface { + comparable EnumValues() []T } // EnumValue returns the value if it's in the enum const's values, // otherwise returns the first item of enums as default value. -func EnumValue[T comparable](val EnumConst[T]) (ret T, valid bool) { +func EnumValue[T EnumConst[T]](val T) (ret T, valid bool) { enums := val.EnumValues() - if slices.Contains(enums, val.(T)) { - return val.(T), true + if slices.Contains(enums, val) { + return val, true } return enums[0], false } diff --git a/modules/web/router.go b/modules/web/router.go index 03b4cf03e2..6541cb1f7b 100644 --- a/modules/web/router.go +++ b/modules/web/router.go @@ -4,6 +4,7 @@ package web import ( + "fmt" "net/http" "net/url" "reflect" @@ -37,8 +38,12 @@ func SetForm(dataStore reqctx.ContextDataProvider, obj any) { } // GetForm returns the validate form information -func GetForm(dataStore reqctx.RequestDataStore) any { - return dataStore.GetData()["__form"] +func GetForm[T any](dataStore reqctx.RequestDataStore) T { + form, ok := dataStore.GetData()["__form"].(T) + if !ok { + panic(fmt.Errorf("bound form %T does not match the requested type %s", dataStore.GetData()["__form"], reflect.TypeFor[T]())) + } + return form } // Router defines a route based on chi's router diff --git a/modules/web/routing/logger_manager.go b/modules/web/routing/logger_manager.go index e0bf3b3263..3a331c8eb5 100644 --- a/modules/web/routing/logger_manager.go +++ b/modules/web/routing/logger_manager.go @@ -54,10 +54,10 @@ func (manager *loggerRequestManager) startSlowQueryDetector(threshold time.Durat // print logs for slow requests manager.reqRecords.Range(func(key, value any) bool { - index, record := key.(uint64), value.(*requestRecord) + record := value.(*requestRecord) //nolint:forcetypeassert // reqRecords only ever holds *requestRecord if now.Sub(record.startTime) >= threshold { manager.logPrint(StillExecutingEvent, record) - manager.reqRecords.Delete(index) + manager.reqRecords.Delete(key) } return true }) diff --git a/routers/api/actions/artifacts.go b/routers/api/actions/artifacts.go index 12c0427864..5a577fdd3e 100644 --- a/routers/api/actions/artifacts.go +++ b/routers/api/actions/artifacts.go @@ -75,6 +75,7 @@ import ( "gitea.dev/modules/json" "gitea.dev/modules/log" "gitea.dev/modules/optional" + "gitea.dev/modules/reqctx" "gitea.dev/modules/setting" "gitea.dev/modules/storage" "gitea.dev/modules/util" @@ -98,7 +99,7 @@ type ArtifactContext struct { func init() { web.RegisterResponseStatusProvider[*ArtifactContext](func(req *http.Request) web_types.ResponseStatusProvider { - return req.Context().Value(artifactContextKey).(*ArtifactContext) + return reqctx.MustContextValue[*ArtifactContext](req.Context(), artifactContextKey) }) } diff --git a/routers/api/actions/artifacts_chunks.go b/routers/api/actions/artifacts_chunks.go index c15085eeca..9c0ad8f02a 100644 --- a/routers/api/actions/artifacts_chunks.go +++ b/routers/api/actions/artifacts_chunks.go @@ -323,7 +323,7 @@ func mergeChunksForArtifact(ctx *ArtifactContext, chunks []*chunkFileItem, st st readers := make([]io.Reader, 0, len(allChunks)) closeReaders := func() { for _, r := range readers { - _ = r.(io.Closer).Close() // it guarantees to be io.Closer by the following loop's Open function + _ = r.(io.Closer).Close() //nolint:forcetypeassert // it guarantees to be io.Closer by the following loop's Open function } readers = nil } diff --git a/routers/api/packages/cargo/cargo.go b/routers/api/packages/cargo/cargo.go index 4e4e6f1289..6c8d04bf50 100644 --- a/routers/api/packages/cargo/cargo.go +++ b/routers/api/packages/cargo/cargo.go @@ -127,7 +127,7 @@ func SearchPackages(ctx *context.Context) { crates = append(crates, &SearchResultCrate{ Name: pd.Package.Name, LatestVersion: pd.Version.Version, - Description: pd.Metadata.(*cargo_module.Metadata).Description, + Description: packages_model.DescriptorMetadata[*cargo_module.Metadata](pd).Description, }) } diff --git a/routers/api/packages/chef/auth.go b/routers/api/packages/chef/auth.go index 9fb1b28c5e..3d3902bdc6 100644 --- a/routers/api/packages/chef/auth.go +++ b/routers/api/packages/chef/auth.go @@ -78,7 +78,12 @@ func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataS return nil, err } - if err := verifySignedHeaders(req, version, pub.(*rsa.PublicKey)); err != nil { + rsaPub, ok := pub.(*rsa.PublicKey) + if !ok { + return nil, errors.New("public key is not a RSA key") + } + + if err := verifySignedHeaders(req, version, rsaPub); err != nil { return nil, err } diff --git a/routers/api/packages/chef/chef.go b/routers/api/packages/chef/chef.go index 4f87857e7b..ae4a874de1 100644 --- a/routers/api/packages/chef/chef.go +++ b/routers/api/packages/chef/chef.go @@ -71,7 +71,7 @@ func PackagesUniverse(ctx *context.Context) { LocationType: "opscode", LocationPath: baseURL, DownloadURL: fmt.Sprintf("%s/cookbooks/%s/versions/%s/download", baseURL, url.PathEscape(pd.Package.Name), pd.Version.Version), - Dependencies: pd.Metadata.(*chef_module.Metadata).Dependencies, + Dependencies: packages_model.DescriptorMetadata[*chef_module.Metadata](pd).Dependencies, } } @@ -128,7 +128,7 @@ func EnumeratePackages(ctx *context.Context) { items := make([]*Item, 0, len(pds)) for _, pd := range pds { - metadata := pd.Metadata.(*chef_module.Metadata) + metadata := packages_model.DescriptorMetadata[*chef_module.Metadata](pd) items = append(items, &Item{ CookbookName: pd.Package.Name, @@ -193,7 +193,7 @@ func PackageMetadata(ctx *context.Context) { latest := pds[len(pds)-1] - metadata := latest.Metadata.(*chef_module.Metadata) + metadata := packages_model.DescriptorMetadata[*chef_module.Metadata](latest) ctx.JSON(http.StatusOK, &Result{ Name: latest.Package.Name, @@ -241,7 +241,7 @@ func PackageVersionMetadata(ctx *context.Context) { baseURL := fmt.Sprintf("%sapi/packages/%s/chef/api/v1/cookbooks/%s", setting.AppURL, ctx.Package.Owner.Name, url.PathEscape(pd.Package.Name)) - metadata := pd.Metadata.(*chef_module.Metadata) + metadata := packages_model.DescriptorMetadata[*chef_module.Metadata](pd) ctx.JSON(http.StatusOK, &Result{ Version: pd.Version.Version, diff --git a/routers/api/packages/composer/api.go b/routers/api/packages/composer/api.go index 8f1a7e0d8a..1e8aa0ae2f 100644 --- a/routers/api/packages/composer/api.go +++ b/routers/api/packages/composer/api.go @@ -50,7 +50,7 @@ func createSearchResultResponse(total int64, pds []*packages_model.PackageDescri for _, pd := range pds { results = append(results, &SearchResult{ Name: pd.Package.Name, - Description: pd.Metadata.(*composer_module.Metadata).Description, + Description: packages_model.DescriptorMetadata[*composer_module.Metadata](pd).Description, Downloads: pd.Version.DownloadCount, }) } @@ -111,7 +111,7 @@ func createPackageMetadataResponse(ctx *context.Context, registryURL string, pds Version: pd.Version.Version, Type: packageType, Created: pd.Version.CreatedUnix.AsLocalTime(), - Metadata: pd.Metadata.(*composer_module.Metadata), + Metadata: packages_model.DescriptorMetadata[*composer_module.Metadata](pd), Dist: Dist{ Type: "zip", URL: fmt.Sprintf("%s/files/%s/%s/%s", registryURL, url.PathEscape(pd.Package.LowerName), url.PathEscape(pd.Version.LowerVersion), url.PathEscape(pd.Files[0].File.LowerName)), diff --git a/routers/api/packages/conan/conan.go b/routers/api/packages/conan/conan.go index f328cd0a44..cbf23aa501 100644 --- a/routers/api/packages/conan/conan.go +++ b/routers/api/packages/conan/conan.go @@ -103,6 +103,14 @@ func ExtractPathParameters(ctx *context.Context) { ctx.Data[packageReferenceKey] = pref } +func getRecipeReference(ctx *context.Context) *conan_module.RecipeReference { + return ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) //nolint:forcetypeassert // must be valid +} + +func getPackageReference(ctx *context.Context) *conan_module.PackageReference { + return ctx.Data[packageReferenceKey].(*conan_module.PackageReference) //nolint:forcetypeassert // must be valid +} + // Ping reports the server capabilities func Ping(ctx *context.Context) { ctx.RespHeader().Add("X-Conan-Server-Capabilities", "revisions") // complex_search,checksum_deploy,matrix_params @@ -164,20 +172,20 @@ func CheckCredentials(ctx *context.Context) { // RecipeSnapshot displays the recipe files with their md5 hash func RecipeSnapshot(ctx *context.Context) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) serveSnapshot(ctx, rref.AsKey()) } // RecipeSnapshot displays the package files with their md5 hash func PackageSnapshot(ctx *context.Context) { - pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference) + pref := getPackageReference(ctx) serveSnapshot(ctx, pref.AsKey()) } func serveSnapshot(ctx *context.Context, fileKey string) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version) if err != nil { @@ -217,7 +225,7 @@ func serveSnapshot(ctx *context.Context, fileKey string) { // RecipeDownloadURLs displays the recipe files with their download url func RecipeDownloadURLs(ctx *context.Context) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) serveDownloadURLs( ctx, @@ -228,7 +236,7 @@ func RecipeDownloadURLs(ctx *context.Context) { // PackageDownloadURLs displays the package files with their download url func PackageDownloadURLs(ctx *context.Context) { - pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference) + pref := getPackageReference(ctx) serveDownloadURLs( ctx, @@ -238,7 +246,7 @@ func PackageDownloadURLs(ctx *context.Context) { } func serveDownloadURLs(ctx *context.Context, fileKey, downloadURL string) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version) if err != nil { @@ -274,7 +282,7 @@ func serveDownloadURLs(ctx *context.Context, fileKey, downloadURL string) { // RecipeUploadURLs displays the upload urls for the provided recipe files func RecipeUploadURLs(ctx *context.Context) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) serveUploadURLs( ctx, @@ -285,7 +293,7 @@ func RecipeUploadURLs(ctx *context.Context) { // PackageUploadURLs displays the upload urls for the provided package files func PackageUploadURLs(ctx *context.Context) { - pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference) + pref := getPackageReference(ctx) serveUploadURLs( ctx, @@ -315,21 +323,21 @@ func serveUploadURLs(ctx *context.Context, fileFilter container.Set[string], upl // UploadRecipeFile handles the upload of a recipe file func UploadRecipeFile(ctx *context.Context) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) uploadFile(ctx, recipeFileList, rref.AsKey()) } // UploadPackageFile handles the upload of a package file func UploadPackageFile(ctx *context.Context) { - pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference) + pref := getPackageReference(ctx) uploadFile(ctx, packageFileList, pref.AsKey()) } func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey string) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) - pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference) + rref := getRecipeReference(ctx) + pref := getPackageReference(ctx) filename := ctx.PathParam("filename") if !fileFilter.Contains(filename) { @@ -454,20 +462,20 @@ func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey // DownloadRecipeFile serves the content of the requested recipe file func DownloadRecipeFile(ctx *context.Context) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) downloadFile(ctx, recipeFileList, rref.AsKey()) } // DownloadPackageFile serves the content of the requested package file func DownloadPackageFile(ctx *context.Context) { - pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference) + pref := getPackageReference(ctx) downloadFile(ctx, packageFileList, pref.AsKey()) } func downloadFile(ctx *context.Context, fileFilter container.Set[string], fileKey string) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) filename := ctx.PathParam("filename") if !fileFilter.Contains(filename) { @@ -503,7 +511,7 @@ func downloadFile(ctx *context.Context, fileFilter container.Set[string], fileKe // DeleteRecipeV1 deletes the requested recipe(s) func DeleteRecipeV1(ctx *context.Context) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) if err := deleteRecipeOrPackage(ctx, rref, true, nil, false); err != nil { if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, conan_model.ErrPackageReferenceNotExist) { @@ -518,7 +526,7 @@ func DeleteRecipeV1(ctx *context.Context) { // DeleteRecipeV2 deletes the requested recipe(s) respecting its revisions func DeleteRecipeV2(ctx *context.Context) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) if err := deleteRecipeOrPackage(ctx, rref, rref.Revision == "", nil, false); err != nil { if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, conan_model.ErrPackageReferenceNotExist) { @@ -533,7 +541,7 @@ func DeleteRecipeV2(ctx *context.Context) { // DeletePackageV1 deletes the requested package(s) func DeletePackageV1(ctx *context.Context) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) type PackageReferences struct { References []string `json:"package_ids"` @@ -582,8 +590,8 @@ func DeletePackageV1(ctx *context.Context) { // DeletePackageV2 deletes the requested package(s) respecting its revisions func DeletePackageV2(ctx *context.Context) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) - pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference) + rref := getRecipeReference(ctx) + pref := getPackageReference(ctx) if pref != nil { // has package reference if err := deleteRecipeOrPackage(ctx, rref, false, pref, pref.Revision == ""); err != nil { @@ -693,7 +701,7 @@ func deleteRecipeOrPackage(apictx *context.Context, rref *conan_module.RecipeRef // ListRecipeRevisions gets a list of all recipe revisions func ListRecipeRevisions(ctx *context.Context) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) revisions, err := conan_model.GetRecipeRevisions(ctx, ctx.Package.Owner.ID, rref) if err != nil { @@ -706,7 +714,7 @@ func ListRecipeRevisions(ctx *context.Context) { // ListPackageRevisions gets a list of all package revisions func ListPackageRevisions(ctx *context.Context) { - pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference) + pref := getPackageReference(ctx) revisions, err := conan_model.GetPackageRevisions(ctx, ctx.Package.Owner.ID, pref) if err != nil { @@ -742,7 +750,7 @@ func listRevisions(ctx *context.Context, revisions []*conan_model.PropertyValue) // LatestRecipeRevision gets the latest recipe revision func LatestRecipeRevision(ctx *context.Context) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) revision, err := conan_model.GetLastRecipeRevision(ctx, ctx.Package.Owner.ID, rref) if err != nil { @@ -759,7 +767,7 @@ func LatestRecipeRevision(ctx *context.Context) { // LatestPackageRevision gets the latest package revision func LatestPackageRevision(ctx *context.Context) { - pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference) + pref := getPackageReference(ctx) revision, err := conan_model.GetLastPackageRevision(ctx, ctx.Package.Owner.ID, pref) if err != nil { @@ -776,20 +784,20 @@ func LatestPackageRevision(ctx *context.Context) { // ListRecipeRevisionFiles gets a list of all recipe revision files func ListRecipeRevisionFiles(ctx *context.Context) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) listRevisionFiles(ctx, rref.AsKey()) } // ListPackageRevisionFiles gets a list of all package revision files func ListPackageRevisionFiles(ctx *context.Context) { - pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference) + pref := getPackageReference(ctx) listRevisionFiles(ctx, pref.AsKey()) } func listRevisionFiles(ctx *context.Context, fileKey string) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version) if err != nil { diff --git a/routers/api/packages/conan/search.go b/routers/api/packages/conan/search.go index f816ab09d7..a7ae16f597 100644 --- a/routers/api/packages/conan/search.go +++ b/routers/api/packages/conan/search.go @@ -72,7 +72,7 @@ func SearchPackagesV2(ctx *context.Context) { } func searchPackages(ctx *context.Context, searchAllRevisions bool) { - rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) + rref := getRecipeReference(ctx) if !searchAllRevisions && rref.Revision == "" { lastRevision, err := conan_model.GetLastRecipeRevision(ctx, ctx.Package.Owner.ID, rref) diff --git a/routers/api/packages/conda/conda.go b/routers/api/packages/conda/conda.go index f6d3be5362..48cb85192b 100644 --- a/routers/api/packages/conda/conda.go +++ b/routers/api/packages/conda/conda.go @@ -138,7 +138,7 @@ func EnumeratePackages(ctx *context.Context) { return } - versionMetadata := pd.Metadata.(*conda_module.VersionMetadata) + versionMetadata := packages_model.DescriptorMetadata[*conda_module.VersionMetadata](pd) pi := &PackageInfo{ Name: pd.PackageProperties.GetByName(conda_module.PropertyName), diff --git a/routers/api/packages/cran/cran.go b/routers/api/packages/cran/cran.go index 57c94f0aae..13357661ff 100644 --- a/routers/api/packages/cran/cran.go +++ b/routers/api/packages/cran/cran.go @@ -93,7 +93,7 @@ func enumeratePackages(ctx *context.Context, format string, opts *cran_model.Sea } } - metadata := pd.Metadata.(*cran_module.Metadata) + metadata := packages_model.DescriptorMetadata[*cran_module.Metadata](pd) fmt.Fprintln(w, "Package:", pd.Package.Name) fmt.Fprintln(w, "Version:", pd.Version.Version) diff --git a/routers/api/packages/npm/api.go b/routers/api/packages/npm/api.go index 588cfb4df6..20da866034 100644 --- a/routers/api/packages/npm/api.go +++ b/routers/api/packages/npm/api.go @@ -45,7 +45,7 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac latest := pds[len(pds)-1] - metadata := latest.Metadata.(*npm_module.Metadata) + metadata := packages_model.DescriptorMetadata[*npm_module.Metadata](latest) return &npm_module.PackageMetadata{ ID: latest.Package.Name, @@ -67,7 +67,7 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac func createPackageMetadataVersion(registryURL string, pd *packages_model.PackageDescriptor) *npm_module.PackageMetadataVersion { hashBytes, _ := hex.DecodeString(pd.Files[0].Blob.HashSHA512) - metadata := pd.Metadata.(*npm_module.Metadata) + metadata := packages_model.DescriptorMetadata[*npm_module.Metadata](pd) return &npm_module.PackageMetadataVersion{ ID: fmt.Sprintf("%s@%s", pd.Package.Name, pd.Version.Version), @@ -107,7 +107,7 @@ func createPackageMetadataVersion(registryURL string, pd *packages_model.Package func createPackageSearchResponse(pds []*packages_model.PackageDescriptor, total int64) *npm_module.PackageSearch { objects := make([]*npm_module.PackageSearchObject, 0, len(pds)) for _, pd := range pds { - metadata := pd.Metadata.(*npm_module.Metadata) + metadata := packages_model.DescriptorMetadata[*npm_module.Metadata](pd) scope := metadata.Scope if scope == "" { diff --git a/routers/api/packages/nuget/api_v2.go b/routers/api/packages/nuget/api_v2.go index 120c9c63fc..b011bb1cda 100644 --- a/routers/api/packages/nuget/api_v2.go +++ b/routers/api/packages/nuget/api_v2.go @@ -332,12 +332,8 @@ func createFeedResponse(l *linkBuilder, totalEntries int64, pds []*packages_mode } } -func createEntryResponse(l *linkBuilder, pd *packages_model.PackageDescriptor) *FeedEntry { - return createEntry(l, pd, true) -} - func createEntry(l *linkBuilder, pd *packages_model.PackageDescriptor, withNamespace bool) *FeedEntry { - metadata := pd.Metadata.(*nuget_module.Metadata) + metadata := packages_model.DescriptorMetadata[*nuget_module.Metadata](pd) id := l.GetPackageMetadataURL(pd.Package.Name, pd.Version.Version) diff --git a/routers/api/packages/nuget/api_v3.go b/routers/api/packages/nuget/api_v3.go index e401cdc99b..5650d9a22e 100644 --- a/routers/api/packages/nuget/api_v3.go +++ b/routers/api/packages/nuget/api_v3.go @@ -111,7 +111,7 @@ func createRegistrationIndexResponse(l *linkBuilder, pds []*packages_model.Packa } func createRegistrationIndexPageItem(l *linkBuilder, pd *packages_model.PackageDescriptor) *RegistrationIndexPageItem { - metadata := pd.Metadata.(*nuget_module.Metadata) + metadata := packages_model.DescriptorMetadata[*nuget_module.Metadata](pd) return &RegistrationIndexPageItem{ RegistrationLeafURL: l.GetRegistrationLeafURL(pd.Package.Name, pd.Version.Version), @@ -120,7 +120,7 @@ func createRegistrationIndexPageItem(l *linkBuilder, pd *packages_model.PackageD CatalogLeafURL: l.GetRegistrationLeafURL(pd.Package.Name, pd.Version.Version), Authors: metadata.Authors, Copyright: metadata.Copyright, - DependencyGroups: createDependencyGroups(pd), + DependencyGroups: createDependencyGroups(metadata), Description: metadata.Description, IconURL: metadata.IconURL, ID: pd.Package.Name, @@ -139,9 +139,7 @@ func createRegistrationIndexPageItem(l *linkBuilder, pd *packages_model.PackageD } } -func createDependencyGroups(pd *packages_model.PackageDescriptor) []*PackageDependencyGroup { - metadata := pd.Metadata.(*nuget_module.Metadata) - +func createDependencyGroups(metadata *nuget_module.Metadata) []*PackageDependencyGroup { dependencyGroups := make([]*PackageDependencyGroup, 0, len(metadata.Dependencies)) for k, v := range metadata.Dependencies { dependencies := make([]*PackageDependency, 0, len(v)) @@ -172,7 +170,7 @@ type RegistrationLeafResponse struct { func createRegistrationLeafResponse(l *linkBuilder, pd *packages_model.PackageDescriptor) *RegistrationLeafResponse { registrationLeafURL := l.GetRegistrationLeafURL(pd.Package.Name, pd.Version.Version) packageDownloadURL := l.GetPackageDownloadURL(pd.Package.Name, pd.Version.Version) - metadata := pd.Metadata.(*nuget_module.Metadata) + metadata := packages_model.DescriptorMetadata[*nuget_module.Metadata](pd) return &RegistrationLeafResponse{ RegistrationLeafURL: registrationLeafURL, RegistrationIndexURL: l.GetRegistrationIndexURL(pd.Package.Name), @@ -182,7 +180,7 @@ func createRegistrationLeafResponse(l *linkBuilder, pd *packages_model.PackageDe CatalogLeafURL: registrationLeafURL, Authors: metadata.Authors, Copyright: metadata.Copyright, - DependencyGroups: createDependencyGroups(pd), + DependencyGroups: createDependencyGroups(metadata), Description: metadata.Description, IconURL: metadata.IconURL, ID: pd.Package.Name, @@ -290,13 +288,13 @@ func createSearchResult(l *linkBuilder, pds []*packages_model.PackageDescriptor) }) } - metadata := latest.Metadata.(*nuget_module.Metadata) + metadata := packages_model.DescriptorMetadata[*nuget_module.Metadata](latest) return &SearchResult{ Authors: metadata.Authors, Copyright: metadata.Copyright, Description: metadata.Description, - DependencyGroups: createDependencyGroups(latest), + DependencyGroups: createDependencyGroups(metadata), IconURL: metadata.IconURL, ID: latest.Package.Name, IsPrerelease: latest.Version.IsPrerelease(), diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go index eca255424e..4c3e1f8c8c 100644 --- a/routers/api/packages/nuget/nuget.go +++ b/routers/api/packages/nuget/nuget.go @@ -267,9 +267,10 @@ func RegistrationLeafV2(ctx *context.Context) { return } - resp := createEntryResponse( + resp := createEntry( &linkBuilder{Base: setting.AppURL + "api/packages/" + ctx.Package.Owner.Name + "/nuget"}, pd, + true, ) xmlResponse(ctx, http.StatusOK, resp) diff --git a/routers/api/packages/pub/pub.go b/routers/api/packages/pub/pub.go index 964af3db76..4ca10eaea0 100644 --- a/routers/api/packages/pub/pub.go +++ b/routers/api/packages/pub/pub.go @@ -67,7 +67,7 @@ func packageDescriptorToMetadata(baseURL string, pd *packages_model.PackageDescr Version: pd.Version.Version, ArchiveURL: fmt.Sprintf("%s/files/%s.tar.gz", baseURL, url.PathEscape(pd.Version.Version)), Published: pd.Version.CreatedUnix.AsLocalTime(), - Pubspec: pd.Metadata.(*pub_module.Metadata).Pubspec, + Pubspec: packages_model.DescriptorMetadata[*pub_module.Metadata](pd).Pubspec, } } diff --git a/routers/api/packages/rubygems/rubygems.go b/routers/api/packages/rubygems/rubygems.go index 5754c0e3c3..c78a1dc63a 100644 --- a/routers/api/packages/rubygems/rubygems.go +++ b/routers/api/packages/rubygems/rubygems.go @@ -75,7 +75,7 @@ func enumeratePackages(ctx *context.Context, filename string, pvs []*packages_mo Name: "Gem::Version", Value: []string{p.Version.Version}, }, - p.Metadata.(*rubygems_module.Metadata).Platform, + packages_model.DescriptorMetadata[*rubygems_module.Metadata](p).Platform, }) } @@ -126,7 +126,7 @@ func ServePackageSpecification(ctx *context.Context) { zw := zlib.NewWriter(ctx.Resp) defer zw.Close() - metadata := pd.Metadata.(*rubygems_module.Metadata) + metadata := packages_model.DescriptorMetadata[*rubygems_module.Metadata](pd) // create a Ruby Gem::Specification object spec := &rubygems_module.RubyUserDef{ @@ -405,7 +405,7 @@ func makePackageVersionDependency(ctx *context.Context, version *packages_model. return "", err } - metadata := pd.Metadata.(*rubygems_module.Metadata) + metadata := packages_model.DescriptorMetadata[*rubygems_module.Metadata](pd) fullFilename := makeGemFullFileName(pd.Package.Name, version.Version, metadata.Platform) file, err := packages_model.GetFileForVersionByName(ctx, version.ID, fullFilename, "") if err != nil { diff --git a/routers/api/packages/swift/swift.go b/routers/api/packages/swift/swift.go index e27ece3720..f81cd6e74b 100644 --- a/routers/api/packages/swift/swift.go +++ b/routers/api/packages/swift/swift.go @@ -197,7 +197,7 @@ func PackageVersionMetadata(ctx *context.Context) { return } - metadata := pd.Metadata.(*swift_module.Metadata) + metadata := packages_model.DescriptorMetadata[*swift_module.Metadata](pd) repositoryURLs := make([]string, 0, len(pd.VersionProperties)) for _, property := range pd.VersionProperties { if property.Name == swift_module.PropertyRepositoryURL { @@ -278,7 +278,7 @@ func DownloadManifest(ctx *context.Context) { swiftVersion = swift_module.TrimmedVersionString(v) } } - m, ok := pd.Metadata.(*swift_module.Metadata).Manifests[swiftVersion] + m, ok := packages_model.DescriptorMetadata[*swift_module.Metadata](pd).Manifests[swiftVersion] if !ok { setResponseHeaders(ctx.Resp, &headers{ Status: http.StatusSeeOther, diff --git a/routers/api/packages/vagrant/vagrant.go b/routers/api/packages/vagrant/vagrant.go index 29a81bf531..5f275fcb48 100644 --- a/routers/api/packages/vagrant/vagrant.go +++ b/routers/api/packages/vagrant/vagrant.go @@ -130,7 +130,7 @@ func EnumeratePackageVersions(ctx *context.Context) { ctx.JSON(http.StatusOK, &packageMetadata{ Name: pds[0].Package.Name, - Description: pds[len(pds)-1].Metadata.(*vagrant_module.Metadata).Description, + Description: packages_model.DescriptorMetadata[*vagrant_module.Metadata](pds[len(pds)-1]).Description, Versions: versions, }) } diff --git a/routers/api/v1/admin/cron.go b/routers/api/v1/admin/cron.go index d8fd49feae..58c4875764 100644 --- a/routers/api/v1/admin/cron.go +++ b/routers/api/v1/admin/cron.go @@ -39,7 +39,7 @@ func ListCronTasks(ctx *context.APIContext) { count := len(tasks) listOpts := utils.GetListOptions(ctx) - tasks = util.PaginateSlice(tasks, listOpts.Page, listOpts.PageSize).(cron.TaskTable) + tasks = util.PaginateSlice(tasks, listOpts.Page, listOpts.PageSize) res := make([]structs.Cron, len(tasks)) for i, task := range tasks { diff --git a/routers/api/v1/admin/hooks.go b/routers/api/v1/admin/hooks.go index f70dcff744..1094a02080 100644 --- a/routers/api/v1/admin/hooks.go +++ b/routers/api/v1/admin/hooks.go @@ -137,7 +137,7 @@ func CreateHook(ctx *context.APIContext) { // "201": // "$ref": "#/responses/Hook" - form := web.GetForm(ctx).(*api.CreateHookOption) + form := web.GetForm[*api.CreateHookOption](ctx) utils.AddSystemHook(ctx, form) } @@ -166,7 +166,7 @@ func EditHook(ctx *context.APIContext) { // "200": // "$ref": "#/responses/Hook" - form := web.GetForm(ctx).(*api.EditHookOption) + form := web.GetForm[*api.EditHookOption](ctx) // TODO in body params hookID := ctx.PathParamInt64("id") diff --git a/routers/api/v1/admin/org.go b/routers/api/v1/admin/org.go index 2e1262589d..cab34f5f1e 100644 --- a/routers/api/v1/admin/org.go +++ b/routers/api/v1/admin/org.go @@ -44,7 +44,7 @@ func CreateOrg(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.CreateOrgOption) + form := web.GetForm[*api.CreateOrgOption](ctx) visibility := api.VisibleTypePublic if form.Visibility != "" { diff --git a/routers/api/v1/admin/repo.go b/routers/api/v1/admin/repo.go index 6b280b759b..30d45683a5 100644 --- a/routers/api/v1/admin/repo.go +++ b/routers/api/v1/admin/repo.go @@ -43,7 +43,7 @@ func CreateRepo(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.CreateRepoOption) + form := web.GetForm[*api.CreateRepoOption](ctx) repo.CreateUserRepo(ctx, ctx.ContextUser, *form) } diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index ec0d5eb3ce..9a4508991c 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -75,7 +75,7 @@ func CreateUser(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.CreateUserOption) + form := web.GetForm[*api.CreateUserOption](ctx) u := &user_model.User{ Name: form.Username, @@ -190,7 +190,7 @@ func EditUser(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.EditUserOption) + form := web.GetForm[*api.EditUserOption](ctx) authOpts := &user_service.UpdateAuthOptions{ LoginSource: optional.FromNonDefault(form.SourceID), @@ -340,7 +340,7 @@ func CreatePublicKey(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.CreateKeyOption) + form := web.GetForm[*api.CreateKeyOption](ctx) user.CreateUserPublicKey(ctx, *form, ctx.ContextUser.ID) } @@ -551,7 +551,7 @@ func RenameUser(ctx *context.APIContext) { return } - newName := web.GetForm(ctx).(*api.RenameUserOption).NewName + newName := web.GetForm[*api.RenameUserOption](ctx).NewName // Check if username has been changed if err := user_service.RenameUser(ctx, ctx.ContextUser, newName, ctx.Doer); err != nil { diff --git a/routers/api/v1/admin/user_badge.go b/routers/api/v1/admin/user_badge.go index 97b12d84ef..878b763cdb 100644 --- a/routers/api/v1/admin/user_badge.go +++ b/routers/api/v1/admin/user_badge.go @@ -66,7 +66,7 @@ func AddUserBadges(ctx *context.APIContext) { // "403": // "$ref": "#/responses/forbidden" - form := web.GetForm(ctx).(*api.UserBadgeOption) + form := web.GetForm[*api.UserBadgeOption](ctx) badges := prepareBadgesForReplaceOrAdd(*form) if err := user_model.AddUserBadges(ctx, ctx.ContextUser, badges); err != nil { @@ -102,7 +102,7 @@ func DeleteUserBadges(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.UserBadgeOption) + form := web.GetForm[*api.UserBadgeOption](ctx) badges := prepareBadgesForReplaceOrAdd(*form) if err := user_model.RemoveUserBadges(ctx, ctx.ContextUser, badges); err != nil { diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index d55d8ffdc4..e138528266 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -396,7 +396,7 @@ func reqUsersExploreEnabled() func(ctx *context.APIContext) { func reqBasicOrRevProxyAuth() func(ctx *context.APIContext) { return func(ctx *context.APIContext) { - if ctx.IsSigned && setting.Service.EnableReverseProxyAuthAPI && ctx.Data["AuthedMethod"].(string) == auth.ReverseProxyMethodName { + if ctx.IsSigned && setting.Service.EnableReverseProxyAuthAPI && ctx.Data["AuthedMethod"] == auth.ReverseProxyMethodName { return } if !ctx.IsBasicAuth { diff --git a/routers/api/v1/misc/markup.go b/routers/api/v1/misc/markup.go index 8d3cb96284..cb37941d7f 100644 --- a/routers/api/v1/misc/markup.go +++ b/routers/api/v1/misc/markup.go @@ -33,7 +33,7 @@ func Markup(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.MarkupOption) + form := web.GetForm[*api.MarkupOption](ctx) mode := util.Iif(form.Wiki, "wiki", form.Mode) //nolint:staticcheck // form.Wiki is deprecated common.RenderMarkup(ctx.Base, ctx.Repo, mode, form.Text, form.Context, form.FilePath) } @@ -58,7 +58,7 @@ func Markdown(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.MarkdownOption) + form := web.GetForm[*api.MarkdownOption](ctx) mode := util.Iif(form.Wiki, "wiki", form.Mode) //nolint:staticcheck // form.Wiki is deprecated common.RenderMarkup(ctx.Base, ctx.Repo, mode, form.Text, form.Context, "") } diff --git a/routers/api/v1/org/action.go b/routers/api/v1/org/action.go index 27d80790a1..e90bce5d57 100644 --- a/routers/api/v1/org/action.go +++ b/routers/api/v1/org/action.go @@ -106,7 +106,7 @@ func (Action) CreateOrUpdateSecret(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption) + opt := web.GetForm[*api.CreateOrUpdateSecretOption](ctx) _, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Org.Organization.ID, 0, ctx.PathParam("secretname"), opt.Data, opt.Description) if err != nil { @@ -373,7 +373,7 @@ func (Action) CreateVariable(ctx *context.APIContext) { // "500": // "$ref": "#/responses/error" - opt := web.GetForm(ctx).(*api.CreateVariableOption) + opt := web.GetForm[*api.CreateVariableOption](ctx) ownerID := ctx.Org.Organization.ID variableName := ctx.PathParam("variablename") @@ -437,7 +437,7 @@ func (Action) UpdateVariable(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - opt := web.GetForm(ctx).(*api.UpdateVariableOption) + opt := web.GetForm[*api.UpdateVariableOption](ctx) v, err := actions_service.GetVariable(ctx, actions_model.FindVariablesOpts{ OwnerID: ctx.Org.Organization.ID, diff --git a/routers/api/v1/org/avatar.go b/routers/api/v1/org/avatar.go index 7e6f8a77c9..b6a077df66 100644 --- a/routers/api/v1/org/avatar.go +++ b/routers/api/v1/org/avatar.go @@ -35,7 +35,7 @@ func UpdateAvatar(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.UpdateUserAvatarOption) + form := web.GetForm[*api.UpdateUserAvatarOption](ctx) content, err := base64.StdEncoding.DecodeString(form.Image) if err != nil { diff --git a/routers/api/v1/org/hook.go b/routers/api/v1/org/hook.go index 8d16997d73..cc19781dbc 100644 --- a/routers/api/v1/org/hook.go +++ b/routers/api/v1/org/hook.go @@ -113,7 +113,7 @@ func CreateHook(ctx *context.APIContext) { utils.AddOwnerHook( ctx, ctx.ContextUser, - web.GetForm(ctx).(*api.CreateHookOption), + web.GetForm[*api.CreateHookOption](ctx), ) } @@ -151,7 +151,7 @@ func EditHook(ctx *context.APIContext) { utils.EditOwnerHook( ctx, ctx.ContextUser, - web.GetForm(ctx).(*api.EditHookOption), + web.GetForm[*api.EditHookOption](ctx), ctx.PathParamInt64("id"), ) } diff --git a/routers/api/v1/org/label.go b/routers/api/v1/org/label.go index 443003d5de..f3a19b2913 100644 --- a/routers/api/v1/org/label.go +++ b/routers/api/v1/org/label.go @@ -86,7 +86,7 @@ func CreateLabel(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.CreateLabelOption) + form := web.GetForm[*api.CreateLabelOption](ctx) form.Color = strings.Trim(form.Color, " ") color, err := label.NormalizeColor(form.Color) if err != nil { @@ -189,7 +189,7 @@ func EditLabel(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.EditLabelOption) + form := web.GetForm[*api.EditLabelOption](ctx) l, err := issues_model.GetLabelInOrgByID(ctx, ctx.Org.Organization.ID, ctx.PathParamInt64("id")) if err != nil { if issues_model.IsErrOrgLabelNotExist(err) { diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go index 196b1c0fc9..99a3b64c2d 100644 --- a/routers/api/v1/org/org.go +++ b/routers/api/v1/org/org.go @@ -261,7 +261,7 @@ func Create(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.CreateOrgOption) + form := web.GetForm[*api.CreateOrgOption](ctx) if !ctx.Doer.CanCreateOrganization() { ctx.APIError(http.StatusForbidden, "not allowed to create org") return @@ -358,7 +358,7 @@ func Rename(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.RenameOrgOption) + form := web.GetForm[*api.RenameOrgOption](ctx) orgUser := ctx.Org.Organization.AsUser() if err := user_service.RenameUser(ctx, orgUser, form.NewName, ctx.Doer); err != nil { if user_model.IsErrUserAlreadyExist(err) || db.IsErrNameReserved(err) || db.IsErrNamePatternNotAllowed(err) || db.IsErrNameCharsNotAllowed(err) { @@ -397,7 +397,7 @@ func Edit(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.EditOrgOption) + form := web.GetForm[*api.EditOrgOption](ctx) if err := org.UpdateOrgEmailAddress(ctx, ctx.Org.Organization, form.Email); err != nil { if errors.Is(err, util.ErrInvalidArgument) { diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go index f57b997a15..2c5d91e050 100644 --- a/routers/api/v1/org/team.go +++ b/routers/api/v1/org/team.go @@ -214,7 +214,7 @@ func CreateTeam(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.CreateTeamOption) + form := web.GetForm[*api.CreateTeamOption](ctx) teamPermission := perm.ParseAccessMode(string(form.Permission), perm.AccessModeNone, perm.AccessModeAdmin) team := &organization.Team{ OrgID: ctx.Org.Organization.ID, @@ -282,7 +282,7 @@ func EditTeam(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.EditTeamOption) + form := web.GetForm[*api.EditTeamOption](ctx) team := ctx.Org.Team if err := team.LoadUnits(ctx); err != nil { ctx.APIErrorInternal(err) diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index 90c4aaf2d0..f7baeb0650 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -135,7 +135,7 @@ func (Action) CreateOrUpdateSecret(ctx *context.APIContext) { repo := ctx.Repo.Repository - opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption) + opt := web.GetForm[*api.CreateOrUpdateSecretOption](ctx) _, created, err := secret_service.CreateOrUpdateSecret(ctx, 0, repo.ID, ctx.PathParam("secretname"), opt.Data, opt.Description) if err != nil { @@ -346,7 +346,7 @@ func (Action) CreateVariable(ctx *context.APIContext) { // "500": // "$ref": "#/responses/error" - opt := web.GetForm(ctx).(*api.CreateVariableOption) + opt := web.GetForm[*api.CreateVariableOption](ctx) repoID := ctx.Repo.Repository.ID variableName := ctx.PathParam("variablename") @@ -413,7 +413,7 @@ func (Action) UpdateVariable(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - opt := web.GetForm(ctx).(*api.UpdateVariableOption) + opt := web.GetForm[*api.UpdateVariableOption](ctx) v, err := actions_service.GetVariable(ctx, actions_model.FindVariablesOpts{ RepoID: ctx.Repo.Repository.ID, @@ -1170,7 +1170,7 @@ func ActionsDispatchWorkflow(ctx *context.APIContext) { // "$ref": "#/responses/validationError" workflowID := ctx.PathParam("workflow_id") - opt := web.GetForm(ctx).(*api.CreateActionWorkflowDispatch) + opt := web.GetForm[*api.CreateActionWorkflowDispatch](ctx) if opt.Ref == "" { ctx.APIError(http.StatusUnprocessableEntity, "ref is required parameter") return diff --git a/routers/api/v1/repo/avatar.go b/routers/api/v1/repo/avatar.go index b28358fd21..8a17f2ef2e 100644 --- a/routers/api/v1/repo/avatar.go +++ b/routers/api/v1/repo/avatar.go @@ -40,7 +40,7 @@ func UpdateAvatar(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.UpdateRepoAvatarOption) + form := web.GetForm[*api.UpdateRepoAvatarOption](ctx) content, err := base64.StdEncoding.DecodeString(form.Image) if err != nil { diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 521013541e..758d1cd7f0 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -212,7 +212,7 @@ func CreateBranch(ctx *context.APIContext) { return } - opt := web.GetForm(ctx).(*api.CreateBranchRepoOption) + opt := web.GetForm[*api.CreateBranchRepoOption](ctx) var oldCommit *git.Commit var err error @@ -426,7 +426,7 @@ func UpdateBranch(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - opt := web.GetForm(ctx).(*api.UpdateBranchRepoOption) + opt := web.GetForm[*api.UpdateBranchRepoOption](ctx) branchName := ctx.PathParam("*") repo := ctx.Repo.Repository @@ -443,14 +443,14 @@ func UpdateBranch(ctx *context.APIContext) { // permission check has been done in api.go if err := repo_service.UpdateBranch(ctx, repo, ctx.Repo.GitRepo, ctx.Doer, branchName, opt.NewCommitID, opt.OldCommitID, opt.Force); err != nil { + var errPushRejected *git.ErrPushRejected switch { case git_model.IsErrBranchNotExist(err): ctx.APIErrorNotFound() case errors.Is(err, util.ErrInvalidArgument): ctx.APIError(http.StatusUnprocessableEntity, err.Error()) - case git.IsErrPushRejected(err): - rej := err.(*git.ErrPushRejected) - ctx.APIError(http.StatusForbidden, rej.Message) + case errors.As(err, &errPushRejected): + ctx.APIError(http.StatusForbidden, errPushRejected.Message) default: ctx.APIErrorInternal(err) } @@ -499,7 +499,7 @@ func RenameBranch(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - opt := web.GetForm(ctx).(*api.RenameBranchRepoOption) + opt := web.GetForm[*api.RenameBranchRepoOption](ctx) oldName := ctx.PathParam("*") repo := ctx.Repo.Repository @@ -654,7 +654,7 @@ func CreateBranchProtection(ctx *context.APIContext) { // "423": // "$ref": "#/responses/repoArchivedError" - form := web.GetForm(ctx).(*api.CreateBranchProtectionOption) + form := web.GetForm[*api.CreateBranchProtectionOption](ctx) repo := ctx.Repo.Repository ruleName := form.RuleName @@ -875,7 +875,7 @@ func EditBranchProtection(ctx *context.APIContext) { // "$ref": "#/responses/validationError" // "423": // "$ref": "#/responses/repoArchivedError" - form := web.GetForm(ctx).(*api.EditBranchProtectionOption) + form := web.GetForm[*api.EditBranchProtectionOption](ctx) repo := ctx.Repo.Repository bpName := ctx.PathParam("*") protectBranch, err := git_model.GetProtectedBranchRuleByName(ctx, repo.ID, bpName) @@ -1292,7 +1292,7 @@ func UpdateBranchProtectionPriories(ctx *context.APIContext) { // "$ref": "#/responses/validationError" // "423": // "$ref": "#/responses/repoArchivedError" - form := web.GetForm(ctx).(*api.UpdateBranchProtectionPriories) + form := web.GetForm[*api.UpdateBranchProtectionPriories](ctx) repo := ctx.Repo.Repository if err := git_model.UpdateProtectBranchPriorities(ctx, repo, form.IDs); err != nil { @@ -1331,7 +1331,7 @@ func MergeUpstream(ctx *context.APIContext) { // "$ref": "#/responses/error" // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.MergeUpstreamRequest) + form := web.GetForm[*api.MergeUpstreamRequest](ctx) mergeStyle, err := repo_service.MergeUpstream(ctx, ctx.Doer, ctx.Repo.Repository, form.Branch, form.FfOnly) if err != nil { if errors.Is(err, util.ErrInvalidArgument) { diff --git a/routers/api/v1/repo/collaborators.go b/routers/api/v1/repo/collaborators.go index 07c0b95e09..bf74299f3d 100644 --- a/routers/api/v1/repo/collaborators.go +++ b/routers/api/v1/repo/collaborators.go @@ -162,7 +162,7 @@ func AddOrUpdateCollaborator(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.AddCollaboratorOption) + form := web.GetForm[*api.AddCollaboratorOption](ctx) collaborator, err := user_model.GetUserByName(ctx, ctx.PathParam("collaborator")) if err != nil { diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index 35e6f5ad2d..5f74ba2ad6 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -323,14 +323,19 @@ func base64Reader(s string) (io.ReadSeeker, error) { } func ReqChangeRepoFileOptionsAndCheck(ctx *context.APIContext) { - commonOpts := web.GetForm(ctx).(api.FileOptionsInterface).GetFileOptions() + commonOpts := web.GetForm[api.FileOptionsInterface](ctx).GetFileOptions() commonOpts.BranchName = util.IfZero(commonOpts.BranchName, ctx.Repo.Repository.DefaultBranch) commonOpts.NewBranchName = util.IfZero(commonOpts.NewBranchName, commonOpts.BranchName) if !ctx.Repo.CanWriteToBranch(ctx, ctx.Doer, commonOpts.NewBranchName) && !ctx.IsUserSiteAdmin() { ctx.APIError(http.StatusForbidden, "user should have a permission to write to the target branch") - return } - changeFileOpts := &files_service.ChangeRepoFilesOptions{ +} + +// getAPIChangeRepoFileOptions requires ReqChangeRepoFileOptionsAndCheck to have run, it fills in the branch defaults +func getAPIChangeRepoFileOptions[T api.FileOptionsInterface](ctx *context.APIContext) (apiOpts T, opts *files_service.ChangeRepoFilesOptions) { + apiOpts = web.GetForm[T](ctx) + commonOpts := apiOpts.GetFileOptions() + opts = &files_service.ChangeRepoFilesOptions{ Message: commonOpts.Message, OldBranch: commonOpts.BranchName, NewBranch: commonOpts.NewBranchName, @@ -349,17 +354,13 @@ func ReqChangeRepoFileOptionsAndCheck(ctx *context.APIContext) { }, Signoff: commonOpts.Signoff, } - if changeFileOpts.Dates.Author.IsZero() { - changeFileOpts.Dates.Author = time.Now() + if opts.Dates.Author.IsZero() { + opts.Dates.Author = time.Now() } - if changeFileOpts.Dates.Committer.IsZero() { - changeFileOpts.Dates.Committer = time.Now() + if opts.Dates.Committer.IsZero() { + opts.Dates.Committer = time.Now() } - ctx.Data["__APIChangeRepoFilesOptions"] = changeFileOpts -} - -func getAPIChangeRepoFileOptions[T api.FileOptionsInterface](ctx *context.APIContext) (apiOpts T, opts *files_service.ChangeRepoFilesOptions) { - return web.GetForm(ctx).(T), ctx.Data["__APIChangeRepoFilesOptions"].(*files_service.ChangeRepoFilesOptions) + return apiOpts, opts } // ChangeFiles handles API call for modifying multiple files @@ -574,9 +575,8 @@ func UpdateFile(ctx *context.APIContext) { } func handleChangeRepoFilesError(ctx *context.APIContext, err error) { - if git.IsErrPushRejected(err) { - err := err.(*git.ErrPushRejected) - ctx.APIError(http.StatusForbidden, err.Message) + if errPushRejected, ok := err.(*git.ErrPushRejected); ok { + ctx.APIError(http.StatusForbidden, errPushRejected.Message) return } if files_service.IsErrUserCannotCommit(err) || pull_service.IsErrFilePathProtected(err) { @@ -896,7 +896,12 @@ func GetFileContentsGet(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // The POST method requires "write" permission, so we also support this "GET" method - handleGetFileContents(ctx) + opts := &api.GetFilesOptions{} + if err := json.Unmarshal(util.UnsafeStringToBytes(ctx.FormString("body")), opts); err != nil { + ctx.APIError(http.StatusBadRequest, "invalid body parameter") + return + } + handleGetFileContents(ctx, opts) } func GetFileContentsPost(ctx *context.APIContext) { @@ -940,18 +945,10 @@ func GetFileContentsPost(ctx *context.APIContext) { // This is actually a "read" request, but we need to accept a "files" list, then POST method seems easy to use. // But the permission system requires that the caller must have "write" permission to use POST method. // At the moment, there is no other way to get around the permission check, so there is a "GET" workaround method above. - handleGetFileContents(ctx) + handleGetFileContents(ctx, web.GetForm[*api.GetFilesOptions](ctx)) } -func handleGetFileContents(ctx *context.APIContext) { - opts, ok := web.GetForm(ctx).(*api.GetFilesOptions) - if !ok { - err := json.Unmarshal(util.UnsafeStringToBytes(ctx.FormString("body")), &opts) - if err != nil { - ctx.APIError(http.StatusBadRequest, "invalid body parameter") - return - } - } +func handleGetFileContents(ctx *context.APIContext, opts *api.GetFilesOptions) { refCommit := resolveRefCommit(ctx, ctx.FormTrim("ref")) if ctx.Written() { return diff --git a/routers/api/v1/repo/fork.go b/routers/api/v1/repo/fork.go index 9ca5243631..012e6aacdc 100644 --- a/routers/api/v1/repo/fork.go +++ b/routers/api/v1/repo/fork.go @@ -148,7 +148,7 @@ func CreateFork(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.CreateForkOption) + form := web.GetForm[*api.CreateForkOption](ctx) forkOwner := ctx.Doer // user/org that will own the fork if form.Organization != nil { org := prepareDoerCreateRepoInOrg(ctx, *form.Organization) diff --git a/routers/api/v1/repo/git_hook.go b/routers/api/v1/repo/git_hook.go index 656fa9c9df..eb1bffcc20 100644 --- a/routers/api/v1/repo/git_hook.go +++ b/routers/api/v1/repo/git_hook.go @@ -126,7 +126,7 @@ func EditGitHook(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.EditGitHookOption) + form := web.GetForm[*api.EditGitHookOption](ctx) hookID := ctx.PathParam("id") hook, err := git.GetHook(ctx.Repo.GitRepo, hookID) if err != nil { diff --git a/routers/api/v1/repo/hook.go b/routers/api/v1/repo/hook.go index b3154696b7..a4aafa4f51 100644 --- a/routers/api/v1/repo/hook.go +++ b/routers/api/v1/repo/hook.go @@ -226,7 +226,7 @@ func CreateHook(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - utils.AddRepoHook(ctx, web.GetForm(ctx).(*api.CreateHookOption)) + utils.AddRepoHook(ctx, web.GetForm[*api.CreateHookOption](ctx)) } // EditHook modify a hook of a repository @@ -262,7 +262,7 @@ func EditHook(ctx *context.APIContext) { // "$ref": "#/responses/Hook" // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.EditHookOption) + form := web.GetForm[*api.EditHookOption](ctx) hookID := ctx.PathParamInt64("id") utils.EditRepoHook(ctx, form, hookID) } diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index fe5772fa46..5f19d58103 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -631,7 +631,7 @@ func CreateIssue(ctx *context.APIContext) { // "423": // "$ref": "#/responses/repoArchivedError" - form := web.GetForm(ctx).(*api.CreateIssueOption) + form := web.GetForm[*api.CreateIssueOption](ctx) var deadlineUnix timeutil.TimeStamp if form.Deadline != nil && ctx.Repo.Permission.CanWrite(unit.TypeIssues) { deadlineUnix = timeutil.TimeStamp(form.Deadline.Unix()) @@ -759,7 +759,7 @@ func EditIssue(ctx *context.APIContext) { // "412": // "$ref": "#/responses/error" - form := web.GetForm(ctx).(*api.EditIssueOption) + form := web.GetForm[*api.EditIssueOption](ctx) issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { @@ -1012,7 +1012,7 @@ func UpdateIssueDeadline(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.EditDeadlineOption) + form := web.GetForm[*api.EditDeadlineOption](ctx) issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { diff --git a/routers/api/v1/repo/issue_assignee.go b/routers/api/v1/repo/issue_assignee.go index d045102930..adc0240eee 100644 --- a/routers/api/v1/repo/issue_assignee.go +++ b/routers/api/v1/repo/issue_assignee.go @@ -60,7 +60,7 @@ func AddIssueAssignees(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - opts := web.GetForm(ctx).(*api.IssueAssigneesOption) + opts := web.GetForm[*api.IssueAssigneesOption](ctx) updateIssueAssignees(ctx, *opts, true) } @@ -105,7 +105,7 @@ func DeleteIssueAssignees(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - opts := web.GetForm(ctx).(*api.IssueAssigneesOption) + opts := web.GetForm[*api.IssueAssigneesOption](ctx) updateIssueAssignees(ctx, *opts, false) } diff --git a/routers/api/v1/repo/issue_attachment.go b/routers/api/v1/repo/issue_attachment.go index 123f66399d..77f5898e3f 100644 --- a/routers/api/v1/repo/issue_attachment.go +++ b/routers/api/v1/repo/issue_attachment.go @@ -265,7 +265,7 @@ func EditIssueAttachment(ctx *context.APIContext) { } // do changes to attachment. only meaningful change is name. - form := web.GetForm(ctx).(*api.EditAttachmentOptions) + form := web.GetForm[*api.EditAttachmentOptions](ctx) if form.Name != "" { attachment.Name = form.Name } diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index 6cece7e5ce..92d520dabc 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -379,7 +379,7 @@ func CreateIssueComment(ctx *context.APIContext) { // "423": // "$ref": "#/responses/repoArchivedError" - form := web.GetForm(ctx).(*api.CreateIssueCommentOption) + form := web.GetForm[*api.CreateIssueCommentOption](ctx) issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { ctx.APIErrorInternal(err) @@ -511,7 +511,7 @@ func EditIssueComment(ctx *context.APIContext) { // "423": // "$ref": "#/responses/repoArchivedError" - form := web.GetForm(ctx).(*api.EditIssueCommentOption) + form := web.GetForm[*api.EditIssueCommentOption](ctx) editIssueComment(ctx, *form) } @@ -561,7 +561,7 @@ func EditIssueCommentDeprecated(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.EditIssueCommentOption) + form := web.GetForm[*api.EditIssueCommentOption](ctx) editIssueComment(ctx, *form) } diff --git a/routers/api/v1/repo/issue_comment_attachment.go b/routers/api/v1/repo/issue_comment_attachment.go index 56d494190e..d9cd46ff57 100644 --- a/routers/api/v1/repo/issue_comment_attachment.go +++ b/routers/api/v1/repo/issue_comment_attachment.go @@ -278,7 +278,7 @@ func EditIssueCommentAttachment(ctx *context.APIContext) { return } - form := web.GetForm(ctx).(*api.EditAttachmentOptions) + form := web.GetForm[*api.EditAttachmentOptions](ctx) if form.Name != "" { attach.Name = form.Name } diff --git a/routers/api/v1/repo/issue_dependency.go b/routers/api/v1/repo/issue_dependency.go index ff4e7cd5b4..615eea9a36 100644 --- a/routers/api/v1/repo/issue_dependency.go +++ b/routers/api/v1/repo/issue_dependency.go @@ -183,7 +183,7 @@ func CreateIssueDependency(ctx *context.APIContext) { } // and
    represents the dependency - form := web.GetForm(ctx).(*api.IssueMeta) + form := web.GetForm[*api.IssueMeta](ctx) dependency := getFormIssue(ctx, form) if ctx.Written() { return @@ -244,7 +244,7 @@ func RemoveIssueDependency(ctx *context.APIContext) { } // and represents the dependency - form := web.GetForm(ctx).(*api.IssueMeta) + form := web.GetForm[*api.IssueMeta](ctx) dependency := getFormIssue(ctx, form) if ctx.Written() { return @@ -404,7 +404,7 @@ func CreateIssueBlocking(ctx *context.APIContext) { return } - form := web.GetForm(ctx).(*api.IssueMeta) + form := web.GetForm[*api.IssueMeta](ctx) target := getFormIssue(ctx, form) if ctx.Written() { return @@ -461,7 +461,7 @@ func RemoveIssueBlocking(ctx *context.APIContext) { return } - form := web.GetForm(ctx).(*api.IssueMeta) + form := web.GetForm[*api.IssueMeta](ctx) target := getFormIssue(ctx, form) if ctx.Written() { return diff --git a/routers/api/v1/repo/issue_label.go b/routers/api/v1/repo/issue_label.go index 5f8f3cabae..a61f604e85 100644 --- a/routers/api/v1/repo/issue_label.go +++ b/routers/api/v1/repo/issue_label.go @@ -103,7 +103,7 @@ func AddIssueLabels(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.IssueLabelsOption) + form := web.GetForm[*api.IssueLabelsOption](ctx) issue, labels, err := prepareForReplaceOrAdd(ctx, *form) if err != nil { return @@ -232,7 +232,7 @@ func ReplaceIssueLabels(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.IssueLabelsOption) + form := web.GetForm[*api.IssueLabelsOption](ctx) issue, labels, err := prepareForReplaceOrAdd(ctx, *form) if err != nil { return diff --git a/routers/api/v1/repo/issue_lock.go b/routers/api/v1/repo/issue_lock.go index 2a4f75a937..14f2768fe3 100644 --- a/routers/api/v1/repo/issue_lock.go +++ b/routers/api/v1/repo/issue_lock.go @@ -50,7 +50,7 @@ func LockIssue(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - reason := web.GetForm(ctx).(*api.LockIssueOption).Reason + reason := web.GetForm[*api.LockIssueOption](ctx).Reason issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { ctx.APIErrorAuto(err) diff --git a/routers/api/v1/repo/issue_reaction.go b/routers/api/v1/repo/issue_reaction.go index 6ad44ead61..a3539af798 100644 --- a/routers/api/v1/repo/issue_reaction.go +++ b/routers/api/v1/repo/issue_reaction.go @@ -135,7 +135,7 @@ func PostIssueCommentReaction(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.EditReactionOption) + form := web.GetForm[*api.EditReactionOption](ctx) changeIssueCommentReaction(ctx, *form, true) } @@ -178,7 +178,7 @@ func DeleteIssueCommentReaction(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.EditReactionOption) + form := web.GetForm[*api.EditReactionOption](ctx) changeIssueCommentReaction(ctx, *form, false) } @@ -364,7 +364,7 @@ func PostIssueReaction(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.EditReactionOption) + form := web.GetForm[*api.EditReactionOption](ctx) changeIssueReaction(ctx, *form, true) } @@ -405,7 +405,7 @@ func DeleteIssueReaction(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.EditReactionOption) + form := web.GetForm[*api.EditReactionOption](ctx) changeIssueReaction(ctx, *form, false) } diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go index 58ff827ea9..6adb8f9367 100644 --- a/routers/api/v1/repo/issue_tracked_time.go +++ b/routers/api/v1/repo/issue_tracked_time.go @@ -199,7 +199,7 @@ func AddTime(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.AddTimeOption) + form := web.GetForm[*api.AddTimeOption](ctx) issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { ctx.APIErrorAuto(err) diff --git a/routers/api/v1/repo/key.go b/routers/api/v1/repo/key.go index b704bcee1d..0104fd4011 100644 --- a/routers/api/v1/repo/key.go +++ b/routers/api/v1/repo/key.go @@ -231,7 +231,7 @@ func CreateDeployKey(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.CreateKeyOption) + form := web.GetForm[*api.CreateKeyOption](ctx) content, err := asymkey_model.CheckPublicKeyString(form.Key) if err != nil { HandleCheckKeyStringError(ctx, err) diff --git a/routers/api/v1/repo/label.go b/routers/api/v1/repo/label.go index cef0dfdfb1..9ce52de6dd 100644 --- a/routers/api/v1/repo/label.go +++ b/routers/api/v1/repo/label.go @@ -145,7 +145,7 @@ func CreateLabel(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.CreateLabelOption) + form := web.GetForm[*api.CreateLabelOption](ctx) color, err := label.NormalizeColor(form.Color) if err != nil { @@ -207,7 +207,7 @@ func EditLabel(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.EditLabelOption) + form := web.GetForm[*api.EditLabelOption](ctx) l, err := issues_model.GetLabelInRepoByID(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("id")) if err != nil { ctx.APIErrorAuto(err) diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index 0e3e68d1e8..38f6cf20e5 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -56,7 +56,7 @@ func Migrate(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.MigrateRepoOptions) + form := web.GetForm[*api.MigrateRepoOptions](ctx) // get repoOwner var ( @@ -217,6 +217,11 @@ func Migrate(ctx *context.APIContext) { } func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, err error) { + var ( + errNameReserved db.ErrNameReserved + errNameCharsNotAllowed db.ErrNameCharsNotAllowed + errNamePatternNotAllowed db.ErrNamePatternNotAllowed + ) switch { case repo_model.IsErrRepoAlreadyExist(err): ctx.APIError(http.StatusConflict, "The repository with the same name already exists.") @@ -228,12 +233,12 @@ func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, err ctx.APIError(http.StatusUnprocessableEntity, "Remote visit required two factors authentication.") case repo_model.IsErrReachLimitOfRepo(err): ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("You have already reached your limit of %d repositories.", repoOwner.MaxCreationLimit())) - case db.IsErrNameReserved(err): - ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("The username '%s' is reserved.", err.(db.ErrNameReserved).Name)) - case db.IsErrNameCharsNotAllowed(err): - ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("The username '%s' contains invalid characters.", err.(db.ErrNameCharsNotAllowed).Name)) - case db.IsErrNamePatternNotAllowed(err): - ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("The pattern '%s' is not allowed in a username.", err.(db.ErrNamePatternNotAllowed).Pattern)) + case errors.As(err, &errNameReserved): + ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("The username '%s' is reserved.", errNameReserved.Name)) + case errors.As(err, &errNameCharsNotAllowed): + ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("The username '%s' contains invalid characters.", errNameCharsNotAllowed.Name)) + case errors.As(err, &errNamePatternNotAllowed): + ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("The pattern '%s' is not allowed in a username.", errNamePatternNotAllowed.Pattern)) case git.IsErrInvalidCloneAddr(err): ctx.APIError(http.StatusUnprocessableEntity, err.Error()) case base.IsErrNotSupported(err): @@ -253,8 +258,7 @@ func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, err } func handleRemoteAddrError(ctx *context.APIContext, err error) { - if git.IsErrInvalidCloneAddr(err) { - addrErr := err.(*git.ErrInvalidCloneAddr) + if addrErr, ok := err.(*git.ErrInvalidCloneAddr); ok { switch { case addrErr.IsURLError: ctx.APIError(http.StatusUnprocessableEntity, "The provided URL is invalid.") diff --git a/routers/api/v1/repo/milestone.go b/routers/api/v1/repo/milestone.go index 8d325a9021..2b19d43b88 100644 --- a/routers/api/v1/repo/milestone.go +++ b/routers/api/v1/repo/milestone.go @@ -147,7 +147,7 @@ func CreateMilestone(ctx *context.APIContext) { // "$ref": "#/responses/Milestone" // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.CreateMilestoneOption) + form := web.GetForm[*api.CreateMilestoneOption](ctx) var deadlineUnix int64 if form.Deadline != nil { @@ -207,7 +207,7 @@ func EditMilestone(ctx *context.APIContext) { // "$ref": "#/responses/Milestone" // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.EditMilestoneOption) + form := web.GetForm[*api.EditMilestoneOption](ctx) milestone := getMilestoneByIDOrName(ctx) if ctx.Written() { return diff --git a/routers/api/v1/repo/mirror.go b/routers/api/v1/repo/mirror.go index c76946493a..c870ee18fc 100644 --- a/routers/api/v1/repo/mirror.go +++ b/routers/api/v1/repo/mirror.go @@ -291,7 +291,7 @@ func AddPushMirror(ctx *context.APIContext) { return } - pushMirror := web.GetForm(ctx).(*api.CreatePushMirrorOption) + pushMirror := web.GetForm[*api.CreatePushMirrorOption](ctx) CreatePushMirror(ctx, pushMirror) } @@ -403,8 +403,7 @@ func CreatePushMirror(ctx *context.APIContext, mirrorOption *api.CreatePushMirro } func HandleRemoteAddressError(ctx *context.APIContext, err error) { - if git.IsErrInvalidCloneAddr(err) { - addrErr := err.(*git.ErrInvalidCloneAddr) + if addrErr, ok := err.(*git.ErrInvalidCloneAddr); ok { switch { case addrErr.IsProtocolInvalid: ctx.APIError(http.StatusBadRequest, "Invalid mirror protocol") diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index cbc7caa1f3..a77226e3bf 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -404,7 +404,7 @@ func CreatePullRequest(ctx *context.APIContext) { // "423": // "$ref": "#/responses/repoArchivedError" - form := *web.GetForm(ctx).(*api.CreatePullRequestOption) + form := *web.GetForm[*api.CreatePullRequestOption](ctx) if form.Head == form.Base { ctx.APIError(http.StatusUnprocessableEntity, "Invalid PullRequest: There are no changes between the head and the base") return @@ -628,7 +628,7 @@ func EditPullRequest(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.EditPullRequestOption) + form := web.GetForm[*api.EditPullRequestOption](ctx) pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { if issues_model.IsErrPullRequestNotExist(err) { @@ -922,7 +922,7 @@ func MergePullRequest(ctx *context.APIContext) { // "423": // "$ref": "#/responses/repoArchivedError" - form := web.GetForm(ctx).(*forms.MergePullRequestForm) + form := web.GetForm[*forms.MergePullRequestForm](ctx) pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { @@ -1044,21 +1044,17 @@ func MergePullRequest(ctx *context.APIContext) { if err := pull_service.Merge(ctx, pr, ctx.Doer, repo_model.MergeStyle(form.Do), form.HeadCommitID, message, false); err != nil { if pull_service.IsErrInvalidMergeStyle(err) { ctx.APIError(http.StatusMethodNotAllowed, fmt.Sprintf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do))) - } else if pull_service.IsErrMergeConflicts(err) { - conflictError := err.(pull_service.ErrMergeConflicts) + } else if conflictError, ok := err.(pull_service.ErrMergeConflicts); ok { ctx.JSON(http.StatusConflict, conflictError) - } else if pull_service.IsErrRebaseConflicts(err) { - conflictError := err.(pull_service.ErrRebaseConflicts) + } else if conflictError, ok := err.(pull_service.ErrRebaseConflicts); ok { ctx.JSON(http.StatusConflict, conflictError) - } else if pull_service.IsErrMergeUnrelatedHistories(err) { - conflictError := err.(pull_service.ErrMergeUnrelatedHistories) + } else if conflictError, ok := err.(pull_service.ErrMergeUnrelatedHistories); ok { ctx.JSON(http.StatusConflict, conflictError) } else if git.IsErrPushOutOfDate(err) { ctx.APIError(http.StatusConflict, "merge push out of date") } else if pull_service.IsErrSHADoesNotMatch(err) { ctx.APIError(http.StatusConflict, "head out of date") - } else if git.IsErrPushRejected(err) { - errPushRej := err.(*git.ErrPushRejected) + } else if errPushRej, ok := err.(*git.ErrPushRejected); ok { if len(errPushRej.Message) == 0 { ctx.APIError(http.StatusConflict, "PushRejected without remote error message") } else { diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go index 18ab857de8..a9dcde7f6d 100644 --- a/routers/api/v1/repo/pull_review.go +++ b/routers/api/v1/repo/pull_review.go @@ -252,7 +252,7 @@ func CreatePullReviewCommentReply(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - opts := web.GetForm(ctx).(*api.CreatePullReviewCommentReplyOptions) + opts := web.GetForm[*api.CreatePullReviewCommentReplyOptions](ctx) parent := getPullReviewCommentToResolve(ctx) if parent == nil { @@ -499,7 +499,7 @@ func CreatePullReview(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - opts := web.GetForm(ctx).(*api.CreatePullReviewOptions) + opts := web.GetForm[*api.CreatePullReviewOptions](ctx) pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { ctx.APIErrorAuto(err) @@ -622,7 +622,7 @@ func SubmitPullReview(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - opts := web.GetForm(ctx).(*api.SubmitPullReviewOptions) + opts := web.GetForm[*api.SubmitPullReviewOptions](ctx) review, pr, isWrong := prepareSingleReview(ctx) if isWrong { return @@ -792,7 +792,7 @@ func CreateReviewRequests(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - opts := web.GetForm(ctx).(*api.PullReviewRequestOptions) + opts := web.GetForm[*api.PullReviewRequestOptions](ctx) apiReviewRequest(ctx, *opts, true) } @@ -834,7 +834,7 @@ func DeleteReviewRequests(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" - opts := web.GetForm(ctx).(*api.PullReviewRequestOptions) + opts := web.GetForm[*api.PullReviewRequestOptions](ctx) apiReviewRequest(ctx, *opts, false) } @@ -1014,7 +1014,7 @@ func DismissPullReview(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/validationError" - opts := web.GetForm(ctx).(*api.DismissPullReviewOptions) + opts := web.GetForm[*api.DismissPullReviewOptions](ctx) dismissReview(ctx, opts.Message, true, opts.Priors) } diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go index d6f3576f31..96aa0ce258 100644 --- a/routers/api/v1/repo/release.go +++ b/routers/api/v1/repo/release.go @@ -28,7 +28,7 @@ func canAccessReleaseDraft(ctx *context.APIContext) bool { return true } // the request is from an access token with scope - scope := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) + scope := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) //nolint:forcetypeassert // must exist requiredScopes := auth_model.GetRequiredScopes(auth_model.Write, auth_model.AccessTokenScopeCategoryRepository) allow, _ := scope.HasScope(requiredScopes...) // err (invalid token) can be safely ignored return allow @@ -244,7 +244,7 @@ func CreateRelease(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.CreateReleaseOption) + form := web.GetForm[*api.CreateReleaseOption](ctx) if ctx.Repo.Repository.IsEmpty { ctx.APIError(http.StatusUnprocessableEntity, "repo is empty") return @@ -346,7 +346,7 @@ func EditRelease(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.EditReleaseOption) + form := web.GetForm[*api.EditReleaseOption](ctx) id := ctx.PathParamInt64("id") rel, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, id) if err != nil && !repo_model.IsErrReleaseNotExist(err) { diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go index 915ac725b0..ea78305748 100644 --- a/routers/api/v1/repo/release_attachment.go +++ b/routers/api/v1/repo/release_attachment.go @@ -310,7 +310,7 @@ func EditReleaseAttachment(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.EditAttachmentOptions) + form := web.GetForm[*api.EditAttachmentOptions](ctx) // Check if release exists an load release releaseID := ctx.PathParamInt64("id") diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index f42f6c7e8a..0fb3d304dc 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -298,7 +298,7 @@ func Create(ctx *context.APIContext) { // description: The repository with the same name already exists. // "422": // "$ref": "#/responses/validationError" - opt := web.GetForm(ctx).(*api.CreateRepoOption) + opt := web.GetForm[*api.CreateRepoOption](ctx) if ctx.Doer.IsOrganization() { // Shouldn't reach this condition, but just in case. ctx.APIError(http.StatusUnprocessableEntity, "not allowed creating repository for organization") @@ -342,7 +342,7 @@ func Generate(ctx *context.APIContext) { // description: The repository with the same name already exists. // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.GenerateRepoOption) + form := web.GetForm[*api.GenerateRepoOption](ctx) if !ctx.Repo.Repository.IsTemplate { ctx.APIError(http.StatusUnprocessableEntity, "this is not a template repo") @@ -484,7 +484,7 @@ func CreateOrgRepo(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "403": // "$ref": "#/responses/forbidden" - opt := web.GetForm(ctx).(*api.CreateRepoOption) + opt := web.GetForm[*api.CreateRepoOption](ctx) orgName := ctx.PathParam("org") org := prepareDoerCreateRepoInOrg(ctx, orgName) if ctx.Written() { @@ -603,7 +603,7 @@ func Edit(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - opts := *web.GetForm(ctx).(*api.EditRepoOption) + opts := *web.GetForm[*api.EditRepoOption](ctx) if err := updateBasicProperties(ctx, opts); err != nil { return diff --git a/routers/api/v1/repo/status.go b/routers/api/v1/repo/status.go index c7d7014e54..2fdbe3daa5 100644 --- a/routers/api/v1/repo/status.go +++ b/routers/api/v1/repo/status.go @@ -52,7 +52,7 @@ func NewCommitStatus(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - form := web.GetForm(ctx).(*api.CreateStatusOption) + form := web.GetForm[*api.CreateStatusOption](ctx) sha := ctx.PathParam("sha") if len(sha) == 0 { ctx.APIError(http.StatusBadRequest, "sha not provided") diff --git a/routers/api/v1/repo/tag.go b/routers/api/v1/repo/tag.go index 5acdc72e98..0d4d4553b4 100644 --- a/routers/api/v1/repo/tag.go +++ b/routers/api/v1/repo/tag.go @@ -194,7 +194,7 @@ func CreateTag(ctx *context.APIContext) { // "$ref": "#/responses/validationError" // "423": // "$ref": "#/responses/repoArchivedError" - form := web.GetForm(ctx).(*api.CreateTagOption) + form := web.GetForm[*api.CreateTagOption](ctx) // If target is not provided use default branch if len(form.Target) == 0 { @@ -411,7 +411,7 @@ func CreateTagProtection(ctx *context.APIContext) { // "423": // "$ref": "#/responses/repoArchivedError" - form := web.GetForm(ctx).(*api.CreateTagProtectionOption) + form := web.GetForm[*api.CreateTagProtectionOption](ctx) repo := ctx.Repo.Repository namePattern := strings.TrimSpace(form.NamePattern) @@ -522,7 +522,7 @@ func EditTagProtection(ctx *context.APIContext) { // "$ref": "#/responses/repoArchivedError" repo := ctx.Repo.Repository - form := web.GetForm(ctx).(*api.EditTagProtectionOption) + form := web.GetForm[*api.EditTagProtectionOption](ctx) id := ctx.PathParamInt64("id") pt, err := git_model.GetProtectedTagByID(ctx, id) diff --git a/routers/api/v1/repo/topic.go b/routers/api/v1/repo/topic.go index 00fef50595..7d2dcc39cf 100644 --- a/routers/api/v1/repo/topic.go +++ b/routers/api/v1/repo/topic.go @@ -101,7 +101,7 @@ func UpdateTopics(ctx *context.APIContext) { // "422": // "$ref": "#/responses/invalidTopicsError" - form := web.GetForm(ctx).(*api.RepoTopicOptions) + form := web.GetForm[*api.RepoTopicOptions](ctx) topicNames := form.Topics validTopics, invalidTopics := repo_model.SanitizeAndValidateTopics(topicNames) diff --git a/routers/api/v1/repo/transfer.go b/routers/api/v1/repo/transfer.go index 63fc3b0712..ef05dac65b 100644 --- a/routers/api/v1/repo/transfer.go +++ b/routers/api/v1/repo/transfer.go @@ -56,7 +56,7 @@ func Transfer(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - opts := web.GetForm(ctx).(*api.TransferRepoOption) + opts := web.GetForm[*api.TransferRepoOption](ctx) newOwner, err := user_model.GetUserByName(ctx, opts.NewOwner) if err != nil { diff --git a/routers/api/v1/repo/wiki.go b/routers/api/v1/repo/wiki.go index 5f5fa2f236..0193defaab 100644 --- a/routers/api/v1/repo/wiki.go +++ b/routers/api/v1/repo/wiki.go @@ -55,7 +55,7 @@ func NewWikiPage(ctx *context.APIContext) { // "423": // "$ref": "#/responses/repoArchivedError" - form := web.GetForm(ctx).(*api.CreateWikiPageOptions) + form := web.GetForm[*api.CreateWikiPageOptions](ctx) if util.IsEmptyString(form.Title) { ctx.APIError(http.StatusBadRequest, "title is required") @@ -133,7 +133,7 @@ func EditWikiPage(ctx *context.APIContext) { // "423": // "$ref": "#/responses/repoArchivedError" - form := web.GetForm(ctx).(*api.CreateWikiPageOptions) + form := web.GetForm[*api.CreateWikiPageOptions](ctx) oldWikiName := wiki_service.WebPathFromRequest(ctx.PathParamRaw("pageName")) newWikiName := wiki_service.UserTitleToWebPath("", form.Title) diff --git a/routers/api/v1/shared/project.go b/routers/api/v1/shared/project.go index c037f61fbd..a4e2624c15 100644 --- a/routers/api/v1/shared/project.go +++ b/routers/api/v1/shared/project.go @@ -478,7 +478,7 @@ func CreateProject(ctx *context.APIContext) { // "$ref": "#/responses/validationError" scope := projectScopeFromContext(ctx) - form := web.GetForm(ctx).(*api.CreateProjectOption) + form := web.GetForm[*api.CreateProjectOption](ctx) templateType, err := convert.ProjectTemplateTypeFromString(form.TemplateType) if err != nil { @@ -611,7 +611,7 @@ func EditProject(ctx *context.APIContext) { return } - form := web.GetForm(ctx).(*api.EditProjectOption) + form := web.GetForm[*api.EditProjectOption](ctx) if form.Title != nil && util.IsEmptyString(*form.Title) { ctx.APIError(http.StatusUnprocessableEntity, "title must not be empty") return @@ -951,7 +951,7 @@ func CreateProjectColumn(ctx *context.APIContext) { return } - form := web.GetForm(ctx).(*api.CreateProjectColumnOption) + form := web.GetForm[*api.CreateProjectColumnOption](ctx) column := &project_model.Column{ Title: form.Title, Color: form.Color, @@ -1185,7 +1185,7 @@ func EditProjectColumn(ctx *context.APIContext) { return } - form := web.GetForm(ctx).(*api.EditProjectColumnOption) + form := web.GetForm[*api.EditProjectColumnOption](ctx) if form.Title != nil { if util.IsEmptyString(*form.Title) { ctx.APIError(http.StatusUnprocessableEntity, "title must not be empty") @@ -1529,7 +1529,7 @@ func MoveProjectColumns(ctx *context.APIContext) { return } - form := web.GetForm(ctx).(*api.MoveProjectColumnsOption) + form := web.GetForm[*api.MoveProjectColumnsOption](ctx) columns, err := project_model.GetColumns(ctx, project.ID, db.ListOptionsAll) if err != nil { ctx.APIErrorInternal(err) @@ -2097,7 +2097,7 @@ func MoveProjectIssue(ctx *context.APIContext) { return } - form := web.GetForm(ctx).(*api.MoveProjectIssueOption) + form := web.GetForm[*api.MoveProjectIssueOption](ctx) column, err := project_model.GetColumnByIDAndProjectID(ctx, form.ColumnID, project.ID) if err != nil { if project_model.IsErrProjectColumnNotExist(err) { diff --git a/routers/api/v1/shared/runners.go b/routers/api/v1/shared/runners.go index fbb0262768..ed4341033c 100644 --- a/routers/api/v1/shared/runners.go +++ b/routers/api/v1/shared/runners.go @@ -131,7 +131,7 @@ func UpdateRunner(ctx *context.APIContext, ownerID, repoID, runnerID int64) { return } - form := web.GetForm(ctx).(*api.EditActionRunnerOption) + form := web.GetForm[*api.EditActionRunnerOption](ctx) if form.Disabled == nil { ctx.APIError(http.StatusUnprocessableEntity, "[Disabled]: Required") return diff --git a/routers/api/v1/user/action.go b/routers/api/v1/user/action.go index 4f8754c4ed..38414e4a4d 100644 --- a/routers/api/v1/user/action.go +++ b/routers/api/v1/user/action.go @@ -48,7 +48,7 @@ func CreateOrUpdateSecret(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption) + opt := web.GetForm[*api.CreateOrUpdateSecretOption](ctx) _, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Doer.ID, 0, ctx.PathParam("secretname"), opt.Data, opt.Description) if err != nil { @@ -134,7 +134,7 @@ func CreateVariable(ctx *context.APIContext) { // "409": // description: variable name already exists. - opt := web.GetForm(ctx).(*api.CreateVariableOption) + opt := web.GetForm[*api.CreateVariableOption](ctx) ownerID := ctx.Doer.ID variableName := ctx.PathParam("variablename") @@ -193,7 +193,7 @@ func UpdateVariable(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - opt := web.GetForm(ctx).(*api.UpdateVariableOption) + opt := web.GetForm[*api.UpdateVariableOption](ctx) v, err := actions_service.GetVariable(ctx, actions_model.FindVariablesOpts{ OwnerID: ctx.Doer.ID, diff --git a/routers/api/v1/user/app.go b/routers/api/v1/user/app.go index 444740573e..c7749b0951 100644 --- a/routers/api/v1/user/app.go +++ b/routers/api/v1/user/app.go @@ -98,7 +98,7 @@ func CreateAccessToken(ctx *context.APIContext) { // "403": // "$ref": "#/responses/forbidden" - form := web.GetForm(ctx).(*api.CreateAccessTokenOption) + form := web.GetForm[*api.CreateAccessTokenOption](ctx) t := &auth_model.AccessToken{ UID: ctx.ContextUser.ID, @@ -242,7 +242,7 @@ func CreateOauth2Application(ctx *context.APIContext) { // "400": // "$ref": "#/responses/error" - data := web.GetForm(ctx).(*api.CreateOAuth2ApplicationOptions) + data := web.GetForm[*api.CreateOAuth2ApplicationOptions](ctx) if invalidURI := forms.DetectInvalidOAuth2ApplicationRedirectURI(data.RedirectURIs); invalidURI != "" { ctx.APIError(http.StatusBadRequest, "invalid redirect URI: "+invalidURI) return @@ -406,7 +406,7 @@ func UpdateOauth2Application(ctx *context.APIContext) { // "$ref": "#/responses/notFound" appID := ctx.PathParamInt64("id") - data := web.GetForm(ctx).(*api.CreateOAuth2ApplicationOptions) + data := web.GetForm[*api.CreateOAuth2ApplicationOptions](ctx) if invalidURI := forms.DetectInvalidOAuth2ApplicationRedirectURI(data.RedirectURIs); invalidURI != "" { ctx.APIError(http.StatusBadRequest, "invalid redirect URI: "+invalidURI) return diff --git a/routers/api/v1/user/avatar.go b/routers/api/v1/user/avatar.go index 428ac0f62b..5266cdf71f 100644 --- a/routers/api/v1/user/avatar.go +++ b/routers/api/v1/user/avatar.go @@ -28,7 +28,7 @@ func UpdateAvatar(ctx *context.APIContext) { // responses: // "204": // "$ref": "#/responses/empty" - form := web.GetForm(ctx).(*api.UpdateUserAvatarOption) + form := web.GetForm[*api.UpdateUserAvatarOption](ctx) content, err := base64.StdEncoding.DecodeString(form.Image) if err != nil { diff --git a/routers/api/v1/user/email.go b/routers/api/v1/user/email.go index ea710b01dd..3d92a82dca 100644 --- a/routers/api/v1/user/email.go +++ b/routers/api/v1/user/email.go @@ -63,15 +63,15 @@ func AddEmail(ctx *context.APIContext) { return } - form := web.GetForm(ctx).(*api.CreateEmailOption) + form := web.GetForm[*api.CreateEmailOption](ctx) if len(form.Emails) == 0 { ctx.APIError(http.StatusUnprocessableEntity, "Email list empty") return } if err := user_service.AddEmailAddresses(ctx, ctx.Doer, form.Emails); err != nil { - if user_model.IsErrEmailAlreadyUsed(err) { - ctx.APIError(http.StatusUnprocessableEntity, "Email address has been used: "+err.(user_model.ErrEmailAlreadyUsed).Email) + if errEmailAlreadyUsed, ok := err.(user_model.ErrEmailAlreadyUsed); ok { + ctx.APIError(http.StatusUnprocessableEntity, "Email address has been used: "+errEmailAlreadyUsed.Email) } else if user_model.IsErrEmailCharIsNotSupported(err) || user_model.IsErrEmailInvalid(err) { email := "" if typedError, ok := err.(user_model.ErrEmailInvalid); ok { @@ -125,7 +125,7 @@ func DeleteEmail(ctx *context.APIContext) { return } - form := web.GetForm(ctx).(*api.DeleteEmailOption) + form := web.GetForm[*api.DeleteEmailOption](ctx) if len(form.Emails) == 0 { ctx.Status(http.StatusNoContent) return diff --git a/routers/api/v1/user/gpg_key.go b/routers/api/v1/user/gpg_key.go index 0148c7f5da..bb6f840ec1 100644 --- a/routers/api/v1/user/gpg_key.go +++ b/routers/api/v1/user/gpg_key.go @@ -187,7 +187,7 @@ func VerifyUserGPGKey(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.VerifyGPGKeyOption) + form := web.GetForm[*api.VerifyGPGKeyOption](ctx) token := asymkey_model.VerificationToken(ctx.Doer, 1) lastToken := asymkey_model.VerificationToken(ctx.Doer, 0) @@ -248,7 +248,7 @@ func CreateGPGKey(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.CreateGPGKeyOption) + form := web.GetForm[*api.CreateGPGKeyOption](ctx) CreateUserGPGKey(ctx, *form, ctx.Doer.ID) } diff --git a/routers/api/v1/user/hook.go b/routers/api/v1/user/hook.go index cc0b24a883..008484f1e6 100644 --- a/routers/api/v1/user/hook.go +++ b/routers/api/v1/user/hook.go @@ -97,7 +97,7 @@ func CreateHook(ctx *context.APIContext) { utils.AddOwnerHook( ctx, ctx.Doer, - web.GetForm(ctx).(*api.CreateHookOption), + web.GetForm[*api.CreateHookOption](ctx), ) } @@ -128,7 +128,7 @@ func EditHook(ctx *context.APIContext) { utils.EditOwnerHook( ctx, ctx.Doer, - web.GetForm(ctx).(*api.EditHookOption), + web.GetForm[*api.EditHookOption](ctx), ctx.PathParamInt64("id"), ) } diff --git a/routers/api/v1/user/key.go b/routers/api/v1/user/key.go index c12e98ca4c..4572e9ce8b 100644 --- a/routers/api/v1/user/key.go +++ b/routers/api/v1/user/key.go @@ -243,7 +243,7 @@ func CreatePublicKey(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - form := web.GetForm(ctx).(*api.CreateKeyOption) + form := web.GetForm[*api.CreateKeyOption](ctx) CreateUserPublicKey(ctx, *form, ctx.Doer.ID) } diff --git a/routers/api/v1/user/settings.go b/routers/api/v1/user/settings.go index d9dcb14e93..466372e801 100644 --- a/routers/api/v1/user/settings.go +++ b/routers/api/v1/user/settings.go @@ -43,7 +43,7 @@ func UpdateUserSettings(ctx *context.APIContext) { // "200": // "$ref": "#/responses/UserSettings" - form := web.GetForm(ctx).(*api.UserSettingsOptions) + form := web.GetForm[*api.UserSettingsOptions](ctx) opts := &user_service.UpdateOptions{ FullName: optional.FromPtr(form.FullName), diff --git a/routers/common/auth.go b/routers/common/auth.go index 5aa8925b76..adcc090211 100644 --- a/routers/common/auth.go +++ b/routers/common/auth.go @@ -24,7 +24,7 @@ func AuthShared(ctx *context.Base, sessionStore auth_service.SessionStore, authM if ctx.Locale.Language() != ar.Doer.Language { ctx.Locale = middleware.Locale(ctx.Resp, ctx.Req) } - ar.IsBasicAuth = ctx.Data["AuthedMethod"].(string) == auth_service.BasicMethodName + ar.IsBasicAuth = ctx.Data["AuthedMethod"] == auth_service.BasicMethodName ctx.Data["IsSigned"] = true ctx.Data[middleware.ContextDataKeySignedUser] = ar.Doer diff --git a/routers/common/middleware.go b/routers/common/middleware.go index b750e85ad8..a1ebc25c14 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -95,7 +95,7 @@ func RequestContextHandler() func(h http.Handler) http.Handler { // The "req" might have changed due to the new "req.WithContext" calls // For example: in NewBaseContext, a new "req" with context is created, and the multipart-form is parsed there. // So we always use the latest "req" from the data store. - ctxReq := ds.GetContextValue(httplib.RequestContextKey).(*http.Request) + ctxReq := ds.GetContextValue(httplib.RequestContextKey).(*http.Request) //nolint:forcetypeassert // must be valid if ctxReq.MultipartForm != nil { _ = ctxReq.MultipartForm.RemoveAll() // remove the temp files buffered to tmp directory } diff --git a/routers/install/install.go b/routers/install/install.go index 5f46bc2770..6bf9ae2b5a 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -189,7 +189,7 @@ func SubmitInstall(ctx *context.Context) { var err error - form := *web.GetForm(ctx).(*forms.InstallForm) + form := *web.GetForm[*forms.InstallForm](ctx) // fix form values if form.AppURL != "" && form.AppURL[len(form.AppURL)-1] != '/' { @@ -524,7 +524,7 @@ func SubmitInstall(ctx *context.Context) { // Now get the http.Server from this request and shut it down // NB: This is not our hammerable graceful shutdown this is http.Server.Shutdown - srv := ctx.Value(http.ServerContextKey).(*http.Server) + srv := ctx.Value(http.ServerContextKey).(*http.Server) //nolint:forcetypeassert // must exist if err := srv.Shutdown(graceful.GetManager().HammerContext()); err != nil { log.Error("Unable to shutdown the install server! Error: %v", err) } diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 206c5e1b8b..9d48292a08 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -98,7 +98,7 @@ func hookPostReceiveSyncDatabaseBranches(ctx *gitea_context.PrivateContext, opts // HookPostReceive updates services and users func HookPostReceive(ctx *gitea_context.PrivateContext) { - opts := web.GetForm(ctx).(*private.HookOptions) + opts := web.GetForm[*private.HookOptions](ctx) if opts.IsWiki { setting.PanicInDevOrTesting("wiki hook-post-receive is not supported") return diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index 3f35068347..ae04a93a95 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -107,7 +107,7 @@ func (ctx *preReceiveContext) AssertCreatePullRequest() bool { // HookPreReceive checks whether a individual commit is acceptable func HookPreReceive(ctx *gitea_context.PrivateContext) { - opts := web.GetForm(ctx).(*private.HookOptions) + opts := web.GetForm[*private.HookOptions](ctx) ourCtx := &preReceiveContext{ PrivateContext: ctx, @@ -224,17 +224,17 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r if protectBranch.RequireSignedCommits { err := verifyCommits(ctx, oldCommitID, newCommitID, gitRepo, ctx.env) if err != nil { - if !isErrUnverifiedCommit(err) { + errUnverified, ok := err.(*errUnverifiedCommit) + if !ok { log.Error("Unable to check commits from %s to %s in %-v: %v", oldCommitID, newCommitID, repo, err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: fmt.Sprintf("Unable to check commits from %s to %s: %v", oldCommitID, newCommitID, err), }) return } - unverifiedCommit := err.(*errUnverifiedCommit).sha - log.Warn("Forbidden: Branch: %s in %-v is protected from unverified commit %s", branchName, repo, unverifiedCommit) + log.Warn("Forbidden: Branch: %s in %-v is protected from unverified commit %s", branchName, repo, errUnverified.sha) ctx.JSON(http.StatusForbidden, private.Response{ - UserMsg: fmt.Sprintf("branch %s is protected from unverified commit %s", branchName, unverifiedCommit), + UserMsg: fmt.Sprintf("branch %s is protected from unverified commit %s", branchName, errUnverified.sha), }) return } @@ -250,7 +250,8 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r if len(globs) > 0 { _, err := pull_service.CheckFileProtection(ctx, gitRepo, branchName, oldCommitID, newCommitID, globs, 1, ctx.env) if err != nil { - if !pull_service.IsErrFilePathProtected(err) { + errFilePathProtected, ok := errors.AsType[pull_service.ErrFilePathProtected](err) + if !ok { log.Error("Unable to check file protection for commits from %s to %s in %-v: %v", oldCommitID, newCommitID, repo, err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: fmt.Sprintf("Unable to check file protection for commits from %s to %s: %v", oldCommitID, newCommitID, err), @@ -259,7 +260,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r } changedProtectedfiles = true - protectedFilePath = err.(pull_service.ErrFilePathProtected).Path + protectedFilePath = errFilePathProtected.Path } } diff --git a/routers/private/hook_proc_receive.go b/routers/private/hook_proc_receive.go index 451a738097..4d2b04ee80 100644 --- a/routers/private/hook_proc_receive.go +++ b/routers/private/hook_proc_receive.go @@ -19,7 +19,7 @@ import ( // HookProcReceive proc-receive hook - only handles agit Proc-Receive requests at present func HookProcReceive(ctx *gitea_context.PrivateContext) { - opts := web.GetForm(ctx).(*private.HookOptions) + opts := web.GetForm[*private.HookOptions](ctx) if !git.DefaultFeatures().SupportProcReceive { ctx.Status(http.StatusNotFound) return diff --git a/routers/private/manager.go b/routers/private/manager.go index d2e8c3461b..e1135776d1 100644 --- a/routers/private/manager.go +++ b/routers/private/manager.go @@ -33,7 +33,7 @@ func ReloadTemplates(ctx *context.PrivateContext) { // FlushQueues flushes all the Queues func FlushQueues(ctx *context.PrivateContext) { - opts := web.GetForm(ctx).(*private.FlushOptions) + opts := web.GetForm[*private.FlushOptions](ctx) if opts.NonBlocking { // Save the hammer ctx here - as a new one is created each time you call this. baseCtx := graceful.GetManager().HammerContext() @@ -102,7 +102,7 @@ func RemoveLogger(ctx *context.PrivateContext) { // AddLogger adds a logger func AddLogger(ctx *context.PrivateContext) { - opts := web.GetForm(ctx).(*private.LoggerOptions) + opts := web.GetForm[*private.LoggerOptions](ctx) if len(opts.Logger) == 0 { opts.Logger = log.DEFAULT diff --git a/routers/private/ssh_log.go b/routers/private/ssh_log.go index fe40e0b030..fb32135656 100644 --- a/routers/private/ssh_log.go +++ b/routers/private/ssh_log.go @@ -20,7 +20,7 @@ func SSHLog(ctx *context.PrivateContext) { return } - opts := web.GetForm(ctx).(*private.SSHLogOption) + opts := web.GetForm[*private.SSHLogOption](ctx) if opts.IsError { log.Error("ssh: %v", opts.Message) diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index d4e3015aac..091376504b 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -153,7 +153,7 @@ func SystemStatus(ctx *context.Context) { // DashboardPost run an admin operation func DashboardPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.AdminDashboardForm) + form := web.GetForm[*forms.AdminDashboardForm](ctx) ctx.Data["Title"] = ctx.Tr("admin.dashboard") ctx.Data["PageIsAdminDashboard"] = true updateSystemStatus() diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go index 3ba8c20355..2723ba102c 100644 --- a/routers/web/admin/auths.go +++ b/routers/web/admin/auths.go @@ -235,7 +235,7 @@ func parseSSPIConfig(ctx *context.Context, form forms.AuthenticationForm) (*sspi // NewAuthSourcePost response for adding an auth source func NewAuthSourcePost(ctx *context.Context) { - form := *web.GetForm(ctx).(*forms.AuthenticationForm) + form := *web.GetForm[*forms.AuthenticationForm](ctx) ctx.Data["Title"] = ctx.Tr("admin.auths.new") ctx.Data["PageIsAdminAuthentications"] = true @@ -268,8 +268,8 @@ func NewAuthSourcePost(ctx *context.Context) { EmailDomain: form.PAMEmailDomain, } case auth.OAuth2: - config = parseOAuth2Config(form) - oauth2Config := config.(*oauth2.Source) + oauth2Config := parseOAuth2Config(form) + config = oauth2Config if oauth2Config.Provider == "openidConnect" { discoveryURL, err := url.Parse(oauth2Config.OpenIDConnectAutoDiscoveryURL) if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") { @@ -310,13 +310,12 @@ func NewAuthSourcePost(ctx *context.Context) { TwoFactorPolicy: form.TwoFactorPolicy, Cfg: config, }); err != nil { - if auth.IsErrSourceAlreadyExist(err) { + if errExist, ok := errors.AsType[auth.ErrSourceAlreadyExist](err); ok { ctx.Data["Err_Name"] = true - ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.login_source_exist", err.(auth.ErrSourceAlreadyExist).Name), tplAuthNew, form) - } else if oauth2.IsErrOpenIDConnectInitialize(err) { + ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.login_source_exist", errExist.Name), tplAuthNew, form) + } else if errInit, ok := err.(oauth2.ErrOpenIDConnectInitialize); ok { ctx.Data["Err_DiscoveryURL"] = true - unwrapped := err.(oauth2.ErrOpenIDConnectInitialize).Unwrap() - ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.unable_to_initialize_openid", unwrapped), tplAuthNew, form) + ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.unable_to_initialize_openid", errInit.Unwrap()), tplAuthNew, form) } else { ctx.ServerError("auth.CreateSource", err) } @@ -348,12 +347,9 @@ func EditAuthSource(ctx *context.Context) { ctx.Data["HasTLS"] = source.HasTLS() if source.IsOAuth2() { - type Named interface { - Name() string - } - + oauth2Source := auth.MustSourceCfg[*oauth2.Source](source) for _, provider := range oauth2providers { - if provider.Name() == source.Cfg.(Named).Name() { + if provider.Name() == oauth2Source.Name() { ctx.Data["CurrentOAuth2Provider"] = provider break } @@ -365,7 +361,7 @@ func EditAuthSource(ctx *context.Context) { // EditAuthSourcePost response for editing auth source func EditAuthSourcePost(ctx *context.Context) { - form := *web.GetForm(ctx).(*forms.AuthenticationForm) + form := *web.GetForm[*forms.AuthenticationForm](ctx) ctx.Data["Title"] = ctx.Tr("admin.auths.edit") ctx.Data["PageIsAdminAuthentications"] = true @@ -398,8 +394,8 @@ func EditAuthSourcePost(ctx *context.Context) { EmailDomain: form.PAMEmailDomain, } case auth.OAuth2: - config = parseOAuth2Config(form) - oauth2Config := config.(*oauth2.Source) + oauth2Config := parseOAuth2Config(form) + config = oauth2Config if oauth2Config.Provider == "openidConnect" { discoveryURL, err := url.Parse(oauth2Config.OpenIDConnectAutoDiscoveryURL) if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") { @@ -425,9 +421,9 @@ func EditAuthSourcePost(ctx *context.Context) { source.Cfg = config source.TwoFactorPolicy = form.TwoFactorPolicy if err := auth.UpdateSource(ctx, source); err != nil { - if auth.IsErrSourceAlreadyExist(err) { + if errExist, ok := errors.AsType[auth.ErrSourceAlreadyExist](err); ok { ctx.Data["Err_Name"] = true - ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.login_source_exist", err.(auth.ErrSourceAlreadyExist).Name), tplAuthEdit, form) + ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.login_source_exist", errExist.Name), tplAuthEdit, form) } else if oauth2.IsErrOpenIDConnectInitialize(err) { ctx.Flash.Error(err.Error(), true) ctx.Data["Err_DiscoveryURL"] = true diff --git a/routers/web/admin/badges.go b/routers/web/admin/badges.go index 227e460b10..5880f19e3a 100644 --- a/routers/web/admin/badges.go +++ b/routers/web/admin/badges.go @@ -54,7 +54,7 @@ func NewBadge(ctx *context.Context) { // NewBadgePost response for adding a new badge func NewBadgePost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.AdminCreateBadgeForm) + form := web.GetForm[*forms.AdminCreateBadgeForm](ctx) if ctx.HasError() { ctx.JSONError(ctx.GetErrMsg()) @@ -100,12 +100,11 @@ func ViewBadge(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("admin.badges.details") ctx.Data["PageIsAdminBadges"] = true - prepareBadgeInfo(ctx) + badge := prepareBadgeInfo(ctx) if ctx.Written() { return } - badge := ctx.Data["Badge"].(*user_model.Badge) opts := &user_model.GetBadgeUsersOptions{ ListOptions: db.ListOptions{ Page: 1, @@ -143,7 +142,7 @@ func EditBadgePost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.AdminEditBadgeForm) + form := web.GetForm[*forms.AdminEditBadgeForm](ctx) if ctx.HasError() { ctx.JSONError(ctx.GetErrMsg()) return diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index c4b93202d1..f9ae597527 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -103,7 +103,7 @@ func NewUser(ctx *context.Context) { // NewUserPost response for adding a new user func NewUserPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.AdminCreateUserForm) + form := web.GetForm[*forms.AdminCreateUserForm](ctx) ctx.Data["Title"] = ctx.Tr("admin.users.new_account") ctx.Data["PageIsAdminUsers"] = true ctx.Data["DefaultUserVisibilityMode"] = setting.Service.DefaultUserVisibilityMode @@ -171,6 +171,9 @@ func NewUserPost(ctx *context.Context) { } if err := user_model.AdminCreateUser(ctx, u, &user_model.Meta{}, overwriteDefault); err != nil { + var errNameReserved db.ErrNameReserved + var errNamePatternNotAllowed db.ErrNamePatternNotAllowed + var errNameCharsNotAllowed db.ErrNameCharsNotAllowed switch { case user_model.IsErrUserAlreadyExist(err): ctx.Data["Err_UserName"] = true @@ -181,15 +184,15 @@ func NewUserPost(ctx *context.Context) { case user_model.IsErrEmailInvalid(err), user_model.IsErrEmailCharIsNotSupported(err): ctx.Data["Err_Email"] = true ctx.RenderWithErrDeprecated(ctx.Tr("form.email_invalid"), tplUserNew, &form) - case db.IsErrNameReserved(err): + case errors.As(err, &errNameReserved): ctx.Data["Err_UserName"] = true - ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_reserved", err.(db.ErrNameReserved).Name), tplUserNew, &form) - case db.IsErrNamePatternNotAllowed(err): + ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_reserved", errNameReserved.Name), tplUserNew, &form) + case errors.As(err, &errNamePatternNotAllowed): ctx.Data["Err_UserName"] = true - ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplUserNew, &form) - case db.IsErrNameCharsNotAllowed(err): + ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_pattern_not_allowed", errNamePatternNotAllowed.Pattern), tplUserNew, &form) + case errors.As(err, &errNameCharsNotAllowed): ctx.Data["Err_UserName"] = true - ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_chars_not_allowed", err.(db.ErrNameCharsNotAllowed).Name), tplUserNew, &form) + ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_chars_not_allowed", errNameCharsNotAllowed.Name), tplUserNew, &form) default: ctx.ServerError("CreateUser", err) } @@ -336,7 +339,7 @@ func EditUserPost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.AdminEditUserForm) + form := web.GetForm[*forms.AdminEditUserForm](ctx) if ctx.HasError() { ctx.HTML(http.StatusOK, tplUserEdit) return @@ -522,7 +525,7 @@ func AvatarPost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.AvatarForm) + form := web.GetForm[*forms.AvatarForm](ctx) if err := user_setting.UpdateAvatarSetting(ctx, form, u); err != nil { ctx.Flash.Error(err.Error()) } else { diff --git a/routers/web/auth/2fa.go b/routers/web/auth/2fa.go index 2c031c1227..e4c19c0d9a 100644 --- a/routers/web/auth/2fa.go +++ b/routers/web/auth/2fa.go @@ -41,17 +41,16 @@ func TwoFactor(ctx *context.Context) { // TwoFactorPost validates a user's two-factor authentication token. func TwoFactorPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.TwoFactorAuthForm) + form := web.GetForm[*forms.TwoFactorAuthForm](ctx) ctx.Data["Title"] = ctx.Tr("twofa") // Ensure user is in a 2FA session. - idSess := ctx.Session.Get("twofaUid") - if idSess == nil { + id, hasSession := ctx.Session.Get("twofaUid").(int64) + if !hasSession { ctx.ServerError("UserSignIn", errors.New("not in 2FA session")) return } - id := idSess.(int64) twofa, err := auth.GetTwoFactorByUID(ctx, id) if err != nil { ctx.ServerError("UserSignIn", err) @@ -66,7 +65,7 @@ func TwoFactorPost(ctx *context.Context) { } if ok { - remember := ctx.Session.Get("twofaRemember").(bool) + remember := ctx.Session.Get("twofaRemember").(bool) //nolint:forcetypeassert // must exist u, err := user_model.GetUserByID(ctx, id) if err != nil { ctx.ServerError("UserSignIn", err) @@ -105,17 +104,16 @@ func TwoFactorScratch(ctx *context.Context) { // TwoFactorScratchPost validates and invalidates a user's two-factor scratch token. func TwoFactorScratchPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.TwoFactorScratchAuthForm) + form := web.GetForm[*forms.TwoFactorScratchAuthForm](ctx) ctx.Data["Title"] = ctx.Tr("twofa_scratch") // Ensure user is in a 2FA session. - idSess := ctx.Session.Get("twofaUid") - if idSess == nil { + id, hasSession := ctx.Session.Get("twofaUid").(int64) + if !hasSession { ctx.ServerError("UserSignIn", errors.New("not in 2FA session")) return } - id := idSess.(int64) twofa, err := auth.GetTwoFactorByUID(ctx, id) if err != nil { ctx.ServerError("UserSignIn", err) @@ -135,7 +133,7 @@ func TwoFactorScratchPost(ctx *context.Context) { return } - remember := ctx.Session.Get("twofaRemember").(bool) + remember := ctx.Session.Get("twofaRemember").(bool) //nolint:forcetypeassert // must exist u, err := user_model.GetUserByID(ctx, id) if err != nil { ctx.ServerError("UserSignIn", err) diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 13e0eca8b5..0256424d84 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -293,7 +293,7 @@ func SignInPost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.SignInForm) + form := web.GetForm[*forms.SignInForm](ctx) if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { context.VerifyCaptcha(ctx, tplSignIn, form) @@ -535,7 +535,7 @@ func SignUpPost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.RegisterForm) + form := web.GetForm[*forms.RegisterForm](ctx) // Permission denied if DisableRegistration or AllowOnlyExternalRegistration options are true if setting.Service.DisableRegistration || setting.Service.AllowOnlyExternalRegistration { @@ -651,6 +651,9 @@ func createUserInContext(ctx *context.Context, tpl templates.TplName, form any, } // handle error with template + var errNameReserved db.ErrNameReserved + var errNamePatternNotAllowed db.ErrNamePatternNotAllowed + var errNameCharsNotAllowed db.ErrNameCharsNotAllowed switch { case user_model.IsErrUserAlreadyExist(err): ctx.Data["Err_UserName"] = true @@ -664,15 +667,15 @@ func createUserInContext(ctx *context.Context, tpl templates.TplName, form any, case user_model.IsErrEmailInvalid(err): ctx.Data["Err_Email"] = true ctx.RenderWithErrDeprecated(ctx.Tr("form.email_invalid"), tpl, form) - case db.IsErrNameReserved(err): + case errors.As(err, &errNameReserved): ctx.Data["Err_UserName"] = true - ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_reserved", err.(db.ErrNameReserved).Name), tpl, form) - case db.IsErrNamePatternNotAllowed(err): + ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_reserved", errNameReserved.Name), tpl, form) + case errors.As(err, &errNamePatternNotAllowed): ctx.Data["Err_UserName"] = true - ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tpl, form) - case db.IsErrNameCharsNotAllowed(err): + ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_pattern_not_allowed", errNamePatternNotAllowed.Pattern), tpl, form) + case errors.As(err, &errNameCharsNotAllowed): ctx.Data["Err_UserName"] = true - ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_chars_not_allowed", err.(db.ErrNameCharsNotAllowed).Name), tpl, form) + ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_chars_not_allowed", errNameCharsNotAllowed.Name), tpl, form) default: ctx.ServerError("CreateUser", err) } diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index d73b2bd1cf..dde59bba2f 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -113,7 +113,7 @@ func handleSignInError(ctx *context.Context, userName string, ptrForm any, tmpl // LinkAccountPostSignIn handle the coupling of external account with another account using signIn func LinkAccountPostSignIn(ctx *context.Context) { - signInForm := web.GetForm(ctx).(*forms.SignInForm) + signInForm := web.GetForm[*forms.SignInForm](ctx) ctx.Data["LinkAccountModeSignIn"] = true @@ -176,7 +176,7 @@ func oauth2LinkAccount(ctx *context.Context, u *user_model.User, linkAccountData // LinkAccountPostRegister handle the creation of a new account for an external account using signUp func LinkAccountPostRegister(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RegisterForm) + form := web.GetForm[*forms.RegisterForm](ctx) ctx.Data["LinkAccountModeRegister"] = true @@ -253,7 +253,7 @@ func LinkAccountPostRegister(ctx *context.Context) { ctx.ServerError("GetSourceByID", err) return } - source := authSource.Cfg.(*oauth2.Source) + source := auth.MustSourceCfg[*oauth2.Source](authSource) if err := syncGroupsToTeams(ctx, source, &linkAccountData.GothUser, u); err != nil { ctx.ServerError("SyncGroupsToTeams", err) return diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 687441a7b4..88ac21e802 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -56,13 +56,15 @@ func SignInOAuth(ctx *context.Context) { return } - if err = authSource.Cfg.(*oauth2.Source).Callout(ctx.Req, ctx.Resp); err != nil { + oauth2Source := auth.MustSourceCfg[*oauth2.Source](authSource) + + if err = oauth2Source.Callout(ctx.Req, ctx.Resp); err != nil { if strings.Contains(err.Error(), "no provider for ") { if err = oauth2.ResetOAuth2(ctx); err != nil { ctx.ServerError("SignIn", err) return } - if err = authSource.Cfg.(*oauth2.Source).Callout(ctx.Req, ctx.Resp); err != nil { + if err = oauth2Source.Callout(ctx.Req, ctx.Resp); err != nil { ctx.ServerError("SignIn", err) } return @@ -100,8 +102,7 @@ func SignInOAuthCallback(ctx *context.Context) { u, gothUser, err := oAuth2UserLoginCallback(ctx, authSource, ctx.Req, ctx.Resp) if err != nil { - if user_model.IsErrUserProhibitLogin(err) { - uplerr := err.(user_model.ErrUserProhibitLogin) + if uplerr, ok := err.(user_model.ErrUserProhibitLogin); ok { log.Info("Failed authentication attempt for %s from %s: %v", uplerr.Name, ctx.RemoteAddr(), err) ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") ctx.HTML(http.StatusOK, "user/auth/prohibit_login") @@ -188,7 +189,7 @@ func SignInOAuthCallback(ctx *context.Context) { IsActive: optional.Some(!setting.OAuth2Client.RegisterEmailConfirm && !setting.Service.RegisterManualConfirm), } - source := authSource.Cfg.(*oauth2.Source) + source := auth.MustSourceCfg[*oauth2.Source](authSource) linkAccountData := &LinkAccountData{authSource.ID, gothUser} if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingDisabled { @@ -368,7 +369,8 @@ func handleOAuth2SignIn(ctx *context.Context, authSource *auth.Source, u *user_m } } - oauth2Source := authSource.Cfg.(*oauth2.Source) + oauth2Source := auth.MustSourceCfg[*oauth2.Source](authSource) + groupTeamMapping, err := auth_module.UnmarshalGroupTeamMapping(oauth2Source.GroupTeamMap) if err != nil { ctx.ServerError("UnmarshalGroupTeamMapping", err) @@ -458,7 +460,7 @@ func handleOAuth2SignIn(ctx *context.Context, authSource *auth.Source, u *user_m // OAuth2UserLoginCallback attempts to handle the callback from the OAuth2 provider and if successful // login the user func oAuth2UserLoginCallback(ctx *context.Context, authSource *auth.Source, request *http.Request, response http.ResponseWriter) (*user_model.User, goth.User, error) { - oauth2Source := authSource.Cfg.(*oauth2.Source) + oauth2Source := auth.MustSourceCfg[*oauth2.Source](authSource) // Make sure that the response is not an error response. errorName := request.FormValue("error") diff --git a/routers/web/auth/oauth2_provider.go b/routers/web/auth/oauth2_provider.go index 8a54c0ea15..a40aa19c20 100644 --- a/routers/web/auth/oauth2_provider.go +++ b/routers/web/auth/oauth2_provider.go @@ -172,7 +172,7 @@ func IntrospectOAuth(ctx *context.Context) { jwt.RegisteredClaims } - form := web.GetForm(ctx).(*forms.IntrospectTokenForm) + form := web.GetForm[*forms.IntrospectTokenForm](ctx) token, err := oauth2_provider.ParseToken(form.Token, oauth2_provider.DefaultSigningKey) if err != nil { // RFC 7662 returns inactive token metadata for invalid/unknown tokens. @@ -221,7 +221,7 @@ func oauthDoerAuthorizePreCheck(ctx *context.Context, formState string) bool { // AuthorizeOAuth manages authorize requests func AuthorizeOAuth(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.AuthorizationForm) + form := web.GetForm[*forms.AuthorizationForm](ctx) if !oauthDoerAuthorizePreCheck(ctx, form.State) { return } @@ -399,7 +399,7 @@ func AuthorizeOAuth(ctx *context.Context) { // GrantApplicationOAuth manages the post request submitted when a user grants access to an application func GrantApplicationOAuth(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.GrantApplicationForm) + form := web.GetForm[*forms.GrantApplicationForm](ctx) if !oauthDoerAuthorizePreCheck(ctx, form.State) { return } @@ -498,7 +498,7 @@ func OIDCKeys(ctx *context.Context) { // AccessTokenOAuth manages all access token requests by the client func AccessTokenOAuth(ctx *context.Context) { - form := *web.GetForm(ctx).(*forms.AccessTokenForm) + form := *web.GetForm[*forms.AccessTokenForm](ctx) // if there is no ClientID or ClientSecret in the request body, fill these fields by the Authorization header and ensure the provided field matches the Authorization header if form.ClientID == "" || form.ClientSecret == "" { if authHeader := ctx.Req.Header.Get("Authorization"); authHeader != "" { diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go index 35fd7397ae..f57030c2f0 100644 --- a/routers/web/auth/openid.go +++ b/routers/web/auth/openid.go @@ -101,7 +101,7 @@ func allowedOpenIDURI(uri string) (err error) { // SignInOpenIDPost response for openid sign in request func SignInOpenIDPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.SignInOpenIDForm) + form := web.GetForm[*forms.SignInOpenIDForm](ctx) ctx.Data["Title"] = ctx.Tr("sign_in") ctx.Data["PageIsSignIn"] = true ctx.Data["PageIsLoginOpenID"] = true @@ -293,7 +293,7 @@ func ConnectOpenID(ctx *context.Context) { // ConnectOpenIDPost handles submission of a form to connect an OpenID URI to an existing account func ConnectOpenIDPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.ConnectOpenIDForm) + form := web.GetForm[*forms.ConnectOpenIDForm](ctx) oid := prepareConnectOpenIDPageData(ctx) if oid == "" { return @@ -366,7 +366,7 @@ func RegisterOpenIDPost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.SignUpOpenIDForm) + form := web.GetForm[*forms.SignUpOpenIDForm](ctx) if setting.Service.AllowOnlyInternalRegistration { ctx.HTTPError(http.StatusForbidden) diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go index 2123a2d9fd..bdc4a0396e 100644 --- a/routers/web/auth/password.go +++ b/routers/web/auth/password.go @@ -265,7 +265,7 @@ func MustChangePassword(ctx *context.Context) { // MustChangePasswordPost response for updating a user's password after their // account was created by an admin func MustChangePasswordPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.MustChangePasswordForm) + form := web.GetForm[*forms.MustChangePasswordForm](ctx) ctx.Data["Title"] = ctx.Tr("auth.must_change_password") ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/settings/change_password" if ctx.HasError() { diff --git a/routers/web/auth/webauthn.go b/routers/web/auth/webauthn.go index 11c038074d..6f43d8a4e8 100644 --- a/routers/web/auth/webauthn.go +++ b/routers/web/auth/webauthn.go @@ -31,12 +31,13 @@ func WebAuthn(ctx *context.Context) { } // Ensure user is in a 2FA session. - if ctx.Session.Get("twofaUid") == nil { + idSess, ok := ctx.Session.Get("twofaUid").(int64) + if !ok { ctx.ServerError("UserSignIn", errors.New("not in WebAuthn session")) return } - hasTwoFactor, err := auth.HasTwoFactorByUID(ctx, ctx.Session.Get("twofaUid").(int64)) + hasTwoFactor, err := auth.HasTwoFactorByUID(ctx, idSess) if err != nil { ctx.ServerError("HasTwoFactorByUID", err) return @@ -265,7 +266,7 @@ func WebAuthnLoginAssertionPost(ctx *context.Context) { return } - remember := ctx.Session.Get("twofaRemember").(bool) + remember := ctx.Session.Get("twofaRemember").(bool) //nolint:forcetypeassert // must exist handleSignInFull(ctx, user, remember) _ = ctx.Session.Delete("twofaUid") ctx.JSONRedirect(consumeAuthRedirectLink(ctx)) diff --git a/routers/web/devtest/mock_actions.go b/routers/web/devtest/mock_actions.go index 278d709c09..d898e19b70 100644 --- a/routers/web/devtest/mock_actions.go +++ b/routers/web/devtest/mock_actions.go @@ -522,7 +522,7 @@ func fillViewRunResponseCurrentJob(ctx *context.Context, resp *actions.ViewRespo } } - req := web.GetForm(ctx).(*actions.ViewRequest) + req := web.GetForm[*actions.ViewRequest](ctx) var mockLogOptions []generateMockStepsLogOptions resp.State.CurrentJob.Steps = append(resp.State.CurrentJob.Steps, &actions.ViewJobStep{ Summary: "step 0 (mock slow)", diff --git a/routers/web/misc/markup.go b/routers/web/misc/markup.go index 964a00282f..2158bd4511 100644 --- a/routers/web/misc/markup.go +++ b/routers/web/misc/markup.go @@ -14,7 +14,7 @@ import ( // Markup render markup document to HTML func Markup(ctx *context.Context) { - form := web.GetForm(ctx).(*api.MarkupOption) + form := web.GetForm[*api.MarkupOption](ctx) mode := util.Iif(form.Wiki, "wiki", form.Mode) //nolint:staticcheck // form.Wiki is deprecated common.RenderMarkup(ctx.Base, ctx.Repo, mode, form.Text, form.Context, form.FilePath) } diff --git a/routers/web/org/org.go b/routers/web/org/org.go index e21d7e42ff..e217e74d74 100644 --- a/routers/web/org/org.go +++ b/routers/web/org/org.go @@ -40,7 +40,7 @@ func Create(ctx *context.Context) { // CreatePost response for create organization func CreatePost(ctx *context.Context) { - form := *web.GetForm(ctx).(*forms.CreateOrgForm) + form := *web.GetForm[*forms.CreateOrgForm](ctx) ctx.Data["Title"] = ctx.Tr("new_org") if !ctx.Doer.CanCreateOrganization() { @@ -63,13 +63,15 @@ func CreatePost(ctx *context.Context) { if err := organization.CreateOrganization(ctx, org, ctx.Doer); err != nil { ctx.Data["Err_OrgName"] = true + var errNameReserved db.ErrNameReserved + var errNamePatternNotAllowed db.ErrNamePatternNotAllowed switch { case user_model.IsErrUserAlreadyExist(err): ctx.RenderWithErrDeprecated(ctx.Tr("form.org_name_been_taken"), tplCreateOrg, &form) - case db.IsErrNameReserved(err): - ctx.RenderWithErrDeprecated(ctx.Tr("org.form.name_reserved", err.(db.ErrNameReserved).Name), tplCreateOrg, &form) - case db.IsErrNamePatternNotAllowed(err): - ctx.RenderWithErrDeprecated(ctx.Tr("org.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplCreateOrg, &form) + case errors.As(err, &errNameReserved): + ctx.RenderWithErrDeprecated(ctx.Tr("org.form.name_reserved", errNameReserved.Name), tplCreateOrg, &form) + case errors.As(err, &errNamePatternNotAllowed): + ctx.RenderWithErrDeprecated(ctx.Tr("org.form.name_pattern_not_allowed", errNamePatternNotAllowed.Pattern), tplCreateOrg, &form) case organization.IsErrUserNotAllowedCreateOrg(err): ctx.RenderWithErrDeprecated(ctx.Tr("org.form.create_org_not_allowed"), tplCreateOrg, &form) default: diff --git a/routers/web/org/org_labels.go b/routers/web/org/org_labels.go index 3c5e7af448..3d76c25844 100644 --- a/routers/web/org/org_labels.go +++ b/routers/web/org/org_labels.go @@ -96,16 +96,15 @@ func DeleteLabel(ctx *context.Context) { // InitializeLabels init labels for an organization func InitializeLabels(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.InitializeLabelsForm) + form := web.GetForm[*forms.InitializeLabelsForm](ctx) if ctx.HasError() { ctx.Redirect(ctx.Org.OrgLink + "/labels") return } if err := repo_module.InitializeLabels(ctx, ctx.Org.Organization.ID, form.TemplateName, true); err != nil { - if label.IsErrTemplateLoad(err) { - originalErr := err.(label.ErrTemplateLoad).OriginalError - ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, originalErr)) + if errTemplateLoad, ok := err.(label.ErrTemplateLoad); ok { + ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, errTemplateLoad.OriginalError)) ctx.Redirect(ctx.Org.OrgLink + "/settings/labels") return } diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index cecaab65e5..fb343b4cdb 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -141,7 +141,7 @@ func RenderNewProject(ctx *context.Context) { // NewProjectPost creates a new project func NewProjectPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.CreateProjectForm) + form := web.GetForm[*forms.CreateProjectForm](ctx) ctx.Data["Title"] = ctx.Tr("repo.projects.new") if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil { ctx.ServerError("RenderUserOrgHeader", err) @@ -253,7 +253,7 @@ func RenderEditProject(ctx *context.Context) { // EditProjectPost response for editing a project func EditProjectPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.CreateProjectForm) + form := web.GetForm[*forms.CreateProjectForm](ctx) projectID := ctx.PathParamInt64("id") ctx.Data["Title"] = ctx.Tr("repo.projects.edit") ctx.Data["PageIsEditProjects"] = true diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go index 9e656350d2..207d116dac 100644 --- a/routers/web/org/setting.go +++ b/routers/web/org/setting.go @@ -58,7 +58,7 @@ func Settings(ctx *context.Context) { // SettingsPost response for settings change submitted func SettingsPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.UpdateOrgSettingForm) + form := web.GetForm[*forms.UpdateOrgSettingForm](ctx) ctx.Data["Title"] = ctx.Tr("org.settings") ctx.Data["PageIsOrgSettings"] = true ctx.Data["PageIsSettingsOptions"] = true @@ -103,7 +103,7 @@ func SettingsPost(ctx *context.Context) { // SettingsAvatar response for change avatar on settings page func SettingsAvatar(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.AvatarForm) + form := web.GetForm[*forms.AvatarForm](ctx) form.Source = forms.AvatarLocal if err := user_setting.UpdateAvatarSetting(ctx, form, ctx.Org.Organization.AsUser()); err != nil { ctx.Flash.Error(err.Error()) @@ -198,7 +198,7 @@ func Labels(ctx *context.Context) { // SettingsRenamePost response for renaming organization func SettingsRenamePost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RenameOrgForm) + form := web.GetForm[*forms.RenameOrgForm](ctx) if ctx.HasError() { ctx.JSONError(ctx.GetErrMsg()) return diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go index 11c4a1da3a..e3dcc1ca79 100644 --- a/routers/web/org/teams.go +++ b/routers/web/org/teams.go @@ -368,7 +368,7 @@ func getUnitPerms(forms url.Values, teamPermission perm.AccessMode) map[unit_mod // NewTeamPost response for create new team func NewTeamPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.CreateTeamForm) + form := web.GetForm[*forms.CreateTeamForm](ctx) includesAllRepositories := form.RepoAccess == "all" teamPermission := perm.ParseAccessMode(form.Permission, perm.AccessModeNone, perm.AccessModeAdmin) unitPerms := getUnitPerms(ctx.Req.Form, teamPermission) @@ -544,7 +544,7 @@ func EditTeam(ctx *context.Context) { // EditTeamPost response for modify team information func EditTeamPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.CreateTeamForm) + form := web.GetForm[*forms.CreateTeamForm](ctx) t := ctx.Org.Team teamPermission := perm.ParseAccessMode(form.Permission, perm.AccessModeNone, perm.AccessModeAdmin) unitPerms := getUnitPerms(ctx.Req.Form, teamPermission) diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index d8f1e03873..bae6d1c026 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -717,7 +717,7 @@ func fillViewRunResponseSummary(ctx *context_module.Context, resp *ViewResponse, } func fillViewRunResponseCurrentJob(ctx *context_module.Context, resp *ViewResponse, run *actions_model.ActionRun, jobs []*actions_model.ActionRunJob) { - req := web.GetForm(ctx).(*ViewRequest) + req := web.GetForm[*ViewRequest](ctx) current, hasPathParam := findCurrentJobByPathParam(ctx, jobs) if current == nil { if hasPathParam { diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index 771a4b292e..d415fa86a5 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -176,7 +176,7 @@ func jsonRedirectBranches(ctx *context.Context) { // CreateBranch creates new branch in repository func CreateBranch(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.NewBranchForm) + form := web.GetForm[*forms.NewBranchForm](ctx) if !ctx.Repo.CanCreateBranch() { ctx.NotFound(nil) return @@ -208,8 +208,7 @@ func CreateBranch(ctx *context.Context) { return } - if release_service.IsErrTagAlreadyExists(err) { - e := err.(release_service.ErrTagAlreadyExists) + if e, ok := err.(release_service.ErrTagAlreadyExists); ok { ctx.Flash.Error(ctx.Tr("repo.branch.tag_collision", e.TagName)) ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL()) return @@ -219,14 +218,12 @@ func CreateBranch(ctx *context.Context) { ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL()) return } - if git_model.IsErrBranchNameConflict(err) { - e := err.(git_model.ErrBranchNameConflict) + if e, ok := err.(git_model.ErrBranchNameConflict); ok { ctx.Flash.Error(ctx.Tr("repo.branch.branch_name_conflict", form.NewBranchName, e.BranchName)) ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL()) return } - if git.IsErrPushRejected(err) { - e := err.(*git.ErrPushRejected) + if e, ok := err.(*git.ErrPushRejected); ok { if len(e.Message) == 0 { ctx.Flash.Error(ctx.Tr("repo.editor.push_rejected_no_message")) } else { diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 187ed837fe..d0f6e7db72 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -112,7 +112,7 @@ func (f *preparedEditorCommitForm[T]) GetCommitMessage(defaultCommitMessage stri } func prepareEditorCommitSubmittedForm[T forms.CommitCommonFormInterface](ctx *context.Context) *preparedEditorCommitForm[T] { - form := web.GetForm(ctx).(T) + form := web.GetForm[T](ctx) if ctx.HasError() { ctx.JSONError(ctx.GetErrMsg()) return nil diff --git a/routers/web/repo/fork.go b/routers/web/repo/fork.go index 7b97e66bad..6e60a9a3d2 100644 --- a/routers/web/repo/fork.go +++ b/routers/web/repo/fork.go @@ -135,7 +135,7 @@ func Fork(ctx *context.Context) { // ForkPost response for forking a repository func ForkPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.CreateRepoForm) + form := web.GetForm[*forms.CreateRepoForm](ctx) ctx.Data["Title"] = ctx.Tr("new_fork") ctxUser := checkContextUser(ctx, form.UID) @@ -205,6 +205,8 @@ func ForkRepoTo(ctx *context.Context, owner *user_model.User, forkOpts repo_serv repo, err := repo_service.ForkRepository(ctx, ctx.Doer, owner, forkOpts) if err != nil { ctx.Data["Err_RepoName"] = true + var errNameReserved db.ErrNameReserved + var errNamePatternNotAllowed db.ErrNamePatternNotAllowed switch { case repo_model.IsErrReachLimitOfRepo(err): maxCreationLimit := owner.MaxCreationLimit() @@ -223,10 +225,10 @@ func ForkRepoTo(ctx *context.Context, owner *user_model.User, forkOpts repo_serv default: ctx.JSONError(ctx.Tr("form.repository_files_already_exist")) } - case db.IsErrNameReserved(err): - ctx.JSONError(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name)) - case db.IsErrNamePatternNotAllowed(err): - ctx.JSONError(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern)) + case errors.As(err, &errNameReserved): + ctx.JSONError(ctx.Tr("repo.form.name_reserved", errNameReserved.Name)) + case errors.As(err, &errNamePatternNotAllowed): + ctx.JSONError(ctx.Tr("repo.form.name_pattern_not_allowed", errNamePatternNotAllowed.Pattern)) case errors.Is(err, user_model.ErrBlockedUser): ctx.JSONError(ctx.Tr("repo.fork.blocked_user")) default: diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 10c9d7d726..67e944a323 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -480,7 +480,7 @@ func UpdateIssueAssignee(ctx *context.Context) { // ChangeIssueReaction create a reaction for issue func ChangeIssueReaction(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.ReactionForm) + form := web.GetForm[*forms.ReactionForm](ctx) issue := GetActionIssue(ctx) if ctx.Written() { return diff --git a/routers/web/repo/issue_comment.go b/routers/web/repo/issue_comment.go index 569b0cf707..dd7ba66e5c 100644 --- a/routers/web/repo/issue_comment.go +++ b/routers/web/repo/issue_comment.go @@ -41,7 +41,7 @@ func NewComment(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.CreateCommentForm) + form := web.GetForm[*forms.CreateCommentForm](ctx) issueType := util.Iif(issue.IsPull, "pulls", "issues") if !ctx.IsSigned || (ctx.Doer.ID != issue.PosterID && !ctx.Repo.Permission.CanReadIssuesOrPulls(issue.IsPull)) { @@ -306,7 +306,7 @@ func DeleteComment(ctx *context.Context) { // ChangeCommentReaction create a reaction for comment func ChangeCommentReaction(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.ReactionForm) + form := web.GetForm[*forms.ReactionForm](ctx) comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64("id")) if err != nil { ctx.NotFoundOrServerError("GetCommentByID", issues_model.IsErrCommentNotExist, err) diff --git a/routers/web/repo/issue_label.go b/routers/web/repo/issue_label.go index b0c0bb0b79..5004b9d978 100644 --- a/routers/web/repo/issue_label.go +++ b/routers/web/repo/issue_label.go @@ -36,16 +36,15 @@ func Labels(ctx *context.Context) { // InitializeLabels init labels for a repository func InitializeLabels(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.InitializeLabelsForm) + form := web.GetForm[*forms.InitializeLabelsForm](ctx) if ctx.HasError() { ctx.Redirect(ctx.Repo.RepoLink + "/labels") return } if err := repo_module.InitializeLabels(ctx, ctx.Repo.Repository.ID, form.TemplateName, false); err != nil { - if label.IsErrTemplateLoad(err) { - originalErr := err.(label.ErrTemplateLoad).OriginalError - ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, originalErr)) + if errTemplateLoad, ok := err.(label.ErrTemplateLoad); ok { + ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, errTemplateLoad.OriginalError)) ctx.Redirect(ctx.Repo.RepoLink + "/labels") return } diff --git a/routers/web/repo/issue_lock.go b/routers/web/repo/issue_lock.go index dfc7d51ebb..4d9e8fe904 100644 --- a/routers/web/repo/issue_lock.go +++ b/routers/web/repo/issue_lock.go @@ -13,7 +13,7 @@ import ( // LockIssue locks an issue. This would limit commenting abilities to // users with write access to the repo. func LockIssue(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.IssueLockForm) + form := web.GetForm[*forms.IssueLockForm](ctx) issue := GetActionIssue(ctx) if ctx.Written() { return diff --git a/routers/web/repo/issue_new.go b/routers/web/repo/issue_new.go index 1b64104eb4..bfcb73def4 100644 --- a/routers/web/repo/issue_new.go +++ b/routers/web/repo/issue_new.go @@ -322,7 +322,7 @@ func ValidateRepoMetasForNewIssue(ctx *context.Context, form forms.CreateIssueFo // NewIssuePost response for creating new issue func NewIssuePost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.CreateIssueForm) + form := web.GetForm[*forms.CreateIssueForm](ctx) repo := ctx.Repo.Repository diff --git a/routers/web/repo/issue_timetrack.go b/routers/web/repo/issue_timetrack.go index 40f0ead68a..89df3b8082 100644 --- a/routers/web/repo/issue_timetrack.go +++ b/routers/web/repo/issue_timetrack.go @@ -19,7 +19,7 @@ import ( // AddTimeManually tracks time manually func AddTimeManually(c *context.Context) { - form := web.GetForm(c).(*forms.AddTimeManuallyForm) + form := web.GetForm[*forms.AddTimeManuallyForm](c) issue := GetActionIssue(c) if c.Written() { return diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index 5e48171321..8911b03876 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -499,8 +499,8 @@ func (prInfo *pullRequestViewInfo) prepareMergeBoxCommitSigning(ctx *context.Con data.willSign = sign data.signingKeyMergeDisplay = asymkey_model.GetDisplaySigningKey(key) if err != nil { - if asymkey_service.IsErrWontSign(err) { - wontSignReason = string(err.(*asymkey_service.ErrWontSign).Reason) + if errWontSign, ok := err.(*asymkey_service.ErrWontSign); ok { + wontSignReason = string(errWontSign.Reason) } else { wontSignReason = "error" if !errors.Is(err, util.ErrNotExist) { @@ -560,8 +560,9 @@ func prepareIssueViewSidebarTimeTracker(ctx *context.Context, issue *issues_mode if ctx.IsSigned { // Deal with the stopwatch - ctx.Data["IsStopwatchRunning"] = issues_model.StopwatchExists(ctx, ctx.Doer.ID, issue.ID) - if !ctx.Data["IsStopwatchRunning"].(bool) { + isStopwatchRunning := issues_model.StopwatchExists(ctx, ctx.Doer.ID, issue.ID) + ctx.Data["IsStopwatchRunning"] = isStopwatchRunning + if !isStopwatchRunning { exists, _, swIssue, err := issues_model.HasUserStopwatch(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("HasUserStopwatch", err) diff --git a/routers/web/repo/migrate.go b/routers/web/repo/migrate.go index c8666eecaa..af08a3c5ab 100644 --- a/routers/web/repo/migrate.go +++ b/routers/web/repo/migrate.go @@ -5,6 +5,7 @@ package repo import ( + "errors" "net/http" "net/url" "strings" @@ -77,6 +78,8 @@ func handleMigrateError(ctx *context.Context, owner *user_model.User, err error, return } + var errNameReserved db.ErrNameReserved + var errNamePatternNotAllowed db.ErrNamePatternNotAllowed switch { case migrations.IsRateLimitError(err): ctx.RenderWithErrDeprecated(ctx.Tr("form.visit_rate_limit"), tpl, form) @@ -101,12 +104,12 @@ func handleMigrateError(ctx *context.Context, owner *user_model.User, err error, default: ctx.RenderWithErrDeprecated(ctx.Tr("form.repository_files_already_exist"), tpl, form) } - case db.IsErrNameReserved(err): + case errors.As(err, &errNameReserved): ctx.Data["Err_RepoName"] = true - ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tpl, form) - case db.IsErrNamePatternNotAllowed(err): + ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_reserved", errNameReserved.Name), tpl, form) + case errors.As(err, &errNamePatternNotAllowed): ctx.Data["Err_RepoName"] = true - ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tpl, form) + ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_pattern_not_allowed", errNamePatternNotAllowed.Pattern), tpl, form) default: err = util.SanitizeErrorCredentialURLs(err) if strings.Contains(err.Error(), "Authentication failed") || @@ -124,8 +127,7 @@ func handleMigrateError(ctx *context.Context, owner *user_model.User, err error, } func handleMigrateRemoteAddrError(ctx *context.Context, err error, tpl templates.TplName, form *forms.MigrateRepoForm) { - if git.IsErrInvalidCloneAddr(err) { - addrErr := err.(*git.ErrInvalidCloneAddr) + if addrErr, ok := err.(*git.ErrInvalidCloneAddr); ok { switch { case addrErr.IsProtocolInvalid: ctx.RenderWithErrDeprecated(ctx.Tr("repo.mirror_address_protocol_invalid"), tpl, form) @@ -151,7 +153,7 @@ func handleMigrateRemoteAddrError(ctx *context.Context, err error, tpl templates // MigratePost response for migrating from external git repository func MigratePost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.MigrateRepoForm) + form := web.GetForm[*forms.MigrateRepoForm](ctx) if setting.Repository.DisableMigrations { ctx.HTTPError(http.StatusForbidden, "MigratePost: the site administrator has disabled migrations") return diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go index c639754dc8..7571d156d4 100644 --- a/routers/web/repo/milestone.go +++ b/routers/web/repo/milestone.go @@ -105,7 +105,7 @@ func NewMilestone(ctx *context.Context) { // NewMilestonePost response for creating milestone func NewMilestonePost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.CreateMilestoneForm) + form := web.GetForm[*forms.CreateMilestoneForm](ctx) ctx.Data["Title"] = ctx.Tr("repo.milestones.new") ctx.Data["PageIsIssueList"] = true ctx.Data["PageIsMilestones"] = true @@ -161,7 +161,7 @@ func EditMilestone(ctx *context.Context) { // EditMilestonePost response for edting milestone func EditMilestonePost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.CreateMilestoneForm) + form := web.GetForm[*forms.CreateMilestoneForm](ctx) ctx.Data["Title"] = ctx.Tr("repo.milestones.edit") ctx.Data["PageIsMilestones"] = true ctx.Data["PageIsEditMilestone"] = true diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index 3212fe1401..b48a4fd7bc 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -127,7 +127,7 @@ func RenderNewProject(ctx *context.Context) { // NewProjectPost creates a new project func NewProjectPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.CreateProjectForm) + form := web.GetForm[*forms.CreateProjectForm](ctx) ctx.Data["Title"] = ctx.Tr("repo.projects.new") if ctx.HasError() { @@ -231,7 +231,7 @@ func RenderEditProject(ctx *context.Context) { // EditProjectPost response for editing a project func EditProjectPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.CreateProjectForm) + form := web.GetForm[*forms.CreateProjectForm](ctx) projectID := ctx.PathParamInt64("id") ctx.Data["Title"] = ctx.Tr("repo.projects.edit") diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 70e6e99d0e..fb39d34a5c 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1007,8 +1007,7 @@ func UpdatePullRequest(ctx *context.Context) { // The update process should not be canceled by the user // so we set the context to be a background context if err = pull_service.Update(graceful.GetManager().ShutdownContext(), issue.PullRequest, ctx.Doer, message, rebase); err != nil { - if pull_service.IsErrMergeConflicts(err) { - conflictError := err.(pull_service.ErrMergeConflicts) + if conflictError, ok := err.(pull_service.ErrMergeConflicts); ok { flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{ "Message": ctx.Tr("repo.pulls.merge_conflict"), "Summary": ctx.Tr("repo.pulls.merge_conflict_summary"), @@ -1020,8 +1019,7 @@ func UpdatePullRequest(ctx *context.Context) { } ctx.JSONError(flashError) return - } else if pull_service.IsErrRebaseConflicts(err) { - conflictError := err.(pull_service.ErrRebaseConflicts) + } else if conflictError, ok := err.(pull_service.ErrRebaseConflicts); ok { flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{ "Message": ctx.Tr("repo.pulls.rebase_conflict", utils.EscapeFlashErrorString(conflictError.CommitSHA)), "Summary": ctx.Tr("repo.pulls.rebase_conflict_summary"), @@ -1047,7 +1045,7 @@ func UpdatePullRequest(ctx *context.Context) { // MergePullRequest response for merging pull request func MergePullRequest(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.MergePullRequestForm) + form := web.GetForm[*forms.MergePullRequestForm](ctx) issue, ok := getPullInfo(ctx) if !ok { return @@ -1156,8 +1154,7 @@ func MergePullRequest(ctx *context.Context) { if err := pull_service.Merge(ctx, pr, ctx.Doer, repo_model.MergeStyle(form.Do), form.HeadCommitID, message, false); err != nil { if pull_service.IsErrInvalidMergeStyle(err) { ctx.JSONError(ctx.Tr("repo.pulls.invalid_merge_option")) - } else if pull_service.IsErrMergeConflicts(err) { - conflictError := err.(pull_service.ErrMergeConflicts) + } else if conflictError, ok := err.(pull_service.ErrMergeConflicts); ok { flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{ "Message": ctx.Tr("repo.editor.merge_conflict"), "Summary": ctx.Tr("repo.editor.merge_conflict_summary"), @@ -1169,8 +1166,7 @@ func MergePullRequest(ctx *context.Context) { } ctx.Flash.Error(flashError) ctx.JSONRedirect(issue.Link()) - } else if pull_service.IsErrRebaseConflicts(err) { - conflictError := err.(pull_service.ErrRebaseConflicts) + } else if conflictError, ok := err.(pull_service.ErrRebaseConflicts); ok { flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{ "Message": ctx.Tr("repo.pulls.rebase_conflict", utils.EscapeFlashErrorString(conflictError.CommitSHA)), "Summary": ctx.Tr("repo.pulls.rebase_conflict_summary"), @@ -1194,9 +1190,8 @@ func MergePullRequest(ctx *context.Context) { log.Debug("MergeHeadOutOfDate error: %v", err) ctx.Flash.Error(ctx.Tr("repo.pulls.head_out_of_date")) ctx.JSONRedirect(issue.Link()) - } else if git.IsErrPushRejected(err) { + } else if pushrejErr, ok := err.(*git.ErrPushRejected); ok { log.Debug("MergePushRejected error: %v", err) - pushrejErr := err.(*git.ErrPushRejected) message := pushrejErr.Message if len(message) == 0 { ctx.Flash.Error(ctx.Tr("repo.pulls.push_rejected_no_message")) @@ -1322,7 +1317,7 @@ func PullsNewRedirect(ctx *context.Context) { // CompareAndPullRequestPost response for creating pull request func CompareAndPullRequestPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.CreateIssueForm) + form := web.GetForm[*forms.CreateIssueForm](ctx) repo := ctx.Repo.Repository comparePageInfo := newComparePageInfo() err := comparePageInfo.parseCompareInfo(ctx, ctx.PathParam("*")) @@ -1416,11 +1411,11 @@ func CompareAndPullRequestPost(ctx *context.Context) { ProjectIDs: projectIDs, } if err := pull_service.NewPullRequest(ctx, prOpts); err != nil { + var pushrejErr *git.ErrPushRejected switch { case repo_model.IsErrUserDoesNotHaveAccessToRepo(err): ctx.HTTPError(http.StatusBadRequest, "UserDoesNotHaveAccessToRepo", err.Error()) - case git.IsErrPushRejected(err): - pushrejErr := err.(*git.ErrPushRejected) + case errors.As(err, &pushrejErr): message := pushrejErr.Message if len(message) == 0 { ctx.JSONError(ctx.Tr("repo.pulls.push_rejected_no_message")) @@ -1537,6 +1532,7 @@ func UpdatePullRequestTarget(ctx *context.Context) { } if err := pull_service.ChangeTargetBranch(ctx, pr, ctx.Doer, targetBranch); err != nil { + var prExistsErr issues_model.ErrPullRequestAlreadyExists switch { case git_model.IsErrBranchNotExist(err): errorMessage := ctx.Tr("form.target_branch_not_exist") @@ -1546,11 +1542,9 @@ func UpdatePullRequestTarget(ctx *context.Context) { "error": err.Error(), "user_error": errorMessage, }) - case issues_model.IsErrPullRequestAlreadyExists(err): - err := err.(issues_model.ErrPullRequestAlreadyExists) - + case errors.As(err, &prExistsErr): RepoRelPath := ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name - errorMessage := ctx.Tr("repo.pulls.has_pull_request", html.EscapeString(ctx.Repo.RepoLink+"/pulls/"+strconv.FormatInt(err.IssueID, 10)), html.EscapeString(RepoRelPath), err.IssueID) // FIXME: Creates url inside locale string + errorMessage := ctx.Tr("repo.pulls.has_pull_request", html.EscapeString(ctx.Repo.RepoLink+"/pulls/"+strconv.FormatInt(prExistsErr.IssueID, 10)), html.EscapeString(RepoRelPath), prExistsErr.IssueID) // FIXME: Creates url inside locale string ctx.Flash.Error(errorMessage) ctx.JSON(http.StatusConflict, map[string]any{ @@ -1595,7 +1589,7 @@ func UpdatePullRequestTarget(ctx *context.Context) { // SetAllowEdits allow edits from maintainers to PRs func SetAllowEdits(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.UpdateAllowEditsForm) + form := web.GetForm[*forms.UpdateAllowEditsForm](ctx) pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go index 2ebd9bd63c..0059860105 100644 --- a/routers/web/repo/pull_review.go +++ b/routers/web/repo/pull_review.go @@ -62,7 +62,7 @@ func RenderNewCodeCommentForm(ctx *context.Context) { // CreateCodeComment will create a code comment including an pending review if required func CreateCodeComment(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.CodeCommentForm) + form := web.GetForm[*forms.CodeCommentForm](ctx) issue := GetActionIssue(ctx) if ctx.Written() { return @@ -221,7 +221,7 @@ func renderConversation(ctx *context.Context, comment *issues_model.Comment, ori // SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist func SubmitReview(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.SubmitReviewForm) + form := web.GetForm[*forms.SubmitReviewForm](ctx) issue := GetActionIssue(ctx) if ctx.Written() { return @@ -279,7 +279,7 @@ func SubmitReview(ctx *context.Context) { // DismissReview dismissing stale review by repo admin func DismissReview(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.DismissReviewForm) + form := web.GetForm[*forms.DismissReviewForm](ctx) comm, err := pull_service.DismissReview(ctx, form.ReviewID, ctx.Repo.Repository.ID, form.Message, ctx.Doer, true, true) if err != nil { if pull_service.IsErrDismissRequestOnClosedPR(err) { diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index 28cbe06b5d..09a535b307 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -48,8 +48,8 @@ func calReleaseNumCommitsBehind(ctx stdCtx.Context, repoCtx *context.Repository, if _, ok := countCache[target]; !ok { commit, err := repoCtx.GitRepo.GetBranchCommit(ctx, target) if err != nil { - var errNotExist git.ErrNotExist - if target == repoCtx.Repository.DefaultBranch || !errors.As(err, &errNotExist) { + _, isNotExist := errors.AsType[git.ErrNotExist](err) + if target == repoCtx.Repository.DefaultBranch || !isNotExist { return fmt.Errorf("GetBranchCommit: %w", err) } // fallback to default branch @@ -189,7 +189,7 @@ func Releases(ctx *context.Context) { ctx.Data["Releases"] = releases - numReleases := ctx.Data["NumReleases"].(int64) + numReleases := ctx.Data["NumReleases"].(int64) //nolint:forcetypeassert // must exist pager := context.NewPagination(numReleases, listOptions.PageSize, listOptions.Page, 5) pager.AddParamFromRequest(ctx.Req) ctx.Data["Page"] = pager @@ -387,7 +387,7 @@ func NewRelease(ctx *context.Context) { // GenerateReleaseNotes builds release notes content for the given tag and base. func GenerateReleaseNotes(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.GenerateReleaseNotesForm) + form := web.GetForm[*forms.GenerateReleaseNotesForm](ctx) if ctx.HasError() { ctx.JSONError(ctx.GetErrMsg()) @@ -418,7 +418,7 @@ func NewReleasePost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.NewReleaseForm) + form := web.GetForm[*forms.NewReleaseForm](ctx) // first, check whether the release exists, and prepare "ShowCreateTagOnlyButton" // the logic should be done before the form error check to make the tmpl has correct variables @@ -579,7 +579,7 @@ func EditReleasePost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.EditReleaseForm) + form := web.GetForm[*forms.EditReleaseForm](ctx) tagName := ctx.PathParam("*") rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tagName) diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index ff213fcc42..4ad6ce2100 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -165,6 +165,8 @@ func Create(ctx *context.Context) { } func handleCreateError(ctx *context.Context, owner *user_model.User, err error, name string, tpl templates.TplName, form any) { + var errNameReserved db.ErrNameReserved + var errNamePatternNotAllowed db.ErrNamePatternNotAllowed switch { case repo_model.IsErrReachLimitOfRepo(err): maxCreationLimit := owner.MaxCreationLimit() @@ -185,12 +187,12 @@ func handleCreateError(ctx *context.Context, owner *user_model.User, err error, default: ctx.RenderWithErrDeprecated(ctx.Tr("form.repository_files_already_exist"), tpl, form) } - case db.IsErrNameReserved(err): + case errors.As(err, &errNameReserved): ctx.Data["Err_RepoName"] = true - ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tpl, form) - case db.IsErrNamePatternNotAllowed(err): + ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_reserved", errNameReserved.Name), tpl, form) + case errors.As(err, &errNamePatternNotAllowed): ctx.Data["Err_RepoName"] = true - ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tpl, form) + ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_pattern_not_allowed", errNamePatternNotAllowed.Pattern), tpl, form) default: ctx.ServerError(name, err) } @@ -199,7 +201,7 @@ func handleCreateError(ctx *context.Context, owner *user_model.User, err error, // CreatePost response for creating repository func CreatePost(ctx *context.Context) { createCommon(ctx) - form := web.GetForm(ctx).(*forms.CreateRepoForm) + form := web.GetForm[*forms.CreateRepoForm](ctx) ctxUser := checkContextUser(ctx, form.UID) if ctx.Written() { @@ -283,11 +285,12 @@ func CreatePost(ctx *context.Context) { } func handleActionError(ctx *context.Context, err error) { + var errLimitReached repo_service.LimitReachedError switch { case errors.Is(err, user_model.ErrBlockedUser): ctx.JSONError(ctx.Tr("repo.action.blocked_user")) - case repo_service.IsRepositoryLimitReached(err): - limit := err.(repo_service.LimitReachedError).Limit + case errors.As(err, &errLimitReached): + limit := errLimitReached.Limit ctx.JSONError(ctx.TrN(limit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", limit)) case errors.Is(err, util.ErrPermissionDenied): ctx.JSONError(ctx.Tr("error.permission_denied")) diff --git a/routers/web/repo/setting/avatar.go b/routers/web/repo/setting/avatar.go index 754e731a9b..b66f31bd65 100644 --- a/routers/web/repo/setting/avatar.go +++ b/routers/web/repo/setting/avatar.go @@ -57,7 +57,7 @@ func UpdateAvatarSetting(ctx *context.Context, form forms.AvatarForm) error { // SettingsAvatar save new POSTed repository avatar func SettingsAvatar(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.AvatarForm) + form := web.GetForm[*forms.AvatarForm](ctx) form.Source = forms.AvatarLocal if err := UpdateAvatarSetting(ctx, *form); err != nil { ctx.Flash.Error(err.Error()) diff --git a/routers/web/repo/setting/deploy_key.go b/routers/web/repo/setting/deploy_key.go index df4f43070a..ad398f6a69 100644 --- a/routers/web/repo/setting/deploy_key.go +++ b/routers/web/repo/setting/deploy_key.go @@ -34,7 +34,7 @@ func DeployKeys(ctx *context.Context) { // DeployKeysPost response for adding a deploy key of a repository func DeployKeysPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.AddKeyForm) + form := web.GetForm[*forms.AddKeyForm](ctx) ctx.Data["Title"] = ctx.Tr("repo.settings.deploy_keys") ctx.Data["PageIsSettingsKeys"] = true ctx.Data["DisableSSH"] = setting.SSH.Disabled diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go index ea51b476a1..145ad5ebe1 100644 --- a/routers/web/repo/setting/protected_branch.go +++ b/routers/web/repo/setting/protected_branch.go @@ -109,7 +109,7 @@ func SettingsProtectedBranch(c *context.Context) { // SettingsProtectedBranchPost updates the protected branch settings func SettingsProtectedBranchPost(ctx *context.Context) { - f := web.GetForm(ctx).(*forms.ProtectBranchForm) + f := web.GetForm[*forms.ProtectBranchForm](ctx) var protectBranch *git_model.ProtectedBranch if f.RuleName == "" { ctx.Flash.Error(ctx.Tr("repo.settings.protected_branch_required_rule_name")) @@ -343,7 +343,7 @@ func UpdateBranchProtectionPriories(ctx *context.Context) { // RenameBranchPost responses for rename a branch func RenameBranchPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RenameBranchForm) + form := web.GetForm[*forms.RenameBranchForm](ctx) if !ctx.Repo.CanCreateBranch() { ctx.NotFound(nil) diff --git a/routers/web/repo/setting/protected_tag.go b/routers/web/repo/setting/protected_tag.go index ba2a1af569..b85476a146 100644 --- a/routers/web/repo/setting/protected_tag.go +++ b/routers/web/repo/setting/protected_tag.go @@ -46,7 +46,7 @@ func NewProtectedTagPost(ctx *context.Context) { } repo := ctx.Repo.Repository - form := web.GetForm(ctx).(*forms.ProtectTagForm) + form := web.GetForm[*forms.ProtectTagForm](ctx) pt := &git_model.ProtectedTag{ RepoID: repo.ID, @@ -107,7 +107,7 @@ func EditProtectedTagPost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.ProtectTagForm) + form := web.GetForm[*forms.ProtectTagForm](ctx) pt.NamePattern = strings.TrimSpace(form.NamePattern) pt.AllowlistUserIDs, _ = base.StringsToInt64s(strings.Split(form.AllowlistUsers, ",")) diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index ff37c7c8e2..b8968cda70 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -198,7 +198,7 @@ func SettingsPost(ctx *context.Context) { } func handleSettingsPostUpdate(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) repo := ctx.Repo.Repository if ctx.HasError() { ctx.HTML(http.StatusOK, tplSettingsOptions) @@ -215,11 +215,13 @@ func handleSettingsPostUpdate(ctx *context.Context) { } if err := repo_service.ChangeRepositoryName(ctx, ctx.Doer, repo, newRepoName); err != nil { ctx.Data["Err_RepoName"] = true + var errNameReserved db.ErrNameReserved + var errNamePatternNotAllowed db.ErrNamePatternNotAllowed switch { case repo_model.IsErrRepoAlreadyExist(err): ctx.RenderWithErrDeprecated(ctx.Tr("form.repo_name_been_taken"), tplSettingsOptions, &form) - case db.IsErrNameReserved(err): - ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tplSettingsOptions, &form) + case errors.As(err, &errNameReserved): + ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_reserved", errNameReserved.Name), tplSettingsOptions, &form) case repo_model.IsErrRepoFilesAlreadyExist(err): ctx.Data["Err_RepoName"] = true switch { @@ -232,8 +234,8 @@ func handleSettingsPostUpdate(ctx *context.Context) { default: ctx.RenderWithErrDeprecated(ctx.Tr("form.repository_files_already_exist"), tplSettingsOptions, form) } - case db.IsErrNamePatternNotAllowed(err): - ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplSettingsOptions, &form) + case errors.As(err, &errNamePatternNotAllowed): + ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_pattern_not_allowed", errNamePatternNotAllowed.Pattern), tplSettingsOptions, &form) default: ctx.ServerError("ChangeRepositoryName", err) } @@ -260,7 +262,7 @@ func handleSettingsPostUpdate(ctx *context.Context) { } func handleSettingsPostMirror(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) repo := ctx.Repo.Repository if !setting.Mirror.Enabled || !repo.IsMirror || repo.IsArchived { ctx.NotFound(nil) @@ -375,7 +377,7 @@ func handleSettingsPostMirrorSync(ctx *context.Context) { } func handleSettingsPostPushMirrorSync(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) repo := ctx.Repo.Repository if !setting.Mirror.Enabled { @@ -396,7 +398,7 @@ func handleSettingsPostPushMirrorSync(ctx *context.Context) { } func handleSettingsPostPushMirrorUpdate(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) repo := ctx.Repo.Repository if !setting.Mirror.Enabled || repo.IsArchived { @@ -438,7 +440,7 @@ func handleSettingsPostPushMirrorUpdate(ctx *context.Context) { } func handleSettingsPostPushMirrorRemove(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) repo := ctx.Repo.Repository if !setting.Mirror.Enabled || repo.IsArchived { @@ -471,7 +473,7 @@ func handleSettingsPostPushMirrorRemove(ctx *context.Context) { } func handleSettingsPostPushMirrorAdd(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) repo := ctx.Repo.Repository if setting.Mirror.DisableNewPush || repo.IsArchived { @@ -546,7 +548,7 @@ func newRepoUnit(repo *repo_model.Repository, unitType unit_model.Type, config c } func handleSettingsPostAdvanced(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) repo := ctx.Repo.Repository var repoChanged bool var units []repo_model.RepoUnit @@ -703,7 +705,7 @@ func handleSettingsPostAdvanced(ctx *context.Context) { } func handleSettingsPostSigning(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) repo := ctx.Repo.Repository trustModel := repo_model.ToTrustModel(form.TrustModel) if trustModel != repo.TrustModel { @@ -726,7 +728,7 @@ func handleSettingsPostAdmin(ctx *context.Context) { } repo := ctx.Repo.Repository - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) if repo.IsFsckEnabled != form.EnableHealthCheck { repo.IsFsckEnabled = form.EnableHealthCheck if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "is_fsck_enabled"); err != nil { @@ -741,7 +743,7 @@ func handleSettingsPostAdmin(ctx *context.Context) { } func handleSettingsPostAdminIndex(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) repo := ctx.Repo.Repository if !ctx.Doer.IsAdmin { ctx.HTTPError(http.StatusForbidden) @@ -772,7 +774,7 @@ func handleSettingsPostAdminIndex(ctx *context.Context) { } func handleSettingsPostConvert(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) repo := ctx.Repo.Repository if !ctx.Repo.Permission.IsOwner() { ctx.JSONErrorNotFound() @@ -802,7 +804,7 @@ func handleSettingsPostConvert(ctx *context.Context) { } func handleSettingsPostConvertFork(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) repo := ctx.Repo.Repository if !ctx.Repo.Permission.IsOwner() { ctx.JSONErrorNotFound() @@ -842,7 +844,7 @@ func handleSettingsPostConvertFork(ctx *context.Context) { } func handleSettingsPostTransfer(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) repo := ctx.Repo.Repository if !ctx.Repo.Permission.IsOwner() { ctx.JSONErrorNotFound() @@ -883,8 +885,8 @@ func handleSettingsPostTransfer(ctx *context.Context) { ctx.JSONError(ctx.Tr("repo.settings.new_owner_has_same_repo")) } else if repo_model.IsErrRepoTransferInProgress(err) { ctx.JSONError(ctx.Tr("repo.settings.transfer_in_progress")) - } else if repo_service.IsRepositoryLimitReached(err) { - limit := err.(repo_service.LimitReachedError).Limit + } else if errLimitReached, ok := err.(repo_service.LimitReachedError); ok { + limit := errLimitReached.Limit ctx.JSONError(ctx.TrN(limit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", limit)) } else if errors.Is(err, user_model.ErrBlockedUser) { ctx.JSONError(ctx.Tr("repo.settings.transfer.blocked_user")) @@ -934,7 +936,7 @@ func handleSettingsPostCancelTransfer(ctx *context.Context) { } func handleSettingsPostDelete(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) repo := ctx.Repo.Repository if !ctx.Repo.Permission.IsOwner() { ctx.JSONErrorNotFound() @@ -961,7 +963,7 @@ func handleSettingsPostDelete(ctx *context.Context) { } func handleSettingsPostDeleteWiki(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.RepoSettingForm) + form := web.GetForm[*forms.RepoSettingForm](ctx) repo := ctx.Repo.Repository if !ctx.Repo.Permission.IsOwner() { ctx.JSONErrorNotFound() @@ -1075,8 +1077,7 @@ func handleSettingsPostVisibility(ctx *context.Context) { } func handleSettingRemoteAddrError(ctx *context.Context, err error, form *forms.RepoSettingForm) { - if git.IsErrInvalidCloneAddr(err) { - addrErr := err.(*git.ErrInvalidCloneAddr) + if addrErr, ok := err.(*git.ErrInvalidCloneAddr); ok { switch { case addrErr.IsProtocolInvalid: ctx.RenderWithErrDeprecated(ctx.Tr("repo.mirror_address_protocol_invalid"), tplSettingsOptions, form) diff --git a/routers/web/repo/setting/webhook.go b/routers/web/repo/setting/webhook.go index f128209f1b..b54f3227e3 100644 --- a/routers/web/repo/setting/webhook.go +++ b/routers/web/repo/setting/webhook.go @@ -326,7 +326,7 @@ func GiteaHooksEditPost(ctx *context.Context) { } func giteaHookParams(ctx *context.Context) webhookParams { - form := web.GetForm(ctx).(*forms.NewWebhookForm) + form := web.GetForm[*forms.NewWebhookForm](ctx) contentType := webhook.ContentTypeJSON if webhook.HookContentType(form.ContentType) == webhook.ContentTypeForm { @@ -353,7 +353,7 @@ func GogsHooksEditPost(ctx *context.Context) { } func gogsHookParams(ctx *context.Context) webhookParams { - form := web.GetForm(ctx).(*forms.NewGogshookForm) + form := web.GetForm[*forms.NewGogshookForm](ctx) contentType := webhook.ContentTypeJSON if webhook.HookContentType(form.ContentType) == webhook.ContentTypeForm { @@ -379,7 +379,7 @@ func DiscordHooksEditPost(ctx *context.Context) { } func discordHookParams(ctx *context.Context) webhookParams { - form := web.GetForm(ctx).(*forms.NewDiscordHookForm) + form := web.GetForm[*forms.NewDiscordHookForm](ctx) return webhookParams{ Type: webhook_module.DISCORD, @@ -404,7 +404,7 @@ func DingtalkHooksEditPost(ctx *context.Context) { } func dingtalkHookParams(ctx *context.Context) webhookParams { - form := web.GetForm(ctx).(*forms.NewDingtalkHookForm) + form := web.GetForm[*forms.NewDingtalkHookForm](ctx) return webhookParams{ Type: webhook_module.DINGTALK, @@ -425,7 +425,7 @@ func TelegramHooksEditPost(ctx *context.Context) { } func telegramHookParams(ctx *context.Context) webhookParams { - form := web.GetForm(ctx).(*forms.NewTelegramHookForm) + form := web.GetForm[*forms.NewTelegramHookForm](ctx) return webhookParams{ Type: webhook_module.TELEGRAM, @@ -459,7 +459,7 @@ func matrixRoomIDEncode(roomID string) string { } func matrixHookParams(ctx *context.Context) webhookParams { - form := web.GetForm(ctx).(*forms.NewMatrixHookForm) + form := web.GetForm[*forms.NewMatrixHookForm](ctx) // TODO: need to migrate to the latest (v3) API: https://spec.matrix.org/v1.18/client-server-api/ return webhookParams{ @@ -487,7 +487,7 @@ func MSTeamsHooksEditPost(ctx *context.Context) { } func mSTeamsHookParams(ctx *context.Context) webhookParams { - form := web.GetForm(ctx).(*forms.NewMSTeamsHookForm) + form := web.GetForm[*forms.NewMSTeamsHookForm](ctx) return webhookParams{ Type: webhook_module.MSTEAMS, @@ -508,7 +508,7 @@ func SlackHooksEditPost(ctx *context.Context) { } func slackHookParams(ctx *context.Context) webhookParams { - form := web.GetForm(ctx).(*forms.NewSlackHookForm) + form := web.GetForm[*forms.NewSlackHookForm](ctx) return webhookParams{ Type: webhook_module.SLACK, @@ -535,7 +535,7 @@ func FeishuHooksEditPost(ctx *context.Context) { } func feishuHookParams(ctx *context.Context) webhookParams { - form := web.GetForm(ctx).(*forms.NewFeishuHookForm) + form := web.GetForm[*forms.NewFeishuHookForm](ctx) return webhookParams{ Type: webhook_module.FEISHU, @@ -556,7 +556,7 @@ func WechatworkHooksEditPost(ctx *context.Context) { } func wechatworkHookParams(ctx *context.Context) webhookParams { - form := web.GetForm(ctx).(*forms.NewWechatWorkHookForm) + form := web.GetForm[*forms.NewWechatWorkHookForm](ctx) return webhookParams{ Type: webhook_module.WECHATWORK, @@ -577,7 +577,7 @@ func PackagistHooksEditPost(ctx *context.Context) { } func packagistHookParams(ctx *context.Context) webhookParams { - form := web.GetForm(ctx).(*forms.NewPackagistHookForm) + form := web.GetForm[*forms.NewPackagistHookForm](ctx) return webhookParams{ Type: webhook_module.PACKAGIST, diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go index 4d82c67fd1..18ef784a41 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -655,7 +655,7 @@ func NewWiki(ctx *context.Context) { // NewWikiPost response for wiki create request func NewWikiPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.NewWikiForm) + form := web.GetForm[*forms.NewWikiForm](ctx) ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page") if ctx.HasError() { @@ -711,7 +711,7 @@ func EditWiki(ctx *context.Context) { // EditWikiPost response for wiki modify request func EditWikiPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.NewWikiForm) + form := web.GetForm[*forms.NewWikiForm](ctx) ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page") if ctx.HasError() { diff --git a/routers/web/shared/actions/runners.go b/routers/web/shared/actions/runners.go index 21a2bb8fc1..b68eb11f9a 100644 --- a/routers/web/shared/actions/runners.go +++ b/routers/web/shared/actions/runners.go @@ -251,7 +251,7 @@ func RunnersEditPost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.EditRunnerForm) + form := web.GetForm[*forms.EditRunnerForm](ctx) runner.Description = form.Description err = actions_model.UpdateRunner(ctx, runner, "description") diff --git a/routers/web/shared/actions/variables.go b/routers/web/shared/actions/variables.go index e26e2ba5d3..de3940d317 100644 --- a/routers/web/shared/actions/variables.go +++ b/routers/web/shared/actions/variables.go @@ -122,7 +122,7 @@ func VariableCreate(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.EditVariableForm) + form := web.GetForm[*forms.EditVariableForm](ctx) v, err := actions_service.CreateVariable(ctx, vCtx.OwnerID, vCtx.RepoID, form.Name, form.Data, form.Description) if err != nil { @@ -154,7 +154,7 @@ func VariableUpdate(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.EditVariableForm) + form := web.GetForm[*forms.EditVariableForm](ctx) variable.Name = form.Name variable.Data = form.Data variable.Description = form.Description diff --git a/routers/web/shared/label/label.go b/routers/web/shared/label/label.go index f1f166cc68..5563e72df5 100644 --- a/routers/web/shared/label/label.go +++ b/routers/web/shared/label/label.go @@ -11,7 +11,7 @@ import ( ) func GetLabelEditForm(ctx *context.Context) *forms.CreateLabelForm { - form := web.GetForm(ctx).(*forms.CreateLabelForm) + form := web.GetForm[*forms.CreateLabelForm](ctx) if ctx.HasError() { ctx.JSONError(ctx.GetErrMsg()) return nil diff --git a/routers/web/shared/packages/packages.go b/routers/web/shared/packages/packages.go index 6c8a588e3d..d88d0be637 100644 --- a/routers/web/shared/packages/packages.go +++ b/routers/web/shared/packages/packages.go @@ -63,7 +63,7 @@ func PerformRuleEditPost(ctx *context.Context, owner *user_model.User, redirectU return } - form := web.GetForm(ctx).(*forms.PackageCleanupRuleForm) + form := web.GetForm[*forms.PackageCleanupRuleForm](ctx) if form.Action == "remove" { if err := packages_model.DeleteCleanupRuleByID(ctx, pcr.ID); err != nil { @@ -85,7 +85,7 @@ func performRuleEditPost(ctx *context.Context, owner *user_model.User, pcr *pack pcr = &packages_model.PackageCleanupRule{} } - form := web.GetForm(ctx).(*forms.PackageCleanupRuleForm) + form := web.GetForm[*forms.PackageCleanupRuleForm](ctx) pcr.Enabled = form.Enabled pcr.OwnerID = owner.ID diff --git a/routers/web/shared/project/project.go b/routers/web/shared/project/project.go index 9ce59418e7..1664912013 100644 --- a/routers/web/shared/project/project.go +++ b/routers/web/shared/project/project.go @@ -78,7 +78,7 @@ func MoveColumns(ctx *context.Context) { } func AddColumnToProjectPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.EditProjectColumnForm) + form := web.GetForm[*forms.EditProjectColumnForm](ctx) project := findProject(ctx) if ctx.Written() { return @@ -98,7 +98,7 @@ func AddColumnToProjectPost(ctx *context.Context) { } func EditProjectColumn(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.EditProjectColumnForm) + form := web.GetForm[*forms.EditProjectColumnForm](ctx) _, column := findColumn(ctx) if ctx.Written() { return diff --git a/routers/web/shared/secrets/secrets.go b/routers/web/shared/secrets/secrets.go index 5371436488..88078a3543 100644 --- a/routers/web/shared/secrets/secrets.go +++ b/routers/web/shared/secrets/secrets.go @@ -27,7 +27,7 @@ func SetSecretsContext(ctx *context.Context, ownerID, repoID int64) { } func PerformSecretsPost(ctx *context.Context, ownerID, repoID int64, redirectURL string) { - form := web.GetForm(ctx).(*forms.AddSecretForm) + form := web.GetForm[*forms.AddSecretForm](ctx) s, _, err := secret_service.CreateOrUpdateSecret(ctx, ownerID, repoID, form.Name, util.NormalizeStringEOL(form.Data), form.Description) if err != nil { diff --git a/routers/web/shared/user/block.go b/routers/web/shared/user/block.go index d08f2be6e8..beaed239fb 100644 --- a/routers/web/shared/user/block.go +++ b/routers/web/shared/user/block.go @@ -66,7 +66,7 @@ func BlockedUsersPost(ctx *context.Context, blocker *user_model.User, redirect s return } - form := web.GetForm(ctx).(*forms.BlockUserForm) + form := web.GetForm[*forms.BlockUserForm](ctx) err := blockedUsersPost(ctx, form, blocker) if err == nil { ctx.JSONRedirect(redirect) diff --git a/routers/web/user/package.go b/routers/web/user/package.go index 35a7ae88d0..102e347d9c 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -455,7 +455,7 @@ func PackageSettings(ctx *context.Context) { // PackageSettingsPost updates the package settings func PackageSettingsPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.PackageSettingForm) + form := web.GetForm[*forms.PackageSettingForm](ctx) switch form.Action { case "link": packageSettingsPostActionLink(ctx, form) diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go index 2901f36284..97e6e43b68 100644 --- a/routers/web/user/setting/account.go +++ b/routers/web/user/setting/account.go @@ -56,7 +56,7 @@ func AccountPost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.ChangePasswordForm) + form := web.GetForm[*forms.ChangePasswordForm](ctx) ctx.Data["Title"] = ctx.Tr("settings_title") ctx.Data["PageIsSettingsAccount"] = true ctx.Data["Email"] = ctx.Doer.Email @@ -106,7 +106,7 @@ func EmailPost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.AddEmailForm) + form := web.GetForm[*forms.AddEmailForm](ctx) ctx.Data["Title"] = ctx.Tr("settings_title") ctx.Data["PageIsSettingsAccount"] = true ctx.Data["Email"] = ctx.Doer.Email diff --git a/routers/web/user/setting/applications.go b/routers/web/user/setting/applications.go index c2adf2c695..942e753c2f 100644 --- a/routers/web/user/setting/applications.go +++ b/routers/web/user/setting/applications.go @@ -34,7 +34,7 @@ func Applications(ctx *context.Context) { // ApplicationsPost response for add user's access token func ApplicationsPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.NewAccessTokenForm) + form := web.GetForm[*forms.NewAccessTokenForm](ctx) ctx.Data["Title"] = ctx.Tr("settings_title") ctx.Data["PageIsSettingsApplications"] = true diff --git a/routers/web/user/setting/keys.go b/routers/web/user/setting/keys.go index 8713ce2619..de843e97f3 100644 --- a/routers/web/user/setting/keys.go +++ b/routers/web/user/setting/keys.go @@ -43,7 +43,7 @@ func Keys(ctx *context.Context) { // KeysPost response for change user's SSH/GPG keys func KeysPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.AddKeyForm) + form := web.GetForm[*forms.AddKeyForm](ctx) ctx.Data["Title"] = ctx.Tr("settings_title") ctx.Data["PageIsSettingsKeys"] = true ctx.Data["DisableSSH"] = setting.SSH.Disabled @@ -98,6 +98,8 @@ func KeysPost(ctx *context.Context) { } if err != nil { ctx.Data["HasGPGError"] = true + var errInvalidTokenSignature asymkey_model.ErrGPGInvalidTokenSignature + var errNoEmailFound asymkey_model.ErrGPGNoEmailFound switch { case asymkey_model.IsErrGPGKeyParsing(err): ctx.Flash.Error(ctx.Tr("form.invalid_gpg_key", err.Error())) @@ -107,20 +109,20 @@ func KeysPost(ctx *context.Context) { ctx.Data["Err_Content"] = true ctx.RenderWithErrDeprecated(ctx.Tr("settings.gpg_key_id_used"), tplSettingsKeys, &form) - case asymkey_model.IsErrGPGInvalidTokenSignature(err): + case errors.As(err, &errInvalidTokenSignature): loadKeysData(ctx) ctx.Data["Err_Content"] = true ctx.Data["Err_Signature"] = true - keyID := err.(asymkey_model.ErrGPGInvalidTokenSignature).ID + keyID := errInvalidTokenSignature.ID ctx.Data["KeyID"] = keyID ctx.Data["PaddedKeyID"] = asymkey_model.PaddedKeyID(keyID) ctx.RenderWithErrDeprecated(ctx.Tr("settings.gpg_invalid_token_signature"), tplSettingsKeys, &form) - case asymkey_model.IsErrGPGNoEmailFound(err): + case errors.As(err, &errNoEmailFound): loadKeysData(ctx) ctx.Data["Err_Content"] = true ctx.Data["Err_Signature"] = true - keyID := err.(asymkey_model.ErrGPGNoEmailFound).ID + keyID := errNoEmailFound.ID ctx.Data["KeyID"] = keyID ctx.Data["PaddedKeyID"] = asymkey_model.PaddedKeyID(keyID) ctx.RenderWithErrDeprecated(ctx.Tr("settings.gpg_no_key_email_found"), tplSettingsKeys, &form) @@ -149,12 +151,13 @@ func KeysPost(ctx *context.Context) { } if err != nil { ctx.Data["HasGPGVerifyError"] = true + var errInvalidTokenSignature asymkey_model.ErrGPGInvalidTokenSignature switch { - case asymkey_model.IsErrGPGInvalidTokenSignature(err): + case errors.As(err, &errInvalidTokenSignature): loadKeysData(ctx) ctx.Data["VerifyingID"] = form.KeyID ctx.Data["Err_Signature"] = true - keyID := err.(asymkey_model.ErrGPGInvalidTokenSignature).ID + keyID := errInvalidTokenSignature.ID ctx.Data["KeyID"] = keyID ctx.Data["PaddedKeyID"] = asymkey_model.PaddedKeyID(keyID) ctx.RenderWithErrDeprecated(ctx.Tr("settings.gpg_invalid_token_signature"), tplSettingsKeys, &form) @@ -224,11 +227,12 @@ func KeysPost(ctx *context.Context) { } if err != nil { ctx.Data["HasSSHVerifyError"] = true + var errInvalidTokenSignature asymkey_model.ErrSSHInvalidTokenSignature switch { - case asymkey_model.IsErrSSHInvalidTokenSignature(err): + case errors.As(err, &errInvalidTokenSignature): loadKeysData(ctx) ctx.Data["Err_Signature"] = true - ctx.Data["Fingerprint"] = err.(asymkey_model.ErrSSHInvalidTokenSignature).Fingerprint + ctx.Data["Fingerprint"] = errInvalidTokenSignature.Fingerprint ctx.RenderWithErrDeprecated(ctx.Tr("settings.ssh_invalid_token_signature"), tplSettingsKeys, &form) default: ctx.ServerError("VerifySSH", err) diff --git a/routers/web/user/setting/oauth2_common.go b/routers/web/user/setting/oauth2_common.go index 30b5ebe5ca..f2226adfed 100644 --- a/routers/web/user/setting/oauth2_common.go +++ b/routers/web/user/setting/oauth2_common.go @@ -23,8 +23,8 @@ type OAuth2CommonHandlers struct { TplAppEdit templates.TplName // the template for the application edit page } -func (oa *OAuth2CommonHandlers) renderEditPage(ctx *context.Context) { - app := ctx.Data["App"].(*auth.OAuth2Application) +func (oa *OAuth2CommonHandlers) renderEditPage(ctx *context.Context, app *auth.OAuth2Application) { + ctx.Data["App"] = app ctx.Data["FormActionPath"] = fmt.Sprintf("%s/%d", oa.BasePathEditPrefix, app.ID) if ctx.ContextUser != nil && ctx.ContextUser.IsOrganization() { @@ -39,7 +39,7 @@ func (oa *OAuth2CommonHandlers) renderEditPage(ctx *context.Context) { // AddApp adds an oauth2 application func (oa *OAuth2CommonHandlers) AddApp(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.EditOAuth2ApplicationForm) + form := web.GetForm[*forms.EditOAuth2ApplicationForm](ctx) if ctx.HasError() { ctx.Flash.Error(ctx.GetErrMsg()) // go to the application list page @@ -61,14 +61,13 @@ func (oa *OAuth2CommonHandlers) AddApp(ctx *context.Context) { // render the edit page with secret ctx.Flash.Success(ctx.Tr("settings.create_oauth2_application_success"), true) - ctx.Data["App"] = app ctx.Data["ClientSecret"], err = app.GenerateClientSecret(ctx) if err != nil { ctx.ServerError("GenerateClientSecret", err) return } - oa.renderEditPage(ctx) + oa.renderEditPage(ctx, app) } // EditShow displays the given application @@ -86,13 +85,12 @@ func (oa *OAuth2CommonHandlers) EditShow(ctx *context.Context) { ctx.NotFound(nil) return } - ctx.Data["App"] = app - oa.renderEditPage(ctx) + oa.renderEditPage(ctx, app) } // EditSave saves the oauth2 application func (oa *OAuth2CommonHandlers) EditSave(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.EditOAuth2ApplicationForm) + form := web.GetForm[*forms.EditOAuth2ApplicationForm](ctx) if ctx.HasError() { app, err := auth.GetOAuth2ApplicationByID(ctx, ctx.PathParamInt64("id")) @@ -108,9 +106,7 @@ func (oa *OAuth2CommonHandlers) EditSave(ctx *context.Context) { ctx.NotFound(nil) return } - ctx.Data["App"] = app - - oa.renderEditPage(ctx) + oa.renderEditPage(ctx, app) return } @@ -145,14 +141,13 @@ func (oa *OAuth2CommonHandlers) RegenerateSecret(ctx *context.Context) { ctx.NotFound(nil) return } - ctx.Data["App"] = app ctx.Data["ClientSecret"], err = app.GenerateClientSecret(ctx) if err != nil { ctx.ServerError("GenerateClientSecret", err) return } ctx.Flash.Success(ctx.Tr("settings.update_oauth2_application_success"), true) - oa.renderEditPage(ctx) + oa.renderEditPage(ctx, app) } // DeleteApp deletes the given oauth2 application diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go index ce52d40e10..d52ecb69d7 100644 --- a/routers/web/user/setting/profile.go +++ b/routers/web/user/setting/profile.go @@ -65,7 +65,7 @@ func ProfilePost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.UpdateProfileForm) + form := web.GetForm[*forms.UpdateProfileForm](ctx) if form.Name != "" { if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureChangeUsername) { @@ -175,7 +175,7 @@ func UpdateAvatarSetting(ctx *context.Context, form *forms.AvatarForm, ctxUser * // AvatarPost response for change user's avatar request func AvatarPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.AvatarForm) + form := web.GetForm[*forms.AvatarForm](ctx) if err := UpdateAvatarSetting(ctx, form, ctx.Doer); err != nil { ctx.Flash.Error(err.Error()) } else { @@ -354,7 +354,7 @@ func Appearance(ctx *context.Context) { // UpdateUIThemePost is used to update users' specific theme func UpdateUIThemePost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.UpdateThemeForm) + form := web.GetForm[*forms.UpdateThemeForm](ctx) ctx.Data["Title"] = ctx.Tr("settings_title") ctx.Data["PageIsSettingsAppearance"] = true @@ -384,7 +384,7 @@ func UpdateUIThemePost(ctx *context.Context) { // UpdateUserLang update a user's language func UpdateUserLang(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.UpdateLanguageForm) + form := web.GetForm[*forms.UpdateLanguageForm](ctx) ctx.Data["Title"] = ctx.Tr("settings_title") ctx.Data["PageIsSettingsAppearance"] = true diff --git a/routers/web/user/setting/security/2fa.go b/routers/web/user/setting/security/2fa.go index 23fd6763fa..1b65ccb85f 100644 --- a/routers/web/user/setting/security/2fa.go +++ b/routers/web/user/setting/security/2fa.go @@ -100,9 +100,8 @@ func DisableTwoFactor(ctx *context.Context) { func twofaGenerateSecretAndQr(ctx *context.Context) bool { var otpKey *otp.Key var err error - uri := ctx.Session.Get("twofaUri") - if uri != nil { - otpKey, err = otp.NewKeyFromURL(uri.(string)) + if uri, ok := ctx.Session.Get("twofaUri").(string); ok { + otpKey, err = otp.NewKeyFromURL(uri) if err != nil { ctx.ServerError("SettingsTwoFactor: Failed NewKeyFromURL: ", err) return false @@ -193,7 +192,7 @@ func EnrollTwoFactorPost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.TwoFactorAuthForm) + form := web.GetForm[*forms.TwoFactorAuthForm](ctx) ctx.Data["Title"] = ctx.Tr("settings_title") ctx.Data["PageIsSettingsSecurity"] = true ctx.Data["ShowTwoFactorRequiredMessage"] = false @@ -218,14 +217,13 @@ func EnrollTwoFactorPost(ctx *context.Context) { return } - secretRaw := ctx.Session.Get("twofaSecret") - if secretRaw == nil { + secret, ok := ctx.Session.Get("twofaSecret").(string) + if !ok { ctx.Flash.Error(ctx.Tr("settings.twofa_failed_get_secret")) ctx.Redirect(setting.AppSubURL + "/user/settings/security/two_factor/enroll") return } - secret := secretRaw.(string) if !totp.Validate(form.Passcode, secret) { if !twofaGenerateSecretAndQr(ctx) { return diff --git a/routers/web/user/setting/security/openid.go b/routers/web/user/setting/security/openid.go index 9a506f3685..b2cf7b23b5 100644 --- a/routers/web/user/setting/security/openid.go +++ b/routers/web/user/setting/security/openid.go @@ -24,7 +24,7 @@ func OpenIDPost(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.AddOpenIDForm) + form := web.GetForm[*forms.AddOpenIDForm](ctx) ctx.Data["Title"] = ctx.Tr("settings_title") ctx.Data["PageIsSettingsSecurity"] = true diff --git a/routers/web/user/setting/security/webauthn.go b/routers/web/user/setting/security/webauthn.go index 3e46d20ca4..4b1daeed21 100644 --- a/routers/web/user/setting/security/webauthn.go +++ b/routers/web/user/setting/security/webauthn.go @@ -30,7 +30,7 @@ func WebAuthnRegister(ctx *context.Context) { return } - form := web.GetForm(ctx).(*forms.WebauthnRegistrationForm) + form := web.GetForm[*forms.WebauthnRegistrationForm](ctx) if form.Name == "" { // Set name to the hexadecimal of the current time form.Name = strconv.FormatInt(time.Now().UnixNano(), 16) diff --git a/routers/web/web.go b/routers/web/web.go index b7193da8cd..34acdd4edb 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -244,11 +244,9 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.Cont } } -func ctxDataSet(args ...any) func(ctx *context.Context) { +func ctxDataSet(data reqctx.ContextData) func(ctx *context.Context) { return func(ctx *context.Context) { - for i := 0; i < len(args); i += 2 { - ctx.Data[args[i].(string)] = args[i+1] - } + ctx.Data.MergeFrom(data) } } @@ -893,7 +891,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { addSettingsVariablesRoutes() addSettingsScopedWorkflowsRoutes() }) - }, adminReq, ctxDataSet("EnableOAuth2", setting.OAuth2.Enabled, "EnablePackages", setting.Packages.Enabled)) + }, adminReq, ctxDataSet(reqctx.ContextData{"EnableOAuth2": setting.OAuth2.Enabled, "EnablePackages": setting.Packages.Enabled})) // ***** END: Admin ***** m.Group("", func() { @@ -1079,7 +1077,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Get("", org.BlockedUsers) m.Post("", web.Bind(forms.BlockUserForm{}), org.BlockedUsersPost) }) - }, ctxDataSet("EnableOAuth2", setting.OAuth2.Enabled, "EnablePackages", setting.Packages.Enabled, "PageIsOrgSettings", true)) + }, ctxDataSet(reqctx.ContextData{"EnableOAuth2": setting.OAuth2.Enabled, "EnablePackages": setting.Packages.Enabled, "PageIsOrgSettings": true})) }, context.OrgAssignment(context.OrgAssignmentOptions{RequireOwner: true})) }, reqSignIn) // end "/org": most org routes @@ -1268,7 +1266,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { }) }, reqSignIn, context.RepoAssignment, reqRepoAdmin, - ctxDataSet("PageIsRepoSettings", true, "LFSStartServer", setting.LFS.StartServer), + ctxDataSet(reqctx.ContextData{"PageIsRepoSettings": true, "LFSStartServer": setting.LFS.StartServer}), ) // end "/{username}/{reponame}/settings" @@ -1481,7 +1479,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Get(".rss", webAuth.AllowBasic, feedEnabled, repo.TagsListFeedRSS) m.Get(".atom", webAuth.AllowBasic, feedEnabled, repo.TagsListFeedAtom) m.Get("/list", repo.GetTagList) - }, ctxDataSet("EnableFeed", setting.Other.EnableFeed)) + }, ctxDataSet(reqctx.ContextData{"EnableFeed": setting.Other.EnableFeed})) m.Post("/tags/delete", reqSignIn, reqRepoCodeWriter, context.RepoMustNotBeArchived(), repo.DeleteTag) }, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqUnitCodeReader) // end "/{username}/{reponame}": repo tags @@ -1493,7 +1491,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Get(".atom", webAuth.AllowBasic, feedEnabled, repo.ReleasesFeedAtom) m.Get("/tag/*", repo.SingleRelease) m.Get("/latest", repo.LatestRelease) - }, ctxDataSet("EnableFeed", setting.Other.EnableFeed)) + }, ctxDataSet(reqctx.ContextData{"EnableFeed": setting.Other.EnableFeed})) m.Get("/releases/attachments/{uuid}", webAuth.AllowBasic, webAuth.AllowOAuth2, repo.GetAttachment) m.Get("/releases/download/{vTag}/{fileName}", webAuth.AllowBasic, webAuth.AllowOAuth2, repo.RedirectDownload) m.Group("/releases", func() { diff --git a/services/actions/context.go b/services/actions/context.go index 667de24ec6..ed40fd6a21 100644 --- a/services/actions/context.go +++ b/services/actions/context.go @@ -20,7 +20,6 @@ import ( "gitea.dev/modules/optional" "gitea.dev/modules/setting" api "gitea.dev/modules/structs" - "gitea.dev/modules/util" ) type GiteaContext map[string]any @@ -318,36 +317,45 @@ func mergeTwoOutputs(o1, o2 map[string]string) map[string]string { return ret } +func contextMapValueOrDefault[T any](m map[string]any, key string, defaultValue T) T { + if value, ok := m[key]; ok { + if v, ok := value.(T); ok { + return v + } + } + return defaultValue +} + func (g *GiteaContext) ToGitHubContext() *model.GithubContext { return &model.GithubContext{ - Event: util.GetMapValueOrDefault(*g, "event", map[string]any(nil)), - EventPath: util.GetMapValueOrDefault(*g, "event_path", ""), - Workflow: util.GetMapValueOrDefault(*g, "workflow", ""), - RunID: util.GetMapValueOrDefault(*g, "run_id", ""), - RunNumber: util.GetMapValueOrDefault(*g, "run_number", ""), - Actor: util.GetMapValueOrDefault(*g, "actor", ""), - Repository: util.GetMapValueOrDefault(*g, "repository", ""), - EventName: util.GetMapValueOrDefault(*g, "event_name", ""), - Sha: util.GetMapValueOrDefault(*g, "sha", ""), - Ref: util.GetMapValueOrDefault(*g, "ref", ""), - RefName: util.GetMapValueOrDefault(*g, "ref_name", ""), - RefType: util.GetMapValueOrDefault(*g, "ref_type", ""), - HeadRef: util.GetMapValueOrDefault(*g, "head_ref", ""), - BaseRef: util.GetMapValueOrDefault(*g, "base_ref", ""), + Event: contextMapValueOrDefault(*g, "event", map[string]any(nil)), + EventPath: contextMapValueOrDefault(*g, "event_path", ""), + Workflow: contextMapValueOrDefault(*g, "workflow", ""), + RunID: contextMapValueOrDefault(*g, "run_id", ""), + RunNumber: contextMapValueOrDefault(*g, "run_number", ""), + Actor: contextMapValueOrDefault(*g, "actor", ""), + Repository: contextMapValueOrDefault(*g, "repository", ""), + EventName: contextMapValueOrDefault(*g, "event_name", ""), + Sha: contextMapValueOrDefault(*g, "sha", ""), + Ref: contextMapValueOrDefault(*g, "ref", ""), + RefName: contextMapValueOrDefault(*g, "ref_name", ""), + RefType: contextMapValueOrDefault(*g, "ref_type", ""), + HeadRef: contextMapValueOrDefault(*g, "head_ref", ""), + BaseRef: contextMapValueOrDefault(*g, "base_ref", ""), Token: "", // deliberately omitted for security - Workspace: util.GetMapValueOrDefault(*g, "workspace", ""), - Action: util.GetMapValueOrDefault(*g, "action", ""), - ActionPath: util.GetMapValueOrDefault(*g, "action_path", ""), - ActionRef: util.GetMapValueOrDefault(*g, "action_ref", ""), - ActionRepository: util.GetMapValueOrDefault(*g, "action_repository", ""), - Job: util.GetMapValueOrDefault(*g, "job", ""), + Workspace: contextMapValueOrDefault(*g, "workspace", ""), + Action: contextMapValueOrDefault(*g, "action", ""), + ActionPath: contextMapValueOrDefault(*g, "action_path", ""), + ActionRef: contextMapValueOrDefault(*g, "action_ref", ""), + ActionRepository: contextMapValueOrDefault(*g, "action_repository", ""), + Job: contextMapValueOrDefault(*g, "job", ""), JobName: "", // not present in GiteaContext - RepositoryOwner: util.GetMapValueOrDefault(*g, "repository_owner", ""), - RetentionDays: util.GetMapValueOrDefault(*g, "retention_days", ""), + RepositoryOwner: contextMapValueOrDefault(*g, "repository_owner", ""), + RetentionDays: contextMapValueOrDefault(*g, "retention_days", ""), RunnerPerflog: "", // not present in GiteaContext RunnerTrackingID: "", // not present in GiteaContext - ServerURL: util.GetMapValueOrDefault(*g, "server_url", ""), - APIURL: util.GetMapValueOrDefault(*g, "api_url", ""), - GraphQLURL: util.GetMapValueOrDefault(*g, "graphql_url", ""), + ServerURL: contextMapValueOrDefault(*g, "server_url", ""), + APIURL: contextMapValueOrDefault(*g, "api_url", ""), + GraphQLURL: contextMapValueOrDefault(*g, "graphql_url", ""), } } diff --git a/services/actions/schedule_tasks_test.go b/services/actions/schedule_tasks_test.go index 8514625486..d1e154a8a0 100644 --- a/services/actions/schedule_tasks_test.go +++ b/services/actions/schedule_tasks_test.go @@ -10,6 +10,7 @@ import ( api "gitea.dev/modules/structs" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestWithScheduleInEventPayload(t *testing.T) { @@ -49,9 +50,15 @@ func TestWithScheduleInEventPayload(t *testing.T) { event := map[string]any{} assert.NoError(t, json.Unmarshal([]byte(updated), &event)) assert.Equal(t, "@weekly", event["schedule"]) - assert.Equal(t, "test-repo", event["repository"].(map[string]any)["name"]) - assert.Equal(t, "test-user", event["sender"].(map[string]any)["login"]) - assert.Equal(t, "test-org", event["organization"].(map[string]any)["name"]) + repository, ok := event["repository"].(map[string]any) + require.True(t, ok) + assert.Equal(t, "test-repo", repository["name"]) + sender, ok := event["sender"].(map[string]any) + require.True(t, ok) + assert.Equal(t, "test-user", sender["login"]) + organization, ok := event["organization"].(map[string]any) + require.True(t, ok) + assert.Equal(t, "test-org", organization["name"]) }) t.Run("keeps payload when schedule empty", func(t *testing.T) { diff --git a/services/asymkey/ssh_key_authorized_principals.go b/services/asymkey/ssh_key_authorized_principals.go index 9a5163b3be..1a3dfd80e9 100644 --- a/services/asymkey/ssh_key_authorized_principals.go +++ b/services/asymkey/ssh_key_authorized_principals.go @@ -18,6 +18,8 @@ import ( "gitea.dev/modules/log" "gitea.dev/modules/setting" "gitea.dev/modules/util" + + "xorm.io/builder" ) // This file contains functions for creating authorized_principals files @@ -88,8 +90,8 @@ func rewriteAllPrincipalKeys(ctx context.Context) error { } func regeneratePrincipalKeys(ctx context.Context, t io.Writer) error { - if err := db.GetEngine(ctx).Where("type = ?", asymkey_model.KeyTypePrincipal).Iterate(new(asymkey_model.PublicKey), func(idx int, bean any) (err error) { - return asymkey_model.WriteAuthorizedStringForValidKey(bean.(*asymkey_model.PublicKey), t) + if err := db.Iterate(ctx, builder.Eq{"type": asymkey_model.KeyTypePrincipal}, func(ctx context.Context, key *asymkey_model.PublicKey) error { + return asymkey_model.WriteAuthorizedStringForValidKey(key, t) }); err != nil { return err } diff --git a/services/auth/basic.go b/services/auth/basic.go index 26883a3746..8ef6333c21 100644 --- a/services/auth/basic.go +++ b/services/auth/basic.go @@ -187,8 +187,8 @@ func validateTOTP(req *http.Request, u *user_model.User) error { } func GetAccessScope(store DataStore) auth_model.AccessTokenScope { - if v, ok := store.GetData()["ApiTokenScope"]; ok { - return v.(auth_model.AccessTokenScope) + if scope, ok := store.GetData()["ApiTokenScope"].(auth_model.AccessTokenScope); ok { + return scope } switch store.GetData()["LoginMethod"] { case OAuth2TokenMethodName: diff --git a/services/auth/httpsign.go b/services/auth/httpsign.go index 929f5da6a4..5e1325db60 100644 --- a/services/auth/httpsign.go +++ b/services/auth/httpsign.go @@ -197,7 +197,11 @@ func VerifyCert(r *http.Request) (*asymkey_model.PublicKey, error) { // doVerify iterates across the provided public keys attempting the verify the current request against each key in turn func doVerify(verifier httpsig.Verifier, sshPublicKeys []ssh.PublicKey) error { for _, publicKey := range sshPublicKeys { - cryptoPubkey := publicKey.(ssh.CryptoPublicKey).CryptoPublicKey() + cryptoPublicKey, ok := publicKey.(ssh.CryptoPublicKey) + if !ok { + continue + } + cryptoPubkey := cryptoPublicKey.CryptoPublicKey() var algos []httpsig.Algorithm diff --git a/services/auth/sspi.go b/services/auth/sspi.go index 5cec793d23..185c37edda 100644 --- a/services/auth/sspi.go +++ b/services/auth/sspi.go @@ -143,7 +143,7 @@ func (s *SSPI) getConfig(ctx context.Context) (*sspi.Source, error) { if len(sources) > 1 { return nil, errors.New("more than one active login source of type SSPI found") } - return sources[0].Cfg.(*sspi.Source), nil + return auth.MustSourceCfg[*sspi.Source](sources[0]), nil } func (s *SSPI) shouldAuthenticate(req *http.Request) (shouldAuth bool) { diff --git a/services/context/access_log.go b/services/context/access_log.go index 7d89269338..ecc6163a1b 100644 --- a/services/context/access_log.go +++ b/services/context/access_log.go @@ -122,8 +122,9 @@ func AccessLogger() func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { start := time.Now() - next.ServeHTTP(w, req) - recorder.record(start, w.(ResponseWriter), req) + respWriter := WrapResponseWriter(w) + next.ServeHTTP(respWriter, req) + recorder.record(start, respWriter, req) }) } } diff --git a/services/context/api.go b/services/context/api.go index 50772bcea6..9b6cc33c7e 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -20,6 +20,7 @@ import ( "gitea.dev/modules/git" "gitea.dev/modules/httpcache" "gitea.dev/modules/log" + "gitea.dev/modules/reqctx" "gitea.dev/modules/setting" "gitea.dev/modules/util" "gitea.dev/modules/web" @@ -56,7 +57,7 @@ func (ctx *APIContext) TokenCanAccessRepo(repo *repo_model.Repository) bool { func init() { web.RegisterResponseStatusProvider[*APIContext](func(req *http.Request) web_types.ResponseStatusProvider { - return req.Context().Value(apiContextKey).(*APIContext) + return GetAPIContext(req) }) } @@ -185,7 +186,7 @@ var apiContextKey = apiContextKeyType{} // GetAPIContext returns a context for API routes func GetAPIContext(req *http.Request) *APIContext { - return req.Context().Value(apiContextKey).(*APIContext) + return reqctx.MustContextValue[*APIContext](req.Context(), apiContextKey) } func genAPILinks(curURL *url.URL, total int64, pageSize, curPage int) []string { diff --git a/services/context/context.go b/services/context/context.go index c1e438975f..89de5fb630 100644 --- a/services/context/context.go +++ b/services/context/context.go @@ -65,10 +65,10 @@ type Context struct { func init() { web.RegisterResponseStatusProvider[*Base](func(req *http.Request) web_types.ResponseStatusProvider { - return req.Context().Value(BaseContextKey).(*Base) + return reqctx.MustContextValue[*Base](req.Context(), BaseContextKey) }) web.RegisterResponseStatusProvider[*Context](func(req *http.Request) web_types.ResponseStatusProvider { - return req.Context().Value(WebContextKey).(*Context) + return reqctx.MustContextValue[*Context](req.Context(), WebContextKey) }) } diff --git a/services/context/context_template.go b/services/context/context_template.go index 27d02a4566..2d1063ec25 100644 --- a/services/context/context_template.go +++ b/services/context/context_template.go @@ -29,11 +29,11 @@ func NewTemplateContext(ctx context.Context, req *http.Request) TemplateContext } func (c TemplateContext) req() *http.Request { - return c["_req"].(*http.Request) + return c["_req"].(*http.Request) //nolint:forcetypeassert // must exist } func (c TemplateContext) parentContext() context.Context { - return c["_ctx"].(context.Context) + return c["_ctx"].(context.Context) //nolint:forcetypeassert // must exist } func (c TemplateContext) Deadline() (deadline time.Time, ok bool) { diff --git a/services/context/private.go b/services/context/private.go index a761706ea3..0adfaeafcd 100644 --- a/services/context/private.go +++ b/services/context/private.go @@ -13,6 +13,7 @@ import ( "gitea.dev/modules/log" "gitea.dev/modules/private" "gitea.dev/modules/process" + "gitea.dev/modules/reqctx" "gitea.dev/modules/web" web_types "gitea.dev/modules/web/types" ) @@ -27,7 +28,7 @@ type PrivateContext struct { func init() { web.RegisterResponseStatusProvider[*PrivateContext](func(req *http.Request) web_types.ResponseStatusProvider { - return req.Context().Value(privateContextKey).(*PrivateContext) + return GetPrivateContext(req) }) } @@ -67,7 +68,7 @@ type privateContextKeyType struct{} var privateContextKey privateContextKeyType func GetPrivateContext(req *http.Request) *PrivateContext { - return req.Context().Value(privateContextKey).(*PrivateContext) + return reqctx.MustContextValue[*PrivateContext](req.Context(), privateContextKey) } func PrivateContexter() func(http.Handler) http.Handler { diff --git a/services/context/repo.go b/services/context/repo.go index da5dc68952..4345e2f7b0 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -193,8 +193,8 @@ func PrepareCommitFormOptions(ctx *Context, doer *user_model.User, targetRepo *r willSign, signKey, _, err := asymkey_service.SignCRUDAction(ctx, doer, targetGitRepo, refName.String()) wontSignReason := "" - if asymkey_service.IsErrWontSign(err) { - wontSignReason = string(err.(*asymkey_service.ErrWontSign).Reason) + if errWontSign, ok := err.(*asymkey_service.ErrWontSign); ok { + wontSignReason = string(errWontSign.Reason) } else if err != nil { return nil, err } @@ -964,7 +964,7 @@ func RepoRefByType(detectRefType git.RefType) func(*Context) { ctx.Repo.RefFullName = repoRefFullName(refType, refShortName) isRenamedBranch, has := ctx.Data["IsRenamedBranch"].(bool) if isRenamedBranch && has { - renamedBranchName := ctx.Data["RenamedBranchName"].(string) + renamedBranchName := ctx.Data["RenamedBranchName"].(string) //nolint:forcetypeassert // must exist ctx.Flash.Info(ctx.Tr("repo.branch.renamed", refShortName, renamedBranchName)) link := setting.AppSubURL + strings.Replace(ctx.Req.URL.EscapedPath(), util.PathEscapeSegments(refShortName), util.PathEscapeSegments(renamedBranchName), 1) ctx.Redirect(link) diff --git a/services/cron/tasks.go b/services/cron/tasks.go index 74ab23a3d1..2b890834da 100644 --- a/services/cron/tasks.go +++ b/services/cron/tasks.go @@ -58,11 +58,9 @@ func (t *Task) IsEnabled() bool { // GetConfig will return a copy of the task's config func (t *Task) GetConfig() Config { if reflect.TypeOf(t.config).Kind() == reflect.Pointer { - // Pointer: - return reflect.New(reflect.ValueOf(t.config).Elem().Type()).Interface().(Config) + return reflect.New(reflect.ValueOf(t.config).Elem().Type()).Interface().(Config) //nolint:forcetypeassert // pointer } - // Not pointer: - return reflect.New(reflect.TypeOf(t.config)).Elem().Interface().(Config) + return reflect.New(reflect.TypeOf(t.config)).Elem().Interface().(Config) //nolint:forcetypeassert // not pointer } // Run will run the task incrementing the cron counter with no user defined @@ -124,9 +122,9 @@ func (t *Task) RunWithUser(doer *user_model.User, config Config) { if err := t.fun(ctx, doer, config); err != nil { var message string var status string - if db.IsErrCancelled(err) { + if errCancelled, ok := err.(db.ErrCancelled); ok { status = "cancelled" - message = err.(db.ErrCancelled).Message + message = errCancelled.Message } else { status = "error" message = err.Error() @@ -168,7 +166,7 @@ func GetTask(name string) *Task { } // RegisterTask allows a task to be registered with the cron service -func RegisterTask(name string, config Config, fun func(context.Context, *user_model.User, Config) error) error { +func RegisterTask[T Config](name string, config T, fun func(context.Context, *user_model.User, T) error) error { log.Debug("Registering task: %s", name) i18nKey := "admin.dashboard." + name @@ -185,7 +183,9 @@ func RegisterTask(name string, config Config, fun func(context.Context, *user_mo task := &Task{ Name: name, config: config, - fun: fun, + fun: func(ctx context.Context, doer *user_model.User, runConfig Config) error { + return fun(ctx, doer, runConfig.(T)) //nolint:forcetypeassert // must be valid + }, } lock.Lock() locked := true @@ -218,7 +218,7 @@ func RegisterTask(name string, config Config, fun func(context.Context, *user_mo } // RegisterTaskFatal will register a task but if there is an error log.Fatal -func RegisterTaskFatal(name string, config Config, fun func(context.Context, *user_model.User, Config) error) { +func RegisterTaskFatal[T Config](name string, config T, fun func(context.Context, *user_model.User, T) error) { if err := RegisterTask(name, config, fun); err != nil { log.Fatal("Unable to register cron task %s Error: %v", name, err) } diff --git a/services/cron/tasks_actions.go b/services/cron/tasks_actions.go index 323aa64260..0f5851babf 100644 --- a/services/cron/tasks_actions.go +++ b/services/cron/tasks_actions.go @@ -27,7 +27,7 @@ func registerStopZombieTasks() { Enabled: true, RunAtStart: true, Schedule: "@every 5m", - }, func(ctx context.Context, _ *user_model.User, cfg Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { return actions_service.StopZombieTasks(ctx) }) } @@ -37,7 +37,7 @@ func registerStopEndlessTasks() { Enabled: true, RunAtStart: true, Schedule: "@every 30m", - }, func(ctx context.Context, _ *user_model.User, cfg Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { return actions_service.StopEndlessTasks(ctx) }) } @@ -47,7 +47,7 @@ func registerCancelAbandonedJobs() { Enabled: true, RunAtStart: true, Schedule: "@every 6h", - }, func(ctx context.Context, _ *user_model.User, cfg Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { return actions_service.CancelAbandonedJobs(ctx) }) } @@ -59,7 +59,7 @@ func registerScheduleTasks() { Enabled: true, RunAtStart: false, Schedule: "@every 1m", - }, func(ctx context.Context, _ *user_model.User, cfg Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { // Call the function to start schedule tasks and pass the context. return actions_service.StartScheduleTasks(ctx) }) @@ -70,7 +70,7 @@ func registerActionsCleanup() { Enabled: true, RunAtStart: false, Schedule: "@midnight", - }, func(ctx context.Context, _ *user_model.User, _ Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { return actions_service.Cleanup(ctx) }) } diff --git a/services/cron/tasks_basic.go b/services/cron/tasks_basic.go index 34183b2271..06be3bdaf8 100644 --- a/services/cron/tasks_basic.go +++ b/services/cron/tasks_basic.go @@ -36,9 +36,8 @@ func registerUpdateMirrorTask() { }, PullLimit: 50, PushLimit: 50, - }, func(ctx context.Context, _ *user_model.User, cfg Config) error { - umtc := cfg.(*UpdateMirrorTaskConfig) - return mirror_service.Update(ctx, umtc.PullLimit, umtc.PushLimit) + }, func(ctx context.Context, _ *user_model.User, cfg *UpdateMirrorTaskConfig) error { + return mirror_service.Update(ctx, cfg.PullLimit, cfg.PushLimit) }) } @@ -56,10 +55,9 @@ func registerRepoHealthCheck() { }, Timeout: time.Duration(setting.Git.Timeout.GC) * time.Second, Args: []string{}, - }, func(ctx context.Context, _ *user_model.User, config Config) error { - rhcConfig := config.(*RepoHealthCheckConfig) + }, func(ctx context.Context, _ *user_model.User, config *RepoHealthCheckConfig) error { // the git args are set by config, they can be safe to be trusted - return repo_service.GitFsckRepos(ctx, rhcConfig.Timeout, gitcmd.ToTrustedCmdArgs(rhcConfig.Args)) + return repo_service.GitFsckRepos(ctx, config.Timeout, gitcmd.ToTrustedCmdArgs(config.Args)) }) } @@ -68,7 +66,7 @@ func registerCheckRepoStats() { Enabled: true, RunAtStart: true, Schedule: "@midnight", - }, func(ctx context.Context, _ *user_model.User, _ Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { return repostats.CheckRepoStats(ctx) }) } @@ -81,9 +79,8 @@ func registerArchiveCleanup() { Schedule: "@midnight", }, OlderThan: 24 * time.Hour, - }, func(ctx context.Context, _ *user_model.User, config Config) error { - acConfig := config.(*OlderThanConfig) - return archiver_service.DeleteOldRepositoryArchives(ctx, acConfig.OlderThan) + }, func(ctx context.Context, _ *user_model.User, config *OlderThanConfig) error { + return archiver_service.DeleteOldRepositoryArchives(ctx, config.OlderThan) }) } @@ -95,9 +92,8 @@ func registerSyncExternalUsers() { Schedule: "@midnight", }, UpdateExisting: true, - }, func(ctx context.Context, _ *user_model.User, config Config) error { - realConfig := config.(*UpdateExistingConfig) - return auth.SyncExternalUsers(ctx, realConfig.UpdateExisting) + }, func(ctx context.Context, _ *user_model.User, config *UpdateExistingConfig) error { + return auth.SyncExternalUsers(ctx, config.UpdateExisting) }) } @@ -109,9 +105,8 @@ func registerDeletedBranchesCleanup() { Schedule: "@midnight", }, OlderThan: 24 * time.Hour, - }, func(ctx context.Context, _ *user_model.User, config Config) error { - realConfig := config.(*OlderThanConfig) - git_model.RemoveOldDeletedBranches(ctx, realConfig.OlderThan) + }, func(ctx context.Context, _ *user_model.User, config *OlderThanConfig) error { + git_model.RemoveOldDeletedBranches(ctx, config.OlderThan) return nil }) } @@ -121,7 +116,7 @@ func registerUpdateMigrationPosterID() { Enabled: true, RunAtStart: true, Schedule: "@midnight", - }, func(ctx context.Context, _ *user_model.User, _ Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { return migrations.UpdateMigrationPosterID(ctx) }) } @@ -136,9 +131,8 @@ func registerCleanupHookTaskTable() { CleanupType: "OlderThan", OlderThan: 168 * time.Hour, NumberToKeep: 10, - }, func(ctx context.Context, _ *user_model.User, config Config) error { - realConfig := config.(*CleanupHookTaskConfig) - return webhook.CleanupHookTaskTable(ctx, webhook.ToHookTaskCleanupType(realConfig.CleanupType), realConfig.OlderThan, realConfig.NumberToKeep) + }, func(ctx context.Context, _ *user_model.User, config *CleanupHookTaskConfig) error { + return webhook.CleanupHookTaskTable(ctx, webhook.ToHookTaskCleanupType(config.CleanupType), config.OlderThan, config.NumberToKeep) }) } @@ -150,9 +144,8 @@ func registerCleanupPackages() { Schedule: "@midnight", }, OlderThan: 24 * time.Hour, - }, func(ctx context.Context, _ *user_model.User, config Config) error { - realConfig := config.(*OlderThanConfig) - return packages_cleanup_service.CleanupTask(ctx, realConfig.OlderThan) + }, func(ctx context.Context, _ *user_model.User, config *OlderThanConfig) error { + return packages_cleanup_service.CleanupTask(ctx, config.OlderThan) }) } @@ -161,7 +154,7 @@ func registerSyncRepoLicenses() { Enabled: false, RunAtStart: false, Schedule: "@annually", - }, func(ctx context.Context, _ *user_model.User, config Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { return repo_service.SyncRepoLicenses(ctx) }) } diff --git a/services/cron/tasks_extended.go b/services/cron/tasks_extended.go index b0706be1b1..842d2621d3 100644 --- a/services/cron/tasks_extended.go +++ b/services/cron/tasks_extended.go @@ -28,9 +28,8 @@ func registerDeleteInactiveUsers() { Schedule: "@annually", }, OlderThan: time.Minute * time.Duration(setting.Service.ActiveCodeLives), - }, func(ctx context.Context, _ *user_model.User, config Config) error { - olderThanConfig := config.(*OlderThanConfig) - return user_service.DeleteInactiveUsers(ctx, olderThanConfig.OlderThan) + }, func(ctx context.Context, _ *user_model.User, config *OlderThanConfig) error { + return user_service.DeleteInactiveUsers(ctx, config.OlderThan) }) } @@ -39,7 +38,7 @@ func registerDeleteRepositoryArchives() { Enabled: false, RunAtStart: false, Schedule: "@annually", - }, func(ctx context.Context, _ *user_model.User, _ Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { return archiver_service.DeleteRepositoryArchives(ctx) }) } @@ -58,10 +57,9 @@ func registerGarbageCollectRepositories() { }, Timeout: time.Duration(setting.Git.Timeout.GC) * time.Second, Args: setting.Git.GCArgs, - }, func(ctx context.Context, _ *user_model.User, config Config) error { - rhcConfig := config.(*RepoHealthCheckConfig) + }, func(ctx context.Context, _ *user_model.User, config *RepoHealthCheckConfig) error { // the git args are set by config, they can be safe to be trusted - return repo_service.GitGcRepos(ctx, rhcConfig.Timeout, gitcmd.ToTrustedCmdArgs(rhcConfig.Args)) + return repo_service.GitGcRepos(ctx, config.Timeout, gitcmd.ToTrustedCmdArgs(config.Args)) }) } @@ -70,7 +68,7 @@ func registerRewriteAllPublicKeys() { Enabled: false, RunAtStart: false, Schedule: "@every 72h", - }, func(ctx context.Context, _ *user_model.User, _ Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { return asymkey_service.RewriteAllPublicKeys(ctx) }) } @@ -80,7 +78,7 @@ func registerRewriteAllPrincipalKeys() { Enabled: false, RunAtStart: false, Schedule: "@every 72h", - }, func(ctx context.Context, _ *user_model.User, _ Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { return asymkey_service.RewriteAllPrincipalKeys(ctx) }) } @@ -90,7 +88,7 @@ func registerRepositoryUpdateHook() { Enabled: false, RunAtStart: false, Schedule: "@every 72h", - }, func(ctx context.Context, _ *user_model.User, _ Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { return repo_service.SyncRepositoryHooks(ctx) }) } @@ -100,7 +98,7 @@ func registerReinitMissingRepositories() { Enabled: false, RunAtStart: false, Schedule: "@every 72h", - }, func(ctx context.Context, _ *user_model.User, _ Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { return repo_service.ReinitMissingRepositories(ctx) }) } @@ -110,7 +108,7 @@ func registerDeleteMissingRepositories() { Enabled: false, RunAtStart: false, Schedule: "@every 72h", - }, func(ctx context.Context, user *user_model.User, _ Config) error { + }, func(ctx context.Context, user *user_model.User, _ *BaseConfig) error { return repo_service.DeleteMissingRepositories(ctx, user) }) } @@ -120,7 +118,7 @@ func registerRemoveRandomAvatars() { Enabled: false, RunAtStart: false, Schedule: "@every 72h", - }, func(ctx context.Context, _ *user_model.User, _ Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { return repo_service.RemoveRandomAvatars(ctx) }) } @@ -133,9 +131,8 @@ func registerDeleteOldActions() { Schedule: "@every 168h", }, OlderThan: 365 * 24 * time.Hour, - }, func(ctx context.Context, _ *user_model.User, config Config) error { - olderThanConfig := config.(*OlderThanConfig) - return activities_model.DeleteOldActions(ctx, olderThanConfig.OlderThan) + }, func(ctx context.Context, _ *user_model.User, config *OlderThanConfig) error { + return activities_model.DeleteOldActions(ctx, config.OlderThan) }) } @@ -151,9 +148,8 @@ func registerUpdateGiteaChecker() { Schedule: "@every 168h", }, HTTPEndpoint: "https://dl.gitea.com/gitea/version.json", - }, func(ctx context.Context, _ *user_model.User, config Config) error { - updateCheckerConfig := config.(*UpdateCheckerConfig) - return updatechecker.GiteaUpdateChecker(updateCheckerConfig.HTTPEndpoint) + }, func(ctx context.Context, _ *user_model.User, config *UpdateCheckerConfig) error { + return updatechecker.GiteaUpdateChecker(config.HTTPEndpoint) }) } @@ -165,9 +161,8 @@ func registerDeleteOldSystemNotices() { Schedule: "@every 168h", }, OlderThan: 365 * 24 * time.Hour, - }, func(ctx context.Context, _ *user_model.User, config Config) error { - olderThanConfig := config.(*OlderThanConfig) - return system.DeleteOldSystemNotices(ctx, olderThanConfig.OlderThan) + }, func(ctx context.Context, _ *user_model.User, config *OlderThanConfig) error { + return system.DeleteOldSystemNotices(ctx, config.OlderThan) }) } @@ -204,12 +199,11 @@ func registerGCLFS() { LastUpdatedMoreThanAgo: 24 * time.Hour * 3, NumberToCheckPerRepo: 100, ProportionToCheckPerRepo: 0.6, - }, func(ctx context.Context, _ *user_model.User, config Config) error { - gcLFSConfig := config.(*GCLFSConfig) + }, func(ctx context.Context, _ *user_model.User, config *GCLFSConfig) error { return repo_service.GarbageCollectLFSMetaObjects(ctx, repo_service.GarbageCollectLFSMetaObjectsOptions{ AutoFix: true, - OlderThan: time.Now().Add(-gcLFSConfig.OlderThan), - UpdatedLessRecentlyThan: time.Now().Add(-gcLFSConfig.LastUpdatedMoreThanAgo), + OlderThan: time.Now().Add(-config.OlderThan), + UpdatedLessRecentlyThan: time.Now().Add(-config.LastUpdatedMoreThanAgo), }) }) } @@ -219,7 +213,7 @@ func registerRebuildIssueIndexer() { Enabled: false, RunAtStart: false, Schedule: "@annually", - }, func(ctx context.Context, _ *user_model.User, config Config) error { + }, func(ctx context.Context, _ *user_model.User, _ *BaseConfig) error { return issue_indexer.PopulateIssueIndexer(ctx) }) } diff --git a/services/doctor/misc.go b/services/doctor/misc.go index 21193b4752..67c205da66 100644 --- a/services/doctor/misc.go +++ b/services/doctor/misc.go @@ -71,7 +71,7 @@ func checkUserStarNum(ctx context.Context, logger log.Logger, autofix bool) erro func checkDaemonExport(ctx context.Context, logger log.Logger, autofix bool) error { numRepos := 0 numNeedUpdate := 0 - cache, err := lru.New[int64, any](512) + cache, err := lru.New[int64, *user_model.User](512) if err != nil { logger.Critical("Unable to create cache: %v", err) return err @@ -80,7 +80,7 @@ func checkDaemonExport(ctx context.Context, logger log.Logger, autofix bool) err numRepos++ if owner, has := cache.Get(repo.OwnerID); has { - repo.Owner = owner.(*user_model.User) + repo.Owner = owner } else { if err := repo.LoadOwner(ctx); err != nil { return err diff --git a/services/oauth2_provider/jwtsigningkey.go b/services/oauth2_provider/jwtsigningkey.go index 7ce37c5ef8..62d8a55c8b 100644 --- a/services/oauth2_provider/jwtsigningkey.go +++ b/services/oauth2_provider/jwtsigningkey.go @@ -81,7 +81,7 @@ type rsaSingingKey struct { } func newRSASingingKey(signingMethod jwt.SigningMethod, key *rsa.PrivateKey) (rsaSingingKey, error) { - kid, err := util.CreatePublicKeyFingerprint(key.Public().(*rsa.PublicKey)) + kid, err := util.CreatePublicKeyFingerprint(&key.PublicKey) if err != nil { return rsaSingingKey{}, err } @@ -110,7 +110,7 @@ func (key rsaSingingKey) VerifyKey() any { } func (key rsaSingingKey) ToJWK() (map[string]string, error) { - pubKey := key.key.Public().(*rsa.PublicKey) + pubKey := &key.key.PublicKey return map[string]string{ "kty": "RSA", @@ -132,7 +132,7 @@ type eddsaSigningKey struct { } func newEdDSASingingKey(signingMethod jwt.SigningMethod, key ed25519.PrivateKey) (eddsaSigningKey, error) { - kid, err := util.CreatePublicKeyFingerprint(key.Public().(ed25519.PublicKey)) + kid, err := util.CreatePublicKeyFingerprint(key.Public().(ed25519.PublicKey)) //nolint:forcetypeassert // ed25519.PrivateKey.Public always returns ed25519.PublicKey if err != nil { return eddsaSigningKey{}, err } @@ -161,7 +161,7 @@ func (key eddsaSigningKey) VerifyKey() any { } func (key eddsaSigningKey) ToJWK() (map[string]string, error) { - pubKey := key.key.Public().(ed25519.PublicKey) + pubKey := key.key.Public().(ed25519.PublicKey) //nolint:forcetypeassert // ed25519.PrivateKey.Public always returns ed25519.PublicKey return map[string]string{ "alg": key.SigningMethod().Alg(), @@ -183,7 +183,7 @@ type ecdsaSingingKey struct { } func newECDSASingingKey(signingMethod jwt.SigningMethod, key *ecdsa.PrivateKey) (ecdsaSingingKey, error) { - kid, err := util.CreatePublicKeyFingerprint(key.Public().(*ecdsa.PublicKey)) + kid, err := util.CreatePublicKeyFingerprint(&key.PublicKey) if err != nil { return ecdsaSingingKey{}, err } @@ -212,7 +212,7 @@ func (key ecdsaSingingKey) VerifyKey() any { } func (key ecdsaSingingKey) ToJWK() (map[string]string, error) { - pubKey := key.key.Public().(*ecdsa.PublicKey) + pubKey := &key.key.PublicKey // PublicKey.Bytes returns the uncompressed SEC 1 format: 0x04 || X || Y pubKeyBytes, err := pubKey.Bytes() diff --git a/services/oauth2_provider/jwtsigningkey_test.go b/services/oauth2_provider/jwtsigningkey_test.go index 55de81dfd8..3c645f8ad6 100644 --- a/services/oauth2_provider/jwtsigningkey_test.go +++ b/services/oauth2_provider/jwtsigningkey_test.go @@ -53,7 +53,8 @@ func TestECDSASigningKeyToJWK(t *testing.T) { assert.Len(t, yBytes, tc.coordLen) // Verify the decoded coordinates reconstruct the original public key point - pubKey := privKey.Public().(*ecdsa.PublicKey) + pubKey, ok := privKey.Public().(*ecdsa.PublicKey) + require.True(t, ok) assert.Equal(t, 0, new(big.Int).SetBytes(xBytes).Cmp(pubKey.X)) assert.Equal(t, 0, new(big.Int).SetBytes(yBytes).Cmp(pubKey.Y)) }) diff --git a/services/packages/cargo/index.go b/services/packages/cargo/index.go index 9bab40de36..f4cc4c7d40 100644 --- a/services/packages/cargo/index.go +++ b/services/packages/cargo/index.go @@ -162,7 +162,7 @@ func BuildPackageIndex(ctx context.Context, p *packages_model.Package) (*bytes.B var b bytes.Buffer for _, pd := range pds { - metadata := pd.Metadata.(*cargo_module.Metadata) + metadata := packages_model.DescriptorMetadata[*cargo_module.Metadata](pd) dependencies := metadata.Dependencies if dependencies == nil { diff --git a/services/pubsub/redis_test.go b/services/pubsub/redis_test.go index 5da2a0c868..f1ad3a7512 100644 --- a/services/pubsub/redis_test.go +++ b/services/pubsub/redis_test.go @@ -38,7 +38,8 @@ func TestRedisBroker(t *testing.T) { // RedisBroker tears down its per-topic Redis subscription and internal // state once the last local subscriber cancels. t.Run("CancelCleansTopicState", func(t *testing.T) { - b := newBroker(t).(*RedisBroker) + b, isRedisBroker := newBroker(t).(*RedisBroker) + require.True(t, isRedisBroker) ch, cancel := b.Subscribe(t.Name()) cancel() diff --git a/services/pull/pull.go b/services/pull/pull.go index 790a537593..f3b5eae3e5 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -595,8 +595,7 @@ func pushToBaseRepoHelper(ctx context.Context, pr *issues_model.PullRequest, pre // This should not happen as we're using force! log.Error("Unable to push PR head for %s#%d (%-v:%s) due to ErrPushOfDate: %v", pr.BaseRepo.FullName(), pr.Index, pr.BaseRepo, gitRefName, err) return err - } else if git.IsErrPushRejected(err) { - rejectErr := err.(*git.ErrPushRejected) + } else if rejectErr, ok := err.(*git.ErrPushRejected); ok { log.Info("Unable to push PR head for %s#%d (%-v:%s) due to rejection:\nStdout: %s\nStderr: %s\nError: %v", pr.BaseRepo.FullName(), pr.Index, pr.BaseRepo, gitRefName, rejectErr.StdOut, rejectErr.StdErr, rejectErr.Err) return err } else if git.IsErrMoreThanOne(err) { diff --git a/services/task/migrate.go b/services/task/migrate.go index e8627d0c03..2dbc761d25 100644 --- a/services/task/migrate.go +++ b/services/task/migrate.go @@ -27,15 +27,19 @@ import ( ) func handleCreateError(owner *user_model.User, err error) error { + var ( + errNameReserved db.ErrNameReserved + errNamePatternNotAllowed db.ErrNamePatternNotAllowed + ) switch { case repo_model.IsErrReachLimitOfRepo(err): return fmt.Errorf("you have already reached your limit of %d repositories", owner.MaxCreationLimit()) case repo_model.IsErrRepoAlreadyExist(err): return errors.New("the repository name is already used") - case db.IsErrNameReserved(err): - return fmt.Errorf("the repository name '%s' is reserved", err.(db.ErrNameReserved).Name) - case db.IsErrNamePatternNotAllowed(err): - return fmt.Errorf("the pattern '%s' is not allowed in a repository name", err.(db.ErrNamePatternNotAllowed).Pattern) + case errors.As(err, &errNameReserved): + return fmt.Errorf("the repository name '%s' is reserved", errNameReserved.Name) + case errors.As(err, &errNamePatternNotAllowed): + return fmt.Errorf("the pattern '%s' is not allowed in a repository name", errNamePatternNotAllowed.Pattern) default: return err } diff --git a/services/webtheme/webtheme.go b/services/webtheme/webtheme.go index 3ce42936fe..7734b0ade4 100644 --- a/services/webtheme/webtheme.go +++ b/services/webtheme/webtheme.go @@ -149,8 +149,8 @@ func parseThemeMetaInfo(fileName, cssContent string) *ThemeMetaInfo { return themeInfo } -func collectThemeFiles(dirFS fs.ReadDirFS, fsPath string) (themes []*ThemeMetaInfo, _ error) { - files, err := dirFS.ReadDir(fsPath) +func collectThemeFiles(dirFS fs.FS, fsPath string) (themes []*ThemeMetaInfo, _ error) { + files, err := fs.ReadDir(dirFS, fsPath) if err != nil { return nil, err } @@ -170,12 +170,12 @@ func collectThemeFiles(dirFS fs.ReadDirFS, fsPath string) (themes []*ThemeMetaIn } func loadThemesFromAssets(isViteDevMode bool) (themeList []*ThemeMetaInfo, themeMap map[string]*ThemeMetaInfo) { - var themeDir fs.ReadDirFS + var themeDir fs.FS var themePath string if isViteDevMode { // In vite dev mode, Vite serves themes directly from source files. - themeDir, themePath = os.DirFS(setting.StaticRootPath).(fs.ReadDirFS), "web_src/css/themes" + themeDir, themePath = os.DirFS(setting.StaticRootPath), "web_src/css/themes" } else { // Without vite dev server, use built assets from AssetFS. themeDir, themePath = public.AssetFS(), "assets/css" diff --git a/tests/integration/api_admin_test.go b/tests/integration/api_admin_test.go index c02137a326..fba9e55c25 100644 --- a/tests/integration/api_admin_test.go +++ b/tests/integration/api_admin_test.go @@ -214,7 +214,7 @@ func TestAPIEditUser(t *testing.T) { errMap := make(map[string]any) json.Unmarshal(resp.Body.Bytes(), &errMap) - assert.Equal(t, "e-mail invalid [email: ]", errMap["message"].(string)) + assert.Equal(t, "e-mail invalid [email: ]", errMap["message"]) user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"}) assert.False(t, user2.IsRestricted) diff --git a/tests/integration/api_httpsig_test.go b/tests/integration/api_httpsig_test.go index a011a55c54..d100d0728e 100644 --- a/tests/integration/api_httpsig_test.go +++ b/tests/integration/api_httpsig_test.go @@ -16,6 +16,7 @@ import ( "gitea.dev/tests" "github.com/42wim/httpsig" + "github.com/stretchr/testify/require" "golang.org/x/crypto/ssh" ) @@ -112,7 +113,9 @@ func TestHTTPSigCert(t *testing.T) { keyID := "gitea" // create our certificate signer using the ssh signer and our certificate - certSigner, err := ssh.NewCertSigner(pkcert.(*ssh.Certificate), sshSigner) + cert, ok := pkcert.(*ssh.Certificate) + require.True(t, ok) + certSigner, err := ssh.NewCertSigner(cert, sshSigner) if err != nil { t.Fatal(err) } @@ -121,7 +124,7 @@ func TestHTTPSigCert(t *testing.T) { req = NewRequest(t, "GET", "/api/v1/admin/users") // add our cert to the request - certString := base64.RawStdEncoding.EncodeToString(pkcert.(*ssh.Certificate).Marshal()) + certString := base64.RawStdEncoding.EncodeToString(cert.Marshal()) req.SetHeader("x-ssh-certificate", certString) signer, _, err := httpsig.NewSSHSigner(certSigner, httpsig.DigestSha512, []string{httpsig.RequestTarget, "(created)", "(expires)", "x-ssh-certificate"}, httpsig.Signature, 10) diff --git a/tests/integration/api_packages_conan_test.go b/tests/integration/api_packages_conan_test.go index 27d57fc479..90fd3b85bf 100644 --- a/tests/integration/api_packages_conan_test.go +++ b/tests/integration/api_packages_conan_test.go @@ -23,6 +23,7 @@ import ( "gitea.dev/tests" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) const ( @@ -327,8 +328,8 @@ func TestPackageConan(t *testing.T) { assert.Nil(t, pd.SemVer) assert.Equal(t, name, pd.Package.Name) assert.Equal(t, version1, pd.Version.Version) - assert.IsType(t, &conan_module.Metadata{}, pd.Metadata) - metadata := pd.Metadata.(*conan_module.Metadata) + metadata, ok := pd.Metadata.(*conan_module.Metadata) + require.True(t, ok) assert.Equal(t, conanLicense, metadata.License) assert.Equal(t, conanAuthor, metadata.Author) assert.Equal(t, conanHomepage, metadata.ProjectURL) diff --git a/tests/integration/api_packages_container_test.go b/tests/integration/api_packages_container_test.go index 298064de57..a4cddf307c 100644 --- a/tests/integration/api_packages_container_test.go +++ b/tests/integration/api_packages_container_test.go @@ -427,8 +427,8 @@ func TestPackageContainer(t *testing.T) { assert.ElementsMatch(t, []string{strings.ToLower(user.LowerName + "/" + image)}, getAllByName(pd.PackageProperties, container_module.PropertyRepository)) assert.True(t, has(pd.VersionProperties, container_module.PropertyManifestTagged)) - assert.IsType(t, &container_module.Metadata{}, pd.Metadata) - metadata := pd.Metadata.(*container_module.Metadata) + metadata, ok := pd.Metadata.(*container_module.Metadata) + require.True(t, ok) assert.Equal(t, container_module.TypeOCI, metadata.Type) assert.Len(t, metadata.ImageLayers, 2) assert.Empty(t, metadata.Manifests) @@ -570,8 +570,8 @@ func TestPackageContainer(t *testing.T) { assert.ElementsMatch(t, []string{manifestDigest, untaggedManifestDigest}, getAllByName(pd.VersionProperties, container_module.PropertyManifestReference)) - assert.IsType(t, &container_module.Metadata{}, pd.Metadata) - metadata := pd.Metadata.(*container_module.Metadata) + metadata, ok := pd.Metadata.(*container_module.Metadata) + require.True(t, ok) assert.Equal(t, container_module.TypeOCI, metadata.Type) assert.Len(t, metadata.Manifests, 2) assert.Condition(t, func() bool { diff --git a/tests/integration/api_packages_maven_test.go b/tests/integration/api_packages_maven_test.go index 65d6844bbd..df25f780f4 100644 --- a/tests/integration/api_packages_maven_test.go +++ b/tests/integration/api_packages_maven_test.go @@ -199,8 +199,9 @@ func TestPackageMaven(t *testing.T) { pd, err = packages.GetPackageDescriptor(t.Context(), pvs[0]) require.NoError(t, err) - assert.IsType(t, &maven.Metadata{}, pd.Metadata) - assert.Equal(t, packageDescription, pd.Metadata.(*maven.Metadata).Description) + metadata, ok := pd.Metadata.(*maven.Metadata) + require.True(t, ok) + assert.Equal(t, packageDescription, metadata.Description) pfs, err := packages.GetFilesByVersionID(t.Context(), pvs[0].ID) require.NoError(t, err) diff --git a/tests/integration/api_packages_pypi_test.go b/tests/integration/api_packages_pypi_test.go index cae33f55c6..a24d6c96eb 100644 --- a/tests/integration/api_packages_pypi_test.go +++ b/tests/integration/api_packages_pypi_test.go @@ -20,6 +20,7 @@ import ( "gitea.dev/tests" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestPackagePyPI(t *testing.T) { @@ -86,8 +87,9 @@ func TestPackagePyPI(t *testing.T) { pd, err := packages.GetPackageDescriptor(t.Context(), pvs[0]) assert.NoError(t, err) assert.Nil(t, pd.SemVer) - assert.IsType(t, &pypi.Metadata{}, pd.Metadata) - assert.Equal(t, projectURL, pd.Metadata.(*pypi.Metadata).ProjectURL) + metadata, ok := pd.Metadata.(*pypi.Metadata) + require.True(t, ok) + assert.Equal(t, projectURL, metadata.ProjectURL) assert.Equal(t, packageName, pd.Package.Name) assert.Equal(t, packageVersion, pd.Version.Version) @@ -165,8 +167,9 @@ func TestPackagePyPI(t *testing.T) { pd, err := packages.GetPackageDescriptor(t.Context(), pvs[0]) assert.NoError(t, err) - assert.IsType(t, &pypi.Metadata{}, pd.Metadata) - assert.Equal(t, projectURL, pd.Metadata.(*pypi.Metadata).ProjectURL) + metadata, ok := pd.Metadata.(*pypi.Metadata) + require.True(t, ok) + assert.Equal(t, projectURL, metadata.ProjectURL) }) t.Run("UploadWithoutAnyHomepageURLMetadata", func(t *testing.T) { @@ -185,8 +188,9 @@ func TestPackagePyPI(t *testing.T) { pd, err := packages.GetPackageDescriptor(t.Context(), pvs[0]) assert.NoError(t, err) - assert.IsType(t, &pypi.Metadata{}, pd.Metadata) - assert.Empty(t, pd.Metadata.(*pypi.Metadata).ProjectURL) + metadata, ok := pd.Metadata.(*pypi.Metadata) + require.True(t, ok) + assert.Empty(t, metadata.ProjectURL) }) t.Run("Download", func(t *testing.T) { diff --git a/tests/integration/api_packages_swift_test.go b/tests/integration/api_packages_swift_test.go index 83452244e3..b521887de4 100644 --- a/tests/integration/api_packages_swift_test.go +++ b/tests/integration/api_packages_swift_test.go @@ -164,8 +164,8 @@ func TestPackageSwift(t *testing.T) { assert.NotNil(t, pd.SemVer) assert.Equal(t, packageID, pd.Package.Name) assert.Equal(t, packageVersion, pd.Version.Version) - assert.IsType(t, &swift_module.Metadata{}, pd.Metadata) - metadata := pd.Metadata.(*swift_module.Metadata) + metadata, ok := pd.Metadata.(*swift_module.Metadata) + require.True(t, ok) assert.Equal(t, packageDescription, metadata.Description) assert.Len(t, metadata.Manifests, 2) assert.Equal(t, contentManifest1, metadata.Manifests[""].Content) @@ -241,8 +241,8 @@ func TestPackageSwift(t *testing.T) { assert.NotNil(t, pd.SemVer) assert.Equal(t, packageID, pd.Package.Name) assert.Equal(t, packageVersion2, pd.Version.Version) - assert.IsType(t, &swift_module.Metadata{}, pd.Metadata) - metadata := pd.Metadata.(*swift_module.Metadata) + metadata, ok := pd.Metadata.(*swift_module.Metadata) + require.True(t, ok) assert.Equal(t, packageDescription, metadata.Description) assert.Len(t, metadata.Manifests, 2) assert.Equal(t, contentManifest1, metadata.Manifests[""].Content) diff --git a/tests/integration/api_pull_review_test.go b/tests/integration/api_pull_review_test.go index 38691b7904..e16cb5cea4 100644 --- a/tests/integration/api_pull_review_test.go +++ b/tests/integration/api_pull_review_test.go @@ -210,7 +210,7 @@ func testAPIPullReviewGeneral(t *testing.T) { resp = MakeRequest(t, req, http.StatusUnprocessableEntity) errMap := make(map[string]any) json.Unmarshal(resp.Body.Bytes(), &errMap) - assert.Equal(t, "review event COMMENT requires a body or a comment", errMap["message"].(string)) + assert.Equal(t, "review event COMMENT requires a body or a comment", errMap["message"]) // test get review requests // to make it simple, use same api with get review diff --git a/tests/integration/auth_ldap_test.go b/tests/integration/auth_ldap_test.go index 467d505943..be238a3bf7 100644 --- a/tests/integration/auth_ldap_test.go +++ b/tests/integration/auth_ldap_test.go @@ -352,7 +352,8 @@ func testLDAPUserSyncWithGroupFilter(t *testing.T) { ldapSource := unittest.AssertExistsAndLoadBean(t, &auth_model.Source{ Name: "ldap", }) - ldapConfig := ldapSource.Cfg.(*ldap.Source) + ldapConfig, ok := ldapSource.Cfg.(*ldap.Source) + require.True(t, ok) ldapConfig.GroupFilter = "(cn=ship_crew)" require.NoError(t, auth_model.UpdateSource(t.Context(), ldapSource)) diff --git a/tests/integration/auth_oauth2_test.go b/tests/integration/auth_oauth2_test.go index 2476bc6bb4..c65854c15b 100644 --- a/tests/integration/auth_oauth2_test.go +++ b/tests/integration/auth_oauth2_test.go @@ -113,7 +113,9 @@ func TestMigrateAzureADV2ToOIDC(t *testing.T) { // --- Step 3: Set ExternalIDClaim = "oid" to restore account continuity --- // Set ExternalIDClaim = "oid" so that the OIDC source extracts the same Object ID that the Azure AD V2 provider previously stored. - authSource.Cfg.(*oauth2.Source).ExternalIDClaim = "oid" + oauth2Source, ok := authSource.Cfg.(*oauth2.Source) + require.True(t, ok) + oauth2Source.ExternalIDClaim = "oid" err = auth_model.UpdateSource(t.Context(), authSource) require.NoError(t, err) diff --git a/tests/integration/incoming_email_test.go b/tests/integration/incoming_email_test.go index 08dec041e1..2c57e8a8d0 100644 --- a/tests/integration/incoming_email_test.go +++ b/tests/integration/incoming_email_test.go @@ -23,6 +23,7 @@ import ( "gitea.dev/tests" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestIncomingEmail(t *testing.T) { @@ -48,13 +49,15 @@ func TestIncomingEmail(t *testing.T) { ref, err := incoming_payload.GetReferenceFromPayload(t.Context(), issuePayload) assert.NoError(t, err) - assert.IsType(t, ref, new(issues_model.Issue)) - assert.Equal(t, issue.ID, ref.(*issues_model.Issue).ID) + refIssue, ok := ref.(*issues_model.Issue) + require.True(t, ok) + assert.Equal(t, issue.ID, refIssue.ID) ref, err = incoming_payload.GetReferenceFromPayload(t.Context(), commentPayload) assert.NoError(t, err) - assert.IsType(t, ref, new(issues_model.Comment)) - assert.Equal(t, comment.ID, ref.(*issues_model.Comment).ID) + refComment, ok := ref.(*issues_model.Comment) + require.True(t, ok) + assert.Equal(t, comment.ID, refComment.ID) }) t.Run("Token", func(t *testing.T) { diff --git a/tests/integration/markup_external_test.go b/tests/integration/markup_external_test.go index 41fa56bdc5..17ed663346 100644 --- a/tests/integration/markup_external_test.go +++ b/tests/integration/markup_external_test.go @@ -78,10 +78,12 @@ func TestExternalMarkupRenderer(t *testing.T) { }) // above tested in-page rendering (no iframe), then we test iframe mode below - r := markup.DetectRendererTypeByFilename("any-file.html").(*external.Renderer) + r, ok := markup.DetectRendererTypeByFilename("any-file.html").(*external.Renderer) + require.True(t, ok) defer test.MockVariableValue(&r.RenderContentMode, setting.RenderContentModeIframe)() assert.True(t, r.NeedPostProcess()) - r = markup.DetectRendererTypeByFilename("any-file.no-sanitizer").(*external.Renderer) + r, ok = markup.DetectRendererTypeByFilename("any-file.no-sanitizer").(*external.Renderer) + require.True(t, ok) defer test.MockVariableValue(&r.RenderContentMode, setting.RenderContentModeIframe)() assert.False(t, r.NeedPostProcess()) diff --git a/tests/integration/oauth_avatar_test.go b/tests/integration/oauth_avatar_test.go index ee94a2c109..2cc3598014 100644 --- a/tests/integration/oauth_avatar_test.go +++ b/tests/integration/oauth_avatar_test.go @@ -39,7 +39,9 @@ func TestOAuth2AvatarFromPicture(t *testing.T) { }) authSource, err := auth_model.GetActiveOAuth2SourceByAuthName(t.Context(), "test-oidc-avatar") require.NoError(t, err) - providerName := authSource.Cfg.(*oauth2.Source).Provider + oauth2Source, ok := authSource.Cfg.(*oauth2.Source) + require.True(t, ok) + providerName := oauth2Source.Provider t.Run("AutoRegister", func(t *testing.T) { defer test.MockVariableValue(&setting.OAuth2Client.Username, "")() diff --git a/tests/integration/oauth_test.go b/tests/integration/oauth_test.go index e3b766288a..535ef1994b 100644 --- a/tests/integration/oauth_test.go +++ b/tests/integration/oauth_test.go @@ -1299,6 +1299,8 @@ func testSignInOauthCallbackSyncSSHKeys(t *testing.T) { addOAuth2Source(t, "test-oidc-source", oauth2Source) authSource, err := auth_model.GetActiveOAuth2SourceByAuthName(ctx, "test-oidc-source") require.NoError(t, err) + authSourceCfg, ok := authSource.Cfg.(*oauth2.Source) + require.True(t, ok) sshKey1 := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICV0MGX/W9IvLA4FXpIuUcdDcbj5KX4syHgsTy7soVgf" sshKey2 := "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIE7kM1R02+4ertDKGKEDcKG0s+2vyDDcIvceJ0Gqv5f1AAAABHNzaDo=" @@ -1336,7 +1338,7 @@ func testSignInOauthCallbackSyncSSHKeys(t *testing.T) { defer test.MockVariableValue(&setting.OAuth2Client.EnableAutoRegistration, true)() defer test.MockVariableValue(&gothic.CompleteUserAuth, func(res http.ResponseWriter, req *http.Request) (goth.User, error) { return goth.User{ - Provider: authSource.Cfg.(*oauth2.Source).Provider, + Provider: authSourceCfg.Provider, UserID: "oidc-userid", Email: "oidc-email@example.com", RawData: c.mockRawData,