mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-27 07:16:17 +00:00
15c6bb500b
New Feature: * Repository struct field for IsFsckEnabled (default true of course) * Admin Settings section on repo options page, accessible only by admin users Possible Enhancements: * There's no way to force running health checks on all repos regardless of their IsFsckEnabled setting. This would be useful if there were an admin API or dashboard button to run fsck immediately. Issue: https://github.com/go-gitea/gitea/issues/1712 Signed-off-by: Allen Wild <allenwild93@gmail.com>
598 lines
18 KiB
Go
598 lines
18 KiB
Go
// 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 repo
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
"code.gitea.io/git"
|
|
|
|
"code.gitea.io/gitea/models"
|
|
"code.gitea.io/gitea/modules/auth"
|
|
"code.gitea.io/gitea/modules/base"
|
|
"code.gitea.io/gitea/modules/context"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
"code.gitea.io/gitea/modules/util"
|
|
"code.gitea.io/gitea/routers/utils"
|
|
)
|
|
|
|
const (
|
|
tplSettingsOptions base.TplName = "repo/settings/options"
|
|
tplCollaboration base.TplName = "repo/settings/collaboration"
|
|
tplBranches base.TplName = "repo/settings/branches"
|
|
tplGithooks base.TplName = "repo/settings/githooks"
|
|
tplGithookEdit base.TplName = "repo/settings/githook_edit"
|
|
tplDeployKeys base.TplName = "repo/settings/deploy_keys"
|
|
tplProtectedBranch base.TplName = "repo/settings/protected_branch"
|
|
)
|
|
|
|
// Settings show a repository's settings page
|
|
func Settings(ctx *context.Context) {
|
|
ctx.Data["Title"] = ctx.Tr("repo.settings")
|
|
ctx.Data["PageIsSettingsOptions"] = true
|
|
ctx.HTML(200, tplSettingsOptions)
|
|
}
|
|
|
|
// SettingsPost response for changes of a repository
|
|
func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
|
ctx.Data["Title"] = ctx.Tr("repo.settings")
|
|
ctx.Data["PageIsSettingsOptions"] = true
|
|
|
|
repo := ctx.Repo.Repository
|
|
|
|
switch ctx.Query("action") {
|
|
case "update":
|
|
if ctx.HasError() {
|
|
ctx.HTML(200, tplSettingsOptions)
|
|
return
|
|
}
|
|
|
|
isNameChanged := false
|
|
oldRepoName := repo.Name
|
|
newRepoName := form.RepoName
|
|
// Check if repository name has been changed.
|
|
if repo.LowerName != strings.ToLower(newRepoName) {
|
|
isNameChanged = true
|
|
if err := models.ChangeRepositoryName(ctx.Repo.Owner, repo.Name, newRepoName); err != nil {
|
|
ctx.Data["Err_RepoName"] = true
|
|
switch {
|
|
case models.IsErrRepoAlreadyExist(err):
|
|
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tplSettingsOptions, &form)
|
|
case models.IsErrNameReserved(err):
|
|
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tplSettingsOptions, &form)
|
|
case models.IsErrNamePatternNotAllowed(err):
|
|
ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tplSettingsOptions, &form)
|
|
default:
|
|
ctx.ServerError("ChangeRepositoryName", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
err := models.NewRepoRedirect(ctx.Repo.Owner.ID, repo.ID, repo.Name, newRepoName)
|
|
if err != nil {
|
|
ctx.ServerError("NewRepoRedirect", err)
|
|
return
|
|
}
|
|
|
|
log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newRepoName)
|
|
}
|
|
// In case it's just a case change.
|
|
repo.Name = newRepoName
|
|
repo.LowerName = strings.ToLower(newRepoName)
|
|
repo.Description = form.Description
|
|
repo.Website = form.Website
|
|
|
|
// Visibility of forked repository is forced sync with base repository.
|
|
if repo.IsFork {
|
|
form.Private = repo.BaseRepo.IsPrivate
|
|
}
|
|
|
|
visibilityChanged := repo.IsPrivate != form.Private
|
|
repo.IsPrivate = form.Private
|
|
if err := models.UpdateRepository(repo, visibilityChanged); err != nil {
|
|
ctx.ServerError("UpdateRepository", err)
|
|
return
|
|
}
|
|
log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
|
|
|
if isNameChanged {
|
|
if err := models.RenameRepoAction(ctx.User, oldRepoName, repo); err != nil {
|
|
log.Error(4, "RenameRepoAction: %v", err)
|
|
}
|
|
}
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
|
ctx.Redirect(repo.Link() + "/settings")
|
|
|
|
case "mirror":
|
|
if !repo.IsMirror {
|
|
ctx.NotFound("", nil)
|
|
return
|
|
}
|
|
|
|
interval, err := time.ParseDuration(form.Interval)
|
|
if err != nil || interval < setting.Mirror.MinInterval {
|
|
ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form)
|
|
} else {
|
|
ctx.Repo.Mirror.EnablePrune = form.EnablePrune
|
|
ctx.Repo.Mirror.Interval = interval
|
|
ctx.Repo.Mirror.NextUpdateUnix = util.TimeStampNow().AddDuration(interval)
|
|
if err := models.UpdateMirror(ctx.Repo.Mirror); err != nil {
|
|
ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form)
|
|
return
|
|
}
|
|
}
|
|
if err := ctx.Repo.Mirror.SaveAddress(form.MirrorAddress); err != nil {
|
|
ctx.ServerError("SaveAddress", err)
|
|
return
|
|
}
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
|
ctx.Redirect(repo.Link() + "/settings")
|
|
|
|
case "mirror-sync":
|
|
if !repo.IsMirror {
|
|
ctx.NotFound("", nil)
|
|
return
|
|
}
|
|
|
|
go models.MirrorQueue.Add(repo.ID)
|
|
ctx.Flash.Info(ctx.Tr("repo.settings.mirror_sync_in_progress"))
|
|
ctx.Redirect(repo.Link() + "/settings")
|
|
|
|
case "advanced":
|
|
var units []models.RepoUnit
|
|
|
|
for _, tp := range models.MustRepoUnits {
|
|
units = append(units, models.RepoUnit{
|
|
RepoID: repo.ID,
|
|
Type: tp,
|
|
Config: new(models.UnitConfig),
|
|
})
|
|
}
|
|
|
|
if form.EnableWiki {
|
|
if form.EnableExternalWiki {
|
|
if !strings.HasPrefix(form.ExternalWikiURL, "http://") && !strings.HasPrefix(form.ExternalWikiURL, "https://") {
|
|
ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error"))
|
|
ctx.Redirect(repo.Link() + "/settings")
|
|
return
|
|
}
|
|
|
|
units = append(units, models.RepoUnit{
|
|
RepoID: repo.ID,
|
|
Type: models.UnitTypeExternalWiki,
|
|
Config: &models.ExternalWikiConfig{
|
|
ExternalWikiURL: form.ExternalWikiURL,
|
|
},
|
|
})
|
|
} else {
|
|
units = append(units, models.RepoUnit{
|
|
RepoID: repo.ID,
|
|
Type: models.UnitTypeWiki,
|
|
Config: new(models.UnitConfig),
|
|
})
|
|
}
|
|
}
|
|
|
|
if form.EnableIssues {
|
|
if form.EnableExternalTracker {
|
|
if !strings.HasPrefix(form.ExternalTrackerURL, "http://") && !strings.HasPrefix(form.ExternalTrackerURL, "https://") {
|
|
ctx.Flash.Error(ctx.Tr("repo.settings.external_tracker_url_error"))
|
|
ctx.Redirect(repo.Link() + "/settings")
|
|
return
|
|
}
|
|
units = append(units, models.RepoUnit{
|
|
RepoID: repo.ID,
|
|
Type: models.UnitTypeExternalTracker,
|
|
Config: &models.ExternalTrackerConfig{
|
|
ExternalTrackerURL: form.ExternalTrackerURL,
|
|
ExternalTrackerFormat: form.TrackerURLFormat,
|
|
ExternalTrackerStyle: form.TrackerIssueStyle,
|
|
},
|
|
})
|
|
} else {
|
|
units = append(units, models.RepoUnit{
|
|
RepoID: repo.ID,
|
|
Type: models.UnitTypeIssues,
|
|
Config: &models.IssuesConfig{
|
|
EnableTimetracker: form.EnableTimetracker,
|
|
AllowOnlyContributorsToTrackTime: form.AllowOnlyContributorsToTrackTime,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
if form.EnablePulls {
|
|
units = append(units, models.RepoUnit{
|
|
RepoID: repo.ID,
|
|
Type: models.UnitTypePullRequests,
|
|
Config: &models.PullRequestsConfig{
|
|
IgnoreWhitespaceConflicts: form.PullsIgnoreWhitespace,
|
|
AllowMerge: form.PullsAllowMerge,
|
|
AllowRebase: form.PullsAllowRebase,
|
|
AllowSquash: form.PullsAllowSquash,
|
|
},
|
|
})
|
|
}
|
|
|
|
if err := models.UpdateRepositoryUnits(repo, units); err != nil {
|
|
ctx.ServerError("UpdateRepositoryUnits", err)
|
|
return
|
|
}
|
|
log.Trace("Repository advanced settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
|
|
case "admin":
|
|
if !ctx.User.IsAdmin {
|
|
ctx.Error(403)
|
|
return
|
|
}
|
|
|
|
if repo.IsFsckEnabled != form.EnableHealthCheck {
|
|
repo.IsFsckEnabled = form.EnableHealthCheck
|
|
if err := models.UpdateRepository(repo, false); err != nil {
|
|
ctx.ServerError("UpdateRepository", err)
|
|
return
|
|
}
|
|
log.Trace("Repository admin settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
|
}
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
|
|
case "convert":
|
|
if !ctx.Repo.IsOwner() {
|
|
ctx.Error(404)
|
|
return
|
|
}
|
|
if repo.Name != form.RepoName {
|
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
|
return
|
|
}
|
|
|
|
if !repo.IsMirror {
|
|
ctx.Error(404)
|
|
return
|
|
}
|
|
repo.IsMirror = false
|
|
|
|
if _, err := models.CleanUpMigrateInfo(repo); err != nil {
|
|
ctx.ServerError("CleanUpMigrateInfo", err)
|
|
return
|
|
} else if err = models.DeleteMirrorByRepoID(ctx.Repo.Repository.ID); err != nil {
|
|
ctx.ServerError("DeleteMirrorByRepoID", err)
|
|
return
|
|
}
|
|
log.Trace("Repository converted from mirror to regular: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.convert_succeed"))
|
|
ctx.Redirect(setting.AppSubURL + "/" + ctx.Repo.Owner.Name + "/" + repo.Name)
|
|
|
|
case "transfer":
|
|
if !ctx.Repo.IsOwner() {
|
|
ctx.Error(404)
|
|
return
|
|
}
|
|
if repo.Name != form.RepoName {
|
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
|
return
|
|
}
|
|
|
|
newOwner := ctx.Query("new_owner_name")
|
|
isExist, err := models.IsUserExist(0, newOwner)
|
|
if err != nil {
|
|
ctx.ServerError("IsUserExist", err)
|
|
return
|
|
} else if !isExist {
|
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil)
|
|
return
|
|
}
|
|
|
|
if err = models.TransferOwnership(ctx.User, newOwner, repo); err != nil {
|
|
if models.IsErrRepoAlreadyExist(err) {
|
|
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil)
|
|
} else {
|
|
ctx.ServerError("TransferOwnership", err)
|
|
}
|
|
return
|
|
}
|
|
log.Trace("Repository transferred: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner)
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed"))
|
|
ctx.Redirect(setting.AppSubURL + "/" + newOwner + "/" + repo.Name)
|
|
|
|
case "delete":
|
|
if !ctx.Repo.IsOwner() {
|
|
ctx.Error(404)
|
|
return
|
|
}
|
|
if repo.Name != form.RepoName {
|
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
|
return
|
|
}
|
|
|
|
if err := models.DeleteRepository(ctx.User, ctx.Repo.Owner.ID, repo.ID); err != nil {
|
|
ctx.ServerError("DeleteRepository", err)
|
|
return
|
|
}
|
|
log.Trace("Repository deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.deletion_success"))
|
|
ctx.Redirect(ctx.Repo.Owner.DashboardLink())
|
|
|
|
case "delete-wiki":
|
|
if !ctx.Repo.IsOwner() {
|
|
ctx.Error(404)
|
|
return
|
|
}
|
|
if repo.Name != form.RepoName {
|
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
|
return
|
|
}
|
|
|
|
repo.DeleteWiki()
|
|
log.Trace("Repository wiki deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.wiki_deletion_success"))
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
|
|
default:
|
|
ctx.NotFound("", nil)
|
|
}
|
|
}
|
|
|
|
// Collaboration render a repository's collaboration page
|
|
func Collaboration(ctx *context.Context) {
|
|
ctx.Data["Title"] = ctx.Tr("repo.settings")
|
|
ctx.Data["PageIsSettingsCollaboration"] = true
|
|
|
|
users, err := ctx.Repo.Repository.GetCollaborators()
|
|
if err != nil {
|
|
ctx.ServerError("GetCollaborators", err)
|
|
return
|
|
}
|
|
ctx.Data["Collaborators"] = users
|
|
|
|
ctx.HTML(200, tplCollaboration)
|
|
}
|
|
|
|
// CollaborationPost response for actions for a collaboration of a repository
|
|
func CollaborationPost(ctx *context.Context) {
|
|
name := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.Query("collaborator")))
|
|
if len(name) == 0 || ctx.Repo.Owner.LowerName == name {
|
|
ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path)
|
|
return
|
|
}
|
|
|
|
u, err := models.GetUserByName(name)
|
|
if err != nil {
|
|
if models.IsErrUserNotExist(err) {
|
|
ctx.Flash.Error(ctx.Tr("form.user_not_exist"))
|
|
ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path)
|
|
} else {
|
|
ctx.ServerError("GetUserByName", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Organization is not allowed to be added as a collaborator.
|
|
if u.IsOrganization() {
|
|
ctx.Flash.Error(ctx.Tr("repo.settings.org_not_allowed_to_be_collaborator"))
|
|
ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path)
|
|
return
|
|
}
|
|
|
|
// Check if user is organization member.
|
|
if ctx.Repo.Owner.IsOrganization() {
|
|
isMember, err := ctx.Repo.Owner.IsOrgMember(u.ID)
|
|
if err != nil {
|
|
ctx.ServerError("IsOrgMember", err)
|
|
return
|
|
} else if isMember {
|
|
ctx.Flash.Info(ctx.Tr("repo.settings.user_is_org_member"))
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
|
return
|
|
}
|
|
}
|
|
|
|
if err = ctx.Repo.Repository.AddCollaborator(u); err != nil {
|
|
ctx.ServerError("AddCollaborator", err)
|
|
return
|
|
}
|
|
|
|
if setting.Service.EnableNotifyMail {
|
|
models.SendCollaboratorMail(u, ctx.User, ctx.Repo.Repository)
|
|
}
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.add_collaborator_success"))
|
|
ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path)
|
|
}
|
|
|
|
// ChangeCollaborationAccessMode response for changing access of a collaboration
|
|
func ChangeCollaborationAccessMode(ctx *context.Context) {
|
|
if err := ctx.Repo.Repository.ChangeCollaborationAccessMode(
|
|
ctx.QueryInt64("uid"),
|
|
models.AccessMode(ctx.QueryInt("mode"))); err != nil {
|
|
log.Error(4, "ChangeCollaborationAccessMode: %v", err)
|
|
}
|
|
}
|
|
|
|
// DeleteCollaboration delete a collaboration for a repository
|
|
func DeleteCollaboration(ctx *context.Context) {
|
|
if err := ctx.Repo.Repository.DeleteCollaboration(ctx.QueryInt64("id")); err != nil {
|
|
ctx.Flash.Error("DeleteCollaboration: " + err.Error())
|
|
} else {
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.remove_collaborator_success"))
|
|
}
|
|
|
|
ctx.JSON(200, map[string]interface{}{
|
|
"redirect": ctx.Repo.RepoLink + "/settings/collaboration",
|
|
})
|
|
}
|
|
|
|
// parseOwnerAndRepo get repos by owner
|
|
func parseOwnerAndRepo(ctx *context.Context) (*models.User, *models.Repository) {
|
|
owner, err := models.GetUserByName(ctx.Params(":username"))
|
|
if err != nil {
|
|
if models.IsErrUserNotExist(err) {
|
|
ctx.NotFound("GetUserByName", err)
|
|
} else {
|
|
ctx.ServerError("GetUserByName", err)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
repo, err := models.GetRepositoryByName(owner.ID, ctx.Params(":reponame"))
|
|
if err != nil {
|
|
if models.IsErrRepoNotExist(err) {
|
|
ctx.NotFound("GetRepositoryByName", err)
|
|
} else {
|
|
ctx.ServerError("GetRepositoryByName", err)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
return owner, repo
|
|
}
|
|
|
|
// GitHooks hooks of a repository
|
|
func GitHooks(ctx *context.Context) {
|
|
ctx.Data["Title"] = ctx.Tr("repo.settings.githooks")
|
|
ctx.Data["PageIsSettingsGitHooks"] = true
|
|
|
|
hooks, err := ctx.Repo.GitRepo.Hooks()
|
|
if err != nil {
|
|
ctx.ServerError("Hooks", err)
|
|
return
|
|
}
|
|
ctx.Data["Hooks"] = hooks
|
|
|
|
ctx.HTML(200, tplGithooks)
|
|
}
|
|
|
|
// GitHooksEdit render for editing a hook of repository page
|
|
func GitHooksEdit(ctx *context.Context) {
|
|
ctx.Data["Title"] = ctx.Tr("repo.settings.githooks")
|
|
ctx.Data["PageIsSettingsGitHooks"] = true
|
|
|
|
name := ctx.Params(":name")
|
|
hook, err := ctx.Repo.GitRepo.GetHook(name)
|
|
if err != nil {
|
|
if err == git.ErrNotValidHook {
|
|
ctx.NotFound("GetHook", err)
|
|
} else {
|
|
ctx.ServerError("GetHook", err)
|
|
}
|
|
return
|
|
}
|
|
ctx.Data["Hook"] = hook
|
|
ctx.HTML(200, tplGithookEdit)
|
|
}
|
|
|
|
// GitHooksEditPost response for editing a git hook of a repository
|
|
func GitHooksEditPost(ctx *context.Context) {
|
|
name := ctx.Params(":name")
|
|
hook, err := ctx.Repo.GitRepo.GetHook(name)
|
|
if err != nil {
|
|
if err == git.ErrNotValidHook {
|
|
ctx.NotFound("GetHook", err)
|
|
} else {
|
|
ctx.ServerError("GetHook", err)
|
|
}
|
|
return
|
|
}
|
|
hook.Content = ctx.Query("content")
|
|
if err = hook.Update(); err != nil {
|
|
ctx.ServerError("hook.Update", err)
|
|
return
|
|
}
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings/hooks/git")
|
|
}
|
|
|
|
// DeployKeys render the deploy keys list of a repository page
|
|
func DeployKeys(ctx *context.Context) {
|
|
ctx.Data["Title"] = ctx.Tr("repo.settings.deploy_keys")
|
|
ctx.Data["PageIsSettingsKeys"] = true
|
|
ctx.Data["DisableSSH"] = setting.SSH.Disabled
|
|
|
|
keys, err := models.ListDeployKeys(ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
ctx.ServerError("ListDeployKeys", err)
|
|
return
|
|
}
|
|
ctx.Data["Deploykeys"] = keys
|
|
|
|
ctx.HTML(200, tplDeployKeys)
|
|
}
|
|
|
|
// DeployKeysPost response for adding a deploy key of a repository
|
|
func DeployKeysPost(ctx *context.Context, form auth.AddKeyForm) {
|
|
ctx.Data["Title"] = ctx.Tr("repo.settings.deploy_keys")
|
|
ctx.Data["PageIsSettingsKeys"] = true
|
|
|
|
keys, err := models.ListDeployKeys(ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
ctx.ServerError("ListDeployKeys", err)
|
|
return
|
|
}
|
|
ctx.Data["Deploykeys"] = keys
|
|
|
|
if ctx.HasError() {
|
|
ctx.HTML(200, tplDeployKeys)
|
|
return
|
|
}
|
|
|
|
content, err := models.CheckPublicKeyString(form.Content)
|
|
if err != nil {
|
|
if models.IsErrSSHDisabled(err) {
|
|
ctx.Flash.Info(ctx.Tr("settings.ssh_disabled"))
|
|
} else if models.IsErrKeyUnableVerify(err) {
|
|
ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
|
|
} else {
|
|
ctx.Data["HasError"] = true
|
|
ctx.Data["Err_Content"] = true
|
|
ctx.Flash.Error(ctx.Tr("form.invalid_ssh_key", err.Error()))
|
|
}
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys")
|
|
return
|
|
}
|
|
|
|
key, err := models.AddDeployKey(ctx.Repo.Repository.ID, form.Title, content, !form.IsWritable)
|
|
if err != nil {
|
|
ctx.Data["HasError"] = true
|
|
switch {
|
|
case models.IsErrKeyAlreadyExist(err):
|
|
ctx.Data["Err_Content"] = true
|
|
ctx.RenderWithErr(ctx.Tr("repo.settings.key_been_used"), tplDeployKeys, &form)
|
|
case models.IsErrKeyNameAlreadyUsed(err):
|
|
ctx.Data["Err_Title"] = true
|
|
ctx.RenderWithErr(ctx.Tr("repo.settings.key_name_used"), tplDeployKeys, &form)
|
|
default:
|
|
ctx.ServerError("AddDeployKey", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
log.Trace("Deploy key added: %d", ctx.Repo.Repository.ID)
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.add_key_success", key.Name))
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys")
|
|
}
|
|
|
|
// DeleteDeployKey response for deleting a deploy key
|
|
func DeleteDeployKey(ctx *context.Context) {
|
|
if err := models.DeleteDeployKey(ctx.User, ctx.QueryInt64("id")); err != nil {
|
|
ctx.Flash.Error("DeleteDeployKey: " + err.Error())
|
|
} else {
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.deploy_key_deletion_success"))
|
|
}
|
|
|
|
ctx.JSON(200, map[string]interface{}{
|
|
"redirect": ctx.Repo.RepoLink + "/settings/keys",
|
|
})
|
|
}
|