App Script Sync to Workspace Directory Function error: Required parameter: [resource.about.Value]

53 Views Asked by At

When I try to execute my script its getting an error.

4:37:30 PM Info Attempting to update user with email: EMAIL

4:37:46 PM Info Failed to get or update user with email: EMAIL Error: GoogleJsonResponseException: API call to directory.users.update failed with error: Required parameter: [resource.about.Value]

This Google Apps Script code is designed to synchronize user data from a Google Sheet to a Google Workspace Directory using Admin SDK Directory Service. Here's a breakdown of the key components and functionality:

** App Scripts Main Functions: **

  1. syncUpdatesToDirectory(): This is the main function called with a trigger based on time. It loops through each row in the active sheet, looking for rows marked with a 'Y' in the "Update" column to process. It does the following:

    • Checks if the "Error Log" sheet exists, if not, it creates one and sets up headers.
    • For each row that needs an update, it retrieves the user's primary email.
    • Using the AdminDirectory.Users.get() method, it fetches the user's current information.
    • It then calls updateUserFieldsFromRow() to map the sheet's data to the user object.
    • After updating the user object, it attempts to push these updates back to the directory with AdminDirectory.Users.update().
    • If any errors occur while fetching or updating the user, these are logged into the "Error Log" sheet.
  2. updateUserFieldsFromRow(): This function takes a user object, a row of data from the sheet, headers, and references to the error log and other pertinent information. It iterates over each cell in the row, mapping them to the user object using setUserField(). If there's an error while updating a specific field, it logs this error into the "Error Log" sheet, only skipping the problematic column instead of the entire row.

Helper Functions and Objects Management:

  • setUserField(user, header, value): Based on the header, this function decides which field of the user object should be updated with the provided value. It handles various user attributes like names, emails, addresses, phones, etc., including custom schema fields for detailed customization.

  • setAddress(user, type, field, value) and setOrAddPhone(user, type, value): These are specialized functions for adding or setting address and phone information in the user object, managing multiple entries when necessary.

  • Initialization of user object arrays and objects: Before setting values, the setUserField() function checks and initializes various parts of the user object such as user.addresses, user.phones, user.emails, etc., if they are not already present.

  • Mapping logic: For specific fields like "Organization FTE" or "Suspension Status", the script does some type conversion or condition checking to ensure the data types are correct for the directory service (e.g., converting a string to an integer or boolean).

Error Handling and Logging:

  • The script uses try-catch blocks to handle exceptions that occur during the update of user fields. If an error occurs while updating a specific field, the script catches it, logs the error message using Logger.log(), and appends the error details to the "Error Log" sheet including the email, column name, error message, and row and column indices.

Workflow Enhancement:

  • Once a row has been processed and updated successfully, the "Update" column for that row is set to 'N' to indicate completion and prevent reprocessing.

Here is the code

// This function maps the data from the sheet row to the user object
function updateUserFieldsFromRow(user, row, headers, errorLogSheet, primaryEmail, rowIndex) {
  for (var j = 0; j < headers.length; j++) {
    var header = headers[j];
    var value = row[j];
    if (value !== "" && header !== "Update" && header !== "Primary Email") {
      try {
        // Update the user object based on the header
        setUserField(user, header, value);
      } catch (e) {
        // Log the error for the specific column
        var errorMessage = "Error updating " + header + " for email: " + primaryEmail + " Error: " + e.toString();
        Logger.log(errorMessage);
        // Log the error in the "Error Log" sheet with specific column that failed
        errorLogSheet.appendRow([primaryEmail, header, e.toString(), rowIndex, j + 1]);
      }
    }
  }
}
// This is the function you will call from the trigger
function syncUpdatesToDirectory() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getActiveSheet();
  var dataRange = sheet.getDataRange();
  var data = dataRange.getValues();

  var headers = data[0];
  var updateIndex = headers.indexOf("Update");
  var emailIndex = headers.indexOf("Primary Email");

  // Create or get the error log sheet
  var errorLogSheet = ss.getSheetByName("Error Log") || ss.insertSheet("Error Log");
  if (errorLogSheet.getLastRow() === 0) {
    errorLogSheet.appendRow(["Email", "Column", "Error", "Row Index", "Column Index"]); // Add headers to the error log if not present
  }

  for (var i = 1; i < data.length; i++) {
    var row = data[i];
    if (row[updateIndex] === 'Y') {
      var primaryEmail = row[emailIndex];
      Logger.log("Attempting to update user with email: " + primaryEmail);

      if (!primaryEmail) {
        Logger.log("No primary email found in row " + (i + 1));
        errorLogSheet.appendRow([primaryEmail, "All", "No primary email found", i + 1, "All"]);
        continue;
      }

      try {
        var user = AdminDirectory.Users.get(primaryEmail);
        updateUserFieldsFromRow(user, row, headers, errorLogSheet, primaryEmail, i + 1);
        AdminDirectory.Users.update(user, primaryEmail);
        sheet.getRange(i + 1, updateIndex + 1).setValue('N');
      } catch (e) {
        // Log the error if there is an issue with getting or updating the user itself
        var errorMessage = "Failed to get or update user with email: " + primaryEmail + " Error: " + e.toString();
        Logger.log(errorMessage);
        errorLogSheet.appendRow([primaryEmail, "General", e.toString(), i + 1, "All"]);
      }
    }
  }
}



// The rest of your functions remain unchanged


// This function maps the data from the sheet row to the user object
function updateUserFieldsFromRow(user, row, headers) {
  for (var j = 0; j < headers.length; j++) {
    var header = headers[j];
    var value = row[j];
    if (value !== "" && header !== "Update" && header !== "UserId") {
      // Update the user object based on the header
      setUserField(user, header, value);
    }
  }
}

// Helper function to set or add an address
function setAddress(user, type, field, value) {
  var addressObj = user.addresses.find(address => address.type === type);
  if (addressObj) {
    addressObj[field] = value;
  } else {
    let newAddress = { type: type };
    newAddress[field] = value;
    user.addresses.push(newAddress);
  }
}

// Helper function to set or add a phone number
function setOrAddPhone(user, type, value) {
  var phoneObj = user.phones.find(phone => phone.type === type);
  if (phoneObj) {
    phoneObj.value = value;
  } else {
    user.phones.push({ type: type, value: value });
  }
}

// This function sets the user field based on the header name
function setUserField(user, header, value) {
  if (!user.name) user.name = {};
  if (!user.organizations) user.organizations = [{}];
  if (!user.locations) user.locations = [{}];
  if (!user.phones) user.phones = [];
  if (!user.emails) user.emails = [];
  if (!user.addresses) user.addresses = [];
  if (!user.relations) user.relations = [{}];
  if (!user.externalIds) user.externalIds = [{}];
  if (!user.ims) user.ims = [{}];
  if (!user.keywords) user.keywords = [{}];
  if (!user.notes) user.notes = {};
  if (!user.customSchemas) user.customSchemas = {};
  if (!user.customSchemas.LOCAH_Contact) user.customSchemas.LOCAH_Contact = {};

  switch (header) {
    case "Primary Email":
      user.primaryEmail = value;
      break;
    case "Given Name":
      user.name.givenName = value;
      break;
    case "Family Name":
      user.name.familyName = value;
      break;
    case "Recovery Email":
      user.recoveryEmail = value;
      break;
    case "Recovery Phone":
      user.recoveryPhone = value;
      break;
    case "Alias":
      user.aliases = value.split(',').map(alias => alias.trim());
      break;
    case "Organization Title":
      user.organizations[0].title = value;
      break;
    case "Organization Department":
      user.organizations[0].department = value;
      break;
    case "Organization Symbol":
      user.organizations[0].symbol = value;
      break;
    case "Organization Location":
      user.organizations[0].location = value;
      break;
    case "Organization Description":
      user.organizations[0].description = value;
      break;
    case "Organization Domain":
      user.organizations[0].domain = value;
      break;
    case "Organization Cost Center":
      user.organizations[0].costCenter = value;
      break;
    case "Organization FTE":
      user.organizations[0].fullTimeEquivalent = parseInt(value, 10);
      break;
    case "Location Type":
      user.locations[0].type = value;
      break;
    case "Location Area":
      user.locations[0].area = value;
      break;
    case "Location Building ID":
      user.locations[0].buildingId = value;
      break;
    case "Location Floor Name":
      user.locations[0].floorName = value;
      break;
    case "Location Floor Section":
      user.locations[0].floorSection = value;
      break;
    case "Location Desk Code":
      user.locations[0].deskCode = value;
      break;
    case "Work Phone":
      setOrAddPhone(user, 'work', value);
      break;
    case "Mobile Phone":
      setOrAddPhone(user, 'mobile', value);
      break;
    case "Secondary Work Email":
      setOrAddEmail(user, 'work_secondary', value);
      break;
      // Address fields for 'Home Address'
      case "Home Address Street":
        setAddress(user, 'home', 'streetAddress', value);
        break;
      case "Home Address Locality":
        setAddress(user, 'home', 'locality', value);
        break;
      case "Home Address Region":
        setAddress(user, 'home', 'region', value);
        break;
      case "Home Address Postal Code":
        setAddress(user, 'home', 'postalCode', value);
        break;
      case "Home Address Country":
        setAddress(user, 'home', 'country', value);
        break;
      case "Home Address Country Code":
        setAddress(user, 'home', 'countryCode', value);
        break;

      // Address fields for 'Work Address'
      case "Work Address Street":
        setAddress(user, 'work', 'streetAddress', value);
        break;
      case "Work Address Locality":
        setAddress(user, 'work', 'locality', value);
        break;
      case "Work Address Region":
        setAddress(user, 'work', 'region', value);
        break;
      case "Work Address Postal Code":
        setAddress(user, 'work', 'postalCode', value);
        break;
      case "Work Address Country":
        setAddress(user, 'work', 'country', value);
        break;
      case "Work Address Country Code":
        setAddress(user, 'work', 'countryCode', value);
        break;
      case "Relation Type":
      user.relations[0].type = value;
      break;
    case "Relation Value":
      user.relations[0].value = value;
      break;
    // ... continue for each externalId, im, keyword
    case "Notes Content Type":
      user.notes.contentType = value;
      break;
    case "Notes Value":
      user.notes.value = value;
      break;
    case "Gender":
      if (!user.gender) user.gender = {};
      user.gender.type = value;
      break;
    case "Birthday":
      user.birthday = value;
      break;
    case "Event":
      if (!user.events) user.events = [{}];
      user.events[0].description = value;
      break;
    case "Suspension Status":
      user.suspended = (value === "Suspended");
      break;
    // Custom schema fields for 'LOCAH Contact'
    case "LOCAH Contact Work Email":
      user.customSchemas.LOCAH_Contact.Work_Email = value;
      break;
    case "LOCAH Contact Work Cell":
      user.customSchemas.LOCAH_Contact.Work_Cell = value;
      break;
    case "LOCAH Contact Personal Cell":
      user.customSchemas.LOCAH_Contact.Personal_Cell = value;
      break;
    case "LOCAH Contact Work Fax":
      user.customSchemas.LOCAH_Contact.Work_Fax = value;
      break;
    case "LOCAH Contact Personal Fax":
      user.customSchemas.LOCAH_Contact.Personal_Fax = value;
      break;
    case "LOCAH Contact Work Office":
      user.customSchemas.LOCAH_Contact.Work_Office = value;
      break;
    case "LOCAH Contact Personal Home":
      user.customSchemas.LOCAH_Contact.Personal_Home = value;
      break;
    // Other custom fields...
  }
}
0

There are 0 best solutions below