mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-16 00:01:18 -04:00
Compare commits
60 Commits
b53df8db35
...
7abd52b6bb
Author | SHA1 | Date | |
---|---|---|---|
|
7abd52b6bb | ||
|
97fc87af89 | ||
|
6fe5c4c4d9 | ||
|
dd1fd89185 | ||
|
d0f790068b | ||
|
20a697eefd | ||
|
fbe7e8e994 | ||
|
596dcc01b5 | ||
|
68ea867522 | ||
|
30027ac0bd | ||
|
185a594d32 | ||
|
20e9c58599 | ||
|
eeca89efb8 | ||
|
d067b1d34f | ||
|
016aa727c0 | ||
|
7383e7bf32 | ||
|
a7aabc5349 | ||
|
b931054fbd | ||
|
a2a01dfbe0 | ||
|
23d969738f | ||
|
0a0837f47b | ||
|
c5c41e3da5 | ||
|
24a302a7ad | ||
|
d4ea5a57d4 | ||
|
975d98d8f1 | ||
|
927da10445 | ||
|
6a18cbe6de | ||
|
e751d6c5fe | ||
|
4475c4f6fc | ||
|
fac47d4790 | ||
|
74043f7b4c | ||
|
58e56cd0c6 | ||
|
24babd6ca1 | ||
|
065001c081 | ||
|
c7440bcc1f | ||
|
897c67b555 | ||
|
34566ea494 | ||
|
d2fd13836c | ||
|
7eebc7c820 | ||
|
cf17f3456b | ||
|
3b2943a002 | ||
|
8819a0a4fc | ||
|
6238b9e746 | ||
|
fec855e323 | ||
|
dbfecced25 | ||
|
852c0df382 | ||
|
81c3d0ce34 | ||
|
aa32ad74af | ||
|
c266568eea | ||
|
5bbbade026 | ||
|
df22b6dd12 | ||
|
ac39273432 | ||
|
a0f8dbd928 | ||
|
e0ae281674 | ||
|
0b8d198b89 | ||
|
922cd13869 | ||
|
b6d45c6476 | ||
|
b6f9d05180 | ||
|
6092b81563 | ||
|
4c0ec221fa |
@ -91,6 +91,7 @@ type Project struct {
|
||||
RepoID int64 `xorm:"INDEX"`
|
||||
Repo *repo_model.Repository `xorm:"-"`
|
||||
CreatorID int64 `xorm:"NOT NULL"`
|
||||
Creator *user_model.User `xorm:"-"`
|
||||
IsClosed bool `xorm:"INDEX"`
|
||||
TemplateType TemplateType `xorm:"'board_type'"` // TODO: rename the column to template_type
|
||||
CardType CardType
|
||||
@ -121,6 +122,14 @@ func (p *Project) LoadOwner(ctx context.Context) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *Project) LoadCreator(ctx context.Context) (err error) {
|
||||
if p.Creator != nil {
|
||||
return nil
|
||||
}
|
||||
p.Creator, err = user_model.GetUserByID(ctx, p.CreatorID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *Project) LoadRepo(ctx context.Context) (err error) {
|
||||
if p.RepoID == 0 || p.Repo != nil {
|
||||
return nil
|
||||
|
43
modules/structs/project.go
Normal file
43
modules/structs/project.go
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package structs
|
||||
|
||||
import "time"
|
||||
|
||||
// swagger:model
|
||||
type NewProjectPayload struct {
|
||||
// required:true
|
||||
Title string `json:"title" binding:"Required"`
|
||||
// required:true
|
||||
BoardType uint8 `json:"board_type"`
|
||||
// required:true
|
||||
CardType uint8 `json:"card_type"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// swagger:model
|
||||
type UpdateProjectPayload struct {
|
||||
// required:true
|
||||
Title string `json:"title" binding:"Required"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// swagger:model
|
||||
type Project struct {
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
TemplateType uint8 `json:"board_type"`
|
||||
IsClosed bool `json:"is_closed"`
|
||||
// swagger:strfmt date-time
|
||||
Created time.Time `json:"created_at"`
|
||||
// swagger:strfmt date-time
|
||||
Updated time.Time `json:"updated_at"`
|
||||
// swagger:strfmt date-time
|
||||
Closed time.Time `json:"closed_at"`
|
||||
|
||||
Repo *RepositoryMeta `json:"repository"`
|
||||
Creator *User `json:"creator"`
|
||||
Owner *User `json:"owner"`
|
||||
}
|
@ -1969,6 +1969,7 @@ pulls.cmd_instruction_checkout_title=Basculer
|
||||
pulls.cmd_instruction_checkout_desc=Depuis votre dépôt, basculer sur une nouvelle branche et tester des modifications.
|
||||
pulls.cmd_instruction_merge_title=Fusionner
|
||||
pulls.cmd_instruction_merge_desc=Fusionner les modifications et mettre à jour sur Gitea.
|
||||
pulls.cmd_instruction_merge_warning=Attention : cette opération ne peut pas fusionner la demande d’ajout car la « détection automatique de fusion manuelle » n’a pas été activée
|
||||
pulls.clear_merge_message=Effacer le message de fusion
|
||||
pulls.clear_merge_message_hint=Effacer le message de fusion ne supprimera que le message de la révision, mais pas les pieds de révision générés tels que "Co-Authored-By:".
|
||||
|
||||
@ -2768,6 +2769,8 @@ branch.new_branch_from=`Créer une nouvelle branche à partir de "%s"`
|
||||
branch.renamed=La branche %s à été renommée en %s.
|
||||
branch.rename_default_or_protected_branch_error=Seuls les administrateurs peuvent renommer les branches par défaut ou protégées.
|
||||
branch.rename_protected_branch_failed=Cette branche est protégée par des règles de protection basées sur des globs.
|
||||
branch.commits_divergence_from=Divergence de révisions : %[1]d en retard et %[2]d en avance sur %[3]s
|
||||
branch.commits_no_divergence=Identique à la branche %[1]s
|
||||
|
||||
tag.create_tag=Créer l'étiquette %s
|
||||
tag.create_tag_operation=Créer une étiquette
|
||||
|
@ -2769,6 +2769,8 @@ branch.new_branch_from=`Cruthaigh brainse nua ó "%s"`
|
||||
branch.renamed=Ainmníodh brainse %s go %s.
|
||||
branch.rename_default_or_protected_branch_error=Ní féidir ach le riarthóirí brainsí réamhshocraithe nó cosanta a athainmniú.
|
||||
branch.rename_protected_branch_failed=Tá an brainse seo faoi chosaint ag rialacha cosanta domhanda.
|
||||
branch.commits_divergence_from=Déanann sé dialltacht a thiomnú: %[1]d taobh thiar agus %[2]d chun tosaigh ar %[3]s
|
||||
branch.commits_no_divergence=Mar an gcéanna le brainse %[1]s
|
||||
|
||||
tag.create_tag=Cruthaigh clib %s
|
||||
tag.create_tag_operation=Cruthaigh clib
|
||||
@ -2782,6 +2784,7 @@ topic.done=Déanta
|
||||
topic.count_prompt=Ní féidir leat níos mó ná 25 topaicí a roghnú
|
||||
topic.format_prompt=Ní mór do thopaicí tosú le litir nó uimhir, is féidir daiseanna ('-') agus poncanna ('.') a áireamh, a bheith suas le 35 carachtar ar fad. Ní mór litreacha a bheith i litreacha beaga.
|
||||
|
||||
find_file.follow_symlink=Lean an nasc siombalach seo go dtí an áit a bhfuil sé ag pointeáil air
|
||||
find_file.go_to_file=Téigh go dtí an comhad
|
||||
find_file.no_matching=Níl aon chomhad meaitseála le fáil
|
||||
|
||||
|
@ -1562,8 +1562,8 @@ issues.filter_project=Planeamento
|
||||
issues.filter_project_all=Todos os planeamentos
|
||||
issues.filter_project_none=Nenhum planeamento
|
||||
issues.filter_assignee=Encarregado
|
||||
issues.filter_assignee_no_assignee=Não atribuído
|
||||
issues.filter_assignee_any_assignee=Atribuído a qualquer pessoa
|
||||
issues.filter_assignee_no_assignee=Não atribuída
|
||||
issues.filter_assignee_any_assignee=Atribuída a alguém
|
||||
issues.filter_poster=Autor(a)
|
||||
issues.filter_user_placeholder=Procurar utilizadores
|
||||
issues.filter_user_no_select=Todos os utilizadores
|
||||
@ -1969,6 +1969,7 @@ pulls.cmd_instruction_checkout_title=Checkout
|
||||
pulls.cmd_instruction_checkout_desc=A partir do seu repositório, crie um novo ramo e teste nele as modificações.
|
||||
pulls.cmd_instruction_merge_title=Integrar
|
||||
pulls.cmd_instruction_merge_desc=Integrar as modificações e enviar para o Gitea.
|
||||
pulls.cmd_instruction_merge_warning=Aviso: Esta operação não pode executar pedidos de integração porque a opção "auto-identificar integração manual" não está habilitada.
|
||||
pulls.clear_merge_message=Apagar mensagem de integração
|
||||
pulls.clear_merge_message_hint=Apagar a mensagem de integração apenas remove o conteúdo da mensagem de cometimento e mantém os rodapés do git, tais como "Co-Autorado-Por …".
|
||||
|
||||
@ -2768,6 +2769,8 @@ branch.new_branch_from=`Criar um novo ramo a partir do ramo "%s"`
|
||||
branch.renamed=O ramo %s foi renomeado para %s.
|
||||
branch.rename_default_or_protected_branch_error=Só os administradores é que podem renomear o ramo principal ou ramos protegidos.
|
||||
branch.rename_protected_branch_failed=Este ramo está protegido por regras de salvaguarda baseadas em padrões glob.
|
||||
branch.commits_divergence_from=Divergência nos cometimentos: %[1]d atrás e %[2]d à frente de %[3]s
|
||||
branch.commits_no_divergence=Idêntico ao ramo %[1]s
|
||||
|
||||
tag.create_tag=Criar etiqueta %s
|
||||
tag.create_tag_operation=Criar etiqueta
|
||||
@ -2781,6 +2784,7 @@ topic.done=Concluído
|
||||
topic.count_prompt=Não pode escolher mais do que 25 tópicos
|
||||
topic.format_prompt=Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') ou pontos ('.') e podem ter até 35 caracteres. As letras têm que ser minúsculas.
|
||||
|
||||
find_file.follow_symlink=Seguir esta ligação simbólica para onde ela está apontando
|
||||
find_file.go_to_file=Ir para o ficheiro
|
||||
find_file.no_matching=Não foi encontrado qualquer ficheiro correspondente
|
||||
|
||||
|
@ -89,6 +89,7 @@ import (
|
||||
"code.gitea.io/gitea/routers/api/v1/notify"
|
||||
"code.gitea.io/gitea/routers/api/v1/org"
|
||||
"code.gitea.io/gitea/routers/api/v1/packages"
|
||||
"code.gitea.io/gitea/routers/api/v1/projects"
|
||||
"code.gitea.io/gitea/routers/api/v1/repo"
|
||||
"code.gitea.io/gitea/routers/api/v1/settings"
|
||||
"code.gitea.io/gitea/routers/api/v1/user"
|
||||
@ -1161,6 +1162,11 @@ func Routes() *web.Router {
|
||||
m.Delete("", user.UnblockUser)
|
||||
}, context.UserAssignmentAPI(), checkTokenPublicOnly())
|
||||
})
|
||||
|
||||
m.Group("/projects", func() {
|
||||
m.Get("", projects.ListUserProjects)
|
||||
m.Post("", bind(api.NewProjectPayload{}), projects.CreateUserProject)
|
||||
})
|
||||
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken())
|
||||
|
||||
// Repositories (requires repo scope, org scope)
|
||||
@ -1467,6 +1473,10 @@ func Routes() *web.Router {
|
||||
}, reqAdmin(), reqToken())
|
||||
|
||||
m.Methods("HEAD,GET", "/{ball_type:tarball|zipball|bundle}/*", reqRepoReader(unit.TypeCode), repo.DownloadArchive)
|
||||
|
||||
m.Group("/projects", func() {
|
||||
m.Post("", bind(api.NewProjectPayload{}), projects.CreateRepoProject)
|
||||
})
|
||||
}, repoAssignment(), checkTokenPublicOnly())
|
||||
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
|
||||
|
||||
@ -1599,7 +1609,7 @@ func Routes() *web.Router {
|
||||
Patch(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.EditMilestoneOption{}), repo.EditMilestone).
|
||||
Delete(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), repo.DeleteMilestone)
|
||||
})
|
||||
}, repoAssignment(), checkTokenPublicOnly())
|
||||
}, repoAssignment())
|
||||
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryIssue))
|
||||
|
||||
// NOTE: these are Gitea package management API - see packages.CommonRoutes and packages.DockerContainerRoutes for endpoints that implement package manager APIs
|
||||
@ -1687,6 +1697,10 @@ func Routes() *web.Router {
|
||||
m.Delete("", org.UnblockUser)
|
||||
})
|
||||
}, reqToken(), reqOrgOwnership())
|
||||
|
||||
m.Group("/projects", func() {
|
||||
m.Post("", bind(api.NewProjectPayload{}), projects.CreateOrgProject)
|
||||
})
|
||||
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(true), checkTokenPublicOnly())
|
||||
m.Group("/teams/{teamid}", func() {
|
||||
m.Combo("").Get(reqToken(), org.GetTeam).
|
||||
|
422
routers/api/v1/projects/project.go
Normal file
422
routers/api/v1/projects/project.go
Normal file
@ -0,0 +1,422 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package projects
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
project_model "code.gitea.io/gitea/models/project"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
"code.gitea.io/gitea/services/convert"
|
||||
)
|
||||
|
||||
func innerCreateProject(ctx *context.APIContext, projectType project_model.Type) {
|
||||
form := web.GetForm(ctx).(*api.NewProjectPayload)
|
||||
project := &project_model.Project{
|
||||
RepoID: 0,
|
||||
OwnerID: ctx.Doer.ID,
|
||||
Title: form.Title,
|
||||
Description: form.Description,
|
||||
CreatorID: ctx.Doer.ID,
|
||||
TemplateType: project_model.TemplateType(form.BoardType),
|
||||
Type: projectType,
|
||||
}
|
||||
|
||||
if ctx.ContextUser != nil {
|
||||
project.OwnerID = ctx.ContextUser.ID
|
||||
}
|
||||
|
||||
if projectType == project_model.TypeRepository {
|
||||
project.RepoID = ctx.Repo.Repository.ID
|
||||
}
|
||||
|
||||
if err := project_model.NewProject(ctx, project); err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
|
||||
project, err := project_model.GetProjectByID(ctx, project.ID)
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
|
||||
projectResponse, err := convert.ToAPIProject(ctx, project)
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusCreated, projectResponse)
|
||||
}
|
||||
|
||||
func CreateUserProject(ctx *context.APIContext) {
|
||||
// swagger:operation POST /user/projects project projectCreateUserProject
|
||||
// ---
|
||||
// summary: Create a user project
|
||||
// produces:
|
||||
// - application/json
|
||||
// consumes:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: project
|
||||
// in: body
|
||||
// required: true
|
||||
// schema: { "$ref": "#/definitions/NewProjectPayload" }
|
||||
// responses:
|
||||
// "201":
|
||||
// "$ref": "#/responses/Project"
|
||||
// "403":
|
||||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
innerCreateProject(ctx, project_model.TypeIndividual)
|
||||
}
|
||||
|
||||
func CreateOrgProject(ctx *context.APIContext) {
|
||||
// swagger:operation POST /orgs/{org}/projects project projectCreateOrgProject
|
||||
// ---
|
||||
// summary: Create a organization project
|
||||
// produces:
|
||||
// - application/json
|
||||
// consumes:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: org
|
||||
// in: path
|
||||
// description: owner of repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: project
|
||||
// in: body
|
||||
// required: true
|
||||
// schema: { "$ref": "#/definitions/NewProjectPayload" }
|
||||
// responses:
|
||||
// "201":
|
||||
// "$ref": "#/responses/Project"
|
||||
// "403":
|
||||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
innerCreateProject(ctx, project_model.TypeOrganization)
|
||||
}
|
||||
|
||||
func CreateRepoProject(ctx *context.APIContext) {
|
||||
// swagger:operation POST /repos/{owner}/{repo}/projects project projectCreateRepositoryProject
|
||||
// ---
|
||||
// summary: Create a repository project
|
||||
// produces:
|
||||
// - application/json
|
||||
// consumes:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: owner
|
||||
// in: path
|
||||
// description: owner of repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: repo
|
||||
// in: path
|
||||
// description: repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: project
|
||||
// in: body
|
||||
// required: true
|
||||
// schema: { "$ref": "#/definitions/NewProjectPayload" }
|
||||
// responses:
|
||||
// "201":
|
||||
// "$ref": "#/responses/Project"
|
||||
// "403":
|
||||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
innerCreateProject(ctx, project_model.TypeRepository)
|
||||
}
|
||||
|
||||
func GetProject(ctx *context.APIContext) {
|
||||
// swagger:operation GET /projects/{id} project projectGetProject
|
||||
// ---
|
||||
// summary: Get project
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: id
|
||||
// in: path
|
||||
// description: id of the project
|
||||
// type: string
|
||||
// required: true
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/Project"
|
||||
// "403":
|
||||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
project, err := project_model.GetProjectByID(ctx, ctx.FormInt64(":id"))
|
||||
if err != nil {
|
||||
if project_model.IsErrProjectNotExist(err) {
|
||||
ctx.APIError(http.StatusNotFound, err)
|
||||
} else {
|
||||
ctx.APIErrorInternal(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
projectResponse, err := convert.ToAPIProject(ctx, project)
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
ctx.JSON(http.StatusOK, projectResponse)
|
||||
}
|
||||
|
||||
func UpdateProject(ctx *context.APIContext) {
|
||||
// swagger:operation PATCH /projects/{id} project projectUpdateProject
|
||||
// ---
|
||||
// summary: Update project
|
||||
// produces:
|
||||
// - application/json
|
||||
// consumes:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: id
|
||||
// in: path
|
||||
// description: id of the project
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: project
|
||||
// in: body
|
||||
// required: true
|
||||
// schema: { "$ref": "#/definitions/UpdateProjectPayload" }
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/Project"
|
||||
// "403":
|
||||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
form := web.GetForm(ctx).(*api.UpdateProjectPayload)
|
||||
project, err := project_model.GetProjectByID(ctx, ctx.FormInt64("id"))
|
||||
if err != nil {
|
||||
if project_model.IsErrProjectNotExist(err) {
|
||||
ctx.APIError(http.StatusNotFound, err)
|
||||
} else {
|
||||
ctx.APIErrorInternal(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if project.Title != form.Title {
|
||||
project.Title = form.Title
|
||||
}
|
||||
if project.Description != form.Description {
|
||||
project.Description = form.Description
|
||||
}
|
||||
|
||||
err = project_model.UpdateProject(ctx, project)
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
projectResponse, err := convert.ToAPIProject(ctx, project)
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
ctx.JSON(http.StatusOK, projectResponse)
|
||||
}
|
||||
|
||||
func DeleteProject(ctx *context.APIContext) {
|
||||
// swagger:operation DELETE /projects/{id} project projectDeleteProject
|
||||
// ---
|
||||
// summary: Delete project
|
||||
// parameters:
|
||||
// - name: id
|
||||
// in: path
|
||||
// description: id of the project
|
||||
// type: string
|
||||
// required: true
|
||||
// responses:
|
||||
// "204":
|
||||
// "description": "Deleted the project"
|
||||
// "403":
|
||||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
|
||||
if err := project_model.DeleteProjectByID(ctx, ctx.FormInt64(":id")); err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func ListUserProjects(ctx *context.APIContext) {
|
||||
// swagger:operation GET /user/projects project projectListUserProjects
|
||||
// ---
|
||||
// summary: List user projects
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: closed
|
||||
// in: query
|
||||
// description: include closed projects or not
|
||||
// type: boolean
|
||||
// - name: page
|
||||
// in: query
|
||||
// description: page number of results to return (1-based)
|
||||
// type: integer
|
||||
// - name: limit
|
||||
// in: query
|
||||
// description: page size of results
|
||||
// type: integer
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/ProjectList"
|
||||
// "403":
|
||||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
projects, count, err := db.FindAndCount[project_model.Project](ctx, project_model.SearchOptions{
|
||||
Type: project_model.TypeIndividual,
|
||||
IsClosed: ctx.FormOptionalBool("closed"),
|
||||
OwnerID: ctx.Doer.ID,
|
||||
ListOptions: db.ListOptions{Page: ctx.FormInt("page")},
|
||||
})
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.SetLinkHeader(int(count), setting.UI.IssuePagingNum)
|
||||
ctx.SetTotalCountHeader(count)
|
||||
|
||||
apiProjects, err := convert.ToAPIProjectList(ctx, projects)
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, apiProjects)
|
||||
}
|
||||
|
||||
func ListOrgProjects(ctx *context.APIContext) {
|
||||
// swagger:operation GET /orgs/{org}/projects project projectListOrgProjects
|
||||
// ---
|
||||
// summary: List org projects
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: org
|
||||
// in: path
|
||||
// description: owner of the repository
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: closed
|
||||
// in: query
|
||||
// description: include closed projects or not
|
||||
// type: boolean
|
||||
// - name: page
|
||||
// in: query
|
||||
// description: page number of results to return (1-based)
|
||||
// type: integer
|
||||
// - name: limit
|
||||
// in: query
|
||||
// description: page size of results
|
||||
// type: integer
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/ProjectList"
|
||||
// "403":
|
||||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
projects, count, err := db.FindAndCount[project_model.Project](ctx, project_model.SearchOptions{
|
||||
OwnerID: ctx.Org.Organization.AsUser().ID,
|
||||
ListOptions: db.ListOptions{Page: ctx.FormInt("page")},
|
||||
IsClosed: ctx.FormOptionalBool("closed"),
|
||||
Type: project_model.TypeOrganization,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.SetLinkHeader(int(count), setting.UI.IssuePagingNum)
|
||||
ctx.SetTotalCountHeader(count)
|
||||
|
||||
apiProjects, err := convert.ToAPIProjectList(ctx, projects)
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, apiProjects)
|
||||
}
|
||||
|
||||
func ListRepoProjects(ctx *context.APIContext) {
|
||||
// swagger:operation GET /repos/{owner}/{repo}/projects project projectListRepositoryProjects
|
||||
// ---
|
||||
// summary: List repository projects
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: owner
|
||||
// in: path
|
||||
// description: owner of the repository
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: repo
|
||||
// in: path
|
||||
// description: repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: closed
|
||||
// in: query
|
||||
// description: include closed projects or not
|
||||
// type: boolean
|
||||
// - name: page
|
||||
// in: query
|
||||
// description: page number of results to return (1-based)
|
||||
// type: integer
|
||||
// - name: limit
|
||||
// in: query
|
||||
// description: page size of results
|
||||
// type: integer
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/ProjectList"
|
||||
// "403":
|
||||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
|
||||
page := ctx.FormInt("page")
|
||||
projects, count, err := db.FindAndCount[project_model.Project](ctx, project_model.SearchOptions{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
IsClosed: ctx.FormOptionalBool("closed"),
|
||||
Type: project_model.TypeRepository,
|
||||
ListOptions: db.ListOptions{Page: page},
|
||||
})
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.SetLinkHeader(int(count), page)
|
||||
ctx.SetTotalCountHeader(count)
|
||||
|
||||
apiProjects, err := convert.ToAPIProjectList(ctx, projects)
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, apiProjects)
|
||||
}
|
@ -221,5 +221,9 @@ type swaggerParameterBodies struct {
|
||||
UpdateVariableOption api.UpdateVariableOption
|
||||
|
||||
// in:body
|
||||
LockIssueOption api.LockIssueOption
|
||||
NewProjectPayload api.NewProjectPayload
|
||||
|
||||
// in:body
|
||||
UpdateProjectPayload api.UpdateProjectPayload
|
||||
LockIssueOption api.LockIssueOption
|
||||
}
|
||||
|
22
routers/api/v1/swagger/project.go
Normal file
22
routers/api/v1/swagger/project.go
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package swagger
|
||||
|
||||
import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// Project
|
||||
// swagger:response Project
|
||||
type swaggerResponseProject struct {
|
||||
// in:body
|
||||
Body api.Project `json:"body"`
|
||||
}
|
||||
|
||||
// ProjectList
|
||||
// swagger:response ProjectList
|
||||
type swaggerResponseProjectList struct {
|
||||
// in:body
|
||||
Body []api.Project `json:"body"`
|
||||
}
|
74
services/convert/project.go
Normal file
74
services/convert/project.go
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
project_model "code.gitea.io/gitea/models/project"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
func ToAPIProject(ctx context.Context, project *project_model.Project) (*api.Project, error) {
|
||||
apiProject := &api.Project{
|
||||
Title: project.Title,
|
||||
Description: project.Description,
|
||||
TemplateType: uint8(project.TemplateType),
|
||||
IsClosed: project.IsClosed,
|
||||
Created: project.CreatedUnix.AsTime(),
|
||||
Updated: project.UpdatedUnix.AsTime(),
|
||||
Closed: project.ClosedDateUnix.AsTime(),
|
||||
}
|
||||
|
||||
if err := project.LoadRepo(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if project.Repo != nil {
|
||||
apiProject.Repo = &api.RepositoryMeta{
|
||||
ID: project.RepoID,
|
||||
Name: project.Repo.Name,
|
||||
Owner: project.Repo.OwnerName,
|
||||
FullName: project.Repo.FullName(),
|
||||
}
|
||||
}
|
||||
|
||||
if err := project.LoadCreator(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if project.Creator != nil {
|
||||
apiProject.Creator = &api.User{
|
||||
ID: project.Creator.ID,
|
||||
UserName: project.Creator.Name,
|
||||
FullName: project.Creator.FullName,
|
||||
}
|
||||
}
|
||||
|
||||
if err := project.LoadOwner(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if project.Owner != nil {
|
||||
apiProject.Owner = &api.User{
|
||||
ID: project.Owner.ID,
|
||||
UserName: project.Owner.Name,
|
||||
FullName: project.Owner.FullName,
|
||||
}
|
||||
}
|
||||
|
||||
return apiProject, nil
|
||||
}
|
||||
|
||||
func ToAPIProjectList(ctx context.Context, projects []*project_model.Project) ([]*api.Project, error) {
|
||||
result := make([]*api.Project, len(projects))
|
||||
var err error
|
||||
for i := range projects {
|
||||
result[i], err = ToAPIProject(ctx, projects[i])
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
@ -29,7 +29,7 @@ export default {
|
||||
important: true, // the frameworks are mixed together, so tailwind needs to override other framework's styles
|
||||
content: [
|
||||
isProduction && '!./templates/devtest/**/*',
|
||||
isProduction && '!./web_src/js/standalone/devtest.js',
|
||||
isProduction && '!./web_src/js/standalone/devtest.ts',
|
||||
'!./templates/swagger/v1_json.tmpl',
|
||||
'!./templates/user/auth/oidc_wellknown.tmpl',
|
||||
'!**/*_test.go',
|
||||
|
486
templates/swagger/v1_json.tmpl
generated
486
templates/swagger/v1_json.tmpl
generated
@ -3311,6 +3311,94 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/orgs/{org}/projects": {
|
||||
"get": {
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"project"
|
||||
],
|
||||
"summary": "List org projects",
|
||||
"operationId": "projectListOrgProjects",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "owner of the repository",
|
||||
"name": "org",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"description": "include closed projects or not",
|
||||
"name": "closed",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "page number of results to return (1-based)",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "page size of results",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/ProjectList"
|
||||
},
|
||||
"403": {
|
||||
"$ref": "#/responses/forbidden"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFound"
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"project"
|
||||
],
|
||||
"summary": "Create a organization project",
|
||||
"operationId": "projectCreateOrgProject",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "owner of repo",
|
||||
"name": "org",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "project",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/NewProjectPayload"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"$ref": "#/responses/Project"
|
||||
},
|
||||
"403": {
|
||||
"$ref": "#/responses/forbidden"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/orgs/{org}/public_members": {
|
||||
"get": {
|
||||
"produces": [
|
||||
@ -4137,6 +4225,106 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/projects/{id}": {
|
||||
"get": {
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"project"
|
||||
],
|
||||
"summary": "Get project",
|
||||
"operationId": "projectGetProject",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id of the project",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/Project"
|
||||
},
|
||||
"403": {
|
||||
"$ref": "#/responses/forbidden"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFound"
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"project"
|
||||
],
|
||||
"summary": "Delete project",
|
||||
"operationId": "projectDeleteProject",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id of the project",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "Deleted the project"
|
||||
},
|
||||
"403": {
|
||||
"$ref": "#/responses/forbidden"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFound"
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"project"
|
||||
],
|
||||
"summary": "Update project",
|
||||
"operationId": "projectUpdateProject",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id of the project",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "project",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/UpdateProjectPayload"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/Project"
|
||||
},
|
||||
"403": {
|
||||
"$ref": "#/responses/forbidden"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFound"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/repos/issues/search": {
|
||||
"get": {
|
||||
"produces": [
|
||||
@ -13411,6 +13599,111 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/repos/{owner}/{repo}/projects": {
|
||||
"get": {
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"project"
|
||||
],
|
||||
"summary": "List repository projects",
|
||||
"operationId": "projectListRepositoryProjects",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "owner of the repository",
|
||||
"name": "owner",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "repo",
|
||||
"name": "repo",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"description": "include closed projects or not",
|
||||
"name": "closed",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "page number of results to return (1-based)",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "page size of results",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/ProjectList"
|
||||
},
|
||||
"403": {
|
||||
"$ref": "#/responses/forbidden"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFound"
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"project"
|
||||
],
|
||||
"summary": "Create a repository project",
|
||||
"operationId": "projectCreateRepositoryProject",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "owner of repo",
|
||||
"name": "owner",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "repo",
|
||||
"name": "repo",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "project",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/NewProjectPayload"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"$ref": "#/responses/Project"
|
||||
},
|
||||
"403": {
|
||||
"$ref": "#/responses/forbidden"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFound"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/repos/{owner}/{repo}/pulls": {
|
||||
"get": {
|
||||
"produces": [
|
||||
@ -19661,6 +19954,83 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/projects": {
|
||||
"get": {
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"project"
|
||||
],
|
||||
"summary": "List user projects",
|
||||
"operationId": "projectListUserProjects",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"description": "include closed projects or not",
|
||||
"name": "closed",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "page number of results to return (1-based)",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "page size of results",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/ProjectList"
|
||||
},
|
||||
"403": {
|
||||
"$ref": "#/responses/forbidden"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFound"
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"project"
|
||||
],
|
||||
"summary": "Create a user project",
|
||||
"operationId": "projectCreateUserProject",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "project",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/NewProjectPayload"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"$ref": "#/responses/Project"
|
||||
},
|
||||
"403": {
|
||||
"$ref": "#/responses/forbidden"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFound"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/repos": {
|
||||
"get": {
|
||||
"produces": [
|
||||
@ -26006,6 +26376,35 @@
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
},
|
||||
"NewProjectPayload": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"title",
|
||||
"board_type",
|
||||
"card_type"
|
||||
],
|
||||
"properties": {
|
||||
"board_type": {
|
||||
"type": "integer",
|
||||
"format": "uint8",
|
||||
"x-go-name": "BoardType"
|
||||
},
|
||||
"card_type": {
|
||||
"type": "integer",
|
||||
"format": "uint8",
|
||||
"x-go-name": "CardType"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"x-go-name": "Description"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"x-go-name": "Title"
|
||||
}
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
},
|
||||
"NodeInfo": {
|
||||
"description": "NodeInfo contains standardized way of exposing metadata about a server running one of the distributed social networks",
|
||||
"type": "object",
|
||||
@ -26578,6 +26977,58 @@
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
},
|
||||
"Project": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"board_type": {
|
||||
"type": "integer",
|
||||
"format": "uint8",
|
||||
"x-go-name": "TemplateType"
|
||||
},
|
||||
"closed_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"x-go-name": "Closed"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"x-go-name": "Created"
|
||||
},
|
||||
"creator": {
|
||||
"$ref": "#/definitions/User"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"x-go-name": "Description"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"x-go-name": "ID"
|
||||
},
|
||||
"is_closed": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "IsClosed"
|
||||
},
|
||||
"owner": {
|
||||
"$ref": "#/definitions/User"
|
||||
},
|
||||
"repository": {
|
||||
"$ref": "#/definitions/RepositoryMeta"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"x-go-name": "Title"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"x-go-name": "Updated"
|
||||
}
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
},
|
||||
"PublicKey": {
|
||||
"description": "PublicKey publickey is a user key to push code to repository",
|
||||
"type": "object",
|
||||
@ -28132,6 +28583,23 @@
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
},
|
||||
"UpdateProjectPayload": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"title"
|
||||
],
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string",
|
||||
"x-go-name": "Description"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"x-go-name": "Title"
|
||||
}
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
},
|
||||
"UpdateRepoAvatarOption": {
|
||||
"description": "UpdateRepoAvatarUserOption options when updating the repo avatar",
|
||||
"type": "object",
|
||||
@ -29202,6 +29670,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Project": {
|
||||
"description": "Project",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Project"
|
||||
}
|
||||
},
|
||||
"ProjectList": {
|
||||
"description": "ProjectList",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Project"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PublicKey": {
|
||||
"description": "PublicKey",
|
||||
"schema": {
|
||||
@ -29664,6 +30147,9 @@
|
||||
"description": "parameterBodies",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/LockIssueOption"
|
||||
},
|
||||
"headers": {
|
||||
"LockIssueOption": {}
|
||||
}
|
||||
},
|
||||
"redirect": {
|
||||
|
170
tests/integration/api_project_test.go
Normal file
170
tests/integration/api_project_test.go
Normal file
@ -0,0 +1,170 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
project_model "code.gitea.io/gitea/models/project"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPICreateUserProject(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
const title, description, boardType = "project_name", "project_description", uint8(project_model.TemplateTypeBasicKanban)
|
||||
|
||||
token := getUserToken(t, "user2", auth_model.AccessTokenScopeWriteIssue, auth_model.AccessTokenScopeWriteUser)
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/projects", &api.NewProjectPayload{
|
||||
Title: title,
|
||||
Description: description,
|
||||
BoardType: boardType,
|
||||
}).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
var apiProject api.Project
|
||||
DecodeJSON(t, resp, &apiProject)
|
||||
assert.Equal(t, title, apiProject.Title)
|
||||
assert.Equal(t, description, apiProject.Description)
|
||||
assert.Equal(t, boardType, apiProject.TemplateType)
|
||||
assert.Equal(t, "user2", apiProject.Creator.UserName)
|
||||
}
|
||||
|
||||
func TestAPICreateOrgProject(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
const title, description, boardType = "project_name", "project_description", uint8(project_model.TemplateTypeBasicKanban)
|
||||
|
||||
orgName := "org17"
|
||||
token := getUserToken(t, "user2", auth_model.AccessTokenScopeWriteIssue, auth_model.AccessTokenScopeWriteOrganization)
|
||||
urlStr := fmt.Sprintf("/api/v1/orgs/%s/projects", orgName)
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.NewProjectPayload{
|
||||
Title: title,
|
||||
Description: description,
|
||||
BoardType: boardType,
|
||||
}).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
var apiProject api.Project
|
||||
DecodeJSON(t, resp, &apiProject)
|
||||
assert.Equal(t, title, apiProject.Title)
|
||||
assert.Equal(t, description, apiProject.Description)
|
||||
assert.Equal(t, boardType, apiProject.TemplateType)
|
||||
assert.Equal(t, "user2", apiProject.Creator.UserName)
|
||||
assert.Equal(t, "org17", apiProject.Owner.UserName)
|
||||
}
|
||||
|
||||
func TestAPICreateRepoProject(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
const title, description, boardType = "project_name", "project_description", uint8(project_model.TemplateTypeBasicKanban)
|
||||
|
||||
ownerName := "user2"
|
||||
repoName := "repo1"
|
||||
token := getUserToken(t, ownerName, auth_model.AccessTokenScopeWriteIssue, auth_model.AccessTokenScopeWriteOrganization)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/projects", ownerName, repoName)
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.NewProjectPayload{
|
||||
Title: title,
|
||||
Description: description,
|
||||
BoardType: boardType,
|
||||
}).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
var apiProject api.Project
|
||||
DecodeJSON(t, resp, &apiProject)
|
||||
assert.Equal(t, title, apiProject.Title)
|
||||
assert.Equal(t, description, apiProject.Description)
|
||||
assert.Equal(t, boardType, apiProject.TemplateType)
|
||||
assert.Equal(t, "repo1", apiProject.Repo.Name)
|
||||
}
|
||||
|
||||
func TestAPIListUserProjects(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
token := getUserToken(t, "user2", auth_model.AccessTokenScopeReadUser, auth_model.AccessTokenScopeReadIssue)
|
||||
link, _ := url.Parse("/api/v1/user/projects")
|
||||
|
||||
req := NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
var apiProjects []*api.Project
|
||||
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiProjects)
|
||||
assert.Len(t, apiProjects, 1)
|
||||
}
|
||||
|
||||
func TestAPIListOrgProjects(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
orgName := "org17"
|
||||
token := getUserToken(t, "user2", auth_model.AccessTokenScopeReadOrganization, auth_model.AccessTokenScopeReadIssue)
|
||||
link, _ := url.Parse(fmt.Sprintf("/api/v1/orgs/%s/projects", orgName))
|
||||
|
||||
req := NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
var apiProjects []*api.Project
|
||||
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiProjects)
|
||||
assert.Len(t, apiProjects, 1)
|
||||
}
|
||||
|
||||
func TestAPIListRepoProjects(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
ownerName := "user2"
|
||||
repoName := "repo1"
|
||||
token := getUserToken(t, "user2", auth_model.AccessTokenScopeReadRepository, auth_model.AccessTokenScopeReadIssue)
|
||||
link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/projects", ownerName, repoName))
|
||||
|
||||
req := NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
var apiProjects []*api.Project
|
||||
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiProjects)
|
||||
assert.Len(t, apiProjects, 1)
|
||||
}
|
||||
|
||||
func TestAPIGetProject(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
token := getUserToken(t, "user2", auth_model.AccessTokenScopeReadUser, auth_model.AccessTokenScopeReadIssue)
|
||||
link, _ := url.Parse(fmt.Sprintf("/api/v1/projects/%d", 1))
|
||||
|
||||
req := NewRequest(t, "GET", link.String()).AddTokenAuth(token)
|
||||
var apiProject *api.Project
|
||||
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiProject)
|
||||
assert.Equal(t, "First project", apiProject.Title)
|
||||
assert.Equal(t, "repo1", apiProject.Repo.Name)
|
||||
assert.Equal(t, "user2", apiProject.Creator.UserName)
|
||||
}
|
||||
|
||||
func TestAPIUpdateProject(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
token := getUserToken(t, "user2", auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteIssue)
|
||||
link, _ := url.Parse(fmt.Sprintf("/api/v1/projects/%d", 1))
|
||||
|
||||
req := NewRequestWithJSON(t, "PATCH", link.String(), &api.UpdateProjectPayload{Title: "First project updated"}).AddTokenAuth(token)
|
||||
|
||||
var apiProject *api.Project
|
||||
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiProject)
|
||||
assert.Equal(t, "First project updated", apiProject.Title)
|
||||
}
|
||||
|
||||
func TestAPIDeleteProject(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
token := getUserToken(t, "user2", auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteIssue)
|
||||
link, _ := url.Parse(fmt.Sprintf("/api/v1/projects/%d", 1))
|
||||
|
||||
req := NewRequest(t, "DELETE", link.String()).AddTokenAuth(token)
|
||||
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
unittest.AssertNotExistsBean(t, &project_model.Project{ID: 1})
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user