Wednesday, August 7, 2013

How to give a name while export a file in csv/xls

Hi friends, recently I came across a situation where client want's to give a name while exporting a file in csv/xls. In salesforce we can not code in such a way that it will ask you any name before save the file at your local drive. Alternate solution is we can pass different names from the different pages, so we can distinguish in between two exported files from different pages. Here is the detail how you can do this.

We need to create below resources for it-

#1-BlogCSV.page
#2-BlogCSV.component
#3-BlogCSVController.cls
#4-ExportTestPage.page


let me take this one by one & tell you how we can pass name while export in this.

#1-BlogCSV.page 
This is a VF page which generate a xls file for given table.
here the important thing is we will pass contenttype attribute something like below





contentType="application/vnd.ms-excel#{!SUBSTITUTE($CurrentPage.parameters.page,'XXXXXX__','')}_YOUR_POSTFIX_HERE.xls"

in this the exported file name will be build by Page Name from where it is exported + your postfix whatever you give in above content type attribute.

here is the complete code for this-
<apex:page language="en-US" cache="false" readonly="true" sidebar="false" showHeader="false" pageStyle="false" contentType="application/vnd.ms-excel#{!SUBSTITUTE($CurrentPage.parameters.page,'PackagePrefix__','')}_YOUR_POSTFIX_HERE.xls">
  <c:BlogCSV id="csvComponent1" />
</apex:page>


#2-BlogCSV.component 
this component is simply rendering the account table which will be going to export.
<apex:component controller="BlogCSVController" id="component1">
 <apex:pageBlock >
        <apex:pageBlockTable value="{!lstOfAccount}" var="lst" width="100%" rendered="{!IF(lstOfAccount.Size>0,true,false)}">
         <apex:column >
                  <apex:facet name="header" >
                    Name
                  </apex:facet>
                  <apex:outputLink value="{!lst.id}" >{!lst.Name}</apex:outputLink>  
              </apex:column>
              <apex:column >
                  <apex:facet name="header" > 
                     AccountSource
                  </apex:facet>
                  <apex:outputLabel value="{!lst.AccountSource}" />  
              </apex:column>
        </apex:pageBlockTable>
    </apex:pageBlock>    
</apex:component>

#3-BlogCSVController.cls
this class is common controller class for both component & page. here is the code for this -
public with sharing class BlogCSVController {
 public string currentPage {get;set;} 
 public String redirectURL {get;set;}
  public PageReference Export(){
     
     
     PageReference pr = Page.BlogCSV;
     pr.getParameters().put('page',currentPage);
     redirectURL = pr.getUrl(); 
     return null; 
    }
    
 public List lstOfAccount{get;set;}
 public BlogCSVController(){
  lstOfAccount = [Select Id,Name, AccountSource from Account LIMIT 10];
 }
}

#4-ExportTestPage.page
finally this is the page where will provide export button which will initiate export.Here is the code-
<apex:page controller="BlogCSVController">
 <apex:form id="form1">
  <apex:pageMessages id="msg" />
  <apex:sectionHeader Title="Export" subtitle="XLS Sample" /> 
  <apex:pageBlock id="block1">
   <apex:pageBlockButtons location="top">
    <input type="button" class="btn" value="Export" onclick="Export('{!$CurrentPage.Name}');" />
                  <apex:actionStatus id="statusLoadingMain">
                      <apex:facet name="start">
                              <span style="font-weight:bold; color: red;">
                                  Please wait while exporting...<img src="/img/loading.gif" /> 
                              </span> 
                      </apex:facet>
                  </apex:actionStatus>
              </apex:pageBlockButtons>
   
   <script>
     function Export(pagename){
             jsExport(pagename);
          } 
   </script>
    
    <apex:outputPanel id="pnlExport"> 
             <script>
                 if("{!redirectURL}" != ""){
                     window.location.href="{!redirectURL}";
                 }
             </script>
         </apex:outputPanel>
         <apex:actionFunction status="statusLoadingMain" name="jsExport" action="{!Export}" rerender="pnlExport,msg">
                     <apex:param name="currentPage" id="currentPage" value="" assignto="{!currentPage}" />
                   </apex:actionFunction>
   </apex:pageBlock>     
   <c:BlogCSV id="csvComponent1" />    
 </apex:form>          
</apex:page>

here notice that we are passing current page name in action function.
Now when you click on export this will be exported with your page name & given postfix.
You can see a demo here


Wednesday, February 27, 2013

SOQL Injection

Hi friends, 

While writing dynamic SOQL query, I came to know that we should care about the injection script. I tried to get the way how one can write this kind of script so code starts giving unexpected result. I did a lot of rnd on internet but I found the same sample everywhere which is given in salesforce pdf file, but still I was not getting the practical example that satisfy my SOQL injection doubt. 

Because of this reason I created a sample to clear my self what is SOQL injection & how this can give you unexpected result. Here I am sharing it with you so you will get an idea what does SOQL injection means.

You can see demo here. There are four buttons in this page. these are quite simple & self explanatory but let me explain in detail if you have any doubt-
Button -1 Execute
This button shows how simple dynamic query works if we use Equal comparison

Button -2 Execute Like
This button shows how simple dynamic query works if we use LIKE comparison

Button -3 Execute Escape
This button show how dynamic query works if we use String.escapeSingleQuotes method in case of equal comparison

Button -4 Execute Like Escape
This button show how dynamic query works if we use String.escapeSingleQuotes method in case of LIKE comparison

salesforce recommend to use String.escapeSingleQuotes method if you are writing dynamic query.

Now If you open this page & enter the text just after the button "Account1' OR name<>'abc" & click on all four buttons & see the output difference. 

In the first two buttons we are not using escapeSingleQuotes while in the last two buttons we are using escapeSingleQuotes method. 

here when we give injection script (Account1' OR name<>'abc) first two button show all account in the system, that should not be. while in the last two buttons because we are using escapeSingleQuotes method that does not allow to execute this injection script.

here is the code of page & class-
SOQL.page

<apex:page controller="SOQLController" tabStyle="Account">
 <apex:form id="form1">
  <apex:pageBlock id="block1">
    <apex:inputText value="{!name}" />
    <apex:commandButton value="Execute" action="{!Execute}" rerender="pnl" />
    <apex:commandButton value="Execute Like" action="{!ExecuteLike}" rerender="pnl" />  
    <apex:commandButton value="Execute Escape" action="{!ExecuteEscape}" rerender="pnl" />
    <apex:commandButton value="Execute Like Escape" action="{!ExecuteLikeEscape}" rerender="pnl" /> <apex:outputLabel value="Account1' OR name<>'abc"></apex:outputLabel>
    <apex:outputPanel id="pnl">
    <apex:pageBlockTable value="{!lstAccount}" var="lst" id="tbl">
     <apex:column value="{!lst.Name}" /> 
    </apex:pageBlockTable>
    <apex:pageBlockSection title="Query" columns="1">
     <apex:outputLabel value="{!query}"  id="qry"/>
    </apex:pageBlockSection> 
   </apex:outputPanel> 
  </apex:pageBlock>
 </apex:form>
</apex:page>

& class code.. SOQLController.cls
public with sharing class SOQLController {
 public List<Account> lstAccount{get;set;}
 public string query {get;set;}
 public String name {get;set;}
 public void Execute(){
  String StrName =   '=\'' + name + '\''; 
  query = 'Select Id, Name from Account where name '  + StrName ;
  lstAccount = Database.Query(query);
  //input -- Account1' OR name<>'xxx
 }
 public void ExecuteLike(){
  String StrName =  'LIKE \'%' + name + '%\''; 
  query = 'Select Id, Name from Account where name '+ StrName;
  lstAccount = Database.Query(query);
 }
 public void ExecuteEscape(){
  String StrName =   '=\'' + String.escapeSingleQuotes(name) + '\''; 
  query = 'Select Id, Name from Account where name  '  + StrName;
  lstAccount = Database.Query(query);
 }
 public void ExecuteLikeEscape(){
  String StrName =  'LIKE \'%' + String.escapeSingleQuotes(name) + '%\''; 
  query = 'Select Id, Name from Account where name '  + StrName ;
  lstAccount = Database.Query(query);
 }
}
 

Thursday, February 21, 2013

Show Star Rating as Salesforce Standard Field


Hi friends, this time I am coming with a solution for star rating. if you want to show star rating in a standard salesforce layout in form of column.
Take a look of below image. in this I am showing some rating as like this is a stanadrd field in salesforce.


In above image notice that you rating field is appear same as standard field on UI. here is how you can do this-
Step-1
Create a new page named "StarRating" & a new controller class "StarRatingController" in salesforce.

Step-2
Get a jquery star plugin files from net & upload these files in salesforce static resource. I will also tell you the path one of my page latter from where you can download these files.

Step-3
I assuming that you uploaded two static resource -
a-OrgResource
b-jQueryStarRatingPlugIn

in first zip file we are having all jquery js & css files. although we are going to use few of them.
second one zip file is having all files which we downloaded from jquery plugin site.

Step-4
Copy & paste below code in VF page
<apex:page id="page1" sidebar="false" showHeader="false" standardController="Account" extensions="StarRatingController">
    <apex:styleSheet value="{!URLFOR($Resource.OrgResource,'development-bundle/themes/base/jquery.ui.all.css')}" />
    <apex:styleSheet value="{!URLFOR($Resource.jQueryStarRatingPlugIn,'jquery.ui.stars.css')}" />
    <apex:includeScript value="{!URLFOR($Resource.OrgResource,'js/jquery-1.5.1.js')}" />
    <apex:includeScript value="{!URLFOR($Resource.OrgResource,'development-bundle/ui/jquery.ui.core.js')}" />
    <apex:includeScript value="{!URLFOR($Resource.OrgResource,'development-bundle/ui/jquery.ui.widget.js')}" />
    <apex:includeScript value="{!URLFOR($Resource.jQueryStarRatingPlugIn,'jquery.ui.stars.min.js')}" />
    <style>
        .detailList{
            width:94%;
        }
        .pbBody, .pbBody a, .pbBody td, .lbBody a, .lbBodyDescription, .list .headerRow .noRowsHeader {
         border-bottom: 0 none !important;
        }
    </style>
    <apex:form id="form1">
        <apex:pageBlock > 
        <div id="ep" class="bDetailBlock bPageBlock secondaryPalette">
            <div class="pbSubsection">
                <table cellspacing="0" cellpadding="0" border="0" class="detailList" style="border-bottom:none !important;" >
                    <tbody>
                        <tr>
                            <td class="labelCol">Rating</td>
                            <td class="dataCol col02">
                                <apex:outputPanel >
                                    <div class="divRating">
                                        <apex:selectList value="{!rating}" size="1">
                                            <apex:selectOptions value="{!listOfRatingOptions}" />
                                        </apex:selectList>
                                    </div>  
                                </apex:outputPanel> 
                            </td>
                            <td class="labelCol">&nbsp;</td>
                            <td class="dataCol col02">&nbsp;</td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>  
            
          <script>
             jQuery(document).ready(function(){
                     jQuery(".divRating").stars({
                        inputType: "select",
                        cancelShow: false,
                        disabled:true
                     });
                     $(".accountBlock").children().attr('class','');
                     $(".detailList").css('width','94%');
                 });
                     
          </script>
        </apex:pageBlock>
    </apex:form>
</apex:page>
Step-5 Copy & paste below class code in controller which you create few steps back
public with sharing class StarRatingController {
 public integer rating {get;set;}
 public List<SelectOption> listOfRatingOptions {get;set;}
 public StarRatingController(ApexPages.StandardController controller){
  listOfRatingOptions = new List<SelectOption>();
  rating = 3;
  string val = '';
  for(integer i=1;i<=5;i++){
   val = string.valueOf(i);
   listOfRatingOptions.add(new SelectOption(val,val));
  }
 }
}
now you can include this page in account stadarad layout. To add this follow next steps.

Step-6
Click on account tab, this will show you list of account. Open one account & click on Edit Layout link at top left.
Step-7
Add a new section from the layout. Give any name to this section.Uncheck Display Section Header On two check box (Detail page & Edit page). In Layout option select 1-Column option & click on save.

Step-8
Add starRating VF page to this section & set height 20 & width 100%.

Save layout & see that rating is available same as a standard field on account detail.

here is the link of star rating page if you want to see how this looks like.You can also download the static resource files by view source.

The same thing you can also do on any VF page. here is demo page. the code of this demo page is as below-
<apex:page standardController="Account" extensions="SiteStarRatingController" id="page1">
  <apex:sectionHeader title="Site"  subTitle="Star Rating Sample" /> 
  <apex:pageBlock id="block1"> 
   <apex:pageBlockSection columns="1">
    <apex:pageBlockSectionItem >
     <apex:outputLabel value="Account Name" />
     <apex:outputField value="{!act.Name}" />
    </apex:pageBlockSectionItem> 
   </apex:pageBlockSection> 
   <apex:pageBlockSection columns="1">
    <apex:iframe src="/apex/StarRating" height="20px" />
   </apex:pageBlockSection>
   <apex:pageBlockSection columns="1">
    <apex:pageBlockSectionItem >
     <apex:outputLabel value="Type" />
     <apex:outputField value="{!act.Type}" />
    </apex:pageBlockSectionItem> 
    <apex:pageBlockSectionItem >
     <apex:outputLabel value="Description" />
     <apex:outputField value="{!act.Description}" />
    </apex:pageBlockSectionItem>
    <apex:pageBlockSectionItem >
     <apex:outputLabel value="Fax" />
     <apex:outputField value="{!act.Fax}" />
    </apex:pageBlockSectionItem>
   </apex:pageBlockSection> 
  </apex:pageBlock>
</apex:page>
controller class is as below-
public with sharing class SiteStarRatingController {
 public Account act{get;set;}
 public SiteStarRatingController(ApexPages.StandardController controller){
  act = [Select Id,Name,Type, Industry, Fax, Description from Account limit 1];
  
 }
}
Done..!! :)