Skip to content

Commit a5bbe02

Browse files
authored
Merge branch 'main' into git.GetTags-paginate
2 parents f7c079b + 9ca0e79 commit a5bbe02

File tree

14 files changed

+86
-26
lines changed

14 files changed

+86
-26
lines changed

cmd/admin.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,10 @@ var (
288288
Value: "",
289289
Usage: "Custom icon URL for OAuth2 login source",
290290
},
291+
cli.BoolFlag{
292+
Name: "skip-local-2fa",
293+
Usage: "Set to true to skip local 2fa for users authenticated by this source",
294+
},
291295
}
292296

293297
microcmdAuthUpdateOauth = cli.Command{
@@ -616,6 +620,7 @@ func parseOAuth2Config(c *cli.Context) *oauth2.Source {
616620
OpenIDConnectAutoDiscoveryURL: c.String("auto-discover-url"),
617621
CustomURLMapping: customURLMapping,
618622
IconURL: c.String("icon-url"),
623+
SkipLocalTwoFA: c.Bool("skip-local-2fa"),
619624
}
620625
}
621626

modules/convert/issue.go

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
package convert
66

77
import (
8+
"fmt"
89
"strings"
910

1011
"code.gitea.io/gitea/models"
12+
"code.gitea.io/gitea/modules/log"
13+
"code.gitea.io/gitea/modules/setting"
1114
api "code.gitea.io/gitea/modules/structs"
1215
)
1316

@@ -25,6 +28,9 @@ func ToAPIIssue(issue *models.Issue) *api.Issue {
2528
if err := issue.LoadRepo(); err != nil {
2629
return &api.Issue{}
2730
}
31+
if err := issue.Repo.GetOwner(); err != nil {
32+
return &api.Issue{}
33+
}
2834

2935
apiIssue := &api.Issue{
3036
ID: issue.ID,
@@ -35,7 +41,7 @@ func ToAPIIssue(issue *models.Issue) *api.Issue {
3541
Title: issue.Title,
3642
Body: issue.Content,
3743
Ref: issue.Ref,
38-
Labels: ToLabelList(issue.Labels),
44+
Labels: ToLabelList(issue.Labels, issue.Repo, issue.Repo.Owner),
3945
State: issue.State(),
4046
IsLocked: issue.IsLocked,
4147
Comments: issue.NumComments,
@@ -168,20 +174,37 @@ func ToTrackedTimeList(tl models.TrackedTimeList) api.TrackedTimeList {
168174
}
169175

170176
// ToLabel converts Label to API format
171-
func ToLabel(label *models.Label) *api.Label {
172-
return &api.Label{
177+
func ToLabel(label *models.Label, repo *models.Repository, org *models.User) *api.Label {
178+
result := &api.Label{
173179
ID: label.ID,
174180
Name: label.Name,
175181
Color: strings.TrimLeft(label.Color, "#"),
176182
Description: label.Description,
177183
}
184+
185+
// calculate URL
186+
if label.BelongsToRepo() && repo != nil {
187+
if repo != nil {
188+
result.URL = fmt.Sprintf("%s/labels/%d", repo.APIURL(), label.ID)
189+
} else {
190+
log.Error("ToLabel did not get repo to calculate url for label with id '%d'", label.ID)
191+
}
192+
} else { // BelongsToOrg
193+
if org != nil {
194+
result.URL = fmt.Sprintf("%sapi/v1/orgs/%s/labels/%d", setting.AppURL, org.Name, label.ID)
195+
} else {
196+
log.Error("ToLabel did not get org to calculate url for label with id '%d'", label.ID)
197+
}
198+
}
199+
200+
return result
178201
}
179202

180203
// ToLabelList converts list of Label to API format
181-
func ToLabelList(labels []*models.Label) []*api.Label {
204+
func ToLabelList(labels []*models.Label, repo *models.Repository, org *models.User) []*api.Label {
182205
result := make([]*api.Label, len(labels))
183206
for i := range labels {
184-
result[i] = ToLabel(labels[i])
207+
result[i] = ToLabel(labels[i], repo, org)
185208
}
186209
return result
187210
}

modules/convert/issue_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
package convert
66

77
import (
8+
"fmt"
89
"testing"
910
"time"
1011

1112
"code.gitea.io/gitea/models"
13+
"code.gitea.io/gitea/modules/setting"
1214
api "code.gitea.io/gitea/modules/structs"
1315
"code.gitea.io/gitea/modules/timeutil"
1416

@@ -18,11 +20,13 @@ import (
1820
func TestLabel_ToLabel(t *testing.T) {
1921
assert.NoError(t, models.PrepareTestDatabase())
2022
label := models.AssertExistsAndLoadBean(t, &models.Label{ID: 1}).(*models.Label)
23+
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: label.RepoID}).(*models.Repository)
2124
assert.Equal(t, &api.Label{
2225
ID: label.ID,
2326
Name: label.Name,
2427
Color: "abcdef",
25-
}, ToLabel(label))
28+
URL: fmt.Sprintf("%sapi/v1/repos/user2/repo1/labels/%d", setting.AppURL, label.ID),
29+
}, ToLabel(label, repo, nil))
2630
}
2731

2832
func TestMilestone_APIFormat(t *testing.T) {

options/locale/locale_en-US.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2456,6 +2456,8 @@ auths.oauth2_tokenURL = Token URL
24562456
auths.oauth2_authURL = Authorize URL
24572457
auths.oauth2_profileURL = Profile URL
24582458
auths.oauth2_emailURL = Email URL
2459+
auths.skip_local_two_fa = Skip local 2FA
2460+
auths.skip_local_two_fa_helper = Leaving unset means local users with 2FA set will still have to pass 2FA to log on
24592461
auths.oauth2_tenant = Tenant
24602462
auths.enable_auto_register = Enable Auto Registration
24612463
auths.sspi_auto_create_users = Automatically create users

routers/api/v1/org/label.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func ListLabels(ctx *context.APIContext) {
5656
}
5757

5858
ctx.SetTotalCountHeader(count)
59-
ctx.JSON(http.StatusOK, convert.ToLabelList(labels))
59+
ctx.JSON(http.StatusOK, convert.ToLabelList(labels, nil, ctx.Org.Organization))
6060
}
6161

6262
// CreateLabel create a label for a repository
@@ -103,7 +103,8 @@ func CreateLabel(ctx *context.APIContext) {
103103
ctx.Error(http.StatusInternalServerError, "NewLabel", err)
104104
return
105105
}
106-
ctx.JSON(http.StatusCreated, convert.ToLabel(label))
106+
107+
ctx.JSON(http.StatusCreated, convert.ToLabel(label, nil, ctx.Org.Organization))
107108
}
108109

109110
// GetLabel get label by organization and label id
@@ -148,7 +149,7 @@ func GetLabel(ctx *context.APIContext) {
148149
return
149150
}
150151

151-
ctx.JSON(http.StatusOK, convert.ToLabel(label))
152+
ctx.JSON(http.StatusOK, convert.ToLabel(label, nil, ctx.Org.Organization))
152153
}
153154

154155
// EditLabel modify a label for an Organization
@@ -212,7 +213,8 @@ func EditLabel(ctx *context.APIContext) {
212213
ctx.Error(http.StatusInternalServerError, "UpdateLabel", err)
213214
return
214215
}
215-
ctx.JSON(http.StatusOK, convert.ToLabel(label))
216+
217+
ctx.JSON(http.StatusOK, convert.ToLabel(label, nil, ctx.Org.Organization))
216218
}
217219

218220
// DeleteLabel delete a label for an organization

routers/api/v1/repo/issue_label.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func ListIssueLabels(ctx *context.APIContext) {
6161
return
6262
}
6363

64-
ctx.JSON(http.StatusOK, convert.ToLabelList(issue.Labels))
64+
ctx.JSON(http.StatusOK, convert.ToLabelList(issue.Labels, ctx.Repo.Repository, ctx.Repo.Owner))
6565
}
6666

6767
// AddIssueLabels add labels for an issue
@@ -117,7 +117,7 @@ func AddIssueLabels(ctx *context.APIContext) {
117117
return
118118
}
119119

120-
ctx.JSON(http.StatusOK, convert.ToLabelList(labels))
120+
ctx.JSON(http.StatusOK, convert.ToLabelList(labels, ctx.Repo.Repository, ctx.Repo.Owner))
121121
}
122122

123123
// DeleteIssueLabel delete a label for an issue
@@ -243,7 +243,7 @@ func ReplaceIssueLabels(ctx *context.APIContext) {
243243
return
244244
}
245245

246-
ctx.JSON(http.StatusOK, convert.ToLabelList(labels))
246+
ctx.JSON(http.StatusOK, convert.ToLabelList(labels, ctx.Repo.Repository, ctx.Repo.Owner))
247247
}
248248

249249
// ClearIssueLabels delete all the labels for an issue

routers/api/v1/repo/label.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func ListLabels(ctx *context.APIContext) {
6262
}
6363

6464
ctx.SetTotalCountHeader(count)
65-
ctx.JSON(http.StatusOK, convert.ToLabelList(labels))
65+
ctx.JSON(http.StatusOK, convert.ToLabelList(labels, ctx.Repo.Repository, nil))
6666
}
6767

6868
// GetLabel get label by repository and label id
@@ -112,7 +112,7 @@ func GetLabel(ctx *context.APIContext) {
112112
return
113113
}
114114

115-
ctx.JSON(http.StatusOK, convert.ToLabel(label))
115+
ctx.JSON(http.StatusOK, convert.ToLabel(label, ctx.Repo.Repository, nil))
116116
}
117117

118118
// CreateLabel create a label for a repository
@@ -165,7 +165,8 @@ func CreateLabel(ctx *context.APIContext) {
165165
ctx.Error(http.StatusInternalServerError, "NewLabel", err)
166166
return
167167
}
168-
ctx.JSON(http.StatusCreated, convert.ToLabel(label))
168+
169+
ctx.JSON(http.StatusCreated, convert.ToLabel(label, ctx.Repo.Repository, nil))
169170
}
170171

171172
// EditLabel modify a label for a repository
@@ -235,7 +236,8 @@ func EditLabel(ctx *context.APIContext) {
235236
ctx.Error(http.StatusInternalServerError, "UpdateLabel", err)
236237
return
237238
}
238-
ctx.JSON(http.StatusOK, convert.ToLabel(label))
239+
240+
ctx.JSON(http.StatusOK, convert.ToLabel(label, ctx.Repo.Repository, nil))
239241
}
240242

241243
// DeleteLabel delete a label for a repository

routers/web/admin/auths.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source {
181181
OpenIDConnectAutoDiscoveryURL: form.OpenIDConnectAutoDiscoveryURL,
182182
CustomURLMapping: customURLMapping,
183183
IconURL: form.Oauth2IconURL,
184+
SkipLocalTwoFA: form.SkipLocalTwoFA,
184185
}
185186
}
186187

routers/web/user/auth.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ func SignInOAuth(ctx *context.Context) {
574574
user, gothUser, err := oAuth2UserLoginCallback(loginSource, ctx.Req, ctx.Resp)
575575
if err == nil && user != nil {
576576
// we got the user without going through the whole OAuth2 authentication flow again
577-
handleOAuth2SignIn(ctx, user, gothUser)
577+
handleOAuth2SignIn(ctx, loginSource, user, gothUser)
578578
return
579579
}
580580

@@ -660,7 +660,7 @@ func SignInOAuthCallback(ctx *context.Context) {
660660
}
661661
}
662662

663-
handleOAuth2SignIn(ctx, u, gothUser)
663+
handleOAuth2SignIn(ctx, loginSource, u, gothUser)
664664
}
665665

666666
func getUserName(gothUser *goth.User) string {
@@ -702,18 +702,22 @@ func updateAvatarIfNeed(url string, u *models.User) {
702702
}
703703
}
704704

705-
func handleOAuth2SignIn(ctx *context.Context, u *models.User, gothUser goth.User) {
705+
func handleOAuth2SignIn(ctx *context.Context, source *models.LoginSource, u *models.User, gothUser goth.User) {
706706
updateAvatarIfNeed(gothUser.AvatarURL, u)
707707

708-
// If this user is enrolled in 2FA, we can't sign the user in just yet.
709-
// Instead, redirect them to the 2FA authentication page.
710-
_, err := models.GetTwoFactorByUID(u.ID)
711-
if err != nil {
712-
if !models.IsErrTwoFactorNotEnrolled(err) {
708+
needs2FA := false
709+
if !source.Cfg.(*oauth2.Source).SkipLocalTwoFA {
710+
_, err := models.GetTwoFactorByUID(u.ID)
711+
if err != nil && !models.IsErrTwoFactorNotEnrolled(err) {
713712
ctx.ServerError("UserSignIn", err)
714713
return
715714
}
715+
needs2FA = err == nil
716+
}
716717

718+
// If this user is enrolled in 2FA and this source doesn't override it,
719+
// we can't sign the user in just yet. Instead, redirect them to the 2FA authentication page.
720+
if !needs2FA {
717721
if err := ctx.Session.Set("uid", u.ID); err != nil {
718722
log.Error("Error setting uid in session: %v", err)
719723
}

services/auth/source/oauth2/source.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type Source struct {
2424
OpenIDConnectAutoDiscoveryURL string
2525
CustomURLMapping *CustomURLMapping
2626
IconURL string
27+
SkipLocalTwoFA bool
2728

2829
// reference to the loginSource
2930
loginSource *models.LoginSource

services/forms/auth_form.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ type AuthenticationForm struct {
6666
Oauth2EmailURL string
6767
Oauth2IconURL string
6868
Oauth2Tenant string
69+
SkipLocalTwoFA bool
6970
SSPIAutoCreateUsers bool
7071
SSPIAutoActivateUsers bool
7172
SSPIStripDomainNames bool

templates/admin/auth/edit.tmpl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,13 @@
255255
<label for="open_id_connect_auto_discovery_url">{{.i18n.Tr "admin.auths.openIdConnectAutoDiscoveryURL"}}</label>
256256
<input id="open_id_connect_auto_discovery_url" name="open_id_connect_auto_discovery_url" value="{{$cfg.OpenIDConnectAutoDiscoveryURL}}">
257257
</div>
258+
<div class="optional field">
259+
<div class="ui checkbox">
260+
<label for="skip_local_two_fa"><strong>{{.i18n.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
261+
<input id="skip_local_two_fa" name="skip_local_two_fa" type="checkbox" {{if $cfg.SkipLocalTwoFA}}checked{{end}}>
262+
<p class="help">{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
263+
</div>
264+
</div>
258265

259266
<div class="oauth2_use_custom_url inline field">
260267
<div class="ui checkbox">

templates/admin/auth/source/oauth.tmpl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@
2828
<label for="open_id_connect_auto_discovery_url">{{.i18n.Tr "admin.auths.openIdConnectAutoDiscoveryURL"}}</label>
2929
<input id="open_id_connect_auto_discovery_url" name="open_id_connect_auto_discovery_url" value="{{.open_id_connect_auto_discovery_url}}">
3030
</div>
31+
<div class="optional field">
32+
<div class="ui checkbox">
33+
<label for="skip_local_two_fa"><strong>{{.i18n.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
34+
<input id="skip_local_two_fa" name="skip_local_two_fa" type="checkbox" {{if .skip_local_two_fa}}checked{{end}}>
35+
<p class="help">{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
36+
</div>
37+
</div>
3138

3239
<div class="oauth2_use_custom_url inline field">
3340
<div class="ui checkbox">

templates/repo/projects/view.tmpl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
<div class="page-content repository">
33
{{template "repo/header" .}}
44
<div class="ui container">
5-
<div class="ui three column stackable grid">
5+
<div class="ui two column stackable grid">
66
<div class="column">
77
{{template "repo/issue/navbar" .}}
88
</div>
99
<div class="column right aligned">
1010
{{if and .CanWriteProjects (not .Repository.IsArchived) .PageIsProjects}}
11+
<a class="ui green button show-modal item" href="{{$.RepoLink}}/issues/new?project={{$.Project.ID}}">{{.i18n.Tr "repo.issues.new"}}</a>
1112
<a class="ui green button show-modal item" data-modal="#new-board-item">{{.i18n.Tr "new_project_board"}}</a>
1213
{{end}}
1314
<div class="ui small modal" id="new-board-item">

0 commit comments

Comments
 (0)