• Justin Behnke
  • NEWBIE
  • 5 Points
  • Member since 2018

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 1
    Questions
  • 1
    Replies
Hello All!
Can someone help me understand how I can refactor this code (pasted below) to handle query limits? 
 
I am expecting to use some sort of tool like Batchable or Queueable. I have reviewed the Async Apex trailheads but the examples are difficult for me to map to what I am trying to do here. 
 
This method must return the performance records based on ALL query results before returning. I am hoping that there is a way to query the records and then operate on all of the results from the query at once. 
 
You can see that the limit is set to 10,000 but when refactored it will need to handle hundreds of thousands of records at one time. I have a few other classes that behave like this one for other metrics but if I can fix this one I'll be able to fix the others also.
 
Warm regards,
Justin Behnke
/**
 * Created by justin on 1/7/19.
 */

public with sharing class SkillDataFetcher implements Data_Based.IR_ISkillDataFetcher {
  private static final String CONTACTS_NAME = 'Attempted Contacts';
  private static final String ANSWER_RATE_NAME = 'Answer Rate';
  private static final String DISCOVERY_NAME = 'Discovery';
  private static final String WIN_RATE_NAME = 'Win Rate';
  private static final String AVG_DEAL_SIZE_NAME = 'Average Deal Size';

  /**
   * For all of the areas that performance is measured for a given representative,
   * gather all of the skill performance metrics for all of the users associated
   * with the user ids that are passed in.
   *
   * All skill performances are derived from Tasks, Leads, and Opportunities that
   * have a last modified date between the start and end date times
   *
   * All skill mappings are associated with an id found in the skillMappings parameter.
   *
   * @param startDateTime the date of the last synchronization with DataBased
   * @param endDateTime a date that will be used as the new last synced date with DataBased
   * @param userIds a list of UserIds received from DataBased
   * @param skillMappings a list of Objects containing customer facing names and the internal Id's that DataBased has for
   *                      the skills that DataBased is prepared to analyze
   * @return a list of skill performances that represent how a rep did on a given skill on a given date
   */
  public List<Data_Based.IR_SkillPerformance> getSkillPerformances(
    Datetime startDateTime,
    Datetime endDateTime,
    List<Id> userIds,
    List<Data_Based.IR_SkillMapping> skillMappings) {
    if (skillMappings.isEmpty()) {
      throw new System.InvalidParameterValueException('skillMappings','Empty');
    }
    List<Data_Based.IR_SkillPerformance> skillPerformances = new List<Data_Based.IR_SkillPerformance>();
    /* PROSPECTING PERFORMANCES */
    List<Lead> allLeads = [
      SELECT
        Id,
        OwnerId,
        IsConverted,
        IsDeleted,
        ConvertedDate,
        ConvertedOpportunityId,
        LastModifiedDate
      FROM Lead
      WHERE IsDeleted = FALSE
      ORDER BY ConvertedDate ASC
      LIMIT 10000];
    Map<Id, Lead> leadsByIds = new Map<Id, Lead>();
    for (Lead l : allLeads) {
      leadsByIds.put(l.Id, l);
    }

    Set<Id> ids = leadsByIds.keySet();
    List<Task> callsPlaced = [
      SELECT
        LastModifiedDate,
        OwnerId,
        ActivityDate,
        IsClosed,
        IsDeleted,
        Status,
        Subject,
        WhoId
      FROM Task
      WHERE WhoId IN :ids
      AND OwnerId IN :userIds
      AND LastModifiedDate > :startDateTime
      AND LastModifiedDate < :endDateTime
      AND (Status = 'Completed - Not Answered' OR Status = 'Completed - Answered')
      AND Subject = 'Call'
      AND IsDeleted = FALSE];
    Data_Based.PerformanceBuilder attemptedContactsPerformanceBuilder = new Data_Based.PerformanceBuilder(false, CONTACTS_NAME, skillMappings);
    Data_Based.PerformanceBuilder callsAnsweredPerformanceBuilder = new Data_Based.PerformanceBuilder(false, ANSWER_RATE_NAME, skillMappings);
    for (Task c : callsPlaced) {
      Lead l = leadsByIds.get(c.WhoId);
      if ((l.IsConverted && c.ActivityDate <= l.ConvertedDate) || (!l.IsConverted)) {
        attemptedContactsPerformanceBuilder.incrementCount(c.OwnerId, c.ActivityDate);
        if (c.Status.equals('Completed - Answered')) {
          callsAnsweredPerformanceBuilder.incrementCount(c.OwnerId, c.ActivityDate);
        }
      }
    }
    skillPerformances.addAll(attemptedContactsPerformanceBuilder.getPerformances(skillMappings));
    skillPerformances.addAll(callsAnsweredPerformanceBuilder.getPerformances(skillMappings));

    /* OPPORTUNITY BASED PERFORMANCES */
    List<Opportunity> allOpportunities = [
      SELECT
        IsWon,
        Amount,
        CloseDate,
        CreatedDate,
        LastModifiedDate,
        OwnerId
      FROM Opportunity
      WHERE
      LastModifiedDate >= :startDateTime
      AND LastModifiedDate < :endDateTime
      AND OwnerId IN :userIds
      AND IsDeleted = FALSE];

    Data_Based.PerformanceBuilder discoveryPerformanceBuilder = new Data_Based.PerformanceBuilder(false, DISCOVERY_NAME, skillMappings);
    Data_Based.PerformanceBuilder winRatePerformanceBuilder = new Data_Based.PerformanceBuilder(false, WIN_RATE_NAME, skillMappings);
    Data_Based.PerformanceBuilder averageDealSizePerformanceBuilder = new Data_Based.PerformanceBuilder(true, AVG_DEAL_SIZE_NAME, skillMappings);

    for (Opportunity o : allOpportunities) {
      discoveryPerformanceBuilder.incrementCount(o.OwnerId, o.CreatedDate.date());
      if (o.IsWon) {
        winRatePerformanceBuilder.incrementCount(o.OwnerId, o.CloseDate);
        averageDealSizePerformanceBuilder.addToSum(o.OwnerId, o.CloseDate, o.Amount);
      }
    }
    skillPerformances.addAll(discoveryPerformanceBuilder.getPerformances(skillMappings));
    skillPerformances.addAll(winRatePerformanceBuilder.getPerformances(skillMappings));
    skillPerformances.addAll(averageDealSizePerformanceBuilder.getPerformances(skillMappings));
    return skillPerformances;
  }
}

 
I'm currently stuck on the "Learn Standard Open Redirect Preventions" challenge of the "App Logic Vulnerability Prevention" module.

The challenge is to submit a valid open redirect attack starting from the Standard Redirect Protections Challenge tab.

However, the links on this page are all to standard record pages, where the hack (e.g changing retURL to returl) won't work (it only works on VF pages).

Even if I attempt this and check the challenge, the error I get states: "It doesn't appear that you've successfully redirected to an external website using the Visualforce page. Please try again." - so it implies that it expects me executing this from a custom VF page.

Can anyone give me some advice on where I'm missing something on the challenge?