Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2017 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package auth
  6. import (
  7. "net/url"
  8. "strings"
  9. "code.gitea.io/gitea/models"
  10. "code.gitea.io/gitea/routers/utils"
  11. "github.com/Unknwon/com"
  12. "github.com/go-macaron/binding"
  13. "gopkg.in/macaron.v1"
  14. )
  15. // _______________________________________ _________.______________________ _______________.___.
  16. // \______ \_ _____/\______ \_____ \ / _____/| \__ ___/\_____ \\______ \__ | |
  17. // | _/| __)_ | ___// | \ \_____ \ | | | | / | \| _// | |
  18. // | | \| \ | | / | \/ \| | | | / | \ | \\____ |
  19. // |____|_ /_______ / |____| \_______ /_______ /|___| |____| \_______ /____|_ // ______|
  20. // \/ \/ \/ \/ \/ \/ \/
  21. // CreateRepoForm form for creating repository
  22. type CreateRepoForm struct {
  23. UID int64 `binding:"Required"`
  24. RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"`
  25. Private bool
  26. Description string `binding:"MaxSize(255)"`
  27. AutoInit bool
  28. Gitignores string
  29. License string
  30. Readme string
  31. }
  32. // Validate validates the fields
  33. func (f *CreateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  34. return validate(errs, ctx.Data, f, ctx.Locale)
  35. }
  36. // MigrateRepoForm form for migrating repository
  37. type MigrateRepoForm struct {
  38. // required: true
  39. CloneAddr string `json:"clone_addr" binding:"Required"`
  40. AuthUsername string `json:"auth_username"`
  41. AuthPassword string `json:"auth_password"`
  42. // required: true
  43. UID int64 `json:"uid" binding:"Required"`
  44. // required: true
  45. RepoName string `json:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"`
  46. Mirror bool `json:"mirror"`
  47. Private bool `json:"private"`
  48. Description string `json:"description" binding:"MaxSize(255)"`
  49. }
  50. // Validate validates the fields
  51. func (f *MigrateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  52. return validate(errs, ctx.Data, f, ctx.Locale)
  53. }
  54. // ParseRemoteAddr checks if given remote address is valid,
  55. // and returns composed URL with needed username and password.
  56. // It also checks if given user has permission when remote address
  57. // is actually a local path.
  58. func (f MigrateRepoForm) ParseRemoteAddr(user *models.User) (string, error) {
  59. remoteAddr := strings.TrimSpace(f.CloneAddr)
  60. // Remote address can be HTTP/HTTPS/Git URL or local path.
  61. if strings.HasPrefix(remoteAddr, "http://") ||
  62. strings.HasPrefix(remoteAddr, "https://") ||
  63. strings.HasPrefix(remoteAddr, "git://") {
  64. u, err := url.Parse(remoteAddr)
  65. if err != nil {
  66. return "", models.ErrInvalidCloneAddr{IsURLError: true}
  67. }
  68. if len(f.AuthUsername)+len(f.AuthPassword) > 0 {
  69. u.User = url.UserPassword(f.AuthUsername, f.AuthPassword)
  70. }
  71. remoteAddr = u.String()
  72. } else if !user.CanImportLocal() {
  73. return "", models.ErrInvalidCloneAddr{IsPermissionDenied: true}
  74. } else if !com.IsDir(remoteAddr) {
  75. return "", models.ErrInvalidCloneAddr{IsInvalidPath: true}
  76. }
  77. return remoteAddr, nil
  78. }
  79. // RepoSettingForm form for changing repository settings
  80. type RepoSettingForm struct {
  81. RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"`
  82. Description string `binding:"MaxSize(255)"`
  83. Website string `binding:"ValidUrl;MaxSize(255)"`
  84. Interval string
  85. MirrorAddress string
  86. Private bool
  87. EnablePrune bool
  88. // Advanced settings
  89. EnableWiki bool
  90. EnableExternalWiki bool
  91. ExternalWikiURL string
  92. EnableIssues bool
  93. EnableExternalTracker bool
  94. ExternalTrackerURL string
  95. TrackerURLFormat string
  96. TrackerIssueStyle string
  97. EnablePulls bool
  98. PullsIgnoreWhitespace bool
  99. PullsAllowMerge bool
  100. PullsAllowRebase bool
  101. PullsAllowSquash bool
  102. EnableTimetracker bool
  103. AllowOnlyContributorsToTrackTime bool
  104. EnableIssueDependencies bool
  105. // Admin settings
  106. EnableHealthCheck bool
  107. }
  108. // Validate validates the fields
  109. func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  110. return validate(errs, ctx.Data, f, ctx.Locale)
  111. }
  112. // __________ .__
  113. // \______ \____________ ____ ____ | |__
  114. // | | _/\_ __ \__ \ / \_/ ___\| | \
  115. // | | \ | | \// __ \| | \ \___| Y \
  116. // |______ / |__| (____ /___| /\___ >___| /
  117. // \/ \/ \/ \/ \/
  118. // ProtectBranchForm form for changing protected branch settings
  119. type ProtectBranchForm struct {
  120. Protected bool
  121. EnableWhitelist bool
  122. WhitelistUsers string
  123. WhitelistTeams string
  124. EnableMergeWhitelist bool
  125. MergeWhitelistUsers string
  126. MergeWhitelistTeams string
  127. RequiredApprovals int64
  128. ApprovalsWhitelistUsers string
  129. ApprovalsWhitelistTeams string
  130. }
  131. // Validate validates the fields
  132. func (f *ProtectBranchForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  133. return validate(errs, ctx.Data, f, ctx.Locale)
  134. }
  135. // __ __ ___. .__ .__ __
  136. // / \ / \ ____\_ |__ | |__ | |__ ____ | | __
  137. // \ \/\/ // __ \| __ \| | \| | \ / _ \| |/ /
  138. // \ /\ ___/| \_\ \ Y \ Y ( <_> ) <
  139. // \__/\ / \___ >___ /___| /___| /\____/|__|_ \
  140. // \/ \/ \/ \/ \/ \/
  141. // WebhookForm form for changing web hook
  142. type WebhookForm struct {
  143. Events string
  144. Create bool
  145. Delete bool
  146. Fork bool
  147. Issues bool
  148. IssueComment bool
  149. Release bool
  150. Push bool
  151. PullRequest bool
  152. Repository bool
  153. Active bool
  154. }
  155. // PushOnly if the hook will be triggered when push
  156. func (f WebhookForm) PushOnly() bool {
  157. return f.Events == "push_only"
  158. }
  159. // SendEverything if the hook will be triggered any event
  160. func (f WebhookForm) SendEverything() bool {
  161. return f.Events == "send_everything"
  162. }
  163. // ChooseEvents if the hook will be triggered choose events
  164. func (f WebhookForm) ChooseEvents() bool {
  165. return f.Events == "choose_events"
  166. }
  167. // NewWebhookForm form for creating web hook
  168. type NewWebhookForm struct {
  169. PayloadURL string `binding:"Required;ValidUrl"`
  170. ContentType int `binding:"Required"`
  171. Secret string
  172. WebhookForm
  173. }
  174. // Validate validates the fields
  175. func (f *NewWebhookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  176. return validate(errs, ctx.Data, f, ctx.Locale)
  177. }
  178. // NewGogshookForm form for creating gogs hook
  179. type NewGogshookForm struct {
  180. PayloadURL string `binding:"Required;ValidUrl"`
  181. ContentType int `binding:"Required"`
  182. Secret string
  183. WebhookForm
  184. }
  185. // Validate validates the fields
  186. func (f *NewGogshookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  187. return validate(errs, ctx.Data, f, ctx.Locale)
  188. }
  189. // NewSlackHookForm form for creating slack hook
  190. type NewSlackHookForm struct {
  191. PayloadURL string `binding:"Required;ValidUrl"`
  192. Channel string `binding:"Required"`
  193. Username string
  194. IconURL string
  195. Color string
  196. WebhookForm
  197. }
  198. // Validate validates the fields
  199. func (f *NewSlackHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  200. return validate(errs, ctx.Data, f, ctx.Locale)
  201. }
  202. // HasInvalidChannel validates the channel name is in the right format
  203. func (f NewSlackHookForm) HasInvalidChannel() bool {
  204. return !utils.IsValidSlackChannel(f.Channel)
  205. }
  206. // NewDiscordHookForm form for creating discord hook
  207. type NewDiscordHookForm struct {
  208. PayloadURL string `binding:"Required;ValidUrl"`
  209. Username string
  210. IconURL string
  211. WebhookForm
  212. }
  213. // Validate validates the fields
  214. func (f *NewDiscordHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  215. return validate(errs, ctx.Data, f, ctx.Locale)
  216. }
  217. // NewDingtalkHookForm form for creating dingtalk hook
  218. type NewDingtalkHookForm struct {
  219. PayloadURL string `binding:"Required;ValidUrl"`
  220. WebhookForm
  221. }
  222. // Validate validates the fields
  223. func (f *NewDingtalkHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  224. return validate(errs, ctx.Data, f, ctx.Locale)
  225. }
  226. // .___
  227. // | | ______ ________ __ ____
  228. // | |/ ___// ___/ | \_/ __ \
  229. // | |\___ \ \___ \| | /\ ___/
  230. // |___/____ >____ >____/ \___ >
  231. // \/ \/ \/
  232. // CreateIssueForm form for creating issue
  233. type CreateIssueForm struct {
  234. Title string `binding:"Required;MaxSize(255)"`
  235. LabelIDs string `form:"label_ids"`
  236. AssigneeIDs string `form:"assignee_ids"`
  237. Ref string `form:"ref"`
  238. MilestoneID int64
  239. AssigneeID int64
  240. Content string
  241. Files []string
  242. }
  243. // Validate validates the fields
  244. func (f *CreateIssueForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  245. return validate(errs, ctx.Data, f, ctx.Locale)
  246. }
  247. // CreateCommentForm form for creating comment
  248. type CreateCommentForm struct {
  249. Content string
  250. Status string `binding:"OmitEmpty;In(reopen,close)"`
  251. Files []string
  252. }
  253. // Validate validates the fields
  254. func (f *CreateCommentForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  255. return validate(errs, ctx.Data, f, ctx.Locale)
  256. }
  257. // ReactionForm form for adding and removing reaction
  258. type ReactionForm struct {
  259. Content string `binding:"Required;In(+1,-1,laugh,confused,heart,hooray)"`
  260. }
  261. // Validate validates the fields
  262. func (f *ReactionForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  263. return validate(errs, ctx.Data, f, ctx.Locale)
  264. }
  265. // _____ .__.__ __
  266. // / \ |__| | ____ _______/ |_ ____ ____ ____
  267. // / \ / \| | | _/ __ \ / ___/\ __\/ _ \ / \_/ __ \
  268. // / Y \ | |_\ ___/ \___ \ | | ( <_> ) | \ ___/
  269. // \____|__ /__|____/\___ >____ > |__| \____/|___| /\___ >
  270. // \/ \/ \/ \/ \/
  271. // CreateMilestoneForm form for creating milestone
  272. type CreateMilestoneForm struct {
  273. Title string `binding:"Required;MaxSize(50)"`
  274. Content string
  275. Deadline string
  276. }
  277. // Validate validates the fields
  278. func (f *CreateMilestoneForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  279. return validate(errs, ctx.Data, f, ctx.Locale)
  280. }
  281. // .____ ___. .__
  282. // | | _____ \_ |__ ____ | |
  283. // | | \__ \ | __ \_/ __ \| |
  284. // | |___ / __ \| \_\ \ ___/| |__
  285. // |_______ (____ /___ /\___ >____/
  286. // \/ \/ \/ \/
  287. // CreateLabelForm form for creating label
  288. type CreateLabelForm struct {
  289. ID int64
  290. Title string `binding:"Required;MaxSize(50)" locale:"repo.issues.label_title"`
  291. Description string `binding:"MaxSize(200)" locale:"repo.issues.label_description"`
  292. Color string `binding:"Required;Size(7)" locale:"repo.issues.label_color"`
  293. }
  294. // Validate validates the fields
  295. func (f *CreateLabelForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  296. return validate(errs, ctx.Data, f, ctx.Locale)
  297. }
  298. // InitializeLabelsForm form for initializing labels
  299. type InitializeLabelsForm struct {
  300. TemplateName string `binding:"Required"`
  301. }
  302. // Validate validates the fields
  303. func (f *InitializeLabelsForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  304. return validate(errs, ctx.Data, f, ctx.Locale)
  305. }
  306. // __________ .__ .__ __________ __
  307. // \______ \__ __| | | | \______ \ ____ ________ __ ____ _______/ |_
  308. // | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\
  309. // | | | | / |_| |__ | | \ ___< <_| | | /\ ___/ \___ \ | |
  310. // |____| |____/|____/____/ |____|_ /\___ >__ |____/ \___ >____ > |__|
  311. // \/ \/ |__| \/ \/
  312. // MergePullRequestForm form for merging Pull Request
  313. type MergePullRequestForm struct {
  314. Do string `binding:"Required;In(merge,rebase,squash)"`
  315. MergeTitleField string
  316. MergeMessageField string
  317. }
  318. // Validate validates the fields
  319. func (f *MergePullRequestForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  320. return validate(errs, ctx.Data, f, ctx.Locale)
  321. }
  322. // CodeCommentForm form for adding code comments for PRs
  323. type CodeCommentForm struct {
  324. Content string `binding:"Required"`
  325. Side string `binding:"Required;In(previous,proposed)"`
  326. Line int64
  327. TreePath string `form:"path" binding:"Required"`
  328. IsReview bool `form:"is_review"`
  329. Reply int64 `form:"reply"`
  330. }
  331. // Validate validates the fields
  332. func (f *CodeCommentForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  333. return validate(errs, ctx.Data, f, ctx.Locale)
  334. }
  335. // SubmitReviewForm for submitting a finished code review
  336. type SubmitReviewForm struct {
  337. Content string
  338. Type string `binding:"Required;In(approve,comment,reject)"`
  339. }
  340. // Validate validates the fields
  341. func (f *SubmitReviewForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  342. return validate(errs, ctx.Data, f, ctx.Locale)
  343. }
  344. // ReviewType will return the corresponding reviewtype for type
  345. func (f SubmitReviewForm) ReviewType() models.ReviewType {
  346. switch f.Type {
  347. case "approve":
  348. return models.ReviewTypeApprove
  349. case "comment":
  350. return models.ReviewTypeComment
  351. case "reject":
  352. return models.ReviewTypeReject
  353. default:
  354. return models.ReviewTypeUnknown
  355. }
  356. }
  357. // HasEmptyContent checks if the content of the review form is empty.
  358. func (f SubmitReviewForm) HasEmptyContent() bool {
  359. reviewType := f.ReviewType()
  360. return (reviewType == models.ReviewTypeComment || reviewType == models.ReviewTypeReject) &&
  361. len(strings.TrimSpace(f.Content)) == 0
  362. }
  363. // __________ .__
  364. // \______ \ ____ | | ____ _____ ______ ____
  365. // | _// __ \| | _/ __ \\__ \ / ___// __ \
  366. // | | \ ___/| |_\ ___/ / __ \_\___ \\ ___/
  367. // |____|_ /\___ >____/\___ >____ /____ >\___ >
  368. // \/ \/ \/ \/ \/ \/
  369. // NewReleaseForm form for creating release
  370. type NewReleaseForm struct {
  371. TagName string `binding:"Required;GitRefName"`
  372. Target string `form:"tag_target" binding:"Required"`
  373. Title string `binding:"Required"`
  374. Content string
  375. Draft string
  376. Prerelease bool
  377. Files []string
  378. }
  379. // Validate validates the fields
  380. func (f *NewReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  381. return validate(errs, ctx.Data, f, ctx.Locale)
  382. }
  383. // EditReleaseForm form for changing release
  384. type EditReleaseForm struct {
  385. Title string `form:"title" binding:"Required"`
  386. Content string `form:"content"`
  387. Draft string `form:"draft"`
  388. Prerelease bool `form:"prerelease"`
  389. Files []string
  390. }
  391. // Validate validates the fields
  392. func (f *EditReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  393. return validate(errs, ctx.Data, f, ctx.Locale)
  394. }
  395. // __ __.__ __ .__
  396. // / \ / \__| | _|__|
  397. // \ \/\/ / | |/ / |
  398. // \ /| | <| |
  399. // \__/\ / |__|__|_ \__|
  400. // \/ \/
  401. // NewWikiForm form for creating wiki
  402. type NewWikiForm struct {
  403. Title string `binding:"Required"`
  404. Content string `binding:"Required"`
  405. Message string
  406. }
  407. // Validate validates the fields
  408. // FIXME: use code generation to generate this method.
  409. func (f *NewWikiForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  410. return validate(errs, ctx.Data, f, ctx.Locale)
  411. }
  412. // ___________ .___.__ __
  413. // \_ _____/ __| _/|__|/ |_
  414. // | __)_ / __ | | \ __\
  415. // | \/ /_/ | | || |
  416. // /_______ /\____ | |__||__|
  417. // \/ \/
  418. // EditRepoFileForm form for changing repository file
  419. type EditRepoFileForm struct {
  420. TreePath string `binding:"Required;MaxSize(500)"`
  421. Content string `binding:"Required"`
  422. CommitSummary string `binding:"MaxSize(100)"`
  423. CommitMessage string
  424. CommitChoice string `binding:"Required;MaxSize(50)"`
  425. NewBranchName string `binding:"GitRefName;MaxSize(100)"`
  426. LastCommit string
  427. }
  428. // Validate validates the fields
  429. func (f *EditRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  430. return validate(errs, ctx.Data, f, ctx.Locale)
  431. }
  432. // EditPreviewDiffForm form for changing preview diff
  433. type EditPreviewDiffForm struct {
  434. Content string
  435. }
  436. // Validate validates the fields
  437. func (f *EditPreviewDiffForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  438. return validate(errs, ctx.Data, f, ctx.Locale)
  439. }
  440. // ____ ___ .__ .___
  441. // | | \______ | | _________ __| _/
  442. // | | /\____ \| | / _ \__ \ / __ |
  443. // | | / | |_> > |_( <_> ) __ \_/ /_/ |
  444. // |______/ | __/|____/\____(____ /\____ |
  445. // |__| \/ \/
  446. //
  447. // UploadRepoFileForm form for uploading repository file
  448. type UploadRepoFileForm struct {
  449. TreePath string `binding:"MaxSize(500)"`
  450. CommitSummary string `binding:"MaxSize(100)"`
  451. CommitMessage string
  452. CommitChoice string `binding:"Required;MaxSize(50)"`
  453. NewBranchName string `binding:"GitRefName;MaxSize(100)"`
  454. Files []string
  455. }
  456. // Validate validates the fields
  457. func (f *UploadRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  458. return validate(errs, ctx.Data, f, ctx.Locale)
  459. }
  460. // RemoveUploadFileForm form for removing uploaded file
  461. type RemoveUploadFileForm struct {
  462. File string `binding:"Required;MaxSize(50)"`
  463. }
  464. // Validate validates the fields
  465. func (f *RemoveUploadFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  466. return validate(errs, ctx.Data, f, ctx.Locale)
  467. }
  468. // ________ .__ __
  469. // \______ \ ____ | | _____/ |_ ____
  470. // | | \_/ __ \| | _/ __ \ __\/ __ \
  471. // | ` \ ___/| |_\ ___/| | \ ___/
  472. // /_______ /\___ >____/\___ >__| \___ >
  473. // \/ \/ \/ \/
  474. // DeleteRepoFileForm form for deleting repository file
  475. type DeleteRepoFileForm struct {
  476. CommitSummary string `binding:"MaxSize(100)"`
  477. CommitMessage string
  478. CommitChoice string `binding:"Required;MaxSize(50)"`
  479. NewBranchName string `binding:"GitRefName;MaxSize(100)"`
  480. }
  481. // Validate validates the fields
  482. func (f *DeleteRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  483. return validate(errs, ctx.Data, f, ctx.Locale)
  484. }
  485. // ___________.__ ___________ __
  486. // \__ ___/|__| _____ ____ \__ ___/___________ ____ | | __ ___________
  487. // | | | |/ \_/ __ \ | | \_ __ \__ \ _/ ___\| |/ // __ \_ __ \
  488. // | | | | Y Y \ ___/ | | | | \// __ \\ \___| <\ ___/| | \/
  489. // |____| |__|__|_| /\___ > |____| |__| (____ /\___ >__|_ \\___ >__|
  490. // \/ \/ \/ \/ \/ \/
  491. // AddTimeManuallyForm form that adds spent time manually.
  492. type AddTimeManuallyForm struct {
  493. Hours int `binding:"Range(0,1000)"`
  494. Minutes int `binding:"Range(0,1000)"`
  495. }
  496. // Validate validates the fields
  497. func (f *AddTimeManuallyForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  498. return validate(errs, ctx.Data, f, ctx.Locale)
  499. }
  500. // SaveTopicForm form for save topics for repository
  501. type SaveTopicForm struct {
  502. Topics []string `binding:"topics;Required;"`
  503. }
  504. // DeadlineForm hold the validation rules for deadlines
  505. type DeadlineForm struct {
  506. DateString string `form:"date" binding:"Required;Size(10)"`
  507. }
  508. // Validate validates the fields
  509. func (f *DeadlineForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
  510. return validate(errs, ctx.Data, f, ctx.Locale)
  511. }