diff --git a/models/system/setting.go b/models/system/setting.go index 1ae6f5c652836..507d23cff6bbf 100644 --- a/models/system/setting.go +++ b/models/system/setting.go @@ -115,24 +115,26 @@ func (d *dbConfigCachedGetter) GetValue(ctx context.Context, key string) (v stri func (d *dbConfigCachedGetter) GetRevision(ctx context.Context) int { d.mu.RLock() - defer d.mu.RUnlock() - if time.Since(d.cacheTime) < time.Second { - return d.revision + cachedDuration := time.Since(d.cacheTime) + cachedRevision := d.revision + d.mu.RUnlock() + + if cachedDuration < time.Second { + return cachedRevision } + + d.mu.Lock() + defer d.mu.Unlock() if GetRevision(ctx) != d.revision { - d.mu.RUnlock() - d.mu.Lock() rev, set, err := GetAllSettings(ctx) if err != nil { log.Error("Unable to get all settings: %v", err) } else { - d.cacheTime = time.Now() d.revision = rev d.settings = set } - d.mu.Unlock() - d.mu.RLock() } + d.cacheTime = time.Now() return d.revision } diff --git a/modules/setting/database.go b/modules/setting/database.go index aa42f506bc51b..761e767e8f5f7 100644 --- a/modules/setting/database.go +++ b/modules/setting/database.go @@ -109,7 +109,7 @@ func DBConnStr() (string, error) { connStr = fmt.Sprintf("%s:%s@%s(%s)/%s%scharset=%s&parseTime=true&tls=%s", Database.User, Database.Passwd, connType, Database.Host, Database.Name, paramSep, Database.MysqlCharset, tls) case "postgres": - connStr = getPostgreSQLConnectionString(Database.Host, Database.User, Database.Passwd, Database.Name, paramSep, Database.SSLMode) + connStr = getPostgreSQLConnectionString(Database.Host, Database.User, Database.Passwd, Database.Name, Database.SSLMode) case "mssql": host, port := ParseMSSQLHostPort(Database.Host) connStr = fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;", host, port, Database.Name, Database.User, Database.Passwd) @@ -157,7 +157,8 @@ func parsePostgreSQLHostPort(info string) (host, port string) { return host, port } -func getPostgreSQLConnectionString(dbHost, dbUser, dbPasswd, dbName, dbParam, dbsslMode string) (connStr string) { +func getPostgreSQLConnectionString(dbHost, dbUser, dbPasswd, dbName, dbsslMode string) (connStr string) { + dbName, dbParam, _ := strings.Cut(dbName, "?") host, port := parsePostgreSQLHostPort(dbHost) connURL := url.URL{ Scheme: "postgres", diff --git a/modules/setting/database_test.go b/modules/setting/database_test.go index 85271c36cb388..1d5b416504b18 100644 --- a/modules/setting/database_test.go +++ b/modules/setting/database_test.go @@ -59,38 +59,39 @@ func Test_parsePostgreSQLHostPort(t *testing.T) { func Test_getPostgreSQLConnectionString(t *testing.T) { tests := []struct { Host string - Port string User string Passwd string Name string - Param string SSLMode string Output string }{ { Host: "/tmp/pg.sock", - Port: "4321", User: "testuser", Passwd: "space space !#$%^^%^```-=?=", Name: "gitea", - Param: "", SSLMode: "false", Output: "postgres://testuser:space%20space%20%21%23$%25%5E%5E%25%5E%60%60%60-=%3F=@:5432/gitea?host=%2Ftmp%2Fpg.sock&sslmode=false", }, { Host: "localhost", - Port: "1234", User: "pgsqlusername", Passwd: "I love Gitea!", Name: "gitea", - Param: "", SSLMode: "true", Output: "postgres://pgsqlusername:I%20love%20Gitea%21@localhost:5432/gitea?sslmode=true", }, + { + Host: "localhost:1234", + User: "user", + Passwd: "pass", + Name: "gitea?param=1", + Output: "postgres://user:pass@localhost:1234/gitea?param=1&sslmode=", + }, } for _, test := range tests { - connStr := getPostgreSQLConnectionString(test.Host, test.User, test.Passwd, test.Name, test.Param, test.SSLMode) + connStr := getPostgreSQLConnectionString(test.Host, test.User, test.Passwd, test.Name, test.SSLMode) assert.Equal(t, test.Output, connStr) } } diff --git a/services/webhook/dingtalk_test.go b/services/webhook/dingtalk_test.go index 7289c751f3845..a03fa46f1458f 100644 --- a/services/webhook/dingtalk_test.go +++ b/services/webhook/dingtalk_test.go @@ -188,6 +188,21 @@ func TestDingTalkPayload(t *testing.T) { assert.Equal(t, "http://localhost:3000/test/repo", parseRealSingleURL(pl.(*DingtalkPayload).ActionCard.SingleURL)) }) + t.Run("Package", func(t *testing.T) { + p := packageTestPayload() + + d := new(DingtalkPayload) + pl, err := d.Package(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &DingtalkPayload{}, pl) + + assert.Equal(t, "Package created: GiteaContainer:latest by user1", pl.(*DingtalkPayload).ActionCard.Text) + assert.Equal(t, "Package created: GiteaContainer:latest by user1", pl.(*DingtalkPayload).ActionCard.Title) + assert.Equal(t, "view package", pl.(*DingtalkPayload).ActionCard.SingleTitle) + assert.Equal(t, "http://localhost:3000/user1/-/packages/container/GiteaContainer/latest", parseRealSingleURL(pl.(*DingtalkPayload).ActionCard.SingleURL)) + }) + t.Run("Wiki", func(t *testing.T) { p := wikiTestPayload() diff --git a/services/webhook/discord_test.go b/services/webhook/discord_test.go index 6a276e9e874da..b567cbc395db1 100644 --- a/services/webhook/discord_test.go +++ b/services/webhook/discord_test.go @@ -211,6 +211,24 @@ func TestDiscordPayload(t *testing.T) { assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL) }) + t.Run("Package", func(t *testing.T) { + p := packageTestPayload() + + d := new(DiscordPayload) + pl, err := d.Package(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &DiscordPayload{}, pl) + + assert.Len(t, pl.(*DiscordPayload).Embeds, 1) + assert.Equal(t, "Package created: GiteaContainer:latest", pl.(*DiscordPayload).Embeds[0].Title) + assert.Empty(t, pl.(*DiscordPayload).Embeds[0].Description) + assert.Equal(t, "http://localhost:3000/user1/-/packages/container/GiteaContainer/latest", pl.(*DiscordPayload).Embeds[0].URL) + assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name) + assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL) + assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL) + }) + t.Run("Wiki", func(t *testing.T) { p := wikiTestPayload() diff --git a/services/webhook/feishu_test.go b/services/webhook/feishu_test.go index a3182e82b09af..98bc50dedec87 100644 --- a/services/webhook/feishu_test.go +++ b/services/webhook/feishu_test.go @@ -144,6 +144,18 @@ func TestFeishuPayload(t *testing.T) { assert.Equal(t, "[test/repo] Repository created", pl.(*FeishuPayload).Content.Text) }) + t.Run("Package", func(t *testing.T) { + p := packageTestPayload() + + d := new(FeishuPayload) + pl, err := d.Package(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &FeishuPayload{}, pl) + + assert.Equal(t, "Package created: GiteaContainer:latest by user1", pl.(*FeishuPayload).Content.Text) + }) + t.Run("Wiki", func(t *testing.T) { p := wikiTestPayload() diff --git a/services/webhook/general_test.go b/services/webhook/general_test.go index a9a8c6b5212c1..41bac3fd04d23 100644 --- a/services/webhook/general_test.go +++ b/services/webhook/general_test.go @@ -303,6 +303,36 @@ func repositoryTestPayload() *api.RepositoryPayload { } } +func packageTestPayload() *api.PackagePayload { + return &api.PackagePayload{ + Action: api.HookPackageCreated, + Sender: &api.User{ + UserName: "user1", + AvatarURL: "http://localhost:3000/user1/avatar", + }, + Repository: nil, + Organization: &api.User{ + UserName: "org1", + AvatarURL: "http://localhost:3000/org1/avatar", + }, + Package: &api.Package{ + Owner: &api.User{ + UserName: "user1", + AvatarURL: "http://localhost:3000/user1/avatar", + }, + Repository: nil, + Creator: &api.User{ + UserName: "user1", + AvatarURL: "http://localhost:3000/user1/avatar", + }, + Type: "container", + Name: "GiteaContainer", + Version: "latest", + HTMLURL: "http://localhost:3000/user1/-/packages/container/GiteaContainer/latest", + }, + } +} + func TestGetIssuesPayloadInfo(t *testing.T) { p := issueTestPayload() diff --git a/services/webhook/matrix.go b/services/webhook/matrix.go index ab7e6b72c25f1..602d16ef39b0e 100644 --- a/services/webhook/matrix.go +++ b/services/webhook/matrix.go @@ -212,14 +212,14 @@ func (m *MatrixPayload) Repository(p *api.RepositoryPayload) (api.Payloader, err func (m *MatrixPayload) Package(p *api.PackagePayload) (api.Payloader, error) { senderLink := MatrixLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName) - repoLink := MatrixLinkFormatter(p.Repository.HTMLURL, p.Repository.FullName) + packageLink := MatrixLinkFormatter(p.Package.HTMLURL, p.Package.Name) var text string switch p.Action { case api.HookPackageCreated: - text = fmt.Sprintf("[%s] Package published by %s", repoLink, senderLink) + text = fmt.Sprintf("[%s] Package published by %s", packageLink, senderLink) case api.HookPackageDeleted: - text = fmt.Sprintf("[%s] Package deleted by %s", repoLink, senderLink) + text = fmt.Sprintf("[%s] Package deleted by %s", packageLink, senderLink) } return getMatrixPayload(text, nil, m.MsgType), nil diff --git a/services/webhook/matrix_test.go b/services/webhook/matrix_test.go index 8c710942280fa..99a22fbd7eb3a 100644 --- a/services/webhook/matrix_test.go +++ b/services/webhook/matrix_test.go @@ -155,6 +155,19 @@ func TestMatrixPayload(t *testing.T) { assert.Equal(t, `[test/repo] Repository created by user1`, pl.(*MatrixPayload).FormattedBody) }) + t.Run("Package", func(t *testing.T) { + p := packageTestPayload() + + d := new(MatrixPayload) + pl, err := d.Package(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &MatrixPayload{}, pl) + + assert.Equal(t, `[[GiteaContainer](http://localhost:3000/user1/-/packages/container/GiteaContainer/latest)] Package published by [user1](https://try.gitea.io/user1)`, pl.(*MatrixPayload).Body) + assert.Equal(t, `[GiteaContainer] Package published by user1`, pl.(*MatrixPayload).FormattedBody) + }) + t.Run("Wiki", func(t *testing.T) { p := wikiTestPayload() diff --git a/services/webhook/msteams.go b/services/webhook/msteams.go index f58da3fe1cd6f..37810b4cd3959 100644 --- a/services/webhook/msteams.go +++ b/services/webhook/msteams.go @@ -316,11 +316,12 @@ func GetMSTeamsPayload(p api.Payloader, event webhook_module.HookEventType, _ st } func createMSTeamsPayload(r *api.Repository, s *api.User, title, text, actionTarget string, color int, fact *MSTeamsFact) *MSTeamsPayload { - facts := []MSTeamsFact{ - { + facts := make([]MSTeamsFact, 0, 2) + if r != nil { + facts = append(facts, MSTeamsFact{ Name: "Repository:", Value: r.FullName, - }, + }) } if fact != nil { facts = append(facts, *fact) diff --git a/services/webhook/msteams_test.go b/services/webhook/msteams_test.go index 990a535df5c1a..8d1aed604086e 100644 --- a/services/webhook/msteams_test.go +++ b/services/webhook/msteams_test.go @@ -329,6 +329,33 @@ func TestMSTeamsPayload(t *testing.T) { assert.Equal(t, "http://localhost:3000/test/repo", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI) }) + t.Run("Package", func(t *testing.T) { + p := packageTestPayload() + + d := new(MSTeamsPayload) + pl, err := d.Package(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &MSTeamsPayload{}, pl) + + assert.Equal(t, "Package created: GiteaContainer:latest", pl.(*MSTeamsPayload).Title) + assert.Equal(t, "Package created: GiteaContainer:latest", pl.(*MSTeamsPayload).Summary) + assert.Len(t, pl.(*MSTeamsPayload).Sections, 1) + assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle) + assert.Empty(t, pl.(*MSTeamsPayload).Sections[0].Text) + assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 1) + for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts { + if fact.Name == "Package:" { + assert.Equal(t, p.Package.Name, fact.Value) + } else { + t.Fail() + } + } + assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1) + assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1) + assert.Equal(t, "http://localhost:3000/user1/-/packages/container/GiteaContainer/latest", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI) + }) + t.Run("Wiki", func(t *testing.T) { p := wikiTestPayload() diff --git a/services/webhook/packagist_test.go b/services/webhook/packagist_test.go index 932b56fe9b9a1..26d01b0555ddc 100644 --- a/services/webhook/packagist_test.go +++ b/services/webhook/packagist_test.go @@ -115,6 +115,15 @@ func TestPackagistPayload(t *testing.T) { require.Nil(t, pl) }) + t.Run("Package", func(t *testing.T) { + p := packageTestPayload() + + d := new(PackagistPayload) + pl, err := d.Package(p) + require.NoError(t, err) + require.Nil(t, pl) + }) + t.Run("Wiki", func(t *testing.T) { p := wikiTestPayload() diff --git a/services/webhook/slack_test.go b/services/webhook/slack_test.go index d9828f374f0dd..b1340963e2301 100644 --- a/services/webhook/slack_test.go +++ b/services/webhook/slack_test.go @@ -144,6 +144,18 @@ func TestSlackPayload(t *testing.T) { assert.Equal(t, "[] Repository created by ", pl.(*SlackPayload).Text) }) + t.Run("Package", func(t *testing.T) { + p := packageTestPayload() + + d := new(SlackPayload) + pl, err := d.Package(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &SlackPayload{}, pl) + + assert.Equal(t, "Package created: by ", pl.(*SlackPayload).Text) + }) + t.Run("Wiki", func(t *testing.T) { p := wikiTestPayload() diff --git a/services/webhook/telegram_test.go b/services/webhook/telegram_test.go index b42b0ccda8847..5b9927d0571e2 100644 --- a/services/webhook/telegram_test.go +++ b/services/webhook/telegram_test.go @@ -144,6 +144,18 @@ func TestTelegramPayload(t *testing.T) { assert.Equal(t, `[test/repo] Repository created`, pl.(*TelegramPayload).Message) }) + t.Run("Package", func(t *testing.T) { + p := packageTestPayload() + + d := new(TelegramPayload) + pl, err := d.Package(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &TelegramPayload{}, pl) + + assert.Equal(t, `Package created: GiteaContainer:latest by user1`, pl.(*TelegramPayload).Message) + }) + t.Run("Wiki", func(t *testing.T) { p := wikiTestPayload()