ブックマークレット作ったけど、他人に共有したら謎のエラーが頻発してChrome extension作って解決した話。
とりあえずソース見せろという場合はこちら。
https://github.com/hazhikko/RtoT
今の現場は、お客さんとのやり取りをBackLog、内部の管理をRedmineでやっています。
この時点ですでに二重管理ですが、PMOから
Redmineは個人のタスクが見えにくい
という話が出て、TaskWorldを追加した三重管理になってしまいました。。。
細々としたタスク管理したいんなら、メインチケットにタスクチケットぶら下げたらいいんじゃないの?
と思うのですが、それでは都合が悪いそうです。
めんどい。
三重管理ということは、
BackLog起票→Redmine起票→TaskWorld起票
をやらないといけないということです。
めんどい。
あまりに面倒だったので、とりあえずRedmine→TaskWorld起票を自動化することにしました。
(BackLogは自分で起票することがまずないので保留)
目次
自動化方法を考える
さて、まずはどうやって自動化するかを考えないといけません。
Redmineのような、昔風のデザイン?で、入力エリアがきっちり表示されていて、ボタンを押したら画面遷移するようなタイプは簡単。
DOM操作で直接テキストボックスに値を入れて、ボタンを押してやればいいです。
JQUERYを使うとセレクタが簡単になってらくちんです。
困るのは、TaskWorldのようなタイプ。
チケットをクリックすると編集画面が出てきたり、画面上でドラッグするとチケットが移動できたり、最近のUIっぽいですね。
こいつは、作りによってはDOM操作が非常にやりにくいです。
さらに、こういったサイトはしょっちゅうUIが変わったりして、すぐ自動化コードが陳腐化するので、DOM操作は避けたいところ。
TaskWorld APIを使う
幸い、TaskWorldにはAPIが用意されているので、これを利用します。
https://asia-api.taskworld.com/
試しにRestlet ClientでPOST送信してみると
こんな感じでレスポンスが返ってきました。
ブックマークレットで作ってみる
Redmineチケット画面でボタンを押したら、その画面の情報を使ってTaskWorldに登録する
というのがいいなと思ったので、ブックマークレットで作ってみることにしました。
1 |
javascript:!function(d,f,s){s=d.createElement("script");s.src="//j.mp/1bPoAXq";s.onload=function(){f(jQuery.noConflict(1))};d.body.appendChild(s);var at="dc4c7a5ca296a2c6f9e27e0f1e2f885ea421283920eb7f27a5df20cc416e0171";var sid="5b5ad7cc958142ac572ccabd";var pid="5b5ad810b9c7c0fb58a5faeb";var u=location.href;var su=u.split("/");su="#"+su[su.length-1]+"%E3%80%8C"+$(".subject h3").text()+"%E3%80%8D";var n=$(".assigned-to a").attr("href").split("/");n=n[n.length-1];var d=$("td.due-date").text();var tid="";var ild="";switch(n){case "123":lid="5b5ad8109a98f946a7db3025";break;default:lid="5b5ad8109a98f946a7db3023";break;}var de=ajax_function();de.done(function(){var pd={"access_token":at,"space_id":sid,"task_id":tid,"description":u};if(d){pd["due_date"]=d+"T10:00:00.000Z";};$.ajax({type:"post",url:"https://asia-api.taskworld.com/v1/task.update",data:pd}).done(function(data){alert("completed");}).fail(function(){alert("comp");});});function ajax_function(){var de=new $.Deferred();$.ajax({type:"POST",url:"https://asia-api.taskworld.com/v1/task.create",data:{"access_token":at,"space_id":sid,"project_id":pid,"list_id":lid,"title":su}}).done(function(data){tid=data.task.task_id;}).fail(function(){alert("failed");}).always(function(){de.resolve();});return de;}}(document,function($){}) |
長い。
1294文字あります。
まぁ、これくらいなら許容範囲内です。
謎のクロスドメインエラー頻発
自分でテストしてた時は一回も発生しなかったのに、みんなに共有したらクロスドメインエラーが出るようになってしまいました。
~is not allowed by Access-Control-Allow-Origin.
というやつです。
え・・・なぜに・・・?
今回使っているのは、TaskWorldのAPIのみなのに、なんでクロスドメインエラーが出るんでしょう。
訳がわかりません。
解決法を探る
Google先生に解決法を聞いてみます。
結論から言えば、全部だめでした。
クロスドメイン制約を回避するChromeショートカットを作る
これがソースをいじることもない、1番簡単な方法です。
やり方はこんなかんじ。
が、私の環境ではできませんでした。
さらに、この制限解除した状態だとセキュリティリスクが気になるのでやめたほうがよさそうです。
サーバー側でAccess-Control-Allow-Originを設定する
これはもう完全不可です。
TaskWorldが提供しているものをいじれるわけがありません。
もし、自分でサーバーの管理をしているAPIを使う場合は、これで間違いなく解決するようです。
データをJSONではなくJSONPとして扱う
これもTaskWorldは対応していなかったので不可。
あと、この方法はセキュリティリスクがあるのでおすすめできないみたいです。
プログラムを経由する
作成時はこの方法を知らなかったのですが、これならできたような気がします。
1 2 3 4 5 |
<?php if(isset($_GET['url']) && preg_match('/^http(s)?:/', $_GET['url'])){ echo file_get_contents($_GET['url']); } ?> |
Javascriptでは、前述のように
url
の値を`/ajax.php?url=http://www.foo.com/test.php’のようにパラメータとしてリクエスト先のURLを渡します。これでブラウザ上のAjaxからのリクエストは同じサーバを向きますのでクロスドメインの問題は起きません。
とのこと。
Chrome extensionならクロスドメイン通信できるらしいよ?
どこで見つけたかもうわかりませんが、何やらそんな記述を見つけました。
結果、大層苦しみましたが完成しました。
RedmineのチケットをTaskWorldにコピーするChrome extension
はい、嘘つきました。
いろいろ解決できないことがあって力尽きたので、自分に必要なところしか作ってません。
ので、自分でswitch文の分岐を増やしたりする必要があります。
長くなったので、苦しんだChrome extension開発(主に非同期制御のせい)は次回に。