ニフクラ mobile backend(mBaaS)お役立ちブログ

スマホアプリ開発にニフクラ mobile backend(mBaaS)。アプリ開発に役立つ情報をおとどけ!

オンラインミートアップ用のチェックインシステムをmBaaSで実現する

f:id:mbaasdevrel:20200305165747p:plain

コロナウイルスの影響により、最近はコミュニティイベントをオンラインで行うケースが増えています。この時、一つ問題になるのが受付システムです。オフラインのイベントでは受付を設けて、そこでチェックできたのですが、オンラインイベントではZoomやGoogle MeetなどのURLに直接アクセスするので、受付できないのが問題でした。

そこで、mBaaSを使ってチェックイン後に動画配信のURLを共有するシステムを作ってみたので紹介します。

仕組みについて

このシステムは3つの段階に分かれています。

  1. connpassにログインする
  2. connpassから参加者一覧を取得する
  3. 参加者がチェックインする

1と2についてはmBaaSのスクリプト機能を使っています。スクリプト機能ではNode.jsとRubyが選べますが、参加者一覧はCSVなので、標準でCSVパーサーが含まれているRubyを利用しました。

connpassにログインする

ここで行うのはconnpassにログインし、そのセッションIDをデータストアに保存することです。今回は不特定多数がログインする想定ではないので、Configというクラスを作って、その中にIDとパスワードを入れています。カラム名はそれぞれusernameとpasswordです。

f:id:mbaasdevrel:20200305165406p:plain

このIDとパスワードを使ってログインします。

# connpassにログインする処理
def login_to_connpass(config)
  # CSRFを取得
  response = HTTParty.get 'https://connpass.com/login/'
  cookies = parse_set_cookie response.headers['set-cookie']
  login_doc = Nokogiri::HTML response.body
  csrfmiddlewaretoken = login_doc.css('[name=csrfmiddlewaretoken]').first.attribute('value')
  # ログイン処理を実行
  response2 = HTTParty.post 'https://connpass.com/login/', body: {
    csrfmiddlewaretoken: csrfmiddlewaretoken,
    username: config.username,
    password: config.password
  }, headers: {
    'Cookie': cookies.map{|k, v| "#{k}=#{v}"}.join("; "),
    'Content-Type': 'application/x-www-form-urlencoded',
    'Referer': 'https://connpass.com/login/'
  }, follow_redirects: false
  # Cookieを返却
  parse_set_cookie response2.headers['set-cookie']
end

# Cookieのパース処理
def parse_set_cookie(all_cookies_string)
  cookies = Hash.new
  all_cookies_string.split(',').each {|single_cookie_string|
    cookie_part_string  = single_cookie_string.strip.split(';')[0]
    cookie_part = cookie_part_string.strip.split('=')
    key = cookie_part[0]
    value = cookie_part[1]
    cookies[key] = value
  }
  # 日付に含まれるカンマで余計なデータが入るので排除
  cookies.reject! {|key, value| value.nil? }
end

セッションIDは同じConfigクラスの中に保存しておきます。カラム名はsessionidになります。

connpassから参加者一覧を取得する

続いて、セッションIDを使って参加者一覧のCSVを取得します。まずEventというクラスを作成して、設定をします。

  • key
    ユニークなキー(任意)
  • name
    イベント名
  • url
    イベントのURL(connpassのもの)
  • classname
    参加者のデータを入れるクラス名
  • video_url
    オンラインイベント会場のURL

f:id:mbaasdevrel:20200305165546p:plain

全体の流れは次のようになります。

def call(env)
  req = Rack::Request.new(env)
  # 設定(セッションID)を取得
  query = NCMB::DataStore.new 'Config'
  config = query.limit(1).get.first
  
  # CSV取得対象のイベントデータを取得
  query = NCMB::DataStore.new 'Event'
  event = query.equalTo('key', req.params['key']).get.first
  rows = get_csv(config.sessionid, event)
  
  # 古いデータの削除
  query = NCMB::DataStore.new event.classname
  query.equalTo('key', event.key).get.each do |p|
    p.delete
  end
  
  # CSVデータの保存
  rows.each do |row|
    p = NCMB::Object.new event.classname
    p.set 'key', event.key
    p.set 'name', row['表示名']
    p.set 'paticipate', row['参加ステータス']
    p.set 'attend', row['出欠ステータス']
    p.set 'no', row['受付番号']
    p.save
  end
  [
    200, {"Content-Type" => "application/json"}, [{attendees: rows.length}.to_json]
  ]
end

参加者一覧の取得処理は次のようになります。

def get_csv(sessionid, event)
  puts "#{event.url}participants_csv/"
  id = event.url.match(/https:\/\/.*?\.connpass\.com\/event\/([0-9]+)(\/|$)/)[1]
  response = HTTParty.get "https://connpass.com/event/#{id}/participants_csv/", headers: {
    'Cookie': "sessionid=#{sessionid}",
    'Referer': event.url
  }
  CSV.parse response.body.encode(Encoding::UTF_8, Encoding::SJIS, replace: '?', invalid: :replace), headers: true 
end

なお、この処理はシステムから呼び出すこともできますが、基本的に管理画面から実行することを想定しています。

f:id:mbaasdevrel:20200305165702p:plain

参加者がチェックインする

参加者がチェックインするための画面(HTML)とJavaScriptファイルを準備します。HTMLファイルはBootstrapを使ったシンプルなもので、ファイルストアにアップロードします。

<html>
  <head>
    <base target="_top">
    <title>connpass受付システム</title>
    <!-- 必要なライブラリの読み込み(省略)-->
    <meta charset="utf-8"/>
  </head>
  <body>
    <div class="container">
      <div class="row justify-content-center">
        <div class="col-8 event">
          <form class="form-signin">
            <h1 class="h3 mb-3 title"></h1>
            <h3>受付番号は<a href="" class="url" target="_blank">connpassのイベントページ</a>で確認できます</h3>
            <br>
            <label for="inputNumber" class="sr-only">受付番号</label>
            <input type="number" id="ticket_number" class="form-control" placeholder="受付番号" required="" autofocus="">
            <button class="btn btn-lg btn-primary btn-block" type="submit">チェックイン</button>
            <p class="mt-5 mb-3 text-muted">© MOONGIFT 2020</p>
          </form>
        </div>
      </div>
    </div>
    <!-- Bootstrapのモーダル -->
    <div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="exampleModalLabel">受付完了!</h5>
            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
              <span aria-hidden="true">×</span>
            </button>
          </div>
          <div class="modal-body">
            <strong><span id="username">name</span>さん、受付完了しました</strong>
            <div>
              <a id="onlineUrl" href="" target="_blank">配信会場はこちらです。クリックしてご参加ください</a>
            </div>
          </div>
        </div>
      </div>
    </div>
    <script src="./app.js"></script>
  </body>
</html>

f:id:mbaasdevrel:20200305165725p:plain

次にJavaScriptです。初期表示時に指定されたイベントを取得します。

$(async () => {
  const applicationKey = 'b6f...ee6';
  const clientKey = '955...202';
  const ncmb = new NCMB(applicationKey, clientKey);
  const key = url('?key');
  if (!key) {
    alert('イベントキーが指定されていません');
    return;
  }
  const event = await ncmb.DataStore('Event').equalTo('key', key).fetch();
  $('.event .title').html(`${event.get('name')}受付`);
  $('.event .url').attr('href', `${event.get('url')}ticket`);
});

次にフォームを送信した際のイベントで、データストアに受付番号の有無を確認します。もしあれば新しいクラスにチェックインデータを書き込みます。そしてモーダルウィンドウを開いて完了です。

$('form').on('submit', async (e) => {
  e.preventDefault();
  const number = $('#ticket_number').val();
  const attendee = await ncmb.DataStore(event.get('classname'))
    .equalTo('key', key)
    .equalTo('no', number)
    .fetch();
  if (Object.keys(attendee).length == 0) {
    alert('受付番号が確認できません。番号を確認いただくか、運営者にお問い合わせください');
    return;
  }
  attend = new (ncmb.DataStore(`${event.get('classname')}Attend`));
  await attend
    .set('attendee', attendee)
    .set('event', event)
    .save();
  $('#username').html(attendee.get('name'));
  $('#onlineUrl').attr('href', event.get('video_url'));
  $('#modal').modal('show');
});

大事なポイントとして、ファイルストアの設定で、HTTPSアクセスを有効にします。

f:id:mbaasdevrel:20200305165808p:plain

そうすると、HTTPアクセスできるURLが表示されますので、このURL + ?key=(イベントのキー) でアクセスしてみます。

f:id:mbaasdevrel:20200305165839p:plain

例えば以下のようになります。

https://mbaas.api.nifcloud.com/2013-09-01/applications/8JSajPkL3qriAK9A/publicFiles/checkin.html?key=(キー)

イベントがあれば、イベント名が表示されます。そして自分の受付番号を入力すると、挨拶メッセージとイベントアクセス用のURLが表示されます。

f:id:mbaasdevrel:20200305165747p:plain

まとめ

チェックインしたというデータが残っていれば、後でconnpassに反映するのは難しくないでしょう。今回の仕組みはスクリプト、データストア、ファイルストアを使っており、サーバレスで運用できます。オンラインイベントを盛り上げるためにもぜひmBaaSを役立ててください。

今回のコードはNCMBMania/online_checkin: mBaaSを用いたオンラインチェックインシステムです。にアップロードしてあります。利用時の参考にしてください。

中津川 篤司

中津川 篤司

NCMBエヴァンジェリスト。プログラマ、エンジニアとしていくつかの企業で働き、28歳のときに独立。 2004年、まだ情報が少なかったオープンソースソフトの技術ブログ「MOONGIFT」を開設し、毎日情報を発信している。2013年に法人化、ビジネスとエンジニアを結ぶDXエージェンシー「DevRel」活動をスタート。