diff options
Diffstat (limited to 'routers/api/v1')
-rw-r--r-- | routers/api/v1/api.go | 8 | ||||
-rw-r--r-- | routers/api/v1/repo/issue_tracked_time.go | 134 | ||||
-rw-r--r-- | routers/api/v1/utils/utils.go | 33 |
3 files changed, 150 insertions, 25 deletions
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 3f766c7a74..9f18951893 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -654,7 +654,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/times", func() { m.Combo("").Get(repo.ListTrackedTimesByRepository) m.Combo("/:timetrackingusername").Get(repo.ListTrackedTimesByUser) - }, mustEnableIssues) + }, mustEnableIssues, reqToken()) m.Group("/issues", func() { m.Combo("").Get(repo.ListIssues). Post(reqToken(), mustNotBeArchived, bind(api.CreateIssueOption{}), repo.CreateIssue) @@ -688,12 +688,12 @@ func RegisterRoutes(m *macaron.Macaron) { m.Delete("/:id", reqToken(), repo.DeleteIssueLabel) }) m.Group("/times", func() { - m.Combo("", reqToken()). + m.Combo(""). Get(repo.ListTrackedTimes). Post(bind(api.AddTimeOption{}), repo.AddTime). Delete(repo.ResetIssueTime) - m.Delete("/:id", reqToken(), repo.DeleteTime) - }) + m.Delete("/:id", repo.DeleteTime) + }, reqToken()) m.Combo("/deadline").Post(reqToken(), bind(api.EditDeadlineOption{}), repo.UpdateIssueDeadline) m.Group("/stopwatch", func() { m.Post("/start", reqToken(), repo.StartIssueStopwatch) diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go index 80830e2fe6..dd959192c9 100644 --- a/routers/api/v1/repo/issue_tracked_time.go +++ b/routers/api/v1/repo/issue_tracked_time.go @@ -5,12 +5,15 @@ package repo import ( + "fmt" "net/http" + "strings" "time" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/routers/api/v1/utils" ) // ListTrackedTimes list all the tracked times of an issue @@ -37,6 +40,16 @@ func ListTrackedTimes(ctx *context.APIContext) { // type: integer // format: int64 // required: true + // - name: since + // in: query + // description: Only show times updated after the given time. This is a timestamp in RFC 3339 format + // type: string + // format: date-time + // - name: before + // in: query + // description: Only show times updated before the given time. This is a timestamp in RFC 3339 format + // type: string + // format: date-time // responses: // "200": // "$ref": "#/responses/TrackedTimeList" @@ -62,6 +75,11 @@ func ListTrackedTimes(ctx *context.APIContext) { IssueID: issue.ID, } + if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil { + ctx.InternalServerError(err) + return + } + if !ctx.IsUserRepoAdmin() && !ctx.User.IsAdmin { opts.UserID = ctx.User.ID } @@ -141,7 +159,7 @@ func AddTime(ctx *context.APIContext, form api.AddTimeOption) { //allow only RepoAdmin, Admin and User to add time user, err = models.GetUserByName(form.User) if err != nil { - ctx.Error(500, "GetUserByName", err) + ctx.Error(http.StatusInternalServerError, "GetUserByName", err) } } } @@ -195,33 +213,33 @@ func ResetIssueTime(ctx *context.APIContext) { // "400": // "$ref": "#/responses/error" // "403": - // "$ref": "#/responses/error" + // "$ref": "#/responses/forbidden" issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrIssueNotExist(err) { ctx.NotFound(err) } else { - ctx.Error(500, "GetIssueByIndex", err) + ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err) } return } if !ctx.Repo.CanUseTimetracker(issue, ctx.User) { if !ctx.Repo.Repository.IsTimetrackerEnabled() { - ctx.JSON(400, struct{ Message string }{Message: "time tracking disabled"}) + ctx.JSON(http.StatusBadRequest, struct{ Message string }{Message: "time tracking disabled"}) return } - ctx.Status(403) + ctx.Status(http.StatusForbidden) return } err = models.DeleteIssueUserTimes(issue, ctx.User) if err != nil { if models.IsErrNotExist(err) { - ctx.Error(404, "DeleteIssueUserTimes", err) + ctx.Error(http.StatusNotFound, "DeleteIssueUserTimes", err) } else { - ctx.Error(500, "DeleteIssueUserTimes", err) + ctx.Error(http.StatusInternalServerError, "DeleteIssueUserTimes", err) } return } @@ -266,52 +284,53 @@ func DeleteTime(ctx *context.APIContext) { // "400": // "$ref": "#/responses/error" // "403": - // "$ref": "#/responses/error" + // "$ref": "#/responses/forbidden" issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrIssueNotExist(err) { ctx.NotFound(err) } else { - ctx.Error(500, "GetIssueByIndex", err) + ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err) } return } if !ctx.Repo.CanUseTimetracker(issue, ctx.User) { if !ctx.Repo.Repository.IsTimetrackerEnabled() { - ctx.JSON(400, struct{ Message string }{Message: "time tracking disabled"}) + ctx.JSON(http.StatusBadRequest, struct{ Message string }{Message: "time tracking disabled"}) return } - ctx.Status(403) + ctx.Status(http.StatusForbidden) return } time, err := models.GetTrackedTimeByID(ctx.ParamsInt64(":id")) if err != nil { - ctx.Error(500, "GetTrackedTimeByID", err) + ctx.Error(http.StatusInternalServerError, "GetTrackedTimeByID", err) return } if !ctx.User.IsAdmin && time.UserID != ctx.User.ID { //Only Admin and User itself can delete their time - ctx.Status(403) + ctx.Status(http.StatusForbidden) return } err = models.DeleteTime(time) if err != nil { - ctx.Error(500, "DeleteTime", err) + ctx.Error(http.StatusInternalServerError, "DeleteTime", err) return } - ctx.Status(204) + ctx.Status(http.StatusNoContent) } // ListTrackedTimesByUser lists all tracked times of the user func ListTrackedTimesByUser(ctx *context.APIContext) { - // swagger:operation GET /repos/{owner}/{repo}/times/{user} user userTrackedTimes + // swagger:operation GET /repos/{owner}/{repo}/times/{user} repository userTrackedTimes // --- // summary: List a user's tracked times in a repo + // deprecated: true // produces: // - application/json // parameters: @@ -335,6 +354,8 @@ func ListTrackedTimesByUser(ctx *context.APIContext) { // "$ref": "#/responses/TrackedTimeList" // "400": // "$ref": "#/responses/error" + // "403": + // "$ref": "#/responses/forbidden" if !ctx.Repo.Repository.IsTimetrackerEnabled() { ctx.Error(http.StatusBadRequest, "", "time tracking disabled") @@ -353,9 +374,23 @@ func ListTrackedTimesByUser(ctx *context.APIContext) { ctx.NotFound() return } - trackedTimes, err := models.GetTrackedTimes(models.FindTrackedTimesOptions{ + + if !ctx.IsUserRepoAdmin() && !ctx.User.IsAdmin && ctx.User.ID != user.ID { + ctx.Error(http.StatusForbidden, "", fmt.Errorf("query user not allowed not enouth rights")) + return + } + + if !ctx.IsUserRepoAdmin() && !ctx.User.IsAdmin && ctx.User.ID != user.ID { + ctx.Error(http.StatusForbidden, "", fmt.Errorf("query user not allowed not enouth rights")) + return + } + + opts := models.FindTrackedTimesOptions{ UserID: user.ID, - RepositoryID: ctx.Repo.Repository.ID}) + RepositoryID: ctx.Repo.Repository.ID, + } + + trackedTimes, err := models.GetTrackedTimes(opts) if err != nil { ctx.Error(http.StatusInternalServerError, "GetTrackedTimes", err) return @@ -385,11 +420,27 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) { // description: name of the repo // type: string // required: true + // - name: user + // in: query + // description: optional filter by user + // type: string + // - name: since + // in: query + // description: Only show times updated after the given time. This is a timestamp in RFC 3339 format + // type: string + // format: date-time + // - name: before + // in: query + // description: Only show times updated before the given time. This is a timestamp in RFC 3339 format + // type: string + // format: date-time // responses: // "200": // "$ref": "#/responses/TrackedTimeList" // "400": // "$ref": "#/responses/error" + // "403": + // "$ref": "#/responses/forbidden" if !ctx.Repo.Repository.IsTimetrackerEnabled() { ctx.Error(http.StatusBadRequest, "", "time tracking disabled") @@ -400,8 +451,30 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) { RepositoryID: ctx.Repo.Repository.ID, } + // Filters + qUser := strings.Trim(ctx.Query("user"), " ") + if qUser != "" { + user, err := models.GetUserByName(qUser) + if err != nil { + ctx.Error(http.StatusInternalServerError, "GetUserByName", err) + return + } + opts.UserID = user.ID + } + + var err error + if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil { + ctx.InternalServerError(err) + return + } + if !ctx.IsUserRepoAdmin() && !ctx.User.IsAdmin { - opts.UserID = ctx.User.ID + if opts.UserID == 0 { + opts.UserID = ctx.User.ID + } else { + ctx.Error(http.StatusForbidden, "", fmt.Errorf("query user not allowed not enouth rights")) + return + } } trackedTimes, err := models.GetTrackedTimes(opts) @@ -423,18 +496,39 @@ func ListMyTrackedTimes(ctx *context.APIContext) { // summary: List the current user's tracked times // produces: // - application/json + // parameters: + // - name: since + // in: query + // description: Only show times updated after the given time. This is a timestamp in RFC 3339 format + // type: string + // format: date-time + // - name: before + // in: query + // description: Only show times updated before the given time. This is a timestamp in RFC 3339 format + // type: string + // format: date-time // responses: // "200": // "$ref": "#/responses/TrackedTimeList" - trackedTimes, err := models.GetTrackedTimes(models.FindTrackedTimesOptions{UserID: ctx.User.ID}) + opts := models.FindTrackedTimesOptions{UserID: ctx.User.ID} + + var err error + if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil { + ctx.InternalServerError(err) + return + } + + trackedTimes, err := models.GetTrackedTimes(opts) if err != nil { ctx.Error(http.StatusInternalServerError, "GetTrackedTimesByUser", err) return } + if err = trackedTimes.LoadAttributes(); err != nil { ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) return } + ctx.JSON(http.StatusOK, trackedTimes.APIFormat()) } diff --git a/routers/api/v1/utils/utils.go b/routers/api/v1/utils/utils.go index f7c2b224d5..35f4873964 100644 --- a/routers/api/v1/utils/utils.go +++ b/routers/api/v1/utils/utils.go @@ -4,7 +4,12 @@ package utils -import "code.gitea.io/gitea/modules/context" +import ( + "strings" + "time" + + "code.gitea.io/gitea/modules/context" +) // UserID user ID of authenticated user, or 0 if not authenticated func UserID(ctx *context.APIContext) int64 { @@ -13,3 +18,29 @@ func UserID(ctx *context.APIContext) int64 { } return ctx.User.ID } + +// GetQueryBeforeSince return parsed time (unix format) from URL query's before and since +func GetQueryBeforeSince(ctx *context.APIContext) (before, since int64, err error) { + qCreatedBefore := strings.Trim(ctx.Query("before"), " ") + if qCreatedBefore != "" { + createdBefore, err := time.Parse(time.RFC3339, qCreatedBefore) + if err != nil { + return 0, 0, err + } + if !createdBefore.IsZero() { + before = createdBefore.Unix() + } + } + + qCreatedAfter := strings.Trim(ctx.Query("since"), " ") + if qCreatedAfter != "" { + createdAfter, err := time.Parse(time.RFC3339, qCreatedAfter) + if err != nil { + return 0, 0, err + } + if !createdAfter.IsZero() { + since = createdAfter.Unix() + } + } + return before, since, nil +} |