| OLD | NEW |
| 1 // Copyright 2015 The LUCI Authors. | 1 // Copyright 2015 The LUCI Authors. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. | 13 // limitations under the License. |
| 14 | 14 |
| 15 package ui | 15 package ui |
| 16 | 16 |
| 17 import ( | 17 import ( |
| 18 "fmt" | 18 "fmt" |
| 19 "net/http" | 19 "net/http" |
| 20 "strconv" | 20 "strconv" |
| 21 "sync" | 21 "sync" |
| 22 | 22 |
| 23 "github.com/luci/luci-go/server/auth" | |
| 24 "github.com/luci/luci-go/server/router" | 23 "github.com/luci/luci-go/server/router" |
| 25 "github.com/luci/luci-go/server/templates" | 24 "github.com/luci/luci-go/server/templates" |
| 26 | 25 |
| 27 "github.com/luci/luci-go/scheduler/appengine/acl" | |
| 28 "github.com/luci/luci-go/scheduler/appengine/engine" | 26 "github.com/luci/luci-go/scheduler/appengine/engine" |
| 29 ) | 27 ) |
| 30 | 28 |
| 31 func invocationPage(c *router.Context) { | 29 func invocationPage(c *router.Context) { |
| 32 projectID := c.Params.ByName("ProjectID") | 30 projectID := c.Params.ByName("ProjectID") |
| 33 jobName := c.Params.ByName("JobName") | 31 jobName := c.Params.ByName("JobName") |
| 34 invID, err := strconv.ParseInt(c.Params.ByName("InvID"), 10, 64) | 32 invID, err := strconv.ParseInt(c.Params.ByName("InvID"), 10, 64) |
| 35 if err != nil { | 33 if err != nil { |
| 36 http.Error(c.Writer, "No such invocation", http.StatusNotFound) | 34 http.Error(c.Writer, "No such invocation", http.StatusNotFound) |
| 37 return | 35 return |
| 38 } | 36 } |
| 39 | 37 |
| 40 var inv *engine.Invocation | 38 var inv *engine.Invocation |
| 41 var job *engine.Job | 39 var job *engine.Job |
| 42 var err1, err2 error | 40 var err1, err2 error |
| 43 | 41 |
| 44 eng := config(c.Context).Engine | 42 eng := config(c.Context).Engine |
| 45 | 43 |
| 46 wg := sync.WaitGroup{} | 44 wg := sync.WaitGroup{} |
| 47 wg.Add(1) | 45 wg.Add(1) |
| 48 go func() { | 46 go func() { |
| 49 defer wg.Done() | 47 defer wg.Done() |
| 50 » » inv, err1 = eng.GetInvocation(c.Context, projectID+"/"+jobName,
invID) | 48 » » inv, err1 = eng.GetVisibleInvocation(c.Context, projectID+"/"+jo
bName, invID) |
| 51 }() | 49 }() |
| 52 wg.Add(1) | 50 wg.Add(1) |
| 53 go func() { | 51 go func() { |
| 54 defer wg.Done() | 52 defer wg.Done() |
| 55 » » job, err2 = eng.GetJob(c.Context, projectID+"/"+jobName) | 53 » » job, err2 = eng.GetVisibleJob(c.Context, projectID+"/"+jobName) |
| 56 }() | 54 }() |
| 57 wg.Wait() | 55 wg.Wait() |
| 58 | 56 |
| 59 // panic on internal datastore errors to trigger HTTP 500. | 57 // panic on internal datastore errors to trigger HTTP 500. |
| 60 switch { | 58 switch { |
| 61 case err1 != nil: | 59 case err1 != nil: |
| 62 panic(err1) | 60 panic(err1) |
| 63 case err2 != nil: | 61 case err2 != nil: |
| 64 panic(err2) | 62 panic(err2) |
| 65 case inv == nil: | 63 case inv == nil: |
| 66 http.Error(c.Writer, "No such invocation", http.StatusNotFound) | 64 http.Error(c.Writer, "No such invocation", http.StatusNotFound) |
| 67 return | 65 return |
| 68 case job == nil: | 66 case job == nil: |
| 69 http.Error(c.Writer, "No such job", http.StatusNotFound) | 67 http.Error(c.Writer, "No such job", http.StatusNotFound) |
| 70 return | 68 return |
| 71 } | 69 } |
| 72 | 70 |
| 73 jobUI := makeJob(c.Context, job) | 71 jobUI := makeJob(c.Context, job) |
| 74 templates.MustRender(c.Context, c.Writer, "pages/invocation.html", map[s
tring]interface{}{ | 72 templates.MustRender(c.Context, c.Writer, "pages/invocation.html", map[s
tring]interface{}{ |
| 75 "Job": jobUI, | 73 "Job": jobUI, |
| 76 "Inv": makeInvocation(jobUI, inv), | 74 "Inv": makeInvocation(jobUI, inv), |
| 77 }) | 75 }) |
| 78 } | 76 } |
| 79 | 77 |
| 80 //////////////////////////////////////////////////////////////////////////////// | 78 //////////////////////////////////////////////////////////////////////////////// |
| 81 // Actions. | 79 // Actions. |
| 82 | 80 |
| 83 func abortInvocationAction(c *router.Context) { | 81 func abortInvocationAction(c *router.Context) { |
| 84 handleInvAction(c, func(jobID string, invID int64) error { | 82 handleInvAction(c, func(jobID string, invID int64) error { |
| 85 » » who := auth.CurrentIdentity(c.Context) | 83 » » return config(c.Context).Engine.AbortInvocation(c.Context, jobID
, invID) |
| 86 » » return config(c.Context).Engine.AbortInvocation(c.Context, jobID
, invID, who) | |
| 87 }) | 84 }) |
| 88 } | 85 } |
| 89 | 86 |
| 90 func handleInvAction(c *router.Context, cb func(string, int64) error) { | 87 func handleInvAction(c *router.Context, cb func(string, int64) error) { |
| 91 projectID := c.Params.ByName("ProjectID") | 88 projectID := c.Params.ByName("ProjectID") |
| 92 jobName := c.Params.ByName("JobName") | 89 jobName := c.Params.ByName("JobName") |
| 93 invID := c.Params.ByName("InvID") | 90 invID := c.Params.ByName("InvID") |
| 94 if !acl.IsJobOwner(c.Context, projectID, jobName) { | |
| 95 http.Error(c.Writer, "Forbidden", 403) | |
| 96 return | |
| 97 } | |
| 98 invIDAsInt, err := strconv.ParseInt(invID, 10, 64) | 91 invIDAsInt, err := strconv.ParseInt(invID, 10, 64) |
| 99 if err != nil { | 92 if err != nil { |
| 100 http.Error(c.Writer, "Bad invocation ID", 400) | 93 http.Error(c.Writer, "Bad invocation ID", 400) |
| 101 return | 94 return |
| 102 } | 95 } |
| 103 » if err := cb(projectID+"/"+jobName, invIDAsInt); err != nil { | 96 » switch err := cb(projectID+"/"+jobName, invIDAsInt); { |
| 97 » case err == engine.ErrNoOwnerPermission: |
| 98 » » http.Error(c.Writer, "Forbidden", 403) |
| 99 » » return |
| 100 » case err != nil: |
| 104 panic(err) | 101 panic(err) |
| 102 default: |
| 103 http.Redirect(c.Writer, c.Request, fmt.Sprintf("/jobs/%s/%s/%s",
projectID, jobName, invID), http.StatusFound) |
| 105 } | 104 } |
| 106 http.Redirect(c.Writer, c.Request, fmt.Sprintf("/jobs/%s/%s/%s", project
ID, jobName, invID), http.StatusFound) | |
| 107 } | 105 } |
| OLD | NEW |