Archive for the ‘Oracle RightNow CX Technologies’ Category

NodeJS ReactJS, NOT using Isomorphic-fetch, using jQuery JSONP GET -> Oracle Service Cloud Article Feedback ci/ajaxCustom Endpoint

Friday, June 23rd, 2017

app.js

'use strict';

const compression = require('compression');
const express = require('express');
const next = require('next');
const path = require('path');
const fetch = require('isomorphic-fetch');

const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const auth = '...';
const site = 'help-*-*';
const server = express();

class GetHelp {
constructor() {

this.initApp();
}

/*
Start express application and express healthcheck.
*/
initApp() {
app.prepare().then(() => {

/*
* API Server
*/

server.get('/api/search/:searchTerm', (req, res, next) => {
const searchTerm = req.params.searchTerm;
var endpoint = `services/rest/connect/v1.3/analyticsReportResults`;

fetch(
`https://${auth}@${site}.....com/${endpoint}`, {
method: 'POST',
mode: 'no-cors',
body: JSON.stringify({
"id": 178394,
"filters": [{
"name": "os_search",
"values": [
searchTerm
]
}]
})
})
.then(function(res) { return res.json(); })
.then(function(data) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ article: data }));
});
});

server.get('/api/article/:articleId', (req, res, next) => {
const articleId = req.params.articleId;
var endpoint = "";
if (parseInt(articleId)) {
endpoint = `/services/rest/connect/v1.3/answers/${articleId}/?fields=solution,summary`;
} else {
endpoint = `/services/rest/connect/v1.3/queryResults/?query=select summary,solution from answers where customFields.c.slug='${articleId}'and customFields.c.lang_id=2035 and language=1 and AccessLevels.NamedIDList.ID=11`;
}

fetch(
`https://${auth}@${site}.....com/${endpoint}`, {
method: 'GET',
mode: 'no-cors',
})
.then(function(res) { return res.json(); })
.then(function(data) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ article: data }));
});
});

var endpoint = "services/rest/connect/v1.3/queryResults/?query=select lookupName,value from messageBases ";
endpoint += "where lookupName in (" + msgToGet + ")";

fetch(
`https://${auth}@${site}.....com/${endpoint}`, {
method: 'GET',
mode: 'no-cors',
})
.then(function(res) { return res.json(); })
.then(function(data) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ messageBase: data }));
});
});

/*
* APP Routes
*/

server.get('/search/:searchTerm/page/:page', (req, res) => {
const params = { searchTerm: req.params.searchTerm, page: req.params.page }
return app.render(req, res, '/search', params);
});

server.get('/article/:articleId', (req, res) => {
const params = { articleId: req.params.articleId }
return app.render(req, res, '/article', params);
});

server.get('*', (req, res) => {
return handle(req, res);
});

server.listen(8080, 'local-www....dev.com', () => {
this.initHealthcheck();
});
});
}

}

module.exports = new GetHelp();

/components/StarRating.js

</pre></pre>
import React from 'react';

import Link from '../components/Link';

import Router from 'next/router'

import 'isomorphic-fetch';

import Modal from 'react-modal';

&nbsp;

&nbsp;

const site = 'help-en-us';

const customStyles = {

content : {

top: '50%',

left: '50%',

right: 'auto',

bottom: 'auto',

marginRight: '-50%',

transform: 'translate(-50%, -50%)'

}

};

&nbsp;

&nbsp;

export default class extends React.Component {

constructor(props) {

super(props);

this.state = {

starRating: 0,

articleId: this.props.articleId,

thankYou: false,

showStars: true

};

&nbsp;

&nbsp;

this.handleStar = this.handleStar.bind(this);

this.submitRating = this.submitRating.bind(this);

this.getToken = this.getToken.bind(this);

this.onKeyPress = this.onKeyPress.bind(this);

this.openModal = this.openModal.bind(this);

this.afterOpenModal = this.afterOpenModal.bind(this);

this.closeModal = this.closeModal.bind(this);

this.cancelModal = this.cancelModal.bind(this);

this.submitAnswerFeedback = this.submitAnswerFeedback.bind(this);

this.getToken = this.getToken.bind(this);

}

&nbsp;

&nbsp;

async submitRating(rating) {

let result = await $.ajax({

url: `http://${site}.....com/ci/ajaxCustom/submitAnswerRating`,

data: `a_id=${this.props.articleId}&amp;amp;rate=${rating}&amp;amp;options_count=5`,

dataType: 'jsonp',

jsonpCallback: 'submitAnswerRating',

success: function(response){

console.log(response.submitted);

}

});

let flag = await result;

return flag

};

&nbsp;

&nbsp;

async getToken(rating){

let result = await $.ajax({

url: `http://${site}.....com/ci/ajaxCustom/getNewFormToken`,

data: `formToken=${Math.random().toString(36).substr(2)}`,

dataType: 'jsonp',

jsonpCallback: 'getNewFormToken',

success: function(response){

//console.log(typeof(response.newToken));

return response;

}

});

let token = await result;

return token

};

&nbsp;

&nbsp;

async submitAnswerFeedback(){

let a_id = this.props.articleId;

let rating = this.state.starRating;

let feedbackMessageValue = this.state.feedbackMessageValue;

let token = this.state.token;

console.log('sAF: ' + token);

&nbsp;

&nbsp;

let result = await $.ajax({

url: `http://${site}.....com/ci/ajaxCustom/submitAnswerFeedback`,

data: `a_id=${a_id}&amp;amp;rate=${rating}&amp;amp;message=${feedbackMessageValue}&amp;amp;f_tok=${token}`,

dataType: 'jsonp',

jsonpCallback: 'submitAnswerFeedback',

success: function(response){

console.log(response);

}

});

&nbsp;

&nbsp;

let message = await result;

this.closeModal();

&nbsp;

&nbsp;

return message

};

&nbsp;

&nbsp;

async handleStar(rating){

// submit the star rating clicked

let ratingSubmitted = await this.submitRating(rating);

if(rating >= 3){

// submitted, and done

this.setState({

thankYou: true,

starRating: rating,

ratingSubmitted: ratingSubmitted,

showStars: false

})

} else {

// less than 3, so get a token, and open popup

let token = await this.getToken(rating);

console.log('obj: ' + token.newToken);

console.log(typeof(token.newToken));

this.openModal();

this.setState({

thankYou: true,

starRating: rating,

ratingSubmitted: ratingSubmitted,

token: token.newToken,

showStars: false

})

}

}

&nbsp;

&nbsp;

onKeyPress(e) {

let feedbackMessageValue = e.target.value;

}

&nbsp;

&nbsp;

onChange(e) {

let feedbackMessageValue = e.target.value;

this.setState({

feedbackMessageValue: feedbackMessageValue

});

}

&nbsp;

&nbsp;

openModal() {

this.setState({

modalIsOpen: true

});

}

&nbsp;

&nbsp;

afterOpenModal() {

// references are now sync'd and can be accessed.

this.subtitle.style.color = '#f00';

}

&nbsp;

&nbsp;

closeModal() {

this.setState({

modalIsOpen: false

});

}

&nbsp;

&nbsp;

cancelModal() {

this.setState({

modalIsOpen: false,

showStars: true,

thankYou: false

})

}

&nbsp;

&nbsp;

render () {

const stars = [1,2,3,4,5];

const starRating = this.state.starRating;

const thankYou = this.state.thankYou;

const showStars = this.state.showStars;

&nbsp;

&nbsp;

return (

&nbsp;

&nbsp;

<div className="box">

<div className="answerFeedback">

{!thankYou ? <div className="title">Please rate this article:</div> : ""}

{showStars ? (  <div className="starsBox">

{

stars.map((star) => {

return(

<span

key={star}

className={`g72-star ${star<=starRating?'selectedStar':''}`}

onClick={(e) => this.handleStar(star)}>

</span>

)

})

}

</div>) : (<span></span>)

}

{thankYou ? <div className="thankYou">Thank you for your feedback!</div> : ""}

<div> {

//<button onClick={this.openModal}>Open Modal</button> }

<Modal

isOpen={this.state.modalIsOpen}

onAfterOpen={this.afterOpenModal}

onRequestClose={this.closeModal}

style={customStyles}

contentLabel="Example Modal">

&nbsp;

<h2 ref = { subtitle => this.subtitle = subtitle }>Provide Additional Information</h2>

<div className = "submittedMessage">Your rating has been submitted, please tell us how we can make this answer more useful.</div>

<div className = "faqQuestion">FAQ Feedback – How can we improve this answer? *</div>

<textarea

className = "feedbackMessage"

id = "feedbackMessage"

name = "feedbackMessage"

rows = "4"

cols = "50"

value = { this.state.feedbackMessageValue }

onKeyPress = { (e) => this.onKeyPress(e) }

onChange={(e) => this.onChange(e)}></textarea>

<div className="formButtons">

<button onClick = { this.submitAnswerFeedback } className="submitButton">Submit</button>

<button onClick = { this.cancelModal } className="cancelButton">Cancel</button>

</div>

&nbsp;

&nbsp;

</Modal>

</div>

</div>

<style jsx>{`

.answerFeedback .title {

font-weigth: bold;

}

.answerFeedback .g72-star {

font-size: 1.5em;

margin: 5px;

cursor: pointer;

color: #6d6b6b;

}

.answerFeedback .g72-star:hover, .selectedStar{

color: rgb(251, 224, 0) !important;

}

.starsBox {

background: #a09e9e;

border-radius: 10px;

padding: 0 10px;

width: 170px;

text-align: center;

}

.feedbackMessage {

border: 1px solid;

margin: 10px 10px 10px 0;

padding: 10px;

width: 100%;

}

.formButtons {

text-align: right;

}

.submitButton, .cancelButton {

width: 100%;

margin: 0;

padding: 10px;

font-weight: bold;

color: white;

text-transform: uppercase;

border-radius: 3px;

text-align: center;

text-decoration: none;

}

.submitButton {

background-color: rgba(250, 84, 0, 1);

}

.submitButton:hover {

background-color: #666;

}

.cancelButton {

background-color: rgb(153, 153, 153);

}

.cancelButton:hover {

background-color: #666;

}

.submitbutton:hover {

&nbsp;

&nbsp;

}

`}</style>

</div>

);

}

}
<pre>
Oracle AjaxCustom Service endpoint
function submitAnswerRating()
 {
 $answerID = $this-&amp;gt;input-&amp;gt;get('a_id');
 $rating = $this-&amp;gt;input-&amp;gt;get('rate');
 $scale = $this-&amp;gt;input-&amp;gt;get('options_count');
 if($answerID){
 if($this-&amp;gt;model('Answer')-&amp;gt;rate($answerID, $rating, $scale)){
 print "submitAnswerRating({'submitted':'true'})";
 }else{
 print "submitAnswerRating({'submitted':'false'})";
 }
 }
 }
 
 function getNewFormToken()
 {
 if($formToken = $this-&amp;gt;input-&amp;gt;get('formToken'))
 {
 $newToken = Framework::createTokenWithExpiration(0, false);
 print "getNewFormToken({'newToken':'" . $newToken . "'})";
 }
 }
 
 function submitAnswerFeedback()
 {
 AbuseDetection::check();
 $answerID = $this-&gt;input-&gt;get('a_id');
 if($answerID === 'null')
 $answerID = null;
 $rate = $this-&gt;input-&gt;get('rate');
 $message = $this-&gt;input-&gt;get('message');
 $givenEmail = '...@....com';
 $threshold = 3;
 $optionsCount = 5;
 $formToken = $this-&gt;input-&gt;get('f_tok');
 $incidentResult = $this-&gt;model('Incident')-&gt;submitFeedback($answerID, $rate, $threshold, null, $message, $givenEmail, $optionsCount);
 if($incidentResult-&gt;result){
 print "submitAnswerFeedback({'ID':'" . $incidentResult-&gt;result-&gt;ID . "'})";
 //$this-&gt;_renderJSON(array('ID' =&gt; $incidentResult-&gt;result-&gt;ID));
 }else{
 if($incidentResult-&gt;error){
 print "submitAnswerFeedback({'error 2':'" . $incidentResult-&gt;error-&gt;externalMessage . "'})";
 }
 }

Oracle Service Cloud RightNowCX External Events / Custom Process: Curl a service on Save or Update

Thursday, February 16th, 2017
/*
* CPMObjectEventHandler: updateContact
* Package: OracleServiceCloud
* Objects: Contact
* Actions: Create, Update
* Version: 1.3
*/

use \RightNow\CPM\v1 as RNCPM;
use \RightNow\Connect\v1_3 as RNCPHP;

load_curl();

class updateContact implements RNCPM\ObjectEventHandler {

/**
* Apply CPM logic to object.
* @param int $runMode
* @param int $action
* @param object $contact
* @param int $cycle
*/
public static function apply($run_mode, $action, $contact, $n_cycles) {

if ($n_cycles != 0) return;

try {

$contact->CustomFields->c->contact_field_being_checked = new RNCPHP\NamedIDLabel();
$contact->CustomFields->c->contact_field_being_checked->ID = 2192; // Unregistered CPM
$header[] = "Content-Type: application/x-www-form-urlencoded";
$service_endpoint = 'http://INTERFACE-URL/cgi-bin/nikeagent.cfg/php/custom/scriptName.php?email=';

$noEmail = true;

foreach ($contact->Emails as $email) {
if ($email) {
$noEmail = false; // found an email

$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $service_endpoint . $email->Address,
CURLOPT_HEADER => 0,
CURLOPT_HTTPHEADER => $header,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_SSL_VERIFYHOST => 0
));
$resp = curl_exec($ch);

if ($resp !== false) {
$respObj = json_decode($resp, true);
$regUserString = $respObj['contact_field_being_checked']; // 1 or empty, is boolean
if ($regUserString == 1) {
$contact->CustomFields->c->contact_field_being_checked->ID = 2189; // Registered CPM
}else{
}
}
curl_close($ch);
}
}

$contact->save(RNCPHP\RNObject::SuppressAll);
} catch (\Exception $e) {
throw $e;
}

return;
}
}

class updateContact_TestHarness implements RNCPM\ObjectEventHandler_TestHarness {
static $test_contact = null;

public static function setup() {
// TODO: Pass array of contacts
// Should pass an array of contacts with different
// emails and different orders of registered emails

// We want to create contacts on the fly, but
// you can't duplicate emails, so we should probably check
// if the email exists, and delete it - perhaps have a set test
// contact
try {
$contact = new RNCPHP\Contact;
$contact->Emails = new RNCPHP\EmailArray();
$contact->Emails[0] = new RNCPHP\Email();
$contact->Emails[0]->AddressType = new RNCPHP\NamedIDOptList();
$contact->Emails[0]->AddressType->LookupName = "Email - Primary";
$contact->Emails[0]->Address = "somebody@fastmail.jp";
$contact->Emails[0]->Invalid = false;
$contact->CRMModules = new RNCPHP\CRMModules();
$contact->CRMModules->Service = 1;
$contact->save(RNCPHP\RNObject::SuppressAll);

static::$test_contact = $contact;
} catch (\Exception $e) {
echo $e->getMessage();
}

return;
}

public static function fetchObject($action, $object_type) {
// Returned object is passed to apply()
return (static::$test_contact);
}

public static function validate($action, $object) {
if (RNCPM\ActionCreate == $action) {
if (assert($object->CustomFields->c->contact_field_being_checked->ID == 2189)) {
echo "Create test passed - " . $object->Emails[0]->Address . "\n";
return true;
} else {
echo "Create test FAILED - " . $object->Emails[0]->Address . "\n";
}
} elseif (RNCPM\ActionUpdate == $action) {
if (assert($object->CustomFields->c->contact_field_being_checked->ID == 2189)) {
echo "Update test passed - " . $object->Emails[0]->Address . "\n";
return true;
} else {
echo "Update test FAILED - " . $object->Emails[0]->Address . "\n";
}
} else {
echo "Invalid action";
}
}

public static function cleanup() {
// Delete temporary test contact
$contact = static::$test_contact;
$contact->destroy();

static::$test_contact = null;
}
}

Oracle Service Cloud RightNowCX Event subscribe Notes

Tuesday, August 30th, 2016

RightNow.Event.subscribe("evt_chatCobrowseAcceptResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatCobrowseStatusResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_fileUploadUpdateResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatNotifyFattachUpdateResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatPostResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatEngagementParticipantAddedResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatEngagementParticipantRemovedResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatEngagementConcludedResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatCobrowseInvitationResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatReconnectUpdateResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatAgentAbsentUpdateResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatAgentStatusChangeResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatPostCompletion",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatEventBusInitializedResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatConnectResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatFetchUpdateResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatStateChangeResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatSetParametersResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatValidateParametersResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatCheckAnonymousResponse",function(e, f){console.log(e,f);},null);

example:

RightNow.Event.subscribe("evt_chatStateChangeResponse",function(e,f){
if(f[0].data.currentState && f[0].data.currentState == 2) {
window.chatID = RightNow.Chat.Controller.ChatCommunicationsController._engagementID;
}
},null);

Oracle Service Cloud RightNowCX Configuration for Developer Chatting with Self

Tuesday, August 30th, 2016

-> Chat starts

-> Triggers Rules evaluation

-> Rule matches regex on email submitted

-> Routes the chat to a particular queue

-> Queue is assigned to a profile

-> Profile is assigned to dev

Now you can submit a chat request via the page/UI, and receive it via the console, or let it sit to develop “waiting”/unconnected experience!

Oracle Service Cloud RightnowCX Custom Controller: Lookup Contact, Create Incident

Tuesday, August 30th, 2016

<?php

namespace Custom\Controllers;

/************* Agent Authentication ***************/
require_once( get_cfg_var("doc_root")."/ConnectPHP/Connect_init.php" );
initConnectAPI();

use RightNow\Connect\v1_2 as RNCPHP;

class GSChatIncident extends \RightNow\Controllers\Base
{

function __construct()
{
parent::__construct();
}

public function createContactIncident() {

try{
\RightNow\Libraries\AbuseDetection::check();

//$incident->SiteInterface = new RNCPHP\NamedIDLabel();
//$incident->SiteInterface->ID = 111;

$email = $_POST['email'];
$cID = (int)$_POST['countryID'];
$languageID = (int)$_POST['langID'];

$CI = &get_instance();
$contactmodelobj=$CI->load->model('standard/Contact_model');

$found = $this->Contact_model->lookupContactByEmail($email, null, null)->result;

if($found != null && is_int($found) && $found != false){
$creatingContact = $found;
} else {
$creatingContact = 1;
}

$incident = new RNCPHP\Incident();
$incident->Subject = "Chat cancelled";
$incident->CustomFields->c->system_source->ID = 2156;
$incident->CustomFields->c->country = new RNCPHP\NamedIDLabel();
$incident->CustomFields->c->country = $cID;
$incident->Language = $languageID;
$incident->PrimaryContact = RNCPHP\Contact::fetch($creatingContact); //Required field to create an incident through connect PHP
$incident->save(RNCPHP\RNObject::SuppressAll);
}

catch (Exception $err ){
echo $err->getMessage();
}
}
}
?>

Oracle Service Cloud RightNow CX PHP Connect API write to Custom Business Object example Custom Controller

Tuesday, August 30th, 2016

url: /cc/GSChatLog/createChatLog


<?php

namespace Custom\Controllers;

/************* Agent Authentication ***************/
require_once( get_cfg_var("doc_root")."/ConnectPHP/Connect_init.php" );
initConnectAPI();
use RightNow\Connect\v1_2 as RNCPHP;

class GSChatLog extends \RightNow\Controllers\Base
{

function __construct()
{
parent::__construct();
}

public function createChatLog() {

try{
\RightNow\Libraries\AbuseDetection::check();

$email = $_POST['email'];
$cID = (int)$_POST['countryID'];
$languageID = (int)$_POST['langID'];
$name = $_POST['name'];
$referrerUrl = $_POST['referrerUrl'];
$siteID = $_POST["siteID"];
$platformID = $_POST["platformID"];
$chatStatus = $_POST["chatStatus"];
$chatID = $_POST["chatID"];
$lob = strtoupper($_POST["lob"]);

$log = new RNCPHP\ContactUs\chat_log();
$log->chat_id = $chatID;
$log->chat_log_status = $chatStatus;
$log->site_id = $siteID;
$log->chat_group = 2156;
$log->referring_url = $referrerUrl;
$log->interface = $platformID;
$log->email_address = $email;
$log->name = $name;
$log->language_id = $languageID;
$log->country_id = $cID;
$log->lob_id = $lob;
$log->save();

catch (Exception $err ){
echo $err->getMessage();
}
}
}
?>

Oracle Service Cloud RightNow CX PHP Connect API Analytics Report example

Tuesday, August 30th, 2016

$report_id = ..74..;
$report = RNCPHP\AnalyticsReport::fetch($report_id);

$report_filter = new RNCPHP\AnalyticsReportSearchFilter;
$report_filter->Name = 'chats.email';
$report_filter->Values = array($email);
$filters = new RNCPHP\AnalyticsReportSearchFilterArray;
$filters[] = $report_filter;

$report_result = $report->run(0,$filters);

while($reportRow = $report_result->next())
{
print_r($reportRow);
$chatID = (int)$reportRow['chat_id'];
}

Oracle Service Cloud (RNT/RNW) promote straight to Production shortcut

Thursday, August 18th, 2016

/ci/admin/deploy/stageandpromote

also straight to a tier environment:

ci/admin/overview/set_cookie/development

optional:

ci/admin/overview/set_cookie/development/mobile (etc)

Eureka Call Library Oracle RightNow get article count per category

Saturday, July 25th, 2015
/**
* Description: Get all categories, display in a list with number of articles in each, alphabetical listing of category level 3
* Date: March 2013
* Classes: GetAllCategories, Generator, Category, CategoryDepot
* Brief Technical:
* Page calls CallLibraryCatList widget
* widget view instantiates GetAllCategories Class, which uses Prodcat model to retrieve categories object
* GetAllCategories Class in turn activates Generator Class
* Generator Class utilizes Category & Category Depot Classes, converting the categories object into instantiated individual category objects that can leverage each other, and then be displayed
*/
class GetAllCategories{
	public $CI;
	public $catListObject;
	public $currentTier = -1;
	public $tier3 = array();
	public $lastLevel = -1;
	public $newLevel = -1;
	public $categoryDepot;

	function __construct() {
		$this->CI =& get_instance();
		$this->CI->load->model('standard/Prodcat_model');
		$this->catListObject = $this->CI->Prodcat_model->getHierPopup(14);
		$this->categoryDepot = new Generator;
		$this->iterateConvert();
	}

	// loops through the returned categories, and uses Generator Class to organize as Category Objects
	function iterateConvert() {
		for( $i=0; $i < count($this->catListObject); $i++ ) {
			if($this->catListObject[$i]['hier_list'] == 588)
			{
				$this->newLevel = $this->catListObject[$i]['level'];

				if ( $this->newLevel < 3 && $this->lastLevel == 3 ) {
					// sort tier 3 alphabetically, then add to collection
					foreach ($this->tier3 as $key => $row) {
						$title[$key] = $row[0];
						$href[$key] = $row['href_list'];
						$level[$key] = $row['level'];
					}
					array_multisort($title, SORT_ASC, $href, SORT_ASC, $level, SORT_ASC, $this->tier3);
					foreach($this->tier3 as $key => $catObject) {
						// create and add tiers 1 & 2 to collection
						$this->categoryDepot->generateCategory($catObject);
					}
					unset($this->tier3);
				}
				if($this->newLevel != 3) {
					// create and add tiers 1 & 2 to collection
					$this->categoryDepot->generateCategory($this->catListObject[$i]);
				}
				if($this->newLevel == 3) {
					// collect tier 3 items
					$this->tier3[] = $this->catListObject[$i];
				}

				$this->lastLevel = $this->newLevel;
				}
			}

			$this->categoryDepot->renderCollection();
		}
	}

class Generator{
	public $categoryDepot;
	public $CI;

	function __construct() {
		$this->categoryDepot = new CategoryDepot;
		$this->CI =& get_instance();
		$this->CI->load->model('custom/AnswersInCategoriesCounter_model');
	}

	function generateCategory($catSent) {
		$category = new Category;
		$category->setTier($catSent['level']);
		$category->setTitle($catSent[0]);
		$categoryArray = $category->setCategories($catSent['hier_list']);
		$finalCategory = $category->getFinalCategory();
		$articleCount = $this->CI->AnswersInCategoriesCounter_model->getCountOfAnswersByCat($finalCategory);
		if($finalCategory != 588 || 0 || null) {
			$this->categoryDepot->addToCollection($category);
		}
		foreach($categoryArray as $key => $categoryId) {
			$this->categoryDepot->updateCategoryArticleCounts($categoryId, $articleCount);
		}
	}	

	function renderCollection() {
		return $this->categoryDepot->getCollection();
	}
}

/**
* $catListObject[$i]['level'] / 0-3
* $catListObject[$i]['hier_list'] / Categories
* $catListObject[$i][0]
*/
class Category {
	public $tier;
	public $categoriesList;
	public $categoryArray;
	public $finalCategory;
	public $title;
	public $parentCategory;
	public $articleCount;
	public $articleTotal;

	function __construct() {
		//echo "Category instantiated";
	}

	function setTier($input) {
		$this->tier = $input;
	}
	
	function setCategories($input) {
		$this->categoriesList = $input;
		$this->setCategoryArray();
		$this->setParentCategory();
		$this->setFinalCategory();
		return $this->categoryArray;
	}

	function setCategoryArray() {
		$this->categoryArray = explode(',',$this->categoriesList);
	}

	function setParentCategory() {
		$itemLevel = $this->tier - 1;
		$this->parentCategory = $this->categoryArray[$itemLevel];
	}

	function setFinalCategory() {
		$this->finalCategory = $this->categoryArray[$this->tier];
	}

	function setTitle($input) {
		$this->title = $input;
	}

	function setArticleCount($input) {
		$newSet = array_unique(array_merge((array)$this->articleCount,(array)$input));
		$this->articleCount = $newSet;
		$this->setArticleTotal();
	}

	function getFinalCategory() { return $this->finalCategory; }
	
	function setArticleTotal() {
		$this->articleTotal = count($this->articleCount);
		return $this->articleTotal;
	}
}

// archives Category Objects, updates each Class's article count, and returns/displays the Collection
class CategoryDepot {
	public $collection;
	public $baseURL = '/app/list_call_library_no_search/r_id/108720/p/646/c/';
	public $currentTier = -1;

	function __construct() {
	}

	function addToCollection($input) {
		$this->collection[] = $input;
	}

	function getCollection() {
		foreach($this->collection as $category) {
			// if articleCount is 0, don't even show count
			if($category->articleTotal != 0){ $articleCount = " (" . $category->articleTotal . ")"; }else{ $articleCount = ''; }

			if($category->tier > $currentTier) {
				$currentTier = $category->tier;
				echo "<ul><li><a href='" . $this->baseURL . $category->categoriesList . "' class='noIntercept'>" . $category->title . $articleCount . "</a>";
			} elseif( $category->tier == $currentTier ) {
				echo "</li><li class='level_" . $category->tier . "'><a href='" . $this->baseURL . $category->categoriesList . "'>" . $category->title . $articleCount . "</a>";
			} elseif($category->tier < $currentTier) {
				$numberToClose = ($currentTier - $category->tier);
				$currentTier = $tier;
				switch ( $numberToClose ) {
					case 1:
						echo "</li></ul></li></ul><ul><li><a href='" . $this->baseURL . $categoriesList . "' class='noIntercept'>" . $category->title . $articleCount . "</a>";
					break;
					case 2:
						echo "</li></ul></li></ul></li></ul><ul><li><a href='" . $this->baseURL . $categoriesList . "' class='noIntercept'>" . $category->title . $articleCount . "</a>";
					break;
				}
			}
		}
	}

	// accepts a finalCategory int and the amount to increment that object's article count
	function updateCategoryArticleCounts($categoryId, $articleCount) {
		foreach ( $this->collection as $category ) {
			if ( $categoryId == $category->finalCategory ) {
				$category->setArticleCount($articleCount);
				break;
			}
		}
	}
}

Oracle RightNow getNamedValues, get all possible values for answer Object attributes, re-making the console

Thursday, May 16th, 2013

$fields = array(“AccessLevels”, “AnswerType”,”Language”, “StatusWithType.Status”, “Categories”, “Products”);
foreach($fields as $key => $field){
$temp = array();
$$field = array();
$parameter = RNCPHP\ConnectAPI::getNamedValues(“RightNow\\Connect\\v1_2\\Answer”, $field);
foreach($parameter as $key => $value){
$temp[$value->ID] = $value->LookupName;
}
$$field = $temp;
if($field == ‘StatusWithType.Status’){ $StatusWithType = $temp; }
}
// Prove it
foreach($StatusWithType as $key => $value){ echo $key . “, ” . $value . “<br />”; }

// Now fill in the answer creation/edit form values with these values

Oracle RightNow CX updating Intake Page Form Custom Fields

Tuesday, November 27th, 2012

This may or may not draw searches, and once found it’s stupid obvious, but with anything RightNow Technologies Console CX, finding it can often be the WHOLE battle… so I’m noting it for me.

In the console, under Home, or any other main level menu, click “Customize List” and search for ‘Custom’, add ‘Custom Fields’, and voila. Ug.

Oracle RightNow Technologies display attachments in your view, use FileListDisplay & answers.fattach

Tuesday, October 9th, 2012

if you are using:
/development/views/answers/detail.php 

then you’re probably displaying the answer content with these tags:
<rn:field name=”answers.summary” highlight=”true”/>
<rn:field name=”answers.solution” highlight=”true”/>

which means that if you use a workspace that allows content teams to upload attachments, the attachments still won’t be visible on your site, until you add this to the detail.php view:
<rn:widget path=”output/FileListDisplay” name=”answers.fattach”/>

Then style things here:
assets/themes/standard/widgetCSS/FileListDisplay.css