Need help on portal

Nivedita9
Tera Contributor

Hi,
I'm facing an issue with portal. I had added few fields on portal and I'm able to see them when I impersonate to end user I can just see one field (LINK). 
End user has itil role and can see the fields on native view.

Html

<div ng-if="!data.isValid">
${Record not found}
</div>
<div ng-if="data.isValid">
<div class="panel panel-{{::options.color}} b">
<div class="panel-heading">
<h4 class="panel-title">${Approval request for {{::task.table}} {{::task.number.display_value}}}</h4>
</div>

<div class="panel-body">
<div ng-if="task.short_description"><label><b>${Short Description}</b></label>: {{::task.short_description.display_value}}</div>
<div ng-if="task.opened_by"><label>${Opened by}</label>: {{::task.opened_by.display_value}}</div>
<div ng-if="task.requested_by"><label>${Requestor}</label>: {{::task.requested_by.display_value}}</div>

<div ng-if="task.table == 'Knowledge'">
<div ng-if="task.version">
<label><b>${Version}:</b></label>
{{::task.version.display_value}}
</div>
<div ng-if="task.author">
<label><b>${Author}:</b></label>
{{::task.author.display_value}}
</div>
<!--The review date has been added as part of ORCHESTRAT-53 story from sprint 105 -->
<div ng-if="task.u_review_date">
<label><b>${Review Date}:</b></label>
{{::task.u_review_date.display_value}}
</div>
<div ng-if="task.kb_link">
<b><a href='{{::task.kb_link}}' target='_blank'>Link to KB Article</a></b>
</div>
<div ng-if="task.kb_text">
<label><b>${Knowledge Body}:</b></label>
<p ng-bind-html="::task.kb_text" class='panel panel-body b'></p>
</div>
</div>

<!-- GSD-7160 VR Approval start -->
<div ng-if="task.source_table">
<div ng-init="variable_toggle=false">
<a id="veiw_more" href="javascript&colon;void(0)" ng-click="variable_toggle = !variable_toggle">
<span class="glyphicon"
ng-class="{'glyphicon-chevron-down': !variable_toggle, 'glyphicon-chevron-up': variable_toggle}">
</span>
${Options}
</a>
<div ng-if="!variable_toggle">
<label class="text-muted"></label>
<div ng-if="task.approval_name"><label>${Approval Name:}</label> {{::task.approval_name}}</div>
<div ng-if="task.approval_state"><label>${Approval State:}</label> {{::task.approval_state}}</div>
<div ng-if="task.desired_state"><label>${Desired State:}</label> {{::task.desired_state}}</div>
<div ng-if="task.desired_substate"><label>${Desired Substate:}</label> {{::task.desired_substate}}</div>
<div ng-if="task.until"><label>${Until:}</label> {{::task.until}}</div>
<div ng-if="task.add_info"><label>${Additional Information:}</label> {{::task.add_info}}</div>
<div ng-if="task.description"><label>${Details:}</label> {{::task.description}}</div>
<!-- </div> -->
</div>
</div>
</div>
<!-- GSD-7160VR Approval end-->

<div ng-if="::data.approver"><label>${Approver}</label> {{::data.approver}}</div>
<div ng-if="task.start_date"><label>${Start}</label> {{::task.start_date.display_value}}</div>
<div ng-if="task.end_date"><label>${End}</label> {{::task.end_date.display_value}}</div>
<div ng-if="task.quantity">${Quantity} {{::task.quantity.display_value}}</div>
<div ng-if="task.price.value > 0"><label>${Price}</label> {{::task.price.display_value}}
<span ng-if="task.recurring_frequency.value != null"><label>${Recurring price}</label>
{{::task.recurring_price.display_value}} {{task.recurring_frequency.display_value}}</span>
<!--label ng-if="task.quantity && task.quantity.value > 1"> ${each}</label-->
</div>

<div ng-if="data.items.length > 0">
<h3 class="h4">${Items in this Request}</h3>
<div ng-repeat="item in data.items">
<h4>
{{::item.short_description}}
</h4>
<div ng-if="item.price">${Price} {{::item.price}}
<span ng-if="item.recurring_price">${Recurring price} {{::item.recurring_price}}
{{::item.recurring_frequency}}</span>
</div>
<sp-widget ng-if="item.variableSummarizerWidget" widget="item.variableSummarizerWidget"></sp-widget>

</div>
</div>

<sp-widget widget="data.variableSummarizerWidget"></sp-widget>
</div>
<sp-widget widget="data.ticketConversation"></sp-widget>
</div>

Server side

(function () {
  // g_approval_form_request is for approval summarizer ACLs
  // that let user read a record they need to approve. This global
  // variable is then deleted at the bottom of the script
  g_approval_form_request = true;
  var approverGR = $sp.getRecord();
  // if (approverGR == null || !approverGR.isValid()) {
  // data.isValid = false;
  // return;
  // }
  if (approverGR.getValue("approver") != gs.getUserID())
    data.approver = approverGR.approver.getDisplayValue();
  data.isValid = true;
  var task = getRecordBeingApproved(approverGR);
  var t = {};
  t = $sp.getFieldsObject(task, 'number,short_description,opened_by,requested_by,start_date,end_date,price,recurring_price,recurring_frequency,version,author,u_review_date');
  t.table = task.getLabel();
//t.tableName = task.getTableName();
 
  // GSD-7160 VR fields start
  if (task.isValidField("approval_state") && !task.approval_state.nil())
    t.approval_state = task.approval_state.getDisplayValue();
 
  if (task.isValidField("name") && !task.name.nil())
    t.approval_name = task.name.getDisplayValue();
 
  if (task.isValidField("desired_state") && !task.desired_state.nil())
    t.desired_state = task.desired_state.getDisplayValue();
 
  if (task.isValidField("desired_substate") && !task.desired_substate.nil())
    t.desired_substate = task.desired_substate.getDisplayValue();
 
 
  if (task.isValidField("desired_ignore_date") && !task.desired_ignore_date.nil())
    t.until = task.getValue('desired_ignore_date');
 
  if (task.isValidField("desired_reason") && !task.desired_reason.nil())
    t.add_info = task.getValue('desired_reason');
 
  if (task.isValidField("description") && !task.description.nil())
    t.description = task.getValue('description');
 
  if (approverGR.source_table == 'sn_vul_change_approval')
    t.source_table = approverGR.source_table;
  // GSD-7160 VR fields end
 
  var items = [];
  var idx = 0;
  var itemsGR = new GlideRecord("sc_req_item");
  itemsGR.addQuery("request", task.sys_id);
  itemsGR.query();
  while (itemsGR.next()) {
    var item = {};
    item.short_description = itemsGR.getValue('short_description');
    if (itemsGR.getValue("price") > 0)
      item.price = itemsGR.getDisplayValue("price");
 
    if (itemsGR.getValue("recurring_price") > 0) {
      item.recurring_price = itemsGR.getDisplayValue("recurring_price");
      item.recurring_frequency = itemsGR.getDisplayValue("recurring_frequency");
    }
    //GSD-4423: Modify approval page in service portal  
    /*if (itemsGR)
      item.variables = $sp.getRecordVariablesArray(itemsGR);
    
    items[idx] = item;
    idx++;*/
    if (itemsGR) {
      item.variables = new GlobalServiceCatalogUtil().getVariablesForTask(itemsGR, true);
      item.variableSummarizerWidget = $sp.getWidget('sc-variable-summarizer', { 'variables': item.variables, 'toggle': false, 'task': t.number.value });
    }
    items[idx] = item;
    idx++;
  }
 
 
  var itemsGR = new GlideRecord("kb_knowledge");
  itemsGR.addQuery("sys_id", task.sys_id);
  itemsGR.query();
  while (itemsGR.next()) {
    var item = {};
    item.can_read_user_criteria = itemsGR.getDisplayValue('can_read_user_criteria');
 
    if (itemsGR.getDisplayValue('text'))
      item.text = itemsGR.getDisplayValue('text').toString();
    item.cannot_read_user_criteria = itemsGR.getDisplayValue('cannot_read_user_criteria');
 
    if (itemsGR)
      item.variables = $sp.getRecordVariablesArray(itemsGR);
 
    items[idx] = item;
    idx++;
  }
  /*data.items = items;
  data.sys_id = approverGR.getUniqueValue();
  data.task = t;
  if (task)
    data.variables = $sp.getRecordVariablesArray(task);*/
  //GSD-4423: Modify approval page in service portal
  data.items = items;
  data.sys_id = approverGR.getUniqueValue();
  data.task = t;
if(t.tableName == 'Knowledge') {
var temp = $sp.getFieldsObject(task, 'text,sys_id');
t.kb_text = temp.text.display_value.substring(0,300) + '...';
t.kb_link = '/kb_knowledge.do?sys_id=' + temp.sys_id.display_value;
}
  if (task) {
    data.variables = new GlobalServiceCatalogUtil().getVariablesForTask(task, true);
    data.variableSummarizerWidget = $sp.getWidget('sc-variable-summarizer', { 'variables': data.variables, 'toggle': true, 'task': t.number.value });
  }
 
  function getRecordBeingApproved(approverGR) {
    if (!approverGR.sysapproval.nil()) {
      refRecord = approverGR.sysapproval.getRefRecord();
      if (refRecord.isValidRecord())
        return refRecord;
    }
 
    return approverGR.document_id.getRefRecord();
  }
 
  var ticketConversationOptions = {
    sys_id: task.getUniqueValue(),
    table: task.getTableName(),
    title: gs.getMessage("Activity Stream"),
    placeholder: gs.getMessage("Type your message here..."),
    placeholderNoEntries: gs.getMessage("Start a conversation..."),
    btnLabel: gs.getMessage("Send")
  };
 
  data.ticketConversation = $sp.getWidget('widget-ticket-conversation', ticketConversationOptions);
  delete g_approval_form_request;
})();
admin view
Nivedita9_0-1752231213009.png

end user

Nivedita9_1-1752231245416.png

 

3 REPLIES 3

Ct111
Giga Sage

Does he (End user)  have the approval request for KB0038454  ?

 

Can you crosscheck and confirm from backend (native view)?

Nivedita9
Tera Contributor

yes end user has

venkat917181
Tera Expert

Hi Nivedita,

ServiceNow has separate ACL evaluations for Service Portal vs native UI. The fields are being filtered out specifically in the portal context.

1. Check Portal-Specific ACLs

Navigate to System Security > Access Control (ACL) and filter by:

  • Table: kb_knowledge
  • Type: read
  • Look for ACLs with Advanced tab conditions like:
     
    // Common portal-blocking conditions
    answer != 'true' && gs.getProperty('glide.ui.portal') == 'true'
    // or
    !gs.hasRole('knowledge_admin') && gs.isInteractive()

2. Create Portal-Specific ACLs

If the existing ACLs don't account for portal access, create new ones:

For each field (version, author, u_review_date):

  • Table: kb_knowledge
  • Field: version (repeat for each field)
  • Type: read
  • Operation: read
  • Role: itil (or appropriate role)
  • Advanced tab - Add condition:
     
    // Allow portal access for users with itil role
    if (gs.hasRole('itil')) {
        answer = true;
    }

3. Modify Existing ACLs

Find the existing ACLs that are blocking portal access and modify them:

Look for ACLs with conditions like:

 
 
// This blocks portal access
gs.getProperty('glide.ui.portal') != 'true'

Change to:

// This allows portal access for itil users
gs.getProperty('glide.ui.portal') != 'true' || gs.hasRole('itil')