diff options
| -rw-r--r-- | cmd/lulu/cost.go | 2 | ||||
| -rw-r--r-- | cmd/lulu/job.go | 2 | ||||
| -rw-r--r-- | cmd/lulu/jobs.go | 2 | ||||
| -rw-r--r-- | cost_test.go | 22 | ||||
| -rw-r--r-- | lulu.go | 66 | ||||
| -rw-r--r-- | print.go | 2 | ||||
| -rw-r--r-- | print_test.go | 74 | ||||
| -rw-r--r-- | testdata/costreq.json (renamed from testdata/printjobcostreq.json) | 0 | ||||
| -rw-r--r-- | testdata/costresp.json (renamed from testdata/printjobcostresp.json) | 0 | ||||
| -rw-r--r-- | testdata/jobsresp.json (renamed from testdata/getprintjobsresp.json) | 0 |
10 files changed, 121 insertions, 49 deletions
diff --git a/cmd/lulu/cost.go b/cmd/lulu/cost.go index 66e1cb5..1826a5c 100644 --- a/cmd/lulu/cost.go +++ b/cmd/lulu/cost.go @@ -37,7 +37,7 @@ func (cmd *CostCmd) Run(cli *kong.Kong, clnt *lulu.Client) error { for i := range cmd.Items { items[i] = cmd.Items[i].PrintJobCostLineItem } - cost, addrVal, err := clnt.PrintJobCost(items, cmd.ShippingAddress.Addr(), cmd.Ship) + cost, addrVal, err := clnt.Cost(items, cmd.ShippingAddress.Addr(), cmd.Ship) if err != nil { return err } diff --git a/cmd/lulu/job.go b/cmd/lulu/job.go index 49948f0..e58ec19 100644 --- a/cmd/lulu/job.go +++ b/cmd/lulu/job.go @@ -14,7 +14,7 @@ type JobCmd struct { } func (cmd JobCmd) Run(clnt *lulu.Client) error { - job, err := clnt.GetPrintJob(cmd.Id) + job, err := clnt.Job(cmd.Id) if err != nil { return err } diff --git a/cmd/lulu/jobs.go b/cmd/lulu/jobs.go index f56c3e0..19deb35 100644 --- a/cmd/lulu/jobs.go +++ b/cmd/lulu/jobs.go @@ -19,7 +19,7 @@ type JobsCmd struct { } func (cmd JobsCmd) Run(clnt *lulu.Client) error { - jobs, err := clnt.GetPrintJobs(cmd.queries()...) + jobs, err := clnt.Jobs(cmd.queries()...) if err != nil { return err } diff --git a/cost_test.go b/cost_test.go index 446440d..c2f18ec 100644 --- a/cost_test.go +++ b/cost_test.go @@ -10,14 +10,14 @@ import ( ) var ( - //go:embed testdata/printjobcostreq.json - printJobCostReqJson string + //go:embed testdata/costreq.json + costReqJson string - //go:embed testdata/printjobcostresp.json - printJobCostRespJson string + //go:embed testdata/costresp.json + costRespJson string ) -var printJobCostReqSample = printJobCostReq{ +var costReqSample = printJobCostReq{ []PrintJobCostLineItem{ { 32, @@ -129,16 +129,16 @@ var printJobCostRespSample = printJobCostResp{ } func TestMarshalPrintJobCostReq(t *testing.T) { - requireMarshalJsonEq(t, printJobCostReqJson, printJobCostReqSample) + requireMarshalJsonEq(t, costReqJson, costReqSample) } func TestUnmarshalPrintJobCostResp(t *testing.T) { - requireUnmarshalJsonEq(t, printJobCostRespSample, printJobCostRespJson) + requireUnmarshalJsonEq(t, printJobCostRespSample, costRespJson) } -func TestPrintJobCost(t *testing.T) { +func TestCost(t *testing.T) { c := newClient(t) - items := printJobCostReqSample.LineItems + items := costReqSample.LineItems addr := ShippingAddress{ City: "Lübeck", Country: "DE", @@ -147,8 +147,8 @@ func TestPrintJobCost(t *testing.T) { Street1: "Holstenstr. 40", Phone: MustParsePhoneNumber("844-212-0689"), } - shiplvl := printJobCostReqSample.ShipOpt - cost, av, err := c.PrintJobCost(items, addr, shiplvl) + shiplvl := costReqSample.ShipOpt + cost, av, err := c.Cost(items, addr, shiplvl) require.NoError(t, err) require.Equal(t, printJobCostRespSample.AddressValidation, av) requireCurrency(t, cost.Currency) @@ -217,11 +217,11 @@ func (c *Client) GetCoverValidation(id uint) (CoverValidation, error) { return rec, nil } -// PrintJobCost calculates the cost of a hypothetical print order without +// Cost calculates the cost of a hypothetical print order without // actually creating a print job. // // https://api.lulu.com/docs/#tag/Print-Job-Cost-Calculations/operation/Print-Job-cost-calculations_create -func (c *Client) PrintJobCost(items []PrintJobCostLineItem, addr ShippingAddress, shipOpt ShippingLevel) (PrintJobCost, ShippingAddressValidation, error) { +func (c *Client) Cost(items []PrintJobCostLineItem, addr ShippingAddress, shipOpt ShippingLevel) (PrintJobCost, ShippingAddressValidation, error) { reqAddr := printJobCostReqShipAddr{ City: addr.City, Country: addr.Country, @@ -240,17 +240,17 @@ func (c *Client) PrintJobCost(items []PrintJobCostLineItem, addr ShippingAddress return resp.cost(), resp.AddressValidation, nil } -// GetPrintJobs retrieves a list of all print jobs that have been -// created, filtered by a set of optional query parameters. +// Jobs retrieves a list of all print jobs that have been created, +// filtered by a set of optional query parameters. // // https://api.lulu.com/docs/#tag/Print-Jobs/operation/Print-Jobs_list -func (c *Client) GetPrintJobs(queries ...PrintJobQuery) ([]PrintJob, error) { +func (c *Client) Jobs(queries ...PrintJobQuery) ([]PrintJob, error) { var q printJobQueries q.apply(queries...) qvals := q.vals() verify := func(v any) error { - resp := v.(*getPrintJobsResp) + resp := v.(*jobsResp) if int(resp.Count) != len(resp.Results) { return fmt.Errorf("count (%d) != len(results) (%d)", resp.Count, len(resp.Results)) } else if len(resp.Results) == 0 && resp.Next != "" { @@ -262,7 +262,7 @@ func (c *Client) GetPrintJobs(queries ...PrintJobQuery) ([]PrintJob, error) { var jobs []PrintJob for page := 1; ; page++ { qvals.Set("page", fmt.Sprint(page)) - var resp getPrintJobsResp + var resp jobsResp if err := c.getQueryDecodeVerify(printJobsPath, qvals, &resp, verify); err != nil { return jobs, pkgErr(err) } @@ -275,10 +275,10 @@ func (c *Client) GetPrintJobs(queries ...PrintJobQuery) ([]PrintJob, error) { } } -// GetPrintJob retrieves the print job with the given ID. +// Job retrieves the print job with the given ID. // // https://api.lulu.com/docs/#tag/Print-Jobs/operation/Print-Jobs_read -func (c *Client) GetPrintJob(id uint64) (PrintJob, error) { +func (c *Client) Job(id uint64) (PrintJob, error) { var job PrintJob path, err := url.JoinPath(printJobsPath, fmt.Sprint(id)) if err != nil { @@ -361,6 +361,25 @@ func verifyProductionDelay(delay time.Duration) error { return nil } +// Cancel cancels the print job with the given ID. +// +// https://api.lulu.com/docs/#tag/Print-Jobs/operation/Print-Jobs_status_cancel +func (c *Client) Cancel(id uint64) error { + path, err := url.JoinPath(printJobsPath, fmt.Sprint(id), "status") + if err != nil { + return pkgErr(err) + } + req := map[string]OrderStatus{"name": OrderCanceled} + var status PrintJobStatus + if err := c.putDecode(path, req, &status); err != nil { + return pkgErr(err) + } + if status.Status != OrderCanceled { + return pkgErr(fmt.Errorf("cancel job %d: expected %s, got %s", id, OrderCanceled, status.Status)) + } + return nil +} + // getDecode sends a GET request and unmarshals the response. func (c *Client) getDecode(path string, v any) error { verify := func(v any) error { return nil } @@ -421,6 +440,35 @@ func (c *Client) post(path string, payload any) (*http.Response, error) { return c.c.Post(url, "application/json", bytes.NewBuffer(body)) } +// putDecode sends a PUT request and unmarshals the response. +func (c *Client) putDecode(path string, payload any, v any) error { + body, err := json.Marshal(payload) + if err != nil { + return errEncReq{payload, path, err} + } + url, err := url.JoinPath(ApiUrl, path) + if err != nil { + return err + } + + debugf("PUT %s request: `%s`\n", url, body) + + req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(body)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + resp, err := c.c.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return errRespStatus{resp} + } + return decodeResponse(resp, v) +} + func decodeResponse(resp *http.Response, v any) error { body, err := io.ReadAll(resp.Body) if err != nil { @@ -70,7 +70,7 @@ type Reprintable struct { Title string `json:"title"` } -type getPrintJobsResp struct { +type jobsResp struct { Count uint `json:"count"` Next string `json:"next"` Prev string `json:"previous"` diff --git a/print_test.go b/print_test.go index b5d87f4..79381a1 100644 --- a/print_test.go +++ b/print_test.go @@ -9,8 +9,8 @@ import ( "github.com/stretchr/testify/require" ) -//go:embed testdata/getprintjobsresp.json -var getPrintJobsRespJson string +//go:embed testdata/jobsresp.json +var jobsRespJson string var printJobSample = PrintJob{ Contact: MustParseEmailAddress("test@test.com"), @@ -85,23 +85,47 @@ var printJobSample = PrintJob{ }, } -func TestUnmarshalGetPrintJobsResp(t *testing.T) { - want := getPrintJobsResp{ +func TestUnmarshaljobsResp(t *testing.T) { + want := jobsResp{ Count: 1, Next: "https://api.lulu.com/resources/?page=1&page_size=1", Prev: "https://api.lulu.com/resources/?page=1&page_size=1", Results: []PrintJob{printJobSample}, } - requireUnmarshalJsonEq(t, want, getPrintJobsRespJson) + requireUnmarshalJsonEq(t, want, jobsRespJson) } -func TestGetPrintJobs(t *testing.T) { +func TestJobs(t *testing.T) { t.Fail() // TODO: create a few print jobs and retrieve them c := newClient(t) - _, err := c.GetPrintJobs() + _, err := c.Jobs() require.NoError(t, err) } +func TestJob(t *testing.T) { + contact := MustParseEmailAddress("test@test.com") + jobEid := "demo-time" + productionDelay := 120 * time.Minute + addr := shipAddrSample + shipOpt := Mail + items := []Printable{printableSample} + + c := newClient(t) + job1, err := c.Print(contact, jobEid, productionDelay, addr, shipOpt, items) + require.NoError(t, err) + require.NotZero(t, job1.Id) + + job2, err := c.Job(job1.Id) + require.NoError(t, err) + + // Ignore timestamp because job gets marked as 'modified' between + // creation and retrieval time even if it hasn't actually + // changed. + job2.Modified = job1.Modified + + require.Equal(t, job1, job2) +} + //go:embed testdata/printreq.json var printReqJson string @@ -203,7 +227,7 @@ func TestReprint(t *testing.T) { // Wait for it to be assigned a printable_id tpoll(t, func() bool { - job1, err = c.GetPrintJob(id1) + job1, err = c.Job(id1) require.NoError(t, err) require.Len(t, job1.LineItems, 1) return job1.LineItems[0].Status.Status != ItemCreated @@ -231,30 +255,30 @@ func TestReprint(t *testing.T) { require.Equal(t, item1.Mfg, item2.Mfg) } -func TestGetPrintJob(t *testing.T) { +func TestCancel(t *testing.T) { + // Print + c := newClient(t) contact := MustParseEmailAddress("test@test.com") - jobEid := "demo-time" + jobEid := "cancel-test" productionDelay := 120 * time.Minute addr := shipAddrSample shipOpt := Mail - items := []Printable{printableSample} - - c := newClient(t) - job1, err := c.Print(contact, jobEid, productionDelay, addr, shipOpt, items) + item := printableSample + job, err := c.Print(contact, jobEid, productionDelay, addr, shipOpt, []Printable{item}) require.NoError(t, err) - require.NotZero(t, job1.Id) + id := job.Id + require.NotZero(t, id) - job2, err := c.GetPrintJob(job1.Id) + // Job exists + _, err = c.Job(id) require.NoError(t, err) - // Ignore timestamp because job gets marked as 'modified' between - // creation and retrieval time even if it hasn't actually - // changed. - job2.Modified = job1.Modified - - require.Equal(t, job1, job2) -} + // Cancel + err = c.Cancel(id) + require.NoError(t, err) -func TestCancel(t *testing.T) { - t.Fail() // TODO + // Job canceled + job, err = c.Job(id) + require.NoError(t, err) + require.Equal(t, OrderCanceled, job.Status.Status) } diff --git a/testdata/printjobcostreq.json b/testdata/costreq.json index d521f77..d521f77 100644 --- a/testdata/printjobcostreq.json +++ b/testdata/costreq.json diff --git a/testdata/printjobcostresp.json b/testdata/costresp.json index f633183..f633183 100644 --- a/testdata/printjobcostresp.json +++ b/testdata/costresp.json diff --git a/testdata/getprintjobsresp.json b/testdata/jobsresp.json index 3f43d2c..3f43d2c 100644 --- a/testdata/getprintjobsresp.json +++ b/testdata/jobsresp.json |