TES Blog

株式会社テクニカルエンジニアリングサポートに所属する社員が、自身が携わるテクノロジーやイベントに関する情報を発信しています。

jQuery を使わずに、記事のシェア数を表示するソーシャルパーツをフラットデザインっぽくカスタマイズする

はじめに

TES で Web エンジニアをしている Hayato Yamashita です。

今回は、はてなブログのソーシャルパーツをフラットデザインっぽくカスタマイズする方法を紹介します。

カスタマイズ後の見た目

こんな感じの見た目になります。
こういうカスタマイズをしたい、どうやってカスタマイズするのか知りたい、という方は本記事をご覧ください。

f:id:h-yamashita:20180402135652p:plain

この記事のポイント

  • ソーシャルパーツをフラットデザインっぽくカスタマイズできる
    • コピペで使える!
  • はてなブックマークと Facebook のシェア数を表示できる
    • jQuery を使わず IE11 対応!
  • 簡単なコード解説付き
    • 理解しやすいかも
続きを読む

jQuery を使わずに、はてなブログの外部参照リンクを target="_blank" にする方法

はじめに

TES で Web エンジニアをしている Hayato Yamashita です。

最近 TES では、外部情報発信の取り組みとして TES Blog を開設しました。
既にいくつか記事をあげていますので、良かったら他の記事も読んでみてください。

記事一覧 - TES Blog

さて、その開設にあたって私の方でいくつか設定をしていたのですが、社員より以下の要望をもらいました。

href の飛び先を別タブにすることは可能?

こちらの方法を調べましたので、記事として共有します。

続きを読む

外部公開サーバがブルートフォース攻撃されているか確認する

こんにちは。インフラの業務をさせて頂いている者です。

だんだん春らしく暖かくなってきましたね。
花粉症の方はこれから一緒に頑張りましょう!

さて、今回は…

f:id:manabkr:20180314160410j:plain

 外部公開しているサーバにブルートフォース攻撃がされているかチェックしてみたい

…と思います。

対象となる読者

  • 外部公開のWebサーバを立ててみたけど何をしたらいいのか分からない方
  • 自身のサーバにどんなSSHブルートフォース攻撃がされているか確認したい方
続きを読む

TwitterAPIで使うアクセストークンが勝手に消えたお話

Twitter APIとの連携で、Twitter Application Managementでトークンを発行して自分のアプリケーションで利用することは多いと思う。

私もTwitter APIを利用してTwitterのBotを作っていたのですが、アプリケーション環境で突如Twitterとの接続でエラーが出るようになった。

Spring Boot エラー内容

2018-02-11T20:14:14.911250+00:00 app[web.1]: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://api.twitter.com/1.1/statuses/update.json": cannot retry due to server authentication, in streaming mode; nested exception is java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode

エラー内容でググってみたら、 callbackUrl を設定したら直るとあったので試してみたがダメ…。

解決方法

色々見てる内に、Twitter Application ManagementKeys and Access Tokens 画面でアクセストークンが消えてることに気がついた。 再度取得し直して、アプリケーション上のトークンを更新してあげたらちゃんと動くようになった。

アクセストークンの再追加時にエラーメッセージで「既に存在するぞ!!」って何故か怒られるが、新しいアクセストークンが発行される。 以前使用していたアクセストークンとは別のものになっているため、アプリケーションで使用していたトークンの更新を忘れないようにすること。

もし同じような状況になったら、アクセストークンが消えていないか確認してみてください。

サーバー環境にある権限のついたファイルをローカル環境にコピーする方法

nginxのログファイルをサーバーからローカル環境に持ってこようとした時に、 Permission denied でエラーとなってしまったのでその時に行なった対策を載せます。

下記参考にさせていただきました。ありがとうございます!!

sshでやる

コピー対象のファイル内容が、ローカル環境で指定したファイルにコピーされます。

ssh -t {{ ホスト名 }} "echo {{ sudo password }} | sudo -S cat /var/log/nginx/access.log" > {{ ローカル側のコピー先ファイル }}

※ 上記コマンドでは echo コマンドによりパスワードの文字列が履歴に残ってしまうため、セキュリティリスクが高まります。利用には細心の注意が必要です。

scpでやる

1.対象のファイルをホームディレクトリにコピー

安全に作業を行うため、一旦ホームディレクトリにコピーする。

ssh {{ ホスト名 }}
sudo cp /var/log/nginx/access.log ~/

2.所有者の変更

ホームディレクトリにコピーしたファイルの権限を自分に書き換える。

# ユーザー名確認
whoami
# 所有者の変更
sudo chown {{ ユーザー名 }} access.log

3.SCPでサーバーからローカルに持ってくる

権限を変更したファイルを、ローカル環境の適当なディレクトリにファイルごとコピーする。

scp {{ ユーザー名 }}@{{ ホスト名 }}:~/access.log {{ ローカルディレクトリ }}

4.ホームディレクトリにコピーしたファイルを削除

コピーが終わったら、ホームティレクトリにコピーしたファイルは不要なので削除する。

rm access.log

Gitコマンドあれこれ

個人的に忘れっぽいコマンドとか、あまり普段使わないようなコマンドを備忘録として載せます。

git rebaseの使い方

コンフリクト解消した後どうするんだっけ…ってたまになる。

1.マスターを最新化する

git checkout master
git pull

2.トピックブランチにリベースする

git checkout {{ トピックブランチ名 }}
git rebase master

3.リベースした時にコンフリクトが発生時

# コンフリクトを解消
git add .
git rebase --continue

4.コンフリクト解消後すでにリモートにpushしてある時

# リベースコンテニュー後に下記を実行
git push -f origin {{ リモートブランチ名 }}

※force pushなので気をつけること

Git Stashの使い方(編集内容一時退避)

編集内容を退避させる

git stash save

※saveは省略可能

退避した内容の復活と、復活させたstash内容の削除を同時に行う

git stash pop stash@{0}

※最新の退避内容を復活&削除したい場合は stash@{0} が不要

複数行のコミットコメントを行う

git commit -F- <<EOM
> コミットコメント要約
>
> コミットコメント詳細
> 詳細あれこれ
> EOM

対象ブランチ間同士の差分系

こんなに差分取ることなんて早々ない。

差分のあるファイルを対象に、ファイル名だけを取得

git diff {{ ブランチ名1 }} {{ ブランチ名2 }}  --name-only

差分の種類を取得(追加・更新・削除など)

git diff --name-status {{ ブランチ名1 }} {{ ブランチ名2 }}

git logの表示形式で差分を取得

git log -p {{ ブランチ名1 }}...{{ ブランチ名2 }}

コミットハッシュ値とコミットコメントのみの差分を取得

git log --pretty=format:"%H %s" {{ ブランチ名1 }}...{{ ブランチ名2 }}

ソースレベルでブランチ同士の差分を取得

git diff {{ ブランチ名1 }} {{ ブランチ名2 }}

空コミットを行ってPRを作成する

プルリク駆動で便利!

1.--allow-emptyで空のコミットを作成

git commit --allow-empty -m "PR作成用空コミット"

2.通常どおりpushする

3.空コミットでpushされたブランチでPRを作成

4.その後、コミットしたい部分をaddする

5.次に変更を行った部分をコミットする場合、--amendで空コミットを上書き

git commit --amend -v

6.force pushで空コミットしたブランチに対応した内容を反映させる

git push -f origin {{ リモートブランチ名 }}

※force pushなので気をつけること

指定ファイルをgitの追跡対象から外す

1.除外する

git update-index --assume-unchanged {{ ファイルパス }}

2.除外を解除する

git update-index --no-assume-unchanged {{ ファイルパス }}

3.除外しているファイルを確認する

git ls-files -v | grep ^h

直前のコミット取り消し

コミットの取り消しとワークディレクトリの編集内容も削除

git reset --hard HEAD^

ワークディレクトリの内容はそのままでコミットだけ取り消し

git reset --soft HEAD^

※ステージングに上げた状態(addした状態)になる

そこからadd状態を取り消すなら

git reset

cherry-pickの使い方

コミット単位でcherry-pick

単一のコミット内容のみ反映する。

git cherry-pick 1 {{ コミット番号 }}

マージコミット単位でcherry-pick

-m オプションを使用する。

git cherry-pick -m 1 {{ マージコミット番号 }}

マージ単位となるので、例えば一つのPRに複数件のコミットがある場合は、すべてのコミット内容が反映対象になります。

[JavaScript]イベントにもasync/awaitを使おう

はじめに

ECMAScriptが2015年から毎年バージョンアップするようになり、JavaScriptの仕様は大きく変わりました。 特に非同期処理まわりは、Promise(ECMAScript2015~)、async/await(ECMAScript2017~)が導入されたことで、 コールバック地獄の回避や可読性の向上などを実現できるようになりました。

また、JavaScriptではクリックやマウスホバーなどのイベントを検知する機能があります。 通常、イベント登録時に、イベント発火時に実行される処理をコールバックとして渡します。 実は、この従来の書き方をasync/awaitに置き換えると、一見すると同期処理的に書けるようにできます。

本記事では、以下の例のように、async/awaitへ置き換える話を説明します。

// いままでの書き方
const target = document.querySelector("#button");
target.addEventListener("click", () => {
  alert("クリックされた!");
});
// async/awaitを使った書き方
const target = document.querySelector("#button");
// ↓async/awaitを使えるように定義した関数(詳細は後述)。
// クリックされるまで、次の処理へ進まず非同期的に待機する。
await awaitForClick(target);
alert("クリックされた!");

考え方

awaitは、Promiseがsuccessされるまで、後続の処理へ進みません。 よって、イベント発火時にPromiseをresolveさせれば良いことになります。 具体的には、こんな感じです。
※今回はクリックイベントに限定していますが、抽象化すれば他のイベントでも応用出来ると思います。

const awaitForClick = target => {
  return new Promise(resolve => { // 処理A
    const listener = resolve;     // 処理B
    target.addEventListener("click", listener, {once: true}); // 処理C
  });
};

処理A:awaitForClick関数は、awaitで待機させるようPromiseのインスタンスを返すようにします。
処理B:イベント発火時にPromiseをresolveするリスナー(コールバック)を定義します。
処理C:処理Bで定義したコールバックを使って、イベント登録します。

これによって、awaitForClick関数は、引数に渡した要素がクリックされるまで、 次の処理へ進まなくなります。

なお、{once: true}で登録すると、1度しか発火しなくなります。 今回、それをオプションで渡しているのは、resolve関数を2回以上呼んでも意味が無いためです。 (resolve関数は、2回目以降何も起こりません)

使用例

クイズの回答を入力する画面で使うケースを紹介します。

JSFiddleでも動かせます。https://jsfiddle.net/fu0c3rnu/22/

<div id="question"></div>
<input type="text" id="user-input">
<button id="answer-button">回答!</button>
(async () => {
  const awaitForClick = target => { // 処理A
    return new Promise(resolve => {
      const listener = resolve;
      target.addEventListener("click", listener, {once: true});
    });
  };

  // 処理B
  const quiz = [
    {question: "日本で一番北に位置する都道府県は?", answer: "北海道",},
    {question: "日本の通貨は「円」。では、中国は?", answer: "元",},
    {question: "与えても無駄という意味のことわざ「豚に○○」。○○とは?", answer: "真珠",},
  ];

  let points = 0;
  for (const {question, answer} of quiz) {
    $("#question").text(question);               // 処理C
    await awaitForClick($("#answer-button")[0]); // 処理D
    const input = $("#user-input").val();        // 処理E
    if (!input || input !== answer) {            // 処理F
      alert(`残念!答えは${answer}でした!`);
    } else {
      points++;
      alert("正解です!");
    }
  }
  alert(`あなたの点数は${quiz.length}点中、${points}点でした!`); // 処理G
})();

処理A:awaitForClick関数を定義します。
処理B:出題する問題を定義します。
処理C:問題文を画面上に出します。
処理D:引数に渡しているボタン要素がクリックされるまで待機します。
処理E:入力された文字列を取得します。
処理F:答え合わせをし、アラートを出します。合っていれば点数を加算します。
処理G:点数をアラートで表示させます。

見ての通り、上から順番に実行されており、同期的処理のコードのように見えます。 処理の流れが追いやすく直感的なので、可読性が上がることが期待できますね。

おわりに

async/awaitを使うことで、同期処理ぽく書けるやり方を説明しました。 また、使用例としてクイズの回答を入力する画面を提示しました。 今回詳しく見ていませんが、モーダルウィンドウでも、いい感じに使えます。
https://jsfiddle.net/njny5xxo/3/

なお、今回のやり方はasync/awaitを実装しているブラウザでしか使えません。 各ブラウザの対応状況は、こちらで確認できます。
https://caniuse.com/#feat=async-functions
例によって、IE11では使えませんので、Babelなどを使う必要があります。