Edited at

Monaca + Movable Type で記事投稿スマホアプリを作ってみる

More than 1 year has passed since last update.

前回の続きです。

今回は、Movable Type のData APIから認証機能を呼び出し


  • Monaca で作成したスマホアプリから Movable Type へサインインする

  • スマホアプリから投稿する

までを作ってみます。

UIには、前回同様 Onsen UIを使います。


新しいプロジェクトの作成

前回の「Monaca プロジェクト作成」と同様に、記事投稿アプリ用のプロジェクトを作成します。


投稿用インデックスファイルの作成

プロジェクトの作成が終わったら、inde.htmlを以下のファイルに差し替えます。

こちらの記事で作成した投稿用のスクリプトを、一部 Monaca 用にアレンジして書き換えました。

<!DOCTYPE html>

<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>autheticationを使った投稿サンプル</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="components/loader.js"></script>
<script src="lib/onsenui/js/onsenui.min.js"></script>

<link rel="stylesheet" href="components/loader.css">
<link rel="stylesheet" href="lib/onsenui/css/onsenui.css">
<link rel="stylesheet" href="lib/onsenui/css/onsen-css-components.css">
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>

<body>

<ons-page>
<ons-toolbar>
<div class="center">MT投稿アプリ</div>
</ons-toolbar>

<div style="text-align: center; margin-top: 30px;" id="content">
<p>
<ons-input id="username" modifier="underbar" placeholder="Username" float></ons-input>
</p>
<p>
<ons-input id="password" modifier="underbar" type="password" placeholder="Password" float></ons-input>
</p>
<p style="margin-top: 30px;">
<ons-button id="signin">サインイン</ons-button>
</p>
</div>
</ons-page>

<script>

$(function() {
const clientId = 'smartphone_post_sample';
const currentSession = 'mt_session_' + clientId;
const currentToken = 'mt_token_' + clientId;
const nowTime = Math.floor(new Date().getTime() / 1000);

const apiUrl = 'http://your-mt/mt-data-api.cgi';
const siteId = 'ブログIDの数字';

if (sessionStorage.getItem(currentSession)) {
haveSignedIn();
}

$('#signin').on('click', function() {
signIn();
});

$('#submit').on('click', function() {
var promise = Promise.resolve(checkToken());
promise.then(function() {
PostEntry();
});
});

$('#signout').on('click', function() {
revokeSession();
});

function haveSignedIn() {
const displayData = `
<h3>投稿する</h3>
<form class="col-sm-8">
<div class="form-group">
<input id="title" name="title" placeholder="タイトル" type="text" class="form-control">
</div>
<div class="form-group">
<textarea id="body" maxlength="140" placeholder="本文" rows="7" class="form-control"></textarea>
</div>
<div class="form-group">
<ons-button id="submit" name="submit" type="button">投稿する</ons-button>
</div>
<div class="form-group">
<ons-button id="signout" name="signout" type="button">サインアウト</ons-button>
</div>
</form>
`

$("#content").empty();
$("#content").append(displayData);
}

function signIn() {
const username = $('#username').val();
const password = $('#password').val();
$.ajax({
url: apiUrl + '/v3/authentication',
type: 'POST',
dataType: 'json',
data: {
'username': username,
'password': password,
'clientId': clientId,
}
}).done(function(data) {
sessionStorage.setItem(currentSession, data.sessionId);
let TokenData = {
'accessToken': data.accessToken,
'expiresIn': data.expiresIn,
'gotTokenTime': nowTime,
}
sessionStorage.setItem(currentToken, JSON.stringify(TokenData));
alert("サインインしました。");
location.reload();
}).fail(function(data) {
alert("サインイン時にエラーが発生しました。再度サインインをお試しください。");
});
}

function PostEntry() {
const entry = {};
entry.title = $('#title').val();
entry.body = $('#body').val();
$.ajax({
url: apiUrl + '/v3/sites/' + siteId + '/entries',
type: 'POST',
dataType: 'json',
headers: {
'X-MT-Authorization': 'MTAuth accessToken=' + JSON.parse(sessionStorage.getItem(currentToken)).accessToken,
},
data: {
'entry': JSON.stringify(entry)
},
}).done(function() {
alert("データを投稿しました。");
}).fail(function(data) {
alert("投稿時にエラーが発生しました。");
});
}

function revokeSession() {
$.ajax({
url: apiUrl + '/v3/token',
type: "DELETE",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-MT-Authorization': 'MTAuth accessToken=' + JSON.parse(sessionStorage.getItem(currentToken)).accessToken,
}
}).done(function() {
$.ajax({
url: apiUrl + "/v3/authentication",
type: "DELETE",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-MT-Authorization': 'MTAuth sessionId=' + sessionStorage.getItem(currentSession),
}
})
}).done(function() {
sessionStorage.removeItem(currentSession);
sessionStorage.removeItem(currentToken);
alert("サインアウトしました。");
location.reload();
}).fail(function(data) {
alert("サインアウト中にエラーが発生しました。もう一度サインインし直してください。");
sessionStorage.removeItem(currentSession);
sessionStorage.removeItem(currentToken);
location.reload();
});
}

function checkToken() {
const expiresIn = JSON.parse(sessionStorage.getItem(currentToken)).expiresIn;
const gotTokenTime = JSON.parse(sessionStorage.getItem(currentToken)).gotTokenTime;
if (nowTime >= expiresIn + gotTokenTime) {
refreshToken();
}
}

function refreshToken() {
$.ajax({
url: apiUrl + '/v3/token',
type: "DELETE",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-MT-Authorization': 'MTAuth accessToken=' + JSON.parse(sessionStorage.getItem(currentToken)).accessToken,
}
}).done(function() {
$.ajax({
url: apiUrl + '/v3/token',
type: "POST",
dataType: "json",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-MT-Authorization': 'MTAuth sessionId=' + sessionStorage.getItem(currentSession),
}
}).done(function(data) {
let TokenData = {
'accessToken': data.accessToken,
'expiresIn': data.expiresIn,
'gotTokenTime': nowTime,
}
sessionStorage.setItem(currentToken, JSON.stringify(TokenData));
}).fail(function(data) {
alert("アクセストークンのリフレッシュ中にエラーが発生しました。サインし直してください。");
sessionStorage.removeItem(currentSession);
sessionStorage.removeItem(currentToken);
location.reload();

});
});
}
});

</script>
</body>
</html>

このアプリでは、以下の機能を実装しています。


  • サインイン画面を表示

  • ユーザー名、パスワードを入力後、「サインイン」ボタンを押すと、Movable Type のData APIを利用した認証を行う

  • ユーザー情報が正しい場合、サインイン画面を消去して記事投稿用のフォームを表示する。

  • 今回は「タイトル」と「本文」を入力できるようにする。

  • データ入力後「投稿する」ボタンを押すと、Movable Type にデータを投稿する。

  • 「サインアウト」ボタンを押すと、サインアウト処理を行い、初期画面に戻る

詳細は元記事を参照ください。

Onsen UI を使うために、header内でOnsen UI の各ライブラリを読み込んでいます。

サインイン用の初期画面、および投稿用画面のボタンを、Onsen UI のタグに書き換え、スマホアプリっぽい見栄えに変えてみました。

保存したら、Monaca デバッガーで確認します。


免責

今回のサンプルは、十分なテストを行っていないため、実際に利用する際は、作成したコードのテスト・チェックを十分に行った上で実装ください。

※何かお気づきの点などありましたら、どうぞお知らせください。