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([]*sdk.User, len(us)) for i := range us { results[i] = &sdk.User{ UserName: us[i].Name, AvatarUrl: us[i].AvatarLink(), FullName: us[i].FullName, } } ctx.Render.JSON(200, map[string]interface{}{ "ok": true, "data": results, }) }
// GET /repos/:username/:reponame/hooks // https://developer.github.com/v3/repos/hooks/#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 { h := &api.Hook{ Id: hooks[i].Id, Type: hooks[i].HookTaskType.Name(), Active: hooks[i].IsActive, Config: make(map[string]string), } // Currently, onle have push event. h.Events = []string{"push"} h.Config["url"] = hooks[i].Url h.Config["content_type"] = hooks[i].ContentType.Name() if hooks[i].HookTaskType == models.SLACK { s := hooks[i].GetSlackHook() h.Config["channel"] = s.Channel } apiHooks[i] = h } ctx.JSON(200, &apiHooks) }
// POST /user/repos // https://developer.github.com/v3/repos/#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 + "/") } }
// 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, &sdk.AccessToken{t.Name, t.Sha1}) }
// 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([]*sdk.AccessToken, len(tokens)) for i := range tokens { apiTokens[i] = &sdk.AccessToken{tokens[i].Name, tokens[i].Sha1} } ctx.JSON(200, &apiTokens) }
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([]*sdk.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] = &sdk.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, }) }
// PATCH /repos/:username/:reponame/hooks/:id // https://developer.github.com/v3/repos/hooks/#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.Slack{ Channel: channel, }) if err != nil { ctx.JSON(500, &base.ApiJsonErr{"slack: JSON marshal failed: " + err.Error(), base.DOC_URL}) return } w.Meta = string(meta) } } } if form.Active != nil { w.IsActive = *form.Active } // FIXME: edit events if err := models.UpdateWebhook(w); err != nil { ctx.JSON(500, &base.ApiJsonErr{"UpdateWebhook: " + err.Error(), base.DOC_URL}) return } ctx.JSON(200, map[string]interface{}{ "ok": true, }) }
// GET /users/:username func GetUserInfo(ctx *middleware.Context) { u, err := models.GetUserByName(ctx.Params(":username")) if err != nil { if err == models.ErrUserNotExist { 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, &sdk.User{u.Id, u.Name, u.FullName, u.Email, u.AvatarLink()}) }
func UpdateIssueMilestone(ctx *middleware.Context) { if !ctx.Repo.IsOwner() { ctx.Error(403) return } issueId := com.StrTo(ctx.Query("issue")).MustInt64() if issueId == 0 { ctx.Error(404) return } issue, err := models.GetIssueById(issueId) if err != nil { if err == models.ErrIssueNotExist { ctx.Handle(404, "issue.UpdateIssueMilestone(GetIssueById)", err) } else { ctx.Handle(500, "issue.UpdateIssueMilestone(GetIssueById)", err) } return } oldMid := issue.MilestoneId mid := com.StrTo(ctx.Query("milestoneid")).MustInt64() 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, mid, issue); err != nil { ctx.Handle(500, "issue.UpdateIssueMilestone(ChangeMilestoneAssign)", err) return } else if err = models.UpdateIssue(issue); err != nil { ctx.Handle(500, "issue.UpdateIssueMilestone(UpdateIssue)", err) return } ctx.JSON(200, map[string]interface{}{ "ok": true, }) }
// 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 UpdateIssue(ctx *middleware.Context, form auth.CreateIssueForm) { idx := com.StrTo(ctx.Params(":index")).MustInt64() if idx <= 0 { ctx.Error(404) return } issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx) if err != nil { if err == models.ErrIssueNotExist { ctx.Handle(404, "issue.UpdateIssue", err) } else { ctx.Handle(500, "issue.UpdateIssue(GetIssueByIndex)", err) } return } if ctx.User.Id != issue.PosterId && !ctx.Repo.IsOwner() { ctx.Error(403) return } issue.Name = form.IssueName //issue.MilestoneId = form.MilestoneId //issue.AssigneeId = form.AssigneeId //issue.LabelIds = form.Labels issue.Content = form.Content // try get content from text, ignore conflict with preview ajax if form.Content == "" { issue.Content = ctx.Query("text") } if err = models.UpdateIssue(issue); err != nil { ctx.Handle(500, "issue.UpdateIssue(UpdateIssue)", err) return } ctx.JSON(200, map[string]interface{}{ "ok": true, "title": issue.Name, "content": string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink)), }) }
func createRepo(ctx *middleware.Context, owner *models.User, opt api.CreateRepoOption) { repo, err := models.CreateRepository(owner, opt.Name, opt.Description, opt.Gitignore, opt.License, opt.Private, false, opt.AutoInit) if err != nil { if err == models.ErrRepoAlreadyExist || err == models.ErrRepoNameIllegal { 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, ctx.User.Name); err != nil { log.Error(4, "DeleteRepository: %v", err) } } ctx.Error(500) } return } ctx.JSON(200, ToApiRepository(owner, repo, api.Permission{true, true, true})) }
func DeleteLabel(ctx *middleware.Context) { removes := ctx.Query("remove") if len(strings.TrimSpace(removes)) == 0 { ctx.JSON(200, map[string]interface{}{ "ok": true, }) return } strIds := strings.Split(removes, ",") for _, strId := range strIds { if err := models.DeleteLabel(ctx.Repo.Repository.Id, strId); err != nil { ctx.Handle(500, "issue.DeleteLabel(DeleteLabel)", err) return } } ctx.JSON(200, map[string]interface{}{ "ok": true, }) }
func UpdateAssignee(ctx *middleware.Context) { if !ctx.Repo.IsOwner() { ctx.Error(403) return } issueId := com.StrTo(ctx.Query("issue")).MustInt64() if issueId == 0 { ctx.Error(404) return } issue, err := models.GetIssueById(issueId) if err != nil { if err == models.ErrIssueNotExist { ctx.Handle(404, "GetIssueById", err) } else { ctx.Handle(500, "GetIssueById", err) } return } aid := com.StrTo(ctx.Query("assigneeid")).MustInt64() // Not check for invalid assignee id and give responsibility to owners. issue.AssigneeId = aid if err = models.UpdateIssueUserPairByAssignee(aid, issue.Id); err != nil { ctx.Handle(500, "UpdateIssueUserPairByAssignee: %v", err) return } else if err = models.UpdateIssue(issue); err != nil { ctx.Handle(500, "UpdateIssue", err) return } ctx.JSON(200, map[string]interface{}{ "ok": true, }) }
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 } ctx.Redirect(ctx.Repo.RepoLink) return ctx.JSON(200, map[string]interface{}{ "ok": true, }) }
// GET /user/repos // https://developer.github.com/v3/repos/#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 { if err = repo.GetOwner(); err != nil { ctx.JSON(500, &base.ApiJsonErr{"GetOwner: " + err.Error(), base.DOC_URL}) return } repos[i] = ToApiRepository(repo.Owner, repo, api.Permission{false, access >= models.ACCESS_MODE_WRITE, true}) // FIXME: cache result to reduce DB query? if repo.Owner.IsOrganization() && repo.Owner.IsOwnedBy(ctx.User.Id) { repos[i].Permissions.Admin = true } i++ } ctx.JSON(200, &repos) }
func UpdateIssueLabel(ctx *middleware.Context) { if !ctx.Repo.IsOwner() { ctx.Error(403) return } idx := com.StrTo(ctx.Params(":index")).MustInt64() if idx <= 0 { ctx.Error(404) return } issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx) if err != nil { if err == models.ErrIssueNotExist { ctx.Handle(404, "issue.UpdateIssueLabel(GetIssueByIndex)", err) } else { ctx.Handle(500, "issue.UpdateIssueLabel(GetIssueByIndex)", err) } return } isAttach := ctx.Query("action") == "attach" labelStrId := ctx.Query("id") labelId := com.StrTo(labelStrId).MustInt64() label, err := models.GetLabelById(labelId) if err != nil { if err == models.ErrLabelNotExist { ctx.Handle(404, "issue.UpdateIssueLabel(GetLabelById)", err) } else { ctx.Handle(500, "issue.UpdateIssueLabel(GetLabelById)", err) } return } isHad := strings.Contains(issue.LabelIds, "$"+labelStrId+"|") isNeedUpdate := false if isAttach { if !isHad { issue.LabelIds += "$" + labelStrId + "|" isNeedUpdate = true } } else { if isHad { issue.LabelIds = strings.Replace(issue.LabelIds, "$"+labelStrId+"|", "", -1) isNeedUpdate = true } } if isNeedUpdate { if err = models.UpdateIssue(issue); err != nil { ctx.Handle(500, "issue.UpdateIssueLabel(UpdateIssue)", err) return } if isAttach { label.NumIssues++ if issue.IsClosed { label.NumClosedIssues++ } } else { label.NumIssues-- if issue.IsClosed { label.NumClosedIssues-- } } if err = models.UpdateLabel(label); err != nil { ctx.Handle(500, "issue.UpdateIssueLabel(UpdateLabel)", err) return } } ctx.JSON(200, map[string]interface{}{ "ok": true, }) }
func Comment(ctx *middleware.Context) { send := func(status int, data interface{}, err error) { if err != nil { log.Error(4, "issue.Comment(?): %s", err) ctx.JSON(status, map[string]interface{}{ "ok": false, "status": status, "error": err.Error(), }) } else { ctx.JSON(status, map[string]interface{}{ "ok": true, "status": status, "data": data, }) } } index := com.StrTo(ctx.Query("issueIndex")).MustInt64() if index == 0 { ctx.Error(404) return } issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index) if err != nil { if err == models.ErrIssueNotExist { send(404, nil, err) } else { send(200, nil, err) } return } // Check if issue owner changes the status of issue. var newStatus string if ctx.Repo.IsOwner() || issue.PosterId == ctx.User.Id { newStatus = ctx.Query("change_status") } if len(newStatus) > 0 { if (strings.Contains(newStatus, "Reopen") && issue.IsClosed) || (strings.Contains(newStatus, "Close") && !issue.IsClosed) { issue.IsClosed = !issue.IsClosed if err = models.UpdateIssue(issue); err != nil { send(500, nil, err) return } else if err = models.UpdateIssueUserPairsByStatus(issue.Id, issue.IsClosed); err != nil { send(500, nil, err) return } if err = issue.GetLabels(); err != nil { send(500, nil, err) return } for _, label := range issue.Labels { if issue.IsClosed { label.NumClosedIssues++ } else { label.NumClosedIssues-- } if err = models.UpdateLabel(label); err != nil { send(500, nil, err) return } } // Change open/closed issue counter for the associated milestone if issue.MilestoneId > 0 { if err = models.ChangeMilestoneIssueStats(issue); err != nil { send(500, nil, err) } } cmtType := models.COMMENT_TYPE_CLOSE if !issue.IsClosed { cmtType = models.COMMENT_TYPE_REOPEN } if _, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, cmtType, "", nil); err != nil { send(200, nil, err) return } log.Trace("%s Issue(%d) status changed: %v", ctx.Req.RequestURI, issue.Id, !issue.IsClosed) } } var comment *models.Comment var ms []string content := ctx.Query("content") // Fix #321. Allow empty comments, as long as we have attachments. if len(content) > 0 || len(ctx.Req.MultipartForm.File["attachments"]) > 0 { switch ctx.Params(":action") { case "new": if comment, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.COMMENT_TYPE_COMMENT, content, nil); err != nil { send(500, nil, err) return } // Update mentions. ms = base.MentionPattern.FindAllString(issue.Content, -1) if len(ms) > 0 { for i := range ms { ms[i] = ms[i][1:] } if err := models.UpdateMentions(ms, issue.Id); err != nil { send(500, nil, err) return } } log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id) default: ctx.Handle(404, "issue.Comment", err) return } } if comment != nil { uploadFiles(ctx, issue.Id, comment.Id) } // Notify watchers. act := &models.Action{ ActUserID: ctx.User.Id, ActUserName: ctx.User.LowerName, ActEmail: ctx.User.Email, OpType: models.COMMENT_ISSUE, Content: fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]), RepoID: ctx.Repo.Repository.Id, RepoUserName: ctx.Repo.Owner.LowerName, RepoName: ctx.Repo.Repository.LowerName, } if err = models.NotifyWatchers(act); err != nil { send(500, nil, err) return } // Mail watchers and mentions. if setting.Service.EnableNotifyMail { issue.Content = content tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue) if err != nil { send(500, nil, err) return } tos = append(tos, ctx.User.LowerName) newTos := make([]string, 0, len(ms)) for _, m := range ms { if com.IsSliceContainsStr(tos, m) { continue } newTos = append(newTos, m) } if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil { send(500, nil, err) return } } send(200, fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, index), nil) }
// POST /repos/:username/:reponame/hooks // https://developer.github.com/v3/repos/hooks/#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 } 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{ PushOnly: true, // Only support it now. }, 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.Slack{ Channel: channel, }) 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 } apiHook := &api.Hook{ Id: w.Id, Type: w.HookTaskType.Name(), Events: []string{"push"}, Active: w.IsActive, Config: map[string]string{ "url": w.Url, "content_type": w.ContentType.Name(), }, } if w.HookTaskType == models.SLACK { s := w.GetSlackHook() apiHook.Config["channel"] = s.Channel } ctx.JSON(201, apiHook) }
func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) { send := func(status int, data interface{}, err error) { if err != nil { log.Error(4, "issue.CreateIssuePost(?): %s", err) ctx.JSON(status, map[string]interface{}{ "ok": false, "status": status, "error": err.Error(), }) } else { ctx.JSON(status, map[string]interface{}{ "ok": true, "status": status, "data": data, }) } } var err error // Get all milestones. _, err = models.GetMilestones(ctx.Repo.Repository.Id, false) if err != nil { send(500, nil, err) return } _, err = models.GetMilestones(ctx.Repo.Repository.Id, true) if err != nil { send(500, nil, err) return } _, err = ctx.Repo.Repository.GetCollaborators() if err != nil { send(500, nil, err) return } if ctx.HasError() { send(400, nil, errors.New(ctx.Flash.ErrorMsg)) return } // Only collaborators can assign. if !ctx.Repo.IsOwner() { form.AssigneeId = 0 } issue := &models.Issue{ RepoId: ctx.Repo.Repository.Id, Index: int64(ctx.Repo.Repository.NumIssues) + 1, Name: form.IssueName, PosterId: ctx.User.Id, MilestoneId: form.MilestoneId, AssigneeId: form.AssigneeId, LabelIds: form.Labels, Content: form.Content, } if err := models.NewIssue(issue); err != nil { send(500, nil, err) return } else if err := models.NewIssueUserPairs(ctx.Repo.Repository, issue.Id, ctx.Repo.Owner.Id, ctx.User.Id, form.AssigneeId); err != nil { send(500, nil, err) return } if setting.AttachmentEnabled { uploadFiles(ctx, issue.Id, 0) } // Update mentions. ms := base.MentionPattern.FindAllString(issue.Content, -1) if len(ms) > 0 { for i := range ms { ms[i] = ms[i][1:] } if err := models.UpdateMentions(ms, issue.Id); err != nil { send(500, nil, err) return } } act := &models.Action{ ActUserID: ctx.User.Id, ActUserName: ctx.User.Name, ActEmail: ctx.User.Email, OpType: models.CREATE_ISSUE, Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name), RepoID: ctx.Repo.Repository.Id, RepoUserName: ctx.Repo.Owner.Name, RepoName: ctx.Repo.Repository.Name, RefName: ctx.Repo.BranchName, IsPrivate: ctx.Repo.Repository.IsPrivate, } // Notify watchers. if err := models.NotifyWatchers(act); err != nil { send(500, nil, err) return } // Mail watchers and mentions. if setting.Service.EnableNotifyMail { tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue) if err != nil { send(500, nil, err) return } tos = append(tos, ctx.User.LowerName) newTos := make([]string, 0, len(ms)) for _, m := range ms { if com.IsSliceContainsStr(tos, m) { continue } newTos = append(newTos, m) } if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil { send(500, nil, err) return } } log.Trace("%d Issue created: %d", ctx.Repo.Repository.Id, issue.Id) send(200, fmt.Sprintf("%s/%s/%s/issues/%d", setting.AppSubUrl, ctx.Params(":username"), ctx.Params(":reponame"), issue.Index), nil) }
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 err == models.ErrUserNotExist { 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") } }