Salesforceのフローにおいて、アップロードされた画像ファイルの公開リンクを発行し、公開リンクの遷移先の画像ファイルのURLを取得する仕組みを考えてみます。
考える具体例
Salesforceにアップロードされた画像ファイルの入力によって、最新バージョンの公開リンクの作成から画像ファイルのURLの取得までを実行する自動起動フローを構築します。
自動起動フローにしておくことで、外部のフローからいつでも呼び出すことができるようになります。
公開リンクの遷移先の画像ファイルのURLの形式
公開リンクの遷移先の画像ファイルのURLの形式は、組織の特定のホスト名を使用して下記のような形式で表記されます。
https://[ホスト名]/sfc/dist/version/renditionDownload
ここで、ホスト名
は組織の設定によってファイルのホスト名(file.force.com
)または組織のログインドメインのホスト名(my.salesforce.com
)になります。
フローを構築する前にテストとして公開リンクを発行し、URLを確認してホスト名を確認しておきます。
また、本記事ではホスト名の取得に【Apex】各種ホスト名の取得アクションを利用します。
公開リンクの遷移先の画像ファイルのURLのパラメータ
URLに付加されるパラメータは下記の通りです。
パラメータ | 変数/定数 | 設定される値 |
---|---|---|
rendition | 変数 | ファイル形式に依存したパラメータ |
versionId | 変数 | ContentVersionレコードのID(15桁) |
operationContext | 定数 | DELIVERY |
contentId | 変数 | ContentDocumentレコードのID(15桁) |
page | 定数 | 0 |
d | 変数 | ContentDistributionのDistributionPublicUrl項目の"/a/"以降の値 |
oid | 変数 | OrganizationレコードのID(15桁) |
dpt | 定数 | null |
viewId | なし |
実装方法
フローの種類を選択する
フローの種類は 「自動起動フロー(トリガーなし)」 を選択します。
入力変数を定義する
入力変数として下記を準備します。
- ContentDocumentId : アップロードしたファイルのContentDocumentレコードのIDを入力するテキスト型の入力で使用可能な変数
出力変数を定義する
出力変数として下記を準備します。
- PublicURL : 公開リンクの遷移先の画像ファイルのURLを出力するテキスト型の出力で使用可能な変数
内部変数を定義する
内部変数として下記を準備します。
- Renditions : 対応するファイル形式を設定するテキスト型のコレクション変数
- DistributionPublicUrl : 公開リンクのURLを設定するテキスト型の変数
対応するファイルを識別する定数を定義する
対応するファイルを識別する定数として下記を準備します。
- RENDITION_JPG : 対応するファイルとしてJPGを設定する定数
- RENDITION_PNG : 対応するファイルとしてPNGを設定する定数
対応するファイル形式を増やしたい場合、種類に応じた定数を増やす必要があります。
対応するファイル形式を設定するコレクション変数を準備する
割り当て要素を使用して、コレクション変数に対応するファイル形式を設定します。
ここでは下記のような設定とします。
- API参照名 : Assign_Renditions
- 変数値を設定 :
- {!Renditions} 追加 {!RENDITION_JPG}
- {!Renditions} 追加 {!RENDITION_PNG}
コンテンツドキュメントを取得する
レコードの取得要素を使用して、入力変数に対するコンテンツドキュメント(ContentDocument)を取得します。
ここでは下記のような設定とします。
- API参照名 : Get_ContentDocument
- オブジェクト : コンテンツドキュメント
- 絞り込み条件 : すべての条件に一致(AND)
- Id 次の文字列と一致する {!ContentDocumentId}
- 保存するレコード数 : 最初のレコードのみ
コンテンツドキュメントの拡張子を判定する
決定要素を使用して、取得したコンテンツドキュメントが対応するファイル形式か判定します。
ここでは下記のような設定とします。
- API参照名 : Decision_ContentDocumentFileExtension
- 結果 - 1 :
- 表示ラベル : 対応あり
- API参照名 : Decision_ContentDocumentFileExtension_containsRenditions
- 条件 : すべての条件に一致(AND)
- {!Renditions} 次の文字列を含む {!Get_ContentDocument.FileExtension}
- デフォルトの結果 : 対応なし
ホスト名を取得する
Apexアクションを使用してホスト名を取得します。
ここでは下記のような設定とします。
- API参照名 : Get_HostName
- アクション : Get Host Name
- アクションの入力値
- Host Type : Content
- Package Name : 設定なし
今回はファイルのホスト名を使用しますが、設定状況によっては組織のログインドメインのホスト名を使用する場合もあります。
実際に公開リンクを発行して確認をすることをお勧めします。
最新のコンテンツバージョンを取得する
レコードの取得要素を使用して、取得したコンテンツドキュメントに対する最新のコンテンツバージョン(ContentVersion)を取得します。
ここでは下記のような設定とします。
- API参照名 : Get_ContentVersion
- オブジェクト : コンテンツバージョン
- 絞り込み条件 : すべての条件に一致(AND)
- Id 次の文字列と一致する {!Get_ContentDocument.LatestPublishedVersionId}
- 保存するレコード数 : 最初のレコードのみ
公開中のコンテンツ配信を取得する
レコードの取得要素を使用して、取得したコンテンツドキュメントおよび取得したコンテンツバージョンに対する公開中のコンテンツ配信(ContentDistribution)を取得します。
ここでは下記のような設定とします。
- API参照名 : Get_PublishedContentDistribution
- オブジェクト : コンテンツ配信
- 絞り込み条件 : カスタム条件ロジックに一致(1 AND 2 AND ( ( 3 AND 4 ) OR NOT 3 ))
- ContentDocumentId 次の文字列と一致する {!Get_ContentDocument.Id}
- ContentVersionId 次の文字列と一致する {!Get_ContentVersion.Id}
- PreferencesExpires 次の文字列と一致する {!$GlobalConstant.True}
- ExpiryDate 以上 {!$Flow.CurrentDate}
- 並べ替え : 降順 : CreatedDate
- 保存するレコード数 : 最初のレコードのみ
公開中のコンテンツ配信の有無を判定する
決定要素を使用して、取得した公開中のコンテンツ配信の有無を判定します。
ここでは下記のような設定とします。
- API参照名 : Decision_PublishedContentDistribution
- 結果 - 1 :
- 表示ラベル : 公開中
- API参照名 : Decision_PublishedContentDistribution_isPublished
- 条件 : すべての条件に一致(AND)
- {!Get_PublishedContentDistribution.Id} null {!$GlobalConstant.False}
- デフォルトの結果 : 未公開
公開中のコンテンツ配信の公開リンクを割り当てる
公開中のコンテンツ配信がある場合、割り当て要素を使用して、変数に公開リンクを割り当てます。
ここでは下記のような設定とします。
- API参照名 : Assign_PublishedURL
- 変数値を設定 :
- {!DistributionPublicUrl} 次の文字列と一致する {!Get_PublishedContentDistribution.DistributionPublicUrl}
コンテンツ配信を作成する
公開中のコンテンツ配信がない場合、コンテンツ配信のレコードを作成します。
ここでは下記のような設定とします。
- API参照名 : Create_ContentDistribution
- レコードの項目値の設定方法 : 手動
- オブジェクト : コンテンツ配信
- 項目値の設定 :
- ContentVersionId ← {!Get_ContentVersion.Id}
作成したコンテンツ配信を取得する
レコードの取得要素を使用して、作成したコンテンツ配信(ContentDistribution)を取得します。
ここでは下記のような設定とします。
- API参照名 : Get_ContentDistribution
- オブジェクト : コンテンツ配信
- 絞り込み条件 : すべての条件に一致(AND)
- Id 次の文字列と一致する {!Create_ContentDistribution}
- 保存するレコード数 : 最初のレコードのみ
作成したコンテンツ配信の公開リンクを割り当てる
割り当て要素を使用して、変数に公開リンクを割り当てます。
ここでは下記のような設定とします。
- API参照名 : Assign_CreatedURL
- 変数値を設定 :
- {!DistributionPublicUrl} 次の文字列と一致する {!Get_ContentDistribution.DistributionPublicUrl}
公開リンクの遷移先の画像ファイルのURLを設定する
公開リンクの遷移先の画像ファイルのURLを数式で作成します。
- Formula_BaseURL : 公開リンクの遷移先の画像ファイルのURLの数式
"https://" + {!Get_HostName.hostName} + "/sfc/dist/version/renditionDownload"
公開リンクの遷移先の画像ファイルのURLのパラメータを設定する
URLに付加されるパラメータを数式で作成します。
-
Formula_Rendition :
rendition
のパラメータを設定する数式
CASE(
{!Get_ContentDocument.FileExtension} ,
{!RENDITION_JPG} , "ORIGINAL_Jpg" ,
{!RENDITION_PNG} , "ORIGINAL_Png" ,
""
)
対応するファイル形式を増やしたい場合、種類に応じた定数を増やす必要があります。
-
Formula_VersionId :
versionId
のパラメータを設定する数式
LEFT( {!Get_ContentVersion.Id} , 15 )
-
Formula_ContentId :
contentId
のパラメータを設定する数式
LEFT( {!Get_ContentDocument.Id} , 15 )
-
Formula_D :
d
のパラメータを設定する数式
RIGHT( {!DistributionPublicUrl} , FIND( "/a/" , {!DistributionPublicUrl} ) + 1 )
-
Formula_OId :
oid
のパラメータを設定する数式
LEFT( {!$Organization.Id} , 15 )
公開リンクの遷移先の画像ファイルのURLを結合する
上記で準備した数式を使用して、公開リンクの遷移先の画像ファイルのURLを結合します。
- Formula_ImagePublicURL : 結合した公開リンクの遷移先の画像ファイルのURLの数式
{!Formula_BaseURL}
+ "?" + "rendision=" + {!Formula_Rendition}
+ "&" + "versionId=" + {!Formula_VersionId}
+ "&" + "operationContext=DELIVERY"
+ "&" + "contentId=" + {!Formula_ContentId}
+ "&" + "page=0"
+ "&" + "d" + {!Formula_D}
+ "&" + "oid=" + {!Formula_OId}
+ "&" + "dpt=null"
+ "&" + "viewId="
出力変数に割り当てる
割り当て要素を使用して、出力変数に結果のURLを割り当てます。
ここでは下記のような設定とします。
- API参照名 : Assign_PublicURL
- 変数値を設定 :
- {!PublicURL} 次の文字列と一致する {!Formula_ImagePublicURL}
フローの完成
完成したフローの形は下記のような形になります。
フローの保存
フローを保存します。
まとめ
発行された公開リンクの遷移先の画像のURLを利用する機会は多くはないですが、稀に必要になる場合があるため記録のために作成しました。
本記事では、公開リンクの遷移先の画像のURLを作成することを目的としていますが、同じような構成で公開リンクのURLやパスワードを設定するフローも作れます。
おまけ
作成したフローのメタデータです。
<?xml version="1.0" encoding="UTF-8"?>
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
<actionCalls>
<name>Get_HostName</name>
<label>ホスト名を取得する</label>
<locationX>182</locationX>
<locationY>458</locationY>
<actionName>HostNameAction</actionName>
<actionType>apex</actionType>
<connector>
<targetReference>Get_ContentVersion</targetReference>
</connector>
<flowTransactionModel>CurrentTransaction</flowTransactionModel>
<inputParameters>
<name>hostType</name>
<value>
<stringValue>Content</stringValue>
</value>
</inputParameters>
<nameSegment>HostNameAction</nameSegment>
<offset>0</offset>
<storeOutputAutomatically>true</storeOutputAutomatically>
<versionSegment>1</versionSegment>
</actionCalls>
<apiVersion>62.0</apiVersion>
<assignments>
<name>Assign_CreatedURL</name>
<label>作成したコンテンツ配信のURLを割り当て</label>
<locationX>314</locationX>
<locationY>1106</locationY>
<assignmentItems>
<assignToReference>DistributionPublicUrl</assignToReference>
<operator>Assign</operator>
<value>
<elementReference>Get_ContentDistribution.DistributionPublicUrl</elementReference>
</value>
</assignmentItems>
<connector>
<targetReference>Assign_PublicURL</targetReference>
</connector>
</assignments>
<assignments>
<name>Assign_PublicURL</name>
<label>出力変数に割り当て</label>
<locationX>182</locationX>
<locationY>1298</locationY>
<assignmentItems>
<assignToReference>PublicURL</assignToReference>
<operator>Assign</operator>
<value>
<elementReference>Formula_ImagePublicURL</elementReference>
</value>
</assignmentItems>
</assignments>
<assignments>
<name>Assign_PublishedURL</name>
<label>公開中のコンテンツ配信のURLを割り当て</label>
<locationX>50</locationX>
<locationY>890</locationY>
<assignmentItems>
<assignToReference>DistributionPublicUrl</assignToReference>
<operator>Assign</operator>
<value>
<elementReference>Get_PublishedContentDistribution.DistributionPublicUrl</elementReference>
</value>
</assignmentItems>
<connector>
<targetReference>Assign_PublicURL</targetReference>
</connector>
</assignments>
<assignments>
<name>Assign_Renditions</name>
<label>対応するファイル形式を設定するコレクション変数の準備</label>
<locationX>380</locationX>
<locationY>134</locationY>
<assignmentItems>
<assignToReference>Renditions</assignToReference>
<operator>Add</operator>
<value>
<elementReference>RENDITION_JPG</elementReference>
</value>
</assignmentItems>
<assignmentItems>
<assignToReference>Renditions</assignToReference>
<operator>Add</operator>
<value>
<elementReference>RENDITION_PNG</elementReference>
</value>
</assignmentItems>
<connector>
<targetReference>Get_ContentDocument</targetReference>
</connector>
</assignments>
<constants>
<name>RENDITION_JPG</name>
<dataType>String</dataType>
<value>
<stringValue>jpg</stringValue>
</value>
</constants>
<constants>
<name>RENDITION_PNG</name>
<dataType>String</dataType>
<value>
<stringValue>png</stringValue>
</value>
</constants>
<decisions>
<name>Decision_ContentDocumentFileExtension</name>
<label>コンテンツドキュメントの拡張子の判定</label>
<locationX>380</locationX>
<locationY>350</locationY>
<defaultConnectorLabel>対応なし</defaultConnectorLabel>
<rules>
<name>Decision_ContentDocumentFileExtension_containsRenditions</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>Renditions</leftValueReference>
<operator>Contains</operator>
<rightValue>
<elementReference>Get_ContentDocument.FileExtension</elementReference>
</rightValue>
</conditions>
<connector>
<targetReference>Get_HostName</targetReference>
</connector>
<label>対応あり</label>
</rules>
</decisions>
<decisions>
<name>Decision_PublishedContentDistribution</name>
<label>公開中のコンテンツ配信の判定</label>
<locationX>182</locationX>
<locationY>782</locationY>
<defaultConnector>
<targetReference>Create_ContentDistribution</targetReference>
</defaultConnector>
<defaultConnectorLabel>未公開</defaultConnectorLabel>
<rules>
<name>Decision_PublishedContentDistribution_isPublished</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>Get_PublishedContentDistribution.Id</leftValueReference>
<operator>IsNull</operator>
<rightValue>
<booleanValue>false</booleanValue>
</rightValue>
</conditions>
<connector>
<targetReference>Assign_PublishedURL</targetReference>
</connector>
<label>公開中</label>
</rules>
</decisions>
<environments>Default</environments>
<formulas>
<name>Formula_BaseURL</name>
<dataType>String</dataType>
<expression>"https://" + {!Get_HostName.hostName} + "/sfc/dist/version/renditionDownload"</expression>
</formulas>
<formulas>
<name>Formula_ContentId</name>
<dataType>String</dataType>
<expression>LEFT( {!Get_ContentDocument.Id} , 15 )</expression>
</formulas>
<formulas>
<name>Formula_D</name>
<dataType>String</dataType>
<expression>RIGHT( {!DistributionPublicUrl} , FIND( "/a/" , {!DistributionPublicUrl} ) + 1 )</expression>
</formulas>
<formulas>
<name>Formula_ImagePublicURL</name>
<dataType>String</dataType>
<expression>{!Formula_BaseURL}
+ "?" + "rendision=" + {!Formula_Rendition}
+ "&" + "versionId=" + {!Formula_VersionId}
+ "&" + "operationContext=DELIVERY"
+ "&" + "contentId=" + {!Formula_ContentId}
+ "&" + "page=0"
+ "&" + "d" + {!Formula_D}
+ "&" + "oid=" + {!Formula_OId}
+ "&" + "dpt=null"
+ "&" + "viewId="</expression>
</formulas>
<formulas>
<name>Formula_OId</name>
<dataType>String</dataType>
<expression>LEFT( {!$Organization.Id} , 15 )</expression>
</formulas>
<formulas>
<name>Formula_Rendition</name>
<dataType>String</dataType>
<expression>CASE(
{!Get_ContentDocument.FileExtension} ,
{!RENDITION_JPG} , "ORIGINAL_Jpg" ,
{!RENDITION_PNG} , "ORIGINAL_Png" ,
""
)</expression>
</formulas>
<formulas>
<name>Formula_VersionId</name>
<dataType>String</dataType>
<expression>LEFT( {!Get_ContentVersion.Id} , 15 )</expression>
</formulas>
<interviewLabel>(自動起動フロー) {!$Flow.CurrentDateTime}</interviewLabel>
<label>(自動起動フロー)画像ファイルの公開リンクURL取得</label>
<processMetadataValues>
<name>BuilderType</name>
<value>
<stringValue>LightningFlowBuilder</stringValue>
</value>
</processMetadataValues>
<processMetadataValues>
<name>CanvasMode</name>
<value>
<stringValue>AUTO_LAYOUT_CANVAS</stringValue>
</value>
</processMetadataValues>
<processMetadataValues>
<name>OriginBuilderType</name>
<value>
<stringValue>LightningFlowBuilder</stringValue>
</value>
</processMetadataValues>
<processType>AutoLaunchedFlow</processType>
<recordCreates>
<name>Create_ContentDistribution</name>
<label>コンテンツ配信を作成</label>
<locationX>314</locationX>
<locationY>890</locationY>
<connector>
<targetReference>Get_ContentDistribution</targetReference>
</connector>
<inputAssignments>
<field>ContentVersionId</field>
<value>
<elementReference>Get_ContentVersion.Id</elementReference>
</value>
</inputAssignments>
<object>ContentDistribution</object>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordCreates>
<recordLookups>
<name>Get_ContentDistribution</name>
<label>コンテンツ配信を取得</label>
<locationX>314</locationX>
<locationY>998</locationY>
<assignNullValuesIfNoRecordsFound>false</assignNullValuesIfNoRecordsFound>
<connector>
<targetReference>Assign_CreatedURL</targetReference>
</connector>
<filterLogic>and</filterLogic>
<filters>
<field>Id</field>
<operator>EqualTo</operator>
<value>
<elementReference>Create_ContentDistribution</elementReference>
</value>
</filters>
<getFirstRecordOnly>true</getFirstRecordOnly>
<object>ContentDistribution</object>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordLookups>
<recordLookups>
<name>Get_ContentDocument</name>
<label>コンテンツドキュメントを取得</label>
<locationX>380</locationX>
<locationY>242</locationY>
<assignNullValuesIfNoRecordsFound>false</assignNullValuesIfNoRecordsFound>
<connector>
<targetReference>Decision_ContentDocumentFileExtension</targetReference>
</connector>
<filterLogic>and</filterLogic>
<filters>
<field>Id</field>
<operator>EqualTo</operator>
<value>
<elementReference>ContentDocumentId</elementReference>
</value>
</filters>
<getFirstRecordOnly>true</getFirstRecordOnly>
<object>ContentDocument</object>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordLookups>
<recordLookups>
<name>Get_ContentVersion</name>
<label>最新のコンテンツバージョンを取得</label>
<locationX>182</locationX>
<locationY>566</locationY>
<assignNullValuesIfNoRecordsFound>false</assignNullValuesIfNoRecordsFound>
<connector>
<targetReference>Get_PublishedContentDistribution</targetReference>
</connector>
<filterLogic>and</filterLogic>
<filters>
<field>Id</field>
<operator>EqualTo</operator>
<value>
<elementReference>Get_ContentDocument.LatestPublishedVersionId</elementReference>
</value>
</filters>
<getFirstRecordOnly>true</getFirstRecordOnly>
<object>ContentVersion</object>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordLookups>
<recordLookups>
<name>Get_PublishedContentDistribution</name>
<label>公開中のコンテンツ配信を取得</label>
<locationX>182</locationX>
<locationY>674</locationY>
<assignNullValuesIfNoRecordsFound>false</assignNullValuesIfNoRecordsFound>
<connector>
<targetReference>Decision_PublishedContentDistribution</targetReference>
</connector>
<filterLogic>1 AND 2 AND ( ( 3 AND 4 ) OR NOT 3 )</filterLogic>
<filters>
<field>ContentDocumentId</field>
<operator>EqualTo</operator>
<value>
<elementReference>Get_ContentDocument.Id</elementReference>
</value>
</filters>
<filters>
<field>ContentVersionId</field>
<operator>EqualTo</operator>
<value>
<elementReference>Get_ContentVersion.Id</elementReference>
</value>
</filters>
<filters>
<field>PreferencesExpires</field>
<operator>EqualTo</operator>
<value>
<booleanValue>true</booleanValue>
</value>
</filters>
<filters>
<field>ExpiryDate</field>
<operator>GreaterThanOrEqualTo</operator>
<value>
<elementReference>$Flow.CurrentDate</elementReference>
</value>
</filters>
<getFirstRecordOnly>true</getFirstRecordOnly>
<object>ContentDistribution</object>
<sortField>CreatedDate</sortField>
<sortOrder>Desc</sortOrder>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordLookups>
<start>
<locationX>254</locationX>
<locationY>0</locationY>
<connector>
<targetReference>Assign_Renditions</targetReference>
</connector>
</start>
<status>Draft</status>
<variables>
<name>ContentDocumentId</name>
<dataType>String</dataType>
<isCollection>false</isCollection>
<isInput>true</isInput>
<isOutput>false</isOutput>
</variables>
<variables>
<name>DistributionPublicUrl</name>
<dataType>String</dataType>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
</variables>
<variables>
<name>PublicURL</name>
<dataType>String</dataType>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>true</isOutput>
</variables>
<variables>
<name>Renditions</name>
<dataType>String</dataType>
<isCollection>true</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
</variables>
</Flow>