Move macaron to chi (#14293)

Use [chi](https://github.com/go-chi/chi) instead of the forked [macaron](https://gitea.com/macaron/macaron). Since macaron and chi have conflicts with session share, this big PR becomes a have-to thing. According my previous idea, we can replace macaron step by step but I'm wrong. :( Below is a list of big changes on this PR.

- [x] Define `context.ResponseWriter` interface with an implementation `context.Response`.
- [x] Use chi instead of macaron, and also a customize `Route` to wrap chi so that the router usage is similar as before.
- [x] Create different routers for `web`, `api`, `internal` and `install` so that the codes will be more clear and no magic .
- [x] Use https://github.com/unrolled/render instead of macaron's internal render
- [x] Use https://github.com/NYTimes/gziphandler instead of https://gitea.com/macaron/gzip
- [x] Use https://gitea.com/go-chi/session which is a modified version of https://gitea.com/macaron/session and removed `nodb` support since it will not be maintained. **BREAK**
- [x] Use https://gitea.com/go-chi/captcha which is a modified version of https://gitea.com/macaron/captcha
- [x] Use https://gitea.com/go-chi/cache which is a modified version of https://gitea.com/macaron/cache
- [x] Use https://gitea.com/go-chi/binding which is a modified version of https://gitea.com/macaron/binding
- [x] Use https://github.com/go-chi/cors instead of https://gitea.com/macaron/cors
- [x] Dropped https://gitea.com/macaron/i18n and make a new one in `code.gitea.io/gitea/modules/translation`
- [x] Move validation form structs from `code.gitea.io/gitea/modules/auth` to `code.gitea.io/gitea/modules/forms` to avoid dependency cycle.
- [x] Removed macaron log service because it's not need any more. **BREAK**
- [x] All form structs have to be get by `web.GetForm(ctx)` in the route function but not as a function parameter on routes definition.
- [x] Move Git HTTP protocol implementation to use routers directly.
- [x] Fix the problem that chi routes don't support trailing slash but macaron did.
- [x] `/api/v1/swagger` now will be redirect to `/api/swagger` but not render directly so that `APIContext` will not create a html render. 

Notices:
- Chi router don't support request with trailing slash
- Integration test `TestUserHeatmap` maybe mysql version related. It's failed on my macOS(mysql 5.7.29 installed via brew) but succeed on CI.

Co-authored-by: 6543 <6543@obermui.de>
This commit is contained in:
Lunny Xiao 2021-01-26 23:36:53 +08:00 committed by GitHub
parent 3adbbb4255
commit 6433ba0ec3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
353 changed files with 5463 additions and 20785 deletions

View file

@ -1,63 +0,0 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package auth
import (
"gitea.com/macaron/binding"
"gitea.com/macaron/macaron"
)
// AdminCreateUserForm form for admin to create user
type AdminCreateUserForm struct {
LoginType string `binding:"Required"`
LoginName string
UserName string `binding:"Required;AlphaDashDot;MaxSize(40)"`
Email string `binding:"Required;Email;MaxSize(254)"`
Password string `binding:"MaxSize(255)"`
SendNotify bool
MustChangePassword bool
}
// Validate validates form fields
func (f *AdminCreateUserForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// AdminEditUserForm form for admin to create user
type AdminEditUserForm struct {
LoginType string `binding:"Required"`
UserName string `binding:"AlphaDashDot;MaxSize(40)"`
LoginName string
FullName string `binding:"MaxSize(100)"`
Email string `binding:"Required;Email;MaxSize(254)"`
Password string `binding:"MaxSize(255)"`
Website string `binding:"ValidUrl;MaxSize(255)"`
Location string `binding:"MaxSize(50)"`
MaxRepoCreation int
Active bool
Admin bool
Restricted bool
AllowGitHook bool
AllowImportLocal bool
AllowCreateOrganization bool
ProhibitLogin bool
Reset2FA bool `form:"reset_2fa"`
}
// Validate validates form fields
func (f *AdminEditUserForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// AdminDashboardForm form for admin dashboard operations
type AdminDashboardForm struct {
Op string `binding:"required"`
From string
}
// Validate validates form fields
func (f *AdminDashboardForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

View file

@ -1,149 +0,0 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package auth
import (
"reflect"
"strings"
"code.gitea.io/gitea/modules/validation"
"gitea.com/macaron/binding"
"gitea.com/macaron/macaron"
"github.com/unknwon/com"
)
// IsAPIPath if URL is an api path
func IsAPIPath(url string) bool {
return strings.HasPrefix(url, "/api/")
}
// Form form binding interface
type Form interface {
binding.Validator
}
func init() {
binding.SetNameMapper(com.ToSnakeCase)
}
// AssignForm assign form values back to the template data.
func AssignForm(form interface{}, data map[string]interface{}) {
typ := reflect.TypeOf(form)
val := reflect.ValueOf(form)
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
val = val.Elem()
}
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
fieldName := field.Tag.Get("form")
// Allow ignored fields in the struct
if fieldName == "-" {
continue
} else if len(fieldName) == 0 {
fieldName = com.ToSnakeCase(field.Name)
}
data[fieldName] = val.Field(i).Interface()
}
}
func getRuleBody(field reflect.StructField, prefix string) string {
for _, rule := range strings.Split(field.Tag.Get("binding"), ";") {
if strings.HasPrefix(rule, prefix) {
return rule[len(prefix) : len(rule)-1]
}
}
return ""
}
// GetSize get size int form tag
func GetSize(field reflect.StructField) string {
return getRuleBody(field, "Size(")
}
// GetMinSize get minimal size in form tag
func GetMinSize(field reflect.StructField) string {
return getRuleBody(field, "MinSize(")
}
// GetMaxSize get max size in form tag
func GetMaxSize(field reflect.StructField) string {
return getRuleBody(field, "MaxSize(")
}
// GetInclude get include in form tag
func GetInclude(field reflect.StructField) string {
return getRuleBody(field, "Include(")
}
func validate(errs binding.Errors, data map[string]interface{}, f Form, l macaron.Locale) binding.Errors {
if errs.Len() == 0 {
return errs
}
data["HasError"] = true
// If the field with name errs[0].FieldNames[0] is not found in form
// somehow, some code later on will panic on Data["ErrorMsg"].(string).
// So initialize it to some default.
data["ErrorMsg"] = l.Tr("form.unknown_error")
AssignForm(f, data)
typ := reflect.TypeOf(f)
val := reflect.ValueOf(f)
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
val = val.Elem()
}
if field, ok := typ.FieldByName(errs[0].FieldNames[0]); ok {
fieldName := field.Tag.Get("form")
if fieldName != "-" {
data["Err_"+field.Name] = true
trName := field.Tag.Get("locale")
if len(trName) == 0 {
trName = l.Tr("form." + field.Name)
} else {
trName = l.Tr(trName)
}
switch errs[0].Classification {
case binding.ERR_REQUIRED:
data["ErrorMsg"] = trName + l.Tr("form.require_error")
case binding.ERR_ALPHA_DASH:
data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_error")
case binding.ERR_ALPHA_DASH_DOT:
data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_dot_error")
case validation.ErrGitRefName:
data["ErrorMsg"] = trName + l.Tr("form.git_ref_name_error")
case binding.ERR_SIZE:
data["ErrorMsg"] = trName + l.Tr("form.size_error", GetSize(field))
case binding.ERR_MIN_SIZE:
data["ErrorMsg"] = trName + l.Tr("form.min_size_error", GetMinSize(field))
case binding.ERR_MAX_SIZE:
data["ErrorMsg"] = trName + l.Tr("form.max_size_error", GetMaxSize(field))
case binding.ERR_EMAIL:
data["ErrorMsg"] = trName + l.Tr("form.email_error")
case binding.ERR_URL:
data["ErrorMsg"] = trName + l.Tr("form.url_error")
case binding.ERR_INCLUDE:
data["ErrorMsg"] = trName + l.Tr("form.include_error", GetInclude(field))
case validation.ErrGlobPattern:
data["ErrorMsg"] = trName + l.Tr("form.glob_pattern_error", errs[0].Message)
default:
data["ErrorMsg"] = l.Tr("form.unknown_error") + " " + errs[0].Classification
}
return errs
}
}
return errs
}

View file

@ -1,70 +0,0 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package auth
import (
"gitea.com/macaron/binding"
"gitea.com/macaron/macaron"
)
// AuthenticationForm form for authentication
type AuthenticationForm struct {
ID int64
Type int `binding:"Range(2,7)"`
Name string `binding:"Required;MaxSize(30)"`
Host string
Port int
BindDN string
BindPassword string
UserBase string
UserDN string
AttributeUsername string
AttributeName string
AttributeSurname string
AttributeMail string
AttributeSSHPublicKey string
AttributesInBind bool
UsePagedSearch bool
SearchPageSize int
Filter string
AdminFilter string
GroupsEnabled bool
GroupDN string
GroupFilter string
GroupMemberUID string
UserUID string
RestrictedFilter string
AllowDeactivateAll bool
IsActive bool
IsSyncEnabled bool
SMTPAuth string
SMTPHost string
SMTPPort int
AllowedDomains string
SecurityProtocol int `binding:"Range(0,2)"`
TLS bool
SkipVerify bool
PAMServiceName string
Oauth2Provider string
Oauth2Key string
Oauth2Secret string
OpenIDConnectAutoDiscoveryURL string
Oauth2UseCustomURL bool
Oauth2TokenURL string
Oauth2AuthURL string
Oauth2ProfileURL string
Oauth2EmailURL string
Oauth2IconURL string
SSPIAutoCreateUsers bool
SSPIAutoActivateUsers bool
SSPIStripDomainNames bool
SSPISeparatorReplacement string `binding:"AlphaDashDot;MaxSize(5)"`
SSPIDefaultLanguage string
}
// Validate validates fields
func (f *AuthenticationForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

View file

@ -1,72 +0,0 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package auth
import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/structs"
"gitea.com/macaron/binding"
"gitea.com/macaron/macaron"
)
// ________ .__ __ .__
// \_____ \_______ _________ ____ |__|____________ _/ |_|__| ____ ____
// / | \_ __ \/ ___\__ \ / \| \___ /\__ \\ __\ |/ _ \ / \
// / | \ | \/ /_/ > __ \| | \ |/ / / __ \| | | ( <_> ) | \
// \_______ /__| \___ (____ /___| /__/_____ \(____ /__| |__|\____/|___| /
// \/ /_____/ \/ \/ \/ \/ \/
// CreateOrgForm form for creating organization
type CreateOrgForm struct {
OrgName string `binding:"Required;AlphaDashDot;MaxSize(40)" locale:"org.org_name_holder"`
Visibility structs.VisibleType
RepoAdminChangeTeamAccess bool
}
// Validate validates the fields
func (f *CreateOrgForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// UpdateOrgSettingForm form for updating organization settings
type UpdateOrgSettingForm struct {
Name string `binding:"Required;AlphaDashDot;MaxSize(40)" locale:"org.org_name_holder"`
FullName string `binding:"MaxSize(100)"`
Description string `binding:"MaxSize(255)"`
Website string `binding:"ValidUrl;MaxSize(255)"`
Location string `binding:"MaxSize(50)"`
Visibility structs.VisibleType
MaxRepoCreation int
RepoAdminChangeTeamAccess bool
}
// Validate validates the fields
func (f *UpdateOrgSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// ___________
// \__ ___/___ _____ _____
// | |_/ __ \\__ \ / \
// | |\ ___/ / __ \| Y Y \
// |____| \___ >____ /__|_| /
// \/ \/ \/
// CreateTeamForm form for creating team
type CreateTeamForm struct {
TeamName string `binding:"Required;AlphaDashDot;MaxSize(30)"`
Description string `binding:"MaxSize(255)"`
Permission string
Units []models.UnitType
RepoAccess string
CanCreateOrgRepo bool
}
// Validate validates the fields
func (f *CreateTeamForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

View file

@ -1,20 +0,0 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package auth
import (
"gitea.com/macaron/binding"
"gitea.com/macaron/macaron"
)
// NewBranchForm form for creating a new branch
type NewBranchForm struct {
NewBranchName string `binding:"Required;MaxSize(100);GitRefName"`
}
// Validate validates the fields
func (f *NewBranchForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

View file

@ -1,775 +0,0 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package auth
import (
"net/url"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/utils"
"gitea.com/macaron/binding"
"gitea.com/macaron/macaron"
)
// _______________________________________ _________.______________________ _______________.___.
// \______ \_ _____/\______ \_____ \ / _____/| \__ ___/\_____ \\______ \__ | |
// | _/| __)_ | ___// | \ \_____ \ | | | | / | \| _// | |
// | | \| \ | | / | \/ \| | | | / | \ | \\____ |
// |____|_ /_______ / |____| \_______ /_______ /|___| |____| \_______ /____|_ // ______|
// \/ \/ \/ \/ \/ \/ \/
// CreateRepoForm form for creating repository
type CreateRepoForm struct {
UID int64 `binding:"Required"`
RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"`
Private bool
Description string `binding:"MaxSize(255)"`
DefaultBranch string `binding:"GitRefName;MaxSize(100)"`
AutoInit bool
Gitignores string
IssueLabels string
License string
Readme string
Template bool
RepoTemplate int64
GitContent bool
Topics bool
GitHooks bool
Webhooks bool
Avatar bool
Labels bool
TrustModel string
}
// Validate validates the fields
func (f *CreateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// MigrateRepoForm form for migrating repository
// this is used to interact with web ui
type MigrateRepoForm struct {
// required: true
CloneAddr string `json:"clone_addr" binding:"Required"`
Service structs.GitServiceType `json:"service"`
AuthUsername string `json:"auth_username"`
AuthPassword string `json:"auth_password"`
AuthToken string `json:"auth_token"`
// required: true
UID int64 `json:"uid" binding:"Required"`
// required: true
RepoName string `json:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"`
Mirror bool `json:"mirror"`
Private bool `json:"private"`
Description string `json:"description" binding:"MaxSize(255)"`
Wiki bool `json:"wiki"`
Milestones bool `json:"milestones"`
Labels bool `json:"labels"`
Issues bool `json:"issues"`
PullRequests bool `json:"pull_requests"`
Releases bool `json:"releases"`
MirrorInterval string `json:"mirror_interval"`
}
// Validate validates the fields
func (f *MigrateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// ParseRemoteAddr checks if given remote address is valid,
// and returns composed URL with needed username and password.
// It also checks if given user has permission when remote address
// is actually a local path.
func ParseRemoteAddr(remoteAddr, authUsername, authPassword string, user *models.User) (string, error) {
remoteAddr = strings.TrimSpace(remoteAddr)
// Remote address can be HTTP/HTTPS/Git URL or local path.
if strings.HasPrefix(remoteAddr, "http://") ||
strings.HasPrefix(remoteAddr, "https://") ||
strings.HasPrefix(remoteAddr, "git://") {
u, err := url.Parse(remoteAddr)
if err != nil {
return "", models.ErrInvalidCloneAddr{IsURLError: true}
}
if len(authUsername)+len(authPassword) > 0 {
u.User = url.UserPassword(authUsername, authPassword)
}
remoteAddr = u.String()
if u.Scheme == "git" && u.Port() != "" && (strings.Contains(remoteAddr, "%0d") || strings.Contains(remoteAddr, "%0a")) {
return "", models.ErrInvalidCloneAddr{IsURLError: true}
}
} else if !user.CanImportLocal() {
return "", models.ErrInvalidCloneAddr{IsPermissionDenied: true}
} else {
isDir, err := util.IsDir(remoteAddr)
if err != nil {
log.Error("Unable to check if %s is a directory: %v", remoteAddr, err)
return "", err
}
if !isDir {
return "", models.ErrInvalidCloneAddr{IsInvalidPath: true}
}
}
return remoteAddr, nil
}
// RepoSettingForm form for changing repository settings
type RepoSettingForm struct {
RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"`
Description string `binding:"MaxSize(255)"`
Website string `binding:"ValidUrl;MaxSize(255)"`
Interval string
MirrorAddress string
MirrorUsername string
MirrorPassword string
Private bool
Template bool
EnablePrune bool
// Advanced settings
EnableWiki bool
EnableExternalWiki bool
ExternalWikiURL string
EnableIssues bool
EnableExternalTracker bool
ExternalTrackerURL string
TrackerURLFormat string
TrackerIssueStyle string
EnableProjects bool
EnablePulls bool
PullsIgnoreWhitespace bool
PullsAllowMerge bool
PullsAllowRebase bool
PullsAllowRebaseMerge bool
PullsAllowSquash bool
EnableTimetracker bool
AllowOnlyContributorsToTrackTime bool
EnableIssueDependencies bool
IsArchived bool
// Signing Settings
TrustModel string
// Admin settings
EnableHealthCheck bool
EnableCloseIssuesViaCommitInAnyBranch bool
}
// Validate validates the fields
func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// __________ .__
// \______ \____________ ____ ____ | |__
// | | _/\_ __ \__ \ / \_/ ___\| | \
// | | \ | | \// __ \| | \ \___| Y \
// |______ / |__| (____ /___| /\___ >___| /
// \/ \/ \/ \/ \/
// ProtectBranchForm form for changing protected branch settings
type ProtectBranchForm struct {
Protected bool
EnablePush string
WhitelistUsers string
WhitelistTeams string
WhitelistDeployKeys bool
EnableMergeWhitelist bool
MergeWhitelistUsers string
MergeWhitelistTeams string
EnableStatusCheck bool
StatusCheckContexts []string
RequiredApprovals int64
EnableApprovalsWhitelist bool
ApprovalsWhitelistUsers string
ApprovalsWhitelistTeams string
BlockOnRejectedReviews bool
BlockOnOfficialReviewRequests bool
BlockOnOutdatedBranch bool
DismissStaleApprovals bool
RequireSignedCommits bool
ProtectedFilePatterns string
}
// Validate validates the fields
func (f *ProtectBranchForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// __ __ ___. .__ .__ __
// / \ / \ ____\_ |__ | |__ | |__ ____ | | __
// \ \/\/ // __ \| __ \| | \| | \ / _ \| |/ /
// \ /\ ___/| \_\ \ Y \ Y ( <_> ) <
// \__/\ / \___ >___ /___| /___| /\____/|__|_ \
// \/ \/ \/ \/ \/ \/
// WebhookForm form for changing web hook
type WebhookForm struct {
Events string
Create bool
Delete bool
Fork bool
Issues bool
IssueAssign bool
IssueLabel bool
IssueMilestone bool
IssueComment bool
Release bool
Push bool
PullRequest bool
PullRequestAssign bool
PullRequestLabel bool
PullRequestMilestone bool
PullRequestComment bool
PullRequestReview bool
PullRequestSync bool
Repository bool
Active bool
BranchFilter string `binding:"GlobPattern"`
}
// PushOnly if the hook will be triggered when push
func (f WebhookForm) PushOnly() bool {
return f.Events == "push_only"
}
// SendEverything if the hook will be triggered any event
func (f WebhookForm) SendEverything() bool {
return f.Events == "send_everything"
}
// ChooseEvents if the hook will be triggered choose events
func (f WebhookForm) ChooseEvents() bool {
return f.Events == "choose_events"
}
// NewWebhookForm form for creating web hook
type NewWebhookForm struct {
PayloadURL string `binding:"Required;ValidUrl"`
HTTPMethod string `binding:"Required;In(POST,GET)"`
ContentType int `binding:"Required"`
Secret string
WebhookForm
}
// Validate validates the fields
func (f *NewWebhookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// NewGogshookForm form for creating gogs hook
type NewGogshookForm struct {
PayloadURL string `binding:"Required;ValidUrl"`
ContentType int `binding:"Required"`
Secret string
WebhookForm
}
// Validate validates the fields
func (f *NewGogshookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// NewSlackHookForm form for creating slack hook
type NewSlackHookForm struct {
PayloadURL string `binding:"Required;ValidUrl"`
Channel string `binding:"Required"`
Username string
IconURL string
Color string
WebhookForm
}
// Validate validates the fields
func (f *NewSlackHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// HasInvalidChannel validates the channel name is in the right format
func (f NewSlackHookForm) HasInvalidChannel() bool {
return !utils.IsValidSlackChannel(f.Channel)
}
// NewDiscordHookForm form for creating discord hook
type NewDiscordHookForm struct {
PayloadURL string `binding:"Required;ValidUrl"`
Username string
IconURL string
WebhookForm
}
// Validate validates the fields
func (f *NewDiscordHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// NewDingtalkHookForm form for creating dingtalk hook
type NewDingtalkHookForm struct {
PayloadURL string `binding:"Required;ValidUrl"`
WebhookForm
}
// Validate validates the fields
func (f *NewDingtalkHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// NewTelegramHookForm form for creating telegram hook
type NewTelegramHookForm struct {
BotToken string `binding:"Required"`
ChatID string `binding:"Required"`
WebhookForm
}
// Validate validates the fields
func (f *NewTelegramHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// NewMatrixHookForm form for creating Matrix hook
type NewMatrixHookForm struct {
HomeserverURL string `binding:"Required;ValidUrl"`
RoomID string `binding:"Required"`
AccessToken string `binding:"Required"`
MessageType int
WebhookForm
}
// Validate validates the fields
func (f *NewMatrixHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// NewMSTeamsHookForm form for creating MS Teams hook
type NewMSTeamsHookForm struct {
PayloadURL string `binding:"Required;ValidUrl"`
WebhookForm
}
// Validate validates the fields
func (f *NewMSTeamsHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// NewFeishuHookForm form for creating feishu hook
type NewFeishuHookForm struct {
PayloadURL string `binding:"Required;ValidUrl"`
WebhookForm
}
// Validate validates the fields
func (f *NewFeishuHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// .___
// | | ______ ________ __ ____
// | |/ ___// ___/ | \_/ __ \
// | |\___ \ \___ \| | /\ ___/
// |___/____ >____ >____/ \___ >
// \/ \/ \/
// CreateIssueForm form for creating issue
type CreateIssueForm struct {
Title string `binding:"Required;MaxSize(255)"`
LabelIDs string `form:"label_ids"`
AssigneeIDs string `form:"assignee_ids"`
Ref string `form:"ref"`
MilestoneID int64
ProjectID int64
AssigneeID int64
Content string
Files []string
}
// Validate validates the fields
func (f *CreateIssueForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// CreateCommentForm form for creating comment
type CreateCommentForm struct {
Content string
Status string `binding:"OmitEmpty;In(reopen,close)"`
Files []string
}
// Validate validates the fields
func (f *CreateCommentForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// ReactionForm form for adding and removing reaction
type ReactionForm struct {
Content string `binding:"Required"`
}
// Validate validates the fields
func (f *ReactionForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// IssueLockForm form for locking an issue
type IssueLockForm struct {
Reason string `binding:"Required"`
}
// Validate validates the fields
func (i *IssueLockForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, i, ctx.Locale)
}
// HasValidReason checks to make sure that the reason submitted in
// the form matches any of the values in the config
func (i IssueLockForm) HasValidReason() bool {
if strings.TrimSpace(i.Reason) == "" {
return true
}
for _, v := range setting.Repository.Issue.LockReasons {
if v == i.Reason {
return true
}
}
return false
}
// __________ __ __
// \______ \_______ ____ |__| ____ _____/ |_ ______
// | ___/\_ __ \/ _ \ | |/ __ \_/ ___\ __\/ ___/
// | | | | \( <_> ) | \ ___/\ \___| | \___ \
// |____| |__| \____/\__| |\___ >\___ >__| /____ >
// \______| \/ \/ \/
// CreateProjectForm form for creating a project
type CreateProjectForm struct {
Title string `binding:"Required;MaxSize(100)"`
Content string
BoardType models.ProjectBoardType
}
// UserCreateProjectForm is a from for creating an individual or organization
// form.
type UserCreateProjectForm struct {
Title string `binding:"Required;MaxSize(100)"`
Content string
BoardType models.ProjectBoardType
UID int64 `binding:"Required"`
}
// EditProjectBoardTitleForm is a form for editing the title of a project's
// board
type EditProjectBoardTitleForm struct {
Title string `binding:"Required;MaxSize(100)"`
}
// _____ .__.__ __
// / \ |__| | ____ _______/ |_ ____ ____ ____
// / \ / \| | | _/ __ \ / ___/\ __\/ _ \ / \_/ __ \
// / Y \ | |_\ ___/ \___ \ | | ( <_> ) | \ ___/
// \____|__ /__|____/\___ >____ > |__| \____/|___| /\___ >
// \/ \/ \/ \/ \/
// CreateMilestoneForm form for creating milestone
type CreateMilestoneForm struct {
Title string `binding:"Required;MaxSize(50)"`
Content string
Deadline string
}
// Validate validates the fields
func (f *CreateMilestoneForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// .____ ___. .__
// | | _____ \_ |__ ____ | |
// | | \__ \ | __ \_/ __ \| |
// | |___ / __ \| \_\ \ ___/| |__
// |_______ (____ /___ /\___ >____/
// \/ \/ \/ \/
// CreateLabelForm form for creating label
type CreateLabelForm struct {
ID int64
Title string `binding:"Required;MaxSize(50)" locale:"repo.issues.label_title"`
Description string `binding:"MaxSize(200)" locale:"repo.issues.label_description"`
Color string `binding:"Required;Size(7)" locale:"repo.issues.label_color"`
}
// Validate validates the fields
func (f *CreateLabelForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// InitializeLabelsForm form for initializing labels
type InitializeLabelsForm struct {
TemplateName string `binding:"Required"`
}
// Validate validates the fields
func (f *InitializeLabelsForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// __________ .__ .__ __________ __
// \______ \__ __| | | | \______ \ ____ ________ __ ____ _______/ |_
// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\
// | | | | / |_| |__ | | \ ___< <_| | | /\ ___/ \___ \ | |
// |____| |____/|____/____/ |____|_ /\___ >__ |____/ \___ >____ > |__|
// \/ \/ |__| \/ \/
// MergePullRequestForm form for merging Pull Request
// swagger:model MergePullRequestOption
type MergePullRequestForm struct {
// required: true
// enum: merge,rebase,rebase-merge,squash
Do string `binding:"Required;In(merge,rebase,rebase-merge,squash)"`
MergeTitleField string
MergeMessageField string
ForceMerge *bool `json:"force_merge,omitempty"`
}
// Validate validates the fields
func (f *MergePullRequestForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// CodeCommentForm form for adding code comments for PRs
type CodeCommentForm struct {
Origin string `binding:"Required;In(timeline,diff)"`
Content string `binding:"Required"`
Side string `binding:"Required;In(previous,proposed)"`
Line int64
TreePath string `form:"path" binding:"Required"`
IsReview bool `form:"is_review"`
Reply int64 `form:"reply"`
LatestCommitID string
}
// Validate validates the fields
func (f *CodeCommentForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// SubmitReviewForm for submitting a finished code review
type SubmitReviewForm struct {
Content string
Type string `binding:"Required;In(approve,comment,reject)"`
CommitID string
}
// Validate validates the fields
func (f *SubmitReviewForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// ReviewType will return the corresponding reviewtype for type
func (f SubmitReviewForm) ReviewType() models.ReviewType {
switch f.Type {
case "approve":
return models.ReviewTypeApprove
case "comment":
return models.ReviewTypeComment
case "reject":
return models.ReviewTypeReject
default:
return models.ReviewTypeUnknown
}
}
// HasEmptyContent checks if the content of the review form is empty.
func (f SubmitReviewForm) HasEmptyContent() bool {
reviewType := f.ReviewType()
return (reviewType == models.ReviewTypeComment || reviewType == models.ReviewTypeReject) &&
len(strings.TrimSpace(f.Content)) == 0
}
// __________ .__
// \______ \ ____ | | ____ _____ ______ ____
// | _// __ \| | _/ __ \\__ \ / ___// __ \
// | | \ ___/| |_\ ___/ / __ \_\___ \\ ___/
// |____|_ /\___ >____/\___ >____ /____ >\___ >
// \/ \/ \/ \/ \/ \/
// NewReleaseForm form for creating release
type NewReleaseForm struct {
TagName string `binding:"Required;GitRefName;MaxSize(255)"`
Target string `form:"tag_target" binding:"Required;MaxSize(255)"`
Title string `binding:"Required;MaxSize(255)"`
Content string
Draft string
Prerelease bool
Files []string
}
// Validate validates the fields
func (f *NewReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// EditReleaseForm form for changing release
type EditReleaseForm struct {
Title string `form:"title" binding:"Required;MaxSize(255)"`
Content string `form:"content"`
Draft string `form:"draft"`
Prerelease bool `form:"prerelease"`
Files []string
}
// Validate validates the fields
func (f *EditReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// __ __.__ __ .__
// / \ / \__| | _|__|
// \ \/\/ / | |/ / |
// \ /| | <| |
// \__/\ / |__|__|_ \__|
// \/ \/
// NewWikiForm form for creating wiki
type NewWikiForm struct {
Title string `binding:"Required"`
Content string `binding:"Required"`
Message string
}
// Validate validates the fields
// FIXME: use code generation to generate this method.
func (f *NewWikiForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// ___________ .___.__ __
// \_ _____/ __| _/|__|/ |_
// | __)_ / __ | | \ __\
// | \/ /_/ | | || |
// /_______ /\____ | |__||__|
// \/ \/
// EditRepoFileForm form for changing repository file
type EditRepoFileForm struct {
TreePath string `binding:"Required;MaxSize(500)"`
Content string
CommitSummary string `binding:"MaxSize(100)"`
CommitMessage string
CommitChoice string `binding:"Required;MaxSize(50)"`
NewBranchName string `binding:"GitRefName;MaxSize(100)"`
LastCommit string
}
// Validate validates the fields
func (f *EditRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// EditPreviewDiffForm form for changing preview diff
type EditPreviewDiffForm struct {
Content string
}
// Validate validates the fields
func (f *EditPreviewDiffForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// ____ ___ .__ .___
// | | \______ | | _________ __| _/
// | | /\____ \| | / _ \__ \ / __ |
// | | / | |_> > |_( <_> ) __ \_/ /_/ |
// |______/ | __/|____/\____(____ /\____ |
// |__| \/ \/
//
// UploadRepoFileForm form for uploading repository file
type UploadRepoFileForm struct {
TreePath string `binding:"MaxSize(500)"`
CommitSummary string `binding:"MaxSize(100)"`
CommitMessage string
CommitChoice string `binding:"Required;MaxSize(50)"`
NewBranchName string `binding:"GitRefName;MaxSize(100)"`
Files []string
}
// Validate validates the fields
func (f *UploadRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// RemoveUploadFileForm form for removing uploaded file
type RemoveUploadFileForm struct {
File string `binding:"Required;MaxSize(50)"`
}
// Validate validates the fields
func (f *RemoveUploadFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// ________ .__ __
// \______ \ ____ | | _____/ |_ ____
// | | \_/ __ \| | _/ __ \ __\/ __ \
// | ` \ ___/| |_\ ___/| | \ ___/
// /_______ /\___ >____/\___ >__| \___ >
// \/ \/ \/ \/
// DeleteRepoFileForm form for deleting repository file
type DeleteRepoFileForm struct {
CommitSummary string `binding:"MaxSize(100)"`
CommitMessage string
CommitChoice string `binding:"Required;MaxSize(50)"`
NewBranchName string `binding:"GitRefName;MaxSize(100)"`
LastCommit string
}
// Validate validates the fields
func (f *DeleteRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// ___________.__ ___________ __
// \__ ___/|__| _____ ____ \__ ___/___________ ____ | | __ ___________
// | | | |/ \_/ __ \ | | \_ __ \__ \ _/ ___\| |/ // __ \_ __ \
// | | | | Y Y \ ___/ | | | | \// __ \\ \___| <\ ___/| | \/
// |____| |__|__|_| /\___ > |____| |__| (____ /\___ >__|_ \\___ >__|
// \/ \/ \/ \/ \/ \/
// AddTimeManuallyForm form that adds spent time manually.
type AddTimeManuallyForm struct {
Hours int `binding:"Range(0,1000)"`
Minutes int `binding:"Range(0,1000)"`
}
// Validate validates the fields
func (f *AddTimeManuallyForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// SaveTopicForm form for save topics for repository
type SaveTopicForm struct {
Topics []string `binding:"topics;Required;"`
}
// DeadlineForm hold the validation rules for deadlines
type DeadlineForm struct {
DateString string `form:"date" binding:"Required;Size(10)"`
}
// Validate validates the fields
func (f *DeadlineForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

View file

@ -1,67 +0,0 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package auth
import (
"testing"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
)
func TestSubmitReviewForm_IsEmpty(t *testing.T) {
cases := []struct {
form SubmitReviewForm
expected bool
}{
// Approved PR with a comment shouldn't count as empty
{SubmitReviewForm{Type: "approve", Content: "Awesome"}, false},
// Approved PR without a comment shouldn't count as empty
{SubmitReviewForm{Type: "approve", Content: ""}, false},
// Rejected PR without a comment should count as empty
{SubmitReviewForm{Type: "reject", Content: ""}, true},
// Rejected PR with a comment shouldn't count as empty
{SubmitReviewForm{Type: "reject", Content: "Awesome"}, false},
// Comment review on a PR with a comment shouldn't count as empty
{SubmitReviewForm{Type: "comment", Content: "Awesome"}, false},
// Comment review on a PR without a comment should count as empty
{SubmitReviewForm{Type: "comment", Content: ""}, true},
}
for _, v := range cases {
assert.Equal(t, v.expected, v.form.HasEmptyContent())
}
}
func TestIssueLock_HasValidReason(t *testing.T) {
// Init settings
_ = setting.Repository
cases := []struct {
form IssueLockForm
expected bool
}{
{IssueLockForm{""}, true}, // an empty reason is accepted
{IssueLockForm{"Off-topic"}, true},
{IssueLockForm{"Too heated"}, true},
{IssueLockForm{"Spam"}, true},
{IssueLockForm{"Resolved"}, true},
{IssueLockForm{"ZZZZ"}, false},
{IssueLockForm{"I want to lock this issue"}, false},
}
for _, v := range cases {
assert.Equal(t, v.expected, v.form.HasValidReason())
}
}

View file

@ -8,19 +8,15 @@ import (
"net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/middlewares"
"code.gitea.io/gitea/modules/session"
)
// DataStore represents a data store
type DataStore interface {
GetData() map[string]interface{}
}
type DataStore middlewares.DataStore
// SessionStore represents a session store
type SessionStore interface {
Get(interface{}) interface{}
Set(interface{}, interface{}) error
Delete(interface{}) error
}
type SessionStore session.Store
// SingleSignOn represents a SSO authentication method (plugin) for HTTP requests.
type SingleSignOn interface {

View file

@ -62,6 +62,8 @@ func (o *OAuth2) Free() error {
// userIDFromToken returns the user id corresponding to the OAuth token.
func (o *OAuth2) userIDFromToken(req *http.Request, store DataStore) int64 {
_ = req.ParseForm()
// Check access token.
tokenSHA := req.Form.Get("token")
if len(tokenSHA) == 0 {

View file

@ -1,366 +0,0 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package auth
import (
"mime/multipart"
"strings"
"code.gitea.io/gitea/modules/setting"
"gitea.com/macaron/binding"
"gitea.com/macaron/macaron"
)
// InstallForm form for installation page
type InstallForm struct {
DbType string `binding:"Required"`
DbHost string
DbUser string
DbPasswd string
DbName string
SSLMode string
Charset string `binding:"Required;In(utf8,utf8mb4)"`
DbPath string
DbSchema string
AppName string `binding:"Required" locale:"install.app_name"`
RepoRootPath string `binding:"Required"`
LFSRootPath string
RunUser string `binding:"Required"`
Domain string `binding:"Required"`
SSHPort int
HTTPPort string `binding:"Required"`
AppURL string `binding:"Required"`
LogRootPath string `binding:"Required"`
SMTPHost string
SMTPFrom string
SMTPUser string `binding:"OmitEmpty;MaxSize(254)" locale:"install.mailer_user"`
SMTPPasswd string
RegisterConfirm bool
MailNotify bool
OfflineMode bool
DisableGravatar bool
EnableFederatedAvatar bool
EnableOpenIDSignIn bool
EnableOpenIDSignUp bool
DisableRegistration bool
AllowOnlyExternalRegistration bool
EnableCaptcha bool
RequireSignInView bool
DefaultKeepEmailPrivate bool
DefaultAllowCreateOrganization bool
DefaultEnableTimetracking bool
NoReplyAddress string
AdminName string `binding:"OmitEmpty;AlphaDashDot;MaxSize(30)" locale:"install.admin_name"`
AdminPasswd string `binding:"OmitEmpty;MaxSize(255)" locale:"install.admin_password"`
AdminConfirmPasswd string
AdminEmail string `binding:"OmitEmpty;MinSize(3);MaxSize(254);Include(@)" locale:"install.admin_email"`
}
// Validate validates the fields
func (f *InstallForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// _____ ____ _________________ ___
// / _ \ | | \__ ___/ | \
// / /_\ \| | / | | / ~ \
// / | \ | / | | \ Y /
// \____|__ /______/ |____| \___|_ /
// \/ \/
// RegisterForm form for registering
type RegisterForm struct {
UserName string `binding:"Required;AlphaDashDot;MaxSize(40)"`
Email string `binding:"Required;Email;MaxSize(254)"`
Password string `binding:"MaxSize(255)"`
Retype string
GRecaptchaResponse string `form:"g-recaptcha-response"`
HcaptchaResponse string `form:"h-captcha-response"`
}
// Validate validates the fields
func (f *RegisterForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// IsEmailDomainWhitelisted validates that the email address
// provided by the user matches what has been configured .
// If the domain whitelist from the config is empty, it marks the
// email as whitelisted
func (f RegisterForm) IsEmailDomainWhitelisted() bool {
if len(setting.Service.EmailDomainWhitelist) == 0 {
return true
}
n := strings.LastIndex(f.Email, "@")
if n <= 0 {
return false
}
domain := strings.ToLower(f.Email[n+1:])
for _, v := range setting.Service.EmailDomainWhitelist {
if strings.ToLower(v) == domain {
return true
}
}
return false
}
// MustChangePasswordForm form for updating your password after account creation
// by an admin
type MustChangePasswordForm struct {
Password string `binding:"Required;MaxSize(255)"`
Retype string
}
// Validate validates the fields
func (f *MustChangePasswordForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// SignInForm form for signing in with user/password
type SignInForm struct {
UserName string `binding:"Required;MaxSize(254)"`
// TODO remove required from password for SecondFactorAuthentication
Password string `binding:"Required;MaxSize(255)"`
Remember bool
}
// Validate validates the fields
func (f *SignInForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// AuthorizationForm form for authorizing oauth2 clients
type AuthorizationForm struct {
ResponseType string `binding:"Required;In(code)"`
ClientID string `binding:"Required"`
RedirectURI string
State string
Scope string
Nonce string
// PKCE support
CodeChallengeMethod string // S256, plain
CodeChallenge string
}
// Validate validates the fields
func (f *AuthorizationForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// GrantApplicationForm form for authorizing oauth2 clients
type GrantApplicationForm struct {
ClientID string `binding:"Required"`
RedirectURI string
State string
Scope string
Nonce string
}
// Validate validates the fields
func (f *GrantApplicationForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// AccessTokenForm for issuing access tokens from authorization codes or refresh tokens
type AccessTokenForm struct {
GrantType string `json:"grant_type"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
RedirectURI string `json:"redirect_uri"`
Code string `json:"code"`
RefreshToken string `json:"refresh_token"`
// PKCE support
CodeVerifier string `json:"code_verifier"`
}
// Validate validates the fields
func (f *AccessTokenForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// __________________________________________.___ _______ ________ _________
// / _____/\_ _____/\__ ___/\__ ___/| |\ \ / _____/ / _____/
// \_____ \ | __)_ | | | | | |/ | \/ \ ___ \_____ \
// / \ | \ | | | | | / | \ \_\ \/ \
// /_______ //_______ / |____| |____| |___\____|__ /\______ /_______ /
// \/ \/ \/ \/ \/
// UpdateProfileForm form for updating profile
type UpdateProfileForm struct {
Name string `binding:"AlphaDashDot;MaxSize(40)"`
FullName string `binding:"MaxSize(100)"`
KeepEmailPrivate bool
Website string `binding:"ValidUrl;MaxSize(255)"`
Location string `binding:"MaxSize(50)"`
Language string
Description string `binding:"MaxSize(255)"`
KeepActivityPrivate bool
}
// Validate validates the fields
func (f *UpdateProfileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// Avatar types
const (
AvatarLocal string = "local"
AvatarByMail string = "bymail"
)
// AvatarForm form for changing avatar
type AvatarForm struct {
Source string
Avatar *multipart.FileHeader
Gravatar string `binding:"OmitEmpty;Email;MaxSize(254)"`
Federavatar bool
}
// Validate validates the fields
func (f *AvatarForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// AddEmailForm form for adding new email
type AddEmailForm struct {
Email string `binding:"Required;Email;MaxSize(254)"`
}
// Validate validates the fields
func (f *AddEmailForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// UpdateThemeForm form for updating a users' theme
type UpdateThemeForm struct {
Theme string `binding:"Required;MaxSize(30)"`
}
// Validate validates the field
func (f *UpdateThemeForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// IsThemeExists checks if the theme is a theme available in the config.
func (f UpdateThemeForm) IsThemeExists() bool {
var exists bool
for _, v := range setting.UI.Themes {
if strings.EqualFold(v, f.Theme) {
exists = true
break
}
}
return exists
}
// ChangePasswordForm form for changing password
type ChangePasswordForm struct {
OldPassword string `form:"old_password" binding:"MaxSize(255)"`
Password string `form:"password" binding:"Required;MaxSize(255)"`
Retype string `form:"retype"`
}
// Validate validates the fields
func (f *ChangePasswordForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// AddOpenIDForm is for changing openid uri
type AddOpenIDForm struct {
Openid string `binding:"Required;MaxSize(256)"`
}
// Validate validates the fields
func (f *AddOpenIDForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// AddKeyForm form for adding SSH/GPG key
type AddKeyForm struct {
Type string `binding:"OmitEmpty"`
Title string `binding:"Required;MaxSize(50)"`
Content string `binding:"Required"`
IsWritable bool
}
// Validate validates the fields
func (f *AddKeyForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// NewAccessTokenForm form for creating access token
type NewAccessTokenForm struct {
Name string `binding:"Required;MaxSize(255)"`
}
// Validate validates the fields
func (f *NewAccessTokenForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// EditOAuth2ApplicationForm form for editing oauth2 applications
type EditOAuth2ApplicationForm struct {
Name string `binding:"Required;MaxSize(255)" form:"application_name"`
RedirectURI string `binding:"Required" form:"redirect_uri"`
}
// Validate validates the fields
func (f *EditOAuth2ApplicationForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// TwoFactorAuthForm for logging in with 2FA token.
type TwoFactorAuthForm struct {
Passcode string `binding:"Required"`
}
// Validate validates the fields
func (f *TwoFactorAuthForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// TwoFactorScratchAuthForm for logging in with 2FA scratch token.
type TwoFactorScratchAuthForm struct {
Token string `binding:"Required"`
}
// Validate validates the fields
func (f *TwoFactorScratchAuthForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// U2FRegistrationForm for reserving an U2F name
type U2FRegistrationForm struct {
Name string `binding:"Required"`
}
// Validate validates the fields
func (f *U2FRegistrationForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// U2FDeleteForm for deleting U2F keys
type U2FDeleteForm struct {
ID int64 `binding:"Required"`
}
// Validate validates the fields
func (f *U2FDeleteForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

View file

@ -1,45 +0,0 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package auth
import (
"gitea.com/macaron/binding"
"gitea.com/macaron/macaron"
)
// SignInOpenIDForm form for signing in with OpenID
type SignInOpenIDForm struct {
Openid string `binding:"Required;MaxSize(256)"`
Remember bool
}
// Validate validates the fields
func (f *SignInOpenIDForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// SignUpOpenIDForm form for signin up with OpenID
type SignUpOpenIDForm struct {
UserName string `binding:"Required;AlphaDashDot;MaxSize(40)"`
Email string `binding:"Required;Email;MaxSize(254)"`
GRecaptchaResponse string `form:"g-recaptcha-response"`
HcaptchaResponse string `form:"h-captcha-response"`
}
// Validate validates the fields
func (f *SignUpOpenIDForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// ConnectOpenIDForm form for connecting an existing account to an OpenID URI
type ConnectOpenIDForm struct {
UserName string `binding:"Required;MaxSize(254)"`
Password string `binding:"Required;MaxSize(255)"`
}
// Validate validates the fields
func (f *ConnectOpenIDForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

View file

@ -1,64 +0,0 @@
// Copyright 2018 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package auth
import (
"testing"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
)
func TestRegisterForm_IsDomainWhiteList_Empty(t *testing.T) {
_ = setting.Service
setting.Service.EmailDomainWhitelist = []string{}
form := RegisterForm{}
assert.True(t, form.IsEmailDomainWhitelisted())
}
func TestRegisterForm_IsDomainWhiteList_InvalidEmail(t *testing.T) {
_ = setting.Service
setting.Service.EmailDomainWhitelist = []string{"gitea.io"}
tt := []struct {
email string
}{
{"securitygieqqq"},
{"hdudhdd"},
}
for _, v := range tt {
form := RegisterForm{Email: v.email}
assert.False(t, form.IsEmailDomainWhitelisted())
}
}
func TestRegisterForm_IsDomainWhiteList_ValidEmail(t *testing.T) {
_ = setting.Service
setting.Service.EmailDomainWhitelist = []string{"gitea.io"}
tt := []struct {
email string
valid bool
}{
{"security@gitea.io", true},
{"security@gITea.io", true},
{"hdudhdd", false},
{"seee@example.com", false},
}
for _, v := range tt {
form := RegisterForm{Email: v.email}
assert.Equal(t, v.valid, form.IsEmailDomainWhitelisted())
}
}