* Add Attachment API * repos/:owner/:repo/releases (add attachments) * repos/:owner/:repo/releases/:id (add attachments) * repos/:owner/:repo/releases/:id/attachments * repos/:owner/:repo/releases/:id/attachments/:attachment_id Signed-off-by: Jonas Franz <info@jonasfranz.de> * Add unit tests for new attachment functions Fix comments Signed-off-by: Jonas Franz <info@jonasfranz.software> * fix lint * Update vendor.json Signed-off-by: Jonas Franz <info@jonasfranz.software> * remove version of sdk Signed-off-by: Jonas Franz <info@jonasfranz.software> * Fix unit tests Add missing license header Signed-off-by: Jonas Franz <info@jonasfranz.software> * Add CreateReleaseAttachment Add EditReleaseAttachment Add DeleteReleaseAttachment Signed-off-by: Jonas Franz <info@jonasfranz.software> * Add filename query parameter for choosing another name for an attachment Signed-off-by: Jonas Franz <info@jonasfranz.software> * Fix order of imports Signed-off-by: Jonas Franz <info@jonasfranz.software> * Restricting updatable attachment columns Signed-off-by: Jonas Franz <info@jonasfranz.software> * gofmt Signed-off-by: Jonas Franz <info@jonasfranz.software> * Update go-sdk Replace Attachments with Assets Signed-off-by: Jonas Franz <info@jonasfranz.de> * Update go-sdk Signed-off-by: Jonas Franz <info@jonasfranz.de> * Updating go-sdk and regenerating swagger Signed-off-by: Jonas Franz <info@jonasfranz.software> * Add missing file of go-sdk Signed-off-by: Jonas Franz <info@jonasfranz.software> * Change origin of code.gitea.io/sdk to code.gitea.io/sdk Update code.gitea.io/sdk Signed-off-by: Jonas Franz <info@jonasfranz.software> * Update swagger Signed-off-by: Jonas Franz <info@jonasfranz.software> * Update updateAttachmentmaster
@@ -11,10 +11,12 @@ import ( | |||||
"os" | "os" | ||||
"path" | "path" | ||||
gouuid "github.com/satori/go.uuid" | |||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
"code.gitea.io/gitea/modules/util" | "code.gitea.io/gitea/modules/util" | ||||
api "code.gitea.io/sdk/gitea" | |||||
"github.com/go-xorm/xorm" | |||||
gouuid "github.com/satori/go.uuid" | |||||
) | ) | ||||
// Attachment represent a attachment of issue/comment/release. | // Attachment represent a attachment of issue/comment/release. | ||||
@@ -39,6 +41,20 @@ func (a *Attachment) IncreaseDownloadCount() error { | |||||
return nil | return nil | ||||
} | } | ||||
// APIFormat converts models.Attachment to api.Attachment | |||||
func (a *Attachment) APIFormat() *api.Attachment { | |||||
size, _ := a.Size() | |||||
return &api.Attachment{ | |||||
ID: a.ID, | |||||
Name: a.Name, | |||||
Created: a.CreatedUnix.AsTime(), | |||||
DownloadCount: a.DownloadCount, | |||||
Size: size, | |||||
UUID: a.UUID, | |||||
DownloadURL: a.DownloadURL(), | |||||
} | |||||
} | |||||
// AttachmentLocalPath returns where attachment is stored in local file | // AttachmentLocalPath returns where attachment is stored in local file | ||||
// system based on given UUID. | // system based on given UUID. | ||||
func AttachmentLocalPath(uuid string) string { | func AttachmentLocalPath(uuid string) string { | ||||
@@ -50,6 +66,20 @@ func (a *Attachment) LocalPath() string { | |||||
return AttachmentLocalPath(a.UUID) | return AttachmentLocalPath(a.UUID) | ||||
} | } | ||||
// Size returns the file's size of the attachment | |||||
func (a *Attachment) Size() (int64, error) { | |||||
fi, err := os.Stat(a.LocalPath()) | |||||
if err != nil { | |||||
return 0, err | |||||
} | |||||
return fi.Size(), nil | |||||
} | |||||
// DownloadURL returns the download url of the attached file | |||||
func (a *Attachment) DownloadURL() string { | |||||
return fmt.Sprintf("%sattachments/%s", setting.AppURL, a.UUID) | |||||
} | |||||
// NewAttachment creates a new attachment object. | // NewAttachment creates a new attachment object. | ||||
func NewAttachment(name string, buf []byte, file multipart.File) (_ *Attachment, err error) { | func NewAttachment(name string, buf []byte, file multipart.File) (_ *Attachment, err error) { | ||||
attach := &Attachment{ | attach := &Attachment{ | ||||
@@ -81,6 +111,22 @@ func NewAttachment(name string, buf []byte, file multipart.File) (_ *Attachment, | |||||
return attach, nil | return attach, nil | ||||
} | } | ||||
// GetAttachmentByID returns attachment by given id | |||||
func GetAttachmentByID(id int64) (*Attachment, error) { | |||||
return getAttachmentByID(x, id) | |||||
} | |||||
func getAttachmentByID(e Engine, id int64) (*Attachment, error) { | |||||
attach := &Attachment{ID: id} | |||||
if has, err := e.Get(attach); err != nil { | |||||
return nil, err | |||||
} else if !has { | |||||
return nil, ErrAttachmentNotExist{ID: id, UUID: ""} | |||||
} | |||||
return attach, nil | |||||
} | |||||
func getAttachmentByUUID(e Engine, uuid string) (*Attachment, error) { | func getAttachmentByUUID(e Engine, uuid string) (*Attachment, error) { | ||||
attach := &Attachment{UUID: uuid} | attach := &Attachment{UUID: uuid} | ||||
has, err := e.Get(attach) | has, err := e.Get(attach) | ||||
@@ -180,3 +226,20 @@ func DeleteAttachmentsByComment(commentID int64, remove bool) (int, error) { | |||||
return DeleteAttachments(attachments, remove) | return DeleteAttachments(attachments, remove) | ||||
} | } | ||||
// UpdateAttachment updates the given attachment in database | |||||
func UpdateAttachment(atta *Attachment) error { | |||||
return updateAttachment(x, atta) | |||||
} | |||||
func updateAttachment(e Engine, atta *Attachment) error { | |||||
var sess *xorm.Session | |||||
if atta.ID != 0 && atta.UUID == "" { | |||||
sess = e.ID(atta.ID) | |||||
} else { | |||||
// Use uuid only if id is not set and uuid is set | |||||
sess = e.Where("uuid = ?", atta.UUID) | |||||
} | |||||
_, err := sess.Cols("name", "issue_id", "release_id", "comment_id", "download_count").Update(atta) | |||||
return err | |||||
} |
@@ -58,3 +58,32 @@ func TestDeleteAttachments(t *testing.T) { | |||||
assert.True(t, IsErrAttachmentNotExist(err)) | assert.True(t, IsErrAttachmentNotExist(err)) | ||||
assert.Nil(t, attachment) | assert.Nil(t, attachment) | ||||
} | } | ||||
func TestGetAttachmentByID(t *testing.T) { | |||||
assert.NoError(t, PrepareTestDatabase()) | |||||
attach, err := GetAttachmentByID(1) | |||||
assert.NoError(t, err) | |||||
assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attach.UUID) | |||||
} | |||||
func TestAttachment_DownloadURL(t *testing.T) { | |||||
attach := &Attachment{ | |||||
UUID: "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", | |||||
ID: 1, | |||||
} | |||||
assert.Equal(t, "https://try.gitea.io/attachments/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attach.DownloadURL()) | |||||
} | |||||
func TestUpdateAttachment(t *testing.T) { | |||||
assert.NoError(t, PrepareTestDatabase()) | |||||
attach, err := GetAttachmentByID(1) | |||||
assert.NoError(t, err) | |||||
assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attach.UUID) | |||||
attach.Name = "new_name" | |||||
assert.NoError(t, UpdateAttachment(attach)) | |||||
AssertExistsAndLoadBean(t, &Attachment{Name: "new_name"}) | |||||
} |
@@ -53,7 +53,7 @@ func (r *Release) loadAttributes(e Engine) error { | |||||
return err | return err | ||||
} | } | ||||
} | } | ||||
return nil | |||||
return GetReleaseAttachments(r) | |||||
} | } | ||||
// LoadAttributes load repo and publisher attributes for a release | // LoadAttributes load repo and publisher attributes for a release | ||||
@@ -79,6 +79,10 @@ func (r *Release) TarURL() string { | |||||
// APIFormat convert a Release to api.Release | // APIFormat convert a Release to api.Release | ||||
func (r *Release) APIFormat() *api.Release { | func (r *Release) APIFormat() *api.Release { | ||||
assets := make([]*api.Attachment, 0) | |||||
for _, att := range r.Attachments { | |||||
assets = append(assets, att.APIFormat()) | |||||
} | |||||
return &api.Release{ | return &api.Release{ | ||||
ID: r.ID, | ID: r.ID, | ||||
TagName: r.TagName, | TagName: r.TagName, | ||||
@@ -92,6 +96,7 @@ func (r *Release) APIFormat() *api.Release { | |||||
CreatedAt: r.CreatedUnix.AsTime(), | CreatedAt: r.CreatedUnix.AsTime(), | ||||
PublishedAt: r.CreatedUnix.AsTime(), | PublishedAt: r.CreatedUnix.AsTime(), | ||||
Publisher: r.Publisher.APIFormat(), | Publisher: r.Publisher.APIFormat(), | ||||
Attachments: assets, | |||||
} | } | ||||
} | } | ||||
@@ -4,4 +4,4 @@ | |||||
"less": "^2.7.2", | "less": "^2.7.2", | ||||
"less-plugin-clean-css": "^1.5.1" | "less-plugin-clean-css": "^1.5.1" | ||||
} | } | ||||
} | |||||
} |
@@ -3225,6 +3225,37 @@ | |||||
}, | }, | ||||
"/repos/{owner}/{repo}/releases": { | "/repos/{owner}/{repo}/releases": { | ||||
"get": { | "get": { | ||||
"produces": [ | |||||
"application/json" | |||||
], | |||||
"tags": [ | |||||
"repository" | |||||
], | |||||
"summary": "List a repo's releases", | |||||
"operationId": "repoListReleases", | |||||
"parameters": [ | |||||
{ | |||||
"type": "string", | |||||
"description": "owner of the repo", | |||||
"name": "owner", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "string", | |||||
"description": "name of the repo", | |||||
"name": "repo", | |||||
"in": "path", | |||||
"required": true | |||||
} | |||||
], | |||||
"responses": { | |||||
"200": { | |||||
"$ref": "#/responses/ReleaseList" | |||||
} | |||||
} | |||||
}, | |||||
"post": { | |||||
"consumes": [ | "consumes": [ | ||||
"application/json" | "application/json" | ||||
], | ], | ||||
@@ -3267,6 +3298,44 @@ | |||||
} | } | ||||
}, | }, | ||||
"/repos/{owner}/{repo}/releases/{id}": { | "/repos/{owner}/{repo}/releases/{id}": { | ||||
"get": { | |||||
"produces": [ | |||||
"application/json" | |||||
], | |||||
"tags": [ | |||||
"repository" | |||||
], | |||||
"summary": "Get a release", | |||||
"operationId": "repoGetRelease", | |||||
"parameters": [ | |||||
{ | |||||
"type": "string", | |||||
"description": "owner of the repo", | |||||
"name": "owner", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "string", | |||||
"description": "name of the repo", | |||||
"name": "repo", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "integer", | |||||
"description": "id of the release to get", | |||||
"name": "id", | |||||
"in": "path", | |||||
"required": true | |||||
} | |||||
], | |||||
"responses": { | |||||
"200": { | |||||
"$ref": "#/responses/Release" | |||||
} | |||||
} | |||||
}, | |||||
"delete": { | "delete": { | ||||
"tags": [ | "tags": [ | ||||
"repository" | "repository" | ||||
@@ -3351,6 +3420,247 @@ | |||||
} | } | ||||
} | } | ||||
}, | }, | ||||
"/repos/{owner}/{repo}/releases/{id}/assets": { | |||||
"get": { | |||||
"produces": [ | |||||
"application/json" | |||||
], | |||||
"tags": [ | |||||
"repository" | |||||
], | |||||
"summary": "List release's attachments", | |||||
"operationId": "repoListReleaseAttachments", | |||||
"parameters": [ | |||||
{ | |||||
"type": "string", | |||||
"description": "owner of the repo", | |||||
"name": "owner", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "string", | |||||
"description": "name of the repo", | |||||
"name": "repo", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "integer", | |||||
"description": "id of the release", | |||||
"name": "id", | |||||
"in": "path", | |||||
"required": true | |||||
} | |||||
], | |||||
"responses": { | |||||
"200": { | |||||
"$ref": "#/responses/AttachmentList" | |||||
} | |||||
} | |||||
}, | |||||
"post": { | |||||
"consumes": [ | |||||
"multipart/form-data" | |||||
], | |||||
"produces": [ | |||||
"application/json" | |||||
], | |||||
"tags": [ | |||||
"repository" | |||||
], | |||||
"summary": "Create a release attachment", | |||||
"operationId": "repoCreateReleaseAttachment", | |||||
"parameters": [ | |||||
{ | |||||
"type": "string", | |||||
"description": "owner of the repo", | |||||
"name": "owner", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "string", | |||||
"description": "name of the repo", | |||||
"name": "repo", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "integer", | |||||
"description": "id of the release", | |||||
"name": "id", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "string", | |||||
"description": "name of the attachment", | |||||
"name": "name", | |||||
"in": "query" | |||||
}, | |||||
{ | |||||
"type": "file", | |||||
"description": "attachment to upload", | |||||
"name": "attachment", | |||||
"in": "formData", | |||||
"required": true | |||||
} | |||||
], | |||||
"responses": { | |||||
"201": { | |||||
"$ref": "#/responses/Attachment" | |||||
} | |||||
} | |||||
} | |||||
}, | |||||
"/repos/{owner}/{repo}/releases/{id}/assets/{attachment_id}": { | |||||
"get": { | |||||
"produces": [ | |||||
"application/json" | |||||
], | |||||
"tags": [ | |||||
"repository" | |||||
], | |||||
"summary": "Get a release attachment", | |||||
"operationId": "repoGetReleaseAttachment", | |||||
"parameters": [ | |||||
{ | |||||
"type": "string", | |||||
"description": "owner of the repo", | |||||
"name": "owner", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "string", | |||||
"description": "name of the repo", | |||||
"name": "repo", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "integer", | |||||
"description": "id of the release", | |||||
"name": "id", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "integer", | |||||
"description": "id of the attachment to get", | |||||
"name": "attachment_id", | |||||
"in": "path", | |||||
"required": true | |||||
} | |||||
], | |||||
"responses": { | |||||
"200": { | |||||
"$ref": "#/responses/Attachment" | |||||
} | |||||
} | |||||
}, | |||||
"delete": { | |||||
"produces": [ | |||||
"application/json" | |||||
], | |||||
"tags": [ | |||||
"repository" | |||||
], | |||||
"summary": "Delete a release attachment", | |||||
"operationId": "repoDeleteReleaseAttachment", | |||||
"parameters": [ | |||||
{ | |||||
"type": "string", | |||||
"description": "owner of the repo", | |||||
"name": "owner", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "string", | |||||
"description": "name of the repo", | |||||
"name": "repo", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "integer", | |||||
"description": "id of the release", | |||||
"name": "id", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "integer", | |||||
"description": "id of the attachment to delete", | |||||
"name": "attachment_id", | |||||
"in": "path", | |||||
"required": true | |||||
} | |||||
], | |||||
"responses": { | |||||
"204": { | |||||
"$ref": "#/responses/empty" | |||||
} | |||||
} | |||||
}, | |||||
"patch": { | |||||
"consumes": [ | |||||
"application/json" | |||||
], | |||||
"produces": [ | |||||
"application/json" | |||||
], | |||||
"tags": [ | |||||
"repository" | |||||
], | |||||
"summary": "Edit a release attachment", | |||||
"operationId": "repoEditReleaseAttachment", | |||||
"parameters": [ | |||||
{ | |||||
"type": "string", | |||||
"description": "owner of the repo", | |||||
"name": "owner", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "string", | |||||
"description": "name of the repo", | |||||
"name": "repo", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "integer", | |||||
"description": "id of the release", | |||||
"name": "id", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"type": "integer", | |||||
"description": "id of the attachment to edit", | |||||
"name": "attachment_id", | |||||
"in": "path", | |||||
"required": true | |||||
}, | |||||
{ | |||||
"name": "body", | |||||
"in": "body", | |||||
"schema": { | |||||
"$ref": "#/definitions/EditAttachmentOptions" | |||||
} | |||||
} | |||||
], | |||||
"responses": { | |||||
"201": { | |||||
"$ref": "#/responses/Attachment" | |||||
} | |||||
} | |||||
} | |||||
}, | |||||
"/repos/{owner}/{repo}/stargazers": { | "/repos/{owner}/{repo}/stargazers": { | ||||
"get": { | "get": { | ||||
"produces": [ | "produces": [ | ||||
@@ -4994,6 +5304,45 @@ | |||||
}, | }, | ||||
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea" | "x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea" | ||||
}, | }, | ||||
"Attachment": { | |||||
"description": "Attachment a generic attachment", | |||||
"type": "object", | |||||
"properties": { | |||||
"browser_download_url": { | |||||
"type": "string", | |||||
"x-go-name": "DownloadURL" | |||||
}, | |||||
"created_at": { | |||||
"type": "string", | |||||
"format": "date-time", | |||||
"x-go-name": "Created" | |||||
}, | |||||
"download_count": { | |||||
"type": "integer", | |||||
"format": "int64", | |||||
"x-go-name": "DownloadCount" | |||||
}, | |||||
"id": { | |||||
"type": "integer", | |||||
"format": "int64", | |||||
"x-go-name": "ID" | |||||
}, | |||||
"name": { | |||||
"type": "string", | |||||
"x-go-name": "Name" | |||||
}, | |||||
"size": { | |||||
"type": "integer", | |||||
"format": "int64", | |||||
"x-go-name": "Size" | |||||
}, | |||||
"uuid": { | |||||
"type": "string", | |||||
"x-go-name": "UUID" | |||||
} | |||||
}, | |||||
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea" | |||||
}, | |||||
"Branch": { | "Branch": { | ||||
"description": "Branch represents a repository branch", | "description": "Branch represents a repository branch", | ||||
"type": "object", | "type": "object", | ||||
@@ -5202,6 +5551,11 @@ | |||||
"uniqueItems": true, | "uniqueItems": true, | ||||
"x-go-name": "Key" | "x-go-name": "Key" | ||||
}, | }, | ||||
"read_only": { | |||||
"description": "Describe if the key has only read access or read/write", | |||||
"type": "boolean", | |||||
"x-go-name": "ReadOnly" | |||||
}, | |||||
"title": { | "title": { | ||||
"description": "Title of the key to add", | "description": "Title of the key to add", | ||||
"type": "string", | "type": "string", | ||||
@@ -5540,6 +5894,17 @@ | |||||
}, | }, | ||||
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea" | "x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea" | ||||
}, | }, | ||||
"EditAttachmentOptions": { | |||||
"description": "EditAttachmentOptions options for editing attachments", | |||||
"type": "object", | |||||
"properties": { | |||||
"name": { | |||||
"type": "string", | |||||
"x-go-name": "Name" | |||||
} | |||||
}, | |||||
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea" | |||||
}, | |||||
"EditHookOption": { | "EditHookOption": { | ||||
"description": "EditHookOption options when modify one hook", | "description": "EditHookOption options when modify one hook", | ||||
"type": "object", | "type": "object", | ||||
@@ -6459,6 +6824,13 @@ | |||||
"description": "Release represents a repository release", | "description": "Release represents a repository release", | ||||
"type": "object", | "type": "object", | ||||
"properties": { | "properties": { | ||||
"assets": { | |||||
"type": "array", | |||||
"items": { | |||||
"$ref": "#/definitions/Attachment" | |||||
}, | |||||
"x-go-name": "Attachments" | |||||
}, | |||||
"author": { | "author": { | ||||
"$ref": "#/definitions/User" | "$ref": "#/definitions/User" | ||||
}, | }, | ||||
@@ -6848,6 +7220,19 @@ | |||||
"AccessTokenList": { | "AccessTokenList": { | ||||
"description": "AccessTokenList represents a list of API access token." | "description": "AccessTokenList represents a list of API access token." | ||||
}, | }, | ||||
"Attachment": { | |||||
"schema": { | |||||
"$ref": "#/definitions/Attachment" | |||||
} | |||||
}, | |||||
"AttachmentList": { | |||||
"schema": { | |||||
"type": "array", | |||||
"items": { | |||||
"$ref": "#/definitions/Attachment" | |||||
} | |||||
} | |||||
}, | |||||
"Branch": { | "Branch": { | ||||
"schema": { | "schema": { | ||||
"$ref": "#/definitions/Branch" | "$ref": "#/definitions/Branch" | ||||
@@ -7131,7 +7516,7 @@ | |||||
}, | }, | ||||
"parameterBodies": { | "parameterBodies": { | ||||
"schema": { | "schema": { | ||||
"$ref": "#/definitions/MigrateRepoForm" | |||||
"$ref": "#/definitions/EditAttachmentOptions" | |||||
}, | }, | ||||
"headers": { | "headers": { | ||||
"AddCollaboratorOption": {}, | "AddCollaboratorOption": {}, | ||||
@@ -7152,6 +7537,7 @@ | |||||
"CreateTeamOption": {}, | "CreateTeamOption": {}, | ||||
"CreateUserOption": {}, | "CreateUserOption": {}, | ||||
"DeleteEmailOption": {}, | "DeleteEmailOption": {}, | ||||
"EditAttachmentOptions": {}, | |||||
"EditHookOption": {}, | "EditHookOption": {}, | ||||
"EditIssueCommentOption": {}, | "EditIssueCommentOption": {}, | ||||
"EditIssueOption": {}, | "EditIssueOption": {}, | ||||
@@ -469,9 +469,18 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
m.Group("/releases", func() { | m.Group("/releases", func() { | ||||
m.Combo("").Get(repo.ListReleases). | m.Combo("").Get(repo.ListReleases). | ||||
Post(reqToken(), reqRepoWriter(), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), repo.CreateRelease) | Post(reqToken(), reqRepoWriter(), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), repo.CreateRelease) | ||||
m.Combo("/:id").Get(repo.GetRelease). | |||||
Patch(reqToken(), reqRepoWriter(), context.ReferencesGitRepo(), bind(api.EditReleaseOption{}), repo.EditRelease). | |||||
Delete(reqToken(), reqRepoWriter(), repo.DeleteRelease) | |||||
m.Group("/:id", func() { | |||||
m.Combo("").Get(repo.GetRelease). | |||||
Patch(reqToken(), reqRepoWriter(), context.ReferencesGitRepo(), bind(api.EditReleaseOption{}), repo.EditRelease). | |||||
Delete(reqToken(), reqRepoWriter(), repo.DeleteRelease) | |||||
m.Group("/assets", func() { | |||||
m.Combo("").Get(repo.ListReleaseAttachments). | |||||
Post(reqToken(), reqRepoWriter(), repo.CreateReleaseAttachment) | |||||
m.Combo("/:asset").Get(repo.GetReleaseAttachment). | |||||
Patch(reqToken(), reqRepoWriter(), bind(api.EditAttachmentOptions{}), repo.EditReleaseAttachment). | |||||
Delete(reqToken(), reqRepoWriter(), repo.DeleteReleaseAttachment) | |||||
}) | |||||
}) | |||||
}) | }) | ||||
m.Post("/mirror-sync", reqToken(), reqRepoWriter(), repo.MirrorSync) | m.Post("/mirror-sync", reqToken(), reqRepoWriter(), repo.MirrorSync) | ||||
m.Get("/editorconfig/:filename", context.RepoRef(), repo.GetEditorconfig) | m.Get("/editorconfig/:filename", context.RepoRef(), repo.GetEditorconfig) | ||||
@@ -13,7 +13,7 @@ import ( | |||||
// GetRelease get a single release of a repository | // GetRelease get a single release of a repository | ||||
func GetRelease(ctx *context.APIContext) { | func GetRelease(ctx *context.APIContext) { | ||||
// swagger:operation GET /repos/{owner}/{repo}/releases repository repoGetRelease | |||||
// swagger:operation GET /repos/{owner}/{repo}/releases/{id} repository repoGetRelease | |||||
// --- | // --- | ||||
// summary: Get a release | // summary: Get a release | ||||
// produces: | // produces: | ||||
@@ -29,7 +29,7 @@ func GetRelease(ctx *context.APIContext) { | |||||
// description: name of the repo | // description: name of the repo | ||||
// type: string | // type: string | ||||
// required: true | // required: true | ||||
// - name: repo | |||||
// - name: id | |||||
// in: path | // in: path | ||||
// description: id of the release to get | // description: id of the release to get | ||||
// type: integer | // type: integer | ||||
@@ -0,0 +1,322 @@ | |||||
// Copyright 2018 The Gitea Authors. All rights reserved. | |||||
// Use of this source code is governed by a MIT-style | |||||
// license that can be found in the LICENSE file. | |||||
package repo | |||||
import ( | |||||
"code.gitea.io/gitea/models" | |||||
"code.gitea.io/gitea/modules/context" | |||||
"code.gitea.io/gitea/modules/setting" | |||||
api "code.gitea.io/sdk/gitea" | |||||
"errors" | |||||
"net/http" | |||||
"strings" | |||||
) | |||||
// GetReleaseAttachment gets a single attachment of the release | |||||
func GetReleaseAttachment(ctx *context.APIContext) { | |||||
// swagger:operation GET /repos/{owner}/{repo}/releases/{id}/assets/{attachment_id} repository repoGetReleaseAttachment | |||||
// --- | |||||
// summary: Get a release attachment | |||||
// produces: | |||||
// - application/json | |||||
// parameters: | |||||
// - name: owner | |||||
// in: path | |||||
// description: owner of the repo | |||||
// type: string | |||||
// required: true | |||||
// - name: repo | |||||
// in: path | |||||
// description: name of the repo | |||||
// type: string | |||||
// required: true | |||||
// - name: id | |||||
// in: path | |||||
// description: id of the release | |||||
// type: integer | |||||
// required: true | |||||
// - name: attachment_id | |||||
// in: path | |||||
// description: id of the attachment to get | |||||
// type: integer | |||||
// required: true | |||||
// responses: | |||||
// "200": | |||||
// "$ref": "#/responses/Attachment" | |||||
releaseID := ctx.ParamsInt64(":id") | |||||
attachID := ctx.ParamsInt64(":asset") | |||||
attach, err := models.GetAttachmentByID(attachID) | |||||
if err != nil { | |||||
ctx.Error(500, "GetAttachmentByID", err) | |||||
return | |||||
} | |||||
if attach.ReleaseID != releaseID { | |||||
ctx.Status(404) | |||||
return | |||||
} | |||||
// FIXME Should prove the existence of the given repo, but results in unnecessary database requests | |||||
ctx.JSON(200, attach.APIFormat()) | |||||
} | |||||
// ListReleaseAttachments lists all attachments of the release | |||||
func ListReleaseAttachments(ctx *context.APIContext) { | |||||
// swagger:operation GET /repos/{owner}/{repo}/releases/{id}/assets repository repoListReleaseAttachments | |||||
// --- | |||||
// summary: List release's attachments | |||||
// produces: | |||||
// - application/json | |||||
// parameters: | |||||
// - name: owner | |||||
// in: path | |||||
// description: owner of the repo | |||||
// type: string | |||||
// required: true | |||||
// - name: repo | |||||
// in: path | |||||
// description: name of the repo | |||||
// type: string | |||||
// required: true | |||||
// - name: id | |||||
// in: path | |||||
// description: id of the release | |||||
// type: integer | |||||
// required: true | |||||
// responses: | |||||
// "200": | |||||
// "$ref": "#/responses/AttachmentList" | |||||
releaseID := ctx.ParamsInt64(":id") | |||||
release, err := models.GetReleaseByID(releaseID) | |||||
if err != nil { | |||||
ctx.Error(500, "GetReleaseByID", err) | |||||
return | |||||
} | |||||
if release.RepoID != ctx.Repo.Repository.ID { | |||||
ctx.Status(404) | |||||
return | |||||
} | |||||
if err := release.LoadAttributes(); err != nil { | |||||
ctx.Error(500, "LoadAttributes", err) | |||||
return | |||||
} | |||||
ctx.JSON(200, release.APIFormat().Attachments) | |||||
} | |||||
// CreateReleaseAttachment creates an attachment and saves the given file | |||||
func CreateReleaseAttachment(ctx *context.APIContext) { | |||||
// swagger:operation POST /repos/{owner}/{repo}/releases/{id}/assets repository repoCreateReleaseAttachment | |||||
// --- | |||||
// summary: Create a release attachment | |||||
// produces: | |||||
// - application/json | |||||
// consumes: | |||||
// - multipart/form-data | |||||
// parameters: | |||||
// - name: owner | |||||
// in: path | |||||
// description: owner of the repo | |||||
// type: string | |||||
// required: true | |||||
// - name: repo | |||||
// in: path | |||||
// description: name of the repo | |||||
// type: string | |||||
// required: true | |||||
// - name: id | |||||
// in: path | |||||
// description: id of the release | |||||
// type: integer | |||||
// required: true | |||||
// - name: name | |||||
// in: query | |||||
// description: name of the attachment | |||||
// type: string | |||||
// required: false | |||||
// - name: attachment | |||||
// in: formData | |||||
// description: attachment to upload | |||||
// type: file | |||||
// required: true | |||||
// responses: | |||||
// "201": | |||||
// "$ref": "#/responses/Attachment" | |||||
// Check if attachments are enabled | |||||
if !setting.AttachmentEnabled { | |||||
ctx.Error(404, "AttachmentEnabled", errors.New("attachment is not enabled")) | |||||
return | |||||
} | |||||
// Check if release exists an load release | |||||
releaseID := ctx.ParamsInt64(":id") | |||||
release, err := models.GetReleaseByID(releaseID) | |||||
if err != nil { | |||||
ctx.Error(500, "GetReleaseByID", err) | |||||
return | |||||
} | |||||
// Get uploaded file from request | |||||
file, header, err := ctx.GetFile("attachment") | |||||
if err != nil { | |||||
ctx.Error(500, "GetFile", err) | |||||
return | |||||
} | |||||
defer file.Close() | |||||
buf := make([]byte, 1024) | |||||
n, _ := file.Read(buf) | |||||
if n > 0 { | |||||
buf = buf[:n] | |||||
} | |||||
// Check if the filetype is allowed by the settings | |||||
fileType := http.DetectContentType(buf) | |||||
allowedTypes := strings.Split(setting.AttachmentAllowedTypes, ",") | |||||
allowed := false | |||||
for _, t := range allowedTypes { | |||||
t := strings.Trim(t, " ") | |||||
if t == "*/*" || t == fileType { | |||||
allowed = true | |||||
break | |||||
} | |||||
} | |||||
if !allowed { | |||||
ctx.Error(400, "DetectContentType", errors.New("File type is not allowed")) | |||||
return | |||||
} | |||||
var filename = header.Filename | |||||
if query := ctx.Query("name"); query != "" { | |||||
filename = query | |||||
} | |||||
// Create a new attachment and save the file | |||||
attach, err := models.NewAttachment(filename, buf, file) | |||||
if err != nil { | |||||
ctx.Error(500, "NewAttachment", err) | |||||
return | |||||
} | |||||
attach.ReleaseID = release.ID | |||||
if err := models.UpdateAttachment(attach); err != nil { | |||||
ctx.Error(500, "UpdateAttachment", err) | |||||
return | |||||
} | |||||
ctx.JSON(201, attach.APIFormat()) | |||||
} | |||||
// EditReleaseAttachment updates the given attachment | |||||
func EditReleaseAttachment(ctx *context.APIContext, form api.EditAttachmentOptions) { | |||||
// swagger:operation PATCH /repos/{owner}/{repo}/releases/{id}/assets/{attachment_id} repository repoEditReleaseAttachment | |||||
// --- | |||||
// summary: Edit a release attachment | |||||
// produces: | |||||
// - application/json | |||||
// consumes: | |||||
// - application/json | |||||
// parameters: | |||||
// - name: owner | |||||
// in: path | |||||
// description: owner of the repo | |||||
// type: string | |||||
// required: true | |||||
// - name: repo | |||||
// in: path | |||||
// description: name of the repo | |||||
// type: string | |||||
// required: true | |||||
// - name: id | |||||
// in: path | |||||
// description: id of the release | |||||
// type: integer | |||||
// required: true | |||||
// - name: attachment_id | |||||
// in: path | |||||
// description: id of the attachment to edit | |||||
// type: integer | |||||
// required: true | |||||
// - name: body | |||||
// in: body | |||||
// schema: | |||||
// "$ref": "#/definitions/EditAttachmentOptions" | |||||
// responses: | |||||
// "201": | |||||
// "$ref": "#/responses/Attachment" | |||||
// Check if release exists an load release | |||||
releaseID := ctx.ParamsInt64(":id") | |||||
attachID := ctx.ParamsInt64(":attachment") | |||||
attach, err := models.GetAttachmentByID(attachID) | |||||
if err != nil { | |||||
ctx.Error(500, "GetAttachmentByID", err) | |||||
return | |||||
} | |||||
if attach.ReleaseID != releaseID { | |||||
ctx.Status(404) | |||||
return | |||||
} | |||||
// FIXME Should prove the existence of the given repo, but results in unnecessary database requests | |||||
if form.Name != "" { | |||||
attach.Name = form.Name | |||||
} | |||||
if err := models.UpdateAttachment(attach); err != nil { | |||||
ctx.Error(500, "UpdateAttachment", attach) | |||||
} | |||||
ctx.JSON(201, attach.APIFormat()) | |||||
} | |||||
// DeleteReleaseAttachment delete a given attachment | |||||
func DeleteReleaseAttachment(ctx *context.APIContext) { | |||||
// swagger:operation DELETE /repos/{owner}/{repo}/releases/{id}/assets/{attachment_id} repository repoDeleteReleaseAttachment | |||||
// --- | |||||
// summary: Delete a release attachment | |||||
// produces: | |||||
// - application/json | |||||
// parameters: | |||||
// - name: owner | |||||
// in: path | |||||
// description: owner of the repo | |||||
// type: string | |||||
// required: true | |||||
// - name: repo | |||||
// in: path | |||||
// description: name of the repo | |||||
// type: string | |||||
// required: true | |||||
// - name: id | |||||
// in: path | |||||
// description: id of the release | |||||
// type: integer | |||||
// required: true | |||||
// - name: attachment_id | |||||
// in: path | |||||
// description: id of the attachment to delete | |||||
// type: integer | |||||
// required: true | |||||
// responses: | |||||
// "204": | |||||
// "$ref": "#/responses/empty" | |||||
// Check if release exists an load release | |||||
releaseID := ctx.ParamsInt64(":id") | |||||
attachID := ctx.ParamsInt64(":attachment") | |||||
attach, err := models.GetAttachmentByID(attachID) | |||||
if err != nil { | |||||
ctx.Error(500, "GetAttachmentByID", err) | |||||
return | |||||
} | |||||
if attach.ReleaseID != releaseID { | |||||
ctx.Status(404) | |||||
return | |||||
} | |||||
// FIXME Should prove the existence of the given repo, but results in unnecessary database requests | |||||
if err := models.DeleteAttachment(attach, true); err != nil { | |||||
ctx.Error(500, "DeleteAttachment", err) | |||||
return | |||||
} | |||||
ctx.Status(204) | |||||
} |
@@ -63,4 +63,6 @@ type swaggerParameterBodies struct { | |||||
EditUserOption api.EditUserOption | EditUserOption api.EditUserOption | ||||
MigrateRepoForm auth.MigrateRepoForm | MigrateRepoForm auth.MigrateRepoForm | ||||
EditAttachmentOptions api.EditAttachmentOptions | |||||
} | } |
@@ -90,3 +90,15 @@ type swaggerResponseWatchInfo struct { | |||||
type swaggerResponseSearchResults struct { | type swaggerResponseSearchResults struct { | ||||
Body api.SearchResults `json:"body"` | Body api.SearchResults `json:"body"` | ||||
} | } | ||||
// swagger:response AttachmentList | |||||
type swaggerResponseAttachmentList struct { | |||||
//in: body | |||||
Body []api.Attachment `json:"body"` | |||||
} | |||||
// swagger:response Attachment | |||||
type swaggerResponseAttachment struct { | |||||
//in: body | |||||
Body api.Attachment `json:"body"` | |||||
} |
@@ -12,7 +12,7 @@ import ( | |||||
// CreateUserOption create user options | // CreateUserOption create user options | ||||
type CreateUserOption struct { | type CreateUserOption struct { | ||||
SourceID int64 `json:"source_id"` | |||||
SourceID int64 `json:"source_id"` | |||||
LoginName string `json:"login_name"` | LoginName string `json:"login_name"` | ||||
// required: true | // required: true | ||||
Username string `json:"username" binding:"Required;AlphaDashDot;MaxSize(35)"` | Username string `json:"username" binding:"Required;AlphaDashDot;MaxSize(35)"` | ||||
@@ -21,8 +21,8 @@ type CreateUserOption struct { | |||||
// swagger:strfmt email | // swagger:strfmt email | ||||
Email string `json:"email" binding:"Required;Email;MaxSize(254)"` | Email string `json:"email" binding:"Required;Email;MaxSize(254)"` | ||||
// required: true | // required: true | ||||
Password string `json:"password" binding:"Required;MaxSize(255)"` | |||||
SendNotify bool `json:"send_notify"` | |||||
Password string `json:"password" binding:"Required;MaxSize(255)"` | |||||
SendNotify bool `json:"send_notify"` | |||||
} | } | ||||
// AdminCreateUser create a user | // AdminCreateUser create a user | ||||
@@ -37,20 +37,20 @@ func (c *Client) AdminCreateUser(opt CreateUserOption) (*User, error) { | |||||
// EditUserOption edit user options | // EditUserOption edit user options | ||||
type EditUserOption struct { | type EditUserOption struct { | ||||
SourceID int64 `json:"source_id"` | |||||
SourceID int64 `json:"source_id"` | |||||
LoginName string `json:"login_name"` | LoginName string `json:"login_name"` | ||||
FullName string `json:"full_name" binding:"MaxSize(100)"` | |||||
FullName string `json:"full_name" binding:"MaxSize(100)"` | |||||
// required: true | // required: true | ||||
// swagger:strfmt email | // swagger:strfmt email | ||||
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"` | |||||
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"` | |||||
} | } | ||||
// AdminEditUser modify user informations | // AdminEditUser modify user informations | ||||
@@ -3,15 +3,90 @@ | |||||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
package gitea // import "code.gitea.io/sdk/gitea" | package gitea // import "code.gitea.io/sdk/gitea" | ||||
import "time" | |||||
import ( | |||||
"bytes" | |||||
"encoding/json" | |||||
"fmt" | |||||
"io" | |||||
"mime/multipart" | |||||
"net/http" | |||||
"time" | |||||
) | |||||
// Attachment a generic attachment | // Attachment a generic attachment | ||||
// swagger:model | |||||
type Attachment struct { | type Attachment struct { | ||||
ID int64 `json:"id"` | |||||
Name string `json:"name"` | |||||
Size int64 `json:"size"` | |||||
DownloadCount int64 `json:"download_count"` | |||||
Created time.Time `json:"created_at"` | |||||
UUID string `json:"uuid"` | |||||
DownloadURL string `json:"browser_download_url"` | |||||
ID int64 `json:"id"` | |||||
Name string `json:"name"` | |||||
Size int64 `json:"size"` | |||||
DownloadCount int64 `json:"download_count"` | |||||
// swagger:strfmt date-time | |||||
Created time.Time `json:"created_at"` | |||||
UUID string `json:"uuid"` | |||||
DownloadURL string `json:"browser_download_url"` | |||||
} | |||||
// ListReleaseAttachments list release's attachments | |||||
func (c *Client) ListReleaseAttachments(user, repo string, release int64) ([]*Attachment, error) { | |||||
attachments := make([]*Attachment, 0, 10) | |||||
err := c.getParsedResponse("GET", | |||||
fmt.Sprintf("/repos/%s/%s/releases/%d/assets", user, repo, release), | |||||
nil, nil, &attachments) | |||||
return attachments, err | |||||
} | |||||
// ListReleaseAttachments list release's attachments | |||||
func (c *Client) GetReleaseAttachment(user, repo string, release int64, id int64) (*Attachment, error) { | |||||
a := new(Attachment) | |||||
err := c.getParsedResponse("GET", | |||||
fmt.Sprintf("/repos/%s/%s/releases/%d/assets/%d", user, repo, release, id), | |||||
nil, nil, &a) | |||||
return a, err | |||||
} | |||||
// CreateReleaseAttachment creates an attachment for the given release | |||||
func (c *Client) CreateReleaseAttachment(user, repo string, release int64, file io.Reader, filename string) (*Attachment, error) { | |||||
// Write file to body | |||||
body := new(bytes.Buffer) | |||||
writer := multipart.NewWriter(body) | |||||
part, err := writer.CreateFormFile("attachment", filename) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
if _, err = io.Copy(part, file); err != nil { | |||||
return nil, err | |||||
} | |||||
if err = writer.Close(); err != nil { | |||||
return nil, err | |||||
} | |||||
// Send request | |||||
attachment := new(Attachment) | |||||
err = c.getParsedResponse("POST", | |||||
fmt.Sprintf("/repos/%s/%s/releases/%d/assets", user, repo, release), | |||||
http.Header{"Content-Type": {writer.FormDataContentType()}}, body, &attachment) | |||||
return attachment, err | |||||
} | |||||
// EditReleaseAttachment updates the given attachment with the given options | |||||
func (c *Client) EditReleaseAttachment(user, repo string, release int64, attachment int64, form EditAttachmentOptions) (*Attachment, error) { | |||||
body, err := json.Marshal(&form) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
attach := new(Attachment) | |||||
return attach, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/releases/%d/assets/%d", user, repo, release, attachment), jsonHeader, bytes.NewReader(body), attach) | |||||
} | |||||
// DeleteReleaseAttachment deletes the given attachment including the uploaded file | |||||
func (c *Client) DeleteReleaseAttachment(user, repo string, release int64, id int64) error { | |||||
_, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/releases/%d/assets/%d", user, repo, release, id), nil, nil) | |||||
return err | |||||
} | |||||
// EditAttachmentOptions options for editing attachments | |||||
// swagger:model | |||||
type EditAttachmentOptions struct { | |||||
Name string `json:"name"` | |||||
} | } |
@@ -7,6 +7,7 @@ package gitea | |||||
import ( | import ( | ||||
"encoding/json" | "encoding/json" | ||||
"errors" | "errors" | ||||
"fmt" | |||||
"io" | "io" | ||||
"io/ioutil" | "io/ioutil" | ||||
"net/http" | "net/http" | ||||
@@ -69,6 +70,8 @@ func (c *Client) getResponse(method, path string, header http.Header, body io.Re | |||||
return nil, errors.New("403 Forbidden") | return nil, errors.New("403 Forbidden") | ||||
case 404: | case 404: | ||||
return nil, errors.New("404 Not Found") | return nil, errors.New("404 Not Found") | ||||
case 422: | |||||
return nil, fmt.Errorf("422 Unprocessable Entity: %s", string(data)) | |||||
} | } | ||||
if resp.StatusCode/100 != 2 { | if resp.StatusCode/100 != 2 { | ||||
@@ -21,16 +21,16 @@ var ( | |||||
// Hook a hook is a web hook when one repository changed | // Hook a hook is a web hook when one repository changed | ||||
type Hook struct { | type Hook 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"` | |||||
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"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Updated time.Time `json:"updated_at"` | |||||
Updated time.Time `json:"updated_at"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Created time.Time `json:"created_at"` | |||||
Created time.Time `json:"created_at"` | |||||
} | } | ||||
// HookList represents a list of API hook. | // HookList represents a list of API hook. | ||||
@@ -67,7 +67,7 @@ type CreateHookOption struct { | |||||
Type string `json:"type" binding:"Required"` | Type string `json:"type" binding:"Required"` | ||||
// required: true | // required: true | ||||
Config map[string]string `json:"config" binding:"Required"` | Config map[string]string `json:"config" binding:"Required"` | ||||
Events []string `json:"events"` | |||||
Events []string `json:"events"` | |||||
// default: false | // default: false | ||||
Active bool `json:"active"` | Active bool `json:"active"` | ||||
} | } | ||||
@@ -95,8 +95,8 @@ func (c *Client) CreateRepoHook(user, repo string, opt CreateHookOption) (*Hook, | |||||
// EditHookOption options when modify one hook | // EditHookOption options when modify one hook | ||||
type EditHookOption struct { | type EditHookOption struct { | ||||
Config map[string]string `json:"config"` | Config map[string]string `json:"config"` | ||||
Events []string `json:"events"` | |||||
Active *bool `json:"active"` | |||||
Events []string `json:"events"` | |||||
Active *bool `json:"active"` | |||||
} | } | ||||
// EditOrgHook modify one hook of an organization, with hook id and options | // EditOrgHook modify one hook of an organization, with hook id and options | ||||
@@ -140,7 +140,7 @@ type Payloader interface { | |||||
// PayloadUser represents the author or committer of a commit | // PayloadUser represents the author or committer of a commit | ||||
type PayloadUser struct { | type PayloadUser struct { | ||||
// Full name of the commit author | // Full name of the commit author | ||||
Name string `json:"name"` | |||||
Name string `json:"name"` | |||||
// swagger:strfmt email | // swagger:strfmt email | ||||
Email string `json:"email"` | Email string `json:"email"` | ||||
UserName string `json:"username"` | UserName string `json:"username"` | ||||
@@ -159,7 +159,7 @@ type PayloadCommit struct { | |||||
Committer *PayloadUser `json:"committer"` | Committer *PayloadUser `json:"committer"` | ||||
Verification *PayloadCommitVerification `json:"verification"` | Verification *PayloadCommitVerification `json:"verification"` | ||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Timestamp time.Time `json:"timestamp"` | |||||
Timestamp time.Time `json:"timestamp"` | |||||
} | } | ||||
// PayloadCommitVerification represents the GPG verification of a commit | // PayloadCommitVerification represents the GPG verification of a commit | ||||
@@ -43,12 +43,12 @@ type Issue struct { | |||||
// | // | ||||
// type: string | // type: string | ||||
// enum: open,closed | // enum: open,closed | ||||
State StateType `json:"state"` | |||||
Comments int `json:"comments"` | |||||
State StateType `json:"state"` | |||||
Comments int `json:"comments"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Created time.Time `json:"created_at"` | |||||
Created time.Time `json:"created_at"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Updated time.Time `json:"updated_at"` | |||||
Updated time.Time `json:"updated_at"` | |||||
PullRequest *PullRequestMeta `json:"pull_request"` | PullRequest *PullRequestMeta `json:"pull_request"` | ||||
} | } | ||||
@@ -86,15 +86,15 @@ func (c *Client) GetIssue(owner, repo string, index int64) (*Issue, error) { | |||||
// CreateIssueOption options to create one issue | // CreateIssueOption options to create one issue | ||||
type CreateIssueOption struct { | type CreateIssueOption struct { | ||||
// required:true | // required:true | ||||
Title string `json:"title" binding:"Required"` | |||||
Body string `json:"body"` | |||||
Title string `json:"title" binding:"Required"` | |||||
Body string `json:"body"` | |||||
// username of assignee | // username of assignee | ||||
Assignee string `json:"assignee"` | |||||
Assignee string `json:"assignee"` | |||||
// milestone id | // milestone id | ||||
Milestone int64 `json:"milestone"` | |||||
Milestone int64 `json:"milestone"` | |||||
// list of label ids | // list of label ids | ||||
Labels []int64 `json:"labels"` | |||||
Closed bool `json:"closed"` | |||||
Labels []int64 `json:"labels"` | |||||
Closed bool `json:"closed"` | |||||
} | } | ||||
// CreateIssue create a new issue for a given repository | // CreateIssue create a new issue for a given repository | ||||
@@ -13,16 +13,16 @@ import ( | |||||
// Comment represents a comment on a commit or issue | // Comment represents a comment on a commit or issue | ||||
type Comment struct { | type Comment struct { | ||||
ID int64 `json:"id"` | |||||
HTMLURL string `json:"html_url"` | |||||
PRURL string `json:"pull_request_url"` | |||||
IssueURL string `json:"issue_url"` | |||||
Poster *User `json:"user"` | |||||
Body string `json:"body"` | |||||
ID int64 `json:"id"` | |||||
HTMLURL string `json:"html_url"` | |||||
PRURL string `json:"pull_request_url"` | |||||
IssueURL string `json:"issue_url"` | |||||
Poster *User `json:"user"` | |||||
Body string `json:"body"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Created time.Time `json:"created_at"` | |||||
Created time.Time `json:"created_at"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Updated time.Time `json:"updated_at"` | |||||
Updated time.Time `json:"updated_at"` | |||||
} | } | ||||
// ListIssueComments list comments on an issue. | // ListIssueComments list comments on an issue. | ||||
@@ -13,8 +13,8 @@ import ( | |||||
// Label a label to an issue or a pr | // Label a label to an issue or a pr | ||||
// swagger:model | // swagger:model | ||||
type Label struct { | type Label struct { | ||||
ID int64 `json:"id"` | |||||
Name string `json:"name"` | |||||
ID int64 `json:"id"` | |||||
Name string `json:"name"` | |||||
// example: 00aabb | // example: 00aabb | ||||
Color string `json:"color"` | Color string `json:"color"` | ||||
URL string `json:"url"` | URL string `json:"url"` | ||||
@@ -36,7 +36,7 @@ func (c *Client) GetRepoLabel(owner, repo string, id int64) (*Label, error) { | |||||
// CreateLabelOption options for creating a label | // CreateLabelOption options for creating a label | ||||
type CreateLabelOption struct { | type CreateLabelOption struct { | ||||
// required:true | // required:true | ||||
Name string `json:"name" binding:"Required"` | |||||
Name string `json:"name" binding:"Required"` | |||||
// required:true | // required:true | ||||
// example: #00aabb | // example: #00aabb | ||||
Color string `json:"color" binding:"Required;Size(7)"` | Color string `json:"color" binding:"Required;Size(7)"` | ||||
@@ -13,16 +13,16 @@ import ( | |||||
// Milestone milestone is a collection of issues on one repository | // Milestone milestone is a collection of issues on one repository | ||||
type Milestone struct { | type Milestone struct { | ||||
ID int64 `json:"id"` | |||||
Title string `json:"title"` | |||||
Description string `json:"description"` | |||||
State StateType `json:"state"` | |||||
OpenIssues int `json:"open_issues"` | |||||
ClosedIssues int `json:"closed_issues"` | |||||
ID int64 `json:"id"` | |||||
Title string `json:"title"` | |||||
Description string `json:"description"` | |||||
State StateType `json:"state"` | |||||
OpenIssues int `json:"open_issues"` | |||||
ClosedIssues int `json:"closed_issues"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Closed *time.Time `json:"closed_at"` | |||||
Closed *time.Time `json:"closed_at"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Deadline *time.Time `json:"due_on"` | |||||
Deadline *time.Time `json:"due_on"` | |||||
} | } | ||||
// ListRepoMilestones list all the milestones of one repository | // ListRepoMilestones list all the milestones of one repository | ||||
@@ -39,10 +39,10 @@ func (c *Client) GetMilestone(owner, repo string, id int64) (*Milestone, error) | |||||
// CreateMilestoneOption options for creating a milestone | // CreateMilestoneOption options for creating a milestone | ||||
type CreateMilestoneOption struct { | type CreateMilestoneOption struct { | ||||
Title string `json:"title"` | |||||
Description string `json:"description"` | |||||
Title string `json:"title"` | |||||
Description string `json:"description"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Deadline *time.Time `json:"due_on"` | |||||
Deadline *time.Time `json:"due_on"` | |||||
} | } | ||||
// CreateMilestone create one milestone with options | // CreateMilestone create one milestone with options | ||||
@@ -13,7 +13,7 @@ import ( | |||||
// TrackedTime worked time for an issue / pr | // TrackedTime worked time for an issue / pr | ||||
type TrackedTime struct { | type TrackedTime struct { | ||||
ID int64 `json:"id"` | |||||
ID int64 `json:"id"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Created time.Time `json:"created"` | Created time.Time `json:"created"` | ||||
// Time in seconds | // Time in seconds | ||||
@@ -42,11 +42,11 @@ func (c *Client) GetOrg(orgname string) (*Organization, error) { | |||||
// CreateOrgOption options for creating an organization | // CreateOrgOption options for creating an organization | ||||
type CreateOrgOption struct { | type CreateOrgOption struct { | ||||
// required: true | // required: true | ||||
UserName string `json:"username" binding:"Required"` | |||||
FullName string `json:"full_name"` | |||||
UserName string `json:"username" binding:"Required"` | |||||
FullName string `json:"full_name"` | |||||
Description string `json:"description"` | Description string `json:"description"` | ||||
Website string `json:"website"` | |||||
Location string `json:"location"` | |||||
Website string `json:"website"` | |||||
Location string `json:"location"` | |||||
} | } | ||||
// EditOrgOption options for editing an organization | // EditOrgOption options for editing an organization | ||||
@@ -10,7 +10,7 @@ type Team struct { | |||||
Name string `json:"name"` | Name string `json:"name"` | ||||
Description string `json:"description"` | Description string `json:"description"` | ||||
// enum: none,read,write,admin,owner | // enum: none,read,write,admin,owner | ||||
Permission string `json:"permission"` | |||||
Permission string `json:"permission"` | |||||
} | } | ||||
// CreateTeamOption options for creating a team | // CreateTeamOption options for creating a team | ||||
@@ -19,7 +19,7 @@ type CreateTeamOption struct { | |||||
Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(30)"` | Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(30)"` | ||||
Description string `json:"description" binding:"MaxSize(255)"` | Description string `json:"description" binding:"MaxSize(255)"` | ||||
// enum: read,write,admin | // enum: read,write,admin | ||||
Permission string `json:"permission"` | |||||
Permission string `json:"permission"` | |||||
} | } | ||||
// EditTeamOption options for editing a team | // EditTeamOption options for editing a team | ||||
@@ -28,5 +28,5 @@ type EditTeamOption struct { | |||||
Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(30)"` | Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(30)"` | ||||
Description string `json:"description" binding:"MaxSize(255)"` | Description string `json:"description" binding:"MaxSize(255)"` | ||||
// enum: read,write,admin | // enum: read,write,admin | ||||
Permission string `json:"permission"` | |||||
Permission string `json:"permission"` | |||||
} | } |
@@ -29,8 +29,8 @@ type PullRequest struct { | |||||
DiffURL string `json:"diff_url"` | DiffURL string `json:"diff_url"` | ||||
PatchURL string `json:"patch_url"` | PatchURL string `json:"patch_url"` | ||||
Mergeable bool `json:"mergeable"` | |||||
HasMerged bool `json:"merged"` | |||||
Mergeable bool `json:"mergeable"` | |||||
HasMerged bool `json:"merged"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Merged *time.Time `json:"merged_at"` | Merged *time.Time `json:"merged_at"` | ||||
MergedCommitID *string `json:"merge_commit_sha"` | MergedCommitID *string `json:"merge_commit_sha"` | ||||
@@ -13,21 +13,22 @@ import ( | |||||
// Release represents a repository release | // Release represents a repository release | ||||
type Release struct { | type Release struct { | ||||
ID int64 `json:"id"` | |||||
TagName string `json:"tag_name"` | |||||
Target string `json:"target_commitish"` | |||||
Title string `json:"name"` | |||||
Note string `json:"body"` | |||||
URL string `json:"url"` | |||||
TarURL string `json:"tarball_url"` | |||||
ZipURL string `json:"zipball_url"` | |||||
IsDraft bool `json:"draft"` | |||||
IsPrerelease bool `json:"prerelease"` | |||||
ID int64 `json:"id"` | |||||
TagName string `json:"tag_name"` | |||||
Target string `json:"target_commitish"` | |||||
Title string `json:"name"` | |||||
Note string `json:"body"` | |||||
URL string `json:"url"` | |||||
TarURL string `json:"tarball_url"` | |||||
ZipURL string `json:"zipball_url"` | |||||
IsDraft bool `json:"draft"` | |||||
IsPrerelease bool `json:"prerelease"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
CreatedAt time.Time `json:"created_at"` | |||||
CreatedAt time.Time `json:"created_at"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
PublishedAt time.Time `json:"published_at"` | |||||
Publisher *User `json:"author"` | |||||
PublishedAt time.Time `json:"published_at"` | |||||
Publisher *User `json:"author"` | |||||
Attachments []*Attachment `json:"assets"` | |||||
} | } | ||||
// ListReleases list releases of a repository | // ListReleases list releases of a repository | ||||
@@ -41,10 +41,10 @@ type Repository struct { | |||||
OpenIssues int `json:"open_issues_count"` | OpenIssues int `json:"open_issues_count"` | ||||
DefaultBranch string `json:"default_branch"` | DefaultBranch string `json:"default_branch"` | ||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Created time.Time `json:"created_at"` | |||||
Created time.Time `json:"created_at"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Updated time.Time `json:"updated_at"` | |||||
Permissions *Permission `json:"permissions,omitempty"` | |||||
Updated time.Time `json:"updated_at"` | |||||
Permissions *Permission `json:"permissions,omitempty"` | |||||
} | } | ||||
// ListMyRepos lists all repositories for the authenticated user that has access to. | // ListMyRepos lists all repositories for the authenticated user that has access to. | ||||
@@ -122,15 +122,15 @@ func (c *Client) DeleteRepo(owner, repo string) error { | |||||
// MigrateRepoOption options for migrating a repository from an external service | // MigrateRepoOption options for migrating a repository from an external service | ||||
type MigrateRepoOption struct { | type MigrateRepoOption struct { | ||||
// required: true | // required: true | ||||
CloneAddr string `json:"clone_addr" binding:"Required"` | |||||
CloneAddr string `json:"clone_addr" binding:"Required"` | |||||
AuthUsername string `json:"auth_username"` | AuthUsername string `json:"auth_username"` | ||||
AuthPassword string `json:"auth_password"` | AuthPassword string `json:"auth_password"` | ||||
// required: true | // required: true | ||||
UID int `json:"uid" binding:"Required"` | UID int `json:"uid" binding:"Required"` | ||||
// required: true | // required: true | ||||
RepoName string `json:"repo_name" binding:"Required"` | |||||
Mirror bool `json:"mirror"` | |||||
Private bool `json:"private"` | |||||
RepoName string `json:"repo_name" binding:"Required"` | |||||
Mirror bool `json:"mirror"` | |||||
Private bool `json:"private"` | |||||
Description string `json:"description"` | Description string `json:"description"` | ||||
} | } | ||||
@@ -13,10 +13,10 @@ import ( | |||||
// DeployKey a deploy key | // DeployKey a deploy key | ||||
type DeployKey struct { | type DeployKey struct { | ||||
ID int64 `json:"id"` | |||||
Key string `json:"key"` | |||||
URL string `json:"url"` | |||||
Title string `json:"title"` | |||||
ID int64 `json:"id"` | |||||
Key string `json:"key"` | |||||
URL string `json:"url"` | |||||
Title string `json:"title"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Created time.Time `json:"created_at"` | Created time.Time `json:"created_at"` | ||||
ReadOnly bool `json:"read_only"` | ReadOnly bool `json:"read_only"` | ||||
@@ -38,9 +38,9 @@ type Status struct { | |||||
Context string `json:"context"` | Context string `json:"context"` | ||||
Creator *User `json:"creator"` | Creator *User `json:"creator"` | ||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Created time.Time `json:"created_at"` | |||||
Created time.Time `json:"created_at"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Updated time.Time `json:"updated_at"` | |||||
Updated time.Time `json:"updated_at"` | |||||
} | } | ||||
// CombinedStatus holds the combined state of several statuses for a single commit | // CombinedStatus holds the combined state of several statuses for a single commit | ||||
@@ -13,13 +13,13 @@ import ( | |||||
// swagger:model | // swagger:model | ||||
type User struct { | type User struct { | ||||
// the user's id | // the user's id | ||||
ID int64 `json:"id"` | |||||
ID int64 `json:"id"` | |||||
// the user's username | // the user's username | ||||
UserName string `json:"login"` | |||||
UserName string `json:"login"` | |||||
// the user's full name | // the user's full name | ||||
FullName string `json:"full_name"` | |||||
FullName string `json:"full_name"` | |||||
// swagger:strfmt email | // swagger:strfmt email | ||||
Email string `json:"email"` | |||||
Email string `json:"email"` | |||||
// URL to the user's avatar | // URL to the user's avatar | ||||
AvatarURL string `json:"avatar_url"` | AvatarURL string `json:"avatar_url"` | ||||
} | } | ||||
@@ -24,9 +24,9 @@ type GPGKey struct { | |||||
CanEncryptStorage bool `json:"can_encrypt_storage"` | CanEncryptStorage bool `json:"can_encrypt_storage"` | ||||
CanCertify bool `json:"can_certify"` | CanCertify bool `json:"can_certify"` | ||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Created time.Time `json:"created_at,omitempty"` | |||||
Created time.Time `json:"created_at,omitempty"` | |||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
Expires time.Time `json:"expires_at,omitempty"` | |||||
Expires time.Time `json:"expires_at,omitempty"` | |||||
} | } | ||||
// GPGKeyEmail an email attached to a GPGKey | // GPGKeyEmail an email attached to a GPGKey | ||||
@@ -0,0 +1,14 @@ | |||||
package gitea | |||||
import "fmt" | |||||
type searchUsersResponse struct { | |||||
Users []*User `json:"data"` | |||||
} | |||||
// SearchUsers finds users by query | |||||
func (c *Client) SearchUsers(query string, limit int) ([]*User, error) { | |||||
resp := new(searchUsersResponse) | |||||
err := c.getParsedResponse("GET", fmt.Sprintf("/users/search?q=%s&limit=%d", query, limit), nil, nil, &resp) | |||||
return resp.Users, err | |||||
} |
@@ -9,10 +9,10 @@ | |||||
"revisionTime": "2018-02-10T03:05:43Z" | "revisionTime": "2018-02-10T03:05:43Z" | ||||
}, | }, | ||||
{ | { | ||||
"checksumSHA1": "Qtq0kW+BnpYMOriaoCjMa86WGG8=", | |||||
"checksumSHA1": "PWaIU7g1YSkETxka2DIS1EYsPK0=", | |||||
"path": "code.gitea.io/sdk/gitea", | "path": "code.gitea.io/sdk/gitea", | ||||
"revision": "79eee8f12c7fc1cc5b802c5cdc5b494ef3733866", | |||||
"revisionTime": "2017-12-20T06:57:50Z" | |||||
"revision": "cdbef997666132599cc92dc22aa94de3db04adeb", | |||||
"revisionTime": "2018-03-02T14:48:43Z" | |||||
}, | }, | ||||
{ | { | ||||
"checksumSHA1": "bOODD4Gbw3GfcuQPU2dI40crxxk=", | "checksumSHA1": "bOODD4Gbw3GfcuQPU2dI40crxxk=", | ||||