diff options
Diffstat (limited to 'modules/forms')
-rw-r--r-- | modules/forms/admin.go | 70 | ||||
-rw-r--r-- | modules/forms/auth_form.go | 75 | ||||
-rw-r--r-- | modules/forms/org.go | 78 | ||||
-rw-r--r-- | modules/forms/repo_branch_form.go | 25 | ||||
-rw-r--r-- | modules/forms/repo_form.go | 810 | ||||
-rw-r--r-- | modules/forms/repo_form_test.go | 67 | ||||
-rw-r--r-- | modules/forms/user_form.go | 388 | ||||
-rw-r--r-- | modules/forms/user_form_auth_openid.go | 51 | ||||
-rw-r--r-- | modules/forms/user_form_test.go | 64 |
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()) + } +} |