ラベル Actions on Google の投稿を表示しています。 すべての投稿を表示
ラベル Actions on Google の投稿を表示しています。 すべての投稿を表示

2022年7月15日金曜日

Dialogflowを削除してもFirebaseプロジェクトが削除できない問題に対処 (エラー:削除を防ぐリーエンがプロジェクトに配置されました。)

Firebaseに新しいプロジェクトを追加しようとしたところ、プロジェクト数の上限が近づいていました。 

過去にActions on Googleを色々試していた時にサンプルを動かすためだけに作ったプロジェクトが多数あったため、それを削除して整理しようと思いました。

発生した現象

Firebaseコンソールでプロジェクトの設定画面からFirebaseプロジェクトを削除しようとすると、「削除を防ぐリーエンがプロジェクトに配置されました。削除を許可するには、リーエンを削除してください。」というエラーが表示され、削除できませんでした。

Dialogflowとリンクされていることが原因のようだったので、Dialogflowコンソールから該当するDialogflowエージェントを削除しました。

ところが、Dialogflowエージェントの削除後も同じエラーが表示され続け、Firebaseプロジェクトが削除できない状態になりました。

解決した方法

下記手順で、プロジェクトの削除を防いでいる「リーエン」を削除することで解決できました。

  1. gcloud CLI (Google Cloud CLI) をインストール
    参考: https://cloud.google.com/sdk/docs/install-sdk?hl=ja

  2. リーエンの一覧を確認
    >gcloud alpha resource-manager liens list --project my-project-name
    NAME                                                 ORIGIN                                                                                                                                                                                                                           REASON
    p703716169729-*********-****-****-****-************  You cannot delete this project because it is linked with a Dialogflow agent. Please follow the link to Dialogflow and delete the agent: https://console.dialogflow.com/api-client/#/agent/430c5fc3-****-****-****-************/  Deletion blocked by Dialogflow.
    
  3. liens/<NAME欄に表示されたリーエンの名前> の形式でリーエン名を指定して、下記コマンドを実行
    >gcloud alpha resource-manager liens delete liens/p703716169729-*********-****-****-****-************
    Deleted [liens/liens/p703716169729-*********-****-****-****-************].
    
  4. リーエンが削除されたことを確認
    >gcloud alpha resource-manager liens list --project my-project-name
    Listed 0 items.
    
  5. Firebaseコンソールに戻り、Firebaseプロジェクトを削除

2019年10月4日金曜日

Actions on Googleで使うFirebase Functionsの開発用ローカルサーバーを作る

Actions on Google のドキュメントやチュートリアルだとあまり詳しく書かれていない、Firebase Functionsの代わりにローカルサーバーを使用する環境を構築する方法です。

コードを1行変えて動作を確認するにも毎回Firebaseにデプロイして…という手間から解放されます…!

【参考記事】
Speed up Actions on Google development workflow with local fulfillment
https://medium.com/voiceano/speed-up-actions-on-google-development-workflow-with-local-fulfilment-7de17d5f166f

実行コマンドやjsonの設定内容も上記記事から引用させていただいています。大変参考になりました。ありがとうございます!

環境

Windows 10 Home (バージョン1903)
Node v10.16.3
firebase-functions @3.2.0
firebase-admin @8.6.0
ngrok @3.2.5
nodemon @1.19.2

設定手順

躓いたポイントは後でまとめるとして、まず全部うまくいった場合の手順を。

すでに、Firebase FunctionにデプロイしてDialogflowと連動して動作しているプロジェクトがある前提で進めます。

2019年9月21日土曜日

Firebase Auth、Cloud Firestoreのセキュリティルールについてメモ

下記の動画の内容について、自分の理解のメモ。

このドキュメントからリンクされていた動画です。
Cloud Firestore セキュリティ ルールを使ってみる | Firebase


{database} →任意のdatabase名にmatchし、matchしたdatabase名を database という変数に格納する
{restOfPath=**} →これ以下のパスにあるすべてのドキュメント・コレクション

Cloud Firestoreでは、上の階層で指定されたルールは下の階層に引き継がれない
(Realtime Databaseの場合と異なる)

service cloud.firestore {
  match databases/{database}/document {
    // restaurantID = The ID of the restaurant doc
    match /restaurants/{restaurantID} {
      // restaurantID = The ID of the restaurant doc
      // reviewID = The ID of the review doc
      allow write: if reviewID == "review_234"
    }
  }
}

アクションは5種類
read

  • get
  • list

write

  • create
  • delete
  • update

request オブジェクトは「authオブジェクト」と「resourceオブジェクト」から成る

  • request.auth にユーザーの認証情報
  • request.resource.data にこのリクエストで渡すデータの内容

が入っている感じ

こんな感じで、ルールにはresourceオブジェクトのバリデーションっぽいものも書くことができる

service cloud.firestore {
  match /databases/{database}/documents {
    match /restaurants/{restaurantID} {
      match /reviews/{reviewID} {
        // score の値が数値の時のみcreateを許可する
        allow create: if request.resource.data.score is number &&
          // かつ、resource の reviewrID が 現在のユーザーのIDと一致する場合のみcreateを許可する
          request.resource.data.reviewerID == request.auth.uid;
      }
    }
  }
}
  • request.resource.data →リクエストで渡すデータの内容
  • resource.data →DBに既に保存されているデータの内容

を指す。

service cloud.firestore {
  match /databases/{database}/documents {
    match /restaurants/{restaurantID} {
      match /reviews/{reviewID} {
        // createのルール
        allow create: if request.resource.data.score is number &&
          request.resource.data.reviewerID == request.auth.uid;

        // updateのルール
        allow update: if request.resource.data.score is number &&
          request.resource.data.reviewerID == request.auth.uid &&
          // リクエストのscoreの値と、既にDBに保存されているscoreの値が同じ時のみupdateを許可する(=scoreの値を変更できないようにする)
          request.resource.data.score == resource.data.score;
      }
    }
  }
}

query で複数のデータのリスト(コレクション)を取得する場合、
ルールで「state が published なデータのみreadを許可する」となっていると、
「全部のデータを取得」のクエリはpermission denied error になる。(たとえ今あるデータがすべてstate == published だったとしても)
「state が publishedの全データを取得」というクエリなら成功する。

自動でstate == published のデータだけフィルターして返してくれたりはしない。
※1件だけを指定して取得するリクエストの場合は、データの内容をチェックしてルールに合致するか見て返す・返さないを判断してくれる。

function の形で再利用できるようにして整理することもできる。

2019年9月6日金曜日

#100DaysOfCode R2 Day15

Day 15: September 6, 2019

Today's Progress:

  • Actions on Google 開発
    • search_again intent の追加
    • 会話内容の改善

今日はちょっと内容軽め。でもフォローアップインテントについてドキュメントを読んだり触ってみたり、合言葉のキーワードが足りない時に訊き返す会話(Prompts)を追加したり(これはDialogflow ConsoleのUIから)

あまり複雑に作り込む前に、次はRailsアプリとFirestoreの接続方法を調べようかと思ってます。

Links to work:

  • なし

2019年9月5日木曜日

#100DaysOfCode R2 Day14

Day 14: September 5, 2019

Today's Progress:

  • Actions on Google 開発
    • Cloud Firestore のデータの検索

できましたー!!!

db.collection(FirestoreNames.NOTICES) は取得できているのに db.collection(FirestoreNames.NOTICES).where(FirestoreNames.KEYWORD, '==', keyword) とするとデータが取得できない(Firebase FunctionsのログによるとMalformed responseというエラー)問題で悩んでいたのですが、Dialogflowのパラメータ名/Firestoreのフィールド名/index.js内の変数名の keyword を全て keyword0 に変更すると動くようになりました…原因はわかりません…

キーワード2つを組み合わせての検索もできました。

昨日セットアップしたローカルサーバー大活躍!確かにこれはいちいちFirebase Functionsにデプロイするよりずっと速いし手間がかからない。

Links to work:

  • なし

2019年9月4日水曜日

#100DaysOfCode R2 Day13

Day 13: September 4, 2019

Today's Progress:

  • Actions on Google 開発
    • ローカル実行環境セットアップ

この記事 を参考に、ローカルで Firebase Functions の代わりになるExpressサーバーを実行できるようにセットアップ。

JavaScriptの単純な文法にすら自信がない上にいろんなサービスを連携させて使わないといけないので、自分のコードが悪いのか何かの設定が上手くいってないのかの切り分けを繰り返すのに、少しコードを変える度に毎回 Firebase Functions にデプロイしないといけないのはかなり辛かったので。

セットアップはうまくいきました!DBにもアクセスできることを確認。これで開発がはかどりそう!

機能うまくいかなかったwhere句での絞り込みは同じように上手くいかず…明日からはこれを調査しようと思います。

Links to work:

  • なし

#100DaysOfCode R2 Day12

Day 12: September 3, 2019

Today's Progress:

  • Actions on Google 開発
    • セットアップ

昨日コードを読んでいたサンプルの真似をしながら、Actions on Googleコンソール、Dialogflow、Cloud Firestore等を設定。
Firestoreからデータの取得もできている。

ところが、なぜか where メソッドで検索した結果を取得しようとすると、急にレスポンスが返ってこなくなり、エラーになる。調査中。

Actions on Google、2年前くらいから構想だけはあって調べていて、日本語の音声でお気に入りの声があったので絶対この子で作ろう!と思っていたのですが、バージョンアップされて声が変わってしまっていて悲しい…(笑)
たしかに自然さはアップしてるんですが。好みの問題で…

Links to work:

  • なし(GitLab private repo)

2019年9月2日月曜日

#100DaysOfCode R2 Day11

Day 11: September 2, 2019

Today's Progress:

サンプルの index.js のコードを読んで、何をしているコードなのかコメントを細かく入れてみました。
JavaScriptを多少勉強してきたおかげか、だいぶActions on Googleの知識が広く浅く集まってきたおかげか、かなり理解がクリアになった気がします。

Dialogflow の設定状態と照らし合わせて読んだのも理解に役立ちました。私も最終的に組み合わせて使いたいので。

Fork したリポジトリにブランチ切ってコメント入れたファイルを公開してみました。(下記)

Links to work:

2019年8月31日土曜日

Actions on Google を Firebase Realtime Database に接続

Actions SDKを使用したAction on GoogleとFirebase Realtime Databaseを接続できるか試しました。

まだかろうじて接続できていることが確認できた段階ですが…

参考にしたページとうまくいった方法のメモ。

Firebaseのドキュメントを読む時、Actions on GoogleはNode.js のウェブアプリと考えて大丈夫そう。

準備

JavaScript でのインストールと設定
https://firebase.google.com/docs/database/web/start

これ↓に沿って進める。

Firebase を JavaScript プロジェクトに追加する
https://firebase.google.com/docs/web/setup

構成情報の入手方法
https://support.google.com/firebase/answer/7015592

こんな感じ

デプロイについてはここら辺も参考になる?
https://firebase.google.com/docs/cli/#deployment

ここ(ウェブでのデータの読み取りと書き込み)ここ(「本気のしりとり」Google Homeアプリを作りました。) を見て色々書いてみるも、 snapshot.val() の値が [object Promise] となってしまってうまくいかない…

↓↓↓

DBからの読み出しができたコード

ここを見て真似したらできた!

データの取得>はじめに
https://firebase.google.com/docs/database/admin/retrieve-data?hl=ja#section-start

やああああっっとできたああああああ

真似したコードはこれ

// Import Admin SDK
var admin = require("firebase-admin");

// Get a database reference to our posts
var db = admin.database();
var ref = db.ref("server/saving-data/fireblog/posts");

// Attach an asynchronous callback to read the data at our posts reference
ref.on("value", function(snapshot) {
  console.log(snapshot.val());
}, function (errorObject) {
  console.log("The read failed: " + errorObject.code);
});

以下、サンプルコードを改変してあいさつの言葉をDBから読みだすようにしたコード。

元コード: actions-on-google/actionssdk-say-number-nodejs: Say a number Actions SDK sample for Actions on Google

改変後

'use strict';

// Firebase App (the core Firebase SDK) is always required and
// must be listed before other Firebase SDKs
var firebase = require("firebase/app");

// Add the Firebase products that you want to use
require("firebase/auth");
require("firebase/database");

const functions = require('firebase-functions');
const {actionssdk} = require('actions-on-google');

const app = actionssdk({debug: true});

// Your web app's Firebase configuration
var firebaseConfig = {
  // Firebase console で取得した構成情報を貼り付け
};

// Initialize Firebase
firebase.initializeApp(firebaseConfig);

// データベースでデータの読み書きを行うには、firebase.database.Reference のインスタンスが必要
// Get a reference to the database service
var database = firebase.database();
var ref = database.ref("greeting/morning");

var greetWord = "Hi!";

// Attach an asynchronous callback to read the data
ref.on("value", function(snapshot) {
  console.log(snapshot.val());
  greetWord = snapshot.val();
}, function (errorObject) {
  console.log("The read failed: " + errorObject.code);
});

app.intent('actions.intent.MAIN', (conv) => {
  conv.ask('<speak>' + greetWord + '<break time="1"/> ' +
  'I can read out an ordinal like ' +
  '<say-as interpret-as="ordinal">123</say-as>. Say a number.</speak>');
});

// 以下、元のサンプルコードと同じ

1回しか読み込まれていない?

けどこのままではfirebase deploy したタイミングでしかDBの変更が反映されない様子。
トリガーのタイミングについてはここら辺?

Realtime Database トリガー
https://firebase.google.com/docs/functions/database-events?hl=ja

こう↓すると、MAIN intent が呼び出される度にDBが読み込まれて、すぐには反映されないけど次の回では反映されてるのが確認できた。
てことはやっぱりPromiseとかCallbackの使い方が間違ってるんだろうな…。

// Attach an asynchronous callback to read the data
function readDb() {
  ref.once("value", function(snapshot) {
    console.log(snapshot.val());
    greetWord = snapshot.val();
  }, function (errorObject) {
    console.log("The read failed: " + errorObject.code);
  });
}

readDb(); // firebase deploy のタイミングで読み込み

app.intent('actions.intent.MAIN', (conv) => {
  readDb();  // MAIN intent のタイミングで読み込み。
  // 次にMAIN intent を呼び出した時には反映されていることが確認できる。

  conv.ask('<speak>' + greetWord + '<break time="1"/> ' +
  'I can read out an ordinal like ' +
  '<say-as interpret-as="ordinal">123</say-as>. Say a number.</speak>');
});