From a1fa62b270bd87dc63a280b6eba98aa9cf9db845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=B4=8A=E1=B4=8F=E1=B4=87=20=E1=B4=84=CA=9C=E1=B4=87?= =?UTF-8?q?=C9=B4?= Date: Tue, 10 Feb 2026 10:56:17 -0500 Subject: [PATCH] all: decouple API types from go-gogs-client SDK (#8171) Co-authored-by: Claude Opus 4.6 (1M context) --- go.mod | 1 - go.sum | 2 - internal/database/actions.go | 28 +- internal/database/comment.go | 23 +- internal/database/issue.go | 93 +++--- internal/database/issue_label.go | 6 +- internal/database/milestone.go | 22 +- internal/database/pull.go | 24 +- internal/database/release.go | 10 +- internal/database/repo.go | 10 +- internal/database/repo_collaboration.go | 10 +- internal/database/repositories.go | 10 +- internal/database/users.go | 8 +- internal/database/webhook.go | 61 ++-- internal/database/webhook_dingtalk.go | 56 ++-- internal/database/webhook_discord.go | 103 +++--- internal/database/webhook_slack.go | 85 +++-- internal/route/api/v1/adapters.go | 303 ++++++++++++++++++ internal/route/api/v1/admin/org.go | 13 - internal/route/api/v1/admin/repo.go | 18 -- internal/route/api/v1/admin_org.go | 9 + .../{admin/org_repo.go => admin_org_repo.go} | 12 +- .../{admin/org_team.go => admin_org_team.go} | 31 +- internal/route/api/v1/admin_repo.go | 14 + .../api/v1/{admin/user.go => admin_user.go} | 55 +++- internal/route/api/v1/api.go | 223 +++++++------ internal/route/api/v1/convert/convert.go | 135 -------- internal/route/api/v1/convert/utils.go | 15 - internal/route/api/v1/{misc => }/markdown.go | 14 +- internal/route/api/v1/{org => }/org.go | 54 ++-- internal/route/api/v1/org/team.go | 22 -- internal/route/api/v1/org_team.go | 20 ++ .../api/v1/{repo/blob.go => repo_blob.go} | 4 +- .../api/v1/{repo/branch.go => repo_branch.go} | 16 +- ...collaborators.go => repo_collaborators.go} | 21 +- .../v1/{repo/commits.go => repo_commits.go} | 46 +-- .../v1/{repo/contents.go => repo_contents.go} | 10 +- .../api/v1/{repo/file.go => repo_file.go} | 14 +- .../api/v1/{repo/hook.go => repo_hook.go} | 35 +- .../api/v1/{repo/issue.go => repo_issue.go} | 53 +-- ...issue_comment.go => repo_issue_comment.go} | 35 +- .../issue_label.go => repo_issue_label.go} | 31 +- .../route/api/v1/{repo/key.go => repo_key.go} | 34 +- .../api/v1/{repo/label.go => repo_label.go} | 35 +- .../{repo/milestone.go => repo_milestone.go} | 40 ++- .../api/v1/{repo/repo.go => repo_repo.go} | 104 +++--- .../route/api/v1/{repo/tag.go => repo_tag.go} | 9 +- .../api/v1/{repo/tree.go => repo_tree.go} | 4 +- internal/route/api/v1/tag.go | 8 + internal/route/api/v1/types/commit.go | 29 ++ internal/route/api/v1/types/hook.go | 23 ++ internal/route/api/v1/types/issue.go | 58 ++++ internal/route/api/v1/types/org.go | 18 ++ internal/route/api/v1/types/pull_request.go | 26 ++ internal/route/api/v1/types/repo.go | 52 +++ internal/route/api/v1/types/user.go | 36 +++ internal/route/api/v1/types/webhook.go | 158 +++++++++ internal/route/api/v1/{user => }/user.go | 29 +- ...access_tokens.go => user_access_tokens.go} | 40 ++- .../api/v1/{user/email.go => user_email.go} | 31 +- .../v1/{user/follower.go => user_follower.go} | 39 ++- .../route/api/v1/{user/key.go => user_key.go} | 53 +-- internal/route/repo/branch.go | 6 +- internal/route/repo/webhook.go | 10 +- 64 files changed, 1634 insertions(+), 963 deletions(-) create mode 100644 internal/route/api/v1/adapters.go delete mode 100644 internal/route/api/v1/admin/org.go delete mode 100644 internal/route/api/v1/admin/repo.go create mode 100644 internal/route/api/v1/admin_org.go rename internal/route/api/v1/{admin/org_repo.go => admin_org_repo.go} (69%) rename internal/route/api/v1/{admin/org_team.go => admin_org_team.go} (57%) create mode 100644 internal/route/api/v1/admin_repo.go rename internal/route/api/v1/{admin/user.go => admin_user.go} (61%) delete mode 100644 internal/route/api/v1/convert/convert.go delete mode 100644 internal/route/api/v1/convert/utils.go rename internal/route/api/v1/{misc => }/markdown.go (60%) rename internal/route/api/v1/{org => }/org.go (55%) delete mode 100644 internal/route/api/v1/org/team.go create mode 100644 internal/route/api/v1/org_team.go rename internal/route/api/v1/{repo/blob.go => repo_blob.go} (95%) rename internal/route/api/v1/{repo/branch.go => repo_branch.go} (67%) rename internal/route/api/v1/{repo/collaborators.go => repo_collaborators.go} (77%) rename internal/route/api/v1/{repo/commits.go => repo_commits.go} (80%) rename internal/route/api/v1/{repo/contents.go => repo_contents.go} (96%) rename internal/route/api/v1/{repo/file.go => repo_file.go} (78%) rename internal/route/api/v1/{repo/hook.go => repo_hook.go} (84%) rename internal/route/api/v1/{repo/issue.go => repo_issue.go} (73%) rename internal/route/api/v1/{repo/issue_comment.go => repo_issue_comment.go} (77%) rename internal/route/api/v1/{repo/issue_label.go => repo_issue_label.go} (76%) rename internal/route/api/v1/{repo/key.go => repo_key.go} (77%) rename internal/route/api/v1/{repo/label.go => repo_label.go} (64%) rename internal/route/api/v1/{repo/milestone.go => repo_milestone.go} (61%) rename internal/route/api/v1/{repo/repo.go => repo_repo.go} (77%) rename internal/route/api/v1/{repo/tag.go => repo_tag.go} (61%) rename internal/route/api/v1/{repo/tree.go => repo_tree.go} (96%) create mode 100644 internal/route/api/v1/tag.go create mode 100644 internal/route/api/v1/types/commit.go create mode 100644 internal/route/api/v1/types/hook.go create mode 100644 internal/route/api/v1/types/issue.go create mode 100644 internal/route/api/v1/types/org.go create mode 100644 internal/route/api/v1/types/pull_request.go create mode 100644 internal/route/api/v1/types/repo.go create mode 100644 internal/route/api/v1/types/user.go create mode 100644 internal/route/api/v1/types/webhook.go rename internal/route/api/v1/{user => }/user.go (58%) rename internal/route/api/v1/{user/access_tokens.go => user_access_tokens.go} (67%) rename internal/route/api/v1/{user/email.go => user_email.go} (69%) rename internal/route/api/v1/{user/follower.go => user_follower.go} (71%) rename internal/route/api/v1/{user/key.go => user_key.go} (52%) diff --git a/go.mod b/go.mod index 6dc337da8..6e55803f2 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,6 @@ require ( github.com/gogs/chardet v0.0.0-20150115103509-2404f7772561 github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 github.com/gogs/git-module v1.8.6 - github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4 github.com/gogs/go-libravatar v0.0.0-20191106065024-33a75213d0a0 github.com/gogs/minwinsvc v0.0.0-20170301035411-95be6356811a github.com/google/go-github v17.0.0+incompatible diff --git a/go.sum b/go.sum index 8f8029817..1147259d5 100644 --- a/go.sum +++ b/go.sum @@ -153,8 +153,6 @@ github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 h1:yXtpJr/LV6PFu4nTLgfjQ github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk= github.com/gogs/git-module v1.8.6 h1:4Io9vWZYQyIjdIPxfKgeYZXnDKNgydc6OZTxII5xCH4= github.com/gogs/git-module v1.8.6/go.mod h1:IiMSJqi8XH62Kjqjt5Rw8IawSo+DHfM2dDjkSzWLjhs= -github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4 h1:C7NryI/RQhsIWwC2bHN601P1wJKeuQ6U/UCOYTn3Cic= -github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU= github.com/gogs/go-libravatar v0.0.0-20191106065024-33a75213d0a0 h1:K02vod+sn3M1OOkdqi2tPxN2+xESK4qyITVQ3JkGEv4= github.com/gogs/go-libravatar v0.0.0-20191106065024-33a75213d0a0/go.mod h1:Zas3BtO88pk1cwUfEYlvnl/CRwh0ybDxRWSwRjG8I3w= github.com/gogs/minwinsvc v0.0.0-20170301035411-95be6356811a h1:8DZwxETOVWIinYxDK+i6L+rMb7eGATGaakD6ZucfHVk= diff --git a/internal/database/actions.go b/internal/database/actions.go index 0aa4e1c29..e6e0a6b2b 100644 --- a/internal/database/actions.go +++ b/internal/database/actions.go @@ -12,13 +12,13 @@ import ( "github.com/cockroachdb/errors" "github.com/gogs/git-module" - api "github.com/gogs/go-gogs-client" "gorm.io/gorm" log "unknwon.dev/clog/v2" "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/lazyregexp" "gogs.io/gogs/internal/repoutil" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" "gogs.io/gogs/internal/strutil" "gogs.io/gogs/internal/testutil" "gogs.io/gogs/internal/tool" @@ -230,7 +230,7 @@ func (s *ActionsStore) MirrorSyncPush(ctx context.Context, opts MirrorSyncPushOp err = PrepareWebhooks( opts.Repo, HookEventTypePush, - &api.PushPayload{ + &apiv1types.WebhookPushPayload{ Ref: opts.RefName, Before: opts.OldCommitID, After: opts.NewCommitID, @@ -496,10 +496,10 @@ func (s *ActionsStore) CommitRepo(ctx context.Context, opts CommitRepoOptions) e err = PrepareWebhooks( opts.Repo, HookEventTypeDelete, - &api.DeletePayload{ + &apiv1types.WebhookDeletePayload{ Ref: refName, RefType: "branch", - PusherType: api.PUSHER_TYPE_USER, + PusherType: apiv1types.WebhookPusherTypeUser, Repo: apiRepo, Sender: apiPusher, }, @@ -540,7 +540,7 @@ func (s *ActionsStore) CommitRepo(ctx context.Context, opts CommitRepoOptions) e err = PrepareWebhooks( opts.Repo, HookEventTypeCreate, - &api.CreatePayload{ + &apiv1types.WebhookCreatePayload{ Ref: refName, RefType: "branch", DefaultBranch: opts.Repo.DefaultBranch, @@ -573,7 +573,7 @@ func (s *ActionsStore) CommitRepo(ctx context.Context, opts CommitRepoOptions) e err = PrepareWebhooks( opts.Repo, HookEventTypePush, - &api.PushPayload{ + &apiv1types.WebhookPushPayload{ Ref: opts.RefFullName, Before: opts.OldCommitID, After: opts.NewCommitID, @@ -635,10 +635,10 @@ func (s *ActionsStore) PushTag(ctx context.Context, opts PushTagOptions) error { err = PrepareWebhooks( opts.Repo, HookEventTypeDelete, - &api.DeletePayload{ + &apiv1types.WebhookDeletePayload{ Ref: refName, RefType: "tag", - PusherType: api.PUSHER_TYPE_USER, + PusherType: apiv1types.WebhookPusherTypeUser, Repo: apiRepo, Sender: apiPusher, }, @@ -658,7 +658,7 @@ func (s *ActionsStore) PushTag(ctx context.Context, opts PushTagOptions) error { err = PrepareWebhooks( opts.Repo, HookEventTypeCreate, - &api.CreatePayload{ + &apiv1types.WebhookCreatePayload{ Ref: refName, RefType: "tag", Sha: opts.NewCommitID, @@ -848,7 +848,7 @@ func NewPushCommits() *PushCommits { } } -func (pcs *PushCommits) APIFormat(ctx context.Context, usersStore *UsersStore, repoPath, repoURL string) ([]*api.PayloadCommit, error) { +func (pcs *PushCommits) APIFormat(ctx context.Context, usersStore *UsersStore, repoPath, repoURL string) ([]*apiv1types.WebhookPayloadCommit, error) { // NOTE: We cache query results in case there are many commits in a single push. usernameByEmail := make(map[string]string) getUsernameByEmail := func(email string) (string, error) { @@ -870,7 +870,7 @@ func (pcs *PushCommits) APIFormat(ctx context.Context, usersStore *UsersStore, r return user.Name, nil } - commits := make([]*api.PayloadCommit, len(pcs.Commits)) + commits := make([]*apiv1types.WebhookPayloadCommit, len(pcs.Commits)) for i, commit := range pcs.Commits { authorUsername, err := getUsernameByEmail(commit.AuthorEmail) if err != nil { @@ -890,16 +890,16 @@ func (pcs *PushCommits) APIFormat(ctx context.Context, usersStore *UsersStore, r } } - commits[i] = &api.PayloadCommit{ + commits[i] = &apiv1types.WebhookPayloadCommit{ ID: commit.Sha1, Message: commit.Message, URL: fmt.Sprintf("%s/commit/%s", repoURL, commit.Sha1), - Author: &api.PayloadUser{ + Author: &apiv1types.WebhookPayloadUser{ Name: commit.AuthorName, Email: commit.AuthorEmail, UserName: authorUsername, }, - Committer: &api.PayloadUser{ + Committer: &apiv1types.WebhookPayloadUser{ Name: commit.CommitterName, Email: commit.CommitterEmail, UserName: committerUsername, diff --git a/internal/database/comment.go b/internal/database/comment.go index 5e29fa48b..bea1a52f4 100644 --- a/internal/database/comment.go +++ b/internal/database/comment.go @@ -11,10 +11,9 @@ import ( log "unknwon.dev/clog/v2" "xorm.io/xorm" - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/errutil" "gogs.io/gogs/internal/markup" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" ) // CommentType defines whether a comment is just a simple comment, an action (like close) or a reference. @@ -136,8 +135,8 @@ func (c *Comment) HTMLURL() string { // This method assumes following fields have been assigned with valid values: // Required - Poster, Issue -func (c *Comment) APIFormat() *api.Comment { - return &api.Comment{ +func (c *Comment) APIFormat() *apiv1types.IssueComment { + return &apiv1types.IssueComment{ ID: c.ID, HTMLURL: c.HTMLURL(), Poster: c.Poster.APIFormat(), @@ -347,8 +346,8 @@ func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content stri } comment.Issue = issue - if err = PrepareWebhooks(repo, HookEventTypeIssueComment, &api.IssueCommentPayload{ - Action: api.HOOK_ISSUE_COMMENT_CREATED, + if err = PrepareWebhooks(repo, HookEventTypeIssueComment, &apiv1types.WebhookIssueCommentPayload{ + Action: apiv1types.WebhookIssueCommentCreated, Issue: issue.APIFormat(), Comment: comment.APIFormat(), Repository: repo.APIFormatLegacy(nil), @@ -483,12 +482,12 @@ func UpdateComment(doer *User, c *Comment, oldContent string) (err error) { if err = c.Issue.LoadAttributes(); err != nil { log.Error("Issue.LoadAttributes [issue_id: %d]: %v", c.IssueID, err) - } else if err = PrepareWebhooks(c.Issue.Repo, HookEventTypeIssueComment, &api.IssueCommentPayload{ - Action: api.HOOK_ISSUE_COMMENT_EDITED, + } else if err = PrepareWebhooks(c.Issue.Repo, HookEventTypeIssueComment, &apiv1types.WebhookIssueCommentPayload{ + Action: apiv1types.WebhookIssueCommentEdited, Issue: c.Issue.APIFormat(), Comment: c.APIFormat(), - Changes: &api.ChangesPayload{ - Body: &api.ChangesFromPayload{ + Changes: &apiv1types.WebhookChangesPayload{ + Body: &apiv1types.WebhookChangesFromPayload{ From: oldContent, }, }, @@ -538,8 +537,8 @@ func DeleteCommentByID(doer *User, id int64) error { if err = comment.Issue.LoadAttributes(); err != nil { log.Error("Issue.LoadAttributes [issue_id: %d]: %v", comment.IssueID, err) - } else if err = PrepareWebhooks(comment.Issue.Repo, HookEventTypeIssueComment, &api.IssueCommentPayload{ - Action: api.HOOK_ISSUE_COMMENT_DELETED, + } else if err = PrepareWebhooks(comment.Issue.Repo, HookEventTypeIssueComment, &apiv1types.WebhookIssueCommentPayload{ + Action: apiv1types.WebhookIssueCommentDeleted, Issue: comment.Issue.APIFormat(), Comment: comment.APIFormat(), Repository: comment.Issue.Repo.APIFormatLegacy(nil), diff --git a/internal/database/issue.go b/internal/database/issue.go index bbdbb7583..4d8af355c 100644 --- a/internal/database/issue.go +++ b/internal/database/issue.go @@ -11,11 +11,10 @@ import ( log "unknwon.dev/clog/v2" "xorm.io/xorm" - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/errutil" "gogs.io/gogs/internal/markup" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" "gogs.io/gogs/internal/tool" ) @@ -172,23 +171,23 @@ func (issue *Issue) HTMLURL() string { } // State returns string representation of issue status. -func (issue *Issue) State() api.StateType { +func (issue *Issue) State() apiv1types.IssueStateType { if issue.IsClosed { - return api.STATE_CLOSED + return apiv1types.IssueStateClosed } - return api.STATE_OPEN + return apiv1types.IssueStateOpen } // This method assumes some fields assigned with values: // Required - Poster, Labels, // Optional - Milestone, Assignee, PullRequest -func (issue *Issue) APIFormat() *api.Issue { - apiLabels := make([]*api.Label, len(issue.Labels)) +func (issue *Issue) APIFormat() *apiv1types.Issue { + apiLabels := make([]*apiv1types.IssueLabel, len(issue.Labels)) for i := range issue.Labels { apiLabels[i] = issue.Labels[i].APIFormat() } - apiIssue := &api.Issue{ + apiIssue := &apiv1types.Issue{ ID: issue.ID, Index: issue.Index, Poster: issue.Poster.APIFormat(), @@ -208,7 +207,7 @@ func (issue *Issue) APIFormat() *api.Issue { apiIssue.Assignee = issue.Assignee.APIFormat() } if issue.IsPull { - apiIssue.PullRequest = &api.PullRequestMeta{ + apiIssue.PullRequest = &apiv1types.PullRequestMeta{ HasMerged: issue.PullRequest.HasMerged, } if issue.PullRequest.HasMerged { @@ -246,16 +245,16 @@ func (issue *Issue) sendLabelUpdatedWebhook(doer *User) { log.Error("LoadIssue: %v", err) return } - err = PrepareWebhooks(issue.Repo, HookEventTypePullRequest, &api.PullRequestPayload{ - Action: api.HOOK_ISSUE_LABEL_UPDATED, + err = PrepareWebhooks(issue.Repo, HookEventTypePullRequest, &apiv1types.WebhookPullRequestPayload{ + Action: apiv1types.WebhookIssueLabelUpdated, Index: issue.Index, PullRequest: issue.PullRequest.APIFormat(), Repository: issue.Repo.APIFormatLegacy(nil), Sender: doer.APIFormat(), }) } else { - err = PrepareWebhooks(issue.Repo, HookEventTypeIssues, &api.IssuesPayload{ - Action: api.HOOK_ISSUE_LABEL_UPDATED, + err = PrepareWebhooks(issue.Repo, HookEventTypeIssues, &apiv1types.WebhookIssuesPayload{ + Action: apiv1types.WebhookIssueLabelUpdated, Index: issue.Index, Issue: issue.APIFormat(), Repository: issue.Repo.APIFormatLegacy(nil), @@ -359,16 +358,16 @@ func (issue *Issue) ClearLabels(doer *User) (err error) { log.Error("LoadIssue: %v", err) return err } - err = PrepareWebhooks(issue.Repo, HookEventTypePullRequest, &api.PullRequestPayload{ - Action: api.HOOK_ISSUE_LABEL_CLEARED, + err = PrepareWebhooks(issue.Repo, HookEventTypePullRequest, &apiv1types.WebhookPullRequestPayload{ + Action: apiv1types.WebhookIssueLabelCleared, Index: issue.Index, PullRequest: issue.PullRequest.APIFormat(), Repository: issue.Repo.APIFormatLegacy(nil), Sender: doer.APIFormat(), }) } else { - err = PrepareWebhooks(issue.Repo, HookEventTypeIssues, &api.IssuesPayload{ - Action: api.HOOK_ISSUE_LABEL_CLEARED, + err = PrepareWebhooks(issue.Repo, HookEventTypeIssues, &apiv1types.WebhookIssuesPayload{ + Action: apiv1types.WebhookIssueLabelCleared, Index: issue.Index, Issue: issue.APIFormat(), Repository: issue.Repo.APIFormatLegacy(nil), @@ -487,29 +486,29 @@ func (issue *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (e if issue.IsPull { // Merge pull request calls issue.changeStatus so we need to handle separately. issue.PullRequest.Issue = issue - apiPullRequest := &api.PullRequestPayload{ + apiPullRequest := &apiv1types.WebhookPullRequestPayload{ Index: issue.Index, PullRequest: issue.PullRequest.APIFormat(), Repository: repo.APIFormatLegacy(nil), Sender: doer.APIFormat(), } if isClosed { - apiPullRequest.Action = api.HOOK_ISSUE_CLOSED + apiPullRequest.Action = apiv1types.WebhookIssueClosed } else { - apiPullRequest.Action = api.HOOK_ISSUE_REOPENED + apiPullRequest.Action = apiv1types.WebhookIssueReopened } err = PrepareWebhooks(repo, HookEventTypePullRequest, apiPullRequest) } else { - apiIssues := &api.IssuesPayload{ + apiIssues := &apiv1types.WebhookIssuesPayload{ Index: issue.Index, Issue: issue.APIFormat(), Repository: repo.APIFormatLegacy(nil), Sender: doer.APIFormat(), } if isClosed { - apiIssues.Action = api.HOOK_ISSUE_CLOSED + apiIssues.Action = apiv1types.WebhookIssueClosed } else { - apiIssues.Action = api.HOOK_ISSUE_REOPENED + apiIssues.Action = apiv1types.WebhookIssueReopened } err = PrepareWebhooks(repo, HookEventTypeIssues, apiIssues) } @@ -529,12 +528,12 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) { if issue.IsPull { issue.PullRequest.Issue = issue - err = PrepareWebhooks(issue.Repo, HookEventTypePullRequest, &api.PullRequestPayload{ - Action: api.HOOK_ISSUE_EDITED, + err = PrepareWebhooks(issue.Repo, HookEventTypePullRequest, &apiv1types.WebhookPullRequestPayload{ + Action: apiv1types.WebhookIssueEdited, Index: issue.Index, PullRequest: issue.PullRequest.APIFormat(), - Changes: &api.ChangesPayload{ - Title: &api.ChangesFromPayload{ + Changes: &apiv1types.WebhookChangesPayload{ + Title: &apiv1types.WebhookChangesFromPayload{ From: oldTitle, }, }, @@ -542,12 +541,12 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) { Sender: doer.APIFormat(), }) } else { - err = PrepareWebhooks(issue.Repo, HookEventTypeIssues, &api.IssuesPayload{ - Action: api.HOOK_ISSUE_EDITED, + err = PrepareWebhooks(issue.Repo, HookEventTypeIssues, &apiv1types.WebhookIssuesPayload{ + Action: apiv1types.WebhookIssueEdited, Index: issue.Index, Issue: issue.APIFormat(), - Changes: &api.ChangesPayload{ - Title: &api.ChangesFromPayload{ + Changes: &apiv1types.WebhookChangesPayload{ + Title: &apiv1types.WebhookChangesFromPayload{ From: oldTitle, }, }, @@ -571,12 +570,12 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) { if issue.IsPull { issue.PullRequest.Issue = issue - err = PrepareWebhooks(issue.Repo, HookEventTypePullRequest, &api.PullRequestPayload{ - Action: api.HOOK_ISSUE_EDITED, + err = PrepareWebhooks(issue.Repo, HookEventTypePullRequest, &apiv1types.WebhookPullRequestPayload{ + Action: apiv1types.WebhookIssueEdited, Index: issue.Index, PullRequest: issue.PullRequest.APIFormat(), - Changes: &api.ChangesPayload{ - Body: &api.ChangesFromPayload{ + Changes: &apiv1types.WebhookChangesPayload{ + Body: &apiv1types.WebhookChangesFromPayload{ From: oldContent, }, }, @@ -584,12 +583,12 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) { Sender: doer.APIFormat(), }) } else { - err = PrepareWebhooks(issue.Repo, HookEventTypeIssues, &api.IssuesPayload{ - Action: api.HOOK_ISSUE_EDITED, + err = PrepareWebhooks(issue.Repo, HookEventTypeIssues, &apiv1types.WebhookIssuesPayload{ + Action: apiv1types.WebhookIssueEdited, Index: issue.Index, Issue: issue.APIFormat(), - Changes: &api.ChangesPayload{ - Body: &api.ChangesFromPayload{ + Changes: &apiv1types.WebhookChangesPayload{ + Body: &apiv1types.WebhookChangesFromPayload{ From: oldContent, }, }, @@ -620,29 +619,29 @@ func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) { isRemoveAssignee := err != nil if issue.IsPull { issue.PullRequest.Issue = issue - apiPullRequest := &api.PullRequestPayload{ + apiPullRequest := &apiv1types.WebhookPullRequestPayload{ Index: issue.Index, PullRequest: issue.PullRequest.APIFormat(), Repository: issue.Repo.APIFormatLegacy(nil), Sender: doer.APIFormat(), } if isRemoveAssignee { - apiPullRequest.Action = api.HOOK_ISSUE_UNASSIGNED + apiPullRequest.Action = apiv1types.WebhookIssueUnassigned } else { - apiPullRequest.Action = api.HOOK_ISSUE_ASSIGNED + apiPullRequest.Action = apiv1types.WebhookIssueAssigned } err = PrepareWebhooks(issue.Repo, HookEventTypePullRequest, apiPullRequest) } else { - apiIssues := &api.IssuesPayload{ + apiIssues := &apiv1types.WebhookIssuesPayload{ Index: issue.Index, Issue: issue.APIFormat(), Repository: issue.Repo.APIFormatLegacy(nil), Sender: doer.APIFormat(), } if isRemoveAssignee { - apiIssues.Action = api.HOOK_ISSUE_UNASSIGNED + apiIssues.Action = apiv1types.WebhookIssueUnassigned } else { - apiIssues.Action = api.HOOK_ISSUE_ASSIGNED + apiIssues.Action = apiv1types.WebhookIssueAssigned } err = PrepareWebhooks(issue.Repo, HookEventTypeIssues, apiIssues) } @@ -789,8 +788,8 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string) log.Error("MailParticipants: %v", err) } - if err = PrepareWebhooks(repo, HookEventTypeIssues, &api.IssuesPayload{ - Action: api.HOOK_ISSUE_OPENED, + if err = PrepareWebhooks(repo, HookEventTypeIssues, &apiv1types.WebhookIssuesPayload{ + Action: apiv1types.WebhookIssueOpened, Index: issue.Index, Issue: issue.APIFormat(), Repository: repo.APIFormatLegacy(nil), diff --git a/internal/database/issue_label.go b/internal/database/issue_label.go index 5f4dc6f73..331ccc718 100644 --- a/internal/database/issue_label.go +++ b/internal/database/issue_label.go @@ -9,10 +9,10 @@ import ( "xorm.io/xorm" "github.com/cockroachdb/errors" - api "github.com/gogs/go-gogs-client" "gogs.io/gogs/internal/errutil" "gogs.io/gogs/internal/lazyregexp" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" "gogs.io/gogs/internal/tool" ) @@ -62,8 +62,8 @@ type Label struct { IsChecked bool `xorm:"-" json:"-" gorm:"-"` } -func (l *Label) APIFormat() *api.Label { - return &api.Label{ +func (l *Label) APIFormat() *apiv1types.IssueLabel { + return &apiv1types.IssueLabel{ ID: l.ID, Name: l.Name, Color: strings.TrimLeft(l.Color, "#"), diff --git a/internal/database/milestone.go b/internal/database/milestone.go index a7d1492e5..6e81aa23f 100644 --- a/internal/database/milestone.go +++ b/internal/database/milestone.go @@ -8,10 +8,10 @@ import ( "xorm.io/xorm" "github.com/cockroachdb/errors" - api "github.com/gogs/go-gogs-client" "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/errutil" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" ) // Milestone represents a milestone of repository. @@ -72,19 +72,19 @@ func (m *Milestone) AfterSet(colName string, _ xorm.Cell) { } // State returns string representation of milestone status. -func (m *Milestone) State() api.StateType { +func (m *Milestone) State() apiv1types.IssueStateType { if m.IsClosed { - return api.STATE_CLOSED + return apiv1types.IssueStateClosed } - return api.STATE_OPEN + return apiv1types.IssueStateOpen } func (m *Milestone) ChangeStatus(isClosed bool) error { return ChangeMilestoneStatus(m, isClosed) } -func (m *Milestone) APIFormat() *api.Milestone { - apiMilestone := &api.Milestone{ +func (m *Milestone) APIFormat() *apiv1types.IssueMilestone { + apiMilestone := &apiv1types.IssueMilestone{ ID: m.ID, State: m.State(), Title: m.Name, @@ -343,11 +343,11 @@ func ChangeMilestoneAssign(doer *User, issue *Issue, oldMilestoneID int64) (err return errors.Newf("commit: %v", err) } - var hookAction api.HookIssueAction + var hookAction apiv1types.WebhookIssueAction if issue.MilestoneID > 0 { - hookAction = api.HOOK_ISSUE_MILESTONED + hookAction = apiv1types.WebhookIssueMilestoned } else { - hookAction = api.HOOK_ISSUE_DEMILESTONED + hookAction = apiv1types.WebhookIssueDemilestoned } if issue.IsPull { @@ -356,7 +356,7 @@ func ChangeMilestoneAssign(doer *User, issue *Issue, oldMilestoneID int64) (err log.Error("LoadIssue: %v", err) return err } - err = PrepareWebhooks(issue.Repo, HookEventTypePullRequest, &api.PullRequestPayload{ + err = PrepareWebhooks(issue.Repo, HookEventTypePullRequest, &apiv1types.WebhookPullRequestPayload{ Action: hookAction, Index: issue.Index, PullRequest: issue.PullRequest.APIFormat(), @@ -364,7 +364,7 @@ func ChangeMilestoneAssign(doer *User, issue *Issue, oldMilestoneID int64) (err Sender: doer.APIFormat(), }) } else { - err = PrepareWebhooks(issue.Repo, HookEventTypeIssues, &api.IssuesPayload{ + err = PrepareWebhooks(issue.Repo, HookEventTypeIssues, &apiv1types.WebhookIssuesPayload{ Action: hookAction, Index: issue.Index, Issue: issue.APIFormat(), diff --git a/internal/database/pull.go b/internal/database/pull.go index 1d17b1114..2d8165df8 100644 --- a/internal/database/pull.go +++ b/internal/database/pull.go @@ -13,12 +13,12 @@ import ( "xorm.io/xorm" "github.com/gogs/git-module" - api "github.com/gogs/go-gogs-client" "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/errutil" "gogs.io/gogs/internal/osutil" "gogs.io/gogs/internal/process" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" "gogs.io/gogs/internal/sync" ) @@ -127,11 +127,11 @@ func (pr *PullRequest) LoadIssue() (err error) { // This method assumes following fields have been assigned with valid values: // Required - Issue, BaseRepo // Optional - HeadRepo, Merger -func (pr *PullRequest) APIFormat() *api.PullRequest { +func (pr *PullRequest) APIFormat() *apiv1types.PullRequest { // In case of head repo has been deleted. - var apiHeadRepo *api.Repository + var apiHeadRepo *apiv1types.Repository if pr.HeadRepo == nil { - apiHeadRepo = &api.Repository{ + apiHeadRepo = &apiv1types.Repository{ Name: "deleted", } } else { @@ -139,7 +139,7 @@ func (pr *PullRequest) APIFormat() *api.PullRequest { } apiIssue := pr.Issue.APIFormat() - apiPullRequest := &api.PullRequest{ + apiPullRequest := &apiv1types.PullRequest{ ID: pr.ID, Index: pr.Index, Poster: apiIssue.Poster, @@ -341,8 +341,8 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle log.Error("LoadAttributes: %v", err) return nil } - if err = PrepareWebhooks(pr.Issue.Repo, HookEventTypePullRequest, &api.PullRequestPayload{ - Action: api.HOOK_ISSUE_CLOSED, + if err = PrepareWebhooks(pr.Issue.Repo, HookEventTypePullRequest, &apiv1types.WebhookPullRequestPayload{ + Action: apiv1types.WebhookIssueClosed, Index: pr.Index, PullRequest: pr.APIFormat(), Repository: pr.Issue.Repo.APIFormatLegacy(nil), @@ -376,7 +376,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle return nil } - p := &api.PushPayload{ + p := &apiv1types.WebhookPushPayload{ Ref: git.RefsHeads + pr.BaseBranch, Before: pr.MergeBase, After: mergeCommit.ID.String(), @@ -500,8 +500,8 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str pr.Issue = pull pull.PullRequest = pr - if err = PrepareWebhooks(repo, HookEventTypePullRequest, &api.PullRequestPayload{ - Action: api.HOOK_ISSUE_OPENED, + if err = PrepareWebhooks(repo, HookEventTypePullRequest, &apiv1types.WebhookPullRequestPayload{ + Action: apiv1types.WebhookIssueOpened, Index: pull.Index, PullRequest: pr.APIFormat(), Repository: repo.APIFormatLegacy(nil), @@ -792,8 +792,8 @@ func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool log.Error("LoadAttributes: %v", err) continue } - if err = PrepareWebhooks(pr.Issue.Repo, HookEventTypePullRequest, &api.PullRequestPayload{ - Action: api.HOOK_ISSUE_SYNCHRONIZED, + if err = PrepareWebhooks(pr.Issue.Repo, HookEventTypePullRequest, &apiv1types.WebhookPullRequestPayload{ + Action: apiv1types.WebhookIssueSynchronized, Index: pr.Issue.Index, PullRequest: pr.Issue.PullRequest.APIFormat(), Repository: pr.Issue.Repo.APIFormatLegacy(nil), diff --git a/internal/database/release.go b/internal/database/release.go index 377cf6f42..ae56c8362 100644 --- a/internal/database/release.go +++ b/internal/database/release.go @@ -11,10 +11,10 @@ import ( "github.com/cockroachdb/errors" "github.com/gogs/git-module" - api "github.com/gogs/go-gogs-client" "gogs.io/gogs/internal/errutil" "gogs.io/gogs/internal/process" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" ) // Release represents a release of repository. @@ -90,8 +90,8 @@ func (r *Release) LoadAttributes() error { // This method assumes some fields assigned with values: // Required - Publisher -func (r *Release) APIFormat() *api.Release { - return &api.Release{ +func (r *Release) APIFormat() *apiv1types.RepositoryRelease { + return &apiv1types.RepositoryRelease{ ID: r.ID, TagName: r.TagName, TargetCommitish: r.Target, @@ -147,8 +147,8 @@ func createTag(gitRepo *git.Repository, r *Release) error { } func (r *Release) preparePublishWebhooks() { - if err := PrepareWebhooks(r.Repo, HookEventTypeRelease, &api.ReleasePayload{ - Action: api.HOOK_RELEASE_PUBLISHED, + if err := PrepareWebhooks(r.Repo, HookEventTypeRelease, &apiv1types.WebhookReleasePayload{ + Action: apiv1types.WebhookReleasePublished, Release: r.APIFormat(), Repository: r.Repo.APIFormatLegacy(nil), Sender: r.Publisher.APIFormat(), diff --git a/internal/database/repo.go b/internal/database/repo.go index b5384160b..54ae75c79 100644 --- a/internal/database/repo.go +++ b/internal/database/repo.go @@ -26,7 +26,6 @@ import ( "xorm.io/xorm" "github.com/gogs/git-module" - api "github.com/gogs/go-gogs-client" embedConf "gogs.io/gogs/conf" "gogs.io/gogs/internal/avatar" @@ -37,6 +36,7 @@ import ( "gogs.io/gogs/internal/osutil" "gogs.io/gogs/internal/process" "gogs.io/gogs/internal/repoutil" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" "gogs.io/gogs/internal/semverutil" "gogs.io/gogs/internal/strutil" "gogs.io/gogs/internal/sync" @@ -377,9 +377,9 @@ func (r *Repository) DeleteAvatar() error { // Arguments that are allowed to be nil: permission // // Deprecated: Use APIFormat instead. -func (r *Repository) APIFormatLegacy(permission *api.Permission, user ...*User) *api.Repository { +func (r *Repository) APIFormatLegacy(permission *apiv1types.RepositoryPermission, user ...*User) *apiv1types.Repository { cloneLink := r.CloneLink() - apiRepo := &api.Repository{ + apiRepo := &apiv1types.Repository{ ID: r.ID, Owner: r.Owner.APIFormat(), Name: r.Name, @@ -406,7 +406,7 @@ func (r *Repository) APIFormatLegacy(permission *api.Permission, user ...*User) // AvatarUrl: r.AvatarLink(), } if r.IsFork { - p := &api.Permission{Pull: true} + p := &apiv1types.RepositoryPermission{Pull: true} if len(user) != 0 { accessMode := Handle.Permissions().AccessMode( context.TODO(), @@ -2609,7 +2609,7 @@ func ForkRepository(doer, owner *User, baseRepo *Repository, name, desc string) if err = repo.UpdateSize(); err != nil { log.Error("UpdateSize [repo_id: %d]: %v", repo.ID, err) } - if err = PrepareWebhooks(baseRepo, HookEventTypeFork, &api.ForkPayload{ + if err = PrepareWebhooks(baseRepo, HookEventTypeFork, &apiv1types.WebhookForkPayload{ Forkee: repo.APIFormatLegacy(nil), Repo: baseRepo.APIFormatLegacy(nil), Sender: doer.APIFormat(), diff --git a/internal/database/repo_collaboration.go b/internal/database/repo_collaboration.go index 8c59f0742..2bfc94a03 100644 --- a/internal/database/repo_collaboration.go +++ b/internal/database/repo_collaboration.go @@ -1,10 +1,10 @@ package database import ( + "github.com/cockroachdb/errors" log "unknwon.dev/clog/v2" - "github.com/cockroachdb/errors" - api "github.com/gogs/go-gogs-client" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" ) // Collaboration represent the relation between an individual and a repository. @@ -87,10 +87,10 @@ type Collaborator struct { Collaboration *Collaboration } -func (c *Collaborator) APIFormat() *api.Collaborator { - return &api.Collaborator{ +func (c *Collaborator) APIFormat() *apiv1types.RepositoryCollaborator { + return &apiv1types.RepositoryCollaborator{ User: c.User.APIFormat(), - Permissions: api.Permission{ + Permissions: apiv1types.RepositoryPermission{ Admin: c.Collaboration.Mode >= AccessModeAdmin, Push: c.Collaboration.Mode >= AccessModeWrite, Pull: c.Collaboration.Mode >= AccessModeRead, diff --git a/internal/database/repositories.go b/internal/database/repositories.go index 3e092d2aa..8edb8e78a 100644 --- a/internal/database/repositories.go +++ b/internal/database/repositories.go @@ -7,11 +7,11 @@ import ( "time" "github.com/cockroachdb/errors" - api "github.com/gogs/go-gogs-client" "gorm.io/gorm" "gogs.io/gogs/internal/errutil" "gogs.io/gogs/internal/repoutil" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" ) // BeforeCreate implements the GORM create hook. @@ -36,19 +36,19 @@ func (r *Repository) AfterFind(_ *gorm.DB) error { } type RepositoryAPIFormatOptions struct { - Permission *api.Permission - Parent *api.Repository + Permission *apiv1types.RepositoryPermission + Parent *apiv1types.Repository } // APIFormat returns the API format of a repository. -func (r *Repository) APIFormat(owner *User, opts ...RepositoryAPIFormatOptions) *api.Repository { +func (r *Repository) APIFormat(owner *User, opts ...RepositoryAPIFormatOptions) *apiv1types.Repository { var opt RepositoryAPIFormatOptions if len(opts) > 0 { opt = opts[0] } cloneLink := repoutil.NewCloneLink(owner.Name, r.Name, false) - return &api.Repository{ + return &apiv1types.Repository{ ID: r.ID, Owner: owner.APIFormat(), Name: r.Name, diff --git a/internal/database/users.go b/internal/database/users.go index e50d9c4e0..11cb3ed97 100644 --- a/internal/database/users.go +++ b/internal/database/users.go @@ -11,7 +11,6 @@ import ( "github.com/cockroachdb/errors" "github.com/go-macaron/binding" - api "github.com/gogs/go-gogs-client" "gorm.io/gorm" log "unknwon.dev/clog/v2" @@ -23,6 +22,7 @@ import ( "gogs.io/gogs/internal/markup" "gogs.io/gogs/internal/osutil" "gogs.io/gogs/internal/repoutil" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" "gogs.io/gogs/internal/strutil" "gogs.io/gogs/internal/tool" "gogs.io/gogs/internal/userutil" @@ -1297,14 +1297,14 @@ func (u *User) IsOrganization() bool { } // APIFormat returns the API format of a user. -func (u *User) APIFormat() *api.User { - return &api.User{ +func (u *User) APIFormat() *apiv1types.User { + return &apiv1types.User{ ID: u.ID, UserName: u.Name, Login: u.Name, FullName: u.FullName, Email: u.Email, - AvatarUrl: u.AvatarURL(), + AvatarURL: u.AvatarURL(), } } diff --git a/internal/database/webhook.go b/internal/database/webhook.go index 887d3f939..f604f78b0 100644 --- a/internal/database/webhook.go +++ b/internal/database/webhook.go @@ -17,12 +17,11 @@ import ( log "unknwon.dev/clog/v2" "xorm.io/xorm" - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/errutil" "gogs.io/gogs/internal/httplib" "gogs.io/gogs/internal/netutil" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" "gogs.io/gogs/internal/sync" "gogs.io/gogs/internal/testutil" ) @@ -430,21 +429,21 @@ type HookResponse struct { // HookTask represents a hook task. type HookTask struct { - ID int64 - RepoID int64 `xorm:"INDEX"` - HookID int64 - UUID string - Type HookTaskType - URL string `xorm:"TEXT"` - Signature string `xorm:"TEXT"` - api.Payloader `xorm:"-" json:"-" gorm:"-"` - PayloadContent string `xorm:"TEXT"` - ContentType HookContentType - EventType HookEventType - IsSSL bool - IsDelivered bool - Delivered int64 - DeliveredString string `xorm:"-" json:"-" gorm:"-"` + ID int64 + RepoID int64 `xorm:"INDEX"` + HookID int64 + UUID string + Type HookTaskType + URL string `xorm:"TEXT"` + Signature string `xorm:"TEXT"` + apiv1types.WebhookPayloader `xorm:"-" json:"-" gorm:"-"` + PayloadContent string `xorm:"TEXT"` + ContentType HookContentType + EventType HookEventType + IsSSL bool + IsDelivered bool + Delivered int64 + DeliveredString string `xorm:"-" json:"-" gorm:"-"` // History info. IsSucceed bool @@ -559,12 +558,12 @@ func UpdateHookTask(t *HookTask) error { } // prepareHookTasks adds list of webhooks to task queue. -func prepareHookTasks(e Engine, repo *Repository, event HookEventType, p api.Payloader, webhooks []*Webhook) (err error) { +func prepareHookTasks(e Engine, repo *Repository, event HookEventType, p apiv1types.WebhookPayloader, webhooks []*Webhook) (err error) { if len(webhooks) == 0 { return nil } - var payloader api.Payloader + var payloader apiv1types.WebhookPayloader for _, w := range webhooks { switch event { case HookEventTypeCreate: @@ -634,15 +633,15 @@ func prepareHookTasks(e Engine, repo *Repository, event HookEventType, p api.Pay } if err = createHookTask(e, &HookTask{ - RepoID: repo.ID, - HookID: w.ID, - Type: w.HookTaskType, - URL: w.URL, - Signature: signature, - Payloader: payloader, - ContentType: w.ContentType, - EventType: event, - IsSSL: w.IsSSL, + RepoID: repo.ID, + HookID: w.ID, + Type: w.HookTaskType, + URL: w.URL, + Signature: signature, + WebhookPayloader: payloader, + ContentType: w.ContentType, + EventType: event, + IsSSL: w.IsSSL, }); err != nil { return errors.Newf("createHookTask: %v", err) } @@ -655,7 +654,7 @@ func prepareHookTasks(e Engine, repo *Repository, event HookEventType, p api.Pay return nil } -func prepareWebhooks(e Engine, repo *Repository, event HookEventType, p api.Payloader) error { +func prepareWebhooks(e Engine, repo *Repository, event HookEventType, p apiv1types.WebhookPayloader) error { webhooks, err := getActiveWebhooksByRepoID(e, repo.ID) if err != nil { return errors.Newf("getActiveWebhooksByRepoID [%d]: %v", repo.ID, err) @@ -674,7 +673,7 @@ func prepareWebhooks(e Engine, repo *Repository, event HookEventType, p api.Payl } // PrepareWebhooks adds all active webhooks to task queue. -func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) error { +func PrepareWebhooks(repo *Repository, event HookEventType, p apiv1types.WebhookPayloader) error { // NOTE: To prevent too many cascading changes in a single refactoring PR, we // choose to ignore this function in tests. if x == nil && testutil.InTest { @@ -684,7 +683,7 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err } // TestWebhook adds the test webhook matches the ID to task queue. -func TestWebhook(repo *Repository, event HookEventType, p api.Payloader, webhookID int64) error { +func TestWebhook(repo *Repository, event HookEventType, p apiv1types.WebhookPayloader, webhookID int64) error { webhook, err := GetWebhookOfRepoByID(repo.ID, webhookID) if err != nil { return errors.Newf("GetWebhookOfRepoByID [repo_id: %d, id: %d]: %v", repo.ID, webhookID, err) diff --git a/internal/database/webhook_dingtalk.go b/internal/database/webhook_dingtalk.go index 8a1a4fa9f..bdc724235 100644 --- a/internal/database/webhook_dingtalk.go +++ b/internal/database/webhook_dingtalk.go @@ -6,9 +6,9 @@ import ( "strings" "github.com/cockroachdb/errors" - "github.com/gogs/git-module" - api "github.com/gogs/go-gogs-client" + + apiv1types "gogs.io/gogs/internal/route/api/v1/types" ) const ( @@ -55,31 +55,31 @@ func NewDingtalkActionCard(singleTitle, singleURL string) DingtalkActionCard { } // TODO: add content -func GetDingtalkPayload(p api.Payloader, event HookEventType) (payload *DingtalkPayload, err error) { +func GetDingtalkPayload(p apiv1types.WebhookPayloader, event HookEventType) (payload *DingtalkPayload, err error) { switch event { case HookEventTypeCreate: - payload = getDingtalkCreatePayload(p.(*api.CreatePayload)) + payload = getDingtalkCreatePayload(p.(*apiv1types.WebhookCreatePayload)) case HookEventTypeDelete: - payload = getDingtalkDeletePayload(p.(*api.DeletePayload)) + payload = getDingtalkDeletePayload(p.(*apiv1types.WebhookDeletePayload)) case HookEventTypeFork: - payload = getDingtalkForkPayload(p.(*api.ForkPayload)) + payload = getDingtalkForkPayload(p.(*apiv1types.WebhookForkPayload)) case HookEventTypePush: - payload = getDingtalkPushPayload(p.(*api.PushPayload)) + payload = getDingtalkPushPayload(p.(*apiv1types.WebhookPushPayload)) case HookEventTypeIssues: - payload = getDingtalkIssuesPayload(p.(*api.IssuesPayload)) + payload = getDingtalkIssuesPayload(p.(*apiv1types.WebhookIssuesPayload)) case HookEventTypeIssueComment: - payload = getDingtalkIssueCommentPayload(p.(*api.IssueCommentPayload)) + payload = getDingtalkIssueCommentPayload(p.(*apiv1types.WebhookIssueCommentPayload)) case HookEventTypePullRequest: - payload = getDingtalkPullRequestPayload(p.(*api.PullRequestPayload)) + payload = getDingtalkPullRequestPayload(p.(*apiv1types.WebhookPullRequestPayload)) case HookEventTypeRelease: - payload = getDingtalkReleasePayload(p.(*api.ReleasePayload)) + payload = getDingtalkReleasePayload(p.(*apiv1types.WebhookReleasePayload)) default: return nil, errors.Errorf("unexpected event %q", event) } return payload, nil } -func getDingtalkCreatePayload(p *api.CreatePayload) *DingtalkPayload { +func getDingtalkCreatePayload(p *apiv1types.WebhookCreatePayload) *DingtalkPayload { refName := git.RefShortName(p.Ref) refType := strings.Title(p.RefType) @@ -94,7 +94,7 @@ func getDingtalkCreatePayload(p *api.CreatePayload) *DingtalkPayload { } } -func getDingtalkDeletePayload(p *api.DeletePayload) *DingtalkPayload { +func getDingtalkDeletePayload(p *apiv1types.WebhookDeletePayload) *DingtalkPayload { refName := git.RefShortName(p.Ref) refType := strings.Title(p.RefType) @@ -109,7 +109,7 @@ func getDingtalkDeletePayload(p *api.DeletePayload) *DingtalkPayload { } } -func getDingtalkForkPayload(p *api.ForkPayload) *DingtalkPayload { +func getDingtalkForkPayload(p *apiv1types.WebhookForkPayload) *DingtalkPayload { actionCard := NewDingtalkActionCard("View Fork", p.Forkee.HTMLURL) actionCard.Text += "# Repo Fork Event" actionCard.Text += "\n- From Repo: **" + MarkdownLinkFormatter(p.Repo.HTMLURL, p.Repo.Name) + "**" @@ -121,7 +121,7 @@ func getDingtalkForkPayload(p *api.ForkPayload) *DingtalkPayload { } } -func getDingtalkPushPayload(p *api.PushPayload) *DingtalkPayload { +func getDingtalkPushPayload(p *apiv1types.WebhookPushPayload) *DingtalkPayload { refName := git.RefShortName(p.Ref) pusher := p.Pusher.FullName @@ -150,7 +150,7 @@ func getDingtalkPushPayload(p *api.PushPayload) *DingtalkPayload { } } -func getDingtalkIssuesPayload(p *api.IssuesPayload) *DingtalkPayload { +func getDingtalkIssuesPayload(p *apiv1types.WebhookIssuesPayload) *DingtalkPayload { issueName := fmt.Sprintf("#%d %s", p.Index, p.Issue.Title) issueURL := fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Index) @@ -159,11 +159,11 @@ func getDingtalkIssuesPayload(p *api.IssuesPayload) *DingtalkPayload { actionCard.Text += "\n- Issue: **" + MarkdownLinkFormatter(issueURL, issueName) + "**" switch p.Action { - case api.HOOK_ISSUE_ASSIGNED: + case apiv1types.WebhookIssueAssigned: actionCard.Text += "\n- New Assignee: **" + p.Issue.Assignee.UserName + "**" - case api.HOOK_ISSUE_MILESTONED: + case apiv1types.WebhookIssueMilestoned: actionCard.Text += "\n- New Milestone: **" + p.Issue.Milestone.Title + "**" - case api.HOOK_ISSUE_LABEL_UPDATED: + case apiv1types.WebhookIssueLabelUpdated: if len(p.Issue.Labels) > 0 { labels := make([]string, len(p.Issue.Labels)) for i, label := range p.Issue.Labels { @@ -185,10 +185,10 @@ func getDingtalkIssuesPayload(p *api.IssuesPayload) *DingtalkPayload { } } -func getDingtalkIssueCommentPayload(p *api.IssueCommentPayload) *DingtalkPayload { +func getDingtalkIssueCommentPayload(p *apiv1types.WebhookIssueCommentPayload) *DingtalkPayload { issueName := fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title) commentURL := fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index) - if p.Action != api.HOOK_ISSUE_COMMENT_DELETED { + if p.Action != apiv1types.WebhookIssueCommentDeleted { commentURL += "#" + CommentHashTag(p.Comment.ID) } @@ -206,9 +206,9 @@ func getDingtalkIssueCommentPayload(p *api.IssueCommentPayload) *DingtalkPayload } } -func getDingtalkPullRequestPayload(p *api.PullRequestPayload) *DingtalkPayload { +func getDingtalkPullRequestPayload(p *apiv1types.WebhookPullRequestPayload) *DingtalkPayload { title := "# Pull Request " + strings.Title(string(p.Action)) - if p.Action == api.HOOK_ISSUE_CLOSED && p.PullRequest.HasMerged { + if p.Action == apiv1types.WebhookIssueClosed && p.PullRequest.HasMerged { title = "# Pull Request Merged" } @@ -216,11 +216,11 @@ func getDingtalkPullRequestPayload(p *api.PullRequestPayload) *DingtalkPayload { content := "- PR: " + MarkdownLinkFormatter(pullRequestURL, fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title)) switch p.Action { - case api.HOOK_ISSUE_ASSIGNED: + case apiv1types.WebhookIssueAssigned: content += "\n- New Assignee: **" + p.PullRequest.Assignee.UserName + "**" - case api.HOOK_ISSUE_MILESTONED: + case apiv1types.WebhookIssueMilestoned: content += "\n- New Milestone: *" + p.PullRequest.Milestone.Title + "*" - case api.HOOK_ISSUE_LABEL_UPDATED: + case apiv1types.WebhookIssueLabelUpdated: labels := make([]string, len(p.PullRequest.Labels)) for i, label := range p.PullRequest.Labels { labels[i] = "**" + label.Name + "**" @@ -231,7 +231,7 @@ func getDingtalkPullRequestPayload(p *api.PullRequestPayload) *DingtalkPayload { actionCard := NewDingtalkActionCard("View Pull Request", pullRequestURL) actionCard.Text += title + "\n" + content - if p.Action == api.HOOK_ISSUE_OPENED || p.Action == api.HOOK_ISSUE_EDITED { + if p.Action == apiv1types.WebhookIssueOpened || p.Action == apiv1types.WebhookIssueEdited { actionCard.Text += "\n> " + p.PullRequest.Body } @@ -241,7 +241,7 @@ func getDingtalkPullRequestPayload(p *api.PullRequestPayload) *DingtalkPayload { } } -func getDingtalkReleasePayload(p *api.ReleasePayload) *DingtalkPayload { +func getDingtalkReleasePayload(p *apiv1types.WebhookReleasePayload) *DingtalkPayload { releaseURL := p.Repository.HTMLURL + "/src/" + p.Release.TagName author := p.Release.Author.FullName diff --git a/internal/database/webhook_discord.go b/internal/database/webhook_discord.go index e9b521696..f16eac2c3 100644 --- a/internal/database/webhook_discord.go +++ b/internal/database/webhook_discord.go @@ -7,11 +7,10 @@ import ( "strings" "github.com/cockroachdb/errors" - "github.com/gogs/git-module" - api "github.com/gogs/go-gogs-client" "gogs.io/gogs/internal/conf" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" ) type DiscordEmbedFooterObject struct { @@ -67,7 +66,7 @@ func DiscordSHALinkFormatter(url, text string) string { } // getDiscordCreatePayload composes Discord payload for create new branch or tag. -func getDiscordCreatePayload(p *api.CreatePayload) *DiscordPayload { +func getDiscordCreatePayload(p *apiv1types.WebhookCreatePayload) *DiscordPayload { refName := git.RefShortName(p.Ref) repoLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name) refLink := DiscordLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName) @@ -78,14 +77,14 @@ func getDiscordCreatePayload(p *api.CreatePayload) *DiscordPayload { URL: conf.Server.ExternalURL + p.Sender.UserName, Author: &DiscordEmbedAuthorObject{ Name: p.Sender.UserName, - IconURL: p.Sender.AvatarUrl, + IconURL: p.Sender.AvatarURL, }, }}, } } // getDiscordDeletePayload composes Discord payload for delete a branch or tag. -func getDiscordDeletePayload(p *api.DeletePayload) *DiscordPayload { +func getDiscordDeletePayload(p *apiv1types.WebhookDeletePayload) *DiscordPayload { refName := git.RefShortName(p.Ref) repoLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name) content := fmt.Sprintf("Deleted %s: %s/%s", p.RefType, repoLink, refName) @@ -95,14 +94,14 @@ func getDiscordDeletePayload(p *api.DeletePayload) *DiscordPayload { URL: conf.Server.ExternalURL + p.Sender.UserName, Author: &DiscordEmbedAuthorObject{ Name: p.Sender.UserName, - IconURL: p.Sender.AvatarUrl, + IconURL: p.Sender.AvatarURL, }, }}, } } // getDiscordForkPayload composes Discord payload for forked by a repository. -func getDiscordForkPayload(p *api.ForkPayload) *DiscordPayload { +func getDiscordForkPayload(p *apiv1types.WebhookForkPayload) *DiscordPayload { baseLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name) forkLink := DiscordLinkFormatter(p.Forkee.HTMLURL, p.Forkee.FullName) content := fmt.Sprintf("%s is forked to %s", baseLink, forkLink) @@ -112,13 +111,13 @@ func getDiscordForkPayload(p *api.ForkPayload) *DiscordPayload { URL: conf.Server.ExternalURL + p.Sender.UserName, Author: &DiscordEmbedAuthorObject{ Name: p.Sender.UserName, - IconURL: p.Sender.AvatarUrl, + IconURL: p.Sender.AvatarURL, }, }}, } } -func getDiscordPushPayload(p *api.PushPayload, slack *SlackMeta) *DiscordPayload { +func getDiscordPushPayload(p *apiv1types.WebhookPushPayload, slack *SlackMeta) *DiscordPayload { // n new commits var ( branchName = git.RefShortName(p.Ref) @@ -162,37 +161,37 @@ func getDiscordPushPayload(p *api.PushPayload, slack *SlackMeta) *DiscordPayload Color: int(color), Author: &DiscordEmbedAuthorObject{ Name: p.Sender.UserName, - IconURL: p.Sender.AvatarUrl, + IconURL: p.Sender.AvatarURL, }, }}, } } -func getDiscordIssuesPayload(p *api.IssuesPayload, slack *SlackMeta) *DiscordPayload { +func getDiscordIssuesPayload(p *apiv1types.WebhookIssuesPayload, slack *SlackMeta) *DiscordPayload { title := fmt.Sprintf("#%d %s", p.Index, p.Issue.Title) url := fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Index) content := "" fields := make([]*DiscordEmbedFieldObject, 0, 1) switch p.Action { - case api.HOOK_ISSUE_OPENED: + case apiv1types.WebhookIssueOpened: title = "New issue: " + title content = p.Issue.Body - case api.HOOK_ISSUE_CLOSED: + case apiv1types.WebhookIssueClosed: title = "Issue closed: " + title - case api.HOOK_ISSUE_REOPENED: + case apiv1types.WebhookIssueReopened: title = "Issue re-opened: " + title - case api.HOOK_ISSUE_EDITED: + case apiv1types.WebhookIssueEdited: title = "Issue edited: " + title content = p.Issue.Body - case api.HOOK_ISSUE_ASSIGNED: + case apiv1types.WebhookIssueAssigned: title = "Issue assigned: " + title fields = []*DiscordEmbedFieldObject{{ Name: "New Assignee", Value: p.Issue.Assignee.UserName, }} - case api.HOOK_ISSUE_UNASSIGNED: + case apiv1types.WebhookIssueUnassigned: title = "Issue unassigned: " + title - case api.HOOK_ISSUE_LABEL_UPDATED: + case apiv1types.WebhookIssueLabelUpdated: title = "Issue labels updated: " + title labels := make([]string, len(p.Issue.Labels)) for i := range p.Issue.Labels { @@ -205,17 +204,17 @@ func getDiscordIssuesPayload(p *api.IssuesPayload, slack *SlackMeta) *DiscordPay Name: "Labels", Value: strings.Join(labels, ", "), }} - case api.HOOK_ISSUE_LABEL_CLEARED: + case apiv1types.WebhookIssueLabelCleared: title = "Issue labels cleared: " + title - case api.HOOK_ISSUE_SYNCHRONIZED: + case apiv1types.WebhookIssueSynchronized: title = "Issue synchronized: " + title - case api.HOOK_ISSUE_MILESTONED: + case apiv1types.WebhookIssueMilestoned: title = "Issue milestoned: " + title fields = []*DiscordEmbedFieldObject{{ Name: "New Milestone", Value: p.Issue.Milestone.Title, }} - case api.HOOK_ISSUE_DEMILESTONED: + case apiv1types.WebhookIssueDemilestoned: title = "Issue demilestoned: " + title } @@ -233,26 +232,26 @@ func getDiscordIssuesPayload(p *api.IssuesPayload, slack *SlackMeta) *DiscordPay }, Author: &DiscordEmbedAuthorObject{ Name: p.Sender.UserName, - IconURL: p.Sender.AvatarUrl, + IconURL: p.Sender.AvatarURL, }, Fields: fields, }}, } } -func getDiscordIssueCommentPayload(p *api.IssueCommentPayload, slack *SlackMeta) *DiscordPayload { +func getDiscordIssueCommentPayload(p *apiv1types.WebhookIssueCommentPayload, slack *SlackMeta) *DiscordPayload { title := fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title) url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID)) content := "" fields := make([]*DiscordEmbedFieldObject, 0, 1) switch p.Action { - case api.HOOK_ISSUE_COMMENT_CREATED: + case apiv1types.WebhookIssueCommentCreated: title = "New comment: " + title content = p.Comment.Body - case api.HOOK_ISSUE_COMMENT_EDITED: + case apiv1types.WebhookIssueCommentEdited: title = "Comment edited: " + title content = p.Comment.Body - case api.HOOK_ISSUE_COMMENT_DELETED: + case apiv1types.WebhookIssueCommentDeleted: title = "Comment deleted: " + title url = fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index) content = p.Comment.Body @@ -272,42 +271,42 @@ func getDiscordIssueCommentPayload(p *api.IssueCommentPayload, slack *SlackMeta) }, Author: &DiscordEmbedAuthorObject{ Name: p.Sender.UserName, - IconURL: p.Sender.AvatarUrl, + IconURL: p.Sender.AvatarURL, }, Fields: fields, }}, } } -func getDiscordPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) *DiscordPayload { +func getDiscordPullRequestPayload(p *apiv1types.WebhookPullRequestPayload, slack *SlackMeta) *DiscordPayload { title := fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title) url := fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index) content := "" fields := make([]*DiscordEmbedFieldObject, 0, 1) switch p.Action { - case api.HOOK_ISSUE_OPENED: + case apiv1types.WebhookIssueOpened: title = "New pull request: " + title content = p.PullRequest.Body - case api.HOOK_ISSUE_CLOSED: + case apiv1types.WebhookIssueClosed: if p.PullRequest.HasMerged { title = "Pull request merged: " + title } else { title = "Pull request closed: " + title } - case api.HOOK_ISSUE_REOPENED: + case apiv1types.WebhookIssueReopened: title = "Pull request re-opened: " + title - case api.HOOK_ISSUE_EDITED: + case apiv1types.WebhookIssueEdited: title = "Pull request edited: " + title content = p.PullRequest.Body - case api.HOOK_ISSUE_ASSIGNED: + case apiv1types.WebhookIssueAssigned: title = "Pull request assigned: " + title fields = []*DiscordEmbedFieldObject{{ Name: "New Assignee", Value: p.PullRequest.Assignee.UserName, }} - case api.HOOK_ISSUE_UNASSIGNED: + case apiv1types.WebhookIssueUnassigned: title = "Pull request unassigned: " + title - case api.HOOK_ISSUE_LABEL_UPDATED: + case apiv1types.WebhookIssueLabelUpdated: title = "Pull request labels updated: " + title labels := make([]string, len(p.PullRequest.Labels)) for i := range p.PullRequest.Labels { @@ -317,17 +316,17 @@ func getDiscordPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) * Name: "Labels", Value: strings.Join(labels, ", "), }} - case api.HOOK_ISSUE_LABEL_CLEARED: + case apiv1types.WebhookIssueLabelCleared: title = "Pull request labels cleared: " + title - case api.HOOK_ISSUE_SYNCHRONIZED: + case apiv1types.WebhookIssueSynchronized: title = "Pull request synchronized: " + title - case api.HOOK_ISSUE_MILESTONED: + case apiv1types.WebhookIssueMilestoned: title = "Pull request milestoned: " + title fields = []*DiscordEmbedFieldObject{{ Name: "New Milestone", Value: p.PullRequest.Milestone.Title, }} - case api.HOOK_ISSUE_DEMILESTONED: + case apiv1types.WebhookIssueDemilestoned: title = "Pull request demilestoned: " + title } @@ -345,14 +344,14 @@ func getDiscordPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) * }, Author: &DiscordEmbedAuthorObject{ Name: p.Sender.UserName, - IconURL: p.Sender.AvatarUrl, + IconURL: p.Sender.AvatarURL, }, Fields: fields, }}, } } -func getDiscordReleasePayload(p *api.ReleasePayload) *DiscordPayload { +func getDiscordReleasePayload(p *apiv1types.WebhookReleasePayload) *DiscordPayload { repoLink := DiscordLinkFormatter(p.Repository.HTMLURL, p.Repository.Name) refLink := DiscordLinkFormatter(p.Repository.HTMLURL+"/src/"+p.Release.TagName, p.Release.TagName) content := fmt.Sprintf("Published new release %s of %s", refLink, repoLink) @@ -362,13 +361,13 @@ func getDiscordReleasePayload(p *api.ReleasePayload) *DiscordPayload { URL: conf.Server.ExternalURL + p.Sender.UserName, Author: &DiscordEmbedAuthorObject{ Name: p.Sender.UserName, - IconURL: p.Sender.AvatarUrl, + IconURL: p.Sender.AvatarURL, }, }}, } } -func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (payload *DiscordPayload, err error) { +func GetDiscordPayload(p apiv1types.WebhookPayloader, event HookEventType, meta string) (payload *DiscordPayload, err error) { slack := &SlackMeta{} if err := json.Unmarshal([]byte(meta), slack); err != nil { return nil, errors.Newf("unmarshal: %v", err) @@ -376,21 +375,21 @@ func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (paylo switch event { case HookEventTypeCreate: - payload = getDiscordCreatePayload(p.(*api.CreatePayload)) + payload = getDiscordCreatePayload(p.(*apiv1types.WebhookCreatePayload)) case HookEventTypeDelete: - payload = getDiscordDeletePayload(p.(*api.DeletePayload)) + payload = getDiscordDeletePayload(p.(*apiv1types.WebhookDeletePayload)) case HookEventTypeFork: - payload = getDiscordForkPayload(p.(*api.ForkPayload)) + payload = getDiscordForkPayload(p.(*apiv1types.WebhookForkPayload)) case HookEventTypePush: - payload = getDiscordPushPayload(p.(*api.PushPayload), slack) + payload = getDiscordPushPayload(p.(*apiv1types.WebhookPushPayload), slack) case HookEventTypeIssues: - payload = getDiscordIssuesPayload(p.(*api.IssuesPayload), slack) + payload = getDiscordIssuesPayload(p.(*apiv1types.WebhookIssuesPayload), slack) case HookEventTypeIssueComment: - payload = getDiscordIssueCommentPayload(p.(*api.IssueCommentPayload), slack) + payload = getDiscordIssueCommentPayload(p.(*apiv1types.WebhookIssueCommentPayload), slack) case HookEventTypePullRequest: - payload = getDiscordPullRequestPayload(p.(*api.PullRequestPayload), slack) + payload = getDiscordPullRequestPayload(p.(*apiv1types.WebhookPullRequestPayload), slack) case HookEventTypeRelease: - payload = getDiscordReleasePayload(p.(*api.ReleasePayload)) + payload = getDiscordReleasePayload(p.(*apiv1types.WebhookReleasePayload)) default: return nil, errors.Errorf("unexpected event %q", event) } diff --git a/internal/database/webhook_slack.go b/internal/database/webhook_slack.go index 330a84948..8b53383c5 100644 --- a/internal/database/webhook_slack.go +++ b/internal/database/webhook_slack.go @@ -6,11 +6,10 @@ import ( "strings" "github.com/cockroachdb/errors" - "github.com/gogs/git-module" - api "github.com/gogs/go-gogs-client" "gogs.io/gogs/internal/conf" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" ) type SlackMeta struct { @@ -68,7 +67,7 @@ func SlackLinkFormatter(url, text string) string { } // getSlackCreatePayload composes Slack payload for create new branch or tag. -func getSlackCreatePayload(p *api.CreatePayload) *SlackPayload { +func getSlackCreatePayload(p *apiv1types.WebhookCreatePayload) *SlackPayload { refName := git.RefShortName(p.Ref) repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name) refLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName) @@ -79,7 +78,7 @@ func getSlackCreatePayload(p *api.CreatePayload) *SlackPayload { } // getSlackDeletePayload composes Slack payload for delete a branch or tag. -func getSlackDeletePayload(p *api.DeletePayload) *SlackPayload { +func getSlackDeletePayload(p *apiv1types.WebhookDeletePayload) *SlackPayload { refName := git.RefShortName(p.Ref) repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name) text := fmt.Sprintf("[%s:%s] %s deleted by %s", repoLink, refName, p.RefType, p.Sender.UserName) @@ -89,7 +88,7 @@ func getSlackDeletePayload(p *api.DeletePayload) *SlackPayload { } // getSlackForkPayload composes Slack payload for forked by a repository. -func getSlackForkPayload(p *api.ForkPayload) *SlackPayload { +func getSlackForkPayload(p *apiv1types.WebhookForkPayload) *SlackPayload { baseLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name) forkLink := SlackLinkFormatter(p.Forkee.HTMLURL, p.Forkee.FullName) text := fmt.Sprintf("%s is forked to %s", baseLink, forkLink) @@ -98,7 +97,7 @@ func getSlackForkPayload(p *api.ForkPayload) *SlackPayload { } } -func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) *SlackPayload { +func getSlackPushPayload(p *apiv1types.WebhookPushPayload, slack *SlackMeta) *SlackPayload { // n new commits var ( branchName = git.RefShortName(p.Ref) @@ -143,36 +142,36 @@ func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) *SlackPayload { } } -func getSlackIssuesPayload(p *api.IssuesPayload, slack *SlackMeta) *SlackPayload { +func getSlackIssuesPayload(p *apiv1types.WebhookIssuesPayload, slack *SlackMeta) *SlackPayload { senderLink := SlackLinkFormatter(conf.Server.ExternalURL+p.Sender.UserName, p.Sender.UserName) titleLink := SlackLinkFormatter(fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Index), fmt.Sprintf("#%d %s", p.Index, p.Issue.Title)) var text, title, attachmentText string switch p.Action { - case api.HOOK_ISSUE_OPENED: + case apiv1types.WebhookIssueOpened: text = fmt.Sprintf("[%s] New issue created by %s", p.Repository.FullName, senderLink) title = titleLink attachmentText = SlackTextFormatter(p.Issue.Body) - case api.HOOK_ISSUE_CLOSED: + case apiv1types.WebhookIssueClosed: text = fmt.Sprintf("[%s] Issue closed: %s by %s", p.Repository.FullName, titleLink, senderLink) - case api.HOOK_ISSUE_REOPENED: + case apiv1types.WebhookIssueReopened: text = fmt.Sprintf("[%s] Issue re-opened: %s by %s", p.Repository.FullName, titleLink, senderLink) - case api.HOOK_ISSUE_EDITED: + case apiv1types.WebhookIssueEdited: text = fmt.Sprintf("[%s] Issue edited: %s by %s", p.Repository.FullName, titleLink, senderLink) attachmentText = SlackTextFormatter(p.Issue.Body) - case api.HOOK_ISSUE_ASSIGNED: + case apiv1types.WebhookIssueAssigned: text = fmt.Sprintf("[%s] Issue assigned to %s: %s by %s", p.Repository.FullName, SlackLinkFormatter(conf.Server.ExternalURL+p.Issue.Assignee.UserName, p.Issue.Assignee.UserName), titleLink, senderLink) - case api.HOOK_ISSUE_UNASSIGNED: + case apiv1types.WebhookIssueUnassigned: text = fmt.Sprintf("[%s] Issue unassigned: %s by %s", p.Repository.FullName, titleLink, senderLink) - case api.HOOK_ISSUE_LABEL_UPDATED: + case apiv1types.WebhookIssueLabelUpdated: text = fmt.Sprintf("[%s] Issue labels updated: %s by %s", p.Repository.FullName, titleLink, senderLink) - case api.HOOK_ISSUE_LABEL_CLEARED: + case apiv1types.WebhookIssueLabelCleared: text = fmt.Sprintf("[%s] Issue labels cleared: %s by %s", p.Repository.FullName, titleLink, senderLink) - case api.HOOK_ISSUE_MILESTONED: + case apiv1types.WebhookIssueMilestoned: text = fmt.Sprintf("[%s] Issue milestoned: %s by %s", p.Repository.FullName, titleLink, senderLink) - case api.HOOK_ISSUE_DEMILESTONED: + case apiv1types.WebhookIssueDemilestoned: text = fmt.Sprintf("[%s] Issue demilestoned: %s by %s", p.Repository.FullName, titleLink, senderLink) } @@ -189,21 +188,21 @@ func getSlackIssuesPayload(p *api.IssuesPayload, slack *SlackMeta) *SlackPayload } } -func getSlackIssueCommentPayload(p *api.IssueCommentPayload, slack *SlackMeta) *SlackPayload { +func getSlackIssueCommentPayload(p *apiv1types.WebhookIssueCommentPayload, slack *SlackMeta) *SlackPayload { senderLink := SlackLinkFormatter(conf.Server.ExternalURL+p.Sender.UserName, p.Sender.UserName) titleLink := SlackLinkFormatter(fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID)), fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title)) var text, title, attachmentText string switch p.Action { - case api.HOOK_ISSUE_COMMENT_CREATED: + case apiv1types.WebhookIssueCommentCreated: text = fmt.Sprintf("[%s] New comment created by %s", p.Repository.FullName, senderLink) title = titleLink attachmentText = SlackTextFormatter(p.Comment.Body) - case api.HOOK_ISSUE_COMMENT_EDITED: + case apiv1types.WebhookIssueCommentEdited: text = fmt.Sprintf("[%s] Comment edited by %s", p.Repository.FullName, senderLink) title = titleLink attachmentText = SlackTextFormatter(p.Comment.Body) - case api.HOOK_ISSUE_COMMENT_DELETED: + case apiv1types.WebhookIssueCommentDeleted: text = fmt.Sprintf("[%s] Comment deleted by %s", p.Repository.FullName, senderLink) title = SlackLinkFormatter(fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index), fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title)) @@ -223,42 +222,42 @@ func getSlackIssueCommentPayload(p *api.IssueCommentPayload, slack *SlackMeta) * } } -func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) *SlackPayload { +func getSlackPullRequestPayload(p *apiv1types.WebhookPullRequestPayload, slack *SlackMeta) *SlackPayload { senderLink := SlackLinkFormatter(conf.Server.ExternalURL+p.Sender.UserName, p.Sender.UserName) titleLink := SlackLinkFormatter(fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index), fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title)) var text, title, attachmentText string switch p.Action { - case api.HOOK_ISSUE_OPENED: + case apiv1types.WebhookIssueOpened: text = fmt.Sprintf("[%s] Pull request submitted by %s", p.Repository.FullName, senderLink) title = titleLink attachmentText = SlackTextFormatter(p.PullRequest.Body) - case api.HOOK_ISSUE_CLOSED: + case apiv1types.WebhookIssueClosed: if p.PullRequest.HasMerged { text = fmt.Sprintf("[%s] Pull request merged: %s by %s", p.Repository.FullName, titleLink, senderLink) } else { text = fmt.Sprintf("[%s] Pull request closed: %s by %s", p.Repository.FullName, titleLink, senderLink) } - case api.HOOK_ISSUE_REOPENED: + case apiv1types.WebhookIssueReopened: text = fmt.Sprintf("[%s] Pull request re-opened: %s by %s", p.Repository.FullName, titleLink, senderLink) - case api.HOOK_ISSUE_EDITED: + case apiv1types.WebhookIssueEdited: text = fmt.Sprintf("[%s] Pull request edited: %s by %s", p.Repository.FullName, titleLink, senderLink) attachmentText = SlackTextFormatter(p.PullRequest.Body) - case api.HOOK_ISSUE_ASSIGNED: + case apiv1types.WebhookIssueAssigned: text = fmt.Sprintf("[%s] Pull request assigned to %s: %s by %s", p.Repository.FullName, SlackLinkFormatter(conf.Server.ExternalURL+p.PullRequest.Assignee.UserName, p.PullRequest.Assignee.UserName), titleLink, senderLink) - case api.HOOK_ISSUE_UNASSIGNED: + case apiv1types.WebhookIssueUnassigned: text = fmt.Sprintf("[%s] Pull request unassigned: %s by %s", p.Repository.FullName, titleLink, senderLink) - case api.HOOK_ISSUE_LABEL_UPDATED: + case apiv1types.WebhookIssueLabelUpdated: text = fmt.Sprintf("[%s] Pull request labels updated: %s by %s", p.Repository.FullName, titleLink, senderLink) - case api.HOOK_ISSUE_LABEL_CLEARED: + case apiv1types.WebhookIssueLabelCleared: text = fmt.Sprintf("[%s] Pull request labels cleared: %s by %s", p.Repository.FullName, titleLink, senderLink) - case api.HOOK_ISSUE_SYNCHRONIZED: + case apiv1types.WebhookIssueSynchronized: text = fmt.Sprintf("[%s] Pull request synchronized: %s by %s", p.Repository.FullName, titleLink, senderLink) - case api.HOOK_ISSUE_MILESTONED: + case apiv1types.WebhookIssueMilestoned: text = fmt.Sprintf("[%s] Pull request milestoned: %s by %s", p.Repository.FullName, titleLink, senderLink) - case api.HOOK_ISSUE_DEMILESTONED: + case apiv1types.WebhookIssueDemilestoned: text = fmt.Sprintf("[%s] Pull request demilestoned: %s by %s", p.Repository.FullName, titleLink, senderLink) } @@ -275,7 +274,7 @@ func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) *Sl } } -func getSlackReleasePayload(p *api.ReleasePayload) *SlackPayload { +func getSlackReleasePayload(p *apiv1types.WebhookReleasePayload) *SlackPayload { repoLink := SlackLinkFormatter(p.Repository.HTMLURL, p.Repository.Name) refLink := SlackLinkFormatter(p.Repository.HTMLURL+"/src/"+p.Release.TagName, p.Release.TagName) text := fmt.Sprintf("[%s] new release %s published by %s", repoLink, refLink, p.Sender.UserName) @@ -284,7 +283,7 @@ func getSlackReleasePayload(p *api.ReleasePayload) *SlackPayload { } } -func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (payload *SlackPayload, err error) { +func GetSlackPayload(p apiv1types.WebhookPayloader, event HookEventType, meta string) (payload *SlackPayload, err error) { slack := &SlackMeta{} if err := json.Unmarshal([]byte(meta), slack); err != nil { return nil, errors.Newf("unmarshal: %v", err) @@ -292,21 +291,21 @@ func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (payload switch event { case HookEventTypeCreate: - payload = getSlackCreatePayload(p.(*api.CreatePayload)) + payload = getSlackCreatePayload(p.(*apiv1types.WebhookCreatePayload)) case HookEventTypeDelete: - payload = getSlackDeletePayload(p.(*api.DeletePayload)) + payload = getSlackDeletePayload(p.(*apiv1types.WebhookDeletePayload)) case HookEventTypeFork: - payload = getSlackForkPayload(p.(*api.ForkPayload)) + payload = getSlackForkPayload(p.(*apiv1types.WebhookForkPayload)) case HookEventTypePush: - payload = getSlackPushPayload(p.(*api.PushPayload), slack) + payload = getSlackPushPayload(p.(*apiv1types.WebhookPushPayload), slack) case HookEventTypeIssues: - payload = getSlackIssuesPayload(p.(*api.IssuesPayload), slack) + payload = getSlackIssuesPayload(p.(*apiv1types.WebhookIssuesPayload), slack) case HookEventTypeIssueComment: - payload = getSlackIssueCommentPayload(p.(*api.IssueCommentPayload), slack) + payload = getSlackIssueCommentPayload(p.(*apiv1types.WebhookIssueCommentPayload), slack) case HookEventTypePullRequest: - payload = getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack) + payload = getSlackPullRequestPayload(p.(*apiv1types.WebhookPullRequestPayload), slack) case HookEventTypeRelease: - payload = getSlackReleasePayload(p.(*api.ReleasePayload)) + payload = getSlackReleasePayload(p.(*apiv1types.WebhookReleasePayload)) default: return nil, errors.Errorf("unexpected event %q", event) } diff --git a/internal/route/api/v1/adapters.go b/internal/route/api/v1/adapters.go new file mode 100644 index 000000000..2386575af --- /dev/null +++ b/internal/route/api/v1/adapters.go @@ -0,0 +1,303 @@ +package v1 + +import ( + "context" + "fmt" + "strconv" + "strings" + + "github.com/gogs/git-module" + + "gogs.io/gogs/internal/conf" + "gogs.io/gogs/internal/database" + "gogs.io/gogs/internal/markup" + "gogs.io/gogs/internal/route/api/v1/types" +) + +// toAllowedPageSize makes sure page size is in allowed range. +func toAllowedPageSize(size int) int { + if size <= 0 { + size = 10 + } else if size > conf.API.MaxResponseItems { + size = conf.API.MaxResponseItems + } + return size +} + +// toUser converts a database user to an API user with the full name sanitized +// for safe HTML rendering. +func toUser(u *database.User) *types.User { + return &types.User{ + ID: u.ID, + UserName: u.Name, + Login: u.Name, + FullName: markup.Sanitize(u.FullName), + Email: u.Email, + AvatarURL: u.AvatarURL(), + } +} + +func toUserEmail(email *database.EmailAddress) *types.UserEmail { + return &types.UserEmail{ + Email: email.Email, + Verified: email.IsActivated, + Primary: email.IsPrimary, + } +} + +func toBranch(b *database.Branch, c *git.Commit) *types.RepositoryBranch { + return &types.RepositoryBranch{ + Name: b.Name, + Commit: toPayloadCommit(c), + } +} + +func toTag(b *database.Tag, c *git.Commit) *tag { + return &tag{ + Name: b.Name, + Commit: toPayloadCommit(c), + } +} + +func toPayloadCommit(c *git.Commit) *types.WebhookPayloadCommit { + authorUsername := "" + author, err := database.Handle.Users().GetByEmail(context.TODO(), c.Author.Email) + if err == nil { + authorUsername = author.Name + } + committerUsername := "" + committer, err := database.Handle.Users().GetByEmail(context.TODO(), c.Committer.Email) + if err == nil { + committerUsername = committer.Name + } + return &types.WebhookPayloadCommit{ + ID: c.ID.String(), + Message: c.Message, + URL: "Not implemented", + Author: &types.WebhookPayloadUser{ + Name: c.Author.Name, + Email: c.Author.Email, + UserName: authorUsername, + }, + Committer: &types.WebhookPayloadUser{ + Name: c.Committer.Name, + Email: c.Committer.Email, + UserName: committerUsername, + }, + Timestamp: c.Author.When, + } +} + +func toUserPublicKey(apiLink string, key *database.PublicKey) *types.UserPublicKey { + return &types.UserPublicKey{ + ID: key.ID, + Key: key.Content, + URL: apiLink + strconv.FormatInt(key.ID, 10), + Title: key.Name, + Created: key.Created, + } +} + +func toRepositoryHook(repoLink string, w *database.Webhook) *types.RepositoryHook { + config := map[string]string{ + "url": w.URL, + "content_type": w.ContentType.Name(), + } + if w.HookTaskType == database.SLACK { + s := w.SlackMeta() + config["channel"] = s.Channel + config["username"] = s.Username + config["icon_url"] = s.IconURL + config["color"] = s.Color + } + + return &types.RepositoryHook{ + ID: w.ID, + Type: w.HookTaskType.Name(), + URL: fmt.Sprintf("%s/settings/hooks/%d", repoLink, w.ID), + Active: w.IsActive, + Config: config, + Events: w.EventsArray(), + Updated: w.Updated, + Created: w.Created, + } +} + +func toDeployKey(apiLink string, key *database.DeployKey) *types.RepositoryDeployKey { + return &types.RepositoryDeployKey{ + ID: key.ID, + Key: key.Content, + URL: apiLink + strconv.FormatInt(key.ID, 10), + Title: key.Name, + Created: key.Created, + ReadOnly: true, // All deploy keys are read-only. + } +} + +func toOrganization(org *database.User) *types.Organization { + return &types.Organization{ + ID: org.ID, + AvatarURL: org.AvatarURL(), + UserName: org.Name, + FullName: org.FullName, + Description: org.Description, + Website: org.Website, + Location: org.Location, + } +} + +func toOrganizationTeam(team *database.Team) *types.OrganizationTeam { + return &types.OrganizationTeam{ + ID: team.ID, + Name: team.Name, + Description: team.Description, + Permission: team.Authorize.String(), + } +} + +func toIssueLabel(l *database.Label) *types.IssueLabel { + return &types.IssueLabel{ + ID: l.ID, + Name: l.Name, + Color: strings.TrimLeft(l.Color, "#"), + } +} + +func issueState(isClosed bool) types.IssueStateType { + if isClosed { + return types.IssueStateClosed + } + return types.IssueStateOpen +} + +// toIssue converts a database issue to an API issue. +// It assumes the following fields have been assigned with valid values: +// Required - Poster, Labels +// Optional - Milestone, Assignee, PullRequest +func toIssue(issue *database.Issue) *types.Issue { + labels := make([]*types.IssueLabel, len(issue.Labels)) + for i := range issue.Labels { + labels[i] = toIssueLabel(issue.Labels[i]) + } + + apiIssue := &types.Issue{ + ID: issue.ID, + Index: issue.Index, + Poster: toUser(issue.Poster), + Title: issue.Title, + Body: issue.Content, + Labels: labels, + State: issueState(issue.IsClosed), + Comments: issue.NumComments, + Created: issue.Created, + Updated: issue.Updated, + } + + if issue.Milestone != nil { + apiIssue.Milestone = toIssueMilestone(issue.Milestone) + } + if issue.Assignee != nil { + apiIssue.Assignee = toUser(issue.Assignee) + } + if issue.IsPull { + apiIssue.PullRequest = &types.PullRequestMeta{ + HasMerged: issue.PullRequest.HasMerged, + } + if issue.PullRequest.HasMerged { + apiIssue.PullRequest.Merged = &issue.PullRequest.Merged + } + } + + return apiIssue +} + +func toIssueComment(c *database.Comment) *types.IssueComment { + return &types.IssueComment{ + ID: c.ID, + HTMLURL: c.HTMLURL(), + Poster: toUser(c.Poster), + Body: c.Content, + Created: c.Created, + Updated: c.Updated, + } +} + +func toIssueMilestone(m *database.Milestone) *types.IssueMilestone { + ms := &types.IssueMilestone{ + ID: m.ID, + State: issueState(m.IsClosed), + Title: m.Name, + Description: m.Content, + OpenIssues: m.NumOpenIssues, + ClosedIssues: m.NumClosedIssues, + } + if m.IsClosed { + ms.Closed = &m.ClosedDate + } + if m.Deadline.Year() < 9999 { + ms.Deadline = &m.Deadline + } + return ms +} + +// toRelease converts a database release to an API release. +// It assumes the Publisher field has been assigned. +func toRelease(r *database.Release) *types.RepositoryRelease { + return &types.RepositoryRelease{ + ID: r.ID, + TagName: r.TagName, + TargetCommitish: r.Target, + Name: r.Title, + Body: r.Note, + Draft: r.IsDraft, + Prerelease: r.IsPrerelease, + Author: toUser(r.Publisher), + Created: r.Created, + } +} + +func toRepositoryCollaborator(c *database.Collaborator) *types.RepositoryCollaborator { + return &types.RepositoryCollaborator{ + User: toUser(c.User), + Permissions: types.RepositoryPermission{ + Admin: c.Collaboration.Mode >= database.AccessModeAdmin, + Push: c.Collaboration.Mode >= database.AccessModeWrite, + Pull: c.Collaboration.Mode >= database.AccessModeRead, + }, + } +} + +// toRepository converts a database repository to an API repository. +// It assumes the Owner field has been loaded on the repo. +func toRepository(repo *database.Repository, perm *types.RepositoryPermission) *types.Repository { + cloneLink := repo.CloneLink() + apiRepo := &types.Repository{ + ID: repo.ID, + Owner: toUser(repo.Owner), + Name: repo.Name, + FullName: repo.FullName(), + Description: repo.Description, + Private: repo.IsPrivate, + Fork: repo.IsFork, + Empty: repo.IsBare, + Mirror: repo.IsMirror, + Size: repo.Size, + HTMLURL: repo.HTMLURL(), + SSHURL: cloneLink.SSH, + CloneURL: cloneLink.HTTPS, + Website: repo.Website, + Stars: repo.NumStars, + Forks: repo.NumForks, + Watchers: repo.NumWatches, + OpenIssues: repo.NumOpenIssues, + DefaultBranch: repo.DefaultBranch, + Created: repo.Created, + Updated: repo.Updated, + Permissions: perm, + } + if repo.IsFork { + p := &types.RepositoryPermission{Pull: true} + apiRepo.Parent = toRepository(repo.BaseRepo, p) + } + return apiRepo +} diff --git a/internal/route/api/v1/admin/org.go b/internal/route/api/v1/admin/org.go deleted file mode 100644 index b00af9a22..000000000 --- a/internal/route/api/v1/admin/org.go +++ /dev/null @@ -1,13 +0,0 @@ -package admin - -import ( - api "github.com/gogs/go-gogs-client" - - "gogs.io/gogs/internal/context" - "gogs.io/gogs/internal/route/api/v1/org" - "gogs.io/gogs/internal/route/api/v1/user" -) - -func CreateOrg(c *context.APIContext, form api.CreateOrgOption) { - org.CreateOrgForUser(c, form, user.GetUserByParams(c)) -} diff --git a/internal/route/api/v1/admin/repo.go b/internal/route/api/v1/admin/repo.go deleted file mode 100644 index d8f39de95..000000000 --- a/internal/route/api/v1/admin/repo.go +++ /dev/null @@ -1,18 +0,0 @@ -package admin - -import ( - api "github.com/gogs/go-gogs-client" - - "gogs.io/gogs/internal/context" - "gogs.io/gogs/internal/route/api/v1/repo" - "gogs.io/gogs/internal/route/api/v1/user" -) - -func CreateRepo(c *context.APIContext, form api.CreateRepoOption) { - owner := user.GetUserByParams(c) - if c.Written() { - return - } - - repo.CreateUserRepo(c, owner, form) -} diff --git a/internal/route/api/v1/admin_org.go b/internal/route/api/v1/admin_org.go new file mode 100644 index 000000000..10d7c9fa6 --- /dev/null +++ b/internal/route/api/v1/admin_org.go @@ -0,0 +1,9 @@ +package v1 + +import ( + "gogs.io/gogs/internal/context" +) + +func adminCreateOrg(c *context.APIContext, form createOrgRequest) { + createOrgForUser(c, form, getUserByParams(c)) +} diff --git a/internal/route/api/v1/admin/org_repo.go b/internal/route/api/v1/admin_org_repo.go similarity index 69% rename from internal/route/api/v1/admin/org_repo.go rename to internal/route/api/v1/admin_org_repo.go index 8fbea234f..81f1aceb2 100644 --- a/internal/route/api/v1/admin/org_repo.go +++ b/internal/route/api/v1/admin_org_repo.go @@ -1,11 +1,11 @@ -package admin +package v1 import ( "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" ) -func GetRepositoryByParams(c *context.APIContext) *database.Repository { +func getRepositoryByParams(c *context.APIContext) *database.Repository { repo, err := database.GetRepositoryByName(c.Org.Team.OrgID, c.Params(":reponame")) if err != nil { c.NotFoundOrError(err, "get repository by name") @@ -14,8 +14,8 @@ func GetRepositoryByParams(c *context.APIContext) *database.Repository { return repo } -func AddTeamRepository(c *context.APIContext) { - repo := GetRepositoryByParams(c) +func adminAddTeamRepository(c *context.APIContext) { + repo := getRepositoryByParams(c) if c.Written() { return } @@ -27,8 +27,8 @@ func AddTeamRepository(c *context.APIContext) { c.NoContent() } -func RemoveTeamRepository(c *context.APIContext) { - repo := GetRepositoryByParams(c) +func adminRemoveTeamRepository(c *context.APIContext) { + repo := getRepositoryByParams(c) if c.Written() { return } diff --git a/internal/route/api/v1/admin/org_team.go b/internal/route/api/v1/admin_org_team.go similarity index 57% rename from internal/route/api/v1/admin/org_team.go rename to internal/route/api/v1/admin_org_team.go index 25650642f..f8f0de43d 100644 --- a/internal/route/api/v1/admin/org_team.go +++ b/internal/route/api/v1/admin_org_team.go @@ -1,17 +1,20 @@ -package admin +package v1 import ( "net/http" - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" - "gogs.io/gogs/internal/route/api/v1/convert" - "gogs.io/gogs/internal/route/api/v1/user" + "gogs.io/gogs/internal/route/api/v1/types" ) -func CreateTeam(c *context.APIContext, form api.CreateTeamOption) { +type adminCreateTeamRequest struct { + Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(30)"` + Description string `json:"description" binding:"MaxSize(255)"` + Permission string `json:"permission"` +} + +func adminCreateTeam(c *context.APIContext, form adminCreateTeamRequest) { team := &database.Team{ OrgID: c.Org.Organization.ID, Name: form.Name, @@ -27,11 +30,11 @@ func CreateTeam(c *context.APIContext, form api.CreateTeamOption) { return } - c.JSON(http.StatusCreated, convert.ToTeam(team)) + c.JSON(http.StatusCreated, toOrganizationTeam(team)) } -func AddTeamMember(c *context.APIContext) { - u := user.GetUserByParams(c) +func adminAddTeamMember(c *context.APIContext) { + u := getUserByParams(c) if c.Written() { return } @@ -43,8 +46,8 @@ func AddTeamMember(c *context.APIContext) { c.NoContent() } -func RemoveTeamMember(c *context.APIContext) { - u := user.GetUserByParams(c) +func adminRemoveTeamMember(c *context.APIContext) { + u := getUserByParams(c) if c.Written() { return } @@ -57,16 +60,16 @@ func RemoveTeamMember(c *context.APIContext) { c.NoContent() } -func ListTeamMembers(c *context.APIContext) { +func adminListTeamMembers(c *context.APIContext) { team := c.Org.Team if err := team.GetMembers(); err != nil { c.Error(err, "get team members") return } - apiMembers := make([]*api.User, len(team.Members)) + apiMembers := make([]*types.User, len(team.Members)) for i := range team.Members { - apiMembers[i] = team.Members[i].APIFormat() + apiMembers[i] = toUser(team.Members[i]) } c.JSONSuccess(apiMembers) } diff --git a/internal/route/api/v1/admin_repo.go b/internal/route/api/v1/admin_repo.go new file mode 100644 index 000000000..72dd87a3f --- /dev/null +++ b/internal/route/api/v1/admin_repo.go @@ -0,0 +1,14 @@ +package v1 + +import ( + "gogs.io/gogs/internal/context" +) + +func adminCreateRepo(c *context.APIContext, form createRepoRequest) { + owner := getUserByParams(c) + if c.Written() { + return + } + + createUserRepo(c, owner, form) +} diff --git a/internal/route/api/v1/admin/user.go b/internal/route/api/v1/admin_user.go similarity index 61% rename from internal/route/api/v1/admin/user.go rename to internal/route/api/v1/admin_user.go index fbfd3432e..915c1e80f 100644 --- a/internal/route/api/v1/admin/user.go +++ b/internal/route/api/v1/admin_user.go @@ -1,16 +1,14 @@ -package admin +package v1 import ( "net/http" - api "github.com/gogs/go-gogs-client" log "unknwon.dev/clog/v2" "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" "gogs.io/gogs/internal/email" - "gogs.io/gogs/internal/route/api/v1/user" ) func parseLoginSource(c *context.APIContext, sourceID int64) { @@ -29,13 +27,23 @@ func parseLoginSource(c *context.APIContext, sourceID int64) { } } -func CreateUser(c *context.APIContext, form api.CreateUserOption) { +type adminCreateUserRequest struct { + SourceID int64 `json:"source_id"` + LoginName string `json:"login_name"` + Username string `json:"username" binding:"Required;AlphaDashDot;MaxSize(35)"` + FullName string `json:"full_name" binding:"MaxSize(100)"` + Email string `json:"email" binding:"Required;Email;MaxSize(254)"` + Password string `json:"password" binding:"MaxSize(255)"` + SendNotify bool `json:"send_notify"` +} + +func adminCreateUser(c *context.APIContext, form adminCreateUserRequest) { parseLoginSource(c, form.SourceID) if c.Written() { return } - user, err := database.Handle.Users().Create( + u, err := database.Handle.Users().Create( c.Req.Context(), form.Username, form.Email, @@ -57,18 +65,33 @@ func CreateUser(c *context.APIContext, form api.CreateUserOption) { } return } - log.Trace("Account %q created by admin %q", user.Name, c.User.Name) + log.Trace("Account %q created by admin %q", u.Name, c.User.Name) // Send email notification. if form.SendNotify && conf.Email.Enabled { - email.SendRegisterNotifyMail(c.Context.Context, database.NewMailerUser(user)) + email.SendRegisterNotifyMail(c.Context.Context, database.NewMailerUser(u)) } - c.JSON(http.StatusCreated, user.APIFormat()) + c.JSON(http.StatusCreated, toUser(u)) } -func EditUser(c *context.APIContext, form api.EditUserOption) { - u := user.GetUserByParams(c) +type adminEditUserRequest struct { + SourceID int64 `json:"source_id"` + LoginName string `json:"login_name"` + FullName string `json:"full_name" binding:"MaxSize(100)"` + Email string `json:"email" binding:"Required;Email;MaxSize(254)"` + Password string `json:"password" binding:"MaxSize(255)"` + Website string `json:"website" binding:"MaxSize(50)"` + Location string `json:"location" binding:"MaxSize(50)"` + Active *bool `json:"active"` + Admin *bool `json:"admin"` + AllowGitHook *bool `json:"allow_git_hook"` + AllowImportLocal *bool `json:"allow_import_local"` + MaxRepoCreation *int `json:"max_repo_creation"` +} + +func adminEditUser(c *context.APIContext, form adminEditUserRequest) { + u := getUserByParams(c) if c.Written() { return } @@ -116,11 +139,11 @@ func EditUser(c *context.APIContext, form api.EditUserOption) { c.Error(err, "get user") return } - c.JSONSuccess(u.APIFormat()) + c.JSONSuccess(toUser(u)) } -func DeleteUser(c *context.APIContext) { - u := user.GetUserByParams(c) +func adminDeleteUser(c *context.APIContext) { + u := getUserByParams(c) if c.Written() { return } @@ -139,10 +162,10 @@ func DeleteUser(c *context.APIContext) { c.NoContent() } -func CreatePublicKey(c *context.APIContext, form api.CreateKeyOption) { - u := user.GetUserByParams(c) +func adminCreatePublicKey(c *context.APIContext, form createPublicKeyRequest) { + u := getUserByParams(c) if c.Written() { return } - user.CreateUserPublicKey(c, form, u.ID) + createUserPublicKey(c, form, u.ID) } diff --git a/internal/route/api/v1/api.go b/internal/route/api/v1/api.go index 8304d876b..b3033d0ac 100644 --- a/internal/route/api/v1/api.go +++ b/internal/route/api/v1/api.go @@ -7,16 +7,9 @@ import ( "github.com/go-macaron/binding" "gopkg.in/macaron.v1" - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" "gogs.io/gogs/internal/form" - "gogs.io/gogs/internal/route/api/v1/admin" - "gogs.io/gogs/internal/route/api/v1/misc" - "gogs.io/gogs/internal/route/api/v1/org" - "gogs.io/gogs/internal/route/api/v1/repo" - "gogs.io/gogs/internal/route/api/v1/user" ) // repoAssignment extracts information from URL parameters to retrieve the repository, @@ -181,245 +174,245 @@ func RegisterRoutes(m *macaron.Macaron) { m.Options("/*", func() {}) // Miscellaneous - m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown) - m.Post("/markdown/raw", misc.MarkdownRaw) + m.Post("/markdown", bind(markdownRequest{}), markdown) + m.Post("/markdown/raw", markdownRaw) // Users m.Group("/users", func() { - m.Get("/search", user.Search) + m.Get("/search", searchUsers) m.Group("/:username", func() { - m.Get("", user.GetInfo) + m.Get("", getUserProfile) m.Group("/tokens", func() { - accessTokensHandler := user.NewAccessTokensHandler(user.NewAccessTokensStore()) + accessTokensHandler := newAccessTokensHandler(newAccessTokensStore()) m.Combo(""). Get(accessTokensHandler.List()). - Post(bind(api.CreateAccessTokenOption{}), accessTokensHandler.Create()) + Post(bind(createAccessTokenRequest{}), accessTokensHandler.Create()) }, reqBasicAuth()) }) }) m.Group("/users", func() { m.Group("/:username", func() { - m.Get("/keys", user.ListPublicKeys) + m.Get("/keys", listPublicKeys) - m.Get("/followers", user.ListFollowers) + m.Get("/followers", listFollowers) m.Group("/following", func() { - m.Get("", user.ListFollowing) - m.Get("/:target", user.CheckFollowing) + m.Get("", listFollowing) + m.Get("/:target", checkFollowing) }) }) }, reqToken()) m.Group("/user", func() { - m.Get("", user.GetAuthenticatedUser) + m.Get("", getAuthenticatedUser) m.Combo("/emails"). - Get(user.ListEmails). - Post(bind(api.CreateEmailOption{}), user.AddEmail). - Delete(bind(api.CreateEmailOption{}), user.DeleteEmail) + Get(listEmails). + Post(bind(createEmailRequest{}), addEmail). + Delete(bind(createEmailRequest{}), deleteEmail) - m.Get("/followers", user.ListMyFollowers) + m.Get("/followers", listMyFollowers) m.Group("/following", func() { - m.Get("", user.ListMyFollowing) + m.Get("", listMyFollowing) m.Combo("/:username"). - Get(user.CheckMyFollowing). - Put(user.Follow). - Delete(user.Unfollow) + Get(checkMyFollowing). + Put(follow). + Delete(unfollow) }) m.Group("/keys", func() { m.Combo(""). - Get(user.ListMyPublicKeys). - Post(bind(api.CreateKeyOption{}), user.CreatePublicKey) + Get(listMyPublicKeys). + Post(bind(createPublicKeyRequest{}), createPublicKey) m.Combo("/:id"). - Get(user.GetPublicKey). - Delete(user.DeletePublicKey) + Get(getPublicKey). + Delete(deletePublicKey) }) - m.Get("/issues", repo.ListUserIssues) + m.Get("/issues", listUserIssues) }, reqToken()) // Repositories - m.Get("/users/:username/repos", reqToken(), repo.ListUserRepositories) - m.Get("/orgs/:org/repos", reqToken(), repo.ListOrgRepositories) + m.Get("/users/:username/repos", reqToken(), listUserRepositories) + m.Get("/orgs/:org/repos", reqToken(), listOrgRepositories) m.Combo("/user/repos", reqToken()). - Get(repo.ListMyRepos). - Post(bind(api.CreateRepoOption{}), repo.Create) - m.Post("/org/:org/repos", reqToken(), bind(api.CreateRepoOption{}), repo.CreateOrgRepo) + Get(listMyRepos). + Post(bind(createRepoRequest{}), createRepo) + m.Post("/org/:org/repos", reqToken(), bind(createRepoRequest{}), createOrgRepo) m.Group("/repos", func() { - m.Get("/search", repo.Search) + m.Get("/search", searchRepos) - m.Get("/:username/:reponame", repoAssignment(), repo.Get) - m.Get("/:username/:reponame/releases", repoAssignment(), repo.Releases) + m.Get("/:username/:reponame", repoAssignment(), getRepo) + m.Get("/:username/:reponame/releases", repoAssignment(), releases) }) m.Group("/repos", func() { - m.Post("/migrate", bind(form.MigrateRepo{}), repo.Migrate) - m.Delete("/:username/:reponame", repoAssignment(), reqRepoOwner(), repo.Delete) + m.Post("/migrate", bind(form.MigrateRepo{}), migrate) + m.Delete("/:username/:reponame", repoAssignment(), reqRepoOwner(), deleteRepo) m.Group("/:username/:reponame", func() { m.Group("/hooks", func() { m.Combo(""). - Get(repo.ListHooks). - Post(bind(api.CreateHookOption{}), repo.CreateHook) + Get(listHooks). + Post(bind(createHookRequest{}), createHook) m.Combo("/:id"). - Patch(bind(api.EditHookOption{}), repo.EditHook). - Delete(repo.DeleteHook) + Patch(bind(editHookRequest{}), editHook). + Delete(deleteHook) }, reqRepoAdmin()) m.Group("/collaborators", func() { - m.Get("", repo.ListCollaborators) + m.Get("", listCollaborators) m.Combo("/:collaborator"). - Get(repo.IsCollaborator). - Put(bind(api.AddCollaboratorOption{}), repo.AddCollaborator). - Delete(repo.DeleteCollaborator) + Get(isCollaborator). + Put(bind(addCollaboratorRequest{}), addCollaborator). + Delete(deleteCollaborator) }, reqRepoAdmin()) - m.Get("/raw/*", context.RepoRef(), repo.GetRawFile) + m.Get("/raw/*", context.RepoRef(), getRawFile) m.Group("/contents", func() { - m.Get("", repo.GetContents) + m.Get("", getContents) m.Combo("/*"). - Get(repo.GetContents). - Put(reqRepoWriter(), bind(repo.PutContentsRequest{}), repo.PutContents) + Get(getContents). + Put(reqRepoWriter(), bind(putContentsRequest{}), putContents) }) - m.Get("/archive/*", repo.GetArchive) + m.Get("/archive/*", getArchive) m.Group("/git", func() { m.Group("/trees", func() { - m.Get("/:sha", repo.GetRepoGitTree) + m.Get("/:sha", getRepoGitTree) }) m.Group("/blobs", func() { - m.Get("/:sha", repo.RepoGitBlob) + m.Get("/:sha", repoGitBlob) }) }) - m.Get("/forks", repo.ListForks) - m.Get("/tags", repo.ListTags) + m.Get("/forks", listForks) + m.Get("/tags", listTags) m.Group("/branches", func() { - m.Get("", repo.ListBranches) - m.Get("/*", repo.GetBranch) + m.Get("", listBranches) + m.Get("/*", getBranch) }) m.Group("/commits", func() { - m.Get("/:sha", repo.GetSingleCommit) - m.Get("", repo.GetAllCommits) - m.Get("/*", repo.GetReferenceSHA) + m.Get("/:sha", getSingleCommit) + m.Get("", getAllCommits) + m.Get("/*", getReferenceSHA) }) m.Group("/keys", func() { m.Combo(""). - Get(repo.ListDeployKeys). - Post(bind(api.CreateKeyOption{}), repo.CreateDeployKey) + Get(listDeployKeys). + Post(bind(createDeployKeyRequest{}), createDeployKey) m.Combo("/:id"). - Get(repo.GetDeployKey). - Delete(repo.DeleteDeploykey) + Get(getDeployKey). + Delete(deleteDeploykey) }, reqRepoAdmin()) m.Group("/issues", func() { m.Combo(""). - Get(repo.ListIssues). - Post(bind(api.CreateIssueOption{}), repo.CreateIssue) + Get(listIssues). + Post(bind(createIssueRequest{}), createIssue) m.Group("/comments", func() { - m.Get("", repo.ListRepoIssueComments) - m.Patch("/:id", bind(api.EditIssueCommentOption{}), repo.EditIssueComment) + m.Get("", listRepoIssueComments) + m.Patch("/:id", bind(editIssueCommentRequest{}), editIssueComment) }) m.Group("/:index", func() { m.Combo(""). - Get(repo.GetIssue). - Patch(bind(api.EditIssueOption{}), repo.EditIssue) + Get(getIssue). + Patch(bind(editIssueRequest{}), editIssue) m.Group("/comments", func() { m.Combo(""). - Get(repo.ListIssueComments). - Post(bind(api.CreateIssueCommentOption{}), repo.CreateIssueComment) + Get(listIssueComments). + Post(bind(createIssueCommentRequest{}), createIssueComment) m.Combo("/:id"). - Patch(bind(api.EditIssueCommentOption{}), repo.EditIssueComment). - Delete(repo.DeleteIssueComment) + Patch(bind(editIssueCommentRequest{}), editIssueComment). + Delete(deleteIssueComment) }) - m.Get("/labels", repo.ListIssueLabels) + m.Get("/labels", listIssueLabels) m.Group("/labels", func() { m.Combo(""). - Post(bind(api.IssueLabelsOption{}), repo.AddIssueLabels). - Put(bind(api.IssueLabelsOption{}), repo.ReplaceIssueLabels). - Delete(repo.ClearIssueLabels) - m.Delete("/:id", repo.DeleteIssueLabel) + Post(bind(issueLabelsRequest{}), addIssueLabels). + Put(bind(issueLabelsRequest{}), replaceIssueLabels). + Delete(clearIssueLabels) + m.Delete("/:id", deleteIssueLabel) }, reqRepoWriter()) }) }, mustEnableIssues) m.Group("/labels", func() { - m.Get("", repo.ListLabels) - m.Get("/:id", repo.GetLabel) + m.Get("", listLabels) + m.Get("/:id", getLabel) }) m.Group("/labels", func() { - m.Post("", bind(api.CreateLabelOption{}), repo.CreateLabel) + m.Post("", bind(createLabelRequest{}), createLabel) m.Combo("/:id"). - Patch(bind(api.EditLabelOption{}), repo.EditLabel). - Delete(repo.DeleteLabel) + Patch(bind(editLabelRequest{}), editLabel). + Delete(deleteLabel) }, reqRepoWriter()) m.Group("/milestones", func() { - m.Get("", repo.ListMilestones) - m.Get("/:id", repo.GetMilestone) + m.Get("", listMilestones) + m.Get("/:id", getMilestone) }) m.Group("/milestones", func() { - m.Post("", bind(api.CreateMilestoneOption{}), repo.CreateMilestone) + m.Post("", bind(createMilestoneRequest{}), createMilestone) m.Combo("/:id"). - Patch(bind(api.EditMilestoneOption{}), repo.EditMilestone). - Delete(repo.DeleteMilestone) + Patch(bind(editMilestoneRequest{}), editMilestone). + Delete(deleteMilestone) }, reqRepoWriter()) - m.Patch("/issue-tracker", reqRepoWriter(), bind(api.EditIssueTrackerOption{}), repo.IssueTracker) - m.Patch("/wiki", reqRepoWriter(), bind(api.EditWikiOption{}), repo.Wiki) - m.Post("/mirror-sync", reqRepoWriter(), repo.MirrorSync) - m.Get("/editorconfig/:filename", context.RepoRef(), repo.GetEditorconfig) + m.Patch("/issue-tracker", reqRepoWriter(), bind(editIssueTrackerRequest{}), issueTracker) + m.Patch("/wiki", reqRepoWriter(), bind(editWikiRequest{}), wiki) + m.Post("/mirror-sync", reqRepoWriter(), mirrorSync) + m.Get("/editorconfig/:filename", context.RepoRef(), getEditorconfig) }, repoAssignment()) }, reqToken()) - m.Get("/issues", reqToken(), repo.ListUserIssues) + m.Get("/issues", reqToken(), listUserIssues) // Organizations m.Combo("/user/orgs", reqToken()). - Get(org.ListMyOrgs). - Post(bind(api.CreateOrgOption{}), org.CreateMyOrg) + Get(listMyOrgs). + Post(bind(createOrgRequest{}), createMyOrg) - m.Get("/users/:username/orgs", org.ListUserOrgs) + m.Get("/users/:username/orgs", listUserOrgs) m.Group("/orgs/:orgname", func() { m.Combo(""). - Get(org.Get). - Patch(bind(api.EditOrgOption{}), org.Edit) - m.Get("/teams", org.ListTeams) + Get(getOrg). + Patch(bind(editOrgRequest{}), editOrg) + m.Get("/teams", listTeams) }, orgAssignment(true)) m.Group("/admin", func() { m.Group("/users", func() { - m.Post("", bind(api.CreateUserOption{}), admin.CreateUser) + m.Post("", bind(adminCreateUserRequest{}), adminCreateUser) m.Group("/:username", func() { m.Combo(""). - Patch(bind(api.EditUserOption{}), admin.EditUser). - Delete(admin.DeleteUser) - m.Post("/keys", bind(api.CreateKeyOption{}), admin.CreatePublicKey) - m.Post("/orgs", bind(api.CreateOrgOption{}), admin.CreateOrg) - m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo) + Patch(bind(adminEditUserRequest{}), adminEditUser). + Delete(adminDeleteUser) + m.Post("/keys", bind(createPublicKeyRequest{}), adminCreatePublicKey) + m.Post("/orgs", bind(createOrgRequest{}), adminCreateOrg) + m.Post("/repos", bind(createRepoRequest{}), adminCreateRepo) }) }) m.Group("/orgs/:orgname", func() { m.Group("/teams", func() { - m.Post("", orgAssignment(true), bind(api.CreateTeamOption{}), admin.CreateTeam) + m.Post("", orgAssignment(true), bind(adminCreateTeamRequest{}), adminCreateTeam) }) }) m.Group("/teams", func() { m.Group("/:teamid", func() { - m.Get("/members", admin.ListTeamMembers) + m.Get("/members", adminListTeamMembers) m.Combo("/members/:username"). - Put(admin.AddTeamMember). - Delete(admin.RemoveTeamMember) + Put(adminAddTeamMember). + Delete(adminRemoveTeamMember) m.Combo("/repos/:reponame"). - Put(admin.AddTeamRepository). - Delete(admin.RemoveTeamRepository) + Put(adminAddTeamRepository). + Delete(adminRemoveTeamRepository) }, orgAssignment(false, true)) }) }, reqAdmin()) diff --git a/internal/route/api/v1/convert/convert.go b/internal/route/api/v1/convert/convert.go deleted file mode 100644 index a4e5769ce..000000000 --- a/internal/route/api/v1/convert/convert.go +++ /dev/null @@ -1,135 +0,0 @@ -package convert - -import ( - "context" - "fmt" - "strconv" - - "github.com/gogs/git-module" - api "github.com/gogs/go-gogs-client" - - "gogs.io/gogs/internal/database" -) - -func ToEmail(email *database.EmailAddress) *api.Email { - return &api.Email{ - Email: email.Email, - Verified: email.IsActivated, - Primary: email.IsPrimary, - } -} - -func ToBranch(b *database.Branch, c *git.Commit) *api.Branch { - return &api.Branch{ - Name: b.Name, - Commit: ToCommit(c), - } -} - -type Tag struct { - Name string `json:"name"` - Commit *api.PayloadCommit `json:"commit"` -} - -func ToTag(b *database.Tag, c *git.Commit) *Tag { - return &Tag{ - Name: b.Name, - Commit: ToCommit(c), - } -} - -func ToCommit(c *git.Commit) *api.PayloadCommit { - authorUsername := "" - author, err := database.Handle.Users().GetByEmail(context.TODO(), c.Author.Email) - if err == nil { - authorUsername = author.Name - } - committerUsername := "" - committer, err := database.Handle.Users().GetByEmail(context.TODO(), c.Committer.Email) - if err == nil { - committerUsername = committer.Name - } - return &api.PayloadCommit{ - ID: c.ID.String(), - Message: c.Message, - URL: "Not implemented", - Author: &api.PayloadUser{ - Name: c.Author.Name, - Email: c.Author.Email, - UserName: authorUsername, - }, - Committer: &api.PayloadUser{ - Name: c.Committer.Name, - Email: c.Committer.Email, - UserName: committerUsername, - }, - Timestamp: c.Author.When, - } -} - -func ToPublicKey(apiLink string, key *database.PublicKey) *api.PublicKey { - return &api.PublicKey{ - ID: key.ID, - Key: key.Content, - URL: apiLink + strconv.FormatInt(key.ID, 10), - Title: key.Name, - Created: key.Created, - } -} - -func ToHook(repoLink string, w *database.Webhook) *api.Hook { - config := map[string]string{ - "url": w.URL, - "content_type": w.ContentType.Name(), - } - if w.HookTaskType == database.SLACK { - s := w.SlackMeta() - config["channel"] = s.Channel - config["username"] = s.Username - config["icon_url"] = s.IconURL - config["color"] = s.Color - } - - return &api.Hook{ - ID: w.ID, - Type: w.HookTaskType.Name(), - URL: fmt.Sprintf("%s/settings/hooks/%d", repoLink, w.ID), - Active: w.IsActive, - Config: config, - Events: w.EventsArray(), - Updated: w.Updated, - Created: w.Created, - } -} - -func ToDeployKey(apiLink string, key *database.DeployKey) *api.DeployKey { - return &api.DeployKey{ - ID: key.ID, - Key: key.Content, - URL: apiLink + strconv.FormatInt(key.ID, 10), - Title: key.Name, - Created: key.Created, - ReadOnly: true, // All deploy keys are read-only. - } -} - -func ToOrganization(org *database.User) *api.Organization { - return &api.Organization{ - ID: org.ID, - AvatarUrl: org.AvatarURL(), - UserName: org.Name, - FullName: org.FullName, - Description: org.Description, - Website: org.Website, - Location: org.Location, - } -} - -func ToTeam(team *database.Team) *api.Team { - return &api.Team{ - ID: team.ID, - Name: team.Name, - Description: team.Description, - Permission: team.Authorize.String(), - } -} diff --git a/internal/route/api/v1/convert/utils.go b/internal/route/api/v1/convert/utils.go deleted file mode 100644 index 783b61b42..000000000 --- a/internal/route/api/v1/convert/utils.go +++ /dev/null @@ -1,15 +0,0 @@ -package convert - -import ( - "gogs.io/gogs/internal/conf" -) - -// ToCorrectPageSize makes sure page size is in allowed range. -func ToCorrectPageSize(size int) int { - if size <= 0 { - size = 10 - } else if size > conf.API.MaxResponseItems { - size = conf.API.MaxResponseItems - } - return size -} diff --git a/internal/route/api/v1/misc/markdown.go b/internal/route/api/v1/markdown.go similarity index 60% rename from internal/route/api/v1/misc/markdown.go rename to internal/route/api/v1/markdown.go index f6857aa9d..4c32c2784 100644 --- a/internal/route/api/v1/misc/markdown.go +++ b/internal/route/api/v1/markdown.go @@ -1,13 +1,17 @@ -package misc +package v1 import ( - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/markup" ) -func Markdown(c *context.APIContext, form api.MarkdownOption) { +// markdownRequest represents the request body for rendering markdown. +type markdownRequest struct { + Text string + Context string +} + +func markdown(c *context.APIContext, form markdownRequest) { if form.Text == "" { _, _ = c.Write([]byte("")) return @@ -16,7 +20,7 @@ func Markdown(c *context.APIContext, form api.MarkdownOption) { _, _ = c.Write(markup.Markdown([]byte(form.Text), form.Context, nil)) } -func MarkdownRaw(c *context.APIContext) { +func markdownRaw(c *context.APIContext) { body, err := c.Req.Body().Bytes() if err != nil { c.Error(err, "read body") diff --git a/internal/route/api/v1/org/org.go b/internal/route/api/v1/org.go similarity index 55% rename from internal/route/api/v1/org/org.go rename to internal/route/api/v1/org.go index aa7182ff3..5f2a47105 100644 --- a/internal/route/api/v1/org/org.go +++ b/internal/route/api/v1/org.go @@ -1,17 +1,22 @@ -package org +package v1 import ( "net/http" - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" - "gogs.io/gogs/internal/route/api/v1/convert" - "gogs.io/gogs/internal/route/api/v1/user" + "gogs.io/gogs/internal/route/api/v1/types" ) -func CreateOrgForUser(c *context.APIContext, apiForm api.CreateOrgOption, user *database.User) { +type createOrgRequest struct { + UserName string `json:"username" binding:"Required"` + FullName string `json:"full_name"` + Description string `json:"description"` + Website string `json:"website"` + Location string `json:"location"` +} + +func createOrgForUser(c *context.APIContext, apiForm createOrgRequest, user *database.User) { if c.Written() { return } @@ -35,10 +40,10 @@ func CreateOrgForUser(c *context.APIContext, apiForm api.CreateOrgOption, user * return } - c.JSON(201, convert.ToOrganization(org)) + c.JSON(201, toOrganization(org)) } -func listUserOrgs(c *context.APIContext, u *database.User, all bool) { +func listOrgsOfUser(c *context.APIContext, u *database.User, all bool) { orgs, err := database.Handle.Organizations().List( c.Req.Context(), database.ListOrgsOptions{ @@ -51,34 +56,41 @@ func listUserOrgs(c *context.APIContext, u *database.User, all bool) { return } - apiOrgs := make([]*api.Organization, len(orgs)) + apiOrgs := make([]*types.Organization, len(orgs)) for i := range orgs { - apiOrgs[i] = convert.ToOrganization(orgs[i]) + apiOrgs[i] = toOrganization(orgs[i]) } c.JSONSuccess(&apiOrgs) } -func ListMyOrgs(c *context.APIContext) { - listUserOrgs(c, c.User, true) +func listMyOrgs(c *context.APIContext) { + listOrgsOfUser(c, c.User, true) } -func CreateMyOrg(c *context.APIContext, apiForm api.CreateOrgOption) { - CreateOrgForUser(c, apiForm, c.User) +func createMyOrg(c *context.APIContext, apiForm createOrgRequest) { + createOrgForUser(c, apiForm, c.User) } -func ListUserOrgs(c *context.APIContext) { - u := user.GetUserByParams(c) +func listUserOrgs(c *context.APIContext) { + u := getUserByParams(c) if c.Written() { return } - listUserOrgs(c, u, false) + listOrgsOfUser(c, u, false) } -func Get(c *context.APIContext) { - c.JSONSuccess(convert.ToOrganization(c.Org.Organization)) +func getOrg(c *context.APIContext) { + c.JSONSuccess(toOrganization(c.Org.Organization)) } -func Edit(c *context.APIContext, form api.EditOrgOption) { +type editOrgRequest struct { + FullName string `json:"full_name"` + Description string `json:"description"` + Website string `json:"website"` + Location string `json:"location"` +} + +func editOrg(c *context.APIContext, form editOrgRequest) { org := c.Org.Organization if !org.IsOwnedBy(c.User.ID) { c.Status(http.StatusForbidden) @@ -105,5 +117,5 @@ func Edit(c *context.APIContext, form api.EditOrgOption) { c.Error(err, "get organization") return } - c.JSONSuccess(convert.ToOrganization(org)) + c.JSONSuccess(toOrganization(org)) } diff --git a/internal/route/api/v1/org/team.go b/internal/route/api/v1/org/team.go deleted file mode 100644 index d59ac57ba..000000000 --- a/internal/route/api/v1/org/team.go +++ /dev/null @@ -1,22 +0,0 @@ -package org - -import ( - api "github.com/gogs/go-gogs-client" - - "gogs.io/gogs/internal/context" - "gogs.io/gogs/internal/route/api/v1/convert" -) - -func ListTeams(c *context.APIContext) { - org := c.Org.Organization - if err := org.GetTeams(); err != nil { - c.Error(err, "get teams") - return - } - - apiTeams := make([]*api.Team, len(org.Teams)) - for i := range org.Teams { - apiTeams[i] = convert.ToTeam(org.Teams[i]) - } - c.JSONSuccess(apiTeams) -} diff --git a/internal/route/api/v1/org_team.go b/internal/route/api/v1/org_team.go new file mode 100644 index 000000000..826fb8ab0 --- /dev/null +++ b/internal/route/api/v1/org_team.go @@ -0,0 +1,20 @@ +package v1 + +import ( + "gogs.io/gogs/internal/context" + "gogs.io/gogs/internal/route/api/v1/types" +) + +func listTeams(c *context.APIContext) { + org := c.Org.Organization + if err := org.GetTeams(); err != nil { + c.Error(err, "get teams") + return + } + + apiTeams := make([]*types.OrganizationTeam, len(org.Teams)) + for i := range org.Teams { + apiTeams[i] = toOrganizationTeam(org.Teams[i]) + } + c.JSONSuccess(apiTeams) +} diff --git a/internal/route/api/v1/repo/blob.go b/internal/route/api/v1/repo_blob.go similarity index 95% rename from internal/route/api/v1/repo/blob.go rename to internal/route/api/v1/repo_blob.go index 7c3b26159..c4dff83a6 100644 --- a/internal/route/api/v1/repo/blob.go +++ b/internal/route/api/v1/repo_blob.go @@ -1,4 +1,4 @@ -package repo +package v1 import ( "encoding/base64" @@ -11,7 +11,7 @@ import ( "gogs.io/gogs/internal/repoutil" ) -func RepoGitBlob(c *context.APIContext) { +func repoGitBlob(c *context.APIContext) { gitRepo, err := git.Open(repoutil.RepositoryPath(c.Params(":username"), c.Params(":reponame"))) if err != nil { c.Error(err, "open repository") diff --git a/internal/route/api/v1/repo/branch.go b/internal/route/api/v1/repo_branch.go similarity index 67% rename from internal/route/api/v1/repo/branch.go rename to internal/route/api/v1/repo_branch.go index 7264cb654..4f6b02c68 100644 --- a/internal/route/api/v1/repo/branch.go +++ b/internal/route/api/v1/repo_branch.go @@ -1,14 +1,12 @@ -package repo +package v1 import ( - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/context" - "gogs.io/gogs/internal/route/api/v1/convert" + "gogs.io/gogs/internal/route/api/v1/types" ) // https://github.com/gogs/go-gogs-client/wiki/Repositories#get-branch -func GetBranch(c *context.APIContext) { +func getBranch(c *context.APIContext) { branch, err := c.Repo.Repository.GetBranch(c.Params("*")) if err != nil { c.NotFoundOrError(err, "get branch") @@ -21,25 +19,25 @@ func GetBranch(c *context.APIContext) { return } - c.JSONSuccess(convert.ToBranch(branch, commit)) + c.JSONSuccess(toBranch(branch, commit)) } // https://github.com/gogs/go-gogs-client/wiki/Repositories#list-branches -func ListBranches(c *context.APIContext) { +func listBranches(c *context.APIContext) { branches, err := c.Repo.Repository.GetBranches() if err != nil { c.Error(err, "get branches") return } - apiBranches := make([]*api.Branch, len(branches)) + apiBranches := make([]*types.RepositoryBranch, len(branches)) for i := range branches { commit, err := branches[i].GetCommit() if err != nil { c.Error(err, "get commit") return } - apiBranches[i] = convert.ToBranch(branches[i], commit) + apiBranches[i] = toBranch(branches[i], commit) } c.JSONSuccess(&apiBranches) diff --git a/internal/route/api/v1/repo/collaborators.go b/internal/route/api/v1/repo_collaborators.go similarity index 77% rename from internal/route/api/v1/repo/collaborators.go rename to internal/route/api/v1/repo_collaborators.go index 11637d359..8f6218519 100644 --- a/internal/route/api/v1/repo/collaborators.go +++ b/internal/route/api/v1/repo_collaborators.go @@ -1,29 +1,32 @@ -package repo +package v1 import ( "net/http" - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" + "gogs.io/gogs/internal/route/api/v1/types" ) -func ListCollaborators(c *context.APIContext) { +func listCollaborators(c *context.APIContext) { collaborators, err := c.Repo.Repository.GetCollaborators() if err != nil { c.Error(err, "get collaborators") return } - apiCollaborators := make([]*api.Collaborator, len(collaborators)) + apiCollaborators := make([]*types.RepositoryCollaborator, len(collaborators)) for i := range collaborators { - apiCollaborators[i] = collaborators[i].APIFormat() + apiCollaborators[i] = toRepositoryCollaborator(collaborators[i]) } c.JSONSuccess(&apiCollaborators) } -func AddCollaborator(c *context.APIContext, form api.AddCollaboratorOption) { +type addCollaboratorRequest struct { + Permission *string `json:"permission"` +} + +func addCollaborator(c *context.APIContext, form addCollaboratorRequest) { collaborator, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Params(":collaborator")) if err != nil { if database.IsErrUserNotExist(err) { @@ -49,7 +52,7 @@ func AddCollaborator(c *context.APIContext, form api.AddCollaboratorOption) { c.NoContent() } -func IsCollaborator(c *context.APIContext) { +func isCollaborator(c *context.APIContext) { collaborator, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Params(":collaborator")) if err != nil { if database.IsErrUserNotExist(err) { @@ -67,7 +70,7 @@ func IsCollaborator(c *context.APIContext) { } } -func DeleteCollaborator(c *context.APIContext) { +func deleteCollaborator(c *context.APIContext) { collaborator, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Params(":collaborator")) if err != nil { if database.IsErrUserNotExist(err) { diff --git a/internal/route/api/v1/repo/commits.go b/internal/route/api/v1/repo_commits.go similarity index 80% rename from internal/route/api/v1/repo/commits.go rename to internal/route/api/v1/repo_commits.go index 5a580af90..8bc348e8d 100644 --- a/internal/route/api/v1/repo/commits.go +++ b/internal/route/api/v1/repo_commits.go @@ -1,4 +1,4 @@ -package repo +package v1 import ( "net/http" @@ -6,16 +6,18 @@ import ( "time" "github.com/gogs/git-module" - api "github.com/gogs/go-gogs-client" "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" "gogs.io/gogs/internal/gitutil" + "gogs.io/gogs/internal/route/api/v1/types" ) -// GetAllCommits returns a slice of commits starting from HEAD. -func GetAllCommits(c *context.APIContext) { +const mediaApplicationSHA = "application/vnd.gogs.sha" + +// getAllCommits returns a slice of commits starting from HEAD. +func getAllCommits(c *context.APIContext) { // Get pagesize, set default if it is not specified. pageSize := c.QueryInt("pageSize") if pageSize == 0 { @@ -29,7 +31,7 @@ func GetAllCommits(c *context.APIContext) { } // The response object returned as JSON - result := make([]*api.Commit, 0, pageSize) + result := make([]*types.Commit, 0, pageSize) commits, err := gitRepo.Log("HEAD", git.LogOptions{MaxCount: pageSize}) if err != nil { c.Error(err, "git log") @@ -47,11 +49,11 @@ func GetAllCommits(c *context.APIContext) { c.JSONSuccess(result) } -// GetSingleCommit will return a single Commit object based on the specified SHA. -func GetSingleCommit(c *context.APIContext) { - if strings.Contains(c.Req.Header.Get("Accept"), api.MediaApplicationSHA) { +// getSingleCommit will return a single Commit object based on the specified SHA. +func getSingleCommit(c *context.APIContext) { + if strings.Contains(c.Req.Header.Get("Accept"), mediaApplicationSHA) { c.SetParams("*", c.Params(":sha")) - GetReferenceSHA(c) + getReferenceSHA(c) return } @@ -73,7 +75,7 @@ func GetSingleCommit(c *context.APIContext) { c.JSONSuccess(apiCommit) } -func GetReferenceSHA(c *context.APIContext) { +func getReferenceSHA(c *context.APIContext) { gitRepo, err := git.Open(c.Repo.Repository.RepoPath()) if err != nil { c.Error(err, "open repository") @@ -114,14 +116,14 @@ func GetReferenceSHA(c *context.APIContext) { } // gitCommitToApiCommit is a helper function to convert git commit object to API commit. -func gitCommitToAPICommit(commit *git.Commit, c *context.APIContext) (*api.Commit, error) { +func gitCommitToAPICommit(commit *git.Commit, c *context.APIContext) (*types.Commit, error) { // Retrieve author and committer information - var apiAuthor, apiCommitter *api.User + var apiAuthor, apiCommitter *types.User author, err := database.Handle.Users().GetByEmail(c.Req.Context(), commit.Author.Email) if err != nil && !database.IsErrUserNotExist(err) { return nil, err } else if err == nil { - apiAuthor = author.APIFormat() + apiAuthor = toUser(author) } // Save one query if the author is also the committer @@ -132,40 +134,40 @@ func gitCommitToAPICommit(commit *git.Commit, c *context.APIContext) (*api.Commi if err != nil && !database.IsErrUserNotExist(err) { return nil, err } else if err == nil { - apiCommitter = committer.APIFormat() + apiCommitter = toUser(committer) } } // Retrieve parent(s) of the commit - apiParents := make([]*api.CommitMeta, commit.ParentsCount()) + apiParents := make([]*types.CommitMeta, commit.ParentsCount()) for i := 0; i < commit.ParentsCount(); i++ { sha, _ := commit.ParentID(i) - apiParents[i] = &api.CommitMeta{ + apiParents[i] = &types.CommitMeta{ URL: c.BaseURL + "/repos/" + c.Repo.Repository.FullName() + "/commits/" + sha.String(), SHA: sha.String(), } } - return &api.Commit{ - CommitMeta: &api.CommitMeta{ + return &types.Commit{ + CommitMeta: &types.CommitMeta{ URL: conf.Server.ExternalURL + c.Link[1:], SHA: commit.ID.String(), }, HTMLURL: c.Repo.Repository.HTMLURL() + "/commits/" + commit.ID.String(), - RepoCommit: &api.RepoCommit{ + RepoCommit: &types.RepoCommit{ URL: conf.Server.ExternalURL + c.Link[1:], - Author: &api.CommitUser{ + Author: &types.CommitUser{ Name: commit.Author.Name, Email: commit.Author.Email, Date: commit.Author.When.Format(time.RFC3339), }, - Committer: &api.CommitUser{ + Committer: &types.CommitUser{ Name: commit.Committer.Name, Email: commit.Committer.Email, Date: commit.Committer.When.Format(time.RFC3339), }, Message: commit.Summary(), - Tree: &api.CommitMeta{ + Tree: &types.CommitMeta{ URL: c.BaseURL + "/repos/" + c.Repo.Repository.FullName() + "/tree/" + commit.ID.String(), SHA: commit.ID.String(), }, diff --git a/internal/route/api/v1/repo/contents.go b/internal/route/api/v1/repo_contents.go similarity index 96% rename from internal/route/api/v1/repo/contents.go rename to internal/route/api/v1/repo_contents.go index 3f02a73ee..03a8fcc55 100644 --- a/internal/route/api/v1/repo/contents.go +++ b/internal/route/api/v1/repo_contents.go @@ -1,4 +1,4 @@ -package repo +package v1 import ( "encoding/base64" @@ -98,7 +98,7 @@ func toRepoContent(c *context.APIContext, ref, subpath string, commit *git.Commi return content, nil } -func GetContents(c *context.APIContext) { +func getContents(c *context.APIContext) { repoPath := repoutil.RepositoryPath(c.Params(":username"), c.Params(":reponame")) gitRepo, err := git.Open(repoPath) if err != nil { @@ -168,15 +168,15 @@ func GetContents(c *context.APIContext) { c.JSONSuccess(contents) } -// PutContentsRequest is the API message for creating or updating a file. -type PutContentsRequest struct { +// putContentsRequest is the API message for creating or updating a file. +type putContentsRequest struct { Message string `json:"message" binding:"Required"` Content string `json:"content" binding:"Required"` Branch string `json:"branch"` } // PUT /repos/:username/:reponame/contents/* -func PutContents(c *context.APIContext, r PutContentsRequest) { +func putContents(c *context.APIContext, r putContentsRequest) { content, err := base64.StdEncoding.DecodeString(r.Content) if err != nil { c.Error(err, "decoding base64") diff --git a/internal/route/api/v1/repo/file.go b/internal/route/api/v1/repo_file.go similarity index 78% rename from internal/route/api/v1/repo/file.go rename to internal/route/api/v1/repo_file.go index fb43bb556..ca76ca47f 100644 --- a/internal/route/api/v1/repo/file.go +++ b/internal/route/api/v1/repo_file.go @@ -1,4 +1,4 @@ -package repo +package v1 import ( "github.com/gogs/git-module" @@ -6,10 +6,10 @@ import ( "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" "gogs.io/gogs/internal/gitutil" - "gogs.io/gogs/internal/route/repo" + routerepo "gogs.io/gogs/internal/route/repo" ) -func GetRawFile(c *context.APIContext) { +func getRawFile(c *context.APIContext) { if !c.Repo.HasAccess() { c.NotFound() return @@ -25,12 +25,12 @@ func GetRawFile(c *context.APIContext) { c.NotFoundOrError(gitutil.NewError(err), "get blob") return } - if err = repo.ServeBlob(c.Context, blob); err != nil { + if err = routerepo.ServeBlob(c.Context, blob); err != nil { c.Error(err, "serve blob") } } -func GetArchive(c *context.APIContext) { +func getArchive(c *context.APIContext) { repoPath := database.RepoPath(c.Params(":username"), c.Params(":reponame")) gitRepo, err := git.Open(repoPath) if err != nil { @@ -39,10 +39,10 @@ func GetArchive(c *context.APIContext) { } c.Repo.GitRepo = gitRepo - repo.Download(c.Context) + routerepo.Download(c.Context) } -func GetEditorconfig(c *context.APIContext) { +func getEditorconfig(c *context.APIContext) { ec, err := c.Repo.Editorconfig() if err != nil { c.NotFoundOrError(gitutil.NewError(err), "get .editorconfig") diff --git a/internal/route/api/v1/repo/hook.go b/internal/route/api/v1/repo_hook.go similarity index 84% rename from internal/route/api/v1/repo/hook.go rename to internal/route/api/v1/repo_hook.go index 280f9957e..73c5eb342 100644 --- a/internal/route/api/v1/repo/hook.go +++ b/internal/route/api/v1/repo_hook.go @@ -1,4 +1,4 @@ -package repo +package v1 import ( "encoding/json" @@ -7,30 +7,35 @@ import ( "github.com/cockroachdb/errors" - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" - "gogs.io/gogs/internal/route/api/v1/convert" + "gogs.io/gogs/internal/route/api/v1/types" ) // https://github.com/gogs/go-gogs-client/wiki/Repositories#list-hooks -func ListHooks(c *context.APIContext) { +func listHooks(c *context.APIContext) { hooks, err := database.GetWebhooksByRepoID(c.Repo.Repository.ID) if err != nil { c.Errorf(err, "get webhooks by repository ID") return } - apiHooks := make([]*api.Hook, len(hooks)) + apiHooks := make([]*types.RepositoryHook, len(hooks)) for i := range hooks { - apiHooks[i] = convert.ToHook(c.Repo.RepoLink, hooks[i]) + apiHooks[i] = toRepositoryHook(c.Repo.RepoLink, hooks[i]) } c.JSONSuccess(&apiHooks) } // https://github.com/gogs/go-gogs-client/wiki/Repositories#create-a-hook -func CreateHook(c *context.APIContext, form api.CreateHookOption) { +type createHookRequest struct { + Type string `json:"type" binding:"Required"` + Config map[string]string `json:"config" binding:"Required"` + Events []string `json:"events"` + Active bool `json:"active"` +} + +func createHook(c *context.APIContext, form createHookRequest) { if !database.IsValidHookTaskType(form.Type) { c.ErrorStatus(http.StatusUnprocessableEntity, errors.New("Invalid hook type.")) return @@ -97,11 +102,17 @@ func CreateHook(c *context.APIContext, form api.CreateHookOption) { return } - c.JSON(http.StatusCreated, convert.ToHook(c.Repo.RepoLink, w)) + c.JSON(http.StatusCreated, toRepositoryHook(c.Repo.RepoLink, w)) } // https://github.com/gogs/go-gogs-client/wiki/Repositories#edit-a-hook -func EditHook(c *context.APIContext, form api.EditHookOption) { +type editHookRequest struct { + Config map[string]string `json:"config"` + Events []string `json:"events"` + Active *bool `json:"active"` +} + +func editHook(c *context.APIContext, form editHookRequest) { w, err := database.GetWebhookOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id")) if err != nil { c.NotFoundOrError(err, "get webhook of repository by ID") @@ -166,10 +177,10 @@ func EditHook(c *context.APIContext, form api.EditHookOption) { return } - c.JSONSuccess(convert.ToHook(c.Repo.RepoLink, w)) + c.JSONSuccess(toRepositoryHook(c.Repo.RepoLink, w)) } -func DeleteHook(c *context.APIContext) { +func deleteHook(c *context.APIContext) { if err := database.DeleteWebhookOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id")); err != nil { c.Errorf(err, "delete webhook of repository by ID") return diff --git a/internal/route/api/v1/repo/issue.go b/internal/route/api/v1/repo_issue.go similarity index 73% rename from internal/route/api/v1/repo/issue.go rename to internal/route/api/v1/repo_issue.go index 1f8f0a89e..b294f7e9b 100644 --- a/internal/route/api/v1/repo/issue.go +++ b/internal/route/api/v1/repo_issue.go @@ -1,18 +1,18 @@ -package repo +package v1 import ( "net/http" "strings" "github.com/cockroachdb/errors" - api "github.com/gogs/go-gogs-client" "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" + "gogs.io/gogs/internal/route/api/v1/types" ) -func listIssues(c *context.APIContext, opts *database.IssuesOptions) { +func queryIssues(c *context.APIContext, opts *database.IssuesOptions) { issues, err := database.Issues(opts) if err != nil { c.Error(err, "list issues") @@ -26,49 +26,58 @@ func listIssues(c *context.APIContext, opts *database.IssuesOptions) { } // FIXME: use IssueList to improve performance. - apiIssues := make([]*api.Issue, len(issues)) + apiIssues := make([]*types.Issue, len(issues)) for i := range issues { if err = issues[i].LoadAttributes(); err != nil { c.Error(err, "load attributes") return } - apiIssues[i] = issues[i].APIFormat() + apiIssues[i] = toIssue(issues[i]) } c.SetLinkHeader(int(count), conf.UI.IssuePagingNum) c.JSONSuccess(&apiIssues) } -func ListUserIssues(c *context.APIContext) { +func listUserIssues(c *context.APIContext) { opts := database.IssuesOptions{ AssigneeID: c.User.ID, Page: c.QueryInt("page"), - IsClosed: api.StateType(c.Query("state")) == api.STATE_CLOSED, + IsClosed: types.IssueStateType(c.Query("state")) == types.IssueStateClosed, } - listIssues(c, &opts) + queryIssues(c, &opts) } -func ListIssues(c *context.APIContext) { +func listIssues(c *context.APIContext) { opts := database.IssuesOptions{ RepoID: c.Repo.Repository.ID, Page: c.QueryInt("page"), - IsClosed: api.StateType(c.Query("state")) == api.STATE_CLOSED, + IsClosed: types.IssueStateType(c.Query("state")) == types.IssueStateClosed, } - listIssues(c, &opts) + queryIssues(c, &opts) } -func GetIssue(c *context.APIContext) { +func getIssue(c *context.APIContext) { issue, err := database.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) if err != nil { c.NotFoundOrError(err, "get issue by index") return } - c.JSONSuccess(issue.APIFormat()) + c.JSONSuccess(toIssue(issue)) } -func CreateIssue(c *context.APIContext, form api.CreateIssueOption) { +type createIssueRequest struct { + Title string `json:"title" binding:"Required"` + Body string `json:"body"` + Assignee string `json:"assignee"` + Milestone int64 `json:"milestone"` + Labels []int64 `json:"labels"` + Closed bool `json:"closed"` +} + +func createIssue(c *context.APIContext, form createIssueRequest) { issue := &database.Issue{ RepoID: c.Repo.Repository.ID, Title: form.Title, @@ -114,10 +123,18 @@ func CreateIssue(c *context.APIContext, form api.CreateIssueOption) { c.Error(err, "get issue by ID") return } - c.JSON(http.StatusCreated, issue.APIFormat()) + c.JSON(http.StatusCreated, toIssue(issue)) } -func EditIssue(c *context.APIContext, form api.EditIssueOption) { +type editIssueRequest struct { + Title string `json:"title"` + Body *string `json:"body"` + Assignee *string `json:"assignee"` + Milestone *int64 `json:"milestone"` + State *string `json:"state"` +} + +func editIssue(c *context.APIContext, form editIssueRequest) { issue, err := database.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) if err != nil { c.NotFoundOrError(err, "get issue by index") @@ -173,7 +190,7 @@ func EditIssue(c *context.APIContext, form api.EditIssueOption) { return } if form.State != nil { - if err = issue.ChangeStatus(c.User, c.Repo.Repository, api.STATE_CLOSED == api.StateType(*form.State)); err != nil { + if err = issue.ChangeStatus(c.User, c.Repo.Repository, types.IssueStateClosed == types.IssueStateType(*form.State)); err != nil { c.Error(err, "change status") return } @@ -185,5 +202,5 @@ func EditIssue(c *context.APIContext, form api.EditIssueOption) { c.Error(err, "get issue by ID") return } - c.JSON(http.StatusCreated, issue.APIFormat()) + c.JSON(http.StatusCreated, toIssue(issue)) } diff --git a/internal/route/api/v1/repo/issue_comment.go b/internal/route/api/v1/repo_issue_comment.go similarity index 77% rename from internal/route/api/v1/repo/issue_comment.go rename to internal/route/api/v1/repo_issue_comment.go index 252dd173a..d4d5cd241 100644 --- a/internal/route/api/v1/repo/issue_comment.go +++ b/internal/route/api/v1/repo_issue_comment.go @@ -1,16 +1,15 @@ -package repo +package v1 import ( "net/http" "time" - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" + "gogs.io/gogs/internal/route/api/v1/types" ) -func ListIssueComments(c *context.APIContext) { +func listIssueComments(c *context.APIContext) { var since time.Time if len(c.Query("since")) > 0 { var err error @@ -34,14 +33,14 @@ func ListIssueComments(c *context.APIContext) { return } - apiComments := make([]*api.Comment, len(comments)) + apiComments := make([]*types.IssueComment, len(comments)) for i := range comments { - apiComments[i] = comments[i].APIFormat() + apiComments[i] = toIssueComment(comments[i]) } c.JSONSuccess(&apiComments) } -func ListRepoIssueComments(c *context.APIContext) { +func listRepoIssueComments(c *context.APIContext) { var since time.Time if len(c.Query("since")) > 0 { var err error @@ -58,14 +57,18 @@ func ListRepoIssueComments(c *context.APIContext) { return } - apiComments := make([]*api.Comment, len(comments)) + apiComments := make([]*types.IssueComment, len(comments)) for i := range comments { - apiComments[i] = comments[i].APIFormat() + apiComments[i] = toIssueComment(comments[i]) } c.JSONSuccess(&apiComments) } -func CreateIssueComment(c *context.APIContext, form api.CreateIssueCommentOption) { +type createIssueCommentRequest struct { + Body string `json:"body" binding:"Required"` +} + +func createIssueComment(c *context.APIContext, form createIssueCommentRequest) { issue, err := database.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) if err != nil { c.Error(err, "get issue by index") @@ -78,10 +81,14 @@ func CreateIssueComment(c *context.APIContext, form api.CreateIssueCommentOption return } - c.JSON(http.StatusCreated, comment.APIFormat()) + c.JSON(http.StatusCreated, toIssueComment(comment)) } -func EditIssueComment(c *context.APIContext, form api.EditIssueCommentOption) { +type editIssueCommentRequest struct { + Body string `json:"body" binding:"Required"` +} + +func editIssueComment(c *context.APIContext, form editIssueCommentRequest) { comment, err := database.GetCommentByID(c.ParamsInt64(":id")) if err != nil { c.NotFoundOrError(err, "get comment by ID") @@ -113,10 +120,10 @@ func EditIssueComment(c *context.APIContext, form api.EditIssueCommentOption) { c.Error(err, "update comment") return } - c.JSONSuccess(comment.APIFormat()) + c.JSONSuccess(toIssueComment(comment)) } -func DeleteIssueComment(c *context.APIContext) { +func deleteIssueComment(c *context.APIContext) { comment, err := database.GetCommentByID(c.ParamsInt64(":id")) if err != nil { c.NotFoundOrError(err, "get comment by ID") diff --git a/internal/route/api/v1/repo/issue_label.go b/internal/route/api/v1/repo_issue_label.go similarity index 76% rename from internal/route/api/v1/repo/issue_label.go rename to internal/route/api/v1/repo_issue_label.go index e22e39c2f..391cbfaed 100644 --- a/internal/route/api/v1/repo/issue_label.go +++ b/internal/route/api/v1/repo_issue_label.go @@ -1,29 +1,32 @@ -package repo +package v1 import ( "net/http" - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" + "gogs.io/gogs/internal/route/api/v1/types" ) -func ListIssueLabels(c *context.APIContext) { +func listIssueLabels(c *context.APIContext) { issue, err := database.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) if err != nil { c.NotFoundOrError(err, "get issue by index") return } - apiLabels := make([]*api.Label, len(issue.Labels)) + apiLabels := make([]*types.IssueLabel, len(issue.Labels)) for i := range issue.Labels { - apiLabels[i] = issue.Labels[i].APIFormat() + apiLabels[i] = toIssueLabel(issue.Labels[i]) } c.JSONSuccess(&apiLabels) } -func AddIssueLabels(c *context.APIContext, form api.IssueLabelsOption) { +type issueLabelsRequest struct { + Labels []int64 `json:"labels"` +} + +func addIssueLabels(c *context.APIContext, form issueLabelsRequest) { issue, err := database.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) if err != nil { c.NotFoundOrError(err, "get issue by index") @@ -47,14 +50,14 @@ func AddIssueLabels(c *context.APIContext, form api.IssueLabelsOption) { return } - apiLabels := make([]*api.Label, len(labels)) + apiLabels := make([]*types.IssueLabel, len(labels)) for i := range labels { - apiLabels[i] = issue.Labels[i].APIFormat() + apiLabels[i] = toIssueLabel(issue.Labels[i]) } c.JSONSuccess(&apiLabels) } -func DeleteIssueLabel(c *context.APIContext) { +func deleteIssueLabel(c *context.APIContext) { issue, err := database.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) if err != nil { c.NotFoundOrError(err, "get issue by index") @@ -79,7 +82,7 @@ func DeleteIssueLabel(c *context.APIContext) { c.NoContent() } -func ReplaceIssueLabels(c *context.APIContext, form api.IssueLabelsOption) { +func replaceIssueLabels(c *context.APIContext, form issueLabelsRequest) { issue, err := database.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) if err != nil { c.NotFoundOrError(err, "get issue by index") @@ -103,14 +106,14 @@ func ReplaceIssueLabels(c *context.APIContext, form api.IssueLabelsOption) { return } - apiLabels := make([]*api.Label, len(labels)) + apiLabels := make([]*types.IssueLabel, len(labels)) for i := range labels { - apiLabels[i] = issue.Labels[i].APIFormat() + apiLabels[i] = toIssueLabel(issue.Labels[i]) } c.JSONSuccess(&apiLabels) } -func ClearIssueLabels(c *context.APIContext) { +func clearIssueLabels(c *context.APIContext) { issue, err := database.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) if err != nil { c.NotFoundOrError(err, "get issue by index") diff --git a/internal/route/api/v1/repo/key.go b/internal/route/api/v1/repo_key.go similarity index 77% rename from internal/route/api/v1/repo/key.go rename to internal/route/api/v1/repo_key.go index 21b3dcbf1..eacc9b060 100644 --- a/internal/route/api/v1/repo/key.go +++ b/internal/route/api/v1/repo_key.go @@ -1,15 +1,14 @@ -package repo +package v1 import ( "net/http" "github.com/cockroachdb/errors" - api "github.com/gogs/go-gogs-client" "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" - "gogs.io/gogs/internal/route/api/v1/convert" + "gogs.io/gogs/internal/route/api/v1/types" ) func composeDeployKeysAPILink(repoPath string) string { @@ -17,7 +16,7 @@ func composeDeployKeysAPILink(repoPath string) string { } // https://github.com/gogs/go-gogs-client/wiki/Repositories-Deploy-Keys#list-deploy-keys -func ListDeployKeys(c *context.APIContext) { +func listDeployKeys(c *context.APIContext) { keys, err := database.ListDeployKeys(c.Repo.Repository.ID) if err != nil { c.Error(err, "list deploy keys") @@ -25,20 +24,20 @@ func ListDeployKeys(c *context.APIContext) { } apiLink := composeDeployKeysAPILink(c.Repo.Owner.Name + "/" + c.Repo.Repository.Name) - apiKeys := make([]*api.DeployKey, len(keys)) + apiKeys := make([]*types.RepositoryDeployKey, len(keys)) for i := range keys { if err = keys[i].GetContent(); err != nil { c.Error(err, "get content") return } - apiKeys[i] = convert.ToDeployKey(apiLink, keys[i]) + apiKeys[i] = toDeployKey(apiLink, keys[i]) } c.JSONSuccess(&apiKeys) } // https://github.com/gogs/go-gogs-client/wiki/Repositories-Deploy-Keys#get-a-deploy-key -func GetDeployKey(c *context.APIContext) { +func getDeployKey(c *context.APIContext) { key, err := database.GetDeployKeyByID(c.ParamsInt64(":id")) if err != nil { c.NotFoundOrError(err, "get deploy key by ID") @@ -56,10 +55,10 @@ func GetDeployKey(c *context.APIContext) { } apiLink := composeDeployKeysAPILink(c.Repo.Owner.Name + "/" + c.Repo.Repository.Name) - c.JSONSuccess(convert.ToDeployKey(apiLink, key)) + c.JSONSuccess(toDeployKey(apiLink, key)) } -func HandleCheckKeyStringError(c *context.APIContext, err error) { +func handleCheckKeyStringError(c *context.APIContext, err error) { if database.IsErrKeyUnableVerify(err) { c.ErrorStatus(http.StatusUnprocessableEntity, errors.New("Unable to verify key content")) } else { @@ -67,7 +66,7 @@ func HandleCheckKeyStringError(c *context.APIContext, err error) { } } -func HandleAddKeyError(c *context.APIContext, err error) { +func handleAddKeyError(c *context.APIContext, err error) { switch { case database.IsErrKeyAlreadyExist(err): c.ErrorStatus(http.StatusUnprocessableEntity, errors.New("Key content has been used as non-deploy key")) @@ -79,26 +78,31 @@ func HandleAddKeyError(c *context.APIContext, err error) { } // https://github.com/gogs/go-gogs-client/wiki/Repositories-Deploy-Keys#add-a-new-deploy-key -func CreateDeployKey(c *context.APIContext, form api.CreateKeyOption) { +type createDeployKeyRequest struct { + Title string `json:"title" binding:"Required"` + Key string `json:"key" binding:"Required"` +} + +func createDeployKey(c *context.APIContext, form createDeployKeyRequest) { content, err := database.CheckPublicKeyString(form.Key) if err != nil { - HandleCheckKeyStringError(c, err) + handleCheckKeyStringError(c, err) return } key, err := database.AddDeployKey(c.Repo.Repository.ID, form.Title, content) if err != nil { - HandleAddKeyError(c, err) + handleAddKeyError(c, err) return } key.Content = content apiLink := composeDeployKeysAPILink(c.Repo.Owner.Name + "/" + c.Repo.Repository.Name) - c.JSON(http.StatusCreated, convert.ToDeployKey(apiLink, key)) + c.JSON(http.StatusCreated, toDeployKey(apiLink, key)) } // https://github.com/gogs/go-gogs-client/wiki/Repositories-Deploy-Keys#remove-a-deploy-key -func DeleteDeploykey(c *context.APIContext) { +func deleteDeploykey(c *context.APIContext) { key, err := database.GetDeployKeyByID(c.ParamsInt64(":id")) if err != nil { c.NotFoundOrError(err, "get deploy key by ID") diff --git a/internal/route/api/v1/repo/label.go b/internal/route/api/v1/repo_label.go similarity index 64% rename from internal/route/api/v1/repo/label.go rename to internal/route/api/v1/repo_label.go index f663a8e8a..f5f199608 100644 --- a/internal/route/api/v1/repo/label.go +++ b/internal/route/api/v1/repo_label.go @@ -1,30 +1,29 @@ -package repo +package v1 import ( "net/http" "strconv" - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" + "gogs.io/gogs/internal/route/api/v1/types" ) -func ListLabels(c *context.APIContext) { +func listLabels(c *context.APIContext) { labels, err := database.GetLabelsByRepoID(c.Repo.Repository.ID) if err != nil { c.Error(err, "get labels by repository ID") return } - apiLabels := make([]*api.Label, len(labels)) + apiLabels := make([]*types.IssueLabel, len(labels)) for i := range labels { - apiLabels[i] = labels[i].APIFormat() + apiLabels[i] = toIssueLabel(labels[i]) } c.JSONSuccess(&apiLabels) } -func GetLabel(c *context.APIContext) { +func getLabel(c *context.APIContext) { var label *database.Label var err error idStr := c.Params(":id") @@ -38,10 +37,15 @@ func GetLabel(c *context.APIContext) { return } - c.JSONSuccess(label.APIFormat()) + c.JSONSuccess(toIssueLabel(label)) } -func CreateLabel(c *context.APIContext, form api.CreateLabelOption) { +type createLabelRequest struct { + Name string `json:"name" binding:"Required"` + Color string `json:"color" binding:"Required;Size(7)"` +} + +func createLabel(c *context.APIContext, form createLabelRequest) { label := &database.Label{ Name: form.Name, Color: form.Color, @@ -51,10 +55,15 @@ func CreateLabel(c *context.APIContext, form api.CreateLabelOption) { c.Error(err, "new labels") return } - c.JSON(http.StatusCreated, label.APIFormat()) + c.JSON(http.StatusCreated, toIssueLabel(label)) } -func EditLabel(c *context.APIContext, form api.EditLabelOption) { +type editLabelRequest struct { + Name *string `json:"name"` + Color *string `json:"color"` +} + +func editLabel(c *context.APIContext, form editLabelRequest) { label, err := database.GetLabelOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id")) if err != nil { c.NotFoundOrError(err, "get label of repository by ID") @@ -71,10 +80,10 @@ func EditLabel(c *context.APIContext, form api.EditLabelOption) { c.Error(err, "update label") return } - c.JSONSuccess(label.APIFormat()) + c.JSONSuccess(toIssueLabel(label)) } -func DeleteLabel(c *context.APIContext) { +func deleteLabel(c *context.APIContext) { if err := database.DeleteLabel(c.Repo.Repository.ID, c.ParamsInt64(":id")); err != nil { c.Error(err, "delete label") return diff --git a/internal/route/api/v1/repo/milestone.go b/internal/route/api/v1/repo_milestone.go similarity index 61% rename from internal/route/api/v1/repo/milestone.go rename to internal/route/api/v1/repo_milestone.go index 97faf483a..4c8753bc5 100644 --- a/internal/route/api/v1/repo/milestone.go +++ b/internal/route/api/v1/repo_milestone.go @@ -1,39 +1,44 @@ -package repo +package v1 import ( "net/http" "time" - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" + "gogs.io/gogs/internal/route/api/v1/types" ) -func ListMilestones(c *context.APIContext) { +func listMilestones(c *context.APIContext) { milestones, err := database.GetMilestonesByRepoID(c.Repo.Repository.ID) if err != nil { c.Error(err, "get milestones by repository ID") return } - apiMilestones := make([]*api.Milestone, len(milestones)) + apiMilestones := make([]*types.IssueMilestone, len(milestones)) for i := range milestones { - apiMilestones[i] = milestones[i].APIFormat() + apiMilestones[i] = toIssueMilestone(milestones[i]) } c.JSONSuccess(&apiMilestones) } -func GetMilestone(c *context.APIContext) { +func getMilestone(c *context.APIContext) { milestone, err := database.GetMilestoneByRepoID(c.Repo.Repository.ID, c.ParamsInt64(":id")) if err != nil { c.NotFoundOrError(err, "get milestone by repository ID") return } - c.JSONSuccess(milestone.APIFormat()) + c.JSONSuccess(toIssueMilestone(milestone)) } -func CreateMilestone(c *context.APIContext, form api.CreateMilestoneOption) { +type createMilestoneRequest struct { + Title string `json:"title"` + Description string `json:"description"` + Deadline *time.Time `json:"due_on"` +} + +func createMilestone(c *context.APIContext, form createMilestoneRequest) { if form.Deadline == nil { defaultDeadline, _ := time.ParseInLocation("2006-01-02", "9999-12-31", time.Local) form.Deadline = &defaultDeadline @@ -50,10 +55,17 @@ func CreateMilestone(c *context.APIContext, form api.CreateMilestoneOption) { c.Error(err, "new milestone") return } - c.JSON(http.StatusCreated, milestone.APIFormat()) + c.JSON(http.StatusCreated, toIssueMilestone(milestone)) } -func EditMilestone(c *context.APIContext, form api.EditMilestoneOption) { +type editMilestoneRequest struct { + Title string `json:"title"` + Description *string `json:"description"` + State *string `json:"state"` + Deadline *time.Time `json:"due_on"` +} + +func editMilestone(c *context.APIContext, form editMilestoneRequest) { milestone, err := database.GetMilestoneByRepoID(c.Repo.Repository.ID, c.ParamsInt64(":id")) if err != nil { c.NotFoundOrError(err, "get milestone by repository ID") @@ -71,7 +83,7 @@ func EditMilestone(c *context.APIContext, form api.EditMilestoneOption) { } if form.State != nil { - if err = milestone.ChangeStatus(api.STATE_CLOSED == api.StateType(*form.State)); err != nil { + if err = milestone.ChangeStatus(types.IssueStateClosed == types.IssueStateType(*form.State)); err != nil { c.Error(err, "change status") return } @@ -80,10 +92,10 @@ func EditMilestone(c *context.APIContext, form api.EditMilestoneOption) { return } - c.JSONSuccess(milestone.APIFormat()) + c.JSONSuccess(toIssueMilestone(milestone)) } -func DeleteMilestone(c *context.APIContext) { +func deleteMilestone(c *context.APIContext) { if err := database.DeleteMilestoneOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id")); err != nil { c.Error(err, "delete milestone of repository by ID") return diff --git a/internal/route/api/v1/repo/repo.go b/internal/route/api/v1/repo_repo.go similarity index 77% rename from internal/route/api/v1/repo/repo.go rename to internal/route/api/v1/repo_repo.go index 349882b3b..f181bfdd5 100644 --- a/internal/route/api/v1/repo/repo.go +++ b/internal/route/api/v1/repo_repo.go @@ -1,25 +1,24 @@ -package repo +package v1 import ( "net/http" "path" "github.com/cockroachdb/errors" - api "github.com/gogs/go-gogs-client" log "unknwon.dev/clog/v2" "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" "gogs.io/gogs/internal/form" - "gogs.io/gogs/internal/route/api/v1/convert" + "gogs.io/gogs/internal/route/api/v1/types" ) -func Search(c *context.APIContext) { +func searchRepos(c *context.APIContext) { opts := &database.SearchRepoOptions{ Keyword: path.Base(c.Query("q")), OwnerID: c.QueryInt64("uid"), - PageSize: convert.ToCorrectPageSize(c.QueryInt("limit")), + PageSize: toAllowedPageSize(c.QueryInt("limit")), Page: c.QueryInt("page"), } @@ -60,9 +59,9 @@ func Search(c *context.APIContext) { return } - results := make([]*api.Repository, len(repos)) + results := make([]*types.Repository, len(repos)) for i := range repos { - results[i] = repos[i].APIFormatLegacy(nil) + results[i] = toRepository(repos[i], nil) } c.SetLinkHeader(int(count), opts.PageSize) @@ -72,7 +71,7 @@ func Search(c *context.APIContext) { }) } -func listUserRepositories(c *context.APIContext, username string) { +func listReposOfUser(c *context.APIContext, username string) { user, err := database.Handle.Users().GetByUsername(c.Req.Context(), username) if err != nil { c.NotFoundOrError(err, "get user by name") @@ -104,9 +103,9 @@ func listUserRepositories(c *context.APIContext, username string) { // Early return for querying other user's repositories if c.User.ID != user.ID { - repos := make([]*api.Repository, len(ownRepos)) + repos := make([]*types.Repository, len(ownRepos)) for i := range ownRepos { - repos[i] = ownRepos[i].APIFormatLegacy(&api.Permission{Admin: true, Push: true, Pull: true}) + repos[i] = toRepository(ownRepos[i], &types.RepositoryPermission{Admin: true, Push: true, Pull: true}) } c.JSONSuccess(&repos) return @@ -128,14 +127,14 @@ func listUserRepositories(c *context.APIContext, username string) { } numOwnRepos := len(ownRepos) - repos := make([]*api.Repository, 0, numOwnRepos+len(accessibleReposWithAccessMode)) + repos := make([]*types.Repository, 0, numOwnRepos+len(accessibleReposWithAccessMode)) for _, r := range ownRepos { - repos = append(repos, r.APIFormatLegacy(&api.Permission{Admin: true, Push: true, Pull: true})) + repos = append(repos, toRepository(r, &types.RepositoryPermission{Admin: true, Push: true, Pull: true})) } for repo, access := range accessibleReposWithAccessMode { repos = append(repos, - repo.APIFormatLegacy(&api.Permission{ + toRepository(repo, &types.RepositoryPermission{ Admin: access >= database.AccessModeAdmin, Push: access >= database.AccessModeWrite, Pull: true, @@ -146,19 +145,29 @@ func listUserRepositories(c *context.APIContext, username string) { c.JSONSuccess(&repos) } -func ListMyRepos(c *context.APIContext) { - listUserRepositories(c, c.User.Name) +func listMyRepos(c *context.APIContext) { + listReposOfUser(c, c.User.Name) } -func ListUserRepositories(c *context.APIContext) { - listUserRepositories(c, c.Params(":username")) +func listUserRepositories(c *context.APIContext) { + listReposOfUser(c, c.Params(":username")) } -func ListOrgRepositories(c *context.APIContext) { - listUserRepositories(c, c.Params(":org")) +func listOrgRepositories(c *context.APIContext) { + listReposOfUser(c, c.Params(":org")) } -func CreateUserRepo(c *context.APIContext, owner *database.User, opt api.CreateRepoOption) { +type createRepoRequest struct { + Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(100)"` + Description string `json:"description" binding:"MaxSize(255)"` + Private bool `json:"private"` + AutoInit bool `json:"auto_init"` + Gitignores string `json:"gitignores"` + License string `json:"license"` + Readme string `json:"readme"` +} + +func createUserRepo(c *context.APIContext, owner *database.User, opt createRepoRequest) { repo, err := database.CreateRepository(c.User, owner, database.CreateRepoOptionsLegacy{ Name: opt.Name, Description: opt.Description, @@ -183,19 +192,19 @@ func CreateUserRepo(c *context.APIContext, owner *database.User, opt api.CreateR return } - c.JSON(201, repo.APIFormatLegacy(&api.Permission{Admin: true, Push: true, Pull: true})) + c.JSON(201, toRepository(repo, &types.RepositoryPermission{Admin: true, Push: true, Pull: true})) } -func Create(c *context.APIContext, opt api.CreateRepoOption) { +func createRepo(c *context.APIContext, opt createRepoRequest) { // Shouldn't reach this condition, but just in case. if c.User.IsOrganization() { c.ErrorStatus(http.StatusUnprocessableEntity, errors.New("Not allowed to create repository for organization.")) return } - CreateUserRepo(c, c.User, opt) + createUserRepo(c, c.User, opt) } -func CreateOrgRepo(c *context.APIContext, opt api.CreateRepoOption) { +func createOrgRepo(c *context.APIContext, opt createRepoRequest) { org, err := database.GetOrgByName(c.Params(":org")) if err != nil { c.NotFoundOrError(err, "get organization by name") @@ -206,10 +215,10 @@ func CreateOrgRepo(c *context.APIContext, opt api.CreateRepoOption) { c.ErrorStatus(http.StatusForbidden, errors.New("Given user is not owner of organization.")) return } - CreateUserRepo(c, org, opt) + createUserRepo(c, org, opt) } -func Migrate(c *context.APIContext, f form.MigrateRepo) { +func migrate(c *context.APIContext, f form.MigrateRepo) { ctxUser := c.User // Not equal means context user is an organization, // or is another user/organization if current user is admin. @@ -287,7 +296,7 @@ func Migrate(c *context.APIContext, f form.MigrateRepo) { } log.Trace("Repository migrated: %s/%s", ctxUser.Name, f.RepoName) - c.JSON(201, repo.APIFormatLegacy(&api.Permission{Admin: true, Push: true, Pull: true})) + c.JSON(201, toRepository(repo, &types.RepositoryPermission{Admin: true, Push: true, Pull: true})) } // FIXME: inject in the handler chain @@ -311,20 +320,20 @@ func parseOwnerAndRepo(c *context.APIContext) (*database.User, *database.Reposit return owner, repo } -func Get(c *context.APIContext) { +func getRepo(c *context.APIContext) { _, repo := parseOwnerAndRepo(c) if c.Written() { return } - c.JSONSuccess(repo.APIFormatLegacy(&api.Permission{ + c.JSONSuccess(toRepository(repo, &types.RepositoryPermission{ Admin: c.Repo.IsAdmin(), Push: c.Repo.IsWriter(), Pull: true, })) } -func Delete(c *context.APIContext) { +func deleteRepo(c *context.APIContext) { owner, repo := parseOwnerAndRepo(c) if c.Written() { return @@ -344,14 +353,14 @@ func Delete(c *context.APIContext) { c.NoContent() } -func ListForks(c *context.APIContext) { +func listForks(c *context.APIContext) { forks, err := c.Repo.Repository.GetForks() if err != nil { c.Error(err, "get forks") return } - apiForks := make([]*api.Repository, len(forks)) + apiForks := make([]*types.Repository, len(forks)) for i := range forks { if err := forks[i].GetOwner(); err != nil { c.Error(err, "get owner") @@ -368,8 +377,8 @@ func ListForks(c *context.APIContext) { }, ) - apiForks[i] = forks[i].APIFormatLegacy( - &api.Permission{ + apiForks[i] = toRepository(forks[i], + &types.RepositoryPermission{ Admin: accessMode >= database.AccessModeAdmin, Push: accessMode >= database.AccessModeWrite, Pull: true, @@ -380,7 +389,15 @@ func ListForks(c *context.APIContext) { c.JSONSuccess(&apiForks) } -func IssueTracker(c *context.APIContext, form api.EditIssueTrackerOption) { +type editIssueTrackerRequest struct { + EnableIssues *bool `json:"enable_issues"` + EnableExternalTracker *bool `json:"enable_external_tracker"` + ExternalTrackerURL *string `json:"external_tracker_url"` + TrackerURLFormat *string `json:"tracker_url_format"` + TrackerIssueStyle *string `json:"tracker_issue_style"` +} + +func issueTracker(c *context.APIContext, form editIssueTrackerRequest) { _, repo := parseOwnerAndRepo(c) if c.Written() { return @@ -410,7 +427,14 @@ func IssueTracker(c *context.APIContext, form api.EditIssueTrackerOption) { c.NoContent() } -func Wiki(c *context.APIContext, form api.EditWikiOption) { +type editWikiRequest struct { + EnableWiki *bool `json:"enable_wiki"` + AllowPublicWiki *bool `json:"allow_public_wiki"` + EnableExternalWiki *bool `json:"enable_external_wiki"` + ExternalWikiURL *string `json:"external_wiki_url"` +} + +func wiki(c *context.APIContext, form editWikiRequest) { _, repo := parseOwnerAndRepo(c) if c.Written() { return @@ -436,7 +460,7 @@ func Wiki(c *context.APIContext, form api.EditWikiOption) { c.NoContent() } -func MirrorSync(c *context.APIContext) { +func mirrorSync(c *context.APIContext) { _, repo := parseOwnerAndRepo(c) if c.Written() { return @@ -449,14 +473,14 @@ func MirrorSync(c *context.APIContext) { c.Status(http.StatusAccepted) } -func Releases(c *context.APIContext) { +func releases(c *context.APIContext) { _, repo := parseOwnerAndRepo(c) releases, err := database.GetReleasesByRepoID(repo.ID) if err != nil { c.Error(err, "get releases by repository ID") return } - apiReleases := make([]*api.Release, 0, len(releases)) + apiReleases := make([]*types.RepositoryRelease, 0, len(releases)) for _, r := range releases { publisher, err := database.Handle.Users().GetByID(c.Req.Context(), r.PublisherID) if err != nil { @@ -466,7 +490,7 @@ func Releases(c *context.APIContext) { r.Publisher = publisher } for _, r := range releases { - apiReleases = append(apiReleases, r.APIFormat()) + apiReleases = append(apiReleases, toRelease(r)) } c.JSONSuccess(&apiReleases) diff --git a/internal/route/api/v1/repo/tag.go b/internal/route/api/v1/repo_tag.go similarity index 61% rename from internal/route/api/v1/repo/tag.go rename to internal/route/api/v1/repo_tag.go index b8049873b..bc14dbb24 100644 --- a/internal/route/api/v1/repo/tag.go +++ b/internal/route/api/v1/repo_tag.go @@ -1,25 +1,24 @@ -package repo +package v1 import ( "gogs.io/gogs/internal/context" - "gogs.io/gogs/internal/route/api/v1/convert" ) -func ListTags(c *context.APIContext) { +func listTags(c *context.APIContext) { tags, err := c.Repo.Repository.GetTags() if err != nil { c.Error(err, "get tags") return } - apiTags := make([]*convert.Tag, len(tags)) + apiTags := make([]*tag, len(tags)) for i := range tags { commit, err := tags[i].GetCommit() if err != nil { c.Error(err, "get commit") return } - apiTags[i] = convert.ToTag(tags[i], commit) + apiTags[i] = toTag(tags[i], commit) } c.JSONSuccess(&apiTags) diff --git a/internal/route/api/v1/repo/tree.go b/internal/route/api/v1/repo_tree.go similarity index 96% rename from internal/route/api/v1/repo/tree.go rename to internal/route/api/v1/repo_tree.go index a3887b32d..46214104b 100644 --- a/internal/route/api/v1/repo/tree.go +++ b/internal/route/api/v1/repo_tree.go @@ -1,4 +1,4 @@ -package repo +package v1 import ( "fmt" @@ -9,7 +9,7 @@ import ( "gogs.io/gogs/internal/gitutil" ) -func GetRepoGitTree(c *context.APIContext) { +func getRepoGitTree(c *context.APIContext) { gitRepo, err := git.Open(c.Repo.Repository.RepoPath()) if err != nil { c.Error(err, "open repository") diff --git a/internal/route/api/v1/tag.go b/internal/route/api/v1/tag.go new file mode 100644 index 000000000..b6672bab2 --- /dev/null +++ b/internal/route/api/v1/tag.go @@ -0,0 +1,8 @@ +package v1 + +import "gogs.io/gogs/internal/route/api/v1/types" + +type tag struct { + Name string `json:"name"` + Commit *types.WebhookPayloadCommit `json:"commit"` +} diff --git a/internal/route/api/v1/types/commit.go b/internal/route/api/v1/types/commit.go new file mode 100644 index 000000000..6d9ae903e --- /dev/null +++ b/internal/route/api/v1/types/commit.go @@ -0,0 +1,29 @@ +package types + +type CommitMeta struct { + URL string `json:"url"` + SHA string `json:"sha"` +} + +type CommitUser struct { + Name string `json:"name"` + Email string `json:"email"` + Date string `json:"date"` +} + +type RepoCommit struct { + URL string `json:"url"` + Author *CommitUser `json:"author"` + Committer *CommitUser `json:"committer"` + Message string `json:"message"` + Tree *CommitMeta `json:"tree"` +} + +type Commit struct { + *CommitMeta + HTMLURL string `json:"html_url"` + RepoCommit *RepoCommit `json:"commit"` + Author *User `json:"author"` + Committer *User `json:"committer"` + Parents []*CommitMeta `json:"parents"` +} diff --git a/internal/route/api/v1/types/hook.go b/internal/route/api/v1/types/hook.go new file mode 100644 index 000000000..7f419f55d --- /dev/null +++ b/internal/route/api/v1/types/hook.go @@ -0,0 +1,23 @@ +package types + +import "time" + +type RepositoryHook struct { + ID int64 `json:"id"` + Type string `json:"type"` + URL string `json:"-"` + Config map[string]string `json:"config"` + Events []string `json:"events"` + Active bool `json:"active"` + Updated time.Time `json:"updated_at"` + Created time.Time `json:"created_at"` +} + +type RepositoryDeployKey struct { + ID int64 `json:"id"` + Key string `json:"key"` + URL string `json:"url"` + Title string `json:"title"` + Created time.Time `json:"created_at"` + ReadOnly bool `json:"read_only"` +} diff --git a/internal/route/api/v1/types/issue.go b/internal/route/api/v1/types/issue.go new file mode 100644 index 000000000..1879b7312 --- /dev/null +++ b/internal/route/api/v1/types/issue.go @@ -0,0 +1,58 @@ +package types + +import "time" + +type IssueStateType string + +const ( + IssueStateOpen IssueStateType = "open" + IssueStateClosed IssueStateType = "closed" +) + +type PullRequestMeta struct { + HasMerged bool `json:"merged"` + Merged *time.Time `json:"merged_at"` +} + +type Issue struct { + ID int64 `json:"id"` + Index int64 `json:"number"` + Poster *User `json:"user"` + Title string `json:"title"` + Body string `json:"body"` + Labels []*IssueLabel `json:"labels"` + Milestone *IssueMilestone `json:"milestone"` + Assignee *User `json:"assignee"` + State IssueStateType `json:"state"` + Comments int `json:"comments"` + Created time.Time `json:"created_at"` + Updated time.Time `json:"updated_at"` + PullRequest *PullRequestMeta `json:"pull_request"` +} + +type IssueLabel struct { + ID int64 `json:"id"` + Name string `json:"name"` + Color string `json:"color"` + URL string `json:"url"` +} + +type IssueMilestone struct { + ID int64 `json:"id"` + Title string `json:"title"` + Description string `json:"description"` + State IssueStateType `json:"state"` + OpenIssues int `json:"open_issues"` + ClosedIssues int `json:"closed_issues"` + Closed *time.Time `json:"closed_at"` + Deadline *time.Time `json:"due_on"` +} + +type IssueComment struct { + ID int64 `json:"id"` + HTMLURL string `json:"html_url"` + Poster *User `json:"user"` + Body string `json:"body"` + Created time.Time `json:"created_at"` + Updated time.Time `json:"updated_at"` +} diff --git a/internal/route/api/v1/types/org.go b/internal/route/api/v1/types/org.go new file mode 100644 index 000000000..0a91747da --- /dev/null +++ b/internal/route/api/v1/types/org.go @@ -0,0 +1,18 @@ +package types + +type Organization struct { + ID int64 `json:"id"` + UserName string `json:"username"` + FullName string `json:"full_name"` + AvatarURL string `json:"avatar_url"` + Description string `json:"description"` + Website string `json:"website"` + Location string `json:"location"` +} + +type OrganizationTeam struct { + ID int64 `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Permission string `json:"permission"` +} diff --git a/internal/route/api/v1/types/pull_request.go b/internal/route/api/v1/types/pull_request.go new file mode 100644 index 000000000..8c918ca84 --- /dev/null +++ b/internal/route/api/v1/types/pull_request.go @@ -0,0 +1,26 @@ +package types + +import "time" + +type PullRequest struct { + ID int64 `json:"id"` + Index int64 `json:"number"` + Poster *User `json:"user"` + Title string `json:"title"` + Body string `json:"body"` + Labels []*IssueLabel `json:"labels"` + Milestone *IssueMilestone `json:"milestone"` + Assignee *User `json:"assignee"` + State IssueStateType `json:"state"` + Comments int `json:"comments"` + HeadBranch string `json:"head_branch"` + HeadRepo *Repository `json:"head_repo"` + BaseBranch string `json:"base_branch"` + BaseRepo *Repository `json:"base_repo"` + HTMLURL string `json:"html_url"` + Mergeable *bool `json:"mergeable"` + HasMerged bool `json:"merged"` + Merged *time.Time `json:"merged_at"` + MergedCommitID *string `json:"merge_commit_sha"` + MergedBy *User `json:"merged_by"` +} diff --git a/internal/route/api/v1/types/repo.go b/internal/route/api/v1/types/repo.go new file mode 100644 index 000000000..dc5842f2e --- /dev/null +++ b/internal/route/api/v1/types/repo.go @@ -0,0 +1,52 @@ +package types + +import "time" + +type RepositoryPermission struct { + Admin bool `json:"admin"` + Push bool `json:"push"` + Pull bool `json:"pull"` +} + +type Repository struct { + ID int64 `json:"id"` + Owner *User `json:"owner"` + Name string `json:"name"` + FullName string `json:"full_name"` + Description string `json:"description"` + Private bool `json:"private"` + Fork bool `json:"fork"` + Parent *Repository `json:"parent"` + Empty bool `json:"empty"` + Mirror bool `json:"mirror"` + Size int64 `json:"size"` + HTMLURL string `json:"html_url"` + SSHURL string `json:"ssh_url"` + CloneURL string `json:"clone_url"` + Website string `json:"website"` + Stars int `json:"stars_count"` + Forks int `json:"forks_count"` + Watchers int `json:"watchers_count"` + OpenIssues int `json:"open_issues_count"` + DefaultBranch string `json:"default_branch"` + Created time.Time `json:"created_at"` + Updated time.Time `json:"updated_at"` + Permissions *RepositoryPermission `json:"permissions,omitempty"` +} + +type RepositoryBranch struct { + Name string `json:"name"` + Commit *WebhookPayloadCommit `json:"commit"` +} + +type RepositoryRelease struct { + ID int64 `json:"id"` + TagName string `json:"tag_name"` + TargetCommitish string `json:"target_commitish"` + Name string `json:"name"` + Body string `json:"body"` + Draft bool `json:"draft"` + Prerelease bool `json:"prerelease"` + Author *User `json:"author"` + Created time.Time `json:"created_at"` +} diff --git a/internal/route/api/v1/types/user.go b/internal/route/api/v1/types/user.go new file mode 100644 index 000000000..f29693dc4 --- /dev/null +++ b/internal/route/api/v1/types/user.go @@ -0,0 +1,36 @@ +package types + +import "time" + +type User struct { + ID int64 `json:"id"` + UserName string `json:"username"` + Login string `json:"login"` + FullName string `json:"full_name"` + Email string `json:"email"` + AvatarURL string `json:"avatar_url"` +} + +type UserEmail struct { + Email string `json:"email"` + Verified bool `json:"verified"` + Primary bool `json:"primary"` +} + +type UserAccessToken struct { + Name string `json:"name"` + Sha1 string `json:"sha1"` +} + +type UserPublicKey struct { + ID int64 `json:"id"` + Key string `json:"key"` + URL string `json:"url,omitempty"` + Title string `json:"title,omitempty"` + Created time.Time `json:"created_at,omitempty"` +} + +type RepositoryCollaborator struct { + *User + Permissions RepositoryPermission `json:"permissions"` +} diff --git a/internal/route/api/v1/types/webhook.go b/internal/route/api/v1/types/webhook.go new file mode 100644 index 000000000..8adaa51a5 --- /dev/null +++ b/internal/route/api/v1/types/webhook.go @@ -0,0 +1,158 @@ +package types + +import ( + "encoding/json" + "time" +) + +// WebhookPayloader is implemented by webhook payload types. +type WebhookPayloader interface { + JSONPayload() ([]byte, error) +} + +func jsonPayload(p any) ([]byte, error) { + return json.MarshalIndent(p, "", " ") +} + +type WebhookPayloadUser struct { + Name string `json:"name"` + Email string `json:"email"` + UserName string `json:"username"` +} + +type WebhookPayloadCommit struct { + ID string `json:"id"` + Message string `json:"message"` + URL string `json:"url"` + Author *WebhookPayloadUser `json:"author"` + Committer *WebhookPayloadUser `json:"committer"` + Added []string `json:"added"` + Removed []string `json:"removed"` + Modified []string `json:"modified"` + Timestamp time.Time `json:"timestamp"` +} + +type WebhookPusherType string + +const WebhookPusherTypeUser WebhookPusherType = "user" + +type WebhookIssueAction string + +const ( + WebhookIssueOpened WebhookIssueAction = "opened" + WebhookIssueClosed WebhookIssueAction = "closed" + WebhookIssueReopened WebhookIssueAction = "reopened" + WebhookIssueEdited WebhookIssueAction = "edited" + WebhookIssueAssigned WebhookIssueAction = "assigned" + WebhookIssueUnassigned WebhookIssueAction = "unassigned" + WebhookIssueLabelUpdated WebhookIssueAction = "label_updated" + WebhookIssueLabelCleared WebhookIssueAction = "label_cleared" + WebhookIssueMilestoned WebhookIssueAction = "milestoned" + WebhookIssueDemilestoned WebhookIssueAction = "demilestoned" + WebhookIssueSynchronized WebhookIssueAction = "synchronized" +) + +type WebhookIssueCommentAction string + +const ( + WebhookIssueCommentCreated WebhookIssueCommentAction = "created" + WebhookIssueCommentEdited WebhookIssueCommentAction = "edited" + WebhookIssueCommentDeleted WebhookIssueCommentAction = "deleted" +) + +type WebhookReleaseAction string + +const WebhookReleasePublished WebhookReleaseAction = "published" + +type WebhookChangesFromPayload struct { + From string `json:"from"` +} + +type WebhookChangesPayload struct { + Title *WebhookChangesFromPayload `json:"title,omitempty"` + Body *WebhookChangesFromPayload `json:"body,omitempty"` +} + +type WebhookCreatePayload struct { + Ref string `json:"ref"` + RefType string `json:"ref_type"` + Sha string `json:"sha"` + DefaultBranch string `json:"default_branch"` + Repo *Repository `json:"repository"` + Sender *User `json:"sender"` +} + +func (p *WebhookCreatePayload) JSONPayload() ([]byte, error) { return jsonPayload(p) } + +type WebhookDeletePayload struct { + Ref string `json:"ref"` + RefType string `json:"ref_type"` + PusherType WebhookPusherType `json:"pusher_type"` + Repo *Repository `json:"repository"` + Sender *User `json:"sender"` +} + +func (p *WebhookDeletePayload) JSONPayload() ([]byte, error) { return jsonPayload(p) } + +type WebhookForkPayload struct { + Forkee *Repository `json:"forkee"` + Repo *Repository `json:"repository"` + Sender *User `json:"sender"` +} + +func (p *WebhookForkPayload) JSONPayload() ([]byte, error) { return jsonPayload(p) } + +type WebhookPushPayload struct { + Ref string `json:"ref"` + Before string `json:"before"` + After string `json:"after"` + CompareURL string `json:"compare_url"` + Commits []*WebhookPayloadCommit `json:"commits"` + Repo *Repository `json:"repository"` + Pusher *User `json:"pusher"` + Sender *User `json:"sender"` +} + +func (p *WebhookPushPayload) JSONPayload() ([]byte, error) { return jsonPayload(p) } + +type WebhookIssuesPayload struct { + Action WebhookIssueAction `json:"action"` + Index int64 `json:"number"` + Issue *Issue `json:"issue"` + Changes *WebhookChangesPayload `json:"changes,omitempty"` + Repository *Repository `json:"repository"` + Sender *User `json:"sender"` +} + +func (p *WebhookIssuesPayload) JSONPayload() ([]byte, error) { return jsonPayload(p) } + +type WebhookIssueCommentPayload struct { + Action WebhookIssueCommentAction `json:"action"` + Issue *Issue `json:"issue"` + Comment *IssueComment `json:"comment"` + Changes *WebhookChangesPayload `json:"changes,omitempty"` + Repository *Repository `json:"repository"` + Sender *User `json:"sender"` +} + +func (p *WebhookIssueCommentPayload) JSONPayload() ([]byte, error) { return jsonPayload(p) } + +type WebhookPullRequestPayload struct { + Action WebhookIssueAction `json:"action"` + Index int64 `json:"number"` + PullRequest *PullRequest `json:"pull_request"` + Changes *WebhookChangesPayload `json:"changes,omitempty"` + Repository *Repository `json:"repository"` + Sender *User `json:"sender"` +} + +func (p *WebhookPullRequestPayload) JSONPayload() ([]byte, error) { return jsonPayload(p) } + +type WebhookReleasePayload struct { + Action WebhookReleaseAction `json:"action"` + Release *RepositoryRelease `json:"release"` + Repository *Repository `json:"repository"` + Sender *User `json:"sender"` +} + +func (p *WebhookReleasePayload) JSONPayload() ([]byte, error) { return jsonPayload(p) } diff --git a/internal/route/api/v1/user/user.go b/internal/route/api/v1/user.go similarity index 58% rename from internal/route/api/v1/user/user.go rename to internal/route/api/v1/user.go index 597dda87c..0974fdb7b 100644 --- a/internal/route/api/v1/user/user.go +++ b/internal/route/api/v1/user.go @@ -1,16 +1,14 @@ -package user +package v1 import ( "net/http" - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" - "gogs.io/gogs/internal/markup" + "gogs.io/gogs/internal/route/api/v1/types" ) -func Search(c *context.APIContext) { +func searchUsers(c *context.APIContext) { pageSize := c.QueryInt("limit") if pageSize <= 0 { pageSize = 10 @@ -24,16 +22,11 @@ func Search(c *context.APIContext) { return } - results := make([]*api.User, len(users)) + results := make([]*types.User, len(users)) for i := range users { - results[i] = &api.User{ - ID: users[i].ID, - UserName: users[i].Name, - AvatarUrl: users[i].AvatarURL(), - FullName: markup.Sanitize(users[i].FullName), - } - if c.IsLogged { - results[i].Email = users[i].Email + results[i] = toUser(users[i]) + if !c.IsLogged { + results[i].Email = "" } } @@ -43,7 +36,7 @@ func Search(c *context.APIContext) { }) } -func GetInfo(c *context.APIContext) { +func getUserProfile(c *context.APIContext) { u, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Params(":username")) if err != nil { c.NotFoundOrError(err, "get user by name") @@ -54,9 +47,9 @@ func GetInfo(c *context.APIContext) { if !c.IsLogged { u.Email = "" } - c.JSONSuccess(u.APIFormat()) + c.JSONSuccess(toUser(u)) } -func GetAuthenticatedUser(c *context.APIContext) { - c.JSONSuccess(c.User.APIFormat()) +func getAuthenticatedUser(c *context.APIContext) { + c.JSONSuccess(toUser(c.User)) } diff --git a/internal/route/api/v1/user/access_tokens.go b/internal/route/api/v1/user_access_tokens.go similarity index 67% rename from internal/route/api/v1/user/access_tokens.go rename to internal/route/api/v1/user_access_tokens.go index c469a7ed8..a167aa6d2 100644 --- a/internal/route/api/v1/user/access_tokens.go +++ b/internal/route/api/v1/user_access_tokens.go @@ -1,30 +1,30 @@ -package user +package v1 import ( gocontext "context" "net/http" - api "github.com/gogs/go-gogs-client" "gopkg.in/macaron.v1" "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" + "gogs.io/gogs/internal/route/api/v1/types" ) -// AccessTokensHandler is the handler for users access tokens API endpoints. -type AccessTokensHandler struct { +// accessTokensHandler is the handler for users access tokens API endpoints. +type accessTokensHandler struct { store AccessTokensStore } -// NewAccessTokensHandler returns a new AccessTokensHandler for users access +// newAccessTokensHandler returns a new accessTokensHandler for users access // tokens API endpoints. -func NewAccessTokensHandler(s AccessTokensStore) *AccessTokensHandler { - return &AccessTokensHandler{ +func newAccessTokensHandler(s AccessTokensStore) *accessTokensHandler { + return &accessTokensHandler{ store: s, } } -func (h *AccessTokensHandler) List() macaron.Handler { +func (h *accessTokensHandler) List() macaron.Handler { return func(c *context.APIContext) { tokens, err := h.store.ListAccessTokens(c.Req.Context(), c.User.ID) if err != nil { @@ -32,16 +32,23 @@ func (h *AccessTokensHandler) List() macaron.Handler { return } - apiTokens := make([]*api.AccessToken, len(tokens)) + apiTokens := make([]*types.UserAccessToken, len(tokens)) for i := range tokens { - apiTokens[i] = &api.AccessToken{Name: tokens[i].Name, Sha1: tokens[i].Sha1} + apiTokens[i] = &types.UserAccessToken{ + Name: tokens[i].Name, + Sha1: tokens[i].Sha1, + } } c.JSONSuccess(&apiTokens) } } -func (h *AccessTokensHandler) Create() macaron.Handler { - return func(c *context.APIContext, form api.CreateAccessTokenOption) { +type createAccessTokenRequest struct { + Name string `json:"name" binding:"Required"` +} + +func (h *accessTokensHandler) Create() macaron.Handler { + return func(c *context.APIContext, form createAccessTokenRequest) { t, err := h.store.CreateAccessToken(c.Req.Context(), c.User.ID, form.Name) if err != nil { if database.IsErrAccessTokenAlreadyExist(err) { @@ -51,7 +58,10 @@ func (h *AccessTokensHandler) Create() macaron.Handler { } return } - c.JSON(http.StatusCreated, &api.AccessToken{Name: t.Name, Sha1: t.Sha1}) + c.JSON(http.StatusCreated, &types.UserAccessToken{ + Name: t.Name, + Sha1: t.Sha1, + }) } } @@ -69,9 +79,9 @@ type AccessTokensStore interface { type accessTokensStore struct{} -// NewAccessTokensStore returns a new AccessTokensStore using the global +// newAccessTokensStore returns a new AccessTokensStore using the global // database handle. -func NewAccessTokensStore() AccessTokensStore { +func newAccessTokensStore() AccessTokensStore { return &accessTokensStore{} } diff --git a/internal/route/api/v1/user/email.go b/internal/route/api/v1/user_email.go similarity index 69% rename from internal/route/api/v1/user/email.go rename to internal/route/api/v1/user_email.go index 61367eb97..e82cd7041 100644 --- a/internal/route/api/v1/user/email.go +++ b/internal/route/api/v1/user_email.go @@ -1,37 +1,40 @@ -package user +package v1 import ( "net/http" "github.com/cockroachdb/errors" - api "github.com/gogs/go-gogs-client" "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" - "gogs.io/gogs/internal/route/api/v1/convert" + "gogs.io/gogs/internal/route/api/v1/types" ) -func ListEmails(c *context.APIContext) { +func listEmails(c *context.APIContext) { emails, err := database.Handle.Users().ListEmails(c.Req.Context(), c.User.ID) if err != nil { c.Error(err, "get email addresses") return } - apiEmails := make([]*api.Email, len(emails)) + apiEmails := make([]*types.UserEmail, len(emails)) for i := range emails { - apiEmails[i] = convert.ToEmail(emails[i]) + apiEmails[i] = toUserEmail(emails[i]) } c.JSONSuccess(&apiEmails) } -func AddEmail(c *context.APIContext, form api.CreateEmailOption) { +type createEmailRequest struct { + Emails []string `json:"emails"` +} + +func addEmail(c *context.APIContext, form createEmailRequest) { if len(form.Emails) == 0 { c.Status(http.StatusUnprocessableEntity) return } - apiEmails := make([]*api.Email, 0, len(form.Emails)) + apiEmails := make([]*types.UserEmail, 0, len(form.Emails)) for _, email := range form.Emails { err := database.Handle.Users().AddEmail(c.Req.Context(), c.User.ID, email, !conf.Auth.RequireEmailConfirmation) if err != nil { @@ -43,17 +46,15 @@ func AddEmail(c *context.APIContext, form api.CreateEmailOption) { return } - apiEmails = append(apiEmails, - &api.Email{ - Email: email, - Verified: !conf.Auth.RequireEmailConfirmation, - }, - ) + apiEmails = append(apiEmails, &types.UserEmail{ + Email: email, + Verified: !conf.Auth.RequireEmailConfirmation, + }) } c.JSON(http.StatusCreated, &apiEmails) } -func DeleteEmail(c *context.APIContext, form api.CreateEmailOption) { +func deleteEmail(c *context.APIContext, form createEmailRequest) { for _, email := range form.Emails { if email == c.User.Email { c.ErrorStatus(http.StatusBadRequest, errors.Errorf("cannot delete primary email %q", email)) diff --git a/internal/route/api/v1/user/follower.go b/internal/route/api/v1/user_follower.go similarity index 71% rename from internal/route/api/v1/user/follower.go rename to internal/route/api/v1/user_follower.go index 7bbc72a5c..657deefbc 100644 --- a/internal/route/api/v1/user/follower.go +++ b/internal/route/api/v1/user_follower.go @@ -1,16 +1,15 @@ -package user +package v1 import ( - api "github.com/gogs/go-gogs-client" - "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" + "gogs.io/gogs/internal/route/api/v1/types" ) func responseAPIUsers(c *context.APIContext, users []*database.User) { - apiUsers := make([]*api.User, len(users)) + apiUsers := make([]*types.User, len(users)) for i := range users { - apiUsers[i] = users[i].APIFormat() + apiUsers[i] = toUser(users[i]) } c.JSONSuccess(&apiUsers) } @@ -24,12 +23,12 @@ func listUserFollowers(c *context.APIContext, u *database.User) { responseAPIUsers(c, users) } -func ListMyFollowers(c *context.APIContext) { +func listMyFollowers(c *context.APIContext) { listUserFollowers(c, c.User) } -func ListFollowers(c *context.APIContext) { - u := GetUserByParams(c) +func listFollowers(c *context.APIContext) { + u := getUserByParams(c) if c.Written() { return } @@ -45,12 +44,12 @@ func listUserFollowing(c *context.APIContext, u *database.User) { responseAPIUsers(c, users) } -func ListMyFollowing(c *context.APIContext) { +func listMyFollowing(c *context.APIContext) { listUserFollowing(c, c.User) } -func ListFollowing(c *context.APIContext) { - u := GetUserByParams(c) +func listFollowing(c *context.APIContext) { + u := getUserByParams(c) if c.Written() { return } @@ -65,28 +64,28 @@ func checkUserFollowing(c *context.APIContext, u *database.User, followID int64) } } -func CheckMyFollowing(c *context.APIContext) { - target := GetUserByParams(c) +func checkMyFollowing(c *context.APIContext) { + target := getUserByParams(c) if c.Written() { return } checkUserFollowing(c, c.User, target.ID) } -func CheckFollowing(c *context.APIContext) { - u := GetUserByParams(c) +func checkFollowing(c *context.APIContext) { + u := getUserByParams(c) if c.Written() { return } - target := GetUserByParamsName(c, ":target") + target := getUserByParamsName(c, ":target") if c.Written() { return } checkUserFollowing(c, u, target.ID) } -func Follow(c *context.APIContext) { - target := GetUserByParams(c) +func follow(c *context.APIContext) { + target := getUserByParams(c) if c.Written() { return } @@ -97,8 +96,8 @@ func Follow(c *context.APIContext) { c.NoContent() } -func Unfollow(c *context.APIContext) { - target := GetUserByParams(c) +func unfollow(c *context.APIContext) { + target := getUserByParams(c) if c.Written() { return } diff --git a/internal/route/api/v1/user/key.go b/internal/route/api/v1/user_key.go similarity index 52% rename from internal/route/api/v1/user/key.go rename to internal/route/api/v1/user_key.go index 5eea6a59e..1ca9ff6a7 100644 --- a/internal/route/api/v1/user/key.go +++ b/internal/route/api/v1/user_key.go @@ -1,19 +1,17 @@ -package user +package v1 import ( "net/http" "github.com/cockroachdb/errors" - api "github.com/gogs/go-gogs-client" "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" - "gogs.io/gogs/internal/route/api/v1/convert" - "gogs.io/gogs/internal/route/api/v1/repo" + "gogs.io/gogs/internal/route/api/v1/types" ) -func GetUserByParamsName(c *context.APIContext, name string) *database.User { +func getUserByParamsName(c *context.APIContext, name string) *database.User { user, err := database.Handle.Users().GetByUsername(c.Req.Context(), c.Params(name)) if err != nil { c.NotFoundOrError(err, "get user by name") @@ -22,16 +20,15 @@ func GetUserByParamsName(c *context.APIContext, name string) *database.User { return user } -// GetUserByParams returns user whose name is presented in URL parameter. -func GetUserByParams(c *context.APIContext) *database.User { - return GetUserByParamsName(c, ":username") +func getUserByParams(c *context.APIContext) *database.User { + return getUserByParamsName(c, ":username") } func composePublicKeysAPILink() string { return conf.Server.ExternalURL + "api/v1/user/keys/" } -func listPublicKeys(c *context.APIContext, uid int64) { +func listPublicKeysOfUser(c *context.APIContext, uid int64) { keys, err := database.ListPublicKeys(uid) if err != nil { c.Error(err, "list public keys") @@ -39,27 +36,27 @@ func listPublicKeys(c *context.APIContext, uid int64) { } apiLink := composePublicKeysAPILink() - apiKeys := make([]*api.PublicKey, len(keys)) + apiKeys := make([]*types.UserPublicKey, len(keys)) for i := range keys { - apiKeys[i] = convert.ToPublicKey(apiLink, keys[i]) + apiKeys[i] = toUserPublicKey(apiLink, keys[i]) } c.JSONSuccess(&apiKeys) } -func ListMyPublicKeys(c *context.APIContext) { - listPublicKeys(c, c.User.ID) +func listMyPublicKeys(c *context.APIContext) { + listPublicKeysOfUser(c, c.User.ID) } -func ListPublicKeys(c *context.APIContext) { - user := GetUserByParams(c) +func listPublicKeys(c *context.APIContext) { + user := getUserByParams(c) if c.Written() { return } - listPublicKeys(c, user.ID) + listPublicKeysOfUser(c, user.ID) } -func GetPublicKey(c *context.APIContext) { +func getPublicKey(c *context.APIContext) { key, err := database.GetPublicKeyByID(c.ParamsInt64(":id")) if err != nil { c.NotFoundOrError(err, "get public key by ID") @@ -67,31 +64,35 @@ func GetPublicKey(c *context.APIContext) { } apiLink := composePublicKeysAPILink() - c.JSONSuccess(convert.ToPublicKey(apiLink, key)) + c.JSONSuccess(toUserPublicKey(apiLink, key)) } -// CreateUserPublicKey creates new public key to given user by ID. -func CreateUserPublicKey(c *context.APIContext, form api.CreateKeyOption, uid int64) { +type createPublicKeyRequest struct { + Title string `json:"title" binding:"Required"` + Key string `json:"key" binding:"Required"` +} + +func createUserPublicKey(c *context.APIContext, form createPublicKeyRequest, uid int64) { content, err := database.CheckPublicKeyString(form.Key) if err != nil { - repo.HandleCheckKeyStringError(c, err) + handleCheckKeyStringError(c, err) return } key, err := database.AddPublicKey(uid, form.Title, content) if err != nil { - repo.HandleAddKeyError(c, err) + handleAddKeyError(c, err) return } apiLink := composePublicKeysAPILink() - c.JSON(http.StatusCreated, convert.ToPublicKey(apiLink, key)) + c.JSON(http.StatusCreated, toUserPublicKey(apiLink, key)) } -func CreatePublicKey(c *context.APIContext, form api.CreateKeyOption) { - CreateUserPublicKey(c, form, c.User.ID) +func createPublicKey(c *context.APIContext, form createPublicKeyRequest) { + createUserPublicKey(c, form, c.User.ID) } -func DeletePublicKey(c *context.APIContext) { +func deletePublicKey(c *context.APIContext) { if err := database.DeletePublicKey(c.User, c.ParamsInt64(":id")); err != nil { if database.IsErrKeyAccessDenied(err) { c.ErrorStatus(http.StatusForbidden, errors.New("You do not have access to this key.")) diff --git a/internal/route/repo/branch.go b/internal/route/repo/branch.go index 90def186e..52f7f4c50 100644 --- a/internal/route/repo/branch.go +++ b/internal/route/repo/branch.go @@ -6,10 +6,10 @@ import ( log "unknwon.dev/clog/v2" "github.com/gogs/git-module" - api "github.com/gogs/go-gogs-client" "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/database" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" "gogs.io/gogs/internal/urlutil" ) @@ -153,10 +153,10 @@ func DeleteBranchPost(c *context.Context) { return } - if err := database.PrepareWebhooks(c.Repo.Repository, database.HookEventTypeDelete, &api.DeletePayload{ + if err := database.PrepareWebhooks(c.Repo.Repository, database.HookEventTypeDelete, &apiv1types.WebhookDeletePayload{ Ref: branchName, RefType: "branch", - PusherType: api.PUSHER_TYPE_USER, + PusherType: apiv1types.WebhookPusherTypeUser, Repo: c.Repo.Repository.APIFormatLegacy(nil), Sender: c.User.APIFormat(), }); err != nil { diff --git a/internal/route/repo/webhook.go b/internal/route/repo/webhook.go index f807ef041..0946c8b2b 100644 --- a/internal/route/repo/webhook.go +++ b/internal/route/repo/webhook.go @@ -10,7 +10,6 @@ import ( "github.com/cockroachdb/errors" "github.com/gogs/git-module" - api "github.com/gogs/go-gogs-client" "gopkg.in/macaron.v1" "gogs.io/gogs/internal/conf" @@ -18,6 +17,7 @@ import ( "gogs.io/gogs/internal/database" "gogs.io/gogs/internal/form" "gogs.io/gogs/internal/netutil" + apiv1types "gogs.io/gogs/internal/route/api/v1/types" ) const ( @@ -513,21 +513,21 @@ func TestWebhook(c *context.Context) { } apiUser := c.User.APIFormat() - p := &api.PushPayload{ + p := &apiv1types.WebhookPushPayload{ Ref: git.RefsHeads + c.Repo.Repository.DefaultBranch, Before: commitID, After: commitID, - Commits: []*api.PayloadCommit{ + Commits: []*apiv1types.WebhookPayloadCommit{ { ID: commitID, Message: commitMessage, URL: c.Repo.Repository.HTMLURL() + "/commit/" + commitID, - Author: &api.PayloadUser{ + Author: &apiv1types.WebhookPayloadUser{ Name: author.Name, Email: author.Email, UserName: authorUsername, }, - Committer: &api.PayloadUser{ + Committer: &apiv1types.WebhookPayloadUser{ Name: committer.Name, Email: committer.Email, UserName: committerUsername,