From e8843d8862cecd37f601f9d0f7d287be4b119180 Mon Sep 17 00:00:00 2001 From: Antoine Date: Tue, 9 Jul 2019 14:39:15 +0900 Subject: [PATCH] add support for process management --- README.md | 2 +- app.go | 78 ++++++++++++++++++++++++++++- process.go | 58 ++++++++++++++++++++++ process_test.go | 128 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 264 insertions(+), 2 deletions(-) create mode 100644 process.go create mode 100644 process_test.go diff --git a/README.md b/README.md index f0ef7ac..8a8af89 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ to access [kintone][] with its official REST API ([en][APIen], [ja][APIja]). ## Version -0.1.1 +0.1.2 ## License diff --git a/app.go b/app.go index 87c8a62..6fa1fa0 100644 --- a/app.go +++ b/app.go @@ -25,7 +25,7 @@ import ( const ( NAME = "kintone-go-SDK" - VERSION = "0.1.1" + VERSION = "0.1.2" DEFAULT_TIMEOUT = time.Second * 600 // Default value for App.Timeout ) @@ -390,6 +390,52 @@ func (app *App) GetAllRecords(fields []string) ([]*Record, error) { } } +func isAllowedLang(allowedLangs []string, lang string) bool { + for _, allowedLang := range allowedLangs { + if lang == allowedLang { + return true + } + } + return false +} + +// GetProcess retrieves the process management settings +// This method can only be used when App is initialized with password authentication +// lang must be one of default, en, zh, ja, user +func (app *App) GetProcess(lang string) (process *Process, err error) { + type request_body struct { + App uint64 `json:"app,string"` + lang string `json:"lang,string"` + } + if app.User == "" || app.Password == "" { + err = errors.New("This API only supports password authentication") + return + } + allowedLangs := []string{"default", "en", "zh", "ja", "user"} + if !isAllowedLang(allowedLangs, lang) { + err = errors.New("Illegal language provided") + return + } + data, _ := json.Marshal(request_body{app.AppId, lang}) + req, err := app.newRequest("GET", "app/status", bytes.NewReader(data)) + if err != nil { + return + } + resp, err := app.do(req) + if err != nil { + return + } + body, err := parseResponse(resp) + if err != nil { + return + } + process, err = DecodeProcess(body) + if err != nil { + err = ErrInvalidResponse + } + return +} + // FileData stores downloaded file data. type FileData struct { ContentType string // MIME type of the contents. @@ -715,6 +761,36 @@ func (app *App) UpdateRecordsByKey(recs []*Record, ignoreRevision bool, keyField return err } +// UpdateRecordStatus updates the Status of a record +func (app *App) UpdateRecordStatus(rec *Record, action *ProcessAction, assignee *Entity, ignoreRevision bool) (err error) { + type request_body struct { + App uint64 `json:"app,string"` + Id uint64 `json:"id,string"` + Revision int64 `json:"revision,string"` + Action string `json:"action"` + Assignee string `json:"assignee,omitempty"` + } + rev := rec.Revision() + if ignoreRevision { + rev = -1 + } + var code string + if assignee != nil { + code = assignee.Code + } + data, _ := json.Marshal(request_body{app.AppId, rec.id, rev, action.Name, code}) + req, err := app.newRequest("PUT", "record/status", bytes.NewReader(data)) + if err != nil { + return + } + resp, err := app.do(req) + if err != nil { + return + } + _, err = parseResponse(resp) + return +} + // DeleteRecords deletes multiple records. // // Up to 100 records can be deleted at once. diff --git a/process.go b/process.go new file mode 100644 index 0000000..3ba27d1 --- /dev/null +++ b/process.go @@ -0,0 +1,58 @@ +// (C) 2014 Cybozu. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package kintone + +import ( + "encoding/json" +) + +// Process represents the process management settings for an application +type Process struct { + Enable bool `json:"enable"` + States map[string](*ProcessState) `json:"states"` + Actions []*ProcessAction `json:"actions"` + Revision string `json:"revision"` +} + +// ProcessState represents a process management status +type ProcessState struct { + Name string `json:"name"` + Index string `json:"index"` + Assignee *ProcessAssignee `json:"assignee"` +} + +// ProcessAction representes a process management action +type ProcessAction struct { + Name string `json:"name"` + From string `json:"from"` + To string `json:"to"` + FilterCond string `json:"filterCond"` +} + +// ProcessAssignee represents a ProcessState assignee +type ProcessAssignee struct { + Type string `json:type` + Entities []*ProcessEntity `json:entities` +} + +// ProcessEntity represents a process assignee entity +type ProcessEntity struct { + Entity *Entity `json:entity` + IncludeSubs bool `json:includeSubs` +} + +// Entity is the concrete representation of a process entity +type Entity struct { + Type string `json:type` + Code string `json:code` +} + +func DecodeProcess(b []byte) (p *Process, err error) { + err = json.Unmarshal(b, &p) + if err != nil { + return + } + return +} diff --git a/process_test.go b/process_test.go new file mode 100644 index 0000000..cdcb2a4 --- /dev/null +++ b/process_test.go @@ -0,0 +1,128 @@ +// (C) 2014 Cybozu. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package kintone + +import ( + "testing" +) + +func TestDecodeProcess(t *testing.T) { + t.Parallel() + j := []byte(` + { + "enable": true, + "states": { + "Not started": { + "name": "Not started", + "index": "0", + "assignee": { + "type": "ONE", + "entities": [ + ] + } + }, + "In progress": { + "name": "In progress", + "index": "1", + "assignee": { + "type": "ALL", + "entities": [ + { + "entity": { + "type": "USER", + "code": "user1" + }, + "includeSubs": false + }, + { + "entity": { + "type": "FIELD_ENTITY", + "code": "creator" + }, + "includeSubs": false + }, + { + "entity": { + "type": "CUSTOM_FIELD", + "code": "Boss" + }, + "includeSubs": false + } + ] + } + }, + "Completed": { + "name": "Completed", + "index": "2", + "assignee": { + "type": "ONE", + "entities": [ + ] + } + } + }, + "actions": [ + { + "name": "Start", + "from": "Not started", + "to": "In progress", + "filterCond": "Record_number = \"1\"" + }, + { + "name": "Complete", + "from": "In progress", + "to": "Completed", + "filterCond": "" + } + ], + "revision": "3" + }`) + process, err := DecodeProcess(j) + if err != nil { + t.Fatal(err) + } + if !process.Enable { + t.Errorf("Expected enabled, got %v", process.Enable) + } + if len(process.States) != 3 { + t.Errorf("Expected 3 states, got %v", len(process.States)) + } + if len(process.Actions) != 2 { + t.Errorf("Expected 2 actions, got %v", len(process.Actions)) + } + if process.Revision != "3" { + t.Errorf("Expected revision to be 3, got %v", process.Revision) + } + notStartedProcess := process.States["Not started"] + if notStartedProcess.Name != "Not started" { + t.Errorf("Expected status name to be \"Not started\", got \"%v\"", notStartedProcess.Name) + } + if notStartedProcess.Index != "0" { + t.Errorf("Expected status index to be 0, got %v", notStartedProcess.Index) + } + if notStartedProcess.Assignee.Type != "ONE" { + t.Errorf("Expected assignee type to be \"ONE\", got \"%v\"", notStartedProcess.Assignee.Type) + } + inProgressProcess := process.States["In progress"] + if len(inProgressProcess.Assignee.Entities) != 3 { + t.Errorf("Expected 0 assignees, got %v", len(inProgressProcess.Assignee.Entities)) + } + if inProgressProcess.Assignee.Entities[0].Entity.Code != "user1" { + t.Errorf("Expected entity to be named \"user1\", got \"%v\"", inProgressProcess.Assignee.Entities[0].Entity.Code) + } + if inProgressProcess.Assignee.Entities[0].IncludeSubs { + t.Errorf("Expected entity to not include subs, got %v", inProgressProcess.Assignee.Entities[0].IncludeSubs) + } + completeAction := process.Actions[1] + if completeAction.Name != "Complete" { + t.Errorf("Expected action name to be \"Complete\", got \"%v\"", completeAction.Name) + } + if completeAction.From != "In progress" { + t.Errorf("Expected previous status to be \"In progress\", got \"%v\"", completeAction.From) + } + if completeAction.To != "Completed" { + t.Errorf("Expected next status to be \"Completed\", got \"%v\"", completeAction.To) + } +}