Upload image in Document object in Salesforce - salesforce

I need help in following code. I need to put my images in document object of Salesforce. Currently I am putting in notes and attachment which is fine, with this I need to put in Document object.
I need to do this because image not displaying in Word file but they displayed in PDF.
#RestResource(urlMapping='/SyncAttachments/*')
global with sharing class AssessmentApp_SyncAttachmentsWebService {
global class Image {
public String primaryKey;
public String base64;
public String parentId;
}
#HttpPost
global static Map<String, String> syncAttachments(Image image) {
System.debug(LoggingLevel.Info, 'image ' + image);
List<Attachment> attachments = [SELECT Id, Name, Body FROM Attachment WHERE Id =:image.primaryKey];
System.Debug('attachments ' + attachments);
//check if attachment is already present. If not, create a new one.
Attachment myAttachment;
if (attachments.size() == 0) {
//Check the parentId of the attachment. Check if parentId belongs to notes
myAttachment = new Attachment();
myAttachment.Body = EncodingUtil.base64Decode(image.base64);
myAttachment.ContentType = 'image/jpg';
myAttachment.Name = image.parentId;
myAttachment.ParentId = image.parentId;
insert myAttachment;
}
else {
myAttachment = attachments[0];
}
Map<String, String> responseMap = new Map<String, String>();
responseMap.put('Success', '1');
responseMap.put('Message', 'Sync Attachment ' + myAttachment.Name + ' Successfully');
return responseMap;
}
}

I kept the #RestResource urlMapping parameter the same, with the wildcard, so the URI would stay the same. The method name also stayed the same. It would be ideal if you updated both of these, as well as your calls upstream, to say "Document" instead of "Attachment."
There is no field ParentId on Document like on Attachment, so parenting logic was not included. You also need to assign each Document into a Folder, you can change FolderId to assign them correctly. This will throw an exception if there aren't any Folders in your org.
#RestResource(urlMapping='/SyncAttachments/*')
global with sharing class AssessmentApp_SyncAttachmentsWebService {
global class Image {
public String primaryKey;
public String base64;
public String parentId;
}
#HttpPost
global static Map<String, String> syncAttachments(Image image) {
List<Document> documents = [SELECT Id, Name, Body FROM Document WHERE Id =:image.primaryKey];
Folder dummyFolder = [SELECT Id FROM Folder LIMIT 1];
Document myDocument;
if (documents.size() == 0) {
myDocument = new Document();
myDocument.FolderId = dummyFolder.id;
myDocument.Body = EncodingUtil.base64Decode(image.base64);
myDocument.ContentType = 'image/jpg';
myDocument.Name = image.parentId;
insert myDocument;
}
else {
myDocument = documents[0];
}
Map<String, String> responseMap = new Map<String, String>();
responseMap.put('Success', '1');
responseMap.put('Message', 'Sync Document ' + myDocument.Name + ' Successfully');
return responseMap;
}
}

Related

Could someone help me build a test apex for an opportunity closed/won trigger?

I'm not a developer and we don't have one currently on our staff. So I looked all over the web and modified this Apex Class to suit my needs so that when an opportunity is marked as closed/won I get a small message in Slack.
It works great and I'd like to send this to Production. However, I didn't realize that I need to include a test for this and I am stuck on what that means.
Here's my Apex Class:
public with sharing class SlackPublisher {
private static final String SLACK_URL = 'https://hooks.slack.com/services/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';
public class Oppty {
#InvocableVariable(label='Opportunity Name')
public String opptyName;
#InvocableVariable(label='Opportunity Owner')
public String opptyOwnerName;
#InvocableVariable(label='Account Name')
public String acctName;
#InvocableVariable(label='Amount')
public String amount;
}
public class UrlMethods {
String BaseUrl; // The Url w/o the page (ex: 'https://na9.salesforce.com/')
String PageUrl; // The Url of the page (ex: '/apex/SomePageName')
String FullUrl; // The full Url of the current page w/query string parameters
// (ex: 'https://na9.salesforce.com/apex/SomePageName?x=1&y=2&z=3')
String Environment; // Writing code that can detect if it is executing in production or a sandbox
// can be extremely useful especially if working with sensitive data.
public UrlMethods() { // Constructor
BaseUrl = URL.getSalesforceBaseUrl().toExternalForm(); // (Example: 'https://na9.salesforce.com/')
}
}
#InvocableMethod(label='Post to Slack')
public static void postToSlack ( List<Oppty> opps ) {
Oppty o = opps[0]; // bulkify the code later
Map<String,Object> msg = new Map<String,Object>();
msg.put('text','Deal ' + o.opptyName + ' was just Closed/Won' + ':champagne:' + '\n' + 'for a total of ' + '$' + o.amount);
msg.put('mrkdwn', true);
String body = JSON.serialize(msg);
System.enqueueJob(new QueueableSlackPost(SLACK_URL, 'POST', body));
}
public class QueueableSlackPost implements System.Queueable, Database.AllowsCallouts {
private final String url;
private final String method;
private final String body;
public QueueableSlackPost(String url, String method, String body) {
this.url = url;
this.method = method;
this.body = body;
}
public void execute(System.QueueableContext ctx) {
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod(method);
req.setBody(body);
Http http = new Http();
HttpResponse res = http.send(req);
}
}
}
and what I found online as a base for a test was this:
#isTest
private class SlackOpportunityPublisherTest {
private class RestMock implements HttpCalloutMock {
public HTTPResponse respond(HTTPRequest req) {
String fullJson = 'your Json Response';
HTTPResponse res = new HTTPResponse();
res.setHeader('Content-Type', 'text/json');
res.setBody(fullJson);
res.setStatusCode(200);
return res;
}
}
static testMethod void service_call() {
Test.setMock(HttpCalloutMock.class, new RestMock());
Test.startTest();
//your webserive call code
Database.GetUpdatedResult r =
Database.getUpdated(
'amount',
Datetime.now().addHours(-1),
Datetime.now());
Test.StopTest();
}
}
When I try to validate this in production it says it only gives me 68% coverage and I need 75%. Can someone help me write the test so that I can put into Prod?

FLS Create for Saleforce Object

Is there a way to apply FLS Create check - Schema.sObjectType.Account.fields.Name.isCreateable() to the following?
public static Account createAccount() {
return new Account(
Name = 'Test',
OwnerId = UserInfo.getUserId()
);
}
Wondering if there is a way to apply without re-writing to the following:
public static Account createAccount() {
Account a = new Account();
if (Schema.sObjectType.Account.fields.Name.isCreateable()) {
a.Name = 'Test';
}
if (Schema.sObjectType.Account.fields.OwnerId.isCreateable()) {
a.OwnerId = UserInfo.getUserId();
}
insert a;
}
You can create a generic method that can iterate on each field to check for the FLS.
if access available then retain
if access not available then remove the particular field from the object instance.
I Have created a Generic Method to truncate the non-writable fields as follow:
public static List<SObject> truncateNotWriteableFields(List<SObject> listSObject){
Set<String> readOnlyFields = new Set<String>();
List<SObject> listSObjectNew = new List<SObject>();
if(listSObject.size() < 1){
return listSObjectNew;
}
Schema.SObjectType sObjType = listSObject.getSObjectType();
for(SObjectField field : sObjType.getDescribe().fields.getMap().values()){
if(field.getDescribe().isAccessible() && !field.getDescribe().isUpdateable() && !field.getDescribe().isCreateable()){
readOnlyFields.add(String.valueOf(field));
}
}
readOnlyFields.remove('Id'); // avoid removal in update
for(SObject obj : listSObject){
Map<String, Object> objMap = (Map<String, Object>) JSON.deserializeUntyped( JSON.serialize( obj ) );
objMap.keySet().removeAll(readOnlyFields);
SObject objWithoutNotWritableFields = (SObject) JSON.deserialize( JSON.serialize( objMap ), SObject.class );
system.debug('objWithoutNotWritableFields=>'+objWithoutNotWritableFields);
listSObjectNew.add(objWithoutNotWritableFields);
}
return listSObjectNew;
}

Salesforce: Get record ID from a DataSourceConnection class

I have a Custom DataSourceConnection class (that extends DataSource.Connection) to retrieve related records for contacts from my server API. I need the record ID for the current contact to make my query, but haven't found a way to retrieve it (ApexPages won't work because it's not using Visualforce).
How can I get the record ID from my DataSourceConnection class?
EDIT:
Here are more details on my issue:
The class is being used/called by an External Object that uses a External Data Source, which uses my Custom DataSourceProvider + DataSourceConnection. It's based on this article:
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_connector_start.htm
I need to get the record ID in the "SampleDataSourceConnection" class, inside the "getRows" method that is called by the overrided "query" method. This is how the code looks:
global class SampleDataSourceConnection
extends DataSource.Connection {
global SampleDataSourceConnection(DataSource.ConnectionParams
connectionParams) {
}
// ...
// ...
override global DataSource.TableResult query(
DataSource.QueryContext context) {
if (context.tableSelection.columnsSelected.size() == 1 &&
context.tableSelection.columnsSelected.get(0).aggregation ==
DataSource.QueryAggregation.COUNT) {
List<Map<String,Object>> rows = getRows(context);
List<Map<String,Object>> response =
DataSource.QueryUtils.filter(context, getRows(context));
List<Map<String, Object>> countResponse =
new List<Map<String, Object>>();
Map<String, Object> countRow =
new Map<String, Object>();
countRow.put(
context.tableSelection.columnsSelected.get(0).columnName,
response.size());
countResponse.add(countRow);
return DataSource.TableResult.get(context,
countResponse);
} else {
List<Map<String,Object>> filteredRows =
DataSource.QueryUtils.filter(context, getRows(context));
List<Map<String,Object>> sortedRows =
DataSource.QueryUtils.sort(context, filteredRows);
List<Map<String,Object>> limitedRows =
DataSource.QueryUtils.applyLimitAndOffset(context,
sortedRows);
return DataSource.TableResult.get(context, limitedRows);
}
}
// ...
// ...
// Helper method to get record values from the external system for the Sample table.
private List<Map<String, Object>> getRows () {
// Get row field values for the Sample table from the external system via a callout.
HttpResponse response = makeGetCallout();
// Parse the JSON response and populate the rows.
Map<String, Object> m = (Map<String, Object>)JSON.deserializeUntyped(
response.getBody());
Map<String, Object> error = (Map<String, Object>)m.get('error');
if (error != null) {
throwException(string.valueOf(error.get('message')));
}
List<Map<String,Object>> rows = new List<Map<String,Object>>();
List<Object> jsonRows = (List<Object>)m.get('value');
if (jsonRows == null) {
rows.add(foundRow(m));
} else {
for (Object jsonRow : jsonRows) {
Map<String,Object> row = (Map<String,Object>)jsonRow;
rows.add(foundRow(row));
}
}
return rows;
}
// ...
I understand that the External Object relates to the Contact Object automatically by the ContactId, but I don't have the ContactId on the external system, so I have to grab the contact email (and so the current contact id) to relate it with the external system...

loaderManager recyclerview imageview viewholder content provider fails

I am new at android and new at posting here and trying a sink in slowly but am stuck here at inflating imageViews. Below am providing code snippets from my app that i would thank you for your help
Here is my table
private static final String CREATE_TABLE = "CREATE TABLE "+TABLE_NAME+" ("+KEY_ID,"+KEY_PROFILEPIC+" BLOB,"+KEY_IMAGE+" BLOB)";
this is my viewholder class
`public CityHolder(final View view) {
super(view);
ButterKnife.bind(this, itemView); }
public void bindData(final Cursor cursor) {
String name = cursor.getString(cursor.getColumnIndex("name"));
this.name.setText(name);
String CircularNetWorkImageView =cursor.getString(cursor.getColumnIndex("profilePic"));
this.CircularNetWorkImageView.setText(CircularNetWorkImageView);
}
`
and then i am using recyclerview to bind to cursor.
am also using a a content Provider to both insert and then retrieve data and load by use of the LoaderManager.LoaderCallbacks
here is how i get the data through volley json
JSONArray jsonArray = response.getJSONArray("city");
for (int i=0;i<jsonArray.length();i++)
{
JSONObject jsonObjectCity = jsonArray.getJSONObject(i);
String name = jsonObjectCity.getString("name");
String profilePic = jsonObjectCity.getString("profilePic");
String image = jsonObjectCity.getString("image");
City city = new City();
city.setName(name);
city.setProfilePic(profilePic);
city.setImage(image);
ContentValues values = new ContentValues();
values.put(CityDb.KEY_NAME, name);
values.put(CityDb.KEY_PROFILEPIC, profilePic);
values.put(CityDb.KEY_IMAGE, image);
getContentResolver().insert(CityContentProvider.CONTENT_URI, values);
}
}catch(JSONException e){e.printStackTrace();}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("Volley","Error");
}
}
);
requestQueue.add(jor);
}
#Override
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
String[] allColumns = new String[] {
CityDb.KEY_ID,
CityDb.KEY_NAME,
CityDb.KEY_PROFILEPIC,
CityDb.KEY_IMAGE
};
return new CursorLoader(this,CityContentProvider.CONTENT_URI,allColumns, null, null, null);
}`
Now the String Name is displayed in my fragment but am having issue getting the image and profilePic in circularNetworkimageView to display.
what could i be missing, please guide me

Updating properties for multiple users

How do I update a list of different Telephone, IPPhone using this
static void Main(string[] args)
{
Console.Write("Enter userid : "); // I would pass this in from the first
//Field in the .csv file 2439009
String username = Console.ReadLine();
try
{
DirectoryEntry myLdapConnection = createDirectoryEntry();
DirectorySearcher search = new DirectorySearcher(myLdapConnection);
search.Filter = "(cn=" + uid + ")";
search.PropertiesToLoad.Add("Telephone","IPPhone");
SearchResult result = search.FindOne();
if (result != null)
{
// create new object from search result
DirectoryEntry entryToUpdate = result.GetDirectoryEntry();
// show existing title
Console.WriteLine("Current title : " + entryToUpdate.Properties["Telephone][0].ToString());
Console.Write("\n\nEnter new title : ");
// get new title and write to AD
String newTitle = Console.ReadLine();
entryToUpdate.Properties["Telephone"].Value = newTelePhone;
entryToUpdate.Properties["IPPhone"].Value = newIPPhone;
entryToUpdate.CommitChanges();
Console.WriteLine("\n\n...new title saved");
}
else Console.WriteLine("User not found!");
}
catch (Exception e)
{
Console.WriteLine("Exception caught:\n\n" + e.ToString());
}
}
static DirectoryEntry createDirectoryEntry()
{
// create and return new LDAP connection with desired settings
DirectoryEntry ldapConnection = new DirectoryEntry("mydomain.dm.com");
ldapConnection.Path = "LDAP://OU=myusers,DC=sales,DC=US,DC=US";
ldapConnection.AuthenticationType = AuthenticationTypes.Secure;
return ldapConnection;
}
I'm guessing you've grabbed someone else's code and don't know how to use it?
You should understand that this code can (will?) cause serious server problems as the DirectoryEntry resources are not closed correctly.
Every DirectoryEntry variable in your Main method should be wrapped in a using(){} statement.
Try something like this:
You define a class CSVRecord which holds your data from the CSV - read that in using FileHelpers. The class looks like this:
public class CSVRecord
{
public string EmployeeNumber { get; set; }
public string TelephoneNumber { get; set; }
public string IPPhoneNumber { get; set; }
}
Once you've read that class in, you need to iterate over its elements, and do the update for each of them.
CSVRecord[] listOfEmployees = (read in via FileHelpers)
// define root for searching your user accounts
using (DirectoryEntry root = new DirectoryEntry("LDAP://dc=yourcompany,dc=com"))
{
// set up directory searcher to find users by employeeId
using (DirectorySearcher searcher = new DirectorySearcher(root))
{
searcher.SearchScope = SearchScope.Subtree;
// iterate over all entries in your list of employees
foreach (CSVRecord csvEntry in listOfEmployees)
{
searcher.Filter = string.Format("(&(objectCategory=user)(employeeId={0}))", csvEntry.EmployeeNumber);
// search for that employee
SearchResult result = searcher.FindOne();
// if found - access the DirectoryEntry
if (result != null)
{
DirectoryEntry foundUser = result.GetDirectoryEntry();
// update properties from values in CSV
foundUser.Properties["telephoneNumber"].Value = csvEntry.TelephoneNumber;
foundUser.Properties["ipPhone"].Value = csvEntry.IPPhoneNumber;
// save changes back to directory
foundUser.CommitChanges();
}
}
}
}
Does that work for you??

Resources