summaryrefslogtreecommitdiffstats
path: root/modules/forms
diff options
context:
space:
mode:
Diffstat (limited to 'modules/forms')
-rw-r--r--modules/forms/admin.go70
-rw-r--r--modules/forms/auth_form.go75
-rw-r--r--modules/forms/org.go78
-rw-r--r--modules/forms/repo_branch_form.go25
-rw-r--r--modules/forms/repo_form.go810
-rw-r--r--modules/forms/repo_form_test.go67
-rw-r--r--modules/forms/user_form.go388
-rw-r--r--modules/forms/user_form_auth_openid.go51
-rw-r--r--modules/forms/user_form_test.go64
9 files changed, 1628 insertions, 0 deletions
diff --git a/modules/forms/admin.go b/modules/forms/admin.go
new file mode 100644
index 0000000000..09ad420e15
--- /dev/null
+++ b/modules/forms/admin.go
@@ -0,0 +1,70 @@
+// 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 forms
+
+import (
+ "net/http"
+
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/middlewares"
+
+ "gitea.com/go-chi/binding"
+)
+
+// 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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.Validate(errs, ctx.Data, f, ctx.Locale)
+}
diff --git a/modules/forms/auth_form.go b/modules/forms/auth_form.go
new file mode 100644
index 0000000000..10d0f82959
--- /dev/null
+++ b/modules/forms/auth_form.go
@@ -0,0 +1,75 @@
+// 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 forms
+
+import (
+ "net/http"
+
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/middlewares"
+
+ "gitea.com/go-chi/binding"
+)
+
+// 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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.Validate(errs, ctx.Data, f, ctx.Locale)
+}
diff --git a/modules/forms/org.go b/modules/forms/org.go
new file mode 100644
index 0000000000..513f80768f
--- /dev/null
+++ b/modules/forms/org.go
@@ -0,0 +1,78 @@
+// 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 forms
+
+import (
+ "net/http"
+
+ "code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/middlewares"
+ "code.gitea.io/gitea/modules/structs"
+
+ "gitea.com/go-chi/binding"
+)
+
+// ________ .__ __ .__
+// \_____ \_______ _________ ____ |__|____________ _/ |_|__| ____ ____
+// / | \_ __ \/ ___\__ \ / \| \___ /\__ \\ __\ |/ _ \ / \
+// / | \ | \/ /_/ > __ \| | \ |/ / / __ \| | | ( <_> ) | \
+// \_______ /__| \___ (____ /___| /__/_____ \(____ /__| |__|\____/|___| /
+// \/ /_____/ \/ \/ \/ \/ \/
+
+// 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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.Validate(errs, ctx.Data, f, ctx.Locale)
+}
diff --git a/modules/forms/repo_branch_form.go b/modules/forms/repo_branch_form.go
new file mode 100644
index 0000000000..afb7f8d4f0
--- /dev/null
+++ b/modules/forms/repo_branch_form.go
@@ -0,0 +1,25 @@
+// 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 forms
+
+import (
+ "net/http"
+
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/middlewares"
+
+ "gitea.com/go-chi/binding"
+)
+
+// 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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.Validate(errs, ctx.Data, f, ctx.Locale)
+}
diff --git a/modules/forms/repo_form.go b/modules/forms/repo_form.go
new file mode 100644
index 0000000000..4a478c7d35
--- /dev/null
+++ b/modules/forms/repo_form.go
@@ -0,0 +1,810 @@
+// 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 forms
+
+import (
+ "net/http"
+ "net/url"
+ "strings"
+
+ "code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/middlewares"
+ "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/go-chi/binding"
+)
+
+// _______________________________________ _________.______________________ _______________.___.
+// \______ \_ _____/\______ \_____ \ / _____/| \__ ___/\_____ \\______ \__ | |
+// | _/| __)_ | ___// | \ \_____ \ | | | | / | \| _// | |
+// | | \| \ | | / | \/ \| | | | / | \ | \\____ |
+// |____|_ /_______ / |____| \_______ /_______ /|___| |____| \_______ /____|_ // ______|
+// \/ \/ \/ \/ \/ \/ \/
+
+// 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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.Validate(errs, ctx.Data, f, ctx.Locale)
+}
diff --git a/modules/forms/repo_form_test.go b/modules/forms/repo_form_test.go
new file mode 100644
index 0000000000..4f65d59ca6
--- /dev/null
+++ b/modules/forms/repo_form_test.go
@@ -0,0 +1,67 @@
+// 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 forms
+
+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())
+ }
+}
diff --git a/modules/forms/user_form.go b/modules/forms/user_form.go
new file mode 100644
index 0000000000..e3090f9ae5
--- /dev/null
+++ b/modules/forms/user_form.go
@@ -0,0 +1,388 @@
+// 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 forms
+
+import (
+ "mime/multipart"
+ "net/http"
+ "strings"
+
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/middlewares"
+ "code.gitea.io/gitea/modules/setting"
+
+ "gitea.com/go-chi/binding"
+)
+
+// 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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.Validate(errs, ctx.Data, f, ctx.Locale)
+}
diff --git a/modules/forms/user_form_auth_openid.go b/modules/forms/user_form_auth_openid.go
new file mode 100644
index 0000000000..06601d7e15
--- /dev/null
+++ b/modules/forms/user_form_auth_openid.go
@@ -0,0 +1,51 @@
+// 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 forms
+
+import (
+ "net/http"
+
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/middlewares"
+ "gitea.com/go-chi/binding"
+)
+
+// 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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.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(req *http.Request, errs binding.Errors) binding.Errors {
+ ctx := context.GetContext(req)
+ return middlewares.Validate(errs, ctx.Data, f, ctx.Locale)
+}
diff --git a/modules/forms/user_form_test.go b/modules/forms/user_form_test.go
new file mode 100644
index 0000000000..6e0518789c
--- /dev/null
+++ b/modules/forms/user_form_test.go
@@ -0,0 +1,64 @@
+// 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 forms
+
+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())
+ }
+}