func UpdateIssueMilestone(ctx *middleware.Context) { issue := getActionIssue(ctx) if ctx.Written() { return } oldMid := issue.MilestoneID mid := ctx.QueryInt64("id") if oldMid == mid { ctx.JSON(200, map[string]interface{}{ "ok": true, }) return } // Not check for invalid milestone id and give responsibility to owners. issue.MilestoneID = mid if err := models.ChangeMilestoneAssign(oldMid, issue); err != nil { ctx.Handle(500, "ChangeMilestoneAssign", err) return } ctx.JSON(200, map[string]interface{}{ "ok": true, }) }
func UpdateIssueAssignee(ctx *middleware.Context) { issue := getActionIssue(ctx) if ctx.Written() { return } aid := ctx.QueryInt64("id") if issue.AssigneeID == aid { ctx.JSON(200, map[string]interface{}{ "ok": true, }) return } // Not check for invalid assignee id and give responsibility to owners. issue.AssigneeID = aid if err := models.UpdateIssueUserByAssignee(issue); err != nil { ctx.Handle(500, "UpdateIssueUserByAssignee: %v", err) return } ctx.JSON(200, map[string]interface{}{ "ok": true, }) }
func createRepo(ctx *middleware.Context, owner *models.User, opt api.CreateRepoOption) { repo, err := models.CreateRepository(owner, models.CreateRepoOptions{ Name: opt.Name, Description: opt.Description, Gitignores: opt.Gitignores, License: opt.License, Readme: opt.Readme, IsPrivate: opt.Private, AutoInit: opt.AutoInit, }) if err != nil { if models.IsErrRepoAlreadyExist(err) || models.IsErrNameReserved(err) || models.IsErrNamePatternNotAllowed(err) { ctx.JSON(422, &base.ApiJsonErr{err.Error(), base.DOC_URL}) } else { log.Error(4, "CreateRepository: %v", err) if repo != nil { if err = models.DeleteRepository(ctx.User.Id, repo.ID); err != nil { log.Error(4, "DeleteRepository: %v", err) } } ctx.Error(500) } return } ctx.JSON(201, ToApiRepository(owner, repo, api.Permission{true, true, true})) }
func UpdateIssueTitle(ctx *middleware.Context) { issue := getActionIssue(ctx) if ctx.Written() { return } if !ctx.IsSigned || (ctx.User.Id != issue.PosterID && !ctx.Repo.IsAdmin()) { ctx.Error(403) return } issue.Name = ctx.Query("title") if len(issue.Name) == 0 { ctx.Error(204) return } if err := models.UpdateIssue(issue); err != nil { ctx.Handle(500, "UpdateIssue", err) return } ctx.JSON(200, map[string]interface{}{ "title": issue.Name, }) }
func UpdateCommentContent(ctx *middleware.Context) { comment, err := models.GetCommentByID(ctx.ParamsInt64(":id")) if err != nil { if models.IsErrCommentNotExist(err) { ctx.Error(404, "GetCommentByID") } else { ctx.Handle(500, "GetCommentByID", err) } return } if !ctx.IsSigned || (ctx.User.Id != comment.PosterID && !ctx.Repo.IsAdmin()) { ctx.Error(403) return } else if comment.Type != models.COMMENT_TYPE_COMMENT { ctx.Error(204) return } comment.Content = ctx.Query("content") if len(comment.Content) == 0 { ctx.JSON(200, map[string]interface{}{ "content": "", }) return } if err := models.UpdateComment(comment); err != nil { ctx.Handle(500, "UpdateComment", err) return } ctx.JSON(200, map[string]interface{}{ "content": string(base.RenderMarkdown([]byte(comment.Content), ctx.Query("context"))), }) }
// https://github.com/gogits/go-gogs-client/wiki/Repositories#create func CreateRepo(ctx *middleware.Context, opt api.CreateRepoOption) { // Shouldn't reach this condition, but just in case. if ctx.User.IsOrganization() { ctx.JSON(422, "not allowed creating repository for organization") return } createRepo(ctx, ctx.User, opt) }
// Render a Markdown document in raw mode. func MarkdownRaw(ctx *middleware.Context) { body, err := ctx.Req.Body().Bytes() if err != nil { ctx.JSON(422, base.ApiJsonErr{err.Error(), base.DOC_URL}) return } ctx.Write(base.RenderRawMarkdown(body, "")) }
func MembersAction(ctx *middleware.Context) { uid := com.StrTo(ctx.Query("uid")).MustInt64() if uid == 0 { ctx.Redirect(ctx.Org.OrgLink + "/members") return } org := ctx.Org.Organization var err error switch ctx.Params(":action") { case "private": if ctx.User.Id != uid && !ctx.Org.IsOwner { ctx.Error(404) return } err = models.ChangeOrgUserStatus(org.Id, uid, false) case "public": if ctx.User.Id != uid { ctx.Error(404) return } err = models.ChangeOrgUserStatus(org.Id, uid, true) case "remove": if !ctx.Org.IsOwner { ctx.Error(404) return } err = org.RemoveMember(uid) if models.IsErrLastOrgOwner(err) { ctx.Flash.Error(ctx.Tr("form.last_org_owner")) ctx.Redirect(ctx.Org.OrgLink + "/members") return } case "leave": err = org.RemoveMember(ctx.User.Id) if models.IsErrLastOrgOwner(err) { ctx.Flash.Error(ctx.Tr("form.last_org_owner")) ctx.Redirect(ctx.Org.OrgLink + "/members") return } } if err != nil { log.Error(4, "Action(%s): %v", ctx.Params(":action"), err) ctx.JSON(200, map[string]interface{}{ "ok": false, "err": err.Error(), }) return } if ctx.Params(":action") != "leave" { ctx.Redirect(ctx.Org.OrgLink + "/members") } else { ctx.Redirect(setting.AppSubUrl + "/") } }
func DeleteWebhook(ctx *middleware.Context) { if err := models.DeleteWebhook(ctx.QueryInt64("id")); err != nil { ctx.Flash.Error("DeleteWebhook: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success")) } ctx.JSON(200, map[string]interface{}{ "redirect": ctx.Org.OrgLink + "/settings/hooks", }) }
func DeleteMilestone(ctx *middleware.Context) { if err := models.DeleteMilestoneByID(ctx.QueryInt64("id")); err != nil { ctx.Flash.Error("DeleteMilestoneByID: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("repo.milestones.deletion_success")) } ctx.JSON(200, map[string]interface{}{ "redirect": ctx.Repo.RepoLink + "/milestones", }) }
func SettingsDeleteApplication(ctx *middleware.Context) { if err := models.DeleteAccessTokenByID(ctx.QueryInt64("id")); err != nil { ctx.Flash.Error("DeleteAccessTokenByID: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("settings.delete_token_success")) } ctx.JSON(200, map[string]interface{}{ "redirect": setting.AppSubUrl + "/user/settings/applications", }) }
func DeleteSSHKey(ctx *middleware.Context) { if err := models.DeletePublicKey(ctx.QueryInt64("id")); err != nil { ctx.Flash.Error("DeletePublicKey: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("settings.ssh_key_deletion_success")) } ctx.JSON(200, map[string]interface{}{ "redirect": setting.AppSubUrl + "/user/settings/ssh", }) }
func DeleteDeployKey(ctx *middleware.Context) { if err := models.DeleteDeployKey(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", }) }
// POST /users/:username/tokens func CreateAccessToken(ctx *middleware.Context, form CreateAccessTokenForm) { t := &models.AccessToken{ UID: ctx.User.Id, Name: form.Name, } if err := models.NewAccessToken(t); err != nil { ctx.JSON(500, &base.ApiJsonErr{"NewAccessToken: " + err.Error(), base.DOC_URL}) return } ctx.JSON(201, &api.AccessToken{t.Name, t.Sha1}) }
func DeleteLabel(ctx *middleware.Context) { if err := models.DeleteLabel(ctx.Repo.Repository.ID, ctx.QueryInt64("id")); err != nil { ctx.Flash.Error("DeleteLabel: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("repo.issues.label_deletion_success")) } ctx.JSON(200, map[string]interface{}{ "redirect": ctx.Repo.RepoLink + "/labels", }) return }
// GET /users/:username/tokens func ListAccessTokens(ctx *middleware.Context) { tokens, err := models.ListAccessTokens(ctx.User.Id) if err != nil { ctx.JSON(500, &base.ApiJsonErr{"ListAccessTokens: " + err.Error(), base.DOC_URL}) return } apiTokens := make([]*api.AccessToken, len(tokens)) for i := range tokens { apiTokens[i] = &api.AccessToken{tokens[i].Name, tokens[i].Sha1} } ctx.JSON(200, &apiTokens) }
// https://github.com/gogits/go-gogs-client/wiki/Repositories#list-hooks func ListRepoHooks(ctx *middleware.Context) { hooks, err := models.GetWebhooksByRepoId(ctx.Repo.Repository.ID) if err != nil { ctx.JSON(500, &base.ApiJsonErr{"GetWebhooksByRepoId: " + err.Error(), base.DOC_URL}) return } apiHooks := make([]*api.Hook, len(hooks)) for i := range hooks { apiHooks[i] = ToApiHook(ctx.Repo.RepoLink, hooks[i]) } ctx.JSON(200, &apiHooks) }
func SearchRepos(ctx *middleware.Context) { opt := models.SearchOption{ Keyword: path.Base(ctx.Query("q")), Uid: com.StrTo(ctx.Query("uid")).MustInt64(), Limit: com.StrTo(ctx.Query("limit")).MustInt(), } if opt.Limit == 0 { opt.Limit = 10 } // Check visibility. if ctx.IsSigned && opt.Uid > 0 { if ctx.User.Id == opt.Uid { opt.Private = true } else { u, err := models.GetUserByID(opt.Uid) if err != nil { ctx.JSON(500, map[string]interface{}{ "ok": false, "error": err.Error(), }) return } if u.IsOrganization() && u.IsOwnedBy(ctx.User.Id) { opt.Private = true } // FIXME: how about collaborators? } } repos, err := models.SearchRepositoryByName(opt) if err != nil { ctx.JSON(500, map[string]interface{}{ "ok": false, "error": err.Error(), }) return } results := make([]*api.Repository, len(repos)) for i := range repos { if err = repos[i].GetOwner(); err != nil { ctx.JSON(500, map[string]interface{}{ "ok": false, "error": err.Error(), }) return } results[i] = &api.Repository{ Id: repos[i].ID, FullName: path.Join(repos[i].Owner.Name, repos[i].Name), } } ctx.JSON(200, map[string]interface{}{ "ok": true, "data": results, }) }
// GET /users/:username func GetUserInfo(ctx *middleware.Context) { u, err := models.GetUserByName(ctx.Params(":username")) if err != nil { if models.IsErrUserNotExist(err) { ctx.Error(404) } else { ctx.JSON(500, &base.ApiJsonErr{"GetUserByName: " + err.Error(), base.DOC_URL}) } return } // Hide user e-mail when API caller isn't signed in. if !ctx.IsSigned { u.Email = "" } ctx.JSON(200, &api.User{u.Id, u.Name, u.FullName, u.Email, u.AvatarLink()}) }
func UploadIssueAttachment(ctx *middleware.Context) { if !setting.AttachmentEnabled { ctx.Error(404, "attachment is not enabled") return } allowedTypes := strings.Split(setting.AttachmentAllowedTypes, ",") file, header, err := ctx.Req.FormFile("file") if err != nil { ctx.Error(500, fmt.Sprintf("FormFile: %v", err)) return } defer file.Close() buf := make([]byte, 1024) n, _ := file.Read(buf) if n > 0 { buf = buf[:n] } fileType := http.DetectContentType(buf) allowed := false for _, t := range allowedTypes { t := strings.Trim(t, " ") if t == "*/*" || t == fileType { allowed = true break } } if !allowed { ctx.Error(400, ErrFileTypeForbidden.Error()) return } attach, err := models.NewAttachment(header.Filename, buf, file) if err != nil { ctx.Error(500, fmt.Sprintf("NewAttachment: %v", err)) return } log.Trace("New attachment uploaded: %s", attach.UUID) ctx.JSON(200, map[string]string{ "uuid": attach.UUID, }) }
// Render an arbitrary Markdown document. func Markdown(ctx *middleware.Context, form apiv1.MarkdownForm) { if ctx.HasApiError() { ctx.JSON(422, base.ApiJsonErr{ctx.GetErrMsg(), base.DOC_URL}) return } if len(form.Text) == 0 { ctx.Write([]byte("")) return } switch form.Mode { case "gfm": ctx.Write(base.RenderMarkdown([]byte(form.Text), setting.AppUrl+strings.TrimPrefix(form.Context, "/"))) default: ctx.Write(base.RenderRawMarkdown([]byte(form.Text), "")) } }
func GetRepoRawFile(ctx *middleware.Context) { if !ctx.Repo.HasAccess() { ctx.Error(404) return } blob, err := ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreeName) if err != nil { if err == git.ErrNotExist { ctx.Error(404) } else { ctx.JSON(500, &base.ApiJsonErr{"GetBlobByPath: " + err.Error(), base.DOC_URL}) } return } if err = repo.ServeBlob(ctx, blob); err != nil { ctx.JSON(500, &base.ApiJsonErr{"ServeBlob: " + err.Error(), base.DOC_URL}) } }
func Action(ctx *middleware.Context) { var err error switch ctx.Params(":action") { case "watch": err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.ID, true) case "unwatch": err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.ID, false) case "star": err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.ID, true) case "unstar": err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.ID, false) case "desc": if !ctx.Repo.IsOwner() { ctx.Error(404) return } ctx.Repo.Repository.Description = ctx.Query("desc") ctx.Repo.Repository.Website = ctx.Query("site") err = models.UpdateRepository(ctx.Repo.Repository, false) } if err != nil { log.Error(4, "Action(%s): %v", ctx.Params(":action"), err) ctx.JSON(200, map[string]interface{}{ "ok": false, "err": err.Error(), }) return } redirectTo := ctx.Query("redirect_to") if len(redirectTo) == 0 { redirectTo = ctx.Repo.RepoLink } ctx.Redirect(redirectTo) return ctx.JSON(200, map[string]interface{}{ "ok": true, }) }
func UpdateIssueContent(ctx *middleware.Context) { issue := getActionIssue(ctx) if ctx.Written() { return } if !ctx.IsSigned || (ctx.User.Id != issue.PosterID && !ctx.Repo.IsAdmin()) { ctx.Error(403) return } issue.Content = ctx.Query("content") if err := models.UpdateIssue(issue); err != nil { ctx.Handle(500, "UpdateIssue", err) return } ctx.JSON(200, map[string]interface{}{ "content": string(base.RenderMarkdown([]byte(issue.Content), ctx.Query("context"))), }) }
// https://github.com/gogits/go-gogs-client/wiki/Repositories#list-your-repositories func ListMyRepos(ctx *middleware.Context) { ownRepos, err := models.GetRepositories(ctx.User.Id, true) if err != nil { ctx.JSON(500, &base.ApiJsonErr{"GetRepositories: " + err.Error(), base.DOC_URL}) return } numOwnRepos := len(ownRepos) accessibleRepos, err := ctx.User.GetAccessibleRepositories() if err != nil { ctx.JSON(500, &base.ApiJsonErr{"GetAccessibleRepositories: " + err.Error(), base.DOC_URL}) return } repos := make([]*api.Repository, numOwnRepos+len(accessibleRepos)) for i := range ownRepos { repos[i] = ToApiRepository(ctx.User, ownRepos[i], api.Permission{true, true, true}) } i := numOwnRepos for repo, access := range accessibleRepos { repos[i] = ToApiRepository(repo.Owner, repo, api.Permission{ Admin: access >= models.ACCESS_MODE_ADMIN, Push: access >= models.ACCESS_MODE_WRITE, Pull: true, }) i++ } ctx.JSON(200, &repos) }
func UpdateIssueLabel(ctx *middleware.Context) { issue := getActionIssue(ctx) if ctx.Written() { return } if ctx.Query("action") == "clear" { if err := issue.ClearLabels(); err != nil { ctx.Handle(500, "ClearLabels", err) return } } else { isAttach := ctx.Query("action") == "attach" label, err := models.GetLabelByID(ctx.QueryInt64("id")) if err != nil { if models.IsErrLabelNotExist(err) { ctx.Error(404, "GetLabelByID") } else { ctx.Handle(500, "GetLabelByID", err) } return } if isAttach && !issue.HasLabel(label.ID) { if err = issue.AddLabel(label); err != nil { ctx.Handle(500, "AddLabel", err) return } } else if !isAttach && issue.HasLabel(label.ID) { if err = issue.RemoveLabel(label); err != nil { ctx.Handle(500, "RemoveLabel", err) return } } } ctx.JSON(200, map[string]interface{}{ "ok": true, }) }
func SearchUsers(ctx *middleware.Context) { opt := models.SearchOption{ Keyword: ctx.Query("q"), Limit: com.StrTo(ctx.Query("limit")).MustInt(), } if opt.Limit == 0 { opt.Limit = 10 } us, err := models.SearchUserByName(opt) if err != nil { ctx.JSON(500, map[string]interface{}{ "ok": false, "error": err.Error(), }) return } results := make([]*api.User, len(us)) for i := range us { results[i] = &api.User{ ID: us[i].Id, UserName: us[i].Name, AvatarUrl: us[i].AvatarLink(), FullName: us[i].FullName, } if ctx.IsSigned { results[i].Email = us[i].Email } } ctx.Render.JSON(200, map[string]interface{}{ "ok": true, "data": results, }) }
// https://github.com/gogits/go-gogs-client/wiki/Repositories#create-a-hook func CreateRepoHook(ctx *middleware.Context, form api.CreateHookOption) { if !models.IsValidHookTaskType(form.Type) { ctx.JSON(422, &base.ApiJsonErr{"invalid hook type", base.DOC_URL}) return } for _, name := range []string{"url", "content_type"} { if _, ok := form.Config[name]; !ok { ctx.JSON(422, &base.ApiJsonErr{"missing config option: " + name, base.DOC_URL}) return } } if !models.IsValidHookContentType(form.Config["content_type"]) { ctx.JSON(422, &base.ApiJsonErr{"invalid content type", base.DOC_URL}) return } if len(form.Events) == 0 { form.Events = []string{"push"} } w := &models.Webhook{ RepoID: ctx.Repo.Repository.ID, URL: form.Config["url"], ContentType: models.ToHookContentType(form.Config["content_type"]), Secret: form.Config["secret"], HookEvent: &models.HookEvent{ ChooseEvents: true, HookEvents: models.HookEvents{ Create: com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_CREATE)), Push: com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_PUSH)), }, }, IsActive: form.Active, HookTaskType: models.ToHookTaskType(form.Type), } if w.HookTaskType == models.SLACK { channel, ok := form.Config["channel"] if !ok { ctx.JSON(422, &base.ApiJsonErr{"missing config option: channel", base.DOC_URL}) return } meta, err := json.Marshal(&models.SlackMeta{ Channel: channel, Username: form.Config["username"], IconURL: form.Config["icon_url"], Color: form.Config["color"], }) if err != nil { ctx.JSON(500, &base.ApiJsonErr{"slack: JSON marshal failed: " + err.Error(), base.DOC_URL}) return } w.Meta = string(meta) } if err := w.UpdateEvent(); err != nil { ctx.JSON(500, &base.ApiJsonErr{"UpdateEvent: " + err.Error(), base.DOC_URL}) return } else if err := models.CreateWebhook(w); err != nil { ctx.JSON(500, &base.ApiJsonErr{"CreateWebhook: " + err.Error(), base.DOC_URL}) return } ctx.JSON(201, ToApiHook(ctx.Repo.RepoLink, w)) }
// https://github.com/gogits/go-gogs-client/wiki/Repositories#edit-a-hook func EditRepoHook(ctx *middleware.Context, form api.EditHookOption) { w, err := models.GetWebhookByID(ctx.ParamsInt64(":id")) if err != nil { ctx.JSON(500, &base.ApiJsonErr{"GetWebhookById: " + err.Error(), base.DOC_URL}) return } if form.Config != nil { if url, ok := form.Config["url"]; ok { w.URL = url } if ct, ok := form.Config["content_type"]; ok { if !models.IsValidHookContentType(ct) { ctx.JSON(422, &base.ApiJsonErr{"invalid content type", base.DOC_URL}) return } w.ContentType = models.ToHookContentType(ct) } if w.HookTaskType == models.SLACK { if channel, ok := form.Config["channel"]; ok { meta, err := json.Marshal(&models.SlackMeta{ Channel: channel, Username: form.Config["username"], IconURL: form.Config["icon_url"], Color: form.Config["color"], }) if err != nil { ctx.JSON(500, &base.ApiJsonErr{"slack: JSON marshal failed: " + err.Error(), base.DOC_URL}) return } w.Meta = string(meta) } } } // Update events if len(form.Events) == 0 { form.Events = []string{"push"} } w.PushOnly = false w.SendEverything = false w.ChooseEvents = true w.Create = com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_CREATE)) w.Push = com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_PUSH)) if err = w.UpdateEvent(); err != nil { ctx.JSON(500, &base.ApiJsonErr{"UpdateEvent: " + err.Error(), base.DOC_URL}) return } if form.Active != nil { w.IsActive = *form.Active } if err := models.UpdateWebhook(w); err != nil { ctx.JSON(500, &base.ApiJsonErr{"UpdateWebhook: " + err.Error(), base.DOC_URL}) return } ctx.JSON(200, ToApiHook(ctx.Repo.RepoLink, w)) }
func TeamsAction(ctx *middleware.Context) { uid := com.StrTo(ctx.Query("uid")).MustInt64() if uid == 0 { ctx.Redirect(ctx.Org.OrgLink + "/teams") return } page := ctx.Query("page") var err error switch ctx.Params(":action") { case "join": if !ctx.Org.IsOwner { ctx.Error(404) return } err = ctx.Org.Team.AddMember(ctx.User.Id) case "leave": err = ctx.Org.Team.RemoveMember(ctx.User.Id) case "remove": if !ctx.Org.IsOwner { ctx.Error(404) return } err = ctx.Org.Team.RemoveMember(uid) page = "team" case "add": if !ctx.Org.IsOwner { ctx.Error(404) return } uname := ctx.Query("uname") var u *models.User u, err = models.GetUserByName(uname) if err != nil { if models.IsErrUserNotExist(err) { ctx.Flash.Error(ctx.Tr("form.user_not_exist")) ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName) } else { ctx.Handle(500, " GetUserByName", err) } return } err = ctx.Org.Team.AddMember(u.Id) page = "team" } if err != nil { if models.IsErrLastOrgOwner(err) { ctx.Flash.Error(ctx.Tr("form.last_org_owner")) } else { log.Error(3, "Action(%s): %v", ctx.Params(":action"), err) ctx.JSON(200, map[string]interface{}{ "ok": false, "err": err.Error(), }) return } } switch page { case "team": ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName) default: ctx.Redirect(ctx.Org.OrgLink + "/teams") } }