Merge pull request '[gitea] week 2024-31 cherry pick (gitea/main -> forgejo)' (#4716) from earl-warren/wcp/2024-31 into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/4716 Reviewed-by: Gusted <gusted@noreply.codeberg.org> Reviewed-by: 0ko <0ko@noreply.codeberg.org>
This commit is contained in:
commit
d40873e768
|
@ -86,7 +86,6 @@ code.gitea.io/gitea/models/repo
|
||||||
WatchRepoMode
|
WatchRepoMode
|
||||||
|
|
||||||
code.gitea.io/gitea/models/user
|
code.gitea.io/gitea/models/user
|
||||||
IsErrPrimaryEmailCannotDelete
|
|
||||||
ErrUserInactive.Error
|
ErrUserInactive.Error
|
||||||
ErrUserInactive.Unwrap
|
ErrUserInactive.Unwrap
|
||||||
IsErrExternalLoginUserAlreadyExist
|
IsErrExternalLoginUserAlreadyExist
|
||||||
|
|
|
@ -115,6 +115,9 @@ prime/
|
||||||
*_source.tar.bz2
|
*_source.tar.bz2
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# nix-direnv generated files
|
||||||
|
.direnv/
|
||||||
|
|
||||||
# Make evidence files
|
# Make evidence files
|
||||||
/.make_evidence
|
/.make_evidence
|
||||||
|
|
||||||
|
|
|
@ -350,6 +350,7 @@ type SearchEmailOptions struct {
|
||||||
|
|
||||||
// SearchEmailResult is an e-mail address found in the user or email_address table
|
// SearchEmailResult is an e-mail address found in the user or email_address table
|
||||||
type SearchEmailResult struct {
|
type SearchEmailResult struct {
|
||||||
|
ID int64
|
||||||
UID int64
|
UID int64
|
||||||
Email string
|
Email string
|
||||||
IsActivated bool
|
IsActivated bool
|
||||||
|
|
|
@ -44,6 +44,12 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp
|
||||||
searchOpt.ProjectID = optional.Some[int64](0) // Those issues with no project(projectid==0)
|
searchOpt.ProjectID = optional.Some[int64](0) // Those issues with no project(projectid==0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.AssigneeID > 0 {
|
||||||
|
searchOpt.AssigneeID = optional.Some(opts.AssigneeID)
|
||||||
|
} else if opts.AssigneeID == -1 { // FIXME: this is inconsistent from other places
|
||||||
|
searchOpt.AssigneeID = optional.Some[int64](0)
|
||||||
|
}
|
||||||
|
|
||||||
// See the comment of issues_model.SearchOptions for the reason why we need to convert
|
// See the comment of issues_model.SearchOptions for the reason why we need to convert
|
||||||
convertID := func(id int64) optional.Option[int64] {
|
convertID := func(id int64) optional.Option[int64] {
|
||||||
if id > 0 {
|
if id > 0 {
|
||||||
|
@ -57,7 +63,6 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp
|
||||||
|
|
||||||
searchOpt.ProjectColumnID = convertID(opts.ProjectColumnID)
|
searchOpt.ProjectColumnID = convertID(opts.ProjectColumnID)
|
||||||
searchOpt.PosterID = convertID(opts.PosterID)
|
searchOpt.PosterID = convertID(opts.PosterID)
|
||||||
searchOpt.AssigneeID = convertID(opts.AssigneeID)
|
|
||||||
searchOpt.MentionID = convertID(opts.MentionedID)
|
searchOpt.MentionID = convertID(opts.MentionedID)
|
||||||
searchOpt.ReviewedID = convertID(opts.ReviewedID)
|
searchOpt.ReviewedID = convertID(opts.ReviewedID)
|
||||||
searchOpt.ReviewRequestedID = convertID(opts.ReviewRequestedID)
|
searchOpt.ReviewRequestedID = convertID(opts.ReviewRequestedID)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/indexer/issues/internal"
|
"code.gitea.io/gitea/modules/indexer/issues/internal"
|
||||||
"code.gitea.io/gitea/modules/optional"
|
"code.gitea.io/gitea/modules/optional"
|
||||||
|
@ -150,6 +151,11 @@ func searchIssueByID(t *testing.T) {
|
||||||
},
|
},
|
||||||
expectedIDs: []int64{6, 1},
|
expectedIDs: []int64{6, 1},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// NOTE: This tests no assignees filtering and also ToSearchOptions() to ensure it will set AssigneeID to 0 when it is passed as -1.
|
||||||
|
opts: *ToSearchOptions("", &issues.IssuesOptions{AssigneeID: -1}),
|
||||||
|
expectedIDs: []int64{22, 21, 16, 15, 14, 13, 12, 11, 20, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
opts: SearchOptions{
|
opts: SearchOptions{
|
||||||
MentionID: optional.Some(int64(4)),
|
MentionID: optional.Some(int64(4)),
|
||||||
|
|
|
@ -3094,6 +3094,10 @@ emails.not_updated = Failed to update the requested email address: %v
|
||||||
emails.duplicate_active = This email address is already active for a different user.
|
emails.duplicate_active = This email address is already active for a different user.
|
||||||
emails.change_email_header = Update Email Properties
|
emails.change_email_header = Update Email Properties
|
||||||
emails.change_email_text = Are you sure you want to update this email address?
|
emails.change_email_text = Are you sure you want to update this email address?
|
||||||
|
emails.delete = Delete Email
|
||||||
|
emails.delete_desc = Are you sure you want to delete this email address?
|
||||||
|
emails.deletion_success = The email address has been deleted.
|
||||||
|
emails.delete_primary_email_error = You can not delete the primary email.
|
||||||
|
|
||||||
orgs.org_manage_panel = Manage organizations
|
orgs.org_manage_panel = Manage organizations
|
||||||
orgs.name = Name
|
orgs.name = Name
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
feat: [commit](https://codeberg.org/forgejo/forgejo/commit/8d23433dab08fcbb8043e5d239171fba59c53108): support pull_request_target event for commit status.
|
||||||
|
fix: [commit](https://codeberg.org/forgejo/forgejo/commit/ee11a263f8c9de33d42fc117443f4054a311c875): add return type to GetRawFileOrLFS and GetRawFile.
|
||||||
|
feat: [commit](https://codeberg.org/forgejo/forgejo/commit/cb9071bbf433715f0e16e39cb60126b65f8236a0): support delete user email in admin panel.
|
||||||
|
fix: [commit](https://codeberg.org/forgejo/forgejo/commit/f61873c7e42b613405d367421ad19db80f831053): properly filter issue list given no assignees filter.
|
|
@ -45,7 +45,7 @@ func GetRawFile(ctx *context.APIContext) {
|
||||||
// ---
|
// ---
|
||||||
// summary: Get a file from a repository
|
// summary: Get a file from a repository
|
||||||
// produces:
|
// produces:
|
||||||
// - application/json
|
// - application/octet-stream
|
||||||
// parameters:
|
// parameters:
|
||||||
// - name: owner
|
// - name: owner
|
||||||
// in: path
|
// in: path
|
||||||
|
@ -70,6 +70,8 @@ func GetRawFile(ctx *context.APIContext) {
|
||||||
// responses:
|
// responses:
|
||||||
// 200:
|
// 200:
|
||||||
// description: Returns raw file content.
|
// description: Returns raw file content.
|
||||||
|
// schema:
|
||||||
|
// type: file
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
|
@ -96,6 +98,8 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
|
||||||
// swagger:operation GET /repos/{owner}/{repo}/media/{filepath} repository repoGetRawFileOrLFS
|
// swagger:operation GET /repos/{owner}/{repo}/media/{filepath} repository repoGetRawFileOrLFS
|
||||||
// ---
|
// ---
|
||||||
// summary: Get a file or it's LFS object from a repository
|
// summary: Get a file or it's LFS object from a repository
|
||||||
|
// produces:
|
||||||
|
// - application/octet-stream
|
||||||
// parameters:
|
// parameters:
|
||||||
// - name: owner
|
// - name: owner
|
||||||
// in: path
|
// in: path
|
||||||
|
@ -120,6 +124,8 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
|
||||||
// responses:
|
// responses:
|
||||||
// 200:
|
// 200:
|
||||||
// description: Returns raw file content.
|
// description: Returns raw file content.
|
||||||
|
// schema:
|
||||||
|
// type: file
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/optional"
|
"code.gitea.io/gitea/modules/optional"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
|
"code.gitea.io/gitea/services/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -150,3 +151,32 @@ func ActivateEmail(ctx *context.Context) {
|
||||||
redirect.RawQuery = q.Encode()
|
redirect.RawQuery = q.Encode()
|
||||||
ctx.Redirect(redirect.String())
|
ctx.Redirect(redirect.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteEmail serves a POST request for delete a user's email
|
||||||
|
func DeleteEmail(ctx *context.Context) {
|
||||||
|
u, err := user_model.GetUserByID(ctx, ctx.FormInt64("Uid"))
|
||||||
|
if err != nil || u == nil {
|
||||||
|
ctx.ServerError("GetUserByID", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
email, err := user_model.GetEmailAddressByID(ctx, u.ID, ctx.FormInt64("id"))
|
||||||
|
if err != nil || email == nil {
|
||||||
|
ctx.ServerError("GetEmailAddressByID", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := user.DeleteEmailAddresses(ctx, u, []string{email.Email}); err != nil {
|
||||||
|
if user_model.IsErrPrimaryEmailCannotDelete(err) {
|
||||||
|
ctx.Flash.Error(ctx.Tr("admin.emails.delete_primary_email_error"))
|
||||||
|
ctx.JSONRedirect("")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.ServerError("DeleteEmailAddresses", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Trace("Email address deleted: %s %s", u.Name, email.Email)
|
||||||
|
|
||||||
|
ctx.Flash.Success(ctx.Tr("admin.emails.deletion_success"))
|
||||||
|
ctx.JSONRedirect("")
|
||||||
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
|
||||||
link := &feeds.Link{Href: act.GetCommentHTMLURL(ctx)}
|
link := &feeds.Link{Href: act.GetCommentHTMLURL(ctx)}
|
||||||
|
|
||||||
// title
|
// title
|
||||||
title = act.ActUser.DisplayName() + " "
|
title = act.ActUser.GetDisplayName() + " "
|
||||||
var titleExtra template.HTML
|
var titleExtra template.HTML
|
||||||
switch act.OpType {
|
switch act.OpType {
|
||||||
case activities_model.ActionCreateRepo:
|
case activities_model.ActionCreateRepo:
|
||||||
|
@ -260,7 +260,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
|
||||||
Description: desc,
|
Description: desc,
|
||||||
IsPermaLink: "false",
|
IsPermaLink: "false",
|
||||||
Author: &feeds.Author{
|
Author: &feeds.Author{
|
||||||
Name: act.ActUser.DisplayName(),
|
Name: act.ActUser.GetDisplayName(),
|
||||||
Email: act.ActUser.GetEmail(),
|
Email: act.ActUser.GetEmail(),
|
||||||
},
|
},
|
||||||
Id: fmt.Sprintf("%v: %v", strconv.FormatInt(act.ID, 10), link.Href),
|
Id: fmt.Sprintf("%v: %v", strconv.FormatInt(act.ID, 10), link.Href),
|
||||||
|
@ -320,7 +320,7 @@ func releasesToFeedItems(ctx *context.Context, releases []*repo_model.Release) (
|
||||||
Link: link,
|
Link: link,
|
||||||
Created: rel.CreatedUnix.AsTime(),
|
Created: rel.CreatedUnix.AsTime(),
|
||||||
Author: &feeds.Author{
|
Author: &feeds.Author{
|
||||||
Name: rel.Publisher.DisplayName(),
|
Name: rel.Publisher.GetDisplayName(),
|
||||||
Email: rel.Publisher.GetEmail(),
|
Email: rel.Publisher.GetEmail(),
|
||||||
},
|
},
|
||||||
Id: fmt.Sprintf("%v: %v", strconv.FormatInt(rel.ID, 10), link.Href),
|
Id: fmt.Sprintf("%v: %v", strconv.FormatInt(rel.ID, 10), link.Href),
|
||||||
|
|
|
@ -696,6 +696,7 @@ func registerRoutes(m *web.Route) {
|
||||||
m.Group("/emails", func() {
|
m.Group("/emails", func() {
|
||||||
m.Get("", admin.Emails)
|
m.Get("", admin.Emails)
|
||||||
m.Post("/activate", admin.ActivateEmail)
|
m.Post("/activate", admin.ActivateEmail)
|
||||||
|
m.Post("/delete", admin.DeleteEmail)
|
||||||
})
|
})
|
||||||
|
|
||||||
m.Group("/orgs", func() {
|
m.Group("/orgs", func() {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
actions_module "code.gitea.io/gitea/modules/actions"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
webhook_module "code.gitea.io/gitea/modules/webhook"
|
webhook_module "code.gitea.io/gitea/modules/webhook"
|
||||||
|
@ -53,7 +54,11 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
|
||||||
}
|
}
|
||||||
sha = payload.HeadCommit.ID
|
sha = payload.HeadCommit.ID
|
||||||
case webhook_module.HookEventPullRequest, webhook_module.HookEventPullRequestSync:
|
case webhook_module.HookEventPullRequest, webhook_module.HookEventPullRequestSync:
|
||||||
event = "pull_request"
|
if run.TriggerEvent == actions_module.GithubEventPullRequestTarget {
|
||||||
|
event = "pull_request_target"
|
||||||
|
} else {
|
||||||
|
event = "pull_request"
|
||||||
|
}
|
||||||
payload, err := run.GetPullRequestEventPayload()
|
payload, err := run.GetPullRequestEventPayload()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetPullRequestEventPayload: %w", err)
|
return fmt.Errorf("GetPullRequestEventPayload: %w", err)
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
</th>
|
</th>
|
||||||
<th>{{ctx.Locale.Tr "admin.emails.primary"}}</th>
|
<th>{{ctx.Locale.Tr "admin.emails.primary"}}</th>
|
||||||
<th>{{ctx.Locale.Tr "admin.emails.activated"}}</th>
|
<th>{{ctx.Locale.Tr "admin.emails.activated"}}</th>
|
||||||
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -59,6 +60,11 @@
|
||||||
{{if .IsActivated}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
|
{{if .IsActivated}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="tw-flex tw-gap-2">
|
||||||
|
<a class="delete-button" href="" data-url="{{$.Link}}/delete" data-id="{{.ID}}" data-data-uid="{{.UID}}">{{svg "octicon-trash"}}</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -95,4 +101,16 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="ui g-modal-confirm delete modal">
|
||||||
|
<div class="header">
|
||||||
|
{{svg "octicon-trash"}}
|
||||||
|
{{ctx.Locale.Tr "admin.emails.delete"}}
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
{{ctx.Locale.Tr "admin.emails.delete_desc"}}
|
||||||
|
</div>
|
||||||
|
{{template "base/modal_actions_confirm" .}}
|
||||||
|
</div>
|
||||||
|
|
||||||
{{template "admin/layout_footer" .}}
|
{{template "admin/layout_footer" .}}
|
||||||
|
|
|
@ -10867,6 +10867,9 @@
|
||||||
},
|
},
|
||||||
"/repos/{owner}/{repo}/media/{filepath}": {
|
"/repos/{owner}/{repo}/media/{filepath}": {
|
||||||
"get": {
|
"get": {
|
||||||
|
"produces": [
|
||||||
|
"application/octet-stream"
|
||||||
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"repository"
|
"repository"
|
||||||
],
|
],
|
||||||
|
@ -10903,7 +10906,10 @@
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "Returns raw file content."
|
"description": "Returns raw file content.",
|
||||||
|
"schema": {
|
||||||
|
"type": "file"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"$ref": "#/responses/notFound"
|
"$ref": "#/responses/notFound"
|
||||||
|
@ -13122,7 +13128,7 @@
|
||||||
"/repos/{owner}/{repo}/raw/{filepath}": {
|
"/repos/{owner}/{repo}/raw/{filepath}": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
"application/json"
|
"application/octet-stream"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"repository"
|
"repository"
|
||||||
|
@ -13160,7 +13166,10 @@
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "Returns raw file content."
|
"description": "Returns raw file content.",
|
||||||
|
"schema": {
|
||||||
|
"type": "file"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"$ref": "#/responses/notFound"
|
"$ref": "#/responses/notFound"
|
||||||
|
|
|
@ -7,6 +7,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
"code.gitea.io/gitea/tests"
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -15,6 +17,7 @@ import (
|
||||||
func TestFeedPlainTextTitles(t *testing.T) {
|
func TestFeedPlainTextTitles(t *testing.T) {
|
||||||
// This test verifies that items' titles in feeds are generated as plain text.
|
// This test verifies that items' titles in feeds are generated as plain text.
|
||||||
// See https://codeberg.org/forgejo/forgejo/pulls/1595
|
// See https://codeberg.org/forgejo/forgejo/pulls/1595
|
||||||
|
defer test.MockVariableValue(&setting.UI.DefaultShowFullName, true)()
|
||||||
|
|
||||||
t.Run("Feed plain text titles", func(t *testing.T) {
|
t.Run("Feed plain text titles", func(t *testing.T) {
|
||||||
t.Run("Atom", func(t *testing.T) {
|
t.Run("Atom", func(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue