Skip to content

Commit ef6813a

Browse files
kolaentejonasfranz
authored andcommitted
Issue due date api (#3890)
* Implemented basic api endpoint to manage deadlines * Fixed checking for permissions * Updating a deadline from the ui is now entirely done via the api * cleanup * Cosmetics * fixed lint + fmt * Added swagger model definition for deadline response * Updated gitea-sdk * Updated gitea-sdk * More cleanup * Generate swagger json * Merge branch 'master' of https://github.com/go-gitea/gitea into issue-due-date-api # Conflicts: # public/swagger.v1.json * Fixed permission to update a deadline via api * Re-added form to change a deadline * Added client-side validation + not ignore error messages from the api * Added locale for error message * Merge branch 'master' of https://github.com/go-gitea/gitea # Conflicts: # models/issue_comment.go * Proper date validation * Fixed indention * moved css to css file * added documentation for error codes * after merge cleanup * Added swagger description * DO NOTHING BUT TRIGGER THAT F*CKIN CI SO IT PICKS UP THE LATEST COMMIT AS IT SHOULD * DO NOTHING BUT TRIGGER THAT F*CKIN CI SO IT PICKS UP THE LATEST COMMIT AS IT SHOULD * regenerated stylesheets
1 parent 55d9ddf commit ef6813a

File tree

12 files changed

+258
-90
lines changed

12 files changed

+258
-90
lines changed

options/locale/locale_en-US.ini

+1
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,7 @@ issues.due_date_added = "added the due date %s %s"
781781
issues.due_date_modified = "modified the due date to %s from %s %s"
782782
issues.due_date_remove = "removed the due date %s %s"
783783
issues.due_date_overdue = "Overdue"
784+
issues.due_date_invalid = "The due date is invalid or out of range. Please use the format yyyy-mm-dd."
784785

785786
pulls.desc = Enable merge requests and code reviews.
786787
pulls.new = New Pull Request

public/css/index.css

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/js/index.js

+37-7
Original file line numberDiff line numberDiff line change
@@ -2447,14 +2447,44 @@ function initTopicbar() {
24472447
}
24482448
});
24492449
}
2450-
function toggleDuedateForm() {
2451-
$('#add_deadline_form').fadeToggle(150);
2450+
function toggleDeadlineForm() {
2451+
$('#deadlineForm').fadeToggle(150);
24522452
}
24532453

2454-
function deleteDueDate(url) {
2455-
$.post(url, {
2456-
'_csrf': csrf,
2457-
},function( data ) {
2458-
window.location.reload();
2454+
function setDeadline() {
2455+
var deadline = $('#deadlineDate').val();
2456+
updateDeadline(deadline);
2457+
}
2458+
2459+
function updateDeadline(deadlineString) {
2460+
$('#deadline-err-invalid-date').hide();
2461+
$('#deadline-loader').addClass('loading');
2462+
2463+
var realDeadline = null;
2464+
if (deadlineString !== '') {
2465+
2466+
var newDate = Date.parse(deadlineString)
2467+
2468+
if (isNaN(newDate)) {
2469+
$('#deadline-loader').removeClass('loading');
2470+
$('#deadline-err-invalid-date').show();
2471+
return false;
2472+
}
2473+
realDeadline = new Date(newDate);
2474+
}
2475+
2476+
$.ajax($('#update-issue-deadline-form').attr('action') + '/deadline', {
2477+
data: JSON.stringify({
2478+
'due_date': realDeadline,
2479+
}),
2480+
contentType: 'application/json',
2481+
type: 'POST',
2482+
success: function () {
2483+
window.location.reload();
2484+
},
2485+
error: function () {
2486+
$('#deadline-loader').removeClass('loading');
2487+
$('#deadline-err-invalid-date').show();
2488+
}
24592489
});
24602490
}

public/less/_repository.less

+7
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@
9898
}
9999
}
100100
}
101+
102+
#deadlineForm input{
103+
width: 12.8rem;
104+
border-radius: 4px 0 0 4px;
105+
border-right: 0;
106+
white-space: nowrap;
107+
}
101108
}
102109
.header-wrapper {
103110
background-color: #FAFAFA;

public/swagger.v1.json

+95
Original file line numberDiff line numberDiff line change
@@ -2320,6 +2320,68 @@
23202320
}
23212321
}
23222322
},
2323+
"/repos/{owner}/{repo}/issues/{index}/deadline": {
2324+
"post": {
2325+
"consumes": [
2326+
"application/json"
2327+
],
2328+
"produces": [
2329+
"application/json"
2330+
],
2331+
"tags": [
2332+
"issue"
2333+
],
2334+
"summary": "Set an issue deadline. If set to null, the deadline is deleted.",
2335+
"operationId": "issueEditIssueDeadline",
2336+
"parameters": [
2337+
{
2338+
"type": "string",
2339+
"description": "owner of the repo",
2340+
"name": "owner",
2341+
"in": "path",
2342+
"required": true
2343+
},
2344+
{
2345+
"type": "string",
2346+
"description": "name of the repo",
2347+
"name": "repo",
2348+
"in": "path",
2349+
"required": true
2350+
},
2351+
{
2352+
"type": "integer",
2353+
"description": "index of the issue to create or update a deadline on",
2354+
"name": "index",
2355+
"in": "path",
2356+
"required": true
2357+
},
2358+
{
2359+
"name": "body",
2360+
"in": "body",
2361+
"schema": {
2362+
"$ref": "#/definitions/EditDeadlineOption"
2363+
}
2364+
}
2365+
],
2366+
"responses": {
2367+
"201": {
2368+
"$ref": "#/responses/IssueDeadline"
2369+
},
2370+
"403": {
2371+
"description": "Not repo writer",
2372+
"schema": {
2373+
"$ref": "#/responses/forbidden"
2374+
}
2375+
},
2376+
"404": {
2377+
"description": "Issue not found",
2378+
"schema": {
2379+
"$ref": "#/responses/empty"
2380+
}
2381+
}
2382+
}
2383+
}
2384+
},
23232385
"/repos/{owner}/{repo}/issues/{index}/labels": {
23242386
"get": {
23252387
"produces": [
@@ -6145,6 +6207,21 @@
61456207
},
61466208
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
61476209
},
6210+
"EditDeadlineOption": {
6211+
"description": "EditDeadlineOption options for creating a deadline",
6212+
"type": "object",
6213+
"required": [
6214+
"due_date"
6215+
],
6216+
"properties": {
6217+
"due_date": {
6218+
"type": "string",
6219+
"format": "date-time",
6220+
"x-go-name": "Deadline"
6221+
}
6222+
},
6223+
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
6224+
},
61486225
"EditHookOption": {
61496226
"description": "EditHookOption options when modify one hook",
61506227
"type": "object",
@@ -6635,6 +6712,18 @@
66356712
},
66366713
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
66376714
},
6715+
"IssueDeadline": {
6716+
"description": "IssueDeadline represents an issue deadline",
6717+
"type": "object",
6718+
"properties": {
6719+
"due_date": {
6720+
"type": "string",
6721+
"format": "date-time",
6722+
"x-go-name": "Deadline"
6723+
}
6724+
},
6725+
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
6726+
},
66386727
"IssueLabelsOption": {
66396728
"description": "IssueLabelsOption a collection of labels",
66406729
"type": "object",
@@ -7635,6 +7724,12 @@
76357724
"$ref": "#/definitions/Issue"
76367725
}
76377726
},
7727+
"IssueDeadline": {
7728+
"description": "IssueDeadline",
7729+
"schema": {
7730+
"$ref": "#/definitions/IssueDeadline"
7731+
}
7732+
},
76387733
"IssueList": {
76397734
"description": "IssueList",
76407735
"schema": {

routers/api/v1/api.go

+2
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,8 @@ func RegisterRoutes(m *macaron.Macaron) {
447447
m.Combo("").Get(repo.ListTrackedTimes).
448448
Post(reqToken(), bind(api.AddTimeOption{}), repo.AddTime)
449449
})
450+
451+
m.Combo("/deadline").Post(reqToken(), bind(api.EditDeadlineOption{}), repo.UpdateIssueDeadline)
450452
})
451453
}, mustEnableIssues)
452454
m.Group("/labels", func() {

routers/api/v1/repo/issue.go

+70-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
278278

279279
// Update the deadline
280280
var deadlineUnix util.TimeStamp
281-
if form.Deadline != nil && !form.Deadline.IsZero() {
281+
if form.Deadline != nil && !form.Deadline.IsZero() && ctx.Repo.IsWriter() {
282282
deadlineUnix = util.TimeStamp(form.Deadline.Unix())
283283
}
284284

@@ -338,3 +338,72 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
338338
}
339339
ctx.JSON(201, issue.APIFormat())
340340
}
341+
342+
// UpdateIssueDeadline updates an issue deadline
343+
func UpdateIssueDeadline(ctx *context.APIContext, form api.EditDeadlineOption) {
344+
// swagger:operation POST /repos/{owner}/{repo}/issues/{index}/deadline issue issueEditIssueDeadline
345+
// ---
346+
// summary: Set an issue deadline. If set to null, the deadline is deleted.
347+
// consumes:
348+
// - application/json
349+
// produces:
350+
// - application/json
351+
// parameters:
352+
// - name: owner
353+
// in: path
354+
// description: owner of the repo
355+
// type: string
356+
// required: true
357+
// - name: repo
358+
// in: path
359+
// description: name of the repo
360+
// type: string
361+
// required: true
362+
// - name: index
363+
// in: path
364+
// description: index of the issue to create or update a deadline on
365+
// type: integer
366+
// required: true
367+
// - name: body
368+
// in: body
369+
// schema:
370+
// "$ref": "#/definitions/EditDeadlineOption"
371+
// responses:
372+
// "201":
373+
// "$ref": "#/responses/IssueDeadline"
374+
// "403":
375+
// description: Not repo writer
376+
// schema:
377+
// "$ref": "#/responses/forbidden"
378+
// "404":
379+
// description: Issue not found
380+
// schema:
381+
// "$ref": "#/responses/empty"
382+
383+
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
384+
if err != nil {
385+
if models.IsErrIssueNotExist(err) {
386+
ctx.Status(404)
387+
} else {
388+
ctx.Error(500, "GetIssueByIndex", err)
389+
}
390+
return
391+
}
392+
393+
if !ctx.Repo.IsWriter() {
394+
ctx.Status(403)
395+
return
396+
}
397+
398+
var deadlineUnix util.TimeStamp
399+
if form.Deadline != nil && !form.Deadline.IsZero() {
400+
deadlineUnix = util.TimeStamp(form.Deadline.Unix())
401+
}
402+
403+
if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.User); err != nil {
404+
ctx.Error(500, "UpdateIssueDeadline", err)
405+
return
406+
}
407+
408+
ctx.JSON(201, api.IssueDeadline{Deadline: form.Deadline})
409+
}

routers/api/v1/swagger/issue.go

+7
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,10 @@ type swaggerResponseTrackedTimeList struct {
7777
// in:body
7878
Body []api.TrackedTime `json:"body"`
7979
}
80+
81+
// IssueDeadline
82+
// swagger:response IssueDeadline
83+
type swaggerIssueDeadline struct {
84+
// in:body
85+
Body api.IssueDeadline `json:"body"`
86+
}

routers/api/v1/swagger/options.go

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ type swaggerParameterBodies struct {
3232
CreateIssueOption api.CreateIssueOption
3333
// in:body
3434
EditIssueOption api.EditIssueOption
35+
// in:body
36+
EditDeadlineOption api.EditDeadlineOption
3537

3638
// in:body
3739
CreateIssueCommentOption api.CreateIssueCommentOption

routers/repo/issue.go

-48
Original file line numberDiff line numberDiff line change
@@ -1490,51 +1490,3 @@ func ChangeCommentReaction(ctx *context.Context, form auth.ReactionForm) {
14901490
"html": html,
14911491
})
14921492
}
1493-
1494-
// UpdateDeadline adds or updates a deadline
1495-
func UpdateDeadline(ctx *context.Context, form auth.DeadlineForm) {
1496-
issue := GetActionIssue(ctx)
1497-
if ctx.Written() {
1498-
return
1499-
}
1500-
1501-
if ctx.HasError() {
1502-
ctx.ServerError("ChangeIssueDeadline", errors.New(ctx.GetErrMsg()))
1503-
return
1504-
}
1505-
1506-
// Make unix of deadline string
1507-
deadline, err := time.ParseInLocation("2006-01-02", form.DateString, time.Local)
1508-
if err != nil {
1509-
ctx.Flash.Error(ctx.Tr("repo.issues.invalid_due_date_format"))
1510-
ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issue.Index))
1511-
return
1512-
}
1513-
1514-
if err = models.UpdateIssueDeadline(issue, util.TimeStamp(deadline.Unix()), ctx.User); err != nil {
1515-
ctx.Flash.Error(ctx.Tr("repo.issues.error_modifying_due_date"))
1516-
}
1517-
1518-
ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issue.Index))
1519-
return
1520-
}
1521-
1522-
// RemoveDeadline removes a deadline
1523-
func RemoveDeadline(ctx *context.Context) {
1524-
issue := GetActionIssue(ctx)
1525-
if ctx.Written() {
1526-
return
1527-
}
1528-
1529-
if ctx.HasError() {
1530-
ctx.ServerError("RemoveIssueDeadline", errors.New(ctx.GetErrMsg()))
1531-
return
1532-
}
1533-
1534-
if err := models.UpdateIssueDeadline(issue, 0, ctx.User); err != nil {
1535-
ctx.Flash.Error(ctx.Tr("repo.issues.error_removing_due_date"))
1536-
}
1537-
1538-
ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issue.Index))
1539-
return
1540-
}

routers/routes/routes.go

-2
Original file line numberDiff line numberDiff line change
@@ -532,8 +532,6 @@ func RegisterRoutes(m *macaron.Macaron) {
532532
})
533533
})
534534
m.Post("/reactions/:action", bindIgnErr(auth.ReactionForm{}), repo.ChangeIssueReaction)
535-
m.Post("/deadline/update", reqRepoWriter, bindIgnErr(auth.DeadlineForm{}), repo.UpdateDeadline)
536-
m.Post("/deadline/delete", reqRepoWriter, repo.RemoveDeadline)
537535
})
538536

539537
m.Post("/labels", reqRepoWriter, repo.UpdateIssueLabel)

0 commit comments

Comments
 (0)