You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

setting.go 20 kB

11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package repo
  5. import (
  6. "encoding/json"
  7. "errors"
  8. "fmt"
  9. "strings"
  10. "time"
  11. "github.com/Unknwon/com"
  12. "github.com/gogits/gogs/models"
  13. "github.com/gogits/gogs/modules/auth"
  14. "github.com/gogits/gogs/modules/base"
  15. "github.com/gogits/gogs/modules/git"
  16. "github.com/gogits/gogs/modules/log"
  17. "github.com/gogits/gogs/modules/mailer"
  18. "github.com/gogits/gogs/modules/middleware"
  19. "github.com/gogits/gogs/modules/setting"
  20. )
  21. const (
  22. SETTINGS_OPTIONS base.TplName = "repo/settings/options"
  23. COLLABORATION base.TplName = "repo/settings/collaboration"
  24. HOOKS base.TplName = "repo/settings/hooks"
  25. HOOK_NEW base.TplName = "repo/settings/hook_new"
  26. ORG_HOOK_NEW base.TplName = "org/settings/hook_new"
  27. GITHOOKS base.TplName = "repo/settings/githooks"
  28. GITHOOK_EDIT base.TplName = "repo/settings/githook_edit"
  29. DEPLOY_KEYS base.TplName = "repo/settings/deploy_keys"
  30. )
  31. func Settings(ctx *middleware.Context) {
  32. ctx.Data["Title"] = ctx.Tr("repo.settings")
  33. ctx.Data["PageIsSettingsOptions"] = true
  34. ctx.HTML(200, SETTINGS_OPTIONS)
  35. }
  36. func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) {
  37. ctx.Data["Title"] = ctx.Tr("repo.settings")
  38. ctx.Data["PageIsSettingsOptions"] = true
  39. repo := ctx.Repo.Repository
  40. switch ctx.Query("action") {
  41. case "update":
  42. if ctx.HasError() {
  43. ctx.HTML(200, SETTINGS_OPTIONS)
  44. return
  45. }
  46. isNameChanged := false
  47. oldRepoName := repo.Name
  48. newRepoName := form.RepoName
  49. // Check if repository name has been changed.
  50. if repo.LowerName != strings.ToLower(newRepoName) {
  51. isNameChanged = true
  52. if err := models.ChangeRepositoryName(ctx.Repo.Owner, repo.Name, newRepoName); err != nil {
  53. ctx.Data["Err_RepoName"] = true
  54. switch {
  55. case models.IsErrRepoAlreadyExist(err):
  56. ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), SETTINGS_OPTIONS, &form)
  57. case models.IsErrNameReserved(err):
  58. ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), SETTINGS_OPTIONS, &form)
  59. case models.IsErrNamePatternNotAllowed(err):
  60. ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), SETTINGS_OPTIONS, &form)
  61. default:
  62. ctx.Handle(500, "ChangeRepositoryName", err)
  63. }
  64. return
  65. }
  66. log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newRepoName)
  67. }
  68. // In case it's just a case change.
  69. repo.Name = newRepoName
  70. repo.LowerName = strings.ToLower(newRepoName)
  71. if ctx.Repo.GitRepo.IsBranchExist(form.Branch) &&
  72. repo.DefaultBranch != form.Branch {
  73. repo.DefaultBranch = form.Branch
  74. if err := ctx.Repo.GitRepo.SetDefaultBranch(form.Branch); err != nil {
  75. if !git.IsErrUnsupportedVersion(err) {
  76. ctx.Handle(500, "SetDefaultBranch", err)
  77. return
  78. }
  79. }
  80. }
  81. repo.Description = form.Description
  82. repo.Website = form.Website
  83. // Visibility of forked repository is forced sync with base repository.
  84. if repo.IsFork {
  85. form.Private = repo.BaseRepo.IsPrivate
  86. }
  87. visibilityChanged := repo.IsPrivate != form.Private
  88. repo.IsPrivate = form.Private
  89. if err := models.UpdateRepository(repo, visibilityChanged); err != nil {
  90. ctx.Handle(500, "UpdateRepository", err)
  91. return
  92. }
  93. log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
  94. if isNameChanged {
  95. if err := models.RenameRepoAction(ctx.User, oldRepoName, repo); err != nil {
  96. log.Error(4, "RenameRepoAction: %v", err)
  97. }
  98. }
  99. if repo.IsMirror {
  100. if form.Interval > 0 {
  101. ctx.Repo.Mirror.Interval = form.Interval
  102. ctx.Repo.Mirror.NextUpdate = time.Now().Add(time.Duration(form.Interval) * time.Hour)
  103. if err := models.UpdateMirror(ctx.Repo.Mirror); err != nil {
  104. log.Error(4, "UpdateMirror: %v", err)
  105. }
  106. }
  107. }
  108. ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
  109. ctx.Redirect(ctx.Repo.RepoLink + "/settings")
  110. case "advanced":
  111. repo.EnableWiki = form.EnableWiki
  112. repo.EnableIssues = form.EnableIssues
  113. repo.EnableExternalTracker = form.EnableExternalTracker
  114. repo.ExternalTrackerFormat = form.TrackerURLFormat
  115. repo.EnablePulls = form.EnablePulls
  116. if err := models.UpdateRepository(repo, false); err != nil {
  117. ctx.Handle(500, "UpdateRepository", err)
  118. return
  119. }
  120. log.Trace("Repository advanced settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
  121. ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
  122. ctx.Redirect(ctx.Repo.RepoLink + "/settings")
  123. case "transfer":
  124. if repo.Name != form.RepoName {
  125. ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)
  126. return
  127. }
  128. if ctx.Repo.Owner.IsOrganization() {
  129. if !ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) {
  130. ctx.Error(404)
  131. return
  132. }
  133. }
  134. newOwner := ctx.Query("new_owner_name")
  135. isExist, err := models.IsUserExist(0, newOwner)
  136. if err != nil {
  137. ctx.Handle(500, "IsUserExist", err)
  138. return
  139. } else if !isExist {
  140. ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), SETTINGS_OPTIONS, nil)
  141. return
  142. }
  143. if err = models.TransferOwnership(ctx.User, newOwner, repo); err != nil {
  144. if models.IsErrRepoAlreadyExist(err) {
  145. ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), SETTINGS_OPTIONS, nil)
  146. } else {
  147. ctx.Handle(500, "TransferOwnership", err)
  148. }
  149. return
  150. }
  151. log.Trace("Repository transfered: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner)
  152. ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed"))
  153. ctx.Redirect(setting.AppSubUrl + "/" + newOwner + "/" + repo.Name)
  154. case "delete":
  155. if repo.Name != form.RepoName {
  156. ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)
  157. return
  158. }
  159. if ctx.Repo.Owner.IsOrganization() {
  160. if !ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) {
  161. ctx.Error(404)
  162. return
  163. }
  164. }
  165. if err := models.DeleteRepository(ctx.Repo.Owner.Id, repo.ID); err != nil {
  166. ctx.Handle(500, "DeleteRepository", err)
  167. return
  168. }
  169. log.Trace("Repository deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name)
  170. ctx.Redirect(ctx.Repo.Owner.DashboardLink())
  171. }
  172. }
  173. func Collaboration(ctx *middleware.Context) {
  174. ctx.Data["Title"] = ctx.Tr("repo.settings")
  175. ctx.Data["PageIsSettingsCollaboration"] = true
  176. if ctx.Req.Method == "POST" {
  177. name := strings.ToLower(ctx.Query("collaborator"))
  178. if len(name) == 0 || ctx.Repo.Owner.LowerName == name {
  179. ctx.Redirect(setting.AppSubUrl + ctx.Req.URL.Path)
  180. return
  181. }
  182. u, err := models.GetUserByName(name)
  183. if err != nil {
  184. if models.IsErrUserNotExist(err) {
  185. ctx.Flash.Error(ctx.Tr("form.user_not_exist"))
  186. ctx.Redirect(setting.AppSubUrl + ctx.Req.URL.Path)
  187. } else {
  188. ctx.Handle(500, "GetUserByName", err)
  189. }
  190. return
  191. }
  192. // Check if user is organization member.
  193. if ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOrgMember(u.Id) {
  194. ctx.Flash.Info(ctx.Tr("repo.settings.user_is_org_member"))
  195. ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
  196. return
  197. }
  198. if err = ctx.Repo.Repository.AddCollaborator(u); err != nil {
  199. ctx.Handle(500, "AddCollaborator", err)
  200. return
  201. }
  202. if setting.Service.EnableNotifyMail {
  203. if err = mailer.SendCollaboratorMail(ctx.Render, u, ctx.User, ctx.Repo.Repository); err != nil {
  204. ctx.Handle(500, "SendCollaboratorMail", err)
  205. return
  206. }
  207. }
  208. ctx.Flash.Success(ctx.Tr("repo.settings.add_collaborator_success"))
  209. ctx.Redirect(setting.AppSubUrl + ctx.Req.URL.Path)
  210. return
  211. }
  212. // Delete collaborator.
  213. remove := strings.ToLower(ctx.Query("remove"))
  214. if len(remove) > 0 && remove != ctx.Repo.Owner.LowerName {
  215. u, err := models.GetUserByName(remove)
  216. if err != nil {
  217. ctx.Handle(500, "GetUserByName", err)
  218. return
  219. }
  220. if err := ctx.Repo.Repository.DeleteCollaborator(u); err != nil {
  221. ctx.Handle(500, "DeleteCollaborator", err)
  222. return
  223. }
  224. ctx.Flash.Success(ctx.Tr("repo.settings.remove_collaborator_success"))
  225. ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
  226. return
  227. }
  228. users, err := ctx.Repo.Repository.GetCollaborators()
  229. if err != nil {
  230. ctx.Handle(500, "GetCollaborators", err)
  231. return
  232. }
  233. ctx.Data["Collaborators"] = users
  234. ctx.HTML(200, COLLABORATION)
  235. }
  236. func Webhooks(ctx *middleware.Context) {
  237. ctx.Data["Title"] = ctx.Tr("repo.settings.hooks")
  238. ctx.Data["PageIsSettingsHooks"] = true
  239. ctx.Data["BaseLink"] = ctx.Repo.RepoLink
  240. ctx.Data["Description"] = ctx.Tr("repo.settings.hooks_desc", "https://github.com/gogits/go-gogs-client/wiki/Repositories-Webhooks")
  241. ws, err := models.GetWebhooksByRepoID(ctx.Repo.Repository.ID)
  242. if err != nil {
  243. ctx.Handle(500, "GetWebhooksByRepoID", err)
  244. return
  245. }
  246. ctx.Data["Webhooks"] = ws
  247. ctx.HTML(200, HOOKS)
  248. }
  249. type OrgRepoCtx struct {
  250. OrgID int64
  251. RepoID int64
  252. Link string
  253. NewTemplate base.TplName
  254. }
  255. // getOrgRepoCtx determines whether this is a repo context or organization context.
  256. func getOrgRepoCtx(ctx *middleware.Context) (*OrgRepoCtx, error) {
  257. if len(ctx.Repo.RepoLink) > 0 {
  258. return &OrgRepoCtx{
  259. RepoID: ctx.Repo.Repository.ID,
  260. Link: ctx.Repo.RepoLink,
  261. NewTemplate: HOOK_NEW,
  262. }, nil
  263. }
  264. if len(ctx.Org.OrgLink) > 0 {
  265. return &OrgRepoCtx{
  266. OrgID: ctx.Org.Organization.Id,
  267. Link: ctx.Org.OrgLink,
  268. NewTemplate: ORG_HOOK_NEW,
  269. }, nil
  270. }
  271. return nil, errors.New("Unable to set OrgRepo context")
  272. }
  273. func checkHookType(ctx *middleware.Context) string {
  274. hookType := strings.ToLower(ctx.Params(":type"))
  275. if !com.IsSliceContainsStr(setting.Webhook.Types, hookType) {
  276. ctx.Handle(404, "checkHookType", nil)
  277. return ""
  278. }
  279. return hookType
  280. }
  281. func WebhooksNew(ctx *middleware.Context) {
  282. ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
  283. ctx.Data["PageIsSettingsHooks"] = true
  284. ctx.Data["PageIsSettingsHooksNew"] = true
  285. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  286. orCtx, err := getOrgRepoCtx(ctx)
  287. if err != nil {
  288. ctx.Handle(500, "getOrgRepoCtx", err)
  289. return
  290. }
  291. ctx.Data["HookType"] = checkHookType(ctx)
  292. if ctx.Written() {
  293. return
  294. }
  295. ctx.Data["BaseLink"] = orCtx.Link
  296. ctx.HTML(200, orCtx.NewTemplate)
  297. }
  298. func ParseHookEvent(form auth.WebhookForm) *models.HookEvent {
  299. return &models.HookEvent{
  300. PushOnly: form.PushOnly(),
  301. SendEverything: form.SendEverything(),
  302. ChooseEvents: form.ChooseEvents(),
  303. HookEvents: models.HookEvents{
  304. Create: form.Create,
  305. Push: form.Push,
  306. },
  307. }
  308. }
  309. func WebHooksNewPost(ctx *middleware.Context, form auth.NewWebhookForm) {
  310. ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
  311. ctx.Data["PageIsSettingsHooks"] = true
  312. ctx.Data["PageIsSettingsHooksNew"] = true
  313. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  314. ctx.Data["HookType"] = "gogs"
  315. orCtx, err := getOrgRepoCtx(ctx)
  316. if err != nil {
  317. ctx.Handle(500, "getOrgRepoCtx", err)
  318. return
  319. }
  320. ctx.Data["BaseLink"] = orCtx.Link
  321. if ctx.HasError() {
  322. ctx.HTML(200, orCtx.NewTemplate)
  323. return
  324. }
  325. contentType := models.JSON
  326. if models.HookContentType(form.ContentType) == models.FORM {
  327. contentType = models.FORM
  328. }
  329. w := &models.Webhook{
  330. RepoID: orCtx.RepoID,
  331. URL: form.PayloadURL,
  332. ContentType: contentType,
  333. Secret: form.Secret,
  334. HookEvent: ParseHookEvent(form.WebhookForm),
  335. IsActive: form.Active,
  336. HookTaskType: models.GOGS,
  337. OrgID: orCtx.OrgID,
  338. }
  339. if err := w.UpdateEvent(); err != nil {
  340. ctx.Handle(500, "UpdateEvent", err)
  341. return
  342. } else if err := models.CreateWebhook(w); err != nil {
  343. ctx.Handle(500, "CreateWebhook", err)
  344. return
  345. }
  346. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  347. ctx.Redirect(orCtx.Link + "/settings/hooks")
  348. }
  349. func SlackHooksNewPost(ctx *middleware.Context, form auth.NewSlackHookForm) {
  350. ctx.Data["Title"] = ctx.Tr("repo.settings")
  351. ctx.Data["PageIsSettingsHooks"] = true
  352. ctx.Data["PageIsSettingsHooksNew"] = true
  353. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  354. orCtx, err := getOrgRepoCtx(ctx)
  355. if err != nil {
  356. ctx.Handle(500, "getOrgRepoCtx", err)
  357. return
  358. }
  359. if ctx.HasError() {
  360. ctx.HTML(200, orCtx.NewTemplate)
  361. return
  362. }
  363. meta, err := json.Marshal(&models.SlackMeta{
  364. Channel: form.Channel,
  365. Username: form.Username,
  366. IconURL: form.IconURL,
  367. Color: form.Color,
  368. })
  369. if err != nil {
  370. ctx.Handle(500, "Marshal", err)
  371. return
  372. }
  373. w := &models.Webhook{
  374. RepoID: orCtx.RepoID,
  375. URL: form.PayloadURL,
  376. ContentType: models.JSON,
  377. HookEvent: ParseHookEvent(form.WebhookForm),
  378. IsActive: form.Active,
  379. HookTaskType: models.SLACK,
  380. Meta: string(meta),
  381. OrgID: orCtx.OrgID,
  382. }
  383. if err := w.UpdateEvent(); err != nil {
  384. ctx.Handle(500, "UpdateEvent", err)
  385. return
  386. } else if err := models.CreateWebhook(w); err != nil {
  387. ctx.Handle(500, "CreateWebhook", err)
  388. return
  389. }
  390. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  391. ctx.Redirect(orCtx.Link + "/settings/hooks")
  392. }
  393. func checkWebhook(ctx *middleware.Context) (*OrgRepoCtx, *models.Webhook) {
  394. ctx.Data["RequireHighlightJS"] = true
  395. orCtx, err := getOrgRepoCtx(ctx)
  396. if err != nil {
  397. ctx.Handle(500, "getOrgRepoCtx", err)
  398. return nil, nil
  399. }
  400. ctx.Data["BaseLink"] = orCtx.Link
  401. w, err := models.GetWebhookByID(ctx.ParamsInt64(":id"))
  402. if err != nil {
  403. if models.IsErrWebhookNotExist(err) {
  404. ctx.Handle(404, "GetWebhookByID", nil)
  405. } else {
  406. ctx.Handle(500, "GetWebhookByID", err)
  407. }
  408. return nil, nil
  409. }
  410. switch w.HookTaskType {
  411. case models.SLACK:
  412. ctx.Data["SlackHook"] = w.GetSlackHook()
  413. ctx.Data["HookType"] = "slack"
  414. default:
  415. ctx.Data["HookType"] = "gogs"
  416. }
  417. ctx.Data["History"], err = w.History(1)
  418. if err != nil {
  419. ctx.Handle(500, "History", err)
  420. }
  421. return orCtx, w
  422. }
  423. func WebHooksEdit(ctx *middleware.Context) {
  424. ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook")
  425. ctx.Data["PageIsSettingsHooks"] = true
  426. ctx.Data["PageIsSettingsHooksEdit"] = true
  427. orCtx, w := checkWebhook(ctx)
  428. if ctx.Written() {
  429. return
  430. }
  431. ctx.Data["Webhook"] = w
  432. ctx.HTML(200, orCtx.NewTemplate)
  433. }
  434. func WebHooksEditPost(ctx *middleware.Context, form auth.NewWebhookForm) {
  435. ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook")
  436. ctx.Data["PageIsSettingsHooks"] = true
  437. ctx.Data["PageIsSettingsHooksEdit"] = true
  438. orCtx, w := checkWebhook(ctx)
  439. if ctx.Written() {
  440. return
  441. }
  442. ctx.Data["Webhook"] = w
  443. if ctx.HasError() {
  444. ctx.HTML(200, orCtx.NewTemplate)
  445. return
  446. }
  447. contentType := models.JSON
  448. if models.HookContentType(form.ContentType) == models.FORM {
  449. contentType = models.FORM
  450. }
  451. w.URL = form.PayloadURL
  452. w.ContentType = contentType
  453. w.Secret = form.Secret
  454. w.HookEvent = ParseHookEvent(form.WebhookForm)
  455. w.IsActive = form.Active
  456. if err := w.UpdateEvent(); err != nil {
  457. ctx.Handle(500, "UpdateEvent", err)
  458. return
  459. } else if err := models.UpdateWebhook(w); err != nil {
  460. ctx.Handle(500, "WebHooksEditPost", err)
  461. return
  462. }
  463. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  464. ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID))
  465. }
  466. func SlackHooksEditPost(ctx *middleware.Context, form auth.NewSlackHookForm) {
  467. ctx.Data["Title"] = ctx.Tr("repo.settings")
  468. ctx.Data["PageIsSettingsHooks"] = true
  469. ctx.Data["PageIsSettingsHooksEdit"] = true
  470. orCtx, w := checkWebhook(ctx)
  471. if ctx.Written() {
  472. return
  473. }
  474. ctx.Data["Webhook"] = w
  475. if ctx.HasError() {
  476. ctx.HTML(200, orCtx.NewTemplate)
  477. return
  478. }
  479. meta, err := json.Marshal(&models.SlackMeta{
  480. Channel: form.Channel,
  481. Username: form.Username,
  482. IconURL: form.IconURL,
  483. Color: form.Color,
  484. })
  485. if err != nil {
  486. ctx.Handle(500, "Marshal", err)
  487. return
  488. }
  489. w.URL = form.PayloadURL
  490. w.Meta = string(meta)
  491. w.HookEvent = ParseHookEvent(form.WebhookForm)
  492. w.IsActive = form.Active
  493. if err := w.UpdateEvent(); err != nil {
  494. ctx.Handle(500, "UpdateEvent", err)
  495. return
  496. } else if err := models.UpdateWebhook(w); err != nil {
  497. ctx.Handle(500, "UpdateWebhook", err)
  498. return
  499. }
  500. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  501. ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID))
  502. }
  503. func DeleteWebhook(ctx *middleware.Context) {
  504. if err := models.DeleteWebhook(ctx.QueryInt64("id")); err != nil {
  505. ctx.Flash.Error("DeleteWebhook: " + err.Error())
  506. } else {
  507. ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success"))
  508. }
  509. ctx.JSON(200, map[string]interface{}{
  510. "redirect": ctx.Repo.RepoLink + "/settings/hooks",
  511. })
  512. }
  513. func parseOwnerAndRepo(ctx *middleware.Context) (*models.User, *models.Repository) {
  514. owner, err := models.GetUserByName(ctx.Params(":username"))
  515. if err != nil {
  516. if models.IsErrUserNotExist(err) {
  517. ctx.Handle(404, "GetUserByName", err)
  518. } else {
  519. ctx.Handle(500, "GetUserByName", err)
  520. }
  521. return nil, nil
  522. }
  523. repo, err := models.GetRepositoryByName(owner.Id, ctx.Params(":reponame"))
  524. if err != nil {
  525. if models.IsErrRepoNotExist(err) {
  526. ctx.Handle(404, "GetRepositoryByName", err)
  527. } else {
  528. ctx.Handle(500, "GetRepositoryByName", err)
  529. }
  530. return nil, nil
  531. }
  532. return owner, repo
  533. }
  534. func GitHooks(ctx *middleware.Context) {
  535. ctx.Data["Title"] = ctx.Tr("repo.settings.githooks")
  536. ctx.Data["PageIsSettingsGitHooks"] = true
  537. hooks, err := ctx.Repo.GitRepo.Hooks()
  538. if err != nil {
  539. ctx.Handle(500, "Hooks", err)
  540. return
  541. }
  542. ctx.Data["Hooks"] = hooks
  543. ctx.HTML(200, GITHOOKS)
  544. }
  545. func GitHooksEdit(ctx *middleware.Context) {
  546. ctx.Data["Title"] = ctx.Tr("repo.settings.githooks")
  547. ctx.Data["PageIsSettingsGitHooks"] = true
  548. name := ctx.Params(":name")
  549. hook, err := ctx.Repo.GitRepo.GetHook(name)
  550. if err != nil {
  551. if err == git.ErrNotValidHook {
  552. ctx.Handle(404, "GetHook", err)
  553. } else {
  554. ctx.Handle(500, "GetHook", err)
  555. }
  556. return
  557. }
  558. ctx.Data["Hook"] = hook
  559. ctx.HTML(200, GITHOOK_EDIT)
  560. }
  561. func GitHooksEditPost(ctx *middleware.Context) {
  562. name := ctx.Params(":name")
  563. hook, err := ctx.Repo.GitRepo.GetHook(name)
  564. if err != nil {
  565. if err == git.ErrNotValidHook {
  566. ctx.Handle(404, "GetHook", err)
  567. } else {
  568. ctx.Handle(500, "GetHook", err)
  569. }
  570. return
  571. }
  572. hook.Content = ctx.Query("content")
  573. if err = hook.Update(); err != nil {
  574. ctx.Handle(500, "hook.Update", err)
  575. return
  576. }
  577. ctx.Redirect(ctx.Repo.RepoLink + "/settings/hooks/git")
  578. }
  579. func DeployKeys(ctx *middleware.Context) {
  580. ctx.Data["Title"] = ctx.Tr("repo.settings.deploy_keys")
  581. ctx.Data["PageIsSettingsKeys"] = true
  582. keys, err := models.ListDeployKeys(ctx.Repo.Repository.ID)
  583. if err != nil {
  584. ctx.Handle(500, "ListDeployKeys", err)
  585. return
  586. }
  587. ctx.Data["Deploykeys"] = keys
  588. ctx.HTML(200, DEPLOY_KEYS)
  589. }
  590. func DeployKeysPost(ctx *middleware.Context, form auth.AddSSHKeyForm) {
  591. ctx.Data["Title"] = ctx.Tr("repo.settings.deploy_keys")
  592. ctx.Data["PageIsSettingsKeys"] = true
  593. keys, err := models.ListDeployKeys(ctx.Repo.Repository.ID)
  594. if err != nil {
  595. ctx.Handle(500, "ListDeployKeys", err)
  596. return
  597. }
  598. ctx.Data["Deploykeys"] = keys
  599. if ctx.HasError() {
  600. ctx.HTML(200, DEPLOY_KEYS)
  601. return
  602. }
  603. content, err := models.CheckPublicKeyString(form.Content)
  604. if err != nil {
  605. if models.IsErrKeyUnableVerify(err) {
  606. ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
  607. } else {
  608. ctx.Data["HasError"] = true
  609. ctx.Data["Err_Content"] = true
  610. ctx.Flash.Error(ctx.Tr("form.invalid_ssh_key", err.Error()))
  611. ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys")
  612. return
  613. }
  614. }
  615. key, err := models.AddDeployKey(ctx.Repo.Repository.ID, form.Title, content)
  616. if err != nil {
  617. ctx.Data["HasError"] = true
  618. switch {
  619. case models.IsErrKeyAlreadyExist(err):
  620. ctx.Data["Err_Content"] = true
  621. ctx.RenderWithErr(ctx.Tr("repo.settings.key_been_used"), DEPLOY_KEYS, &form)
  622. case models.IsErrKeyNameAlreadyUsed(err):
  623. ctx.Data["Err_Title"] = true
  624. ctx.RenderWithErr(ctx.Tr("repo.settings.key_name_used"), DEPLOY_KEYS, &form)
  625. default:
  626. ctx.Handle(500, "AddDeployKey", err)
  627. }
  628. return
  629. }
  630. log.Trace("Deploy key added: %d", ctx.Repo.Repository.ID)
  631. ctx.Flash.Success(ctx.Tr("repo.settings.add_key_success", key.Name))
  632. ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys")
  633. }
  634. func DeleteDeployKey(ctx *middleware.Context) {
  635. if err := models.DeleteDeployKey(ctx.User, ctx.QueryInt64("id")); err != nil {
  636. ctx.Flash.Error("DeleteDeployKey: " + err.Error())
  637. } else {
  638. ctx.Flash.Success(ctx.Tr("repo.settings.deploy_key_deletion_success"))
  639. }
  640. ctx.JSON(200, map[string]interface{}{
  641. "redirect": ctx.Repo.RepoLink + "/settings/keys",
  642. })
  643. }