読者です 読者をやめる 読者になる 読者になる

ietty TECH blog

Google Data Studioとre:dashでつくるダッシュボード講座

f:id:chanshimo:20161202183733j:plain iettyでマーケティングとサービス企画を担当している下地と申します。

今回は、Google Data Studio、re:dash、googleスプレッドシートを使ったダッシュボードの構築方法について説明します。

ざっくり言うと

  • Google Data Studioでダッシュボードを作った

  • Google Apps Scriptでre:dashのデータをGoogleスプレッドシートへインポート

  • Googleスプレッドシートで異なるデータをJOINする

続きを読む

ポケモンGOで会社の近くに出現したポケモンをSlack通知させた話

f:id:mikeda3:20160730152015j:plain ietty社内でも人気のポケモンGOですが、会社の近くにレアポケモンが出現していないかポケビジョンばかり見て仕事にならなくなってしまったので、レアポケモンが出現した時にSlackにメンション付きで通知するようにしました。

とりあえず準備

Slack BOTはHubotで開発し、サーバには無料で使えるHerokuを使います。

HubotはNode.jsで開発ができるので、ポケモンGOのAPI取得部分はjavascriptでポケモンGOのAPIを扱えるPokemon-GO-node-apiを使います。 github.com ※npmに公開されているのでnpm install pokemon-go-node-apiで簡単にインストールできます。

ソースコード

module.exports = (robot) ->
  PokemonGO = require('pokemon-go-node-api')

  # JSON(pokemon-go-node-apiの中にあるpokemon.jsonを日本語化したもの
  pokemonJson = require('./pokemon.json')

  # 通知先チャンネル
  @pokemonUser = room: '#hogehoge'

  # ポケモン捜索先の位置情報
  location = {
    type: 'coords',
    coords: {
      latitude: 35.64780246266644,
      longitude: 139.7102701663971,
      altitude: 10
    }
  }

  # 認証用情報(登録時のgmailのアカウントを入れてください)
  username = 'hogehoge@gmail.com'
  password = '12345678'
  provider = 'google'

  # レアポケモンが出た時に飛ばすメンション
  @pokemonMention = '@hogehoge'

  # 重複して出さないように配列でチェック
  duplicateChackArray = [];

  # APIにリコネクトがないので接続切れを起こさないように10秒に1回ログインして情報を収集する
  setInterval(() =>
    io = new PokemonGO.Pokeio()
    io.init(username, password, location, provider, (err) =>
      if err
        console.log(err)
      console.log('1[i] Current location: ' + io.playerInfo.locationName)
      console.log('1[i] lat/long/alt: : ' + io.playerInfo.latitude + ' ' + io.playerInfo.longitude + ' ' + io.playerInfo.altitude)

      io.GetProfile((err, profile) =>
        if err
          console.log(err)
        console.log('1[i] Username: ' + profile.username)
        io.Heartbeat((err, hb) =>
          if (err)
            console.log(err)
          for val in hb.cells
            if val.NearbyPokemon
              for item in val.NearbyPokemon
                pokemon = pokemonJson.pokemon[parseInt(item.PokedexNumber)-1]
                if duplicateChackArray.indexOf(item.EncounterId.toString()) == -1
                  duplicateChackArray.push(item.EncounterId.toString())
                  # ポケモンのレアリティによってメンションを飛ばすか判定
                  if pokemon.egg == '10 km' || pokemon.egg == 'Not in Eggs'
                    mention = @pokemonMention
                  else
                    mention = ''

                  robot.send @pokemonUser,
                    mention + '\n' + pokemon.name + '(' + pokemon.egg + ') を ' + item.DistanceMeters.toString() + ' メートル圏内に発見!\n' + pokemon.img
        )
      )
    )
  , 10000)

できたもの

f:id:tioken12:20160729201423p:plain

ポケモンの名前の横に出ている◯kmはどの卵から出るポケモンかを表示しています。 その数値からレアリティを判定して、10kmの卵のポケモンと卵から出ないポケモンだけ自分にメンションを飛ばすようにしました。

メンションが飛んできたらポケビジョンで位置を確認してダッシュで捕まえに行きましょう!

Photoshopとcsvデータを連動させて画像を高速量産できる!変数データセットが超便利な件

f:id:mikeda3:20160622180055p:plain こんにちは!iettyデザイナー池田です。

Photoshopには変数データセットという機能があり、csvデータと連動させて複数バージョンの画像をすばやく書き出すことができます! 詳しいやり方についてはAdobeのページをごらんください。

オウンドメディア担当者と連携して、ietty Magazineのアイキャッチ画像を量産する体制を確立したので方法をご紹介します!

続きを読む

WordPressでAPI連携

要件としては、投稿ページ等にAPIで取得したデータを表示させたいということだったので WordPressのwp_remote_get関数を使って取得してみました。

wp_remote_get

wp_remote_get - WordPress Codex

使い方は簡単で、パラメータにURLを指定するだけでデータを取得することができます。

wp_remote_get('http://hogehoge.com/');

また、第2引数に配列でオプションを指定することも可能となります。

// timeoutを10秒に設定
wp_remote_get('http://hogehoge.com/', array('timeout' => 10))

戻り値は配列で返却され、headersやbodyなどがあり、データについてはbody内に格納されています。

※配列の詳細については、こちらを参照

ショートコード化

APIからデータを取得することはできたが、ページの好きな場所に表示させるにはどうしようかと 思ったところ、ショートコードを自作すれば任意の場所に表示させられるじゃないかと思い wp_remote_getで取得したデータをショートコード化してみました。

function.php
<?php

...

function get_remote_by_hogehoge($args) {
  $url = 'http://hogehoge.com/'
  $url = empty($args) ? $url : $url . '?' . http_build_query($args);
  $arr = wp_remote_get($url);

  if (is_wp_error($arr) || $arr['response']) {
    // エラー処理
    ...
  }

  $body = json_decode($arr['body']);

  // 以下省略
  ...
}
add_shortcode('hogehoge', get_remote_by_hogehoge);

...

これで投稿ページ等に[hogehoge]と追加した場合に、データが表示されます。

また、[hogehoge param1=test]等、引数を指定した場合には http://hogehoge.com/?param1=testのように、クエリパラメータを付与できるようにしてみました。

ユーザーストーリーマッピングで大規模改修のプランニングをやってみた

f:id:mikeda3:20160512162456j:plain こんにちは! iettyのデザイナー池田です。

今回はユーザーストーリーマッピングの紹介です!

iettyは2012年2月創業から4年、サービスを支える管理画面を要望に合わせてつぎたしつぎたし作っていましたが、 全体像がわかりづらくなってきました…。長く運営されているサービスならよくあることだと思います。

今まで山ほど積もっている改善要望、いつかやりたいと思っていたこと、全部の夢をまとめた「さいきょうのかんりがめん」にしたい!! でもどこから手をつけていいのかわからない……

そんな問題を解決すべく、管理画面の大規模改修プロジェクトの計画フェーズにユーザーストーリーマッピングを取り入れてみましたので紹介します!

続きを読む

Tips for rails4-autocomplete

github.com

rails4-autocomplete is a very useful gem for textfield auto complete function, but it's not maintained so use it on your own judgement, or use https://github.com/bigtunacan/rails-jquery-autocomplete.

Using rails4-autocomplete let textfield add auto complete function easily.

You can use scope to restrict search result as README says, but sometimes you want to restrict search result by id as well.

So, how do I achieve this?

In controller which you want use auto completion, override get_autocomplete_items like below.

def get_autocomplete_items(parameters)  
    super(parameters).where(some_id: some_ids)
end

Also, you can customize autocomplete suggestions.

To override the autocomplete_xxx_name method which generates automatically like below does the trick.

def autocomplete_xxx_name
    term = params[:term]
    models = Model.joins(other_model).some_scope(term).all
    render json: models.map { |model| { id: model.id, label: model.some_column, value: model.some_column} }
 end

You can join other table, customize suggestion text and choose send value.

LINE BOT API と Riot API で遊んでみた

先着10,000名限定で公開された『BOT API Trial Account』ですが、研究開発の時間を頂けたので少し触ってみました。

そのままテストしてもつまらないので、偶然持っていたLeague of LegendsのProduction APIを使って戦績を返すBOTを作ってみました。

とりあえず準備

LINE BOT API

アカウントの取得方法やAPIの使い方などは、この記事が分かりやすかったので見てください。 qiita.com

Callback先にはSSL証明書(Let's Encrypt以外の)が必須らしいので、とりあえず僕の開発用のサーバをCallback URLに指定。

Riot API

Development APIはRiot Games APIからすぐ作れます。

僕の持ってるProduction APIは申請から承認まで3週間ほどかかるのですが、日本サーバにアカウントを移動させたタイミングで使えなくなってたので問い合わせたらすぐに対応してくれました。 f:id:tioken12:20160415194358p:plain

サーバ

ずっと昔に作って放置してたCodeigniterの環境にLINE BOT用のコントローラーを設置し、さきほどのQiitaの投稿をベースに書いてきます。

<?php
public function index() {
  // アカウント情報設定
  $this->channel_id = "[チャンネルID]";
  $this->channel_secret = "[チャンネルシークレット]";
  $this->mid = "[MID]";

  // メッセージ受信
  $json_string = file_get_contents('php://input');
  $json_object = json_decode($json_string);
  $this->content = $json_object->result{0}->content;

  $event_type = "138311608800106203";

  $this->_api_post_request("/v1/events", $event_type, json_encode($this->_create_text($this->_get_summoner_data($this->content->text))));
}

private function _create_text($text) {
  $text = array(
    'toType' => 1,
    'contentType' => 1,
    'text' => $text,
  );

  return $text;
}

private function _api_post_request($path, $event_type, $content) {
  $url = "https://trialbot-api.line.me{$path}";
  $headers = array(
    "Content-Type: application/json",
    "X-Line-ChannelID: {$this->channel_id}",
    "X-Line-ChannelSecret: {$this->channel_secret}",
    "X-Line-Trusted-User-With-ACL: {$this->mid}"
  );

  $post = <<< EOM
{
"to":["{$this->content->from}"],
"toChannel":1383378250,
"eventType":"{$event_type}",
"content":{$content}
}
EOM;

  $curl = curl_init($url);
  curl_setopt($curl, CURLOPT_POST, true);
  curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
   $output = curl_exec($curl);
}

$this->content->text にチャットの内容が入ってくるので、それをサモナー検索用のメソッドに投げて、返ってきた値をcreate_textメソッドに投げることでcallback用の配列に格納し、api_post_requestで $this->content->from に入っているチャットルームIDに向けてメッセージを送信しています。

できたのがこれ

LOL Summoner Info

f:id:tioken12:20160415201310p:plain

チャットで入力したサモナーの戦績をRiot APIから取得して返してくれます!

まだLINE BOT APIがトライアルということもあり、50人までしかフレンドに登録できませんがもしよかったら追加して遊んでみてください。 f:id:tioken12:20160415202007p:plain