カテゴリー: プログラミング Page 1 of 8

SlackAPIを使って簡単なTODOチェックアプリを作成してみた

WEBエンジニアの石田です。
さて、僕は前回もSlackネタでしたが、今回もSlackネタです。

弊社では、お掃除部という部活(?)がありまして、拭き掃除・ゴミ出し・換気などのオフィス内の掃除、あと朝一のコーヒー作りを有志が毎日行っています。
当番とかは決まっておらず、できるメンバーでやろう!というスタンスなのですが、部員の大半を占めるエンジニア達はフレックス制で出社時間がバラバラ…
となると、チェックリストは欲しいですよね。

紙とかホワイトボードでチェック!となるのがまあ普通だと思いますが、弊社はIT企業。そして社内のコミュニケーションにSlackを使ってるんだから、せっかくならオンラインで済ませてしまいたい。という欲が僕の中で沸々と湧き上がってきたので、SlackAPIを使ってアプリ作りました(・ω・)b

まずは出来上がったものをご紹介します。

f:id:seeds-std:20190425000202g:plain
ボタンをクリックすると名前が登録され、同じボタンを押すと登録が解除されます

仕組み

  • AM9:00になるとタスク一覧と、項目ごとの絵文字のボタンが並んでいるメッセージが自動投稿される。
    • cronで平日毎日9:00にpostするAPIを叩く
  • タスクの絵文字ボタンをクリックすると、クリックしたユーザーのIDがタスク一覧の下に表示される。
  • 既にボタンをクリック済みのユーザーが、もう一度同じ絵文字のボタンをクリックするとタスク一覧の下に表示されていた名前が消える。
    • 絵文字のボタンを押すとSlack から指定したURLにリクエストが送られ、リクエストに応じて処理し、メッセージを書き換えるAPIを叩く

今回つかったもの

  • PHP
  • MySQL
  • Slack API
    • Interactive Components

やってみる

1. Slack APIでAppを作成

  • Interactive Components
    メッセージにボタンやメニューなどを付与し、ユーザーからのアクションに応じて応答できる機能です。
    GitHubやBitBucketのAppをはじめ、最近とても頻繁に使われているので多分見たことあるのではないでしょうか。

https://api.slack.com/apps?new_app=1

f:id:seeds-std:20190610212654p:plain
AppNameは後から変更も可能でした。

上記のURLにアクセスすると、SlackAppの作成画面が出るので AppName (アプリ名) と Development Slack Workspace (使用するSlackのワークスペース) を指定し、 Create App します。
SlackでAPIを作成すると、FeaturesにInteractive Componentsという項目があり、Onにすると設定が可能になります。
f:id:seeds-std:20190610213057p:plain
設定は色々とありそうですが、今回は Request URLに任意のURL( example.com/api/hogehoge.php など)を貼ればOK。

あと、投稿用にSlackのトークンを取得しておきます。
OAuth & Permissions からScopesを絞って Install App。 Permission Scopeはchat:write:botを選択でOKです。

f:id:seeds-std:20190725210251p:plain
権限はchatだけでok
f:id:seeds-std:20190725210349p:plain
Permissionを設定したらInstall App

これでSlack上の設定は完了。

2. サーバー側の設定

とりあえずmysqlでDBを用意。型は適当につけてます

CREATE TABLE polls
(
id          INT AUTO_INCREMENT PRIMARY KEY,
message_ts  VARCHAR(255) NOT NULL,
channel_id  VARCHAR(255) NOT NULL,
text        TEXT         NOT NULL,
answers     TEXT         NOT NULL,
attachments TEXT         NOT NULL,
created_at  TIMESTAMP    NULL
) DEFAULT CHARSET = utf8 AUTO_INCREMENT = 1;
CREATE TABLE votes
(
id          INT AUTO_INCREMENT PRIMARY KEY,
channel_id   VARCHAR(255) NOT NULL,
message_ts   VARCHAR(255) NOT NULL,
user_name    VARCHAR(255) NOT NULL,
user_id      VARCHAR(255) NOT NULL,
action_name  VARCHAR(255) NOT NULL,
action_value VARCHAR(255) NOT NULL,
created_at   TIMESTAMP    NOT NULL
) DEFAULT CHARSET = utf8 AUTO_INCREMENT = 1;

貼り付けた任意のURLではなく、まずpublicの外にでも投稿用のファイルを作成します。
postの第一引数の連想配列が選択肢です。nameに表示する文字を入れて、 iconはslackのアイコンの名前を入力(::はとる)でOK。なくてもOK。

<?php
post([
['name' => '換気',    'icon' => 'wind_blowing_face'],
['name' => 'ゴミ出し',    'icon' => 'wastebasket'],
['name' => '拭き掃除',   'icon' => 'sparkles'],
['name' => 'コーヒー', 'icon' => 'coffee'],
] , '今日のTODO');
function post($questions, $description) {
$attachments = [];
$buttons = [];
$text = $description . "\n";
// answersが表示テキスト、buttonsが実施ボタンになる
$answers = [];
foreach ($questions as $key => $button) {
$answers[] = ':' . $button['icon'] . ': ' . $button['name'];
$buttons[] = [
'name' => $button['icon'] ?? ($key + 1),
'text' => ':' . ($button['icon'] ?? ($key + 1)) . ':',
'type' => 'button',
'value' => $button['name']
];
}
// ボタンは5つを超えるとattachmentがスマホで表示できなくなるためを分割しておく
$block = array_chunk($buttons, 5);
// タスクごとに改行する
$text .= implode("\n", $answers);
// ボタンのブロックごとにattachmentを作成する
foreach ($block as $key => $action) {
$attachments[] =
[
'fallback' => 'daily' . $key,
"callback_id" => "daily",
"color" => "#3AA3E3",
"attachment_type" => "default",
'actions' => $action
];
}
// Slackに投稿を行う
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_URL => 'https://slack.com/api/chat.postMessage',
CURLOPT_HTTPHEADER => [
'Content-Type: application/json; charset=utf-8',
'Authorization: Bearer ' . '【SLACKのトークン】'
],
CURLOPT_POSTFIELDS => json_encode([
'channel' => '【投稿チャンネル】',
'text'    => $text,
'attachments' => $attachments
])
]);
$response = curl_exec($curl);
$response = json_decode($response, true) ?? null;
if ( !$response ) {
return false;
}
//投稿情報をMySQLに保存しておく
$db = new PDO(
'mysql:host=' . '【接続するホスト】' .';dbname=' . '【DB名】' . ';charset=utf8',
'【DBユーザー名】', '【DBパスワード】', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
$query = $db->prepare('INSERT INTO polls (message_ts, channel_id, text, answers, attachments, created_at) VALUES (:message_ts, :channel_id, :text, :answers, :attachments, :created_at)');
$query->execute([
':message_ts'  => $response['ts'],
':channel_id'  => $response['channel'],
':text'        => $description,
':answers'     => json_encode($answers),
':attachments' => json_encode($response['message']['attachments']),
':created_at'  => date('Y-m-d H:i:s')
]);
return $response;
}

上記のPHPファイルを実行すると指定したチャンネルに下記のようなフォームみたいなものが投稿されます。

f:id:seeds-std:20190809175228p:plain

各ボタンをクリックすると、先程のURLのhoge.phpにPOSTが走るので、下記を配置しておきます。

<?php
if (!empty($_POST['payload'])) {
$vote = json_decode($_POST['payload'], true);
$message = $vote['message_ts'];
$channel = $vote['channel']['id'];
$user_id = $vote['user']['id'];
$username = $vote['user']['name'];
$db = new PDO(
'mysql:host=' . '【接続するホスト】' .';dbname=' . '【DB名】' . ';charset=utf8',
'【DBユーザー名】', '【DBパスワード】', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
$query = $db->prepare('SELECT * FROM polls WHERE message_ts = :message_ts AND channel_id = :channel_id');
$query->execute([
':message_ts'   => $message,
':channel_id'   => $channel
]);
$data = current($query->fetchAll());
if ($data) {
$attachments = json_decode($data['attachments'], true);
//既に存在する実施TODO・実施者IDとボタン押した人の実施TODO・IDが一致したら存在フラグをたてる
$votes = selectVotes($db, $message, $channel);
$exist = false;
foreach ($votes as $answer) {
if ($answer['user_id'] === $user_id && $answer['action_value'] === $vote['actions'][0]['value']) {
$exist = $answer['id'];
}
}
//存在フラグが立ってる場合は削除・ない場合は新規挿入
if ($exist) {
$db->prepare('DELETE FROM votes WHERE id=:id')->execute([':id' => $exist]);
} else {
$db->prepare('
INSERT INTO
votes
(channel_id, message_ts, user_name, user_id, action_name, action_value, created_at)
VALUES
(:channel_id, :message_ts, :user_name, :user_id, :action_name, :action_value, :created_at)')
->execute([
':channel_id'   => $channel,
':message_ts'   => $message,
':user_name'    => $username,
':user_id'      => $user_id,
':action_name'  => $vote['actions'][0]['name'],
':action_value' => $vote['actions'][0]['value'],
':created_at'   => date('Y-m-d H:i:s')
]);
}
// 投稿したTODOの現在の実施者一覧を出す
$votes = selectVotes($db, $message, $channel);
$result = [];
$answers = json_decode($data['answers']);
foreach ($answers as $answer) {
$result[$answer] = '';
foreach ($votes as $vote) {
if ($answer === ':' . $vote['action_name'] . ': ' . $vote['action_value']) {
$result[$answer] .= ' <@' . $vote['user_id'] . '>';
}
}
}
// 実施者一覧をメッセージに反映する
$text = $data['text'];
foreach ($result as $answer => $voters) {
$text .= "\n" . $answer . "\n";
$text .= empty($voters) ? '' : $voters . "\n";
}
$update = [
'channel' => $data['channel_id'],
'ts' => $data['message_ts'],
'text' => $text,
'attachments' => $attachments
];
// Slackのメッセージを更新する
$url = 'https://slack.com/api/chat.update';
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_URL => $url,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json; charset=utf-8',
'Authorization: Bearer ' . '【SLACKのトークン】'
],
CURLOPT_POSTFIELDS => json_encode($update)
]);
return curl_exec($curl);
}
}
function selectVotes(PDO $db, string $message_ts, string $channel_id)
{
$query = $db->prepare('
SELECT
*
FROM
votes
WHERE
message_ts = :message_ts AND
channel_id = :channel_id
ORDER BY
action_value
');
$query->execute([
':message_ts'   => $message_ts,
':channel_id'   => $channel_id
]);
return $query->fetchAll();
}

送られてきたpostの中にユーザーID・ボタンを押したmessageの情報・押したボタンの情報があるので、それを照合し、あれば削除(MySQLから既存レコードをDELETE)・なければ作成(MySQLにINSERT)し、元のメッセージを状況に合わせて更新することで投票を実現しています。

所感

プログラムの部分で長くはなってしまいましたが、これでTODOアプリは完成です。シーズでは毎日の日次タスクと、月曜日に週次タスクを投稿する形で運用してますが、今のところ問題なく稼働しています。
こういったTODOリストの共有やリマインダ、GitHub/BitBucketの連携など、SlackAPIを応用することで、手軽に様々な機能を日々のコミュニケーションの中に自力で追加できるのはとても魅力的だと感じました。

アイデア次第ではもっと面白いことができそうなSlackAPI、もっと色々な活用方法を見出して社内に還元していきたいなあ…と目論んでおります!

AWS IoT Enterprise Buttonを使ってSlackに通知を送ってみた

はじめまして!18年度新卒・WEBエンジニアの石田です。

弊社のコーヒーメーカーがリニューアルされ、コーヒーを淹れる機会がすごく多くなりました。
しかし、コーヒーメーカーができてから30分で保温が切れる設定で、
・追加で保温ができない…
・どうせならできたてが飲みたいけど、できたタイミングが分かりにくい…
・かといっていちいちSlackにコーヒーできましたって書くのもめんどくさい!
→自動投稿させたい!
→→ボタンワンクリックで済ませたい!

ということで、会社にAmazon「AWS IoT Enterprise Button」を買ってもらい、折角なのでクリエイターズブログに投稿することにしました!

f:id:seeds-std:20181105211732j:plain
新コーヒーメーカーと「AWS IoT Enterorise Button」

新コーヒーメーカーと「AWS IoT Enterorise Button」

AWS IoT Enterorise Button

ワンプッシュで商品が注文できる!と話題になった Amazon Dash Buttonをベースにした、自由にプログラムを動作させることのできるボタンです。
ボタンのクリックをトリガーに、AWSのサービスに接続できます。すごい。

f:id:seeds-std:20181105212349j:plain
ちっちゃいです

モバイルアプリを使ってWiFiの設定ができ、ステータスも確認可能。

f:id:seeds-std:20181105213458p:plainf:id:seeds-std:20181105221850p:plain
iOSアプリ「AWS IoT 1-Click」

何度か設定してみたのですが、デバイスリージョンはオレゴン一択なのでしょうか。東京リージョンに変更できませんでした。

そこからAWS IoT 1-Clickというサービスを選択し、プロジェクトを作成することでデバイスの動作を定義することができます。

選択できるのは
・SMSの送信
・Eメールの送信
・Lambda関数の選択
Slackに自動投稿したかったのでLambda一択でしたが、SMS・Eメール送信も色々使えそうで良いですね。

あとはLambdaでjavascriptを使ってwebhookにPOSTすれば投稿完了!

exports.handler = function(event, context) {
const slack = (params) => {
let https = require('https');
let host = 'hooks.slack.com';
let data = JSON.stringify({"text": params['message']});
let options = {
hostname: host,
port: 443,
path: params['path'],
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(data)
}
};
let req = https.request(options, (res) => {
console.log('status code : ' + res.statusCode);
res.setEncoding('utf8');
res.on('data', (d) => {
console.log(d);
});
});
req.on('error', (e) => {
console.error(e)
;});
req.write(data);
req.end();
};
var post = function() {
return slack({
path: 'hogehogehogehogehoge',
message: 'コーヒーができました:coffee:'
});
};
setTimeout(post, (60 * 6 * 1000));
};

f:id:seeds-std:20181105221032p:plain
アイコンはデザイナー・コウノ氏が作ってくれました!かわいい

6分で完成するので、その分だけタイムアウトさせるようにしています。
起動時間は5分までだと思ってたからどうしようかな…と思っていたのですが、15分までいけるようになっていたのが驚きでした。

IoT ButtonやLambdaを触ったのははじめてだったので時間がかかりましたが、セットアップからSlackに投稿できるようになるまで1時間ほど。すごく簡単でした。
他にもいろいろな使い方ができそうですね。シーズでは早速、更に2台のIoT Buttonを追加購入しました(笑)
社内でアイデアを募ってどういう使い方をしようかと思案中です!

【デーモン化で解決!】WEBrickでRedmineを立ち上げるとpost時に真っ白になる

f:id:seeds-std:20161108200910p:plain

どうも、はらぐちです。

今回は、
「WEBrickでRedmineを立ち上げると、なぜかpostした時だけ真っ白になってしまう」という件について、
解決法をご紹介します。
rails力が足りなくてハマった感じですが……

経緯

シーズではプロジェクト管理ソフトのひとつにRedmineを使用しているのですが、
最近、古いサーバー上のRedmineを、最新OSを搭載した新しいサーバーに移行することになりました。

1.データをそのままごっそり持ってきて、
2.mysqldumpをリストア、
3.rbenvで該当バージョンをそろえて、
4.gemも同じバージョンを入れていったのですが、

どうしても、Passengerだけがうまく使えない……

そこで、WEBrickで起動し、apacheのリバースプロキシ経由で参照するように設定をしてみました。

おおむねこれでうまく動いていたのですが、
なぜかPostした時だけ真っ白なページになる状態に……
(※真っ白なページにはなりますが、更新自体はされている。)

解決法

いろいろ調べてみた結果、
そのままフォアグランドで起動するとうまくいくのにバックグラウンド実行するとうまくいかない事がわかりました。
そこからはWEBrickのドキュメントなどを参照して、-dオプションでデーモン化で立ち上げる事が可能と判明。
以下のような起動方法で問題なく動作しました

/path/to/redmine/script/server -d -e production

デーモン化は知りませんでしたが、バックグラウンド実行だと何故こんな動きになるんでしょうね?
ひとまずはデーモン化で解決しました!

FuelPHP はじめました。複雑な 独自validation 設定には Closure を使おう

Fuel PHP

ども。Webエンジニアの ishino です。

最近 FuelPHP を触る機会が増えてきたのていたので、学んだことを少しづつに記事にしていこうと思います。
珍しく、真面目にプログラムのこと書きましたので、よろしくお願いします。

FuelPHPとは?

FuelPHPはPHPで書かれたオープンソースのHMVCパターンを使うフレームワークです。
フレームワークは基本的な機能が揃っているので、高速にアプリケーションを開発することができます。
PHPのフレームワークにはたくさんの種類がありますが、中でもFuelPHPは比較的新しく、軽量で中規模のアプリケーションの開発に向いていると言われています。

validationの基本

FuelPHPは、POSTされた値の内容に対して、かんたんにvalidationをかけることができます。
必須項目の入力チェックは

$val = Validation::forge();
$val->add('name', '名前')
->add_rule('required');

でOKです。

ただ、複雑なvalidationチェックを行うには、自分で設定しなければなりません。
はじめは、この書き方が分からず、調べましたのでここに書いておきます。

複雑な 独自Validation 設定には Closure を使う

$option['name'] = 'hoge';
$val = Validation::forge();
$val->add('name', '名前')
->add_rule(['validation_name' => function($name) use ($option) {
if ($name != $option['name']) {
Validation::active()->set_message('validation_name', '「:label」が正しくありません');
return false;
} else {
return true;
}
}]);

このようにClosureを使うことで、独自validationを記述できるようになります。

また、functionの引数にはPOSTの値が、
その他でvalidtionで使うパラメータはuseで渡すことも可能です。

また、独自Validationを複数設定する時は、Closureに名前を設定しないとエラーメッセージが上書きされてしまうので、
上のコードのように名前を設定しておくといいですよ。

◎下の記事が参考になりました。
FuelPHPのValidationにクロージャを使う
FuelPHPを更に使ってみて使えるなと思った拡張ValidationRuleの書き方とCore拡張の小技

【COALESCE関数で解決!】MySQLで値が NULL のデータを集計(count)したい

MySQL

どうも、はらぐちです。

本来は NULL を撲滅すべきなのですが、
MySQLで値が NULL のデータを、どうしても集計(count)してみたくなったもので……

というわけで、やってみました!

やりたかった事

以下のようなテーブルとデータがあるとして

テーブル data
+-------+
| value |
+-------+
| aaa   |
| aaa   |
| aaa   |
| aaa   |
| bbb   |
| bbb   |
| NULL  |
| NULL  |
| NULL  |
+-------+

それぞれの値の数を集計するために、以下のSQLを実行したら

SELECT value,count(value) FROM data GROUP BY value;

結果

+-----------+--------------+
| value     | count(value) |
+-----------+--------------+
| NULL      |            0 |
| aaa       |            4 |
| bbb       |            2 |
+-----------+--------------+

NULLのカウントは 0 になって集計できない……
これをなんとか集計したい!

解決策

COALESCE関数を使う

引数を順番に評価し、NULL と評価されない最初の式の現在の値を返し、
すべての引数がNULLの場合はNULLを返すという関数です。

例えば以下の場合

COAESCE(value,value2,'abc')

valueカラムが null の場合は value2 を返す。
value2も null の場合は ‘abc’ という値を返す

という動きになります。

これを踏まえて、はじめのSQLを以下のように編集

SELECT value,count(COALESCE(value,'')) FROM data GROUP BY value;

結果

+-----------+---------------------------+
| value     | count(COALESCE(value,'')) |
+-----------+---------------------------+
| NULL      |                         3 |
| aaa       |                         4 |
| bbb       |                         2 |
+-----------+---------------------------+

値が NULL のレコード数がカウントできました!
ばんざい。

Vagrantのboxサイズを拡張する

提供されているboxが8GBしかなかったので拡張したのですが、結構大変だったのでメモします。

ディスクの拡張

boxから普通にインスタンスを作成。
インスタンスを作成したらシャットダウンして作業を行います。

VirtualBoxではディスクサイズが可変のタイプは .vdiなのですが、
Vagrantのboxとできるディスクタイプはvmdkとなります。
まずは、現在のvmdkディスクをクローンしてvdi形式のディスクを作成します。

その後、カレントディレクトリを作成した仮想サーバのディスクがある所まで移動して

VBoxManage clonehd "box-disk1.vmdk" "clone-box-disk1.vdi" --format vdi

クローンしたディスクの容量を拡張します。ここでは20GBにしたいと仮定して20480を設定しています。
(20(GB) * 1024(MB) = 20480)

VBoxManage modifyhd clone-box-disk1.vdi --resize 20480

次に、ディスク拡張されたvdiをvmdkにクローンします。

VBoxManage clonehd "clone-box-disk1.vdi" "box-disk2.vmdk" --format vmdk

拡張したディスクを差し替えます。
この作業は、VirtualBoxから行ってもいいかもしれません。
–port 0 –device 0 の部分はbox-disk1.vmdkが入っていたものを指定します。
ちなみに、server_default_1448874918650_80404 は仮想サーバー名です。

VBoxManage storageattach server_default_1448874918650_80404 --storagectl "SATA" --port 0 --device 0 --type hdd --medium box-disk2.vmdk

この設定を行った後、起動してみて無事に起動すればOKです。
確認できたら、またまたシャットダウンします。

パーティション操作

現在ディスクは20GBに拡張しましたが、パーティションは8GBまでしか使用されていない状態です。
パーティションを操作して、8GBを20GBに拡張します。

新たに作成された box-disk2.vmdk を適当な仮想サーバにアタッチします。
アタッチ後、lsblkコマンドでディスクの様態をチェック。

# lsblk
NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda    202:65   0   8G  0 disk /
└ sda1 202:145  0   1G  0 part
└─sda2 202:145  0   8G  0 part
sdb    202:144  0  20G  0 disk
└ sdb1 202:145  0   1G  0 [SWAP]
└─sdb2 202:145  0   8G  0 part

今回くっつけたものはsdbとして認識されていました。
partedでパーティション操作を行っていきます。

ない場合は、 yum install parted か apt-get install partedでインストールします。

# parted /dev/sdb
GNU Parted 2.1
/dev/sdb を使用
GNU Parted へようこそ! コマンド一覧を見るには 'help' と入力してください。

表記をセクターに変更します。

(parted) unit s

現在の情報を表示します。

(parted) print
Model: ATA VBOX HARDDISK (scsi)
Disk /dev/sda: 41943040s
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Number  Start     End        Size       Type     File system     Flags
1      2048s     1953791s   1951744s   primary  linux-swap(v1)
2      1953792s  15988735s  15986688s  primary   ext4            boot

この情報はあとで使用するため、メモしておきましょう。
今回は、特にNumber2の行が重要になります。

次に、パーティションを削除します。

(parted) rm 2

パーティションを作成します。

(parted) mkpart
Partition name? []?
File system type? [ext2]? ext4
Start? 1953792s
End? 100%

パーティションサイズ以外は、元のパーティションと同じになるように修正します。

(parted) set 2 boot on
(parted) set 2 LBA off

ここまでできたら、EndとSize以外は元と同じになっているか確認します。

(parted) print
Model: ATA VBOX HARDDISK (scsi)
Disk /dev/sda: 41943040s
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Number  Start     End        Size       Type     File system     Flags
1      2048s     1953791s   1951744s   primary  linux-swap(v1)
2      1953792s  41943039s  39989248s  primary  ext4            boot

終了!

(parted) quit

20GBに拡張されていることを確認します。

# lsblk
NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda    202:65   0   8G  0 disk /
└ sda1 202:145  0   1G  0 part
└─sda2 202:145  0   8G  0 part
sdb    202:144  0  20G  0 disk
└ sdb1 202:145  0   1G  0 [SWAP]
└─sdb2 202:145  0  19G  0 part

念のため、ディスクチェックをかけましょう。

e2fsck -f /dev/sdb2

ここまでできたら、適当な仮想サーバをシャットダウンしてディスクを外します。

パーティション拡張したディスクで起動

インスタンスを起動します。

resize2fs /dev/sda2

ここで、サイズが20GBに拡張されたら完了です。

box作成

あとはVagrantfileがあるディレクトリでboxを作成して終了です。

vagrant package

Codecademyをやってみた

こんにちは、WEBエンジニアのyuchiです。

最近、WEB上でプログラム学習ができる無料のサイトがたくさん作られていますよね。
そんな多々あるサービスの中で、私は以前「Codecademy」というサービス(もちろん無料)を使って勉強してみました。

○Codecademy
http://www.codecademy.com/

普段、私は主にPHPをさわっているので、今回は違う言語にチャレンジしようと思い、
よく使われている汎用なプログラミング言語「Python(パイソン)」を選択してみました。

すると、下記のような画面が出てきます。

 

 

「Codecademy」は日本語に対応していないようなので、説明は英語で書かれています・・・

 

とりあえず説明を読みながら、黒いエディター部分にプログラムを書いて、「Save & SubmitCode」をクリックしました。

 

書いたコードがOKだったら、右上の部分に結果が表示され、プログラムが実行されます。
このように、1つクリアすると次の章に進んでいき、徐々に基礎的なプログラミングが学べるようになっていました。
誰でも気軽に始められるので、初心者の方もこういったツールをぜひ活用してみてほしいです!

以上、終わります。

MW WP Formを使って動かない時に確認したいこと

「Word Press」のコンタクトフォームと言えば「Contact Form 7」。
いつも迷うことなく利用し続けていました。
「Contact Form 7」といえば、海外で開発されているため、基本確認画面がありません
日本では確認画面が必要な案件が多く、「Contact Form 7」を使用するともれなく
カスタマイズしなければなりません。
そうなると手間がかかってしまったり、精度が落ちてしまうという問題点が….

そこで、新しく話題に上がった「MW WP Form」を試しに使ってみました!

管理画面からの設定が簡単で、とても使いやすい!
ですが、実装してみたところ動かない!?という問題にぶつかってしまいました・・・

いろいろ調べてみましたが、比較的新しいプラグインということもあり情報が少ないのが難点。
有力な情報がなく困ってしまいました。
試行錯誤した結果、なんとか解決することができたので、その際の注意点をまとめたいと思います。

1.ループの記述がない。


<p>タグが入るのが面倒で、独自テンプレートに $post->post_content; だけを記述していることが
私はよくあります。

これではショートコードは展開できないので、

[code]
if (have_posts()) :
while (have_posts()) :
the_post();
remove_filter( ‘the_content’, ‘wpautop’ );
remove_filter( ‘the_excerpt’, ‘wpautop’ );
the_content();
endwhile;
else:
<p>記事がありません</p>
endif;
[/code]

こんな感じで書くとショートコードも展開出来て、無駄な<p>タグも除去できます。

2.wp_head();とwp_footer();が足りていない。


これは、プラグインが動作しない大半の原因ですね。
独自テンプレートを作る際どうしても忘れてしまいがちなので要注意です。

3.<form></form>タグが作成したページに入っている


私は、これに一番躓いてしまいました。
フォームのページをコーディングし、WordPressに組み込む際に、管理画面にそのまま貼り付けていました。
その時に3.<form></form>が残ってしまっていたようです。

「MW WP Form」は自動でコードを挿入してくれるので、それよりも中に
<form></form>タグがあると動きません。
きちんとチェックしなくてから組み込まないといけませんね。反省。

まとめ

実装してみた感想として、基礎的なところを見落としていたことが悔やまれます。
動作さえすれば、使い勝手もよく優れたプラグインなので、今後カスタマイズなどの記事も
かけたらと思っています。

外部サイトからのDB接続について(MYSQL)

こんにちは、yagiyagiです。
早速ですが、本題に入ろうと思います。

 

外部サイトからDBサーバ(MYSQL)に接続する場合、セキュリティの観点から
通常、接続できません。権限を付与する必要があります。

GRANT ALL PRIVILEGES ON *.* TO スキーマ名@"%" IDENTIFIED BY 'passward' WITH GRANT OPTION;

ですね。ググるとよく見かけます。(詳細な説明は他サイトを参照してください)
これで、少しハマってしまった経験があるので、ご紹介したいと思います。

どういう経緯かはよく覚えていないのですが、

GRANT ALL PRIVILEGES ON *.* TO hoge@"%" IDENTIFIED BY 'passward1' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON *.* TO hoge@"192.168.1.199" IDENTIFIED BY 'passward2' WITH GRANT OPTION;

という2つのSQL文を発行しました。エラーなく正常終了します。
そして接続しようと試みたところ、コネクションエラーが発生。。。

うーーん、なぜ接続できないのだろうかと悩み、ユーザ情報を確認してみると

select user, host,password from mysql.user;
+------+---------------+----------+
| user | host          |password  |
+------+---------------+----------+
| hoge | %             |passward1 |
| hoge | 192.168.1.199 |passward2 |
+------+---------------+----------+

あれ!?パスワードが微妙に違う。。。(汗)

もうおわかりですね。
hoge/passward2で接続を試みた結果がコネクションエラーでした。。
hoge/passward1で接続するかキチンと意図した権限を付与しなおすと正常接続できました。

ググってコピペで実行。。。よくやってしまう行為ですが
開発環境とはいえ、意味を理解して実行しないといけないなと反省しました。というお話です。

ISUCON5に参加しました。

チーム名「京都スイーツnext」でISUCON5に参加しました!

 

昨年に続き2回目の参加です。

昨年はサーバーもシステムも先輩方に頼りっきりで、

僕は邪魔にならないように応援することしかできませんでした( ̄▽ ̄;)

挙句の果てに唯一任せていただいたSELECT文 の「*」をカラム名指定で書くという修正でヘマをして

失格になるという。。

 

今回はスーパープログラマーの先輩がいなかったので、システムの修正は僕が担当しました!

サーバーエンジニアのはらぐちさんと相談しながら、うまく役割分担して修正を進めました。

今回はそこそこ貢献できたと思います。

まだまだできることがたくさんある中終了してしまい、結果は惜しくも本戦出場なりませんでした。

簡単なこともググりながらの作業で、基礎力のなさを痛感しました。

来年も参加して次こそは本戦出場したいです(`・ω・´)

 

ほぼ感想だけになってしまいましたが、修正内容とかはサーバーエンジニアのはらぐちさんもブログにまとめていただいてます。

ISUCON5に「京都スイーツnext」で参加してきました

 

 

Page 1 of 8

© SEEDS Co.,Ltd.