質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

1回答

164閲覧

draftsのアクションを利用したtoggleTrackAPIの実行方法

tabakazu

総合スコア1

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2024/09/15 22:52

実現したいこと

macアプリのdraftsのアクションを利用して、入力された文字列の1行目をタスク名としてtoggle trackのタスクを開始したいと考えています。

発生している問題・分からないこと

api tokenによる認証周りはクリアしているようなのですが、jsonの形式が不適切であるというエラーが出てうまくタスクを登録することができません。

エラーメッセージ

error

1Test 2Input title:Test 3Final Title:Test 4Start Time:2024-09-15T22:36:22.158Z 5description:Test 6start:2024-09-15T22:36:22.158Z 7duration:-1 8created_with:Drafts App 9Request Data Object (before stringify):[object Object] 10URLhttps://api.track.toggl.com/api/v9/workspaces/<workspacesID>/time_entries 11Request Data String (after stringify):{"workspace_id":"<workspacesID>,"description":"Test","start":"2024-09-15T22:36:22.158Z","duration":-1,"created_with":"Drafts App"} 12HTTP.request Failed: 400, Unknown error 13Full Response: 14Response Status Code:400 15Response Headers:[object Object] 16Response Text:"JSON is not valid" 17Togglへのタスク追加エラー: 400 18Response Text:"JSON is not valid" 19Script step completed.

該当のソースコード

javascript

1// スクリプトで使用する関数の定義 2const togglApiToken = ''APIToken"; 3const workspaceID = '"workspaceID'; // 手動で取得したワークスペースIDをここに設定 4 5 6// Base64エンコードの関数 7function encodeBase64(input) { 8 const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; 9 let str = input; 10 let output = ''; 11 12 for (let block = 0, charCode, i = 0, map = chars; 13 str.charAt(i | 0) || (map = '=', i % 1); 14 output += map.charAt(63 & (block >> (8 - (i % 1) * 8))) 15 ) { 16 charCode = str.charCodeAt(i += 3/4); 17 if (charCode > 0xFF) { 18 throw new Error("The string to be encoded contains characters outside of the Latin1 range."); 19 } 20 block = (block << 8) | charCode; 21 } 22 23 return output; 24} 25 26// Togglへのタスク追加関数 27function addTaskToToggl(title) { 28 const http = HTTP.create(); 29 const now = new Date(); 30 const startTime = now.toISOString(); // ISO 8601形式で日付をフォーマット 31 //const startTime = now.toISOString().replace('Z', '+00:00'); // "Z"を"+00:00"に置き換える 32 33 console.log("Input title:"+title); 34 35 // タイトルが空または未定義の場合、デフォルト値を設定 36 if (!title || title.trim() === "") { 37 title = "Untitled Task"; 38 console.log("Warning: Empty title. Using default:", title); 39 } 40 41 // 現在時刻をUNIXエポック秒で取得 42 const currentUnixTime = Math.floor(now.getTime() / 1000); 43 44 console.log("Final Title:"+title); 45 console.log("Start Time:"+startTime); 46 47 // Unixエポックからの経過時間を秒単位で計算 48 const duration = -1 * Math.floor(now.getTime() / 1000); 49 50 // リクエストデータを正しく設定 51 let requestData = { 52 "workspace_id": parseInt(workspaceID, 10), // workspace_idを整数として指定 53 "description": title, 54 "start": startTime, 55 "duration": -1, 56 "created_with": "Drafts App" 57 }; 58 59 console.log("description:"+requestData.description); 60 console.log("start:"+requestData.start); 61 console.log("duration:"+requestData.duration); 62 console.log("created_with:"+requestData.created_with); 63 64 console.log("Request Data Object (before stringify):"+requestData); 65 console.log("URL"+`https://api.track.toggl.com/api/v9/workspaces/${workspaceID}/time_entries`) 66 67 let requestDataString; 68 try { 69 requestDataString = JSON.stringify(requestData); 70 console.log("Request Data String (after stringify):"+requestDataString); 71 } catch (e) { 72 console.log("JSON.stringify Error:"+e.message); 73 return false; 74 } 75 76 try { 77 const response = http.request({ 78 "url": `https://api.track.toggl.com/api/v9/workspaces/${workspaceID}/time_entries`, 79 "method": "POST", 80 "data": requestDataString, 81 "headers": { 82 "Authorization": "Basic " + encodeBase64(togglApiToken + ":api_token"), 83 "Content-Type": "application/json" 84 } 85 }); 86 87 console.log("Full Response:", JSON.stringify(response, null, 2)); // 2つのスペースで整形して表示 88 console.log("Response Status Code:"+response.statusCode); 89 console.log("Response Headers:"+response.headers); 90 console.log("Response Text:"+response.responseText); 91 92 if (response.statusCode === 200 || response.statusCode === 201) { 93 console.log("Togglタスクが正常に作成されました。"); 94 return true; 95 } else { 96 console.log("Togglへのタスク追加エラー: " + response.statusCode); 97 console.log("Response Text:"+response.responseText); 98 return false; 99 } 100 } catch (error) { 101 console.log("リクエスト送信中にエラーが発生しました:", error.message); 102 return false; 103 } 104} 105 106 107 108 109// ユーザーに登録先を選ばせる 110function showPrompt() { 111 let p = Prompt.create(); 112 p.title = "ノート登録先の選択"; 113 p.addButton("Notion"); 114 p.addButton("DayOne"); 115 p.show(); 116 return p.buttonPressed; 117} 118 119// 選択されたテキストをブロックとして処理する関数 120function processSelectedTextAsBlock(selectedText) { 121 let lines = selectedText.split("\n").map(line => line.trim()).filter(line => line.length > 0); 122 123 if (lines.length > 0) { 124 let title = lines[0]; // 選択された部分の最初の行をタイトルとする 125 let body = lines.slice(1).join("\n"); // 2行目以降をコンテンツとする 126 127 return {"title":title,"body":body}; 128 } else { 129 app.displayErrorMessage("選択されたテキストが無効です。"); 130 return {"title":"","body":""}; 131 } 132} 133 134//テキスト取得関数 135function getTitleContentsDic() { 136 if (editor.getSelectedText().length > 0) { 137 // 選択されている部分がある場合、その部分を自動的にブロックとして登録 138 let selectedText = editor.getSelectedText(); 139 //1行めをtitle,2行目以降をコンテンツとして取得 140 return(processSelectedTextAsBlock(selectedText)); 141 } else { 142 // Draft全体を1つのNotionページとして登録 143 let title = draft.title; // 1行目をタイトルとして使用 144 let d = draft.lines; 145 d.shift(); // 最初の行を削除して残りをコンテンツとして使用 146 let body = d.join("\n"); 147 return {"title":title, "body":body}; 148 } 149} 150 151 152//メインの実行ロジック 153(function() { 154 // Togglへのタスク追加 155 dic_titleContents=getTitleContentsDic() 156 console.log(dic_titleContents["title"]); 157 158 let taskAdded = addTaskToToggl(dic_titleContents["title"]); 159 if (!taskAdded) { 160 alert("Togglへのタスク登録に失敗しました。詳細はコンソールログを確認してください。"); 161 return; 162 } 163 164 // ユーザーに登録先を選ばせる 165 let choice = showPrompt(); 166 if (choice === "Notion") { 167 alert("Notionへのノート登録を開始します。"); 168 } else if (choice === "DayOne") { 169 alert("DayOneへのノート登録を開始します。"); 170 } else { 171 alert("キャンセルされました。"); 172 return; 173 } 174})();

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

8時間程度あれこれ試しましたが、durationやdescriptionの値をどのように変更してもエラーが解消されません。

補足

分かる方がいらっしゃいましたらよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

Toggl APIのドキュメントを見ると、start属性に指定する日時のフォーマットはYYYY-MM-DDTHH:mm:ssZと記載されていますが、Date.prototype.toISOString()メソッドで得られる日付のフォーマットはYYYY-MM-DDTHH:mm:ss.sssZです。
https://engineering.toggl.com/docs/api/time_entries#body
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString

次のように変更して日付のフォーマットをToggl APIのドキュメントに書かれているものに揃えてみてください

diff

1function addTaskToToggl(title) { 2 const http = HTTP.create(); 3 const now = new Date(); 4- const startTime = now.toISOString(); 5+ const startTime = now.toISOString().replace(/\.[0-9]{3}/, "");

投稿2024/09/16 04:02

FoxRefire

総合スコア148

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tabakazu

2024/09/17 21:40

回答ありがとうございます。APIのドキュメントも確認していただいてありがとうございます。 ご指摘いただいたとおり、変更し試してみましたが解決できませんでした ログ出力は Test Input title:Test Final Title:Test Start Time:2024-09-17T21:33:43Z description:Test start:2024-09-17T21:33:43Z duration:-1 created_with:Drafts App Request Data Object (before stringify):[object Object] URLhttps://api.track.toggl.com/api/v9/workspaces/<workspaceID>/time_entries Request Data String (after stringify):{"workspace_id":<workspaceID>,"description":"Test","start":"2024-09-17T21:33:43Z","duration":-1,"created_with":"Drafts App"} HTTP.request Failed: 400, Unknown error Full Response: Response Status Code:400 Response Headers:[object Object] Response Text:"JSON is not valid" Togglへのタスク追加エラー: 400 Response Text:"JSON is not valid" Script step completed. となっており、ご指摘いただいた部分は修正されているようなのですが.... この場合どの辺りに原因がありそうでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問