diff --git a/cmd/conf/cfg.toml b/cmd/conf/cfg.toml new file mode 100644 index 0000000..0c4ed1c --- /dev/null +++ b/cmd/conf/cfg.toml @@ -0,0 +1,5 @@ + +[logger] +conf = "./conf/log.yml" +path = "./log/" +app_name = "asana" diff --git a/cmd/conf/log.yml b/cmd/conf/log.yml new file mode 100644 index 0000000..5355c34 --- /dev/null +++ b/cmd/conf/log.yml @@ -0,0 +1,32 @@ + +level: "info" +development: false +disableCaller: false +disableStacktrace: false +sampling: +encoding: "console" + +# encoder +encoderConfig: + messageKey: "message" + levelKey: "level" + timeKey: "time" + nameKey: "logger" + callerKey: "caller" + stacktraceKey: "stacktrace" + lineEnding: "" + # levelEncoder: "capitalColor" + timeEncoder: "iso8601" + durationEncoder: "seconds" + callerEncoder: "short" + nameEncoder: "" + +outputPaths: + # - "../logs/yuanex.log" + # - "./logs/yuanex.log" + - "stderr" +errorOutputPaths: + # - "../logs/yuanex.error" + # - "./logs/yuanex.error" + - "stderr" +initialFields: diff --git a/cmd/log/asana.error b/cmd/log/asana.error new file mode 100644 index 0000000..e69de29 diff --git a/cmd/log/asana.log b/cmd/log/asana.log new file mode 100644 index 0000000..7a51324 --- /dev/null +++ b/cmd/log/asana.log @@ -0,0 +1,480 @@ +2021-08-10T18:31:29.360+0800 cmd/tasks.go:13 started ... +2021-08-10T18:31:29.360+0800 util/http.go:117 request url: https://app.asana.com/api/1.0/tasks +2021-08-10T18:31:30.541+0800 task/task.go:64 [�]new task ID: +2021-08-10T18:31:30.544+0800 cmd/tasks.go:36 succeeded, task gid: +2021-08-10T18:31:30.550+0800 cmd/tasks.go:39 completed ... +2021-08-10T18:40:09.261+0800 cmd/tasks.go:13 started ... +2021-08-10T18:40:09.261+0800 util/http.go:117 request url: https://app.asana.com/api/1.0/tasks +2021-08-10T18:40:10.619+0800 task/task.go:68 response status: 400 +2021-08-10T18:40:10.620+0800 task/task.go:70 unexpected response +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/module/task.(*Request).Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/task/task.go:70 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:35 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-10T18:40:10.623+0800 cmd/tasks.go:37 failed to create new task: unexpected response +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:37 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-10T18:40:10.623+0800 cmd/tasks.go:42 completed ... +2021-08-10T18:41:29.865+0800 cmd/tasks.go:13 started ... +2021-08-10T18:41:29.866+0800 task/task.go:60 request: {"resource_subtype":"default_task","assignee":"1199521781039350","name":"Tue Aug 10 10:41:29 2021 Testing","completed":false,"due_on":"2021-08-17","linked":false,"notes":"Testing - Tue, 10 Aug 2021 10:41:29 UTC","start_on":"2021-08-10","custom_fields":{"1199521775380609":"1199521775380611","1200366443430274":"1200366443431311","1200750482997339":"20210810131701","1200753569394602":"1200753569396679"},"projects":["1200750482997336"],"workspace":"916657163525497"} +2021-08-10T18:41:29.867+0800 util/http.go:117 request url: https://app.asana.com/api/1.0/tasks +2021-08-10T18:41:31.580+0800 util/http.go:142 response: {"errors":[{"message":"You should specify one of workspace, parent, projects","help":"For more information on API status codes and how to handle them, read the docs on errors: https://asana.com/developers/documentation/getting-started/errors"}]} +2021-08-10T18:41:31.582+0800 task/task.go:70 response status: 400 +2021-08-10T18:41:31.593+0800 task/task.go:72 unexpected response +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/module/task.(*Request).Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/task/task.go:72 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:35 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-10T18:41:31.596+0800 cmd/tasks.go:37 failed to create new task: unexpected response +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:37 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-10T18:41:31.598+0800 cmd/tasks.go:42 completed ... +2021-08-10T18:45:14.701+0800 cmd/tasks.go:13 started ... +2021-08-10T18:45:14.702+0800 task/task.go:70 request: {"data":{"resource_subtype":"default_task","assignee":"1199521781039350","name":"Tue Aug 10 10:45:14 2021 Testing","completed":false,"due_on":"2021-08-17","linked":false,"notes":"Testing - Tue, 10 Aug 2021 10:45:14 UTC","start_on":"2021-08-10","custom_fields":{"1199521775380609":"1199521775380611","1200366443430274":"1200366443431311","1200750482997339":"20210810131701","1200753569394602":"1200753569396679"},"projects":["1200750482997336"],"workspace":"916657163525497"}} +2021-08-10T18:45:14.704+0800 util/http.go:117 request url: https://app.asana.com/api/1.0/tasks +2021-08-10T18:45:22.727+0800 util/http.go:142 response: {"data":{"gid":"1200757350074250","projects":[{"gid":"1200750482997336","resource_type":"project","name":"Development Project for Tickets"}],"resource_type":"task","created_at":"2021-08-10T10:45:20.542Z","modified_at":"2021-08-10T10:45:20.542Z","name":"Tue Aug 10 10:45:14 2021 Testing","notes":"Testing - Tue, 10 Aug 2021 10:45:14 UTC","assignee":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"completed":false,"assignee_status":"inbox","completed_at":null,"due_on":"2021-08-17","due_at":null,"resource_subtype":"default_task","start_on":"2021-08-10","start_at":null,"tags":[],"workspace":{"gid":"916657163525497","resource_type":"workspace","name":"yuansfer.com"},"num_hearts":0,"num_likes":0,"permalink_url":"https://app.asana.com/0/1200750482997336/1200757350074250","followers":[{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"}],"parent":null,"hearted":false,"hearts":[],"assignee_section":{"gid":"1200524821166545","resource_type":"section","name":"Recently assigned"},"liked":false,"likes":[],"memberships":[{"project":{"gid":"1200750482997336","resource_type":"project","name":"Development Project for Tickets"},"section":{"gid":"1200753569417613","resource_type":"section","name":"Backlog"}}],"custom_fields":[{"gid":"1200366443430274","resource_type":"custom_field","resource_subtype":"enum","type":"enum","name":"Ticket Type","enabled":true,"enum_value":{"gid":"1200366443431311","resource_type":"enum_option","enabled":true,"name":"Merchant Profile Updates","color":"green"},"display_value":"Merchant Profile Updates","enum_options":[{"gid":"1200366443431311","resource_type":"enum_option","enabled":true,"name":"Merchant Profile Updates","color":"green"},{"gid":"1200366443431316","resource_type":"enum_option","enabled":true,"name":"Transaction Errors","color":"red"},{"gid":"1200366443431388","resource_type":"enum_option","enabled":true,"name":"Product Requests","color":"orange"},{"gid":"1200366443431401","resource_type":"enum_option","enabled":true,"name":"Declined Merchant/Disabled Account","color":"yellow-orange"},{"gid":"1200366443432434","resource_type":"enum_option","enabled":true,"name":"Bug Fixes","color":"yellow"},{"gid":"1200366464813839","resource_type":"enum_option","enabled":true,"name":"Internal Development Project","color":"yellow-green"},{"gid":"1200680513739265","resource_type":"enum_option","enabled":true,"name":"Feedback","color":"blue-green"}],"created_by":{"gid":"1200057682745929","resource_type":"user","name":"Jeremy Jones"}},{"gid":"1199521775380609","resource_type":"custom_field","created_by":null,"resource_subtype":"enum","type":"enum","name":"Priority","enabled":true,"enum_value":{"gid":"1199521775380611","resource_type":"enum_option","enabled":true,"name":"Medium","color":"orange"},"display_value":"Medium","enum_options":[{"gid":"1199521775380610","resource_type":"enum_option","enabled":true,"name":"High","color":"red"},{"gid":"1199521775380611","resource_type":"enum_option","enabled":true,"name":"Medium","color":"orange"},{"gid":"1199521775380612","resource_type":"enum_option","enabled":true,"name":"Low","color":"green"}]},{"gid":"1200107390884071","resource_type":"custom_field","created_by":null,"resource_subtype":"enum","type":"enum","name":"Product stage","enabled":true,"enum_value":null,"display_value":null,"enum_options":[{"gid":"1200107390884072","resource_type":"enum_option","enabled":true,"name":"Spec needed","color":"none"},{"gid":"1200107390884073","resource_type":"enum_option","enabled":true,"name":"Design ready","color":"none"},{"gid":"1200107390884074","resource_type":"enum_option","enabled":true,"name":"Eng ready","color":"none"},{"gid":"1200107390884075","resource_type":"enum_option","enabled":true,"name":"QA ready","color":"none"},{"gid":"1200107390884076","resource_type":"enum_option","enabled":true,"name":"Marketing ready","color":"none"}]},{"gid":"1200128693528351","resource_type":"custom_field","resource_subtype":"enum","type":"enum","name":"Status","enabled":true,"enum_value":null,"display_value":null,"created_by":{"gid":"1199874732832801","resource_type":"user","name":"Shawn Zheng"},"enum_options":[{"gid":"1200128693528355","resource_type":"enum_option","enabled":true,"name":"Completed","color":"green"},{"gid":"1200128693529382","resource_type":"enum_option","enabled":true,"name":"In Progress","color":"red"},{"gid":"1200163946180464","resource_type":"enum_option","enabled":true,"name":"Not Started","color":"orange"}]},{"gid":"1200107390884078","resource_type":"custom_field","created_by":null,"resource_subtype":"number","type":"number","name":"Cost","enabled":true,"precision":0,"number_value":null,"display_value":null},{"gid":"1200750482997339","resource_type":"custom_field","created_by":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"resource_subtype":"text","type":"text","name":"Ticket ID","enabled":true,"text_value":"20210810131701","display_value":"20210810131701"},{"gid":"1200753569394602","resource_type":"custom_field","created_by":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"resource_subtype":"enum","type":"enum","name":"Month","enabled":true,"enum_value":{"gid":"1200753569396679","resource_type":"enum_option","enabled":true,"name":"August","color":"yellow-orange"},"display_value":"August","enum_options":[{"gid":"1200753569394609","resource_type":"enum_option","enabled":true,"name":"May","color":"green"},{"gid":"1200753569394617","resource_type":"enum_option","enabled":true,"name":"June","color":"red"},{"gid":"1200753569395650","resource_type":"enum_option","enabled":true,"name":"July","color":"orange"},{"gid":"1200753569396679","resource_type":"enum_option","enabled":true,"name":"August","color":"yellow-orange"}]}]}} +2021-08-10T18:45:22.732+0800 task/task.go:80 response status: 201 +2021-08-10T18:45:22.745+0800 task/task.go:92 [�]new task ID: +2021-08-10T18:45:22.746+0800 cmd/tasks.go:39 succeeded, task gid: +2021-08-10T18:45:22.747+0800 cmd/tasks.go:42 completed ... +2021-08-11T05:44:42.850+0800 cmd/tasks.go:26 started ... +2021-08-11T05:44:42.851+0800 cmd/tasks.go:35 ticket No.: � +2021-08-11T05:44:42.851+0800 task/task.go:82 request: {"data":{"resource_subtype":"default_task","assignee":"1199521781039350","name":"#�-Tue Aug 10 21:44:42 2021-Merchant Profile Updates","completed":false,"due_on":"2021-08-18","linked":false,"notes":"Testing - Tue, 10 Aug 2021 21:44:42 UTC","start_on":"2021-08-11","custom_fields":{"1199521775380609":"1199521775380611","1200366443430274":"1200366443431311","1200750482997339":"�","1200753569394602":"1200753569396679"},"projects":["1200750482997336"],"workspace":"916657163525497"}} +2021-08-11T05:44:42.851+0800 util/http.go:117 request url: https://app.asana.com/api/1.0/tasks +2021-08-11T05:44:46.627+0800 util/http.go:142 response: {"data":{"gid":"1200762320061738","projects":[{"gid":"1200750482997336","resource_type":"project","name":"Development Project for Tickets"}],"resource_type":"task","created_at":"2021-08-10T21:44:45.977Z","modified_at":"2021-08-10T21:44:45.977Z","name":"#�-Tue Aug 10 21:44:42 2021-Merchant Profile Updates","notes":"Testing - Tue, 10 Aug 2021 21:44:42 UTC","assignee":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"completed":false,"assignee_status":"inbox","completed_at":null,"due_on":"2021-08-18","due_at":null,"resource_subtype":"default_task","start_on":"2021-08-11","start_at":null,"tags":[],"workspace":{"gid":"916657163525497","resource_type":"workspace","name":"yuansfer.com"},"num_hearts":0,"num_likes":0,"permalink_url":"https://app.asana.com/0/1200750482997336/1200762320061738","followers":[{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"}],"parent":null,"hearted":false,"hearts":[],"assignee_section":{"gid":"1200524821166545","resource_type":"section","name":"Recently assigned"},"liked":false,"likes":[],"memberships":[{"project":{"gid":"1200750482997336","resource_type":"project","name":"Development Project for Tickets"},"section":{"gid":"1200753569417613","resource_type":"section","name":"Backlog"}}],"custom_fields":[{"gid":"1200366443430274","resource_type":"custom_field","resource_subtype":"enum","type":"enum","name":"Ticket Type","enabled":true,"enum_value":{"gid":"1200366443431311","resource_type":"enum_option","enabled":true,"name":"Merchant Profile Updates","color":"green"},"display_value":"Merchant Profile Updates","created_by":{"gid":"1200057682745929","resource_type":"user","name":"Jeremy Jones"},"enum_options":[{"gid":"1200366443431311","resource_type":"enum_option","enabled":true,"name":"Merchant Profile Updates","color":"green"},{"gid":"1200366443431316","resource_type":"enum_option","enabled":true,"name":"Transaction Errors","color":"red"},{"gid":"1200366443431388","resource_type":"enum_option","enabled":true,"name":"Product Requests","color":"orange"},{"gid":"1200366443431401","resource_type":"enum_option","enabled":true,"name":"Declined Merchant/Disabled Account","color":"yellow-orange"},{"gid":"1200366443432434","resource_type":"enum_option","enabled":true,"name":"Bug Fixes","color":"yellow"},{"gid":"1200366464813839","resource_type":"enum_option","enabled":true,"name":"Internal Development Project","color":"yellow-green"},{"gid":"1200680513739265","resource_type":"enum_option","enabled":true,"name":"Feedback","color":"blue-green"},{"gid":"1200760425076272","resource_type":"enum_option","enabled":true,"name":"Others","color":"cool-gray"}]},{"gid":"1199521775380609","resource_type":"custom_field","created_by":null,"resource_subtype":"enum","type":"enum","name":"Priority","enabled":true,"enum_value":{"gid":"1199521775380611","resource_type":"enum_option","enabled":true,"name":"Medium","color":"orange"},"display_value":"Medium","enum_options":[{"gid":"1199521775380610","resource_type":"enum_option","enabled":true,"name":"High","color":"red"},{"gid":"1199521775380611","resource_type":"enum_option","enabled":true,"name":"Medium","color":"orange"},{"gid":"1199521775380612","resource_type":"enum_option","enabled":true,"name":"Low","color":"green"}]},{"gid":"1200107390884071","resource_type":"custom_field","created_by":null,"resource_subtype":"enum","type":"enum","name":"Product stage","enabled":true,"enum_value":null,"display_value":null,"enum_options":[{"gid":"1200107390884072","resource_type":"enum_option","enabled":true,"name":"Spec needed","color":"none"},{"gid":"1200107390884073","resource_type":"enum_option","enabled":true,"name":"Design ready","color":"none"},{"gid":"1200107390884074","resource_type":"enum_option","enabled":true,"name":"Eng ready","color":"none"},{"gid":"1200107390884075","resource_type":"enum_option","enabled":true,"name":"QA ready","color":"none"},{"gid":"1200107390884076","resource_type":"enum_option","enabled":true,"name":"Marketing ready","color":"none"}]},{"gid":"1200128693528351","resource_type":"custom_field","resource_subtype":"enum","type":"enum","name":"Status","enabled":true,"enum_value":null,"display_value":null,"created_by":{"gid":"1199874732832801","resource_type":"user","name":"Shawn Zheng"},"enum_options":[{"gid":"1200128693528355","resource_type":"enum_option","enabled":true,"name":"Completed","color":"green"},{"gid":"1200128693529382","resource_type":"enum_option","enabled":true,"name":"In Progress","color":"red"},{"gid":"1200163946180464","resource_type":"enum_option","enabled":true,"name":"Not Started","color":"orange"}]},{"gid":"1200107390884078","resource_type":"custom_field","created_by":null,"resource_subtype":"number","type":"number","name":"Cost","enabled":true,"precision":0,"number_value":null,"display_value":null},{"gid":"1200750482997339","resource_type":"custom_field","created_by":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"resource_subtype":"text","type":"text","name":"Ticket ID","enabled":true,"text_value":"�","display_value":"�"},{"gid":"1200753569394602","resource_type":"custom_field","created_by":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"resource_subtype":"enum","type":"enum","name":"Month","enabled":true,"enum_value":{"gid":"1200753569396679","resource_type":"enum_option","enabled":true,"name":"August","color":"yellow-orange"},"display_value":"August","enum_options":[{"gid":"1200753569394609","resource_type":"enum_option","enabled":true,"name":"May","color":"green"},{"gid":"1200753569394617","resource_type":"enum_option","enabled":true,"name":"June","color":"red"},{"gid":"1200753569395650","resource_type":"enum_option","enabled":true,"name":"July","color":"orange"},{"gid":"1200753569396679","resource_type":"enum_option","enabled":true,"name":"August","color":"yellow-orange"}]}]}} +2021-08-11T05:44:46.656+0800 task/task.go:92 response status: 201 +2021-08-11T05:44:46.708+0800 task/task.go:105 [�]new task ID:1200762320061738 +2021-08-11T05:44:46.708+0800 cmd/tasks.go:58 succeeded, task gid: 1200762320061738 +2021-08-11T05:44:46.714+0800 cmd/tasks.go:28 completed ... +2021-08-11T05:50:03.261+0800 cmd/tasks.go:27 started ... +2021-08-11T05:50:03.261+0800 cmd/tasks.go:38 ticket No.: 1628632203 +2021-08-11T05:50:03.263+0800 task/task.go:82 request: {"data":{"resource_subtype":"default_task","assignee":"1199521781039350","name":"#1628632203-Tue Aug 10 21:50:03 2021-Merchant Profile Updates","completed":false,"due_on":"2021-08-18","linked":false,"notes":"Testing - Tue, 10 Aug 2021 21:50:03 UTC","start_on":"2021-08-11","custom_fields":{"1199521775380609":"1199521775380611","1200366443430274":"1200366443431311","1200750482997339":"1628632203","1200753569394602":"1200753569396679"},"projects":["1200750482997336"],"workspace":"916657163525497"}} +2021-08-11T05:50:03.266+0800 util/http.go:117 request url: https://app.asana.com/api/1.0/tasks +2021-08-11T05:50:06.961+0800 util/http.go:142 response: {"data":{"gid":"1200762462637997","projects":[{"gid":"1200750482997336","resource_type":"project","name":"Development Project for Tickets"}],"resource_type":"task","created_at":"2021-08-10T21:50:06.313Z","modified_at":"2021-08-10T21:50:06.313Z","name":"#1628632203-Tue Aug 10 21:50:03 2021-Merchant Profile Updates","notes":"Testing - Tue, 10 Aug 2021 21:50:03 UTC","assignee":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"completed":false,"assignee_status":"inbox","completed_at":null,"due_on":"2021-08-18","due_at":null,"resource_subtype":"default_task","start_on":"2021-08-11","start_at":null,"tags":[],"workspace":{"gid":"916657163525497","resource_type":"workspace","name":"yuansfer.com"},"num_hearts":0,"num_likes":0,"permalink_url":"https://app.asana.com/0/1200750482997336/1200762462637997","followers":[{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"}],"parent":null,"hearted":false,"hearts":[],"assignee_section":{"gid":"1200524821166545","resource_type":"section","name":"Recently assigned"},"liked":false,"likes":[],"memberships":[{"project":{"gid":"1200750482997336","resource_type":"project","name":"Development Project for Tickets"},"section":{"gid":"1200753569417613","resource_type":"section","name":"Backlog"}}],"custom_fields":[{"gid":"1200366443430274","resource_type":"custom_field","resource_subtype":"enum","type":"enum","name":"Ticket Type","enabled":true,"enum_value":{"gid":"1200366443431311","resource_type":"enum_option","enabled":true,"name":"Merchant Profile Updates","color":"green"},"display_value":"Merchant Profile Updates","created_by":{"gid":"1200057682745929","resource_type":"user","name":"Jeremy Jones"},"enum_options":[{"gid":"1200366443431311","resource_type":"enum_option","enabled":true,"name":"Merchant Profile Updates","color":"green"},{"gid":"1200366443431316","resource_type":"enum_option","enabled":true,"name":"Transaction Errors","color":"red"},{"gid":"1200366443431388","resource_type":"enum_option","enabled":true,"name":"Product Requests","color":"orange"},{"gid":"1200366443431401","resource_type":"enum_option","enabled":true,"name":"Declined Merchant/Disabled Account","color":"yellow-orange"},{"gid":"1200366443432434","resource_type":"enum_option","enabled":true,"name":"Bug Fixes","color":"yellow"},{"gid":"1200366464813839","resource_type":"enum_option","enabled":true,"name":"Internal Development Project","color":"yellow-green"},{"gid":"1200680513739265","resource_type":"enum_option","enabled":true,"name":"Feedback","color":"blue-green"},{"gid":"1200760425076272","resource_type":"enum_option","enabled":true,"name":"Others","color":"cool-gray"}]},{"gid":"1199521775380609","resource_type":"custom_field","created_by":null,"resource_subtype":"enum","type":"enum","name":"Priority","enabled":true,"enum_value":{"gid":"1199521775380611","resource_type":"enum_option","enabled":true,"name":"Medium","color":"orange"},"display_value":"Medium","enum_options":[{"gid":"1199521775380610","resource_type":"enum_option","enabled":true,"name":"High","color":"red"},{"gid":"1199521775380611","resource_type":"enum_option","enabled":true,"name":"Medium","color":"orange"},{"gid":"1199521775380612","resource_type":"enum_option","enabled":true,"name":"Low","color":"green"}]},{"gid":"1200107390884071","resource_type":"custom_field","created_by":null,"resource_subtype":"enum","type":"enum","name":"Product stage","enabled":true,"enum_value":null,"display_value":null,"enum_options":[{"gid":"1200107390884072","resource_type":"enum_option","enabled":true,"name":"Spec needed","color":"none"},{"gid":"1200107390884073","resource_type":"enum_option","enabled":true,"name":"Design ready","color":"none"},{"gid":"1200107390884074","resource_type":"enum_option","enabled":true,"name":"Eng ready","color":"none"},{"gid":"1200107390884075","resource_type":"enum_option","enabled":true,"name":"QA ready","color":"none"},{"gid":"1200107390884076","resource_type":"enum_option","enabled":true,"name":"Marketing ready","color":"none"}]},{"gid":"1200128693528351","resource_type":"custom_field","resource_subtype":"enum","type":"enum","name":"Status","enabled":true,"enum_value":null,"display_value":null,"created_by":{"gid":"1199874732832801","resource_type":"user","name":"Shawn Zheng"},"enum_options":[{"gid":"1200128693528355","resource_type":"enum_option","enabled":true,"name":"Completed","color":"green"},{"gid":"1200128693529382","resource_type":"enum_option","enabled":true,"name":"In Progress","color":"red"},{"gid":"1200163946180464","resource_type":"enum_option","enabled":true,"name":"Not Started","color":"orange"}]},{"gid":"1200107390884078","resource_type":"custom_field","created_by":null,"resource_subtype":"number","type":"number","name":"Cost","enabled":true,"precision":0,"number_value":null,"display_value":null},{"gid":"1200750482997339","resource_type":"custom_field","created_by":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"resource_subtype":"text","type":"text","name":"Ticket ID","enabled":true,"text_value":"1628632203","display_value":"1628632203"},{"gid":"1200753569394602","resource_type":"custom_field","created_by":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"resource_subtype":"enum","type":"enum","name":"Month","enabled":true,"enum_value":{"gid":"1200753569396679","resource_type":"enum_option","enabled":true,"name":"August","color":"yellow-orange"},"display_value":"August","enum_options":[{"gid":"1200753569394609","resource_type":"enum_option","enabled":true,"name":"May","color":"green"},{"gid":"1200753569394617","resource_type":"enum_option","enabled":true,"name":"June","color":"red"},{"gid":"1200753569395650","resource_type":"enum_option","enabled":true,"name":"July","color":"orange"},{"gid":"1200753569396679","resource_type":"enum_option","enabled":true,"name":"August","color":"yellow-orange"}]}]}} +2021-08-11T05:50:06.962+0800 task/task.go:92 response status: 201 +2021-08-11T05:50:06.972+0800 task/task.go:105 [1628632203]new task ID:1200762462637997 +2021-08-11T05:50:06.976+0800 cmd/tasks.go:61 succeeded, task gid: 1200762462637997 +2021-08-11T05:50:06.977+0800 cmd/tasks.go:31 completed ... +2021-08-11T05:50:33.051+0800 cmd/tasks.go:27 started ... +2021-08-11T05:50:33.054+0800 story/stories.go:102 request: {"data":{"text":"comment - Wed, 11 Aug 2021 05:50:33 CST","is_pinned":false}} +2021-08-11T05:50:33.058+0800 util/http.go:117 request url: https://app.asana.com/api/1.0/tasks/1200762462637997/stories +2021-08-11T05:50:34.905+0800 util/http.go:142 response: {"data":{"gid":"1200762439188269","resource_type":"story","created_at":"2021-08-10T21:50:36.058Z","target":{"gid":"1200762462637997","resource_type":"task","name":"#1628632203-Tue Aug 10 21:50:03 2021-Merchant Profile Updates","resource_subtype":"default_task"},"source":"api","is_pinned":false,"type":"comment","text":"comment - Wed, 11 Aug 2021 05:50:33 CST","is_edited":false,"resource_subtype":"comment_added","num_hearts":0,"num_likes":0,"created_by":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"is_editable":true,"hearted":false,"hearts":[],"previews":[],"liked":false,"likes":[]}} +2021-08-11T05:50:34.906+0800 story/stories.go:112 response status: 201 +2021-08-11T05:50:34.913+0800 story/stories.go:121 illegal comment result: json: cannot unmarshal bool into Go struct field Response.data.is_pinned of type string +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/module/story.Request.Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/story/stories.go:121 +main.createStory + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:72 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:29 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T05:50:34.917+0800 cmd/tasks.go:75 failed to create new comment: json: cannot unmarshal bool into Go struct field Response.data.is_pinned of type string +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +main.createStory + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:75 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:29 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T05:50:34.918+0800 cmd/tasks.go:31 completed ... +2021-08-11T05:54:16.724+0800 cmd/tasks.go:27 started ... +2021-08-11T05:54:18.320+0800 attach/attachments.go:68 failed to detect content type: EOF +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/module/attach.Request.Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:68 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:93 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T05:54:18.321+0800 cmd/tasks.go:95 failed to upload attachment: EOF +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:95 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T05:54:18.331+0800 cmd/tasks.go:31 completed ... +2021-08-11T06:00:10.100+0800 cmd/tasks.go:27 started ... +2021-08-11T06:00:13.225+0800 util/http.go:166 unexpected status: 400 +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/util.Request + G:/dev/go/git.drinkme.beer/yinghe/asana/util/http.go:166 +asana/module/attach.Request.Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:103 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:93 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T06:00:13.225+0800 cmd/tasks.go:95 failed to upload attachment: unexpected status +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:95 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T06:00:13.230+0800 cmd/tasks.go:31 completed ... +2021-08-11T06:01:45.465+0800 cmd/tasks.go:27 started ... +2021-08-11T06:01:45.467+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200762462637997/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=170f99fe80eb51cc2a28e0dee9833b0287225d0e2817bf0282e1c50c7d6b]] 0xc000006090 0 [] false app.asana.com map[] map[] map[] 0xc00000a0c8} +2021-08-11T06:01:47.139+0800 util/http.go:166 unexpected status: 400 +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/util.Request + G:/dev/go/git.drinkme.beer/yinghe/asana/util/http.go:166 +asana/module/attach.Request.Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:103 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:93 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T06:01:47.141+0800 cmd/tasks.go:95 failed to upload attachment: unexpected status +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:95 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T06:01:47.148+0800 cmd/tasks.go:31 completed ... +2021-08-11T06:31:01.534+0800 cmd/tasks.go:27 started ... +2021-08-11T06:31:01.535+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200762462637997/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=5bada70f791756c1db6957c15f9bc4222177d4d2199aec1d90a3bd328bf7]] 0xc000006090 0 [] false app.asana.com map[] map[] map[] 0xc00000a0c8} +2021-08-11T06:31:03.187+0800 util/http.go:166 unexpected status: 400 +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/util.Request + G:/dev/go/git.drinkme.beer/yinghe/asana/util/http.go:166 +asana/module/attach.Request.Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:108 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:93 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T06:31:03.188+0800 cmd/tasks.go:95 failed to upload attachment: unexpected status +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:95 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T06:31:03.193+0800 cmd/tasks.go:31 completed ... +2021-08-11T06:44:42.230+0800 cmd/tasks.go:27 started ... +2021-08-11T06:44:42.231+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200762462637997/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=b526940b1887f6ff2fcad6220ed7e982e43e00b84aa567433c2bbe9755ef]] 0xc000006090 0 [] false app.asana.com map[] map[] map[] 0xc00000a0c8} +2021-08-11T06:44:43.983+0800 util/http.go:166 unexpected status: 400 +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/util.Request + G:/dev/go/git.drinkme.beer/yinghe/asana/util/http.go:166 +asana/module/attach.Request.Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:109 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:93 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T06:44:43.985+0800 cmd/tasks.go:95 failed to upload attachment: unexpected status +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:95 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T06:44:43.989+0800 cmd/tasks.go:31 completed ... +2021-08-11T06:54:16.012+0800 cmd/tasks.go:27 started ... +2021-08-11T06:54:16.014+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200762462637997/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=45b8a6f7327632c862599ba5e8f05f28a699e1b5c3c1b7c629aaed8da832]] 0xc000006090 0 [] false app.asana.com map[] map[] map[] 0xc00000a0c8} +2021-08-11T06:54:17.104+0800 attach/attachments.go:93 content type: image/jpeg +2021-08-11T06:54:17.743+0800 util/http.go:169 response: {"errors":[{"message":"Could not interpret Content-Type as an identifier in Content-Type.","help":"For more information on API status codes and how to handle them, read the docs on errors: https://asana.com/developers/documentation/getting-started/errors"}]} +2021-08-11T06:54:17.745+0800 util/http.go:171 unexpected status: 400 +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/util.Request + G:/dev/go/git.drinkme.beer/yinghe/asana/util/http.go:171 +asana/module/attach.Request.Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:109 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:93 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T06:54:17.754+0800 cmd/tasks.go:95 failed to upload attachment: unexpected status +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:95 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T06:54:17.754+0800 cmd/tasks.go:31 completed ... +2021-08-11T06:55:52.546+0800 cmd/tasks.go:27 started ... +2021-08-11T06:55:52.548+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200762462637997/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=2d2cb063e3eb9a1117ff82cf148333ba2da5f2a101b36fd9c9c51d483259]] 0xc000006090 0 [] false app.asana.com map[] map[] map[] 0xc00000a0c8} +2021-08-11T06:55:53.694+0800 attach/attachments.go:93 content type: image/jpeg +2021-08-11T06:55:55.563+0800 util/http.go:181 response: {"data":{"gid":"1200762676545607","resource_type":"attachment","name":"WechatIMG8.jpeg","resource_subtype":"asana"}} +2021-08-11T06:55:55.564+0800 cmd/tasks.go:97 attachment id: 1200762676545607 +2021-08-11T06:55:55.570+0800 cmd/tasks.go:31 completed ... +2021-08-11T07:00:46.448+0800 cmd/tasks.go:27 started ... +2021-08-11T07:00:46.451+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200762462637997/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=27567d33c5b4e1614a4dc5c6305df405b27ba4e8642639f4d19fb1c3bd1a]] 0xc000006090 0 [] false app.asana.com map[] map[] map[] 0xc00000a0c8} +2021-08-11T07:00:49.749+0800 util/http.go:181 response: {"data":{"gid":"1200762737643119","resource_type":"attachment","name":"WechatIMG8.jpeg","resource_subtype":"asana"}} +2021-08-11T07:00:49.750+0800 cmd/tasks.go:97 attachment id: 1200762737643119 +2021-08-11T07:00:49.757+0800 cmd/tasks.go:31 completed ... +2021-08-11T07:08:05.457+0800 cmd/tasks.go:27 started ... +2021-08-11T07:08:05.460+0800 attach/attachments.go:70 failed to detect content type: invalid argument +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/module/attach.Request.Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:70 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:93 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T07:08:05.464+0800 cmd/tasks.go:95 failed to upload attachment: invalid argument +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:95 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T07:08:05.465+0800 cmd/tasks.go:31 completed ... +2021-08-11T07:09:34.589+0800 cmd/tasks.go:27 started ... +2021-08-11T07:09:35.674+0800 attach/attachments.go:70 failed to detect content type: EOF +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/module/attach.Request.Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:70 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:93 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T07:09:35.676+0800 cmd/tasks.go:95 failed to upload attachment: EOF +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:95 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T07:09:35.688+0800 cmd/tasks.go:31 completed ... +2021-08-11T07:10:03.056+0800 cmd/tasks.go:27 started ... +2021-08-11T07:10:03.058+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200762462637997/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=92993be3bf147bf6749d9c50cddfec28bc9f5e54cf1bdb98eb6fdc8cd60d]] 0xc000006090 0 [] false app.asana.com map[] map[] map[] 0xc00000a0c8} +2021-08-11T07:10:05.261+0800 util/http.go:181 response: {"data":{"gid":"1200762804306062","resource_type":"attachment","name":"beer","resource_subtype":"asana"}} +2021-08-11T07:10:05.261+0800 cmd/tasks.go:97 attachment id: 1200762804306062 +2021-08-11T07:10:05.265+0800 cmd/tasks.go:31 completed ... +2021-08-11T07:13:17.583+0800 cmd/tasks.go:27 started ... +2021-08-11T07:13:17.584+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200762462637997/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=8ca35bf11205c05ab86a9707672c5cdee67c90f425a55243371dcfbb7c02]] 0xc000006090 0 [] false app.asana.com map[] map[] map[] 0xc00000a0c8} +2021-08-11T07:13:20.638+0800 util/http.go:181 response: {"data":{"gid":"1200762709092387","resource_type":"attachment","name":"abeer.jpg","resource_subtype":"asana"}} +2021-08-11T07:13:20.640+0800 cmd/tasks.go:97 attachment id: 1200762709092387 +2021-08-11T07:13:20.645+0800 cmd/tasks.go:31 completed ... +2021-08-11T07:15:27.754+0800 cmd/tasks.go:27 started ... +2021-08-11T07:15:27.757+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200762462637997/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=a9bd48158af0807d4720841e28ed0764f35ef47d1e21ccf1557ebd638102]] 0xc000148080 0 [] false app.asana.com map[] map[] map[] 0xc000110180} +2021-08-11T07:15:30.979+0800 util/http.go:181 response: {"data":{"gid":"1200762756654257","resource_type":"attachment","name":"abeer.jpg","resource_subtype":"asana"}} +2021-08-11T07:15:30.980+0800 cmd/tasks.go:97 attachment id: 1200762756654257 +2021-08-11T07:15:30.985+0800 cmd/tasks.go:31 completed ... +2021-08-11T07:16:01.885+0800 cmd/tasks.go:27 started ... +2021-08-11T07:16:01.887+0800 cmd/tasks.go:38 ticket No.: 1628637361 +2021-08-11T07:16:01.887+0800 task/task.go:82 request: {"data":{"resource_subtype":"default_task","assignee":"1199521781039350","name":"#1628637361-Merchant Profile Updates-Tue Aug 10 23:16:01 2021","completed":false,"due_on":"2021-08-18","linked":false,"notes":"Testing - Tue, 10 Aug 2021 23:16:01 UTC","start_on":"2021-08-11","custom_fields":{"1199521775380609":"1199521775380611","1200366443430274":"1200366443431311","1200750482997339":"1628637361","1200753569394602":"1200753569396679"},"projects":["1200750482997336"],"workspace":"916657163525497"}} +2021-08-11T07:16:01.888+0800 util/http.go:117 request url: https://app.asana.com/api/1.0/tasks +2021-08-11T07:16:05.676+0800 util/http.go:142 response: {"data":{"gid":"1200762811929407","projects":[{"gid":"1200750482997336","resource_type":"project","name":"Development Project for Tickets"}],"resource_type":"task","created_at":"2021-08-10T23:16:04.993Z","modified_at":"2021-08-10T23:16:04.993Z","name":"#1628637361-Merchant Profile Updates-Tue Aug 10 23:16:01 2021","notes":"Testing - Tue, 10 Aug 2021 23:16:01 UTC","assignee":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"completed":false,"assignee_status":"inbox","completed_at":null,"due_on":"2021-08-18","due_at":null,"resource_subtype":"default_task","start_on":"2021-08-11","start_at":null,"tags":[],"workspace":{"gid":"916657163525497","resource_type":"workspace","name":"yuansfer.com"},"num_hearts":0,"num_likes":0,"permalink_url":"https://app.asana.com/0/1200750482997336/1200762811929407","followers":[{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"}],"parent":null,"hearted":false,"hearts":[],"assignee_section":{"gid":"1200524821166545","resource_type":"section","name":"Recently assigned"},"liked":false,"likes":[],"memberships":[{"project":{"gid":"1200750482997336","resource_type":"project","name":"Development Project for Tickets"},"section":{"gid":"1200753569417613","resource_type":"section","name":"Backlog"}}],"custom_fields":[{"gid":"1200366443430274","resource_type":"custom_field","resource_subtype":"enum","type":"enum","name":"Ticket Type","enabled":true,"enum_value":{"gid":"1200366443431311","resource_type":"enum_option","enabled":true,"name":"Merchant Profile Updates","color":"green"},"display_value":"Merchant Profile Updates","created_by":{"gid":"1200057682745929","resource_type":"user","name":"Jeremy Jones"},"enum_options":[{"gid":"1200366443431311","resource_type":"enum_option","enabled":true,"name":"Merchant Profile Updates","color":"green"},{"gid":"1200366443431316","resource_type":"enum_option","enabled":true,"name":"Transaction Errors","color":"red"},{"gid":"1200366443431388","resource_type":"enum_option","enabled":true,"name":"Product Requests","color":"orange"},{"gid":"1200366443431401","resource_type":"enum_option","enabled":true,"name":"Declined Merchant/Disabled Account","color":"yellow-orange"},{"gid":"1200366443432434","resource_type":"enum_option","enabled":true,"name":"Bug Fixes","color":"yellow"},{"gid":"1200366464813839","resource_type":"enum_option","enabled":true,"name":"Internal Development Project","color":"yellow-green"},{"gid":"1200680513739265","resource_type":"enum_option","enabled":true,"name":"Feedback","color":"blue-green"},{"gid":"1200760425076272","resource_type":"enum_option","enabled":true,"name":"Others","color":"cool-gray"}]},{"gid":"1199521775380609","resource_type":"custom_field","created_by":null,"resource_subtype":"enum","type":"enum","name":"Priority","enabled":true,"enum_value":{"gid":"1199521775380611","resource_type":"enum_option","enabled":true,"name":"Medium","color":"orange"},"display_value":"Medium","enum_options":[{"gid":"1199521775380610","resource_type":"enum_option","enabled":true,"name":"High","color":"red"},{"gid":"1199521775380611","resource_type":"enum_option","enabled":true,"name":"Medium","color":"orange"},{"gid":"1199521775380612","resource_type":"enum_option","enabled":true,"name":"Low","color":"green"}]},{"gid":"1200107390884071","resource_type":"custom_field","created_by":null,"resource_subtype":"enum","type":"enum","name":"Product stage","enabled":true,"enum_value":null,"display_value":null,"enum_options":[{"gid":"1200107390884072","resource_type":"enum_option","enabled":true,"name":"Spec needed","color":"none"},{"gid":"1200107390884073","resource_type":"enum_option","enabled":true,"name":"Design ready","color":"none"},{"gid":"1200107390884074","resource_type":"enum_option","enabled":true,"name":"Eng ready","color":"none"},{"gid":"1200107390884075","resource_type":"enum_option","enabled":true,"name":"QA ready","color":"none"},{"gid":"1200107390884076","resource_type":"enum_option","enabled":true,"name":"Marketing ready","color":"none"}]},{"gid":"1200128693528351","resource_type":"custom_field","resource_subtype":"enum","type":"enum","name":"Status","enabled":true,"enum_value":null,"display_value":null,"created_by":{"gid":"1199874732832801","resource_type":"user","name":"Shawn Zheng"},"enum_options":[{"gid":"1200128693528355","resource_type":"enum_option","enabled":true,"name":"Completed","color":"green"},{"gid":"1200128693529382","resource_type":"enum_option","enabled":true,"name":"In Progress","color":"red"},{"gid":"1200163946180464","resource_type":"enum_option","enabled":true,"name":"Not Started","color":"orange"}]},{"gid":"1200107390884078","resource_type":"custom_field","created_by":null,"resource_subtype":"number","type":"number","name":"Cost","enabled":true,"precision":0,"number_value":null,"display_value":null},{"gid":"1200750482997339","resource_type":"custom_field","created_by":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"resource_subtype":"text","type":"text","name":"Ticket ID","enabled":true,"text_value":"1628637361","display_value":"1628637361"},{"gid":"1200753569394602","resource_type":"custom_field","created_by":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"resource_subtype":"enum","type":"enum","name":"Month","enabled":true,"enum_value":{"gid":"1200753569396679","resource_type":"enum_option","enabled":true,"name":"August","color":"yellow-orange"},"display_value":"August","enum_options":[{"gid":"1200753569394609","resource_type":"enum_option","enabled":true,"name":"May","color":"green"},{"gid":"1200753569394617","resource_type":"enum_option","enabled":true,"name":"June","color":"red"},{"gid":"1200753569395650","resource_type":"enum_option","enabled":true,"name":"July","color":"orange"},{"gid":"1200753569396679","resource_type":"enum_option","enabled":true,"name":"August","color":"yellow-orange"}]}]}} +2021-08-11T07:16:05.678+0800 task/task.go:92 response status: 201 +2021-08-11T07:16:05.689+0800 task/task.go:105 [1628637361]new task ID:1200762811929407 +2021-08-11T07:16:05.696+0800 cmd/tasks.go:61 succeeded, task gid: 1200762811929407 +2021-08-11T07:16:05.696+0800 cmd/tasks.go:31 completed ... +2021-08-11T07:16:28.366+0800 cmd/tasks.go:27 started ... +2021-08-11T07:16:28.368+0800 story/stories.go:102 request: {"data":{"text":"comment - Wed, 11 Aug 2021 07:16:28 CST","is_pinned":false}} +2021-08-11T07:16:28.372+0800 util/http.go:117 request url: https://app.asana.com/api/1.0/tasks/1200762811929407/stories +2021-08-11T07:16:30.340+0800 util/http.go:142 response: {"data":{"gid":"1200762758090758","resource_type":"story","created_at":"2021-08-10T23:16:31.587Z","target":{"gid":"1200762811929407","resource_type":"task","name":"#1628637361-Merchant Profile Updates-Tue Aug 10 23:16:01 2021","resource_subtype":"default_task"},"source":"api","is_pinned":false,"type":"comment","text":"comment - Wed, 11 Aug 2021 07:16:28 CST","is_edited":false,"resource_subtype":"comment_added","num_hearts":0,"num_likes":0,"created_by":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"is_editable":true,"hearted":false,"hearts":[],"previews":[],"liked":false,"likes":[]}} +2021-08-11T07:16:30.340+0800 story/stories.go:112 response status: 201 +2021-08-11T07:16:30.347+0800 story/stories.go:125 [1200762811929407]new comment ID:1200762758090758 +2021-08-11T07:16:30.349+0800 cmd/tasks.go:77 succeeded, comment gid: 1200762758090758 +2021-08-11T07:16:30.350+0800 cmd/tasks.go:31 completed ... +2021-08-11T07:16:49.987+0800 cmd/tasks.go:27 started ... +2021-08-11T07:16:49.989+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200762811929407/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=62e8543c9c05d612597b9aca0a65c03876a7c2d0a50d5528a06f75eeae11]] 0xc000006090 0 [] false app.asana.com map[] map[] map[] 0xc00000a0c8} +2021-08-11T07:16:52.222+0800 util/http.go:181 response: {"data":{"gid":"1200762809106604","resource_type":"attachment","name":"abeer.jpg","resource_subtype":"asana"}} +2021-08-11T07:16:52.223+0800 cmd/tasks.go:97 attachment id: 1200762809106604 +2021-08-11T07:16:52.226+0800 cmd/tasks.go:31 completed ... +2021-08-11T07:40:17.804+0800 cmd/tasks.go:27 started ... +2021-08-11T07:40:17.805+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200762811929407/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=f20c43a7863784b1a8c2a1c582b664a229c2a0314afe2dcd15ea248fee01]] 0xc000006090 0 [] false app.asana.com map[] map[] map[] 0xc00000a0c8} +2021-08-11T07:40:17.805+0800 attach/attachments.go:103 Content-Type: image/jpeg +2021-08-11T07:40:21.281+0800 util/http.go:181 response: {"data":{"gid":"1200762840050800","resource_type":"attachment","name":"abeer.jpg","resource_subtype":"asana"}} +2021-08-11T07:40:21.282+0800 cmd/tasks.go:97 attachment id: 1200762840050800 +2021-08-11T07:40:21.292+0800 cmd/tasks.go:31 completed ... +2021-08-11T09:11:00.821+0800 cmd/tasks.go:27 started ... +2021-08-11T09:11:00.823+0800 cmd/tasks.go:38 ticket No.: 1628644260 +2021-08-11T09:11:00.824+0800 task/task.go:82 request: {"data":{"resource_subtype":"default_task","assignee":"1199521781039350","name":"#1628644260-Merchant Profile Updates-Wed Aug 11 01:11:00 2021","completed":false,"due_on":"2021-08-18","linked":false,"notes":"Testing - Wed, 11 Aug 2021 01:11:00 UTC","start_on":"2021-08-11","custom_fields":{"1199521775380609":"1199521775380611","1200366443430274":"1200366443431311","1200750482997339":"1628644260","1200753569394602":"1200753569396679"},"projects":["1200750482997336"],"workspace":"916657163525497"}} +2021-08-11T09:11:00.825+0800 util/http.go:117 request url: https://app.asana.com/api/1.0/tasks +2021-08-11T09:11:04.875+0800 util/http.go:142 response: {"data":{"gid":"1200763212554435","projects":[{"gid":"1200750482997336","resource_type":"project","name":"Development Project for Tickets"}],"resource_type":"task","created_at":"2021-08-11T01:11:04.538Z","modified_at":"2021-08-11T01:11:04.538Z","name":"#1628644260-Merchant Profile Updates-Wed Aug 11 01:11:00 2021","notes":"Testing - Wed, 11 Aug 2021 01:11:00 UTC","assignee":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"completed":false,"assignee_status":"inbox","completed_at":null,"due_on":"2021-08-18","due_at":null,"resource_subtype":"default_task","start_on":"2021-08-11","start_at":null,"tags":[],"workspace":{"gid":"916657163525497","resource_type":"workspace","name":"yuansfer.com"},"num_hearts":0,"num_likes":0,"permalink_url":"https://app.asana.com/0/1200750482997336/1200763212554435","followers":[{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"}],"parent":null,"hearted":false,"hearts":[],"assignee_section":{"gid":"1200524821166545","resource_type":"section","name":"Recently assigned"},"liked":false,"likes":[],"memberships":[{"project":{"gid":"1200750482997336","resource_type":"project","name":"Development Project for Tickets"},"section":{"gid":"1200753569417613","resource_type":"section","name":"Backlog"}}],"custom_fields":[{"gid":"1200366443430274","resource_type":"custom_field","resource_subtype":"enum","type":"enum","name":"Ticket Type","enabled":true,"enum_value":{"gid":"1200366443431311","resource_type":"enum_option","enabled":true,"name":"Merchant Profile Updates","color":"green"},"display_value":"Merchant Profile Updates","created_by":{"gid":"1200057682745929","resource_type":"user","name":"Jeremy Jones"},"enum_options":[{"gid":"1200366443431311","resource_type":"enum_option","enabled":true,"name":"Merchant Profile Updates","color":"green"},{"gid":"1200366443431316","resource_type":"enum_option","enabled":true,"name":"Transaction Errors","color":"red"},{"gid":"1200366443431388","resource_type":"enum_option","enabled":true,"name":"Product Requests","color":"orange"},{"gid":"1200366443431401","resource_type":"enum_option","enabled":true,"name":"Declined Merchant/Disabled Account","color":"yellow-orange"},{"gid":"1200366443432434","resource_type":"enum_option","enabled":true,"name":"Bug Fixes","color":"yellow"},{"gid":"1200366464813839","resource_type":"enum_option","enabled":true,"name":"Internal Development Project","color":"yellow-green"},{"gid":"1200680513739265","resource_type":"enum_option","enabled":true,"name":"Feedback","color":"blue-green"},{"gid":"1200760425076272","resource_type":"enum_option","enabled":true,"name":"Others","color":"cool-gray"}]},{"gid":"1199521775380609","resource_type":"custom_field","created_by":null,"resource_subtype":"enum","type":"enum","name":"Priority","enabled":true,"enum_value":{"gid":"1199521775380611","resource_type":"enum_option","enabled":true,"name":"Medium","color":"orange"},"display_value":"Medium","enum_options":[{"gid":"1199521775380610","resource_type":"enum_option","enabled":true,"name":"High","color":"red"},{"gid":"1199521775380611","resource_type":"enum_option","enabled":true,"name":"Medium","color":"orange"},{"gid":"1199521775380612","resource_type":"enum_option","enabled":true,"name":"Low","color":"green"}]},{"gid":"1200107390884071","resource_type":"custom_field","created_by":null,"resource_subtype":"enum","type":"enum","name":"Product stage","enabled":true,"enum_value":null,"display_value":null,"enum_options":[{"gid":"1200107390884072","resource_type":"enum_option","enabled":true,"name":"Spec needed","color":"none"},{"gid":"1200107390884073","resource_type":"enum_option","enabled":true,"name":"Design ready","color":"none"},{"gid":"1200107390884074","resource_type":"enum_option","enabled":true,"name":"Eng ready","color":"none"},{"gid":"1200107390884075","resource_type":"enum_option","enabled":true,"name":"QA ready","color":"none"},{"gid":"1200107390884076","resource_type":"enum_option","enabled":true,"name":"Marketing ready","color":"none"}]},{"gid":"1200128693528351","resource_type":"custom_field","resource_subtype":"enum","type":"enum","name":"Status","enabled":true,"enum_value":null,"display_value":null,"created_by":{"gid":"1199874732832801","resource_type":"user","name":"Shawn Zheng"},"enum_options":[{"gid":"1200128693528355","resource_type":"enum_option","enabled":true,"name":"Completed","color":"green"},{"gid":"1200128693529382","resource_type":"enum_option","enabled":true,"name":"In Progress","color":"red"},{"gid":"1200163946180464","resource_type":"enum_option","enabled":true,"name":"Not Started","color":"orange"}]},{"gid":"1200107390884078","resource_type":"custom_field","created_by":null,"resource_subtype":"number","type":"number","name":"Cost","enabled":true,"precision":0,"number_value":null,"display_value":null},{"gid":"1200750482997339","resource_type":"custom_field","created_by":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"resource_subtype":"text","type":"text","name":"Ticket ID","enabled":true,"text_value":"1628644260","display_value":"1628644260"},{"gid":"1200753569394602","resource_type":"custom_field","created_by":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"resource_subtype":"enum","type":"enum","name":"Month","enabled":true,"enum_value":{"gid":"1200753569396679","resource_type":"enum_option","enabled":true,"name":"August","color":"yellow-orange"},"display_value":"August","enum_options":[{"gid":"1200753569394609","resource_type":"enum_option","enabled":true,"name":"May","color":"green"},{"gid":"1200753569394617","resource_type":"enum_option","enabled":true,"name":"June","color":"red"},{"gid":"1200753569395650","resource_type":"enum_option","enabled":true,"name":"July","color":"orange"},{"gid":"1200753569396679","resource_type":"enum_option","enabled":true,"name":"August","color":"yellow-orange"}]}]}} +2021-08-11T09:11:04.880+0800 task/task.go:92 response status: 201 +2021-08-11T09:11:04.893+0800 task/task.go:105 [1628644260]new task ID:1200763212554435 +2021-08-11T09:11:04.899+0800 cmd/tasks.go:61 succeeded, task gid: 1200763212554435 +2021-08-11T09:11:04.899+0800 cmd/tasks.go:31 completed ... +2021-08-11T09:11:27.885+0800 cmd/tasks.go:27 started ... +2021-08-11T09:11:27.887+0800 story/stories.go:102 request: {"data":{"text":"comment - Wed, 11 Aug 2021 09:11:27 CST","is_pinned":false}} +2021-08-11T09:11:27.887+0800 util/http.go:117 request url: https://app.asana.com/api/1.0/tasks/1200763212554435/stories +2021-08-11T09:11:30.277+0800 util/http.go:142 response: {"data":{"gid":"1200763160493094","resource_type":"story","created_at":"2021-08-11T01:11:31.591Z","target":{"gid":"1200763212554435","resource_type":"task","name":"#1628644260-Merchant Profile Updates-Wed Aug 11 01:11:00 2021","resource_subtype":"default_task"},"source":"api","is_pinned":false,"type":"comment","text":"comment - Wed, 11 Aug 2021 09:11:27 CST","is_edited":false,"resource_subtype":"comment_added","num_hearts":0,"num_likes":0,"created_by":{"gid":"1199521781039350","resource_type":"user","name":"Frank Liu"},"is_editable":true,"hearted":false,"hearts":[],"previews":[],"liked":false,"likes":[]}} +2021-08-11T09:11:30.277+0800 story/stories.go:112 response status: 201 +2021-08-11T09:11:30.280+0800 story/stories.go:125 [1200763212554435]new comment ID:1200763160493094 +2021-08-11T09:11:30.285+0800 cmd/tasks.go:77 succeeded, comment gid: 1200763160493094 +2021-08-11T09:11:30.287+0800 cmd/tasks.go:31 completed ... +2021-08-11T09:11:46.516+0800 cmd/tasks.go:27 started ... +2021-08-11T09:11:47.464+0800 attach/attachments.go:81 failed to detect content type: EOF +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/module/attach.Request.Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:81 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:93 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T09:11:47.466+0800 cmd/tasks.go:95 failed to upload attachment: EOF +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:95 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T09:11:47.471+0800 cmd/tasks.go:31 completed ... +2021-08-11T09:15:36.254+0800 cmd/tasks.go:27 started ... +2021-08-11T09:15:36.466+0800 attach/attachments.go:81 failed to detect content type: EOF +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/module/attach.Request.Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:81 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:93 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T09:15:36.468+0800 cmd/tasks.go:95 failed to upload attachment: EOF +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:95 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T09:15:36.483+0800 cmd/tasks.go:31 completed ... +2021-08-11T09:33:05.245+0800 cmd/tasks.go:27 started ... +2021-08-11T09:33:05.448+0800 attach/attachments.go:148 EOF +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/module/attach.fDetectContentType + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:148 +asana/module/attach.Request.Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:78 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:93 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T09:33:05.449+0800 attach/attachments.go:81 failed to detect content type: EOF +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/module/attach.Request.Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:81 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:93 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T09:33:05.469+0800 cmd/tasks.go:95 failed to upload attachment: EOF +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:95 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T09:33:05.476+0800 cmd/tasks.go:31 completed ... +2021-08-11T09:39:55.802+0800 cmd/tasks.go:27 started ... +2021-08-11T09:39:55.995+0800 attach/attachments.go:103 Content-Type: image/jpeg +2021-08-11T09:39:55.995+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200763212554435/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=142ea28323748ac414bed095d6d6e396e50366eae5b7c5d9c3a1f4f80273]] 0xc0001fc008 0 [] false app.asana.com map[] map[] map[] 0xc00000a0c8} +2021-08-11T09:39:58.696+0800 util/http.go:181 response: {"data":{"gid":"1200763283314288","resource_type":"attachment","name":"abeer.jpg","resource_subtype":"asana"}} +2021-08-11T09:39:58.697+0800 cmd/tasks.go:97 attachment id: 1200763283314288 +2021-08-11T09:39:58.702+0800 cmd/tasks.go:31 completed ... +2021-08-11T09:43:43.690+0800 cmd/tasks.go:27 started ... +2021-08-11T09:43:43.882+0800 attach/attachments.go:103 Content-Type: image/jpeg +2021-08-11T09:43:43.882+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200763212554435/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=692c5a003cde1aa48c6f8e592f98bd76420442218dd6cdf9ef47488c8809]] 0xc000188048 0 [] false app.asana.com map[] map[] map[] 0xc00000a0c8} +2021-08-11T09:43:46.111+0800 util/http.go:181 response: {"data":{"gid":"1200763287249606","resource_type":"attachment","name":"abeer.jpg","resource_subtype":"asana"}} +2021-08-11T09:43:46.111+0800 cmd/tasks.go:97 attachment id: 1200763287249606 +2021-08-11T09:43:46.113+0800 cmd/tasks.go:31 completed ... +2021-08-11T09:45:14.948+0800 cmd/tasks.go:27 started ... +2021-08-11T09:45:15.141+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200763212554435/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=68c6c5664497c22e88e1d969404f63b2301cd6eef98430caa149963b8eef]] 0xc0000060c0 0 [] false app.asana.com map[] map[] map[] 0xc00000a0c8} +2021-08-11T09:45:15.141+0800 attach/attachments.go:104 Content-Type: image/jpeg +2021-08-11T09:45:17.172+0800 util/http.go:181 response: {"data":{"gid":"1200763403488204","resource_type":"attachment","name":"abeer.jpg","resource_subtype":"asana"}} +2021-08-11T09:45:17.175+0800 attach/attachments.go:70 failed to remove temporary file: remove ./static/abeer.jpg: The process cannot access the file because it is being used by another process. +git.drinkme.beer/yinghe/log.Errorf + E:/liuda/go/pkg/mod/git.drinkme.beer/yinghe/log@v0.1.3/logging.go:22 +asana/module/attach.Request.Create.func1 + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:70 +asana/module/attach.Request.Create + G:/dev/go/git.drinkme.beer/yinghe/asana/module/attach/attachments.go:136 +main.uploadAttachment + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:93 +main.main + G:/dev/go/git.drinkme.beer/yinghe/asana/cmd/tasks.go:30 +runtime.main + E:/go/src/runtime/proc.go:204 +2021-08-11T09:45:17.180+0800 cmd/tasks.go:97 attachment id: 1200763403488204 +2021-08-11T09:45:17.181+0800 cmd/tasks.go:31 completed ... +2021-08-11T09:50:09.559+0800 cmd/tasks.go:27 started ... +2021-08-11T09:50:09.758+0800 attach/attachments.go:109 Content-Type: image/jpeg +2021-08-11T09:50:09.758+0800 util/http.go:156 &{POST https://app.asana.com/api/1.0/tasks/1200763212554435/attachments HTTP/1.1 1 1 map[Authorization:[Bearer 1/1199521781039350:1fc8fb9e093189ab00284f6f21e56431] Content-Type:[multipart/form-data; boundary=aa836485ac9ac8f90ebdce027598e26b893b62f258fa9d5ffdd168c0caa7]] 0xc000096008 0 [] false app.asana.com map[] map[] map[] 0xc00000a0c8} +2021-08-11T09:50:12.199+0800 util/http.go:181 response: {"data":{"gid":"1200763409179552","resource_type":"attachment","name":"abeer.jpg","resource_subtype":"asana"}} +2021-08-11T09:50:12.200+0800 attach/attachments.go:73 exiting temporary file succeeded! +2021-08-11T09:50:12.208+0800 attach/attachments.go:79 removing temporary file succeeded! +2021-08-11T09:50:12.209+0800 cmd/tasks.go:97 attachment id: 1200763409179552 +2021-08-11T09:50:12.210+0800 cmd/tasks.go:31 completed ... diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..51a9a7b --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module asana + +go 1.15 + +require git.drinkme.beer/yinghe/log v0.1.3 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8ac8ca7 --- /dev/null +++ b/go.sum @@ -0,0 +1,58 @@ +git.drinkme.beer/yinghe/log v0.1.3 h1:QwHVLEqPo5nF/uucrmJJPSl9OXgjrx4JUzKieRfsOes= +git.drinkme.beer/yinghe/log v0.1.3/go.mod h1:4PAIGcEDUqVkKYSFQEN65+R6QWSsjvbfkIoEhGThGH8= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/module/attach/attachments.go b/module/attach/attachments.go new file mode 100644 index 0000000..e3b1426 --- /dev/null +++ b/module/attach/attachments.go @@ -0,0 +1,202 @@ +package attach + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/textproto" + "os" + "strings" + + "git.drinkme.beer/yinghe/log" + + "asana/util" +) + +const ( + URI = "/api/1.0/tasks/%s/attachments" +) + +type Request struct { + Body io.Reader + TaskID string + Name string + Path string + PAToken string + TicketID string +} + +type Data struct { + Response Response `json:"data"` +} + +type Response struct { + ID string `json:"gid"` + ResourceType string `json:"resource_type"` + Name string `json:"name"` + // ResourceSubtype - asana, dropbox, gdrive, onedrive, box, and external + ResourceSubtype string `json:"resource_subtype"` +} + +var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"") + +func escapeQuotes(s string) string { + return quoteEscaper.Replace(s) +} + +// Create - upload attachments +func (r Request) Create() (resp *Response, err error) { + var ( + tempPath string + data struct { + Response Response `json:"data"` + } + ) + tempPath = "./static/" + r.Name + + // TODO + err = download(r.Path, tempPath) + if nil != err { + return nil, err + } + + attachments, _ := os.Open(tempPath) + defer func() { + err := attachments.Close() + if nil != err { + log.Errorf("failed to close temporary file: %s", err.Error()) + } + + err = os.Remove(tempPath) + if nil != err { + log.Errorf("failed to remove temporary file: %s", err.Error()) + } + }() + + // Step 1. Try to determine the contentType. + contentType, body, err := fDetectContentType(attachments) + if nil != err { + log.Errorf("failed to detect content type: %s", err.Error()) + return + } + + if nil == body { + log.Errorf("empty attachment") + return nil, errors.New("generating attachment failed") + } + + // Step 2: + // Initiate and then make the upload. + prc, pwc := io.Pipe() + mpartW := multipart.NewWriter(pwc) + go func() { + defer func() { + _ = mpartW.Close() + _ = pwc.Close() + }() + h := make(textproto.MIMEHeader) + h.Set("Content-Disposition", + fmt.Sprintf(`form-data; name="%s"; filename="%s"`, + escapeQuotes("file"), escapeQuotes(r.Name))) + //h.Set("Content-Type", "application/octet-stream") + log.Infof("Content-Type: %s", contentType) + h.Set("Content-Type", contentType) + formFile, err := mpartW.CreatePart(h) + //formFile, err := mpartW.CreateFormFile("file", r.Name) + if err != nil { + return + } + _, _ = io.Copy(formFile, body) + //writeStringField(mpartW, "Content-Type", contentType) + //writeStringField(mpartW, "resource_subtype", "asana") + //writeStringField(mpartW, "name", "20210811065901") + }() + + fullURL := fmt.Sprintf("%s/api/1.0/tasks/%s/attachments", util.AsanaHost, r.TaskID) + + req, err := http.NewRequest("POST", fullURL, prc) + if err != nil { + log.Errorf("failed to build attachment request: %s", err.Error()) + return nil, err + } + req.Header.Set("Content-Type", mpartW.FormDataContentType()) + req.Header.Set("Authorization", r.PAToken) + + buf, err := util.Request(req) + if nil != err { + return nil, err + } + err = json.Unmarshal(buf, &data) + if nil != err { + log.Errorf("[%s][%s]failed to upload attachments: %s", r.TicketID, r.TaskID, err.Error()) + return nil, err + } + return &data.Response, err +} + +func fDetectContentType(r io.Reader) (string, io.Reader, error) { + if r == nil { + return "", nil, errors.New("empty attachments") + } + + seeker, seekable := r.(io.Seeker) + sniffBuf := make([]byte, 512) + n, err := io.ReadAtLeast(r, sniffBuf, 1) + if err != nil { + log.Errorf(err.Error()) + return "", nil, err + } + + contentType := http.DetectContentType(sniffBuf) + needsRepad := !seekable + if seekable { + if _, err = seeker.Seek(int64(-n), io.SeekCurrent); err != nil { + // Since we failed to rewind it, mark it as needing repad + needsRepad = true + } + } + + if needsRepad { + r = io.MultiReader(bytes.NewReader(sniffBuf), r) + } + + return contentType, r, nil +} + +func writeStringField(w *multipart.Writer, key, value string) { + fw, err := w.CreateFormField(key) + if err == nil { + _, _ = io.WriteString(fw, value) + } +} + +var ( + errValidation = errors.New("invalid request") +) + +func download(src, filename string) error { + if "" == src || "" == filename { + return errValidation + } + f, err := os.Create(filename) + if nil != err { + log.Errorf("failed to create attachments") + return errors.New("failed to create file") + } + defer f.Close() + //defer os.Remove(filename) + + resp, err := http.Get(src) + if nil != err { + log.Infof("download report failed: %s", err.Error()) + return err + } + + defer resp.Body.Close() + _, err = io.Copy(f, resp.Body) + return err +} diff --git a/module/story/stories.go b/module/story/stories.go new file mode 100644 index 0000000..5313fe5 --- /dev/null +++ b/module/story/stories.go @@ -0,0 +1,127 @@ +package story + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + + "git.drinkme.beer/yinghe/log" + + "asana/util" +) + +const ( + URI = "/api/1.0/tasks/%s/stories" +) + +type Data struct { + Request Request `json:"data"` +} + +type Request struct { + HtmlText string `json:"html_text,omitempty"` + Text string `json:"text"` + StickerName string `json:"sticker_name,omitempty"` + IsPinned bool `json:"is_pinned"` + + taskID string + ticketID string + paToken string +} + +func (r *Request) GetTaskID() string { + return r.taskID +} + +func (r *Request) SetTaskID(id string) { + r.taskID = id +} + +func (r *Request) GetTicketID() string { + return r.ticketID +} + +func (r *Request) SetTicketID(id string) { + r.ticketID = id +} + +func (r *Request) GetPAToken() string { + return r.paToken +} + +func (r *Request) SetPAToken(token string) { + r.paToken = token +} + +type Response struct { + ID string `json:"gid"` + ResourceType string `json:"resource_type"` + Type string `json:"type"` + Text string `json:"text"` + // IsPinned Conditional + // Whether the story should be pinned on the resource. + IsPinned bool `json:"is_pinned"` + StickerName string `json:"sticker_name,omitempty"` +} + +func (r Request) validate() error { + if "" == r.taskID { + log.Errorf("task id is empty") + return errors.New("task id is empty") + } + return nil +} + +// Create comments on task +func (r Request) Create() (resp *Response, err error) { + var ( + reqData Data + respData struct { + Response Response `json:"data"` + } + ) + if err = r.validate(); nil != err { + return + } + + resp = new(Response) + + headers := make(map[string]string) + headers["Authorization"] = r.paToken + headers["Content-Type"] = util.ContentType + + reqData.Request = r + + buf, err := json.Marshal(&reqData) + if nil != err { + log.Errorf("failed to generate comment request: %s", err.Error()) + return + } + + log.Infof("request: %s", string(buf)) + + client := util.NewHttpClient(util.AsanaHost, fmt.Sprintf(URI, r.taskID), util.HttpPostMethod, buf) + client.Headers = headers + + err = client.Request() + if nil != err { + log.Errorf("failed to create new task comment: %s", err.Error()) + return + } + log.Infof("response status: %d", client.HTTPStatus) + if http.StatusCreated != client.HTTPStatus { + log.Errorf("unexpected response") + err = errors.New("unexpected response") + return + } + + err = json.Unmarshal(client.Body, &respData) + if nil != err { + log.Errorf("illegal comment result: %s", err.Error()) + return + } + resp = &respData.Response + log.Infof("[%s]new comment ID:%s", r.taskID, resp.ID) + return +} diff --git a/module/task/task.go b/module/task/task.go new file mode 100644 index 0000000..ad72fef --- /dev/null +++ b/module/task/task.go @@ -0,0 +1,107 @@ +package task + +import ( + "encoding/json" + "errors" + "net/http" + + "git.drinkme.beer/yinghe/log" + + "asana/util" +) + +type Data struct { + Request Request `json:"data"` +} + +type Request struct { + ResourceSubtype string `json:"resource_subtype"` + Assignee string `json:"assignee"` + Name string `json:"name"` + Completed bool `json:"completed"` + DueOn string `json:"due_on"` + Liked bool `json:"linked"` + // Notes refer to the content of each Ticket + Notes string `json:"notes"` + StartOn string `json:"start_on"` + CustomFields map[string]string `json:"custom_fields"` + Projects []string `json:"projects"` + Workspace string `json:"workspace"` + + TicketID string `json:"-"` + TicketType string `json:"-"` + paToken string +} + +func (r *Request) GetPAToken() string { + return r.paToken +} + +func (r *Request) SetPAToken(token string) { + r.paToken = token +} + +type Response struct { + ID string `json:"gid"` + Name string `json:"name"` + ResourceType string `json:"resource_type"` + AssigneeStatus string `json:"assignee_status"` +} + +const ( + URI = "/api/1.0/tasks" + ResourceSubtype = "default_task" +) + +func (r Request) Create() (resp *Response, err error) { + var ( + reqData Data + respData struct { + Response Response `json:"data"` + } + ) + + resp = new(Response) + + headers := make(map[string]string) + headers["Authorization"] = r.paToken + headers["Content-Type"] = util.ContentType + + if "" == r.ResourceSubtype { + r.ResourceSubtype = ResourceSubtype + } + + reqData.Request = r + + buf, err := json.Marshal(&reqData) + if nil != err { + log.Errorf("failed to generate task request: %s", err.Error()) + return + } + + log.Infof("request: %s", string(buf)) + + client := util.NewHttpClient(util.AsanaHost, URI, util.HttpPostMethod, buf) + client.Headers = headers + + err = client.Request() + if nil != err { + log.Errorf("failed to create new Asana task: %s", err.Error()) + return + } + log.Infof("response status: %d", client.HTTPStatus) + if http.StatusCreated != client.HTTPStatus { + log.Errorf("unexpected response") + err = errors.New("unexpected response") + return + } + + err = json.Unmarshal(client.Body, &respData) + if nil != err { + log.Errorf("illegal task result: %s", err.Error()) + return + } + resp = &respData.Response + log.Infof("[%s]new task ID:%s", r.TicketID, resp.ID) + return +} diff --git a/util/constant.go b/util/constant.go new file mode 100644 index 0000000..9d0bd07 --- /dev/null +++ b/util/constant.go @@ -0,0 +1,16 @@ +package util + +const ( + AsanaHost = "https://app.asana.com" + + ContentType = "application/json" + + HttpGetMethod = "GET" + HttpPostMethod = "POST" + + AsanaDateFormat = "2006-01-02" +) + +var ( + AsanaHeaders = make(map[string]string) +) diff --git a/util/http.go b/util/http.go new file mode 100644 index 0000000..9f719c8 --- /dev/null +++ b/util/http.go @@ -0,0 +1,184 @@ +package util + +import ( + "bufio" + "bytes" + "context" + "errors" + //"fmt" + "io/ioutil" + "net" + "net/http" + "time" + + "git.drinkme.beer/yinghe/log" +) + +// Network contains common configuration. +type Network struct { + Env string `toml:"env"` + Host []string `toml:"gateway"` + GatewayURL string + RequestTimeout time.Duration `toml:"request_timeout"` + ConnectTimeout time.Duration `toml:"connect_timeout"` + SocketTimeout time.Duration `toml:"socket_timeout"` +} + +var network = Network{ + RequestTimeout: 45 * time.Second, + ConnectTimeout: 45 * time.Second, + SocketTimeout: 55 * time.Second, +} + +var client = &http.Client{ + Transport: &http.Transport{ + DialContext: func(ctx context.Context, n, addr string) (net.Conn, error) { + conn, err := net.DialTimeout(n, addr, + time.Second*network.RequestTimeout, + ) + if err != nil { + return conn, err + } + conn.SetDeadline(time.Now(). + Add(time.Second * network.ConnectTimeout)) + return conn, err + }, + ResponseHeaderTimeout: time.Second * network.SocketTimeout, + MaxConnsPerHost: 20, + IdleConnTimeout: 3 * time.Minute, + MaxIdleConns: 10, + //Proxy: func(_ *http.Request) (*url.URL, error) { + // return url.Parse("http://192.168.0.104:1087") + //}, + }, +} + +func SetNetworkCfg(cfg Network) { + if 0 < cfg.RequestTimeout { + network.RequestTimeout = cfg.RequestTimeout + } + + if 0 < cfg.ConnectTimeout { + network.ConnectTimeout = cfg.ConnectTimeout + } + + if 0 < cfg.SocketTimeout { + network.SocketTimeout = cfg.SocketTimeout + } +} + +type Body interface { + BuildRequest() []byte +} + +type Client struct { + GatewayURL string + URI string + Headers map[string]string + Authorization string + Method string + HTTPStatus int + Body []byte // Indicates both Request Body & Response Body + TraceId interface{} + Buffer *bufio.Reader +} + +func (c *Client) AddHeader(k, v string) { + c.Headers[k] = v +} + +type Bytes []byte + +func (self Bytes) BuildRequest() []byte { + return self +} + +/* +url, uri, method, body +*/ +func NewHttpClient(url, uri, m string, b []byte) *Client { + return &Client{ + GatewayURL: url, + URI: uri, + Method: m, + Headers: make(map[string]string), + Body: b, + } +} + +func (c *Client) BuildRequest(body Body) { + if nil == c.Body { + c.Body = make([]byte, 0, 1024) + } + c.Body = append(c.Body, body.BuildRequest()...) +} + +func (c *Client) Request() (err error) { + log.Infof("request url: %s", c.GatewayURL+c.URI) + request, err := http.NewRequest(c.Method, + c.GatewayURL+c.URI, + bytes.NewReader(c.Body), + ) + if err != nil { + log.Info("Post err occurs:", err.Error()) + return + } + + for k, v := range c.Headers { + request.Header.Set(k, v) + } + + resp, err := client.Do(request) + if nil == resp { + log.Info("none response received") + err = errors.New("none response received") + return + } + + defer resp.Body.Close() + c.HTTPStatus = resp.StatusCode + c.Body, err = ioutil.ReadAll(resp.Body) + + log.Infof("response: %s", string(c.Body)) + return +} + +func Request(req *http.Request) ([]byte, error) { + var ( + err error + body []byte + ) + + if nil == req { + log.Errorf("illegal request") + return nil, errors.New("illegal request") + } + log.Infof("%v", req) + resp, err := client.Do(req) + if nil == resp { + log.Info("none response received") + err = errors.New("none response received") + return nil, err + } + + defer resp.Body.Close() + if http.StatusOK != resp.StatusCode { + if nil != resp.Body { + + body, _ = ioutil.ReadAll(resp.Body) + log.Infof("response: %s", string(body)) + } + log.Errorf("unexpected status: %d", resp.StatusCode) + return nil, errors.New("unexpected status") + } + + body, err = ioutil.ReadAll(resp.Body) + if nil != err { + log.Errorf("invalid response body: %s", err.Error()) + return nil, err + } + + log.Infof("response: %s", string(body)) + + return body, nil +}