save_resource_data()
Description
Save resource dataIMPORTANT: inactive nodes should be left alone (don't add/remove) except when processing fixed list field types that
only hold one value (dropdown, radio). Plugins should determine this based on their use cases when hooking.
Parameters
Column | Type | Default | Description |
---|---|---|---|
$ref | int | ||
$multi | bool | ||
$autosave_field | string|int | "" |
Return
true|array | List of errors if unsuccessful, true otherwise |
Location
include/resource_functions.php lines 685 to 1410
Definition
function save_resource_data($ref,$multi,$autosave_field="")
{
debug_function_call("save_resource_data", func_get_args());
# Save all submitted data for resource $ref.
# Also re-index all keywords from indexable fields.
global $lang, $languages, $language, $FIXED_LIST_FIELD_TYPES,
$DATE_FIELD_TYPES, $reset_date_field, $reset_date_upload_template,
$edit_contributed_by, $new_checksums, $upload_review_mode, $blank_edit_template, $is_template, $NODE_FIELDS,
$userref, $userresourcedefaults;
hook("befsaveresourcedata", "", array($ref));
// Ability to avoid editing conflicts by checking checksums.
// NOTE: this should NOT apply to upload.
$check_edit_checksums = true;
// Save resource defaults (functionality available for upload only)
// Call it here so that if users have access to the field and want
// to override it, they can do so
if(0 > $ref)
{
set_resource_defaults($ref);
$check_edit_checksums = false;
}
# Loop through the field data and save (if necessary)
$errors=array();
$fields=get_resource_field_data($ref,$multi, !hook("customgetresourceperms"));
$expiry_field_edited=false;
$resource_data=get_resource_data($ref);
if($resource_data["lock_user"] > 0 && $resource_data["lock_user"] != $userref)
{
$errors[] = get_resource_lock_message($resource_data["lock_user"]);
return $errors;
}
# Load the configuration for the selected resource type. Allows for alternative notification addresses, etc.
resource_type_config_override($resource_data["resource_type"]);
# Set up arrays of node ids to add/remove. We can't remove all nodes as user may not have access
$nodes_to_add = [];
$nodes_to_remove = [];
$oldnodenames = [];
$nodes_check_delete = [];
$resource_update_log_sql = [];
$ui_selected_node_values = [];
$all_current_field_nodes = [];
$new_node_values = [];
$updated_resources = [];
$node_not_active = fn(array $node): bool => !node_is_active($node);
// All the nodes passed for editing. Some of them were already a value
// of the fields while others have been added/removed
$user_set_values = getval('nodes', [], false, 'is_array');
// Initialise array to store new checksums that client needs after autosave, without which subsequent edits will fail
$new_checksums = array();
for ($n=0;$n<count($fields);$n++)
{
if(!(
checkperm('F' . $fields[$n]['ref'])
|| (checkperm("F*") && !checkperm('F-' . $fields[$n]['ref']))
// If we hide on upload the field, there is no need to check values passed from the UI as there shouldn't be any
|| ((0 > $ref || $upload_review_mode) && $fields[$n]['hide_when_uploading'])
)
&& ('' == $autosave_field || $autosave_field == $fields[$n]['ref']
|| (is_array($autosave_field) && in_array($fields[$n]['ref'], $autosave_field))
)
)
{
// Fixed list fields use node IDs directly
if(in_array($fields[$n]['type'], $FIXED_LIST_FIELD_TYPES))
{
debug("save_resource_data(): Checking nodes to add/ remove for field {$fields[$n]['ref']} - {$fields[$n]['title']}");
// Get currently selected nodes for this field
$current_field_nodes = get_resource_nodes($ref, $fields[$n]['ref']);
$all_current_field_nodes = array_merge($all_current_field_nodes,$current_field_nodes);
// Check if resource field data has been changed between form being loaded and submitted
$post_cs = getval("field_" . $fields[$n]['ref'] . "_checksum","");
sort($current_field_nodes);
$current_cs = md5(implode(",",$current_field_nodes));
if($check_edit_checksums && $post_cs != "" && $post_cs != $current_cs)
{
$errors[$fields[$n]["ref"]] = i18n_get_translated($fields[$n]['title']) . ': ' . $lang["save-conflict-error"];
continue;
}
debug("save_resource_data(): Current nodes for resource " . $ref . ": " . implode(",",$current_field_nodes));
// Work out nodes submitted by user
if(isset($user_set_values[$fields[$n]['ref']])
&& !is_array($user_set_values[$fields[$n]['ref']])
&& '' != $user_set_values[$fields[$n]['ref']]
&& is_numeric($user_set_values[$fields[$n]['ref']]))
{
$ui_selected_node_values[] = $user_set_values[$fields[$n]['ref']];
}
elseif(isset($user_set_values[$fields[$n]['ref']])
&& is_array($user_set_values[$fields[$n]['ref']]))
{
$ui_selected_node_values = $user_set_values[$fields[$n]['ref']];
}
// Check nodes are valid for this field
if(FIELD_TYPE_CATEGORY_TREE === $fields[$n]['type'])
{
$all_tree_nodes_ordered = get_cattree_nodes_ordered($fields[$n]['ref'], null, true);
// remove the fake "root" node which get_cattree_nodes_ordered() is adding since we won't be using get_cattree_node_strings()
array_shift($all_tree_nodes_ordered);
$inactive_nodes = array_column(array_filter($all_tree_nodes_ordered, $node_not_active), 'ref');
$all_tree_nodes_ordered = array_values($all_tree_nodes_ordered);
$node_options = array_column($all_tree_nodes_ordered, 'name', 'ref');
$validnodes = array_keys($node_options);
}
else
{
$fieldnodes = get_nodes($fields[$n]['ref'], '', false);
$node_options = array_column($fieldnodes, 'name', 'ref');
$validnodes = array_column($fieldnodes, 'ref');
$inactive_nodes = array_column(array_filter($fieldnodes, $node_not_active), 'ref');
}
// $validnodes are already sorted by the order_by (default for get_nodes). This is needed for the data_joins fields later
$ui_selected_node_values = array_values(array_intersect($validnodes, $ui_selected_node_values));
debug("save_resource_data(): UI selected nodes for resource {$ref}: " . implode(',', $ui_selected_node_values));
// Set new value for logging
$new_node_values = array_merge($new_node_values, $ui_selected_node_values);
$added_nodes = array_diff($ui_selected_node_values, $current_field_nodes, $inactive_nodes);
debug("save_resource_data(): Adding nodes to resource " . $ref . ": " . implode(",",$added_nodes));
$nodes_to_add = array_merge($nodes_to_add, $added_nodes);
if (
// We must release an inactive node if the type can only hold one value...
in_array($fields[$n]['type'], [FIELD_TYPE_DROP_DOWN_LIST, FIELD_TYPE_RADIO_BUTTONS])
// ...but prevent direct removals (ie. no value)
&& $ui_selected_node_values !== []
) {
$removed_nodes = array_diff($current_field_nodes, $ui_selected_node_values);
$current_inactive_resource_field_nodes = [];
} else {
$removed_nodes = array_diff($current_field_nodes, $ui_selected_node_values, $inactive_nodes);
$current_inactive_resource_field_nodes = array_intersect($current_field_nodes, $inactive_nodes);
}
debug("save_resource_data(): Removed nodes from resource " . $ref . ": " . implode(",",$removed_nodes));
$nodes_to_remove = array_merge($nodes_to_remove, $removed_nodes);
if(count($added_nodes) > 0 || count($removed_nodes) > 0)
{
$new_nodevals = array();
// Build new value
foreach($ui_selected_node_values as $ui_selected_node_value)
{
if(FIELD_TYPE_CATEGORY_TREE === $fields[$n]['type'])
{
$new_nodevals[] = implode(
'/',
array_column(
compute_node_branch_path($all_tree_nodes_ordered, $ui_selected_node_value),
'name'
)
);
continue;
}
$new_nodevals[] = $node_options[$ui_selected_node_value];
}
# Is this is a 'joined' field?
$joins=get_resource_table_joins();
if (in_array($fields[$n]["ref"],$joins))
{
$new_nodes_val = implode($GLOBALS['field_column_string_separator'], $new_nodevals);
if ((1 == $fields[$n]['required'] && "" != $new_nodes_val) || 0 == $fields[$n]['required']) # If joined field is required we shouldn't be able to clear it.
{
update_resource_field_column($ref,$fields[$n]["ref"],$new_nodes_val);
}
}
$val = implode(",",$new_nodevals);
$ui_selected_node_values = array_merge($ui_selected_node_values, $current_inactive_resource_field_nodes);
sort($ui_selected_node_values);
$new_checksums[$fields[$n]['ref']] = md5(implode(',',$ui_selected_node_values));
$updated_resources[$ref][$fields[$n]['ref']] = $new_nodevals; // To pass to hook
}
else
{
$val = "";
}
} // End of if in $FIXED_LIST_FIELD_TYPES
else
{
if($fields[$n]['type']==FIELD_TYPE_DATE_RANGE)
{
# date range type
# each value will be a node so we end up with a pair of nodes to represent the start and end dates
$daterangenodes=array();
$newval="";
if(($date_edtf=getval("field_" . $fields[$n]["ref"] . "_edtf",""))!=="")
{
// We have been passed the range in EDTF format, check it is in the correct format
$rangeregex="/^(\d{4})(-\d{2})?(-\d{2})?\/(\d{4})(-\d{2})?(-\d{2})?/";
if(!preg_match($rangeregex,$date_edtf,$matches))
{
$errors[$fields[$n]["ref"]] = $lang["information-regexp_fail"] . " : " . $date_edtf;
continue;
}
if(is_int_loose($fields[$n]["linked_data_field"]))
{
// Update the linked field with the raw EDTF string submitted
update_field($ref,$fields[$n]["linked_data_field"],$date_edtf);
}
$rangedates = explode("/",$date_edtf);
$rangestart=str_pad($rangedates[0], 10, "-00");
$rangeendparts=explode("-",$rangedates[1]);
$rangeendyear=$rangeendparts[0];
$rangeendmonth=isset($rangeendparts[1])?$rangeendparts[1]:12;
$rangeendday=isset($rangeendparts[2])?$rangeendparts[2]:cal_days_in_month(CAL_GREGORIAN, $rangeendmonth, $rangeendyear);
$rangeend=$rangeendyear . "-" . $rangeendmonth . "-" . $rangeendday;
$newval = $rangestart . DATE_RANGE_SEPARATOR . $rangeend;
$daterangenodes[]=set_node(null, $fields[$n]["ref"], $rangestart, null, null);
$daterangenodes[]=set_node(null, $fields[$n]["ref"], $rangeend, null, null);
}
else
{
// Range has been passed via normal inputs, construct the value from the date/time dropdowns
$date_parts=array("_start","_end");
foreach($date_parts as $date_part)
{
$val = getval("field_" . $fields[$n]["ref"] . $date_part . "-y","");
if (intval($val)<=0)
{
$val="";
}
elseif (($field=getval("field_" . $fields[$n]["ref"] . $date_part . "-m",""))!="")
{
$val.="-" . $field;
if (($field=getval("field_" . $fields[$n]["ref"] . $date_part . "-d",""))!="")
{
$val.="-" . $field;
}
else
{
$val.="-00";
}
}
else
{
$val.="-00-00";
}
$newval.= ($newval != "" ? DATE_RANGE_SEPARATOR : "") . $val;
if($val!=="")
{
$daterangenodes[]=set_node(null, $fields[$n]["ref"], $val, null, null);
}
}
}
natsort($daterangenodes);
// Set new value for logging
$new_node_values = array_merge($new_node_values,$daterangenodes);
// Get currently selected nodes for this field
$current_field_nodes = get_resource_nodes($ref, $fields[$n]['ref'], false, SORT_ASC);
$all_current_field_nodes = array_merge($all_current_field_nodes,$current_field_nodes);
// Check if resource field data has been changed between form being loaded and submitted
$post_cs = getval("field_" . $fields[$n]['ref'] . "_checksum","");
sort($current_field_nodes);
$current_cs = md5(implode(",",$current_field_nodes));
if($check_edit_checksums && $post_cs != "" && $post_cs != $current_cs)
{
$errors[$fields[$n]["ref"]] = i18n_get_translated($fields[$n]['title']) . ': ' . $lang["save-conflict-error"];
continue;
}
if($daterangenodes !== $current_field_nodes)
{
$added_nodes = array_diff($daterangenodes, $current_field_nodes);
debug("save_resource_data(): Adding nodes to resource " . $ref . ": " . implode(",",$added_nodes));
$nodes_to_add = array_merge($nodes_to_add, $added_nodes);
$removed_nodes = array_diff($current_field_nodes,$daterangenodes);
debug("save_resource_data(): Removed nodes from resource " . $ref . ": " . implode(",",$removed_nodes));
$nodes_to_remove = array_merge($nodes_to_remove, $removed_nodes);
$val = $newval;
# If this is a 'joined' field it still needs to be added to the resource column
$joins=get_resource_table_joins();
if (in_array($fields[$n]["ref"],$joins))
{
update_resource_field_column($ref,$fields[$n]["ref"],$newval);
}
sort($daterangenodes);
$new_checksums[$fields[$n]['ref']] = md5(implode(",",$daterangenodes));
$updated_resources[$ref][$fields[$n]['ref']][] = $newval; // To pass to hook
}
}
elseif(in_array($fields[$n]['type'], $DATE_FIELD_TYPES))
{
# date type, construct the value from the date/time dropdowns to be used in DB
$val=sanitize_date_field_input($fields[$n]["ref"], false);
// A proper input:date field
if ($GLOBALS['use_native_input_for_date_field'] && $fields[$n]['type'] === FIELD_TYPE_DATE)
{
$val = getval("field_{$fields[$n]['ref']}", '');
if($val !== '' && !validateDatetime($val, 'Y-m-d'))
{
$errors[$fields[$n]['ref']] = $lang['error_invalid_date'] . ' : ' . $val;
continue;
}
}
// Upload template: always reset to today's date, if configured and field is hidden
if(0 > $ref
&& $reset_date_upload_template
&& $reset_date_field == $fields[$n]['ref']
&& $fields[$n]['hide_when_uploading']
)
{
$val = date('Y-m-d H:i');
}
// Check if resource field data has been changed between form being loaded and submitted
$post_cs = getval("field_" . $fields[$n]['ref'] . "_checksum","");
$current_cs = md5((string)$fields[$n]['value']);
if($check_edit_checksums && $post_cs != "" && $post_cs != $current_cs)
{
$errors[$fields[$n]["ref"]] = i18n_get_translated($fields[$n]['title']) . ': ' . $lang["save-conflict-error"];
continue;
}
$new_checksums[$fields[$n]['ref']] = md5($val);
$updated_resources[$ref][$fields[$n]['ref']][] = $val; // To pass to hook
}
else
{
# Set the value exactly as sent.
$val=getval("field_" . $fields[$n]["ref"],"");
$rawval = getval("field_" . $fields[$n]["ref"],"");
# Check if resource field data has been changed between form being loaded and submitted
# post_cs is the checksum of the data when it was loaded from the database
# current_cs is the checksum of the data on the database now
# if they are the same then there has been no intervening update and so its ok to update with our new value
# if our new data yields a different checksum, then we know the new value represents a change
# the new checksum for the new value of a field is stored in $new_checksums[$fields[$n]['ref']]
$post_cs = getval("field_" . $fields[$n]['ref'] . "_checksum","");
$current_cs = md5(trim(preg_replace('/\s\s+/', ' ', (string) $fields[$n]['value'])));
if($check_edit_checksums && $post_cs != "" && $post_cs != $current_cs)
{
$errors[$fields[$n]["ref"]] = i18n_get_translated($fields[$n]['title']) . ': ' . $lang["save-conflict-error"];
continue;
}
$new_checksums[$fields[$n]['ref']] = md5(trim(preg_replace('/\s\s+/', ' ', $rawval)));
$updated_resources[$ref][$fields[$n]['ref']][] = $val; // To pass to hook
}
# Check for regular expression match
if (strlen(trim((string)$fields[$n]["regexp_filter"]))>=1 && strlen((string) $val)>0)
{
global $regexp_slash_replace;
if(preg_match("#^" . str_replace($regexp_slash_replace, '\\',$fields[$n]["regexp_filter"]) . "$#",$val,$matches)<=0)
{
global $lang;
debug($lang["information-regexp_fail"] . ": -" . "reg exp: " . str_replace($regexp_slash_replace, '\\',$fields[$n]["regexp_filter"]) . ". Value passed: " . $val);
$errors[$fields[$n]["ref"]]=$lang["information-regexp_fail"] . " : " . $val;
continue;
}
}
$modified_val=hook("modifiedsavedfieldvalue",'',array($fields,$n,$val));
if(!empty($modified_val))
{
$val=$modified_val;
$new_checksums[$fields[$n]['ref']] = md5(trim(preg_replace('/\s\s+/', ' ', $val)));
}
$error = hook("additionalvalcheck", "all", array($fields, $fields[$n]));
if($error)
{
$errors[$fields[$n]["ref"]]=$error;
continue;
}
} // End of if not a fixed list field
// Determine whether a required field has a default for the user
$field_has_default_for_user=false;
if($userresourcedefaults != '')
{
foreach(explode(';', $userresourcedefaults) as $rule)
{
$rule_detail = explode('=', trim($rule));
$field_shortname = $rule_detail[0];
$field_default_value = $rule_detail[1];
if($field_shortname == $fields[$n]['name'] && $field_default_value !="")
{
$field_has_default_for_user=true;
break;
}
}
}
// Populate empty field with the default if necessary
if($field_has_default_for_user && strlen((string) $val)==0) {
$val=$field_default_value;
$new_checksums[$fields[$n]['ref']] = md5(trim(preg_replace('/\s\s+/', ' ', $val)));
}
if( $fields[$n]['required'] == 1
&& check_display_condition($n, $fields[$n], $fields, false, $ref)
&& (
// Required node field with no nodes submitted is a candidate for error
(in_array($fields[$n]['type'], $FIXED_LIST_FIELD_TYPES) && count($ui_selected_node_values) == 0)
// Required continuous field with no value is a candidate for error
|| (!in_array($fields[$n]['type'], $FIXED_LIST_FIELD_TYPES) && trim(strip_leading_comma($val)) == '')
)
&& (
// An existing resource node field with neither any nodes submitted nor a resource default
($ref > 0 && in_array($fields[$n]['type'], $FIXED_LIST_FIELD_TYPES) && count($ui_selected_node_values) == 0 && !$field_has_default_for_user)
// An existing resource continuous field with neither an input value nor a resource default
|| ($ref > 0 && !in_array($fields[$n]['type'], $FIXED_LIST_FIELD_TYPES) && strlen((string) $val)==0 && !$field_has_default_for_user)
// A template node field with neither any nodes submitted nor a resource default
|| ($ref < 0 && in_array($fields[$n]['type'], $FIXED_LIST_FIELD_TYPES) && count($ui_selected_node_values) == 0 && !$field_has_default_for_user)
// A template continuous field with neither an input value nor a resource default
|| ($ref < 0 && !in_array($fields[$n]['type'], $FIXED_LIST_FIELD_TYPES) && strlen((string) $val)==0 && !$field_has_default_for_user)
)
// Not a metadata template
&& !$is_template
)
{
$field_visibility_status=getval("field_".$fields[$n]['ref']."_displayed","");
# Register an error only if the empty required field was actually displayed
if (is_field_displayed($fields[$n]) && $field_visibility_status=="block")
{
$errors[$fields[$n]['ref']] = i18n_get_translated($fields[$n]['title']) . ": {$lang['requiredfield']}";
continue;
}
}
// If all good so far, then save the data
if(
in_array($fields[$n]['type'], NON_FIXED_LIST_SINGULAR_RESOURCE_VALUE_FIELD_TYPES)
&& str_replace("\r\n", "\n", trim((string) $fields[$n]['value'])) !== str_replace("\r\n", "\n", trim((string) $val))
)
{
# This value is different from the value we have on record.
# Expiry field? Set that expiry date(s) have changed so the expiry notification flag will be reset later in this function.
if ($fields[$n]["type"]==FIELD_TYPE_EXPIRY_DATE)
{
$expiry_field_edited=true;
}
$use_node = null;
if(trim((string) $fields[$n]["nodes"]) != "")
{
// Remove any existing node IDs for this non-fixed list field (there should only be one) unless used by other resources.
$current_field_nodes = array_filter(explode(",",$fields[$n]["nodes"]),"is_int_loose");
$all_current_field_nodes = array_merge($all_current_field_nodes,$current_field_nodes);
foreach($current_field_nodes as $current_field_node)
{
$inuse = get_nodes_use_count([$current_field_node]);
$inusecount = $inuse[$current_field_node] ?? 0;
if ($current_field_node > 0 && $inusecount == 1)
{
// Reuse same node
$use_node = $current_field_node;
}
else
{
// Remove node from resource and create new node
$nodes_to_remove[] = $current_field_node;
$nodes_check_delete[] = $current_field_node;
}
}
}
# Add new node unless empty string
if($val == '')
{
// Remove and delete node
$nodes_to_remove[] = $current_field_node;
$nodes_check_delete[] = $current_field_node;
}
else
{
// Update the existing node
$newnode = set_node($use_node, $fields[$n]["ref"], $val, null, null);
if((int)$newnode != (int)$use_node)
{
// Node already exists, remove current node and replace
$nodes_to_add[] = $newnode;
$nodes_to_remove[] = $use_node;
$nodes_check_delete[]=$use_node;
// Set new value for logging
$new_node_values[] = $newnode;
}
else
{
$new_node_values[] = $use_node;
}
// Add to array for logging
if (!is_null($use_node))
{
$oldnodenames[$use_node] = $fields[$n]['value'];
}
}
# If this is a 'joined' field we need to add it to the resource column
$joins=get_resource_table_joins();
if (in_array($fields[$n]["ref"],$joins))
{
update_resource_field_column($ref,$fields[$n]["ref"],$val);
}
}
# Add any onchange code if new checksum for field shows that it has changed
if(isset($fields[$n]["onchange_macro"]) && $fields[$n]["onchange_macro"]!==""
&& $post_cs !==""
&& isset($new_checksums[$fields[$n]["ref"]])
&& $post_cs !== $new_checksums[$fields[$n]["ref"]])
{
$macro_resource_id=$ref;
eval(eval_check_signed($fields[$n]["onchange_macro"]));
}
} # End of if "allowed to edit field conditions"
} # End of for $fields
// When editing a resource, prevent applying the change to the resource if there are any errors
if(count($errors) > 0 && $ref > 0)
{
return $errors;
}
# Save related resource field if value for Related input field is autosaved, or if form has been submitted by user
if (($autosave_field=="" || $autosave_field=="Related") && isset($_POST["related"]))
{
# save related resources field
$related=explode(",",getval("related",""));
# Trim whitespace from each entry
foreach ($related as &$relatedentry)
{
$relatedentry = trim($relatedentry);
}
# Make sure all submitted values are numeric
$to_relate = array_filter($related,"is_int_loose");
$currently_related = get_related_resources($ref);
$to_add = array_diff($to_relate, $currently_related);
$to_delete = array_diff($currently_related, $to_relate);
if(count($to_add) > 0)
{
update_related_resource($ref, $to_add, true);
}
if(count($to_delete) > 0)
{
update_related_resource($ref, $to_delete, false);
}
}
// Update resource_node table
db_begin_transaction("update_resource_node");
if(count($nodes_to_remove)>0)
{
delete_resource_nodes($ref,$nodes_to_remove, false);
}
if(count($nodes_to_add)>0)
{
add_resource_nodes($ref,$nodes_to_add, false, false);
}
log_node_changes($ref,$new_node_values, $all_current_field_nodes,"",$oldnodenames);
if(count($nodes_check_delete)>0)
{
// This has to be after call to log_node_changes() or nodes cannot be resolved
check_delete_nodes($nodes_check_delete);
}
db_end_transaction("update_resource_node");
// Autocomplete any blank fields without overwriting any existing metadata
$autocomplete_fields = autocomplete_blank_fields($ref, false, true);
foreach($autocomplete_fields as $autocomplete_field_ref => $autocomplete_field_value)
{
$new_checksums[$autocomplete_field_ref] = md5((string)$autocomplete_field_value);
}
// Initialise an array of updates for the resource table
$resource_update_sql = array();
$resource_update_params = array();
if($edit_contributed_by)
{
$created_by = $resource_data['created_by'];
$new_created_by = getval("created_by",0,true);
if((getval("created_by",0,true) > 0) && $new_created_by != $created_by)
{
# Also update created_by
$resource_update_sql[] = "created_by= ?";
$resource_update_params[]="i";$resource_update_params[]=$new_created_by;
$olduser=get_user($created_by);
$newuser=get_user($new_created_by);
$resource_update_log_sql[] = array(
"ref"=>$ref,
"type"=>LOG_CODE_CREATED_BY_CHANGED,
"field"=>0,
"notes"=>"",
"from"=>$created_by . " (" . ($olduser["fullname"]=="" ? $olduser["username"] : $olduser["fullname"]) . ")","to"=>$new_created_by . " (" . ($newuser["fullname"]=="" ? $newuser["username"] : $newuser["fullname"]) . ")");
}
}
# Expiry field(s) edited? Reset the notification flag so that warnings are sent again when the date is reached.
if ($expiry_field_edited)
{
$resource_update_sql[] = "expiry_notification_sent='0'";
}
if (!hook('forbidsavearchive', '', array($errors)))
{
# Also update archive status and access level
$oldaccess=$resource_data['access'];
$access=getval("access",$oldaccess,true);
$oldarchive=$resource_data['archive'];
$setarchivestate=getval("status",$oldarchive,true);
if($setarchivestate!=$oldarchive && !checkperm("e" . $setarchivestate)) // don't allow change if user has no permission to change archive state
{
$setarchivestate=$oldarchive;
}
// Only if changed
if(($autosave_field=="" || $autosave_field=="Status") && $setarchivestate != $oldarchive)
{
// Check if resource status has already been changed between form being loaded and submitted
if(getval("status_checksum","") != "" && getval("status_checksum","") != $oldarchive)
{
$errors["status"] = $lang["status"] . ': ' . $lang["save-conflict-error"];
}
else
{
// update archive status if different (doesn't matter whether it is a user template or a genuine resource)
if($setarchivestate != $oldarchive)
{
update_archive_status($ref,$setarchivestate,array($oldarchive));
}
$new_checksums["status"] = $setarchivestate;
}
}
if(($autosave_field=="" || $autosave_field=="Access") && $access != $oldaccess)
{
// Check if resource access has already been changed between form being loaded and submitted
if(getval("access_checksum","") != "" && getval("access_checksum","") != $oldaccess)
{
$errors["access"] = $lang["access"] . ': ' . $lang["save-conflict-error"];
}
else
{
$resource_update_sql[] = "access= ?";
$resource_update_params[]="i";$resource_update_params[]=$access;
if($access != $oldaccess && 0 < $ref)
{
$resource_update_log_sql[] = array(
'ref' => $ref,
'type' => 'a',
'field' => 0,
'notes' => '',
'from' => $oldaccess,
'to' => $access);
}
if ($oldaccess==3 && $access!=3)
{
# Moving out of the custom state. Delete any usergroup specific access.
# This can delete any 'manual' usergroup grants also as the user will have seen this as part of the custom access.
delete_resource_custom_access_usergroups($ref);
}
$new_checksums["access"] = $access;
}
}
}
if(count($resource_update_sql)>0)
{
$sql = "UPDATE resource SET " . implode(",",$resource_update_sql) . " WHERE ref=?";
$sqlparams = array_merge($resource_update_params,["i",$ref]);
ps_query($sql,$sqlparams);
}
foreach($resource_update_log_sql as $log_sql)
{
resource_log($log_sql["ref"],$log_sql["type"],$log_sql["field"],$log_sql["notes"],$log_sql["from"],$log_sql["to"]);
}
# Save any custom permissions
if (getval("access",0)==RESOURCE_ACCESS_CUSTOM_GROUP)
{
save_resource_custom_access($ref);
}
// Plugins can do extra actions once all fields have been saved and return errors back if needed
$plg_errors = hook('aftersaveresourcedata', '', array($ref, $nodes_to_add, $nodes_to_remove, $autosave_field, $fields,$updated_resources));
if(is_array($plg_errors) && !empty($plg_errors))
{
$errors = array_merge($errors, $plg_errors);
}
if (count($errors)==0)
{
daily_stat("Resource edit", $ref);
return true;
}
return $errors;
}
This article was last updated 17th November 2024 15:05 Europe/London time based on the source file dated 15th November 2024 18:30 Europe/London time.