Morning Girl

Web API, Windows, C#, .NET, Dynamics 365/CRM etc..

LogicAppsでHTTPコネクタを使う時、SwaggerSpec(OpenAPI)を挟むと楽ができるよというお話

SwaggerってなんとなくAPIを開発する側やAPIを使ってプログラミングする側が嬉しいよねー、っていうシチュエーションで語られることが多いと思うんですが、今ローコードな界隈でも結構役立ちます。

Swagger なにそれ? みたいな方は以下の記事をどうぞ。

bit.ly

その一例がMicrosoftが提供している「LogicApps」での活用です。

https://azure.microsoft.com/ja-jp/services/logic-apps/

f:id:sugimomoto:20190524232549p:plain

LogicAppsではフローチャートを描くようにGUIベースでデータ統合処理を開発することができる、PaaS基盤です。

標準のHTTPコネクタはこんな感じ

LogicAppsは標準でも数多くのSaaSクラウドサービス・DBに接続するためのコネクタが提供されていますが、標準提供以外のWeb APIなどと連携するために「HTTP」コネクタが用意されています。

コネクタを開くと、おそらくPostmanなどを普段使う人にとっては馴染み深い画面が表示されます。 「あー、Method選んで、URI書いて、ヘッダー書いて、URLパラメータとしてクエリ書けばいいのね。ふむふむ」みたいな人はこれで済みますが、そういったことに馴染みが薄い人はなかなか大変です。

(知っている人でもちまちまドキュメントからコピペしてくるのは面倒だと思う)

f:id:sugimomoto:20190524232558p:plain

せっかくなのでこのAPIを通じてCustomer情報を取得して、Dynamics 365 に取引先担当者を作るための処理をGIF動画に撮ってみました。

https://s3-ap-northeast-1.amazonaws.com/cdatajbuilds/sugimototest/LogicApps/NormalHTTPRequest.gif

URLやヘッダー、パラメータを手打ちしなければいけず、また取得した本文も一度JSON解析をしなければいけないのが若干面倒ですね。(慣れてしまえばそんなことも無いかもだけど)

そこで HTTP + Swagger を使おう

そこで、Swagger ベースで公開されている API であればさくっとHTTPリクエストが使えるようになる「HTTP + Swagger」を使ってみます。

f:id:sugimomoto:20190524232616p:plain

https://s3-ap-northeast-1.amazonaws.com/cdatajbuilds/sugimototest/LogicApps/SwaggerHTTPRequest.gif

今回使うAPIは以下のとおりです。顧客情報であるCustomerリソースを取得・作成・更新・削除するエンドポイントを備えています。

https://decodeapiserverdemo.azurewebsites.net/api.rst

f:id:sugimomoto:20190524232624p:plain

このAPIの作り方は、以下のURLから。

kageura.hatenadiary.jp

このAPIではSwaggerで作られているのと同時にSwagger Specを取得するためのエンドポイントもサポートしています。以下のURLでアクセス可能。

https://decodeapiserverdemo.azurewebsites.net/api.rsc/@1q0E5n7v8V1k4r1U5g0e/$swagger

f:id:sugimomoto:20190524232711p:plain

これを「HTTP+Swagger」に取り込むと

f:id:sugimomoto:20190524232717p:plain

こんな感じで、APIの機能をリストアップ

f:id:sugimomoto:20190524232725p:plain

URLパラメータや認証処理なんかもさくっと選択して入力することができます。

f:id:sugimomoto:20190524232745p:plain

また予めレスポンスオブジェクトのフォーマットがわかっているのでそのままValueを取り出して、値を設定することができます。

f:id:sugimomoto:20190524232753p:plain

注意点

Swaggerを取り込むためのURLはCORSが許可されていないとLogicAppsがアクセスできないです。

もし、CORSが許可されていない場合は、Azure Storeageに配置してCORSを許可する方法があります。(ただちょっと面倒か)

Reference

docs.microsoft.com

Slack の利用状況を可視化して見えてくるものってなんだろう? Power BI と CData Slack Connector で利用状況レポートを作る方法

最近Twitterでこんなご意見をもらいました!

社内利用状況レポート! なるほど!

最近はビジネスチャット戦国時代ですもんね。Slackを筆頭に、TeamsやChatWork、LineWorkなど、どんどんサービスが増えて、盛り上がっているなーと感じます。

boxil.jp

ただ、導入したとしても、うまく活用されているのかってやっぱり気になりますよね。もっと有効活用されるには、もっとコミュニケーションが活発になるにはどうしたらいいのか? いろんな会社・コミュニティで試行錯誤しているのかなとも感じています。

そこでやっぱりひとつの指針として(サブスクリプションサービスにお金を払っているなら尚更)、利用状況というのは可視化したいというニーズは強いのでしょうね。

でも実際のところ利用状況レポートってどうなの? 役立つの? 

ただ、私自身実際にデータは取れることは理解していても、Slackのデータを分析することで見えてくるものが本当にあるのか? ってわからなかったんですよね。

そこで今回は、Slackをベースにチャットツールからのデータの取得の仕方だけでなく、実際にレポートとして作成したものを紹介して、どんな情報が可視化できるのか!? 試してみた結果をお届けします。

また、チャットツールって結構会社さんごとに使い方にばらつきがあるのではないかと思っているので、SNSを通じて、みんなが使っているSlackの状況を共有してもらおうと考えています!

いい感じに協力してくれた方のレポートが集まったら、それをまとめた記事+勉強会での発表もしようかなと考えていますので、是非ご協力いただければと思います!

こんなレポートが出来上がった!

早速ですが、作成した Slack 利用状況レポートを紹介したいと思います。

今回はなんと Microsoft Power BI MVP の清水さんに協力頂いてレポートを作成してもらうことができました!

こんな感じのレポートです! 接続先は清水さんがイベントの管理などで利用しているSlackとのこと。

f:id:sugimomoto:20190516195540p:plain

Messages数の偏りやチャネルごとの投稿状況、時間帯別の投稿状況が可視化されていて、面白いレポートに仕上がっています!

f:id:sugimomoto:20190516195546p:plain

そのSlackの役割にもよるかもしれませんが、メインのチャネルが固定されていて、ユーザー投稿にもかなり偏りがあることが見て取れます。

私は勝手に、チャネルごとにみんなバラバラ投稿しているんじゃないかなと思っていたりしたのですが、やはりSlackごとに特色があるものですねー。

ちなみに、以下のURLでReportのテンプレートの使い方を公開しています!

bit.ly

是非試してみてください! そしてよかったら、Poewr BI Facebook Groupかツイッターで流してもらえると、みんなで比較ができるので、いろんな考察が捗るのではないかと思っています。

Slackのデータはどうやって取得するの?

それでは実際にレポートを作るためのデータ取得方法を解説したいと思います。

Slackのデータは現状Power BI に標準のコネクタが無いので、基本的には Web API 経由で取得しないといけません。ただ、認証だったり、取得したJsonのパースだったり、テーブル形式に直したりと、手間がかかることが多いので、CData Slack Power BI Connectorを使って、楽をします。

f:id:sugimomoto:20190516195636p:plain

https://www.cdata.com/jp/drivers/slack/powerbi/

こちらのページから「ダウンロード」をクリックして、評価版を入手してみてください。

継続的にデータを分析するのであれば製品版が必要ですが、一回きりの取得であれば、機能差は無いので評価版で大丈夫です。

ダウンロード後、インストーラーが起動するので、そのまま次へ進めていきます。

f:id:sugimomoto:20190516195702p:plain

インストールが完了すると、以下のように接続設定の画面が表示されます。

特に入力は不要で、そのまま「接続のテスト」をクリックすればOKです。

f:id:sugimomoto:20190516195708p:plain

すると、以下のようにOAuthの承認画面が表示されるので、内容を確認の上「許可する」をクリックしてください。

f:id:sugimomoto:20190516195714p:plain

f:id:sugimomoto:20190516195719p:plain

以下のような画面が表示されれば接続OKです。接続画面もそのままOKをクリックして閉じます。

f:id:sugimomoto:20190516195725p:plain

Power BI でのデータ取得方法

それでは、Power BIからSlackのデータを取得してみます。

まずは手軽にチャンネルの一覧から。

f:id:sugimomoto:20190516195731p:plain

CData Power BI Connectorのインストールが正常に完了していると、データを取得の一覧で、以下のようにCData Slackのアイコンが追加されます。これを選択して、「接続」をクリックします。

f:id:sugimomoto:20190516195738p:plain

最初にサードパーティサービスの確認が出てくるので、そのまま続行をクリック

f:id:sugimomoto:20190516195743p:plain

Data Source Nameを選択(1種類しか無いはずです)して、OKをクリックします。ちなみに、CData Power BI ConnectorはSQLでSlackのデータが取得できるようになっているので、SQL Statementのところに「SELECT * FROM hogehoge」と書いてもデータが取得できますが、それは後ほど。

f:id:sugimomoto:20190516195749p:plain

ナビゲーターの画面では、取得できるテーブルの一覧が表示されるので、Channelsを選択して、読み込みます。

f:id:sugimomoto:20190516195755p:plain

すると、こんな感じでチャンネルの一覧が取得できます。

f:id:sugimomoto:20190516195801p:plain

Messageの取得方法

Messageの取得方法は若干特殊です。

もともとSlackのAPIでは、Messageの取得処理にChannelIdが必要となっているので、CData Power BI Connectorを使う場合も、ChannelIdをWhere句で指定する必要があります。

今回はすべてのチャネルからメッセージを取得したいので、Power Queryを使ってこれを実現します。

新しくデータを追加するため、「クエリの編集」をクリックし

f:id:sugimomoto:20190516195943p:plain

「空のクエリ」を追加します。

f:id:sugimomoto:20190516200107p:plain

詳細エディタを開いて、以下のようなクエリを追加します。

let
    Source = "CData Power BI Slack",
    ChannelsQuery = "select * from Channels ",
    MessagesQuery = "select * from Messages Where ChannelId = '",
    
    Channels = CData.Slack.DataSource(Source, null, [Query = ChannelsQuery]),

    ChannelRecoreds = Table.Column(Channels,"Id"),

    AllData = Table.Combine(
    List.Transform(
        ChannelRecoreds,
        each CData.Slack.DataSource(Source, null, [Query = MessagesQuery & _ & "'" ])
        )
    )
in
    AllData

f:id:sugimomoto:20190516200327p:plain

やっていることは単純で「select * from Channels」で取得してきたチャネル一覧を元に、「"select * from Messages Where ChannelId = 」で各チャネルからメッセージを取得しています。

これで、以下のようにメッセージ一覧が取得できます。

f:id:sugimomoto:20190516200505p:plain

あとは取得したデータのリレーションを構成して、レポートを作成できる環境が整います。

f:id:sugimomoto:20190516200607p:plain

おわりに

Power BI で Slack の利用状況を可視化しよう!How to use Power BI Template & CData Power BI Connectoer

この記事では、Power BI Slack 利用状況可視化レポートの使い方を解説します。

実行すると、自身のSlack環境に接続でき、以下のようなレポートが自動で表示されます!

レポートは初期状態でチャネル名やユーザー名を伏せた状態になるので、このままキャプチャしたものを公開してもSlack内の情報が漏れることは無いので安心してください。

f:id:sugimomoto:20190516193809p:plain

f:id:sugimomoto:20190516193815p:plain

Report のTemplateは以下のURLから入手できます。

https://s3-ap-northeast-1.amazonaws.com/cdatajbuilds/sugimototest/SlackPowerBI.zip

Power BI Report Templateの作成には、Power BI の Microsoft MVP である清水さんにご協力いただきました! ありがとうございます!

twitter.com

清水さんは他にも様々なレポートを公開しています。是非見てみてください。

qiita.com

必要なもの

実施にあたり必要なものは以下のとおりです。

  1. Power BI Desktop ※古いバージョンの場合、Templeateが利用できない可能性があるため、最新バージョンをインストールしてください。

  2. Power BI Slack Report Template(こちらからダウンロード https://s3-ap-northeast-1.amazonaws.com/cdatajbuilds/sugimototest/SlackPowerBI.zip

  3. CData Power BI Slack Connector (https://www.cdata.com/jp/drivers/slack/powerbi/

  4. Slack アカウント

注意事項

  1. 無償版 Slack の場合、1環境に登録できるアプリが10までとなっているため、すでに10個アプリを接続している場合は、使用することができません。

  2. 無償版Slackの場合、取得できるメッセージの上限が10,000件までです。そのため、チャネルによっては、

1. CData Power BI Slack Connector のダウンロード・セットアップ

まず Power BI から Slackに接続できるようにするために、CData Power BI Connector を入手します。

以下のURLから30日間のトライアル版がダウンロード可能です。機能制限は無いため、今回はそのまま利用できます。

https://www.cdata.com/jp/drivers/slack/powerbi/

ダウンロードをクリックし

f:id:sugimomoto:20190516194003p:plain

「ダウンロード評価版」を選択します。

f:id:sugimomoto:20190516194011p:plain

必要情報を入力して、「ダウンロード」をクリックしてください。

f:id:sugimomoto:20190516194017p:plain

ダウンロードした、インストーラーはそのまま次へ次へと進めれば、完了します。

f:id:sugimomoto:20190516194023p:plain

2. Slack への接続設定

インストール後、以下のような画面が立ち上がるので、特に何も入力せず「接続のテスト」をクリックしてください。

(ProxyServerなどを経由したい場合は別途設定ができます。わからないことがあれば、私のTwitterFacebookまでどうぞ。@sugimomoto)

f:id:sugimomoto:20190516194029p:plain

「接続のテスト」をクリックすると、OAuth認証処理が開始されるので、ログインするSlackのアカウントを選択した後、接続の許可を行います。

f:id:sugimomoto:20190516194034p:plain

f:id:sugimomoto:20190516194040p:plain

最終的に以下のような画面が表示されれば、接続構成はOKです。

f:id:sugimomoto:20190516194048p:plain

3. Report Template を立ち上げる

最後にダウンロードした Report Template を開きます。

f:id:sugimomoto:20190516194053p:plain

立ち上げるとODBCの接続情報入力が表示されるので「CData Power BI Slack」と入力します。(※スペースなどに気をつけてください)

f:id:sugimomoto:20190516194058p:plain

すると、先程接続構成を行ったSlackからデータの取得処理が開始されます。

f:id:sugimomoto:20190516194105p:plain

取得が完了すると、以下のようにレポートが表示されます。

f:id:sugimomoto:20190516194113p:plain

4. よかったら FacebookTwitter でシェアしてください。

Facebook で Power BI Groupがあるので、是非投稿してください。

www.facebook.com

また、ツイッターでのツイートも大歓迎です! 以下はハッシュタグ付きのツイート用URLです。

twitter.com

Office365 GraphAPI で認証アプローチ毎のアクセス範囲にハマった話 ユーザーの予定(Event)を横断的に取得したい! 

先週くらいに、Office365 のCalendar情報を横断的に取得したいという要望があって調べていたんですが、ちょっと変に先入観があって躓いていました。

https://twitter.com/sugimomoto/status/1113275622841737218?s=20

いろいろと試行錯誤を経て解決したんですが、改めて全体像を調べてスッキリ理解できたので、GraphAPIにおける認証アプローチとアクセス範囲に関する考え方をまとめておきたいと思います。

ちなみにわかり易さから予定表(イベント)の取得に焦点を当てていますが、考え方はファイルやメールなどにも共通するお話です。

なお、Exchange Online(EWS)ベースのアプローチであれば、以前取り組んでいたのをBlogにしています。

kageura.hatenadiary.jp

やりたかったこと

Office365の予定表では、以下のような感じにいろんな人の予定が見えるようになっていると思いますが、これをGraphAPI経由で横断的に取得したい、というのが今回の目的です。

こんな感じの予定データを

f:id:sugimomoto:20190422185231p:plain

横断的に取得して、分析活用したい、というイメージですね。

f:id:sugimomoto:20190422185236p:plain

データ連携的観点でも、例えば外部のCRMアプリケーションなどで作られた営業案件の再訪問スケジュールを連携して、結果を確認したい、みたいなことがあると思います。

それを実現するための、GraphAPIアクセス範囲・アクセス許可の考え方です。

今回のお話の焦点:Azure AD アプリにおけるGraphAPIのアクセス許可

今回とりあげるのは、Azure ADのアプリケーション登録で行う以下のアクセス許可の話です。

f:id:sugimomoto:20190422185247p:plain

以下のリファレンスがベースになりますが、私の解釈も踏まえてざっくりお話していきます。

docs.microsoft.com

ベースとなるアクセス許可は2種類

まず、大前提として抑えておきたいことは、ベースとなる「アクセス許可」は2種類存在するということです。

docs.microsoft.com

それが、「委任されたアクセス許可」と「アプリケーションのアクセス許可」です。

f:id:sugimomoto:20190422185322p:plain

なんのことを言っているんだ、となるかもしれませんが、これはOAuthのAuthorizationURLが2種類

「委任されたアクセス許可」の場合以下のようなURLで

https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?client_id=6731de76-14a6-49ae-97bc-6eba6914391e&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F&response_mode=query&scope=offline_access%20user.read%20mail.read&state=12345

このようなアクセス許可を求められますね。

f:id:sugimomoto:20190422185349p:plain

https://docs.microsoft.com/ja-jp/graph/auth-v2-user#2-get-authorization

「アプリケーションのアクセス許可」の場合は、URL構成が変わって、

https://login.microsoftonline.com/{tenant}/adminconsent?client_id=6731de76-14a6-49ae-97bc-6eba6914391e&state=12345&redirect_uri=https://localhost/myapp/permissions

ちょっとだけ、メッセージも変わったことがわかると思います。

f:id:sugimomoto:20190422185355p:plain

https://docs.microsoft.com/ja-jp/graph/auth-v2-service#3-get-administrator-consent

メッセージが示すとおりでもありますが、それぞれで役割が違います。

  • 委任されたアクセス許可

明示的なサインインユーザーが存在する場合に利用するアプローチです。 これは言ってしまえば、ユーザー自身がOffice365を利用する時と同様のアクセス範囲を想定した 自分の予定、自分のメール、自分のファイルをベースに、アクセス許可を行ったユーザーに共有されたgファイル、予定などにもアクセスすることを想定しています。

  • アプリケーションのアクセス許可

明示的なサインインユーザーが存在しないアプリで利用するアプローチです。たとえば、バックグラウンド でデータ連携をしたり、強力な権限で組織全体のリソースにアクセスしたい場合に使用します。そして注意したいのが、アプリケーションのアクセス許可は「管理者のみが同意」してはじめて利用できるようになるという点です。

GraphAPIリソースへのアクセス許可は「リソース:操作:制約」の3つで捉える

その上で、GraphAPIのアクセス許可は以下の図に示すように、「リソース:操作:制約」の3つで捉えるのが個人的にいいと思っています。

  • リソースは「Event、File」など、どんなデータにアクセスするのか
  • 操作は「Read、Write」など、データに対してどんな処理を行うのか
  • 制約は「All、Shared、None」など、どの範囲までアクセスするのか

f:id:sugimomoto:20190422185433p:plain

今回の図は趣旨を理解しやすくするために単純化していますが、「操作」と「制約」はこれ以外にもいくつかあります。

必要な操作とリソースの特定方法

おそらく、操作とリソースは比較的わかりやすいでしょう。

予定を取りたいなら、CalenderのRead

予定の書き込みも行いたいなら、CalenderのReadWrite

各必要なリソース名、操作はそれぞれのリソースページから確認することができます。

例えば予定(Event)の主得であれば、以下の通り。

docs.microsoft.com

f:id:sugimomoto:20190422185443p:plain

アクセス範囲の肝となる「制約」の考え方

そして、今回のポイントになるのは、この「制約」の部分になります。

基本的な制約の種類は以下の3種類。一番上が強い権限です。

  • All
  • Shared
  • None(制約の指定無し)

Noneだけちょっと分かりづらいですが、一番弱い(アクセス範囲が狭い)権限です。ドキュメントでは「制約の指定無し」と書かれていて、混乱を招きやすいですね・・・。一番弱い制約って言うと語弊がありますし。

これ以外に、AppFolderや各リソース固有のものが存在しますが、基本的には上記の3種類がベースになっていると思っていいと思います。

それぞれの制約の範囲イメージ

これらの制約をEventのリソースをベースに表したのが、以下のそれぞれの図になります。

Noneの場合は、アプリケーションにログインしたユーザー自身のリソースにしかアクセスできません。これは、予定が共有されていたとしても変わりません。

f:id:sugimomoto:20190422185507p:plain

そして、もう少しアクセス範囲を広げたい場合は、Sharedが必要になります。この場合は自分の予定に加えて、共有されている予定にもアクセスできます。

f:id:sugimomoto:20190422185515p:plain

そして、最後に共有されていない予定にもアクセスしたい場合は、「All」が必要になります。これが今回私が必要としていたアクセス範囲です。

一番注意したいのが、委任されたアクセス許可では、この制約範囲を利用できない、ということです。

f:id:sugimomoto:20190422185522p:plain

制約で「All」を使いたい場合は 2種類のアクセス許可に気をつける

ここが今回私が躓いたポイントでした。

アプリケーションの権限で「Calender.ReadAndWrite.All」を付与していたにも関わらず、アクセス許可は「アプリケーションのアクセス許可」で実施していなかったので、他のユーザーのリソースにアクセスしようとしても「Access is denied.」になってしまいました。

f:id:sugimomoto:20190422185534p:plain

それぞれの「アクセス許可」方法の確認

ここまで来れば、あとはそれぞれの「アクセス許可」を使ってAccessTokenを取得するだけです。

アプリケーションの登録方法はどちらも同じですが、アクセス許可の方法は

「委任されたアクセス許可」の場合、「AuthorizationCode」

「アプリケーションのアクセス許可」の場合、「ClientCredential」

で実施します。

ちなみに、Graphエクスプローラーは現在「AuthorizationCode」にしか対応していないみたいなのでご注意ください。

「委任されたアクセス許可」を使ってユーザーの代わりにアクセスを取得する

ほとんどリファレンスに書かれている通りなので、要点だけ記載します。

docs.microsoft.com

1. AuthorizationURLを生成して、ユーザーへログイン要求を実施

この時ポイントになるのが、Scopeパラメータ。アプリ側で権限を許可していても、ここでスコープの要求をしない限り、操作を実施することはできないので要注意。

https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?client_id=6731de76-14a6-49ae-97bc-6eba6914391e&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F&response_mode=query&scope=offline_access%20user.read%20mail.read&state=12345

f:id:sugimomoto:20190422185554p:plain

2. アクセス許可後のリダイレクトURLに含まれる「Code」を使って、AccessTokenを取得

Callbackとして、以下のようなデータが返却されるので、Stateをチェックし、Codeを取得したら

https://localhost/myapp/?
code=M0ab92efe-b6fd-df08-87dc-2c6500a7f84d
&state=12345

そのCodeを利用して、TokenエンドポイントにAccessTokenを要求します。この時GrantTypeはAuthoricationCodeを指定します。

POST https://login.microsoftonline.com/common/oauth2/v2.0/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&scope=user.read%20mail.read
&code=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq3n8b2JRLk4OxVXr...
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&grant_type=authorization_code
&client_secret=JqQX2PNo9bpM0uEihUPzyrh

これで晴れてAccessTokenが取得できます。

{
    "token_type": "Bearer",
    "scope": "user.read%20Fmail.read",
    "expires_in": 3600,
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...",
    "refresh_token": "AwABAAAAvPM1KaPlrEqdFSBzjqfTGAMxZGUTdM0t4B4..."
}

「アプリケーションのアクセス許可」の仕方、ユーザーなしでアクセスを取得する

docs.microsoft.com

アプリケーションのアクセス許可も基本プロセスは似ていますが、要所要所でちょっと違います。

1. Adminconsentエンドポイントを使って、管理者の同意を実施

前述したとおり、一番最初に必要なことは、対象のアプリケーション(ClientID)に対して、管理者が同意するというプロセスです。「委任されたアクセス許可」とはURLやパラメータが違うことに注意してください。

GET https://login.microsoftonline.com/{tenant}/adminconsent
?client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&state=12345
&redirect_uri=https://localhost/myapp/permissions

f:id:sugimomoto:20190422185624p:plain

また、レスポンスも変わり、「委任されたアクセス許可」であったようなCodeは含まれません。つまり、「アプリケーションのアクセス許可」の場合、同意と後続のプロセスは独立した形になります。

GET https://localhost/myapp/permissions
?tenant=a8990e1f-ff32-408a-9f8e-78d3b9139b95&state=12345
&admin_consent=True

2. 同意された後、AccessTokenを取得する

同意が完了したら、あとはAccessTokenを取得するだけです。前述したとおり、Codeを渡す必要は無いので、同意さえ取っていれば、どのタイミングで実施しても問題ありません。

POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded

client_id=535fb089-9ff3-47b6-9bfb-4f1264799865
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_secret=qWgdYAmab0YSkuL1qKv5bPX
&grant_type=client_credentials

あとは、同じようにAccessTokenがレスポンスで変えるだけですが、Scopeが含まれないので要注意。

{
  "token_type": "Bearer",
  "expires_in": 3599,
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBP..."
}

※ちなみに、管理者の同意はAzure ADのアプリケーション管理画面で「アクセス許可の付与」をクリックすれば、特にURLの生成などは必要なく実施することができます。(逆に手軽に実施できてしまうので要注意)

f:id:sugimomoto:20190422185652p:plain

余談:そもそも「管理者」ってどんな「管理者」?

GraphAPIとAzure ADのアプリリファレンスを見ていると、たくさんの「管理者」というキーワードに遭遇します。

そして、今ひとつどの管理者設定を入れておけば、この管理者という要件を満たすのかが、いまいちわかりづらいですね。

管理者の同意に必要な権限は何か?

結論から言うと、Azure AD ロールの「アプリケーション管理者(全体管理者でももちろんOK)」が必要です。

アプリケーション管理者:このロールのユーザーは、エンタープライズ アプリケーション、アプリケーション登録、アプリケーション プロキシの設定の全側面を作成して管理できます。 さらに、このロールは、委任されたアクセス許可とアプリケーション アクセス許可 (Microsoft Graph と Azure AD Graph を除く) に同意する権限を付与します。 このロールに割り当てられたユーザーは、新しいアプリケーション登録またはエンタープライズ アプリケーションを作成する際に、所有者として追加されません。

https://docs.microsoft.com/ja-jp/azure/active-directory/users-groups-roles/directory-assign-admin-roles

以下の画面で付与することができます。

f:id:sugimomoto:20190422185718p:plain

なので、例えば、予定表を取得したいからといって、Exchangeの管理者権限が必要か? といえばそんなことは無いようです。アプリケーション管理者が同意してしまえば、そのClientIDはその権限にしたがって効力を発揮します。

ちなみに、私がはじめ勘違いしていたのですが、Office365 管理画面で表示できる、この画面の役割とさっきのAzure ADロール管理画面の役割は一緒です。同期されてます。

f:id:sugimomoto:20190422185708p:plain

ただし、アプリケーション管理者のロールはAzure ADロール管理画面でしか付与することができませんので要注意。

実際に予定を取得してみる

というわけで、実際に予定を取得してみます。せっかくなので「アプリケーションのアクセス許可」で試してみましょう。シェアをしていないユーザーの想定です。

docs.microsoft.com

1. Azure AD アプリケーション登録

まず、リファレンスにある通り、「Calendars.Read.All」の権限を持ったAzure ADアプリを作成。

CientIDとCientSecretを取得します。(アプリの作り方は以前Blogで書いているので割愛。)

kageura.hatenadiary.jp

2. 管理者の同意を取得

さくっと、Azure ADの画面から実施してしまいます。

f:id:sugimomoto:20190422185652p:plain

3. アクセストークンの取得

そして、アクセストークンを取得します。

POST /a67527d4-180e-4472-bcdd-bca82c56c70a/oauth2/token?api-version=1.0 HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=XXXXXXXXXXXXXXXXXXXXXXXXXX
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_secret=XXXXXXXXXXXXXXXXXXXXXXXXXXXX=
&grant_type=client_credentials

4. 指定ユーザーのイベントを取得

通常、自分自身のイベントを取得する場合は以下のようなURLですが

GET /me/events

他のユーザーのイベントを取得する場合はUsersの後にXXX@XXX.onmicrosoft.comといった形でユーザーを指定することで、予定を取得できます。

GET /users/{id | userPrincipalName}/events

実際にはこんな感じのリクエストですね。

GET /v1.0/users/user01@sugimomoto21.onmicrosoft.com/events HTTP/1.1
Host: graph.microsoft.com
Authorization: Bearer eyJ0XXXXXXXXX

CData Office365 Driverの対応状況

ちなみに、CData Office365 Driverを使って、予定やファイルの取得が可能なのですが、今の所「委任されたアクセス許可」のみに対応中でした。

でも、やっぱり管理権限でバッチ処理を動かしたり、予定を横断的に取得したいというシナリオはよく聞くので、現在USチームと実装に向けてディスカッション中です。

もし、そういった使い方

https://www.cdata.com/jp/drivers/office365/

ちなみに、Excel-Addinで予定を取得する場合は、Office365 Excel Add-inをインストールして

Excelのリボンから「From Office365」をクリック

f:id:sugimomoto:20190422191723p:plain

接続画面はDefaultのままでいいので、「Test Connection」をクリック

f:id:sugimomoto:20190422191756p:plain

同意画面が表示されるので、内容を確認して、承諾するだけ。

f:id:sugimomoto:20190422192313p:plain

接続が完了します。

f:id:sugimomoto:20190422192328p:plain

あとは、Eventsテーブルを選択して、OKをクリックすれば

f:id:sugimomoto:20190422192422p:plain

自分自身の予定データがずらっと取得できます。

f:id:sugimomoto:20190422192551p:plain

おわりに

結構権限周りを調べるのはめんどいことがわかった記事でした。

結構悩む人は多いのではなかろうか。。。

追記 20210201

「アプリケーションのアクセス許可」と書くべきところを、「委任されたアプリケーションアクセス許可」と書いていたので修正しました。

Dynamics 365 Business Central GraphAPI(Beta)を触ってみる:トライアル取得からGraphエクスプローラーでアクセスするまで

Dynamics シリーズとしては初となる、GraphAPI エンドポイントが Dynamics Business Centralで提供されはじめましたー。

まだ、Betaの状況ですが、基本的な機能は試せる感じです。

今回はトライアルアカウントの取得方法とGraphエクスプローラーでテストするまでを書き留めておきたいと思います。

Dynamics 365 Business Centralって?

f:id:sugimomoto:20190414155422p:plain

https://dynamics.microsoft.com/ja-jp/business-central/overview/

公式サイトから引用すると

財務、営業、サービス、運用を結び付けることができるオールインワンの ERP ビジネス管理ソリューション

もともとはDynamics NAVとして提供されていた製品が Dynamics 365に統合され、正式にクラウド版として提供を開始され、製品名をリブランディングした、といった形でしょうか。

日本では、PBCが日本語へのローカライゼーションを行って、提供していますね。

https://www.pbc.co.jp/product/microsoft-dynamics-nav/dynamics-365-business-central/

f:id:sugimomoto:20190414155937p:plain

Business Central Graph APIドキュメント

以下のURLで API ドキュメントが提供されています。

docs.microsoft.com

f:id:sugimomoto:20190414155437p:plain

もともとはDynamics 365 BC のユーザー画面やWeb Serviceの画面から認証用のKeyを発行したり、有効化を行ったりしていましたが、今回からGraphAPIに統合されたので、認証もAzure ADベースで行います。

docs.microsoft.com

Azure ADでのアクセス方法は以前私のBlodでも書いていましたが、今回はGraphエクスプローラーで簡易的に試すので割愛します。

kageura.hatenadiary.jp

GraphAPIなのでもちろんODataベースでの提供です。

docs.microsoft.com

Dynamics 365 BC自身も以前からODataでAPIを提供していたので、あまり操作感は変わらないでしょう。

ページングやフィルター、バッチ要求なども恐らくGraphAPIの機能範囲でサポートされると思いますが、細かなサポート範囲は特に記載がありませんでした。

トライアルを申し込む前に

トライアルにはUSのOffice365アカウント(XXX@XXX.onmicrosoft.com)が必要です。現在日本地域で取得したOffice365アカウントでは作成することができません。

Dynamics 365 のページからはアカウントを作ることができなくなっているみたいなので、適当にOffice365 USサイトからE3のトライアルを申し込むのがいいと思います。

https://products.office.com/en-us/business/office-365-enterprise-e3-business-software

f:id:sugimomoto:20190414155531p:plain

Business Central の Free Trial を申し込む

US版Office365アカウントを取得してしまえば、環境の取得は結構簡単です。

以下のURLにアクセスして、「START FREE」をクリック

https://dynamics.microsoft.com/en-us/business-central/overview/

f:id:sugimomoto:20190414155556p:plain

取得したUS版Office365アカウントを入力して、SignUP

f:id:sugimomoto:20190414155608p:plain

あとは2クリックくらいするだけで、特に難しい設定はなく作業が完了します。らくちん。

f:id:sugimomoto:20190414155617p:plain

Graphエクスプローラーで戯れる

それでは、APIを試してみたいと思います。

以下のURLにアクセスして、取得したアカウントでサインインします。

https://developer.microsoft.com/ja-jp/graph/graph-explorer

f:id:sugimomoto:20190414155625p:plain

ログイン後、必要な委譲権限を追加します。権限はシンプルで、一つだけ。

Financials.ReadWrite.All

f:id:sugimomoto:20190414155631p:plain

以下のようにドキュメントに記載されています。

f:id:sugimomoto:20190414155638p:plain

これを付けて再度認証すればOKです。

APIの実行

Dynamics 365 BCは会社情報(Companies)を中心としてデータが集積されています。

なので、とりあえずCompaniesを取得してみます。

docs.microsoft.com

GET https://graph.microsoft.com/beta/financials/companies

f:id:sugimomoto:20190414161632p:plain

{
    "@odata.context": "https://graph.microsoft.com/beta/$metadata#financials/companies",
    "value": [
        {
            "id": "c79fb153-0632-4e09-bad7-ccb78bd13dac",
            "systemVersion": "29776",
            "name": "CRONUS USA, Inc.",
            "displayName": "CRONUS USA, Inc.",
            "businessProfileId": ""
        },
        {
            "id": "a5d0bc68-7ab8-4ab5-99ab-a30aa5d250f3",
            "systemVersion": "29776",
            "name": "My Company",
            "displayName": "",
            "businessProfileId": ""
        }
    ]
}

次に対象のCompaniesが特定できたので、その会社に紐付いた顧客を取得してみます。

companiesに対象の会社GUIDを渡して、accountsエンドポイントを叩きます。

companies('c79fb153-0632-4e09-bad7-ccb78bd13dac')/accounts

GET https://graph.microsoft.com/beta/financials/companies('c79fb153-0632-4e09-bad7-ccb78bd13dac')/accounts

f:id:sugimomoto:20190414155715p:plain

こんな感じで取得できました。

{
    "@odata.context": "https://graph.microsoft.com/beta/$metadata#financials/companies('c79fb153-0632-4e09-bad7-ccb78bd13dac')/accounts",
    "value": [
        {
            "@odata.etag": "W/\"JzQ0O3RRQ2NNZUZNMUtWa2VmQytLRHZQbmFtZW9od2JjTThFR3ZjbWpNWGtmQ3c9MTswMDsn\"",
            "id": "fed40b9a-754d-420a-82b0-03530193b3dc",
            "number": "40100",
            "displayName": "Income, Services",
            "category": "Income",
            "subCategory": "Income, Services",
            "blocked": false,
            "lastModifiedDateTime": "2019-03-24T13:21:11.5Z"
        },
        {
            "@odata.etag": "W/\"JzQ0O3pCWG9YN2MxVnNGY0xSdWRYWWh6VVFiSTBkWUNmWVB4NHlvS2tBaXVQa2s9MTswMDsn\"",
            "id": "aa758160-4702-4a48-bb56-03dc92845959",
            "number": "10600",
            "displayName": "Prepaid Insurance",
            "category": "Assets",
            "subCategory": "Prepaid Expenses",
            "blocked": false,
            "lastModifiedDateTime": "2019-03-24T13:21:10.63Z"
        }
    ]
}

せっかくなので、顧客情報の作成も試してみようと思いましたが、

https://docs.microsoft.com/ja-jp/graph/api/dynamics-create-customer?view=graph-rest-beta

POST https://graph.microsoft.com/beta/financials/companies('c79fb153-0632-4e09-bad7-ccb78bd13dac')/accounts
{
  "number": "10000",
  "displayName": "Coho Winery",
  "type": "Company",
  "address": {
    "street": "192 Market Square",
    "city": "Atlanta",
    "state": "GA",
    "countryLetterCode": "US",
    "postalCode": "31772"
  },
  "phoneNumber": "",
  "email": "jim.glynn@cronuscorp.net",
  "website": "",
  "taxLiable": true,
  "taxAreaId": "taxAreaId-value",
  "taxAreaDisplayName": "tax area",
  "taxRegistrationNumber": "28012001T",
  "currencyId": "currencyId-value",
  "currencyCode": "USD",
  "paymentTermsId": "paymentTermsId-value",
  "shipmentMethodId": "shipmentMethodId-value",
  "paymentMethodId": "paymentMethodId-value",
  "blocked": false,
  "overdueAmount": 0,
  "totalSalesExcludingTax": 0,
}

f:id:sugimomoto:20190414155730p:plain

「Entity does not support insert.」と怒られてしまいました。このあたりはまだBetaだからなんでしょうか?

{
    "error": {
        "code": "BadRequest_MethodNotAllowed",
        "message": "Entity does not support insert.",
        "innerError": {
            "request-id": "ca27a7a2-caca-485e-86b4-4e5138f760a6",
            "date": "2019-04-14T06:50:37"
        }
    }
}

とりあえず、試せるだけ試せることがわかったので、今回はこれで満足です。

Publicリリースはいつになるのか、気になるところですねー。

Dynamics 365 for Customer Engagement (Dynamics CRM) のデータを ローカルの SQL Server に1時間に1回バックアップする:CData Sync

クラウドサービスを使っていて、一番面倒なことの筆頭として、「バックアップどうするの?」があげられるんじゃないかなと思います。

もちろん、何を観点として「バックアップ」と言うのか? については多くの議論が必要になるでしょう。

Dynamics 365 自体もクラウドとしてディザスタリカバリやデータセンターのバックアップについては十分ちゃんとした対応を取っています。

でも、自分たちの手元に自分たちがコントロールできる状態にデータを持っておきたい、という考えはベンダーに依存するよりも健全であるし、多様なクラウドサービスの選択肢がある今の時代においては適切な判断ではないかと思っています。

それは採算やコスト度外視なアプローチではなく、現実的なラインで自分たちが適切にコントロールしメリットを感じられるスケールで行うことが大事かなと。

今回はそんなバックアップ手段の一つの選択肢として、Dynamics 365 for Customer Engagement のデータをローカルのSQL Serverにバックアップする方法を書き留めておきたいと思います。

続きを読む

2月20日にWindows女子部で「Dynamics 365 Customer Engagement 理解のススメ -サブスクリプションビジネスモデルから読み解くカスタマーサポート機能活用のポイント-」の発表をしてきました

久しぶりに Dynamics 365 一色なセッションを2月20日Windows女子部で発表してきました。

(Burikaigi 2019ではちょっといろいろ手を出していたのと共同セッションだったので、また今回は毛色が違いますね。)

f:id:sugimomoto:20190226205241p:plain

connpass.com

第して、「Dynamics 365 Customer Engagement 理解のススメ -サブスクリプションビジネスモデルから読み解くカスタマーサポート機能活用のポイント-」

以下でセッションスライドを公開しています。

www.slideshare.net

なんでこんな発表をしようと思ったのか?

今回 Windows 女子部という、あまり普段 Dynamics に馴染みが無い層の方々向け、ということを考えていた部分もありますが、

おそらく大きく影響したのは私自身が「SIerでは無くなったこと」が大きなきっかけとしてあるなと思います。

視点が実際にCRMを使って、業務を効率化したり、可視化する側のエンドユーザーサイドに立ったことで、今までの自分自身の知っているコンテンツを棚卸しし、かつ私自身のエンドユーザー経験も踏まえて、Dynamics ってこういうことじゃないの? というお話をまとめてみたいなーという野望がありました。

かつ、昨今 Power Platform (Power Apps / Power BI / Flow)が広まって、徐々に認知されるようになってきた Dynamics 365 シリーズですが、まだ実際に触った方は少ないのではないかなと思うので、そもそも Dynamics 365 を理解するためには、何から始めるべきなのか? という下地の部分を訴えてみたかったところもあります。

機能とかデータモデルとか触ってみるとかのその前に、「考え方」「捉え方」から伝えてみたい。それが以下の1スライドのメッセージでも掲げられているところかなと思っています。

Dynamics 365 CEを理解するためには Dynamics 365 CE を知る・触るよりも前に 何かの課題を解決しようとした ビジネスモデル・手法を理解する必要がある

それをより明確に伝えるため、昨今のビジネスモデルの流れ、サブスクリプションビジネスモデルを取り上げることで、よりよく Dynamics 365を理解するための礎になればという感じでした。

個人的にテクニカルな内容は5%くらいで、かなり新しい試みのセッションになりました。

すごく独断と偏見と経験にまみれた内容ではあります。(Microsoftはこんなことを言ってはいないw)

でも、ビジネスモデルに多様な「解」があるように、おそらくこれも一つの「解」なのだと思って見てもらえると嬉しいです。

今後 Dynamics 365 の導入を予定されている会社の参加者からも「すごく参考になった、ここのなぜ? どうやって?使うのかという意識の部分は、私の会社でも根付かせていかなければいけない」といったコメントをいただけて、個人的な棚卸しも含めてとても有意義なセッションだったなと思います。

せっかくなので、このあたりの「考え方」の部分は、今後もどこかで発表しつつ棚卸ししていきたいなと思った次第です。