PowerCMS™

PowerCMS ブログ

ホーム > PowerCMS ブログ

先日の記事では、S3 同期の際に Lambda で自動的に CloudFront のキャッシュをパージする 仕組みをご紹介しましたが、その中で作成する Lambda 関数で、ランタイムに Python を選択していました。今回は Node.js を使って同じ仕組みを構築してみましょう。

全体の流れ

先日の記事 でご紹介している手順とほぼ同じで、「Lambda 関数の作成」のみが今回ご紹介する Node.js に変わります。

また今回、コードを差し替えるだけでは面白くないので、合わせて Node.js の動作に必要なモジュールを追加する手順もご紹介します。

準備

先日の記事 のうち、「前提」から「キャッシュパージの回数を記録するための S3 バケットを作成する」までを行ってください。

Lambda 関数の作成(Node.js 版)

新しい関数を作成します。関数名はここでは「limited-cloudfront-purge-by-file-nodejs」とし、ランタイムに「Node.js 14.x」を指定します。他の項目はデフォルトのまま [関数を作成] ボタンを押します。

新しい Lambda 関数の作成

関数が作成されたら、コードソースに下記をコピー&ペーストします。DISTRIBUTION_ID, ORIGIN_BUCKET_NAME, COUNT_BUCKET_NAME をご利用環境に合わせて変更してください。また、ここでは、ファイル名が「.purge」のファイルに変更があったら、一日に 10 回までキャッシュのパージを行う設定になっています。状況に合わせて COUNT_MAX, TARGET_FILE を変更してください。

また、念のため、CloudWatch Logs に記録するための console.log を入れています。

require('date-utils');

const AWS = require('aws-sdk');
const s3 = new AWS.S3();
const cloudfront = new AWS.CloudFront();

const DISTRIBUTION_ID = 'CloudFront の ID';
const ORIGIN_BUCKET_NAME = 'オリジンである S3 バケットの名前';
const COUNT_BUCKET_NAME='パージ回数を記録する S3 バケットの名前';
const COUNT_MAX=10;
const TARGET_FILE='.purge';

const pattern = new RegExp('^' + TARGET_FILE + '$');

exports.handler = async (event) => {

  let dt = new Date();
  let key = dt.toFormat("YYYY-MM-DD") + '.txt';

  let count = 0;
  await s3.getObject(
    {
      Bucket: COUNT_BUCKET_NAME,
      Key: key,
    }, (err, data) => {
      if (! err) {
        count = parseInt(data.Body.toString(),10);
        if (isNaN(count)) {
          count = 0;
        }
      }
    }
  ).promise().catch(
    function (error) {
      count = 0;
    }
  );

  console.log(count);

  if ( count < COUNT_MAX ) {
    console.log('NOT MAX');
    for (let i = 0; i < event["Records"].length; i++) {
      let item = event["Records"][i];
      if (item["s3"]["bucket"]["name"] == ORIGIN_BUCKET_NAME ) {
        if (item["s3"]["object"]["key"].match(pattern)) {
          console.log('FILENAME PATTERN MATCHED');
          let params = {
            DistributionId: DISTRIBUTION_ID,
            InvalidationBatch: {
              Paths: {
                Quantity: 1,
                Items: ['/*']
              },
              CallerReference: dt.toFormat("YYYYMMDDHH24MISS")
            }
          };
          await cloudfront.createInvalidation(params).promise();
          console.log('INVALIDATION CREATED');
        }
      }
    }
  } else {
    console.log('IS MAX');
    return;
  }
  var params = {
    Bucket: COUNT_BUCKET_NAME,
    Key: key,
    Body: String(count)
  };
  await s3.putObject(params).promise();
  return;
};

パージ回数を記録するバケットには、「2021-08-06.txt」のように、日付ごとにファイルを作成し、内容としてパージ回数が記録していきます。月ごとにする場合は、"YYYY-MM-DD" の部分を "YYYY-MM" にしてください。合わせて COUNT_MAX も増やしたほうがいいかもしれません。

※ このコードでは日付が UTC となりますが、内容の簡略化のため、JST にする方法はここでは触れません

コードソースの編集が終わったら、[Deploy] ボタンを押してデプロイします。

このコード内では、日付の作成処理を簡易化するために date-utils を使用していますが、Lambda 標準では利用できません。続いてレイヤーの追加を行うことで date-utils を利用できるようにしていきます。

date-utils を使わずに動作させる場合は、dt.toFormat() 部分を任意のコードに置き換えてください

レイヤーの追加

ローカルで ZIP アーカイブを作成し、AWS にアップロードする流れになります。

下記のように、新しく作成した nodejs フォルダの中で date-utils をインストールしたあと、nodejs フォルダを ZIP アーカイブし、「nodejs.zip」を作成します。

※ npm コマンドがインストールされていない場合はインストールを行ってください

mkdir nodejs
cd nodejs
npm install date-utils
cd ../
zip -r nodejs.zip nodejs

インストールコマンド実行後の nodejs ディレクトリ内は下記のようになっています。

コマンド実行後の nodejs ディレクトリ内

AWS コンソールに戻り、[Lambda] > 左メニュー [その他のリソース] 内 [レイヤー] > [レイヤーの作成] と進みます。ここでは、レイヤーの名前を「NodeJS-Modules」とし、[.zip ファイルをアップロード] から作成した「nodejs.zip」をアップロード、[互換性のあるランタイム] では「Node.js 14.x」を選択しました。

レイヤーの作成

レイヤーの追加が終わったら、作成中の関数のコードソース編集画面に戻り、同ページ下部の [レイヤー] 内 [レイヤーの追加] を選択します。

「レイヤーの追加」を選択する

[レイヤーソース] では「カスタムレイヤー」を選択し、[カスタムレイヤー] で先ほど作成した「NodeJS-Modules」を、[バージョン] では「1」を選択し、[追加] ボタンを押します。

レイヤーの追加を行う画面

関数にレイヤーが追加されると、下記のような状態になります。これで date-utils が使えるようになりました。

レイヤーが追加された状態2

アクセス権限の設定〜動作テスト

先日の記事 の「アクセス権限の設定」以降の手順を実施し、動作テストを行ってください。

なお、Lambda はデフォルトのタイムアウト設定が 3 秒ですが、CloudWatch Logs にタイムアウトが記録されるようであれば、タイムアウト設定を延ばしてみてください。この記事の作成時には 20 秒に設定していました。

お問い合わせ

環境構築やカスタマイズのご相談につきましては、お問い合わせフォームよりお問い合わせください。

カテゴリー
PowerCMS 5技術情報

平素より PowerCMS をご利用、検討いただきありがとうございます。

本日は「PowerCMS 製品サポート」について2021年8月の実績を紹介します。

PowerCMSサポート(アンケート評価) 2021年8月満足評価 96.3%

サポート対応についてのアンケート評価

サポート対応のアンケート評価の結果です。

アンケートを送付した数
108件
評価いただいた数
54件
満足で評価いただいた数
52件
不満で評価いただいた数
2件

不満の評価につきましては真摯に受け止め、チーム全体で内容を振り返り、よりよいサポート対応が行えるよう努めてまいります。

「サポート対応についてのアンケート」については下記記事を参照してください。

お問い合わせの件数

2021年8月1日から8月31日までにいただいたお問い合わせは 141 件でした。

クローズされた件数

基本的にはお客様からご連絡をいただいてからクローズしておりますが、返信いただけていないものは状況を確認させていただいた後にクローズしております。

8月中にクローズされた件数

  • サポート全体でクローズされたお問い合わせは 106 件でした。

※ こちらは前月までにお問い合わせされたものも含みます。

8月中にいただいたお問い合わせのうちクローズされた件数

  • 8月中のお問い合わせ 141 件のうち、クローズされたのは 54 件でした。

※ こちらの件数は8月中にクローズされた 106 件に含まれます。

一回の連絡でクローズされた件数

  • お問い合わせいただいてから一回の連絡でクローズされた件数は 31 件でした。

※ こちらの件数は8月中にクローズされた 106 件に含まれます。

24時間以内にクローズされた件数

  • お問い合わせをいただいてから24時間以内にクローズされた件数は 5 件でした。

※ こちらの件数は8月中にクローズされた 106 件に含まれます。

「回答、対応を急いでいる」を利用された件数

「回答、対応を急いでいる」を利用されたお問い合わせは 54 件でした。

よくあるご質問

下記の 3 件を追加しました。

今後とも PowerCMS をよろしくお願いいたします。

カテゴリー
サポート

みなさんはイベントカレンダーといわれてどういうものをイメージしますか? PowerCMS の導入検討されているお客様よりイベントカレンダーの機能があるかお問い合わせを頂くことがありますが、カレンダーに求められる要件はさまざまです。

今回はお問い合わせ頂くカレンダーの中から「9月1日から9月9日まで開催」というような期間を指定したカレンダーの実装例を紹介いたします。

完成イメージ

出力イメージ中で複数日に表示されているイベントはそれぞれ1件の記事です。

縦型カレンダーの出力

縦型カレンダーの写真

テーブル形カレンダーの出力

テーブル形カレンダーの写真

イベントの登録画面 (記事の編集画面)

イベントの登録画面 (記事の編集画面) の写真

実装の概要

本記事で紹介するイベントカレンダーは以下の要件になります。

  • イベントは記事として登録する
  • 記事には「イベント開始日」と「イベント終了日」の設定を行う (YYYY-MM-DD)
    • イベントの期間が1日の場合は「イベント終了日」に「イベント開始日」と同じ日付を設定する
  • サイト上のカレンダーでは「イベント開始日」から「イベント終了日」の期間もイベントがあるように表示、出力を行う

下記の内容について制限事項となります。

  • 月をまたぐイベントは表示できない
    • 月毎にイベント(記事)をわけて登録することで可能

1. 記事のカスタムフィールドを作成する

記事に対して「イベント開始日」「イベント終了日」を設定できるようにカスタムフィールドを作成します。

イベント開始日

システムオブジェクト 記事
種類 日付と時刻
オプション 日付
名前 イベント開始日
必須 チェックを入れる
ベースネーム eventstartdate
テンプレートタグ EntryDataEventStartDate

※ 名前、ベースネーム以外を変更した場合、後で紹介するテンプレートの内容をそのまま使うことができなくなります

イベント終了日

システムオブジェクト 記事
種類 日付と時刻
オプション 日付
名前 イベント終了日
必須 チェックを入れる
ベースネーム eventenddate
テンプレートタグ EntryDataEventEndDate

※ 名前、ベースネーム以外を変更した場合、後で紹介するテンプレートの内容をそのまま使うことができなくなります

2. テンプレートを実装する

カレンダーを出力したい日付別のアーカイブテンプレートへ、下記を参考にカレンダーを出力するテンプレートを記述します。

※ 日付別アーカイブテンプレート以外でカレンダーを出力したい場合はテンプレートを適宜修正してください。

縦型カレンダーのテンプレート記述例

<table class="table" summary="<$MTCalendarDate format="%Y/%m"$> のカレンダー">
    <tr>
        <th>日 (曜日)</th>
        <th>開催イベント</th>
    </tr>
<MTCalendar month="this">
    <tr>
    <MTCalendarIfBlank>
    <MTElse>
        <td class="dayof<$MTCalendarDate format="%w"$>">
            <$MTCalendarDay$>日
            (<$MTCalendarDate format="%A"$>)
        </td>
        <$MTCalendarDate format="%Y-%m-%d" setvar="currentday"$>
    </MTCalendarIfBlank>
    <MTSearchEntryField field="eventstartdate" query="$currentday" class="entry">
        <$MTEntryID setvar="entry_id"$>
        <$MTEntryDataEventStartDate format="%e日" setvar="start_date"$>
        <$MTEntryDataEventEndDate format="%e日" setvar="end_date"$>
        <MTSetVarBlock name="events" key="$entry_id">
            <a href="<$MTEntryPermalink$>"><$MTEntryTitle$></a>
            (会期 : <$MTVar name="start_date"><MTIf name="start_date" ne="$end_date">-<$MTVar name="end_date"></MTIf>)
        </MTSetVarBlock>
    </MTSearchEntryField>
        <td>
            <MTIf name="events">
            <ul>
                <MTLoop name="events" sort_by="value">
                <li><$MTVar name="__value__"$></li>
                </MTLoop>
            </ul>
            </MTIf>
        </td>
    <MTSearchEntryField field="eventenddate" query="$currentday" class="entry">
        <$MTEntryID setvar="entry_id"$>
        <$MTSetVar name="events" key="$entry_id" function="delete"$>
    </MTSearchEntryField>
    </tr>
    </MTCalendar>
</table>

テーブル形カレンダーのテンプレートの記述例

<table class="table" summary="<$MTCalendarDate format="%Y/%m"$> のカレンダー">
    <tr>
        <th abbr="日曜日" class="dayof0">日</th>
        <th abbr="月曜日" class="dayof1">月</th>
        <th abbr="火曜日" class="dayof2">火</th>
        <th abbr="水曜日" class="dayof3">水</th>
        <th abbr="木曜日" class="dayof4">木</th>
        <th abbr="金曜日" class="dayof5">金</th>
        <th abbr="土曜日" class="dayof6">土</th>
    </tr>
<MTCalendar month="this">
    <MTCalendarWeekHeader>
    <tr>
    </MTCalendarWeekHeader>
        <td>
    <MTCalendarIfBlank>
    <MTElse>
            <span class="dayof<$MTCalendarDate format="%w"$>"><$MTCalendarDay$>日</span>
            <$MTCalendarDate format="%Y-%m-%d" setvar="currentday"$>
    </MTCalendarIfBlank>
    <MTSearchEntryField field="eventstartdate" query="$currentday" class="entry">
        <$MTEntryID setvar="entry_id"$>
        <MTSetVarBlock name="events" key="$entry_id">
            <a href="<$MTEntryPermalink$>"><$MTEntryTitle$></a>
        </MTSetVarBlock>
    </MTSearchEntryField>
    <MTIf name="events">
            <ul>
        <MTLoop name="events" sort_by="value">
                <li><$MTVar name="__value__"$></li>
        </MTLoop>
            </ul>
    </MTIf>
    <MTSearchEntryField field="eventenddate" query="$currentday" class="entry">
        <$MTEntryID setvar="entry_id"$>
        <$MTSetVar name="events" key="$entry_id" function="delete"$>
    </MTSearchEntryField>
        </td>
    <MTCalendarWeekFooter>
    </tr>
    </MTCalendarWeekFooter>
</MTCalendar>
</table>

イベントカレンダーの実装はテンプレートで完結するため必要な設定は以上です。

3. 動作確認

「イベント開始日」「イベント終了日」を入力して記事を投稿、公開してサイトの表示をご確認ください。

本記事のイベントカレンダーに関する FAQ

Q. 「イベント開始日」についてカスタムフィールドではなく記事の「公開日」を利用することはできるか?

記事の「公開日」へ「イベント開始日」を入力する実装も可能です。 その場合にはサンプルのテンプレートをそのまま使うことはできませんので修正が必要です。

本記事でカスタムフィールドを使っているのは「イベント開始日」「イベント終了日」の入力欄が近く操作が行いやすくなると考えてです。また、イベントの開始日より前に記事を日時指定公開することも可能です。

Q. 「イベント終了日」の入力を必須にしないことはできますか?

「イベント終了日」を任意入力とすることも可能です。

本記事で「イベント終了日」を必須入力としたのはテンプレートの構造がシンプルになり、サンプルとして実装イメージを掴みやすくなると考えたためです。

Q. テーブル形のカレンダーについて、イベントを帯のように表示することはできますか?

イベントを帯のように複数日にまたいで表示するデザインも可能です。 テンプレートだけで実現しようとするとかなり複雑な記述になるため今回は取り上げませんでした。 (要望を頂いた場合には検討いたします)

イベントカレンダーは色々あります!

今後、下記のような別パターンのイベントカレンダーを紹介する予定です。

  • イベントと別に休業予定を登録表示するカレンダー
  • 月間予定を登録表示するカレンダー

今回紹介したイベントカレンダーはとてもシンプルな構成です。 この記事を参考に独自のカレンダーの実装へチャレンジしてみてください。

カテゴリー
PowerCMS 3PowerCMS 4PowerCMS 5テンプレート作成Tips

Recent Entries