Appirio's Tech Blog

2011年5月20日金曜日

実装者のためのセールスフォース・コンテンツ入門

セールスフォース・コンテンツは、組織のビジネス文書を体系立てて整理できる文書の保管庫です。セールスフォース・コンテンツが管理できるビジネス文書には、プレゼンテーションや、商品のデータシート、各種指針、提案書テンプレート、ベストプラクティスなどがあります。セールスフォース・コンテンツは一般的な文書フォーマットに幅広く対応するストレージを提供し、ほとんどのコンテンツがプレビュー閲覧できるので、中身を見る為にわざわざダウンロードする必要がありません。

この入門は、私がセールスフォース・コンテンツを実際に実装しながら、ぶつかった困難や編み出した解決策から作ったものです。ここに記載された ヒントやトリック、そして "落とし穴"が、少しでも実装者の皆さんの時間の節約になることを願います。

用語と概念
まずはセールスフォース・コンテンツの基本的な用語と概念についてざっと確認しましょう。
  • Content Document:これはContentVersionオブジェクトのラッパーオブジェクトです。OwnerやLatestPublishedVersionIdといった項目を持っています。
  • Content Version:(API名は ContentVersion) これはセールスフォース・コンテンツの主要なオブジェクトです。ContentVersionは実際のコンテンツをバージョン毎に保持しています。コンテンツのデータはbase64でエンコードされ、VersionData項目に保存されています。
  • コンテンツ項目:システムで定義された項目に加えて、カスタム項目をコンテンツオブジェクトに追加することができます。
  • コンテンツタイプ:コンテンツタイプはビジネス文書の種類を定義したものです。トレーニング資料や、ケーススタディ、マーケティング資料、などです。コンテンツタイプを使って、ページレイアウトでコンテンツ項目をグループ化することができます。さらに、コンテンツタイプ毎に、関連するレコードタイプが作られます。
  • 特定のコンテンツタイプのためのページレイアウト:ユーザーがコンテンツタイプを選択すると、関連づけられたページレイアウトが開き、そのレイアウトで定義された項目が表示されます。ページレイアウトを編集するには、コンテンツタイプに対して "編集" をクリックし、項目をドラッグ&ドロップで希望する箇所に配置していきます。
  • 選択リストのカスタマイズ: コンテンツタイプは、選択リストをカスタマイズするために使うこともできます。 "選択リスト" リンクをクリックすると、コンテンツタイプの一覧が表示されるので、選択リストをカスタマイズしたいコンテンツタイプを選択します。
  • 次のページでは、選択リスト項目の一覧が表示されます。カスタマイズしたい選択リストを選択します
  • ワークスペース:ワークスペースはユーザーがコンテンツを共同管理する場所です。個々のワークスペースはユーザー間で共有することができます。
  • ワークスペース権限:ここでワークスペース権限を追加、編集、削除します。
  • ワークスペース権限の割り当て:ワークスペースをセールスフォース・コンテンツのユーザー、もしくはこれらユーザーを含む公開グループに割り当てることができます。
  • ワークスペースのコンテンツタイプ制限:ワークスペースに配信されるコンテンツタイプに制限をかけることもできます。

  • 組織内の全コンテンツユーザーに公開グループを定義する:ワークスペースの割り当て作業を簡単にするために、公開グループを利用します。例:組織内の全ユーザーに、"Pictures" ワークスペースの編集と公開権限を割り当てたい場合、カスタマーポータルを有効化し、 "すべての組織内ユーザー" 公開グループを有効にします。次に、"すべての組織内ユーザー" 公開グループを利用して、"すべての組織内コンテンツユーザー" を定義します。ここで定義した "すべての組織内コンテンツユーザー" カスタムグループを使って、ワークスペースに権限を割り当てることができます。

  • コンテンツの一括アップロード:コンテンツを一括アップロードするには、次の手順を行います:
1. 次のような書式で、CSVファイルを作成します:
CSVとコンテンツ項目のマッピング
列名 = 項目名 [説明]:


File Name = PathOnClient
[Power Point文書、Word文書、jpg画像といったファイルタイプが、ここで記載したファイル名の拡張子に基づいて決まります。]

Document Location = VersionData
[アップロードするファイルのパスです。ここで記載されたファイルの中身が VersionData システム項目にロードされます。]

Workspace Id = FirstPublishLocationId
[コンテンツが最初にアップロードされるワークスペースです。ワークスペースの権限設定によって、コンテンツはアップロード後に他のワークスペースとも共有されます。]

2. データローダを使い、上記のCSVファイルからコンテンツをアップロードします。
- オブジェクト名:Content(ContentVersion)
- "Show all salesforce objects" をクリックして ContentVersion オブジェクトを表示する
- 最新バージョンのデータローダを利用する - 以前のバージョンは Content オブジェクトをサポートしていません。

3. 項目と列を自動的に一致させた後、上記のマッピングより FILE NAME, DOCUMENT LOCATION, WORKSPACE Id を対応付けます。今後のアップロードの為にこの対応付けを保存してください。
ヒントとトリック、そして "落とし穴"

1. コンテンツの画像をポータルに表示する:画像データは base64エンコードされた文字列で保存されています。

コントローラのソースコード:
public transient String imageData {get; set;}

public void loadImageData() {
List<contentversion> content = [select id, versiondata, pathonclient 
      from ContentVersion where Id=:contentid];

imageData = EncodingUtil.base64Encode(content[0].versiondata);
}

Visualforceページのソースコード:
 <apex:outputpanel id="imgPanel">
   <div id="imgContainer" style="margin: 0px; padding-top: 13px;">
  <center>
   <img src="data:image/jpg;base64,{!imageData}" style="height: 265px; width: 340px;" />
  </center>
  </div>
 </apex:outputpanel> 

注釈:このテクニックはFirefoxなどのIE以外のブラウザで動作します。

2. コンテンツタイプ(コンテンツレイアウトなど)を変更セットやANT移行ツールでデプロイしないでください。これは、コンテンツタイプを壊して、修復不可能にしてしまいます。そうなった場合、salesforce.comに連絡し、dbscriptを流してもらうしかありません。

3. 購読しているコンテンツやワークスペース、著者やタグはAPIから取得できません。

4. 購読機能は "フォロー"機能に置き換えられる予定です。

5. 現在のところ、コンテンツ、著者、タグのみがフォローできます。ワークスペースはフォローできませんが、今後のリリースではできるようになるでしょう。

6. 著者のフォローは、ユーザーのフォローをすることで可能です。

7. コンテンツフィルタの適用順を制御することも、特定のフィルタを表示/非表示にすることもできません。

8. オブジェクトに添付された関連するコンテンツはSOQLやAPIで検索できません。

9. ワークスペースや、ワークスペース権限をSandbox組織から本番環境、または他のSandbox組織にデプロイすることはサポートされていません。

10. コンテンツフィルタはコンテンツタイプをフィルタ条件に含めることができません [参照記事]。以下のような回避策があります:
a. コンテンツオブジェクトにカスタム項目 "Content Type" を データ型:テキスト(255) で追加する。
b. "Content Type" カスタム項目の値を RecordType.Name から設定するようなバッチApexクラスを書く。
バッチApexクラスのソースコード:


global class ContentBatch implements Schedulable, Database.Batchable <sobject> {
    
    global List<contentversion> failedContent = new List<contentversion>();
    
    global void execute(SchedulableContext SC) {
     ContentBatch contentBatch = new ContentBatch();
     ID batchprocessid = Database.executeBatch(contentBatch);
 }
    
    global Database.QueryLocator start(Database.BatchableContext BC) {
     return Database.getQueryLocator([SELECT id, recordtype.name
                                      FROM ContentVersion
                                      WHERE isLatest = true
                                      AND recordtype.name != ''
                                      AND content_type__c = '']);
 }
    
    global void execute(Database.BatchableContext BC, List<sobject> batch) {

     List<contentversion> contentList = (List<contentversion>)batch;
   
 Set<id> recordConnectionIds = new Set<id>();
     for (ContentVersion contentRecord : contentList) {
         contentRecord.content_type__c = contentRecord.recordtype.name;         
     }
    
 Database.SaveResult[] dbResults = Database.update(contentList,false);

 // send failed updates via email to job submitter.
     String emailSubject = 'Content Batch Errors';
     String emailBody = '';
     Boolean sendEmail = false;
     
     for (Database.SaveResult dbResult : dbResults){
         if (!dbResult.isSuccess()) {
             Database.Error err = dbResult.getErrors()[0];
             emailBody += '\n' + 'id=' + dbResult.getId() + ' Error: ' + err.getMessage();
             sendEmail = true;
         }
     }
     
     if (sendEmail) {
      
      AsyncApexJob apexJob = [Select Id, Status, NumberOfErrors, JobItemsProcessed,
                            TotalJobItems, CreatedBy.Email
                           from AsyncApexJob where Id =:BC.getJobId()];
      // send an email out with results.
         Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
         String[] toAddresses = new String[] {apexJob.CreatedBy.Email};
         mail.setToAddresses(toAddresses);
         mail.setSubject(emailSubject);
         mail.setPlainTextBody(emailBody);
         Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
      
     }
 }
    
 global void finish(Database.BatchableContext BC) {
 }
    
 @isTest
 public static void testBatch() {
    ContentBatch cbatch = new ContentBatch();
     Database.executeBatch(cbatch);
       
  // Schedule the batch for hourly run
 String sch = '0 0 * * * ?';
     system.schedule('Content Hourly batch',sch,cbatch);
     
 }
}

c. 上記バッチApexクラスを毎時、もしくは適切な期間で起動するようにスケジュールする。
バッチのスケジュールを行うには、下記のコマンドを "execute anonymous" ブロックで実行してください。
ContentBatch cbatch = new ContentBatch();
String sch = '0 0 * * * ?';
system.schedule('Content Hourly batch',sch,cbatch);

バッチをオンデマンドで動かすには、下記のコマンドを"execute anonymous" ブロックで実行してください。
ContentBatch cbatch = new ContentBatch();
Database.executeBatch(cbatch);

スケジュール済みジョブを確認するには
設定 > 管理者設定 > 監視 > スケジュール済みジョブ

Apexバッチジョブを監視するには
設定 > 管理者設定 > 監視 > Apex ジョブ

11. セールスフォース・コンテンツは(既存の)ファイルに近づいていく方向性のようです。現在のコンテンツタブはファイルタブに置き換えられ、コンテンツワークスペースはコンテンツライブラリに改名されるようです。ファイルタブではコンテンツライブラリのファイルだけではなく、Chatterフィードに投稿されたファイルも表示されるようになります。

Posted by Nitin Jain (Appirio US)
[原文へ(英語)]

0 コメント:

コメントを投稿

 
2006-2011 Appirio Inc. All rights reserved.
アピリオ | リソースセンター(英語) | お問い合わせ先 | 採用情報 | プライバシーポリシー(英語)