<?xml version="1.0" encoding="UTF-8"?>
<unload unload_date="2018-09-07 20:22:44">
<sys_script_include action="INSERT_OR_UPDATE">
<access>public</access>
<active>true</active>
<api_name>global.JournalRedactor</api_name>
<client_callable>false</client_callable>
<description>Documentation and description at http://redactor.snc.guru/</description>
<name>JournalRedactor</name>
<script><![CDATA[var JournalRedactor = Class.create();
JournalRedactor.prototype = {
	
	
	initialize: function(journalEntryID) {
		this.journalEntryData = new this._JournalEntry();
		if (journalEntryID) {
			this.journalEntryData.journal_entry_id = journalEntryID;
			this._populateJournalEntryData(journalEntryID);
		}
		this._verbose = false;
	},
	
	redact: function(deleteEntry, newValue) {
		if (!this._readyForRedaction(this.journalEntryData)) {
			gs.logError('Not ready for redaction. Some data is missing from journalEntryData: ' +
				JSON.stringify(this.journalEntryData),
				'redact method of JournalRedactor Script Include');
			return false;
		}
		if (!deleteEntry && !newValue) {
			//If deleteEntry is not true, but no new value is specified, log an error
			gs.logError('deleteEntry is not true, but newValue is not specified. Cannot ' +
				'continue.', 'redact method of JournalRedactor Script Include');
			return false;
		} else if (!this.journalEntryData.journal_entry_id) {
			gs.logError('Journal entry ID not known. Please call setJournalID() or ' +
				'findJournalID() methods to set or find the journal ID before attempting ' +
				'to redact.', 'redact method of JournalRedactor Script Include');
			return false;
		}
		if (newValue) {
			this.journalEntryData.new_journal_value = newValue;
		}
		
		var success = this._redactJournalEntry(this.journalEntryData, deleteEntry, newValue) &&
			this._redactAudit(this.journalEntryData, deleteEntry, newValue) &&
			this._deleteHistory(this.journalEntryData);
		
		return success;
	},
	
	setJournalID: function(journalEntryID) {
		if (!journalEntryID) {
			gs.logWarning('setJournalID method of JournalRedactor Script Include called, ' +
				'but no journal entry sys_id was specified. Clearing journal entry ID value.',
				'JournalRedactor Script Include setJournalID method');
			this.journalEntryData.journal_entry_id = '';
			return false;
		} else {
			this.journalEntryData.journal_entry_id = journalEntryID;
		}
		this._populateJournalEntryData(journalEntryID); //Need this data in the data object for future redaction steps.
		return this.journalEntryData;
	},
	
	/**
	 * Use this method if you don't already know the sys_id of the sys_journal_field
	 * 	record corresponding to the journal entry you'd like to redact or delete.
	 * 	This will grab all the necessary data
	 * This method accepts two, three, or four arguments
	 * @param recordID {String}
	 * @param journalText {String}
	 * @param targetTableName {String=}
	 * @param journalFieldName {String=}
	 * @returns {Boolean} True if the journal entry was successfully located, or false if it was not.
	 */
	findJournalID: function(recordID, journalText, targetTableName, journalFieldName) {
		var journalEntryID;
		
		if (this._verbose) {
			gs.log('Attempting to find record in sys_journal_field table, with ' +
				arguments.length + ' arguments: ' + JSON.stringify(arguments));
		}
		
		/*//Set variables based on number of arguments specified
		if (arguments.length == 2) {
			recordID = arguments[0];
			journalText = arguments[1];
		} else if (arguments.length == 3) {
			recordID = arguments[0];
			targetTableName = arguments[1];
			journalText = arguments[2];
		} else if (arguments.length = 4) {
			recordID = arguments[0];
			targetTableName = arguments[1];
			journalFieldName = arguments[2];
			journalText = arguments[3];
		}*/
		if (arguments.length < 2 || arguments.length > 4) { //ERROR!
			gs.logError('Incorrect number of arguments specified. ' + arguments.length +
				' arguments specified, but 2, 3, or 4 arguments are expected.',
				'getJournalID method of JournalRedactor Script Include');
			return false;
		}
		
		/*if (!recordID || !journalText) {
			gs.logError('getJournalID method of JournalRedactor Script Include could not ' +
				'continue. Invalid argument(s) specified. recordID: ' + recordID + '. ' +
				'journalText: ' + journalText + '.');
			return this.journalEntryData;
		}*/ //replaced by handling for different numbers of arguments above
		
		//Update details in journalEntryData
		this.journalEntryData.target_record_id = recordID;
		this.journalEntryData.old_journal_value = journalText;
		
		var grJournal = new GlideRecord('sys_journal_field');
		grJournal.addQuery('element_id', recordID);
		grJournal.addQuery('value', journalText);
		if (targetTableName) {
			grJournal.addQuery('name', targetTableName);
		}
		if (journalFieldName) {
			grJournal.addQuery('element', journalFieldName);
		}
		grJournal.query();
		
		if (grJournal.next()) {
			journalEntryID = grJournal.getValue('sys_id');
			journalFieldName = grJournal.getValue('element');
			targetTableName = grJournal.getValue('name');
			
			this.journalEntryData.journal_entry_id = journalEntryID;
			this.journalEntryData.journal_field_name = journalFieldName;
			this.journalEntryData.target_table_name = targetTableName;
		} else {
			return false;
		}
		if (grJournal.hasNext() && this._verbose) {
			gs.log('findJournalID() method of JournalRedactor Script Include: ' +
				'Additional journal entry was found, matching these arguments: ' +
				JSON.stringify(arguments) + '. You may want to run this script again.');
		}
		
		return journalEntryID;
	},
	
	setVerbose: function(b) {
		this._verbose = b;
	},
	
	/******PRIVATE METHODS BELOW******/
	
	_readyForRedaction: function(journalEntryData) {
		var p;
		journalEntryData = journalEntryData ? journalEntryData : this.journalEntryData;
		
		if (this._verbose) {
			gs.log('Checking if journalEntryData is ready for redaction: ' +
				JSON.stringify(journalEntryData));
			
		}
		
		for (p in journalEntryData) {
			if (journalEntryData.hasOwnProperty(p)) {
				if (p != 'old_journal_value' && !journalEntryData[p]) {
					if (this._verbose) {
						gs.log('journalEntryData not ready for redaction: ' +
							JSON.stringify(journalEntryData));
					}
					return false;
				}
			}
		}
		if (this._verbose) {
			gs.log('journalEntryData IS ready for redaction: ' +
				JSON.stringify(journalEntryData));
		}
		return true;
	},
	
	_redactJournalEntry: function(journalEntryData, deleteEntry, newValue) {
		journalEntryData = journalEntryData ? journalEntryData : this.journalEntryData;
		
		if (this._verbose) {
			gs.log('Beginning redaction of sys_journal_field record: ' +
				JSON.stringify(journalEntryData));
		}
		
		if (!deleteEntry && !newValue) {
			//If deleteEntry is not true, but no new value is specified, log an error
			gs.logError('deleteEntry is not true, but newValue is not specified. Cannot ' +
				'continue.', '_redactJournalEntry method of JournalRedactor Script Include');
			return false;
		} else if (!journalEntryData.journal_entry_id) {
			gs.logError('Journal entry ID not known. Please call setJournalID() or ' +
				'findJournalID() methods to set or find the journal ID before attempting ' +
				'to redact.', '_redactJournalEntry method of JournalRedactor Script Include');
			return false;
		}
		
		var grJournal = new GlideRecord('sys_journal_field');
		grJournal.get(journalEntryData.journal_entry_id);
		if (deleteEntry) {
			grJournal.deleteRecord();
			if (this._verbose) {
				gs.log('Deleted journal entry with ID ' + journalEntryData.journal_entry_id);
			}
		} else {
			grJournal.setValue('value', newValue);
			grJournal.update();
			if (this._verbose) {
				gs.log('Updated journal entry with ID ' + journalEntryData.journal_entry_id +
					' to new value: ' + newValue);
			}
		}
		if (this._verbose) {
			gs.log('redaction complete: ' +
				JSON.stringify(journalEntryData));
		}
		return true;
	},
	
	
	_redactAudit: function(journalEntryData, deleteEntry, newValue) {
		journalEntryData = journalEntryData ? journalEntryData : this.journalEntryData;
		if (this._verbose) {
			gs.log('Beginning redaction of sys_audit record: ' +
				JSON.stringify(journalEntryData));
		}
		if (!deleteEntry && !newValue) {
			//If deleteEntry is not true, but no new value is specified, log an error
			gs.logError('deleteEntry is not true, but newValue is not specified. Cannot ' +
				'continue.', '_redactAudit method of JournalRedactor Script Include');
			return false;
		} else if (!journalEntryData.journal_entry_id) {
			gs.logError('Journal entry ID not known. Please call setJournalID() or ' +
				'findJournalID() methods to set or find the journal ID before attempting ' +
				'to redact.', '_redactAudit method of JournalRedactor Script Include');
			return false;
		}
		
		var grAudit = new GlideRecord('sys_audit');
		
		grAudit.addQuery('tablename', journalEntryData.target_table_name);
		grAudit.addQuery('documentkey', journalEntryData.target_record_id);
		grAudit.addQuery('newvalue', journalEntryData.old_journal_value);
		//field names are not misspelled, they're just weird in this table.
		grAudit.query();
		
		while (grAudit.next()) {
			if (deleteEntry) {
				if (this._verbose) {
					gs.log('Deleting audit record because deleteEntry param is set to ' +
						deleteEntry);
				}
				grAudit.deleteRecord();
			} else {
				if (this._verbose) {
					gs.log('Updating audit record because deleteEntry param is set to ' +
						deleteEntry + ' and newValue is set to ' + newValue);
				}
				grAudit.setValue('newvalue', newValue);
				grAudit.update();
			}
		}
		if (this._verbose) {
			gs.log('_redactAudit() finished');
		}
		return true;
	},
	
	_deleteHistory: function(journalEntryData) {
		journalEntryData = journalEntryData ? journalEntryData : this.journalEntryData;
		if (this._verbose) {
			gs.log('_deleteHistory() running with journalEntryData: ' +
				JSON.stringify(journalEntryData));
		}
		if (!journalEntryData.target_record_id || !journalEntryData.target_table_name) {
			gs.logError(
				'Journal entry ID or target table name not known. Please call setJournalID() or ' +
				'findJournalID() methods to set or find the journal ID before attempting ' +
				'to redact.', '_deleteHistory method of JournalRedactor Script Include');
			return false;
		}
		
		var grHistorySet = new GlideRecord('sys_history_set');
		
		grHistorySet.addQuery('id', journalEntryData.target_record_id);
		grHistorySet.addQuery('table', journalEntryData.target_table_name);
		grHistorySet.deleteMultiple();
		
		if (this._verbose) {
			gs.log('_deleteHistory() finished with journalEntryData: ' +
				JSON.stringify(journalEntryData));
		}
		return true;
	},
	
	_populateJournalEntryData: function(journalEntryID) {
		if (this._verbose) {
			gs.log('_populateJournalEntryData() running with journalEntryID: ' + journalEntryID);
		}
		var grJournal = new GlideRecord('sys_journal_field');
		if (grJournal.get(journalEntryID)) {
			this.journalEntryData.target_record_id = grJournal.getValue('element_id');
			this.journalEntryData.target_table_name = grJournal.getValue('name');
			this.journalEntryData.old_journal_value = grJournal.getValue('value');
			this.journalEntryData.journal_field_name = grJournal.getValue('element');
			grJournal.update();
			
			if (this._verbose) {
				gs.log('_populateJournalEntryData() finished with journalEntryData: ' +
					JSON.stringify(this.journalEntryData));
			}
			return grJournal;
		} else {
			gs.logError('sys_journal_field record with sys_id ' + journalEntryID + ' not found.',
				'_populateJournalEntryData method of JournalRedactor Script Include');
		}
	},
	
	_JournalEntry: function() {
		this.journal_entry_id = '';
		this.target_record_id = '';
		this.target_table_name = '';
		this.old_journal_value = '';
		this.journal_field_name = '';
		this.new_journal_value = '';
	},
	
	type: 'JournalRedactor'
};]]></script>
<sys_class_name>sys_script_include</sys_class_name>
<sys_created_by>admin</sys_created_by>
<sys_created_on>2018-09-07 17:44:58</sys_created_on>
<sys_id>785ec25b3710230090b68cf6c3990e9c</sys_id>
<sys_mod_count>7</sys_mod_count>
<sys_name>JournalRedactor</sys_name>
<sys_package display_value="Global" source="global">global</sys_package>
<sys_policy/>
<sys_scope display_value="Global">global</sys_scope>
<sys_update_name>sys_script_include_785ec25b3710230090b68cf6c3990e9c</sys_update_name>
<sys_updated_by>admin</sys_updated_by>
<sys_updated_on>2018-09-07 20:22:30</sys_updated_on>
</sys_script_include>
</unload>
