setting.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. // Copyright 2015 The Gogs Authors. All rights reserved.
  2. // Copyright 2018 Gitote. All rights reserved.
  3. //
  4. // This source code is licensed under the MIT license found in the
  5. // LICENSE file in the root directory of this source tree.
  6. package repo
  7. import (
  8. "fmt"
  9. "gitote/gitote/models"
  10. "gitote/gitote/models/errors"
  11. "gitote/gitote/pkg/context"
  12. "gitote/gitote/pkg/form"
  13. "gitote/gitote/pkg/mailer"
  14. "gitote/gitote/pkg/setting"
  15. "gitote/gitote/pkg/tool"
  16. "io/ioutil"
  17. "strings"
  18. "time"
  19. "github.com/Unknwon/com"
  20. raven "github.com/getsentry/raven-go"
  21. "gitlab.com/gitote/git-module"
  22. log "gopkg.in/clog.v1"
  23. )
  24. const (
  25. SETTINGS_OPTIONS = "repo/settings/options"
  26. SETTINGS_REPO_AVATAR = "repo/settings/avatar"
  27. SETTINGS_COLLABORATION = "repo/settings/collaboration"
  28. SETTINGS_BRANCHES = "repo/settings/branches"
  29. SETTINGS_PROTECTED_BRANCH = "repo/settings/protected_branch"
  30. SETTINGS_GITHOOKS = "repo/settings/githooks"
  31. SETTINGS_GITHOOK_EDIT = "repo/settings/githook_edit"
  32. SETTINGS_DEPLOY_KEYS = "repo/settings/deploy_keys"
  33. )
  34. func Settings(c *context.Context) {
  35. c.Title("repo.settings")
  36. c.PageIs("SettingsOptions")
  37. c.RequireAutosize()
  38. c.Success(SETTINGS_OPTIONS)
  39. }
  40. func SettingsPost(c *context.Context, f form.RepoSetting) {
  41. c.Title("repo.settings")
  42. c.PageIs("SettingsOptions")
  43. c.RequireAutosize()
  44. repo := c.Repo.Repository
  45. switch c.Query("action") {
  46. case "update":
  47. if c.HasError() {
  48. c.Success(SETTINGS_OPTIONS)
  49. return
  50. }
  51. isNameChanged := false
  52. oldRepoName := repo.Name
  53. newRepoName := f.RepoName
  54. // Check if repository name has been changed.
  55. if repo.LowerName != strings.ToLower(newRepoName) {
  56. isNameChanged = true
  57. if err := models.ChangeRepositoryName(c.Repo.Owner, repo.Name, newRepoName); err != nil {
  58. c.FormErr("RepoName")
  59. switch {
  60. case models.IsErrRepoAlreadyExist(err):
  61. c.RenderWithErr(c.Tr("form.repo_name_been_taken"), SETTINGS_OPTIONS, &f)
  62. case models.IsErrNameReserved(err):
  63. c.RenderWithErr(c.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), SETTINGS_OPTIONS, &f)
  64. case models.IsErrNamePatternNotAllowed(err):
  65. c.RenderWithErr(c.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), SETTINGS_OPTIONS, &f)
  66. default:
  67. c.ServerError("ChangeRepositoryName", err)
  68. }
  69. return
  70. }
  71. log.Trace("Repository name changed: %s/%s -> %s", c.Repo.Owner.Name, repo.Name, newRepoName)
  72. }
  73. // In case it's just a case change.
  74. repo.Name = newRepoName
  75. repo.LowerName = strings.ToLower(newRepoName)
  76. repo.Description = f.Description
  77. repo.Website = f.Website
  78. repo.DonateURL = f.DonateURL
  79. repo.DonateBadge = f.DonateBadge
  80. // Visibility of forked repository is forced sync with base repository.
  81. if repo.IsFork {
  82. f.Private = repo.BaseRepo.IsPrivate
  83. }
  84. visibilityChanged := repo.IsPrivate != f.Private
  85. repo.IsPrivate = f.Private
  86. if err := models.UpdateRepository(repo, visibilityChanged); err != nil {
  87. c.ServerError("UpdateRepository", err)
  88. return
  89. }
  90. log.Trace("Repository basic settings updated: %s/%s", c.Repo.Owner.Name, repo.Name)
  91. if isNameChanged {
  92. if err := models.RenameRepoAction(c.User, oldRepoName, repo); err != nil {
  93. raven.CaptureErrorAndWait(err, nil)
  94. log.Error(2, "RenameRepoAction: %v", err)
  95. }
  96. }
  97. c.Flash.Success(c.Tr("repo.settings.update_settings_success"))
  98. c.Redirect(repo.Link() + "/settings")
  99. case "mirror":
  100. if !repo.IsMirror {
  101. c.NotFound()
  102. return
  103. }
  104. if f.Interval > 0 {
  105. c.Repo.Mirror.EnablePrune = f.EnablePrune
  106. c.Repo.Mirror.Interval = f.Interval
  107. c.Repo.Mirror.NextSync = time.Now().Add(time.Duration(f.Interval) * time.Hour)
  108. if err := models.UpdateMirror(c.Repo.Mirror); err != nil {
  109. c.ServerError("UpdateMirror", err)
  110. return
  111. }
  112. }
  113. if err := c.Repo.Mirror.SaveAddress(f.MirrorAddress); err != nil {
  114. c.ServerError("SaveAddress", err)
  115. return
  116. }
  117. c.Flash.Success(c.Tr("repo.settings.update_settings_success"))
  118. c.Redirect(repo.Link() + "/settings")
  119. case "mirror-sync":
  120. if !repo.IsMirror {
  121. c.NotFound()
  122. return
  123. }
  124. go models.MirrorQueue.Add(repo.ID)
  125. c.Flash.Info(c.Tr("repo.settings.mirror_sync_in_progress"))
  126. c.Redirect(repo.Link() + "/settings")
  127. case "advanced":
  128. repo.EnableWiki = f.EnableWiki
  129. repo.AllowPublicWiki = f.AllowPublicWiki
  130. repo.EnableExternalWiki = f.EnableExternalWiki
  131. repo.ExternalWikiURL = f.ExternalWikiURL
  132. repo.EnableIssues = f.EnableIssues
  133. repo.AllowPublicIssues = f.AllowPublicIssues
  134. repo.EnableExternalTracker = f.EnableExternalTracker
  135. repo.ExternalTrackerURL = f.ExternalTrackerURL
  136. repo.ExternalTrackerFormat = f.TrackerURLFormat
  137. repo.ExternalTrackerStyle = f.TrackerIssueStyle
  138. repo.EnablePulls = f.EnablePulls
  139. repo.PullsIgnoreWhitespace = f.PullsIgnoreWhitespace
  140. repo.PullsAllowRebase = f.PullsAllowRebase
  141. if err := models.UpdateRepository(repo, false); err != nil {
  142. c.ServerError("UpdateRepository", err)
  143. return
  144. }
  145. log.Trace("Repository advanced settings updated: %s/%s", c.Repo.Owner.Name, repo.Name)
  146. c.Flash.Success(c.Tr("repo.settings.update_settings_success"))
  147. c.Redirect(c.Repo.RepoLink + "/settings")
  148. case "convert":
  149. if !c.Repo.IsOwner() {
  150. c.NotFound()
  151. return
  152. }
  153. if repo.Name != f.RepoName {
  154. c.RenderWithErr(c.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)
  155. return
  156. }
  157. if c.Repo.Owner.IsOrganization() {
  158. if !c.Repo.Owner.IsOwnedBy(c.User.ID) {
  159. c.NotFound()
  160. return
  161. }
  162. }
  163. if !repo.IsMirror {
  164. c.NotFound()
  165. return
  166. }
  167. repo.IsMirror = false
  168. if _, err := models.CleanUpMigrateInfo(repo); err != nil {
  169. c.ServerError("CleanUpMigrateInfo", err)
  170. return
  171. } else if err = models.DeleteMirrorByRepoID(c.Repo.Repository.ID); err != nil {
  172. c.ServerError("DeleteMirrorByRepoID", err)
  173. return
  174. }
  175. log.Trace("Repository converted from mirror to regular: %s/%s", c.Repo.Owner.Name, repo.Name)
  176. c.Flash.Success(c.Tr("repo.settings.convert_succeed"))
  177. c.Redirect(setting.AppSubURL + "/" + c.Repo.Owner.Name + "/" + repo.Name)
  178. case "transfer":
  179. if !c.Repo.IsOwner() {
  180. c.NotFound()
  181. return
  182. }
  183. if repo.Name != f.RepoName {
  184. c.RenderWithErr(c.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)
  185. return
  186. }
  187. if c.Repo.Owner.IsOrganization() && !c.User.IsAdmin {
  188. if !c.Repo.Owner.IsOwnedBy(c.User.ID) {
  189. c.NotFound()
  190. return
  191. }
  192. }
  193. newOwner := c.Query("new_owner_name")
  194. isExist, err := models.IsUserExist(0, newOwner)
  195. if err != nil {
  196. c.ServerError("IsUserExist", err)
  197. return
  198. } else if !isExist {
  199. c.RenderWithErr(c.Tr("form.enterred_invalid_owner_name"), SETTINGS_OPTIONS, nil)
  200. return
  201. }
  202. if err = models.TransferOwnership(c.User, newOwner, repo); err != nil {
  203. if models.IsErrRepoAlreadyExist(err) {
  204. c.RenderWithErr(c.Tr("repo.settings.new_owner_has_same_repo"), SETTINGS_OPTIONS, nil)
  205. } else {
  206. c.ServerError("TransferOwnership", err)
  207. }
  208. return
  209. }
  210. log.Trace("Repository transferred: %s/%s -> %s", c.Repo.Owner.Name, repo.Name, newOwner)
  211. c.Flash.Success(c.Tr("repo.settings.transfer_succeed"))
  212. c.Redirect(setting.AppSubURL + "/" + newOwner + "/" + repo.Name)
  213. case "delete":
  214. if !c.Repo.IsOwner() {
  215. c.NotFound()
  216. return
  217. }
  218. if repo.Name != f.RepoName {
  219. c.RenderWithErr(c.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)
  220. return
  221. }
  222. if c.Repo.Owner.IsOrganization() && !c.User.IsAdmin {
  223. if !c.Repo.Owner.IsOwnedBy(c.User.ID) {
  224. c.NotFound()
  225. return
  226. }
  227. }
  228. if err := models.DeleteRepository(c.Repo.Owner.ID, repo.ID); err != nil {
  229. c.ServerError("DeleteRepository", err)
  230. return
  231. }
  232. log.Trace("Repository deleted: %s/%s", c.Repo.Owner.Name, repo.Name)
  233. c.Flash.Success(c.Tr("repo.settings.deletion_success"))
  234. c.Redirect(c.Repo.Owner.DashboardLink())
  235. case "delete-wiki":
  236. if !c.Repo.IsOwner() {
  237. c.NotFound()
  238. return
  239. }
  240. if repo.Name != f.RepoName {
  241. c.RenderWithErr(c.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)
  242. return
  243. }
  244. if c.Repo.Owner.IsOrganization() && !c.User.IsAdmin {
  245. if !c.Repo.Owner.IsOwnedBy(c.User.ID) {
  246. c.NotFound()
  247. return
  248. }
  249. }
  250. repo.DeleteWiki()
  251. log.Trace("Repository wiki deleted: %s/%s", c.Repo.Owner.Name, repo.Name)
  252. repo.EnableWiki = false
  253. if err := models.UpdateRepository(repo, false); err != nil {
  254. c.ServerError("UpdateRepository", err)
  255. return
  256. }
  257. c.Flash.Success(c.Tr("repo.settings.wiki_deletion_success"))
  258. c.Redirect(c.Repo.RepoLink + "/settings")
  259. default:
  260. c.NotFound()
  261. }
  262. }
  263. func SettingsAvatar(c *context.Context) {
  264. c.Title("settings.avatar")
  265. c.PageIs("SettingsAvatar")
  266. c.Success(SETTINGS_REPO_AVATAR)
  267. }
  268. func SettingsAvatarPost(c *context.Context, f form.Avatar) {
  269. f.Source = form.AVATAR_LOCAL
  270. if err := UpdateAvatarSetting(c, f, c.Repo.Repository); err != nil {
  271. c.Flash.Error(err.Error())
  272. } else {
  273. c.Flash.Success(c.Tr("settings.update_avatar_success"))
  274. }
  275. c.SubURLRedirect(c.Repo.RepoLink + "/settings")
  276. }
  277. func SettingsDeleteAvatar(c *context.Context) {
  278. if err := c.Repo.Repository.DeleteAvatar(); err != nil {
  279. c.Flash.Error(fmt.Sprintf("Failed to delete avatar: %v", err))
  280. }
  281. c.SubURLRedirect(c.Repo.RepoLink + "/settings")
  282. }
  283. // FIXME: limit upload size
  284. func UpdateAvatarSetting(c *context.Context, f form.Avatar, ctxRepo *models.Repository) error {
  285. ctxRepo.UseCustomAvatar = true
  286. if f.Avatar != nil {
  287. r, err := f.Avatar.Open()
  288. if err != nil {
  289. return fmt.Errorf("open avatar reader: %v", err)
  290. }
  291. defer r.Close()
  292. data, err := ioutil.ReadAll(r)
  293. if err != nil {
  294. return fmt.Errorf("read avatar content: %v", err)
  295. }
  296. if !tool.IsImageFile(data) {
  297. return errors.New(c.Tr("settings.uploaded_avatar_not_a_image"))
  298. }
  299. if err = ctxRepo.UploadAvatar(data); err != nil {
  300. return fmt.Errorf("upload avatar: %v", err)
  301. }
  302. } else {
  303. // No avatar is uploaded and reset setting back.
  304. if !com.IsFile(ctxRepo.CustomAvatarPath()) {
  305. ctxRepo.UseCustomAvatar = false
  306. }
  307. }
  308. if err := models.UpdateRepository(ctxRepo, false); err != nil {
  309. return fmt.Errorf("update repository: %v", err)
  310. }
  311. return nil
  312. }
  313. func SettingsCollaboration(c *context.Context) {
  314. c.Data["Title"] = c.Tr("repo.settings")
  315. c.Data["PageIsSettingsCollaboration"] = true
  316. users, err := c.Repo.Repository.GetCollaborators()
  317. if err != nil {
  318. c.Handle(500, "GetCollaborators", err)
  319. return
  320. }
  321. c.Data["Collaborators"] = users
  322. c.HTML(200, SETTINGS_COLLABORATION)
  323. }
  324. func SettingsCollaborationPost(c *context.Context) {
  325. name := strings.ToLower(c.Query("collaborator"))
  326. if len(name) == 0 || c.Repo.Owner.LowerName == name {
  327. c.Redirect(setting.AppSubURL + c.Req.URL.Path)
  328. return
  329. }
  330. u, err := models.GetUserByName(name)
  331. if err != nil {
  332. if errors.IsUserNotExist(err) {
  333. c.Flash.Error(c.Tr("form.user_not_exist"))
  334. c.Redirect(setting.AppSubURL + c.Req.URL.Path)
  335. } else {
  336. c.Handle(500, "GetUserByName", err)
  337. }
  338. return
  339. }
  340. // Organization is not allowed to be added as a collaborator
  341. if u.IsOrganization() {
  342. c.Flash.Error(c.Tr("repo.settings.org_not_allowed_to_be_collaborator"))
  343. c.Redirect(setting.AppSubURL + c.Req.URL.Path)
  344. return
  345. }
  346. if err = c.Repo.Repository.AddCollaborator(u); err != nil {
  347. c.Handle(500, "AddCollaborator", err)
  348. return
  349. }
  350. if setting.Service.EnableNotifyMail {
  351. mailer.SendCollaboratorMail(models.NewMailerUser(u), models.NewMailerUser(c.User), models.NewMailerRepo(c.Repo.Repository))
  352. }
  353. c.Flash.Success(c.Tr("repo.settings.add_collaborator_success"))
  354. c.Redirect(setting.AppSubURL + c.Req.URL.Path)
  355. }
  356. func ChangeCollaborationAccessMode(c *context.Context) {
  357. if err := c.Repo.Repository.ChangeCollaborationAccessMode(
  358. c.QueryInt64("uid"),
  359. models.AccessMode(c.QueryInt("mode"))); err != nil {
  360. raven.CaptureErrorAndWait(err, nil)
  361. log.Error(2, "ChangeCollaborationAccessMode: %v", err)
  362. return
  363. }
  364. c.Status(204)
  365. }
  366. func DeleteCollaboration(c *context.Context) {
  367. if err := c.Repo.Repository.DeleteCollaboration(c.QueryInt64("id")); err != nil {
  368. c.Flash.Error("DeleteCollaboration: " + err.Error())
  369. } else {
  370. c.Flash.Success(c.Tr("repo.settings.remove_collaborator_success"))
  371. }
  372. c.JSON(200, map[string]interface{}{
  373. "redirect": c.Repo.RepoLink + "/settings/collaboration",
  374. })
  375. }
  376. func SettingsBranches(c *context.Context) {
  377. c.Data["Title"] = c.Tr("repo.settings.branches")
  378. c.Data["PageIsSettingsBranches"] = true
  379. if c.Repo.Repository.IsBare {
  380. c.Flash.Info(c.Tr("repo.settings.branches_bare"), true)
  381. c.HTML(200, SETTINGS_BRANCHES)
  382. return
  383. }
  384. protectBranches, err := models.GetProtectBranchesByRepoID(c.Repo.Repository.ID)
  385. if err != nil {
  386. c.Handle(500, "GetProtectBranchesByRepoID", err)
  387. return
  388. }
  389. // Filter out deleted branches
  390. branches := make([]string, 0, len(protectBranches))
  391. for i := range protectBranches {
  392. if c.Repo.GitRepo.IsBranchExist(protectBranches[i].Name) {
  393. branches = append(branches, protectBranches[i].Name)
  394. }
  395. }
  396. c.Data["ProtectBranches"] = branches
  397. c.HTML(200, SETTINGS_BRANCHES)
  398. }
  399. func UpdateDefaultBranch(c *context.Context) {
  400. branch := c.Query("branch")
  401. if c.Repo.GitRepo.IsBranchExist(branch) &&
  402. c.Repo.Repository.DefaultBranch != branch {
  403. c.Repo.Repository.DefaultBranch = branch
  404. if err := c.Repo.GitRepo.SetDefaultBranch(branch); err != nil {
  405. if !git.IsErrUnsupportedVersion(err) {
  406. c.Handle(500, "SetDefaultBranch", err)
  407. return
  408. }
  409. c.Flash.Warning(c.Tr("repo.settings.update_default_branch_unsupported"))
  410. c.Redirect(c.Repo.RepoLink + "/settings/branches")
  411. return
  412. }
  413. }
  414. if err := models.UpdateRepository(c.Repo.Repository, false); err != nil {
  415. c.Handle(500, "UpdateRepository", err)
  416. return
  417. }
  418. c.Flash.Success(c.Tr("repo.settings.update_default_branch_success"))
  419. c.Redirect(c.Repo.RepoLink + "/settings/branches")
  420. }
  421. func SettingsProtectedBranch(c *context.Context) {
  422. branch := c.Params("*")
  423. if !c.Repo.GitRepo.IsBranchExist(branch) {
  424. c.NotFound()
  425. return
  426. }
  427. c.Data["Title"] = c.Tr("repo.settings.protected_branches") + " - " + branch
  428. c.Data["PageIsSettingsBranches"] = true
  429. protectBranch, err := models.GetProtectBranchOfRepoByName(c.Repo.Repository.ID, branch)
  430. if err != nil {
  431. if !errors.IsErrBranchNotExist(err) {
  432. c.Handle(500, "GetProtectBranchOfRepoByName", err)
  433. return
  434. }
  435. // No options found, create defaults.
  436. protectBranch = &models.ProtectBranch{
  437. Name: branch,
  438. }
  439. }
  440. if c.Repo.Owner.IsOrganization() {
  441. users, err := c.Repo.Repository.GetWriters()
  442. if err != nil {
  443. c.Handle(500, "Repo.Repository.GetPushers", err)
  444. return
  445. }
  446. c.Data["Users"] = users
  447. c.Data["whitelist_users"] = protectBranch.WhitelistUserIDs
  448. teams, err := c.Repo.Owner.TeamsHaveAccessToRepo(c.Repo.Repository.ID, models.ACCESS_MODE_WRITE)
  449. if err != nil {
  450. c.Handle(500, "Repo.Owner.TeamsHaveAccessToRepo", err)
  451. return
  452. }
  453. c.Data["Teams"] = teams
  454. c.Data["whitelist_teams"] = protectBranch.WhitelistTeamIDs
  455. }
  456. c.Data["Branch"] = protectBranch
  457. c.HTML(200, SETTINGS_PROTECTED_BRANCH)
  458. }
  459. func SettingsProtectedBranchPost(c *context.Context, f form.ProtectBranch) {
  460. branch := c.Params("*")
  461. if !c.Repo.GitRepo.IsBranchExist(branch) {
  462. c.NotFound()
  463. return
  464. }
  465. protectBranch, err := models.GetProtectBranchOfRepoByName(c.Repo.Repository.ID, branch)
  466. if err != nil {
  467. if !errors.IsErrBranchNotExist(err) {
  468. c.Handle(500, "GetProtectBranchOfRepoByName", err)
  469. return
  470. }
  471. // No options found, create defaults.
  472. protectBranch = &models.ProtectBranch{
  473. RepoID: c.Repo.Repository.ID,
  474. Name: branch,
  475. }
  476. }
  477. protectBranch.Protected = f.Protected
  478. protectBranch.RequirePullRequest = f.RequirePullRequest
  479. protectBranch.EnableWhitelist = f.EnableWhitelist
  480. if c.Repo.Owner.IsOrganization() {
  481. err = models.UpdateOrgProtectBranch(c.Repo.Repository, protectBranch, f.WhitelistUsers, f.WhitelistTeams)
  482. } else {
  483. err = models.UpdateProtectBranch(protectBranch)
  484. }
  485. if err != nil {
  486. c.Handle(500, "UpdateOrgProtectBranch/UpdateProtectBranch", err)
  487. return
  488. }
  489. c.Flash.Success(c.Tr("repo.settings.update_protect_branch_success"))
  490. c.Redirect(fmt.Sprintf("%s/settings/branches/%s", c.Repo.RepoLink, branch))
  491. }
  492. func SettingsGitHooks(c *context.Context) {
  493. c.Data["Title"] = c.Tr("repo.settings.githooks")
  494. c.Data["PageIsSettingsGitHooks"] = true
  495. hooks, err := c.Repo.GitRepo.Hooks()
  496. if err != nil {
  497. c.Handle(500, "Hooks", err)
  498. return
  499. }
  500. c.Data["Hooks"] = hooks
  501. c.HTML(200, SETTINGS_GITHOOKS)
  502. }
  503. func SettingsGitHooksEdit(c *context.Context) {
  504. c.Data["Title"] = c.Tr("repo.settings.githooks")
  505. c.Data["PageIsSettingsGitHooks"] = true
  506. c.Data["RequireSimpleMDE"] = true
  507. name := c.Params(":name")
  508. hook, err := c.Repo.GitRepo.GetHook(name)
  509. if err != nil {
  510. if err == git.ErrNotValidHook {
  511. c.Handle(404, "GetHook", err)
  512. } else {
  513. c.Handle(500, "GetHook", err)
  514. }
  515. return
  516. }
  517. c.Data["Hook"] = hook
  518. c.HTML(200, SETTINGS_GITHOOK_EDIT)
  519. }
  520. func SettingsGitHooksEditPost(c *context.Context) {
  521. name := c.Params(":name")
  522. hook, err := c.Repo.GitRepo.GetHook(name)
  523. if err != nil {
  524. if err == git.ErrNotValidHook {
  525. c.Handle(404, "GetHook", err)
  526. } else {
  527. c.Handle(500, "GetHook", err)
  528. }
  529. return
  530. }
  531. hook.Content = c.Query("content")
  532. if err = hook.Update(); err != nil {
  533. c.Handle(500, "hook.Update", err)
  534. return
  535. }
  536. c.Redirect(c.Data["Link"].(string))
  537. }
  538. func SettingsDeployKeys(c *context.Context) {
  539. c.Data["Title"] = c.Tr("repo.settings.deploy_keys")
  540. c.Data["PageIsSettingsKeys"] = true
  541. keys, err := models.ListDeployKeys(c.Repo.Repository.ID)
  542. if err != nil {
  543. c.Handle(500, "ListDeployKeys", err)
  544. return
  545. }
  546. c.Data["Deploykeys"] = keys
  547. c.HTML(200, SETTINGS_DEPLOY_KEYS)
  548. }
  549. func SettingsDeployKeysPost(c *context.Context, f form.AddSSHKey) {
  550. c.Data["Title"] = c.Tr("repo.settings.deploy_keys")
  551. c.Data["PageIsSettingsKeys"] = true
  552. keys, err := models.ListDeployKeys(c.Repo.Repository.ID)
  553. if err != nil {
  554. c.Handle(500, "ListDeployKeys", err)
  555. return
  556. }
  557. c.Data["Deploykeys"] = keys
  558. if c.HasError() {
  559. c.HTML(200, SETTINGS_DEPLOY_KEYS)
  560. return
  561. }
  562. content, err := models.CheckPublicKeyString(f.Content)
  563. if err != nil {
  564. if models.IsErrKeyUnableVerify(err) {
  565. c.Flash.Info(c.Tr("form.unable_verify_ssh_key"))
  566. } else {
  567. c.Data["HasError"] = true
  568. c.Data["Err_Content"] = true
  569. c.Flash.Error(c.Tr("form.invalid_ssh_key", err.Error()))
  570. c.Redirect(c.Repo.RepoLink + "/settings/keys")
  571. return
  572. }
  573. }
  574. key, err := models.AddDeployKey(c.Repo.Repository.ID, f.Title, content)
  575. if err != nil {
  576. c.Data["HasError"] = true
  577. switch {
  578. case models.IsErrKeyAlreadyExist(err):
  579. c.Data["Err_Content"] = true
  580. c.RenderWithErr(c.Tr("repo.settings.key_been_used"), SETTINGS_DEPLOY_KEYS, &f)
  581. case models.IsErrKeyNameAlreadyUsed(err):
  582. c.Data["Err_Title"] = true
  583. c.RenderWithErr(c.Tr("repo.settings.key_name_used"), SETTINGS_DEPLOY_KEYS, &f)
  584. default:
  585. c.Handle(500, "AddDeployKey", err)
  586. }
  587. return
  588. }
  589. log.Trace("Deploy key added: %d", c.Repo.Repository.ID)
  590. c.Flash.Success(c.Tr("repo.settings.add_key_success", key.Name))
  591. c.Redirect(c.Repo.RepoLink + "/settings/keys")
  592. }
  593. func DeleteDeployKey(c *context.Context) {
  594. if err := models.DeleteDeployKey(c.User, c.QueryInt64("id")); err != nil {
  595. c.Flash.Error("DeleteDeployKey: " + err.Error())
  596. } else {
  597. c.Flash.Success(c.Tr("repo.settings.deploy_key_deletion_success"))
  598. }
  599. c.JSON(200, map[string]interface{}{
  600. "redirect": c.Repo.RepoLink + "/settings/keys",
  601. })
  602. }