Skip to content
This repository was archived by the owner on Mar 4, 2025. It is now read-only.

Commit cfcc846

Browse files
committed
initial commit
0 parents  commit cfcc846

File tree

54 files changed

+2673
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2673
-0
lines changed

AutoReportRunner Instructions.doc

27.5 KB
Binary file not shown.

AutoReportRunner2.swf

13.3 MB
Binary file not shown.

README

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Challenge Requirements
2+
3+
Report Selection - User should be able to open the “Schedule Excel Report” page and select from a list of available Reports
4+
5+
Recipient(s) - User should be able to define a list of Users and optional email addresses, comma separated.
6+
7+
Schedule Frequency
8+
9+
Day of the Week - Ability to choose specific days of the week to send report
10+
11+
Start Date / End Date - Required to choose a range of dates that the scheduled job will be eligible for.
12+
13+
Time of Day - User should be able to select a time of day that the job should execute.
14+
15+
Email Template - to facilitate ease of customization, a default Email Template should be created as part of this project. The contents should be similar to the out-of-the-box SFDC scheduled report email format. The existence of this Template should be required upon save of the Schedule Excel Report record.
16+
17+
The recipient of the email does not have to be a SFDC user.
18+
19+
List View - User should have a list-view interface for viewing existing
20+
21+
Scheduled Excel Report records. Include a status/message field for tracking an execution error messages.
22+
23+
Include capabilities to start/stop future Scheduled Excel Report jobs.
24+
25+
Upon execution, the apex code should execute the report, create a new Email message and attach the report output to the email as an Excel attachment.

ScheduleReportPackage/.project

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>ScheduleReportPackage</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>com.salesforce.ide.builder.default</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
</buildSpec>
14+
<natures>
15+
<nature>com.salesforce.ide.nature.default</nature>
16+
</natures>
17+
</projectDescription>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#Tue Nov 22 17:31:35 GMT 2011
2+
eclipse.preferences.version=1
3+
endpointApiVersion=23.0
4+
endpointEnvironment=Production/Developer Edition
5+
endpointServer=www.salesforce.com
6+
httpsProtocol=true
7+
ideVersion=23.0
8+
keependpoint=false
9+
metadataFormatVersion=23.0
10+
namespacePrefix=
11+
packageName=Scheduled Report Exports
12+
readTimeout=400
13+
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
place holder
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<CustomApplication xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<defaultLandingTab>Scheduled_Report_Export__c</defaultLandingTab>
4+
<label>Auto Report Runner</label>
5+
<tab>standard-report</tab>
6+
<tab>Scheduled_Report_Export__c</tab>
7+
</CustomApplication>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
public with sharing class ExportReport {
2+
3+
/*
4+
5+
Credits:
6+
Progmatic Access to Salesforce.com Reports
7+
http://sfdc-heretic.warped-minds.com/2006/04/10/progmatic-access-to-salesforcecom-reports/
8+
9+
HTTP Callout to Salesforce
10+
http://boards.developerforce.com/t5/Best-Practices-Discussion/Http-Callout-to-Salesforce/td-p/179143
11+
12+
13+
*/
14+
public class customException extends Exception{}
15+
16+
String sfDomain = Properties.getSalesforceDomain;
17+
String un = Properties.getUsername;
18+
String pw = Properties.getPassword;
19+
20+
//used to direct the flow and set values when unit testing
21+
public enum TestPath {REDIRECT, REDIRECT_ERROR, OK_CSV, OK_NONCSV, ERROR}
22+
23+
private HTTPRequest buildWebService(String endPoint, String sid) {
24+
HttpRequest req = new HttpRequest();
25+
req.setEndpoint(endPoint);
26+
req.setMethod('GET');
27+
//if session id is provided add to the cookie so the webservice is authenticated
28+
if (sid!=null) req.setHeader('Cookie','sid='+sid);
29+
return req;
30+
}
31+
private HTTPResponse invokeWebService(HttpRequest req, String encoding, TestPath path) {
32+
Http http = new Http();
33+
HTTPResponse res = new HTTPResponse();
34+
if ( !Test.isRunningTest() ) {
35+
res = http.send(req);
36+
} else {
37+
//TEST EXECUTION PATH
38+
if (path == null) path = TestPath.OK_CSV;
39+
40+
if (path == TestPath.Redirect) {
41+
res.setStatus('Found');
42+
res.setStatusCode(302);
43+
res.setHeader('Location', 'https://na12.salesforce.com/secur/frontdoor.jsp?sid=123456789&apv=1');
44+
} else if (path == TestPath.REDIRECT_ERROR) {
45+
res.setStatus('Found');
46+
res.setStatusCode(302);
47+
//do not provide redirect location
48+
} else if (path == TestPath.OK_CSV) {
49+
res.setStatus('OK');
50+
res.setStatusCode(200);
51+
res.setBody('IT WORKS!');
52+
res.setHeader('Content-Type', encoding);
53+
} else if (path == TestPath.OK_NONCSV) {
54+
res.setStatus('OK');
55+
res.setStatusCode(200);
56+
res.setBody('');
57+
res.setHeader('Content-Type', 'text/html; charset=UTF-8');
58+
} else if (path == TestPath.ERROR) {
59+
res.setStatus('ERROR');
60+
res.setStatusCode(404);
61+
}
62+
63+
}
64+
return res;
65+
}
66+
67+
public String handleRedirectRequest(String redirectURI) {
68+
return handleRedirectRequest(redirectURI, TestPath.Redirect);
69+
}
70+
public String handleRedirectRequest(String redirectURI, TestPath path) {
71+
system.debug('Entering...handleRedirectRequest...' + redirectURI);
72+
73+
try {
74+
HttpRequest req = buildWebService(redirectURI, null);
75+
HTTPResponse res = invokeWebService(req, '', path);
76+
77+
if (res.getStatusCode() == 302) {
78+
//after first login salesforce retruns a redirect we need ot handle this
79+
redirectURI = res.getHeader('Location');
80+
81+
if (redirectURI != null) {
82+
System.debug('handleRedirectRequest...redirectURI ...' + redirectURI );
83+
String sid = redirectURI.substring(redirectURI.indexOf('sid=')+4, redirectURI.indexOf('&', redirectURI.indexOf('sid=')));
84+
System.debug('handleRedirectRequest...sid...' + sid);
85+
sid = EncodingUtil.urlDecode(sid, 'UTF-8');
86+
System.debug('handleRedirectRequest...sidDecoded...' + sid);
87+
return sid;
88+
} else {
89+
throw new customException('Redirect during login with no redirect location');
90+
}
91+
} else {
92+
throw new customException('Unhandled response from web service, Web Service Response: ' + res);
93+
}
94+
} catch (System.CalloutException callOutEx) {
95+
throw new customException('Unable to login via web service. Error: ' + callOutEx.getMessage());
96+
} catch (Exception ex) {
97+
throw new customException('Unkown Error: ' + ex.getMessage());
98+
}
99+
}
100+
101+
private String getSessionId() {
102+
//as these methods are called from scheduled classes and futures UserInfo.session is not available
103+
//as a workaround I do a login call using httprequest adns crape the session id
104+
105+
if (sfDomain == null) {
106+
throw new customException('Salesoforce domain URL not defined in custom setting');
107+
}
108+
if (un == null || pw == null) {
109+
throw new customException('Login credentials not defined in custom setting');
110+
}
111+
//login to salesforce using web callout to scrape for the session id
112+
String authURL = sfDomain + '?un=' + un + '&pw=' + pw;
113+
String sid = handleRedirectRequest(authURL);
114+
115+
return sid;
116+
}
117+
118+
public blob getReportAsCSV(Id reportId, TestPath path) {
119+
String sid = getSessionId();
120+
121+
//url format to return an exported report in csv format
122+
String uri = sfDomain + reportId + '?export=1&enc=UTF-8&xf=csv';
123+
return Blob.valueOf(getReport(uri, 'text/csv; charset=UTF-8', sid, path));
124+
}
125+
public String getReportAsHTML(Id reportId, TestPath path) {
126+
String sid = getSessionId();
127+
128+
//url format to return report without headers
129+
String uri = sfDomain + reportId + '?isdtp=nv';
130+
String body = getReport(uri, 'text/html; charset=UTF-8', sid, path);
131+
if (body.indexOf('<div class="bGeneratedReport') > 0) {
132+
//return just the body of the report output
133+
body = body.substring(body.indexOf('<div class="bGeneratedReport'), body.indexOf('</form>'));
134+
} else {
135+
//having trouble with more obscure reports e.g. Lead Status
136+
body = '';
137+
}
138+
system.debug('runReport...body...' + body);
139+
return body;
140+
}
141+
private String getReport(String uri, String encoding, String sid, TestPath path) {
142+
try {
143+
system.debug('runReport...sid...' + sid);
144+
system.debug('runReport...uri...' + uri);
145+
146+
HttpRequest req = buildWebService(uri, sid);
147+
HTTPResponse res = invokeWebService(req, encoding, path);
148+
149+
if (res.getStatusCode() == 200) {
150+
String body = res.getBody();
151+
system.debug('runReport...body...' + body);
152+
153+
//check that the encoding is correct - during testing a response of text/html when csv is expected means the authentication failed somewhere
154+
if (res.getHeader('Content-Type').equals(encoding)) {
155+
return body;
156+
} else {
157+
throw new customException('Unexpected content type returned: ' + res.getHeader('Content-Type'));
158+
}
159+
} else {
160+
system.debug('runReport...res...' + res);
161+
throw new customException('Unhandled response from web service, Web Service Response: ' + res);
162+
}
163+
} catch (Exception ex) {
164+
throw new customException('Unkown Error: ' + ex.getMessage());
165+
}
166+
}
167+
168+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>23.0</apiVersion>
4+
<status>Active</status>
5+
</ApexClass>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
public with sharing class Properties {
2+
3+
private static String getStringValue(String key) {
4+
String retVal;
5+
6+
try {
7+
Properties__c prop = Properties__c.getValues(key);
8+
retVal = prop.Value__c;
9+
} catch (Exception ex) {
10+
System.debug('Properties...getValueString...' + key + '...ex...' + ex);
11+
}
12+
13+
return retVal;
14+
}
15+
private static Boolean getBooleanValue(String key) {
16+
Boolean retVal;
17+
18+
try {
19+
if (getStringValue(key).equals('true')) {
20+
retVal = true;
21+
} else if (getStringValue(key).equals('false')) {
22+
retVal = false;
23+
}
24+
} catch (Exception ex) {
25+
System.debug('Properties...getValueBoolean...' + key + '...ex...' + ex);
26+
}
27+
28+
return retVal;
29+
}
30+
31+
public static Boolean isComplianceEnabled { get { return getBooleanValue('ccComplianceEnabled'); } }
32+
public static String getComplianceEmail { get { return getStringValue('ComplianceEmail'); } }
33+
public static String getSalesforceDomain { get { return getStringValue('SalesforceDomain'); } }
34+
public static String getPassword { get { return getStringValue('Password'); } }
35+
public static String getUsername { get { return getStringValue('Username'); } }
36+
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>23.0</apiVersion>
4+
<status>Active</status>
5+
</ApexClass>

0 commit comments

Comments
 (0)