How to lock annotation role based

WebViewer Version:
I want to handle the annotation role based lock like if i assigned two different signature fields for two different people and i want only person can edit or make change in the annotation to whom it was assigned otherwise all other annotations will on readOnly mode so that my functionality will work properly I have also attached my code for referrence

Do you have an issue with a specific file(s)?
Can you reproduce using one of our samples or online demos?
Are you using the WebViewer server?
Does the issue only happen on certain browsers?
Is your issue related to a front-end framework?
Is your issue related to annotations?

Please give a brief summary of your issue:
(Think of this as an email subject)

Please describe your issue and provide steps to reproduce it:
(The more descriptive your answer, the faster we are able to help you)

Please provide a link to a minimal sample where the issue is reproducible:

const applyFields = async () => {
console.log(“@@@@@@@@@@@@@@@@@@@@@@@@”);
const { Annotations, documentViewer } = instance.Core;
const annotationManager = documentViewer.getAnnotationManager();
const fieldManager = annotationManager.getFieldManager();
const annotationsList = annotationManager.getAnnotationsList();
const annotsToDelete = ;
const annotsToDraw = ;
const fieldArr = ; // Array to store field names

// Get current user
const currentUser = annotationManager.getCurrentUser();

await Promise.all(
  annotationsList.map(async (annot, index) => {
    let inputAnnot;
    let field;

    // Add this check here - right at the start of processing each annotation
    if (!annot || !annot.custom) {
      return; // Skip invalid annotations
    }

    // Skip fields the current user doesn't have access to
    if (!canAccessField(annot)) {
      return;
    }

    // Extract fieldName values
    const fieldNames = annotationsList
      .filter((annot) => annot.custom && annot.custom.name) // Ensure the annotation has a custom name
      .map((annot) => annot.custom.name);

    // Update the state with the collected field names
    setSavedFieldNames(fieldNames);

    // Log the field names for debugging
    console.log("Saved Field Names:", fieldNames);

    // Get the user data from the annotation with proper fallbacks
    const fieldData = {
      creator: annot.custom.creator || currentUser || "",
      assignee: annot.custom.assignee || "",
      type: annot.custom.type || "",
      value: annot.custom.value || "",
    };

    // Create a unique field name that includes user information
    const fieldName = `${fieldData.assignee}_${
      fieldData.type
    }_${Date.now()}_${index}`;
    console.log("fieldName", fieldName);

    fieldArr.push(fieldName);
    console.log("fieldArr", fieldArr);

    // Proceed with the existing save logic
    const annotations = annotationManager.exportAnnotations({ link: true });
    const body = { annotationData: annotations };
    const val = JSON.stringify(body);

    // create a form field based on the type of annotation
    if (fieldData.type === "TEXT") {
      field = new Annotations.Forms.Field(fieldName, {
        type: "Tx",
        value: fieldData.value,
        userData: fieldData,
      });
      inputAnnot = new Annotations.TextWidgetAnnotation(field);
      inputAnnot.setFieldIndicator(true, "Insert text here");
    } else if (fieldData.type === "SIGNATURE") {
      field = new Annotations.Forms.Field(fieldName, {
        type: "Sig",
        userData: fieldData,
      });
      inputAnnot = new Annotations.SignatureWidgetAnnotation(field, {
        appearance: "_DEFAULT",
        appearances: {
          _DEFAULT: {
            Normal: {
              data: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjEuMWMqnEsAAAANSURBVBhXY/j//z8DAAj8Av6IXwbgAAAAAElFTkSuQmCC",
              offset: {
                x: 100,
                y: 100,
              },
            },
          },
        },
      });
      inputAnnot.setFieldIndicator(true, "Sign Here");
    } else if (fieldData.type === "DATE") {
      field = new Annotations.Forms.Field(fieldName, {
        type: "Tx",
        value: "mm-dd-yyyy",
        userData: fieldData,
        actions: {
          F: [
            {
              name: "JavaScript",
              javascript: 'AFDate_FormatEx("mmm d, yyyy");',
            },
          ],
          K: [
            {
              name: "JavaScript",
              javascript: 'AFDate_FormatEx("mmm d, yyyy");',
            },
          ],
        },
      });
      inputAnnot = new Annotations.DatePickerWidgetAnnotation(field);
    } else {
      // exit early for other annotations
      annotationManager.deleteAnnotation(annot, false, true);
      return;
    }

    // set position
    inputAnnot.PageNumber = annot.getPageNumber();
    inputAnnot.X = annot.getX();
    inputAnnot.Y = annot.getY();
    inputAnnot.rotation = annot.Rotation;
    if (annot.Rotation === 0 || annot.Rotation === 180) {
      inputAnnot.Width = annot.getWidth();
      inputAnnot.Height = annot.getHeight();
    } else {
      inputAnnot.Width = annot.getHeight();
      inputAnnot.Height = annot.getWidth();
    }

    // Set the author of the annotation
    inputAnnot.Author = fieldData.creator;

    // delete original annotation
    annotsToDelete.push(annot);

    // customize styles of the form field
    Annotations.WidgetAnnotation.getCustomStyles = function (widget) {
      if (widget instanceof Annotations.SignatureWidgetAnnotation) {
        return {
          border: "1px solid #a5c7ff",
        };
      }
      if (widget instanceof Annotations.TextWidgetAnnotation) {
        return {
          border: "1px dashed #ff9800",
          backgroundColor: "#fff3cd",
        };
      }
      if (widget instanceof Annotations.DatePickerWidgetAnnotation) {
        return {
          border: "1px dashedrgb(255, 51, 0)",
          backgroundColor: "#fff3cd",
        };
      }
    };
    Annotations.WidgetAnnotation.getCustomStyles(inputAnnot);

    // draw the annotation the viewer
    annotationManager.addAnnotation(inputAnnot);
    fieldManager.addField(field);
    annotsToDraw.push(inputAnnot);
  })
  // setFieldsApplied(true)
);

// Step 2: Group fields by email ID
const groupedFields = fieldArr.reduce((acc, field) => {
  // Extract the email ID from the field name
  const email = field.split("_")[0]; // Get the part before the first underscore

  // Initialize the array for the email if it doesn't exist
  if (!acc[email]) {
    acc[email] = [];
  }

  // Add the field to the corresponding email group
  acc[email].push(field);

  return acc;
}, {});

// Step 3: Convert the grouped object into an array of objects
const finalArray = Object.keys(groupedFields).map((email) => {
  const modifiedEmail = email.replace(/\.([^.]*)$/, "<>$1");
  return { [modifiedEmail]: groupedFields[email] };
});

setUserAnnotations(finalArray); // Update the state with the final array

// Step 3: Log the final array for debugging
console.log("Final Array of Categorized Fields:", finalArray);
// delete old annotations
annotationManager.deleteAnnotations(annotsToDelete, null, true);

// refresh viewer
await annotationManager.drawAnnotationsFromList(annotsToDraw);

// Save the annotations with user data
const annotations = await annotationManager.exportAnnotations({
  link: true,
});
// console.log("annotations", annotations);
const body = {
  annotationData: annotations,
  userAnnotations: finalArray,
};
const val = JSON.stringify(body);

try {
  await props.saveDmsAnnotation(val, props.fileId);
  dispatch(setSnackbar(true, "success", "Fields saved successfully"));
} catch (error) {
  console.error("Error saving annotations:", error);
  dispatch(setSnackbar(true, "error", "Failed to save fields"));
}

};

const addField = (type, point = {}, name = “”, value = “”, flag = {}) => {
if (instance) {
const { documentViewer, Annotations } = instance.Core;
// const annotationManager = documentViewer.getAnnotationManager();
const doc = documentViewer.getDocument();
const displayMode = documentViewer
.getDisplayModeManager()
.getDisplayMode();

  const page = displayMode.getSelectedPages(point, point);
  if (!!point?.x && page.first == null) {
    return; //don't add field to an invalid page location
  }
  const page_idx =
    page.first !== null ? page.first : documentViewer.getCurrentPage();
  const page_info = doc.getPageInfo(page_idx);
  const page_point = displayMode.windowToPage(point, page_idx);
  const zoom = documentViewer.getZoomLevel();

  var textAnnot = new Annotations.FreeTextAnnotation();
  console.log("textAnnnnnnnnot", textAnnot);
  textAnnot.PageNumber = page_idx;
  const rotation = documentViewer.getCompleteRotation(page_idx) * 90;
  textAnnot.Rotation = rotation;
  if (rotation === 270 || rotation === 90) {
    textAnnot.Width = 50.0 / zoom;
    textAnnot.Height = 250.0 / zoom;
  } else {
    textAnnot.Width = 250.0 / zoom;
    textAnnot.Height = 50.0 / zoom;
  }
  textAnnot.X =
    (page_point?.x || page_info.width / 2) - textAnnot.Width / 2;
  textAnnot.Y =
    (page_point.y || page_info.height / 2) - textAnnot.Height / 2;

  textAnnot.setPadding(new Annotations.Rect(0, 0, 0, 0));
  textAnnot.setCustomData("assignee", assignedValues);
  textAnnot.custom = {
    type,
    value,
    flag,
    name: `${assignedValues}_${type}_`,
    // name: `${type}`,
    assignee: assignedValues, // Add this to track who the field belongs to
    creator: annotationManager.getCurrentUser() || "", // Track who created the field
  };

  // set the type of annot
  textAnnot.setContents(textAnnot.custom.name);
  textAnnot.FontSize = "" + 20.0 / zoom + "px";
  textAnnot.FillColor = new Annotations.Color(211, 211, 211, 0.5);
  textAnnot.TextColor = new Annotations.Color(0, 165, 228);
  textAnnot.StrokeThickness = 1;
  textAnnot.StrokeColor = new Annotations.Color(0, 165, 228);
  textAnnot.TextAlign = "center";
  textAnnot.Author = annotationManager.getCurrentUser();

  annotationManager.deselectAllAnnotations();
  annotationManager.addAnnotation(textAnnot, true);
  annotationManager.redrawAnnotation(textAnnot);
  annotationManager.selectAnnotation(textAnnot);

  // Update the field count for the selected user
  setFieldCounts((prevCounts) => ({
    ...prevCounts,
    [assignedValues]: prevCounts[assignedValues] + 1, // Increment the count for the selected user
  }));

  // Create an array of objects with email and count
  const userFieldCounts = Object.keys(fieldCounts).map((email) => ({
    email,
    count: fieldCounts[email],
  }));

  // Console log the array
  console.log("User Field Counts:", userFieldCounts);

  // âś… Increment field count when added
  setFieldCount((prevCount) => prevCount + 1);

  // âś… Add a unique ID to the annotation for tracking
  textAnnot.Id = `field_${Date.now()}`;

  // âś… Store reference to track the added field
  if (!window.fieldMap) {
    window.fieldMap = new Map();
  }
  window.fieldMap.set(textAnnot.Id, textAnnot);

  // âś… Add listener to detect annotation deletions
  annotationManager.addEventListener(
    "annotationChanged",
    (annotations, action) => {
      if (action === "delete") {
        annotations.forEach((annot) => {
          if (window.fieldMap.has(annot.Id)) {
            setFieldCount((prevCount) => Math.max(prevCount - 1, 0));
            window.fieldMap.delete(annot.Id);
          }
        });
      }
    }
  );

  // âś… Add listener to detect annotation filled
  annotationManager.addEventListener(
    "annotationChanged",
    (annotations, action) => {
      if (action === "modify") {
        annotations.forEach((annot) => {
          if (
            annot instanceof Annotations.WidgetAnnotation &&
            annot.getField().type === "Sign"
          ) {
            const fieldName = annot.getField().name;
            const value = annot.getField().value;

            if (value && !window.filledSignatureSet.has(annot.Id)) {
              // Signature was just filled
              window.filledSignatureSet.add(annot.Id);
              setFilledSignatureCount((prevCount) => prevCount + 1);
            }

            if (!value && window.filledSignatureSet.has(annot.Id)) {
              // Signature was cleared (optional support)
              window.filledSignatureSet.delete(annot.Id);
              setFilledSignatureCount((prevCount) =>
                Math.max(prevCount - 1, 0)
              );
            }
          }
        });
      }
    }
  );
}

};

1 Like

Hello, I’m AiRon, an automated tech support bot :robot:
While you wait for one of our customer support representatives, I can help you with your question.


You are looking to implement role-based locking of annotations in WebViewer so that only specific users can edit or modify annotations that are assigned to them. This involves checking the current user against the assigned user for each annotation and setting the annotation’s properties accordingly.

Some things you can try:

  • Utilize the Annotations API to set annotations to read-only if the current user is not the assigned user.

  • Check the custom data of each annotation to retrieve the assignee information and compare it with the currentUser.

  • Use the setReadOnly method on annotations to prevent unauthorized users from editing them.

  • Listen for changes in the annotation state using annotationChanged events to enforce read-only status dynamically.

  • Consider using a helper function like canAccessField to determine if the current user should have edit access to a specific annotation.




Here are some resources that might help you:



Hopefully, this helps you solve your problem while you wait for a human to get back to you.

1 Like

Hi there,

Please see this guide on setting the author property of the annotation:

This will make it so that only the author that matches the annotation’s author will be able to interact with them.

We also have a sample snippet that shows/hides annotation based on user permissions here:

best regards,
Kevin

1 Like