From 8a334e1f3046bf7c8e4f3a6cdddc148f711d4104 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Sun, 17 Apr 2022 14:37:54 +0300 Subject: [PATCH] REST API username prefix should be non-modifiable --- app/resources/locales/en_US/error.po | 3 ++ app/src/Lib/Traits/ValidationTrait.php | 54 ++++++++++++++++++++++---- app/src/View/Helper/FieldHelper.php | 40 +++++++++++++++++-- app/templates/ApiUsers/fields.inc | 2 +- app/webroot/css/co-base.css | 12 ++++++ 5 files changed, 99 insertions(+), 12 deletions(-) diff --git a/app/resources/locales/en_US/error.po b/app/resources/locales/en_US/error.po index edf321951..8b5c9c754 100644 --- a/app/resources/locales/en_US/error.po +++ b/app/resources/locales/en_US/error.po @@ -108,6 +108,9 @@ msgstr "Invalid character found" msgid "input.invalid.email" msgstr "The provided value is not a valid email address" +msgid "input.invalid.prefix" +msgstr "The provided value is not valid. \"{0}\" prefix is required" + msgid "input.invalid.url" msgstr "The provided value is not a valid URL" diff --git a/app/src/Lib/Traits/ValidationTrait.php b/app/src/Lib/Traits/ValidationTrait.php index e31881c50..9b25b7f68 100644 --- a/app/src/Lib/Traits/ValidationTrait.php +++ b/app/src/Lib/Traits/ValidationTrait.php @@ -30,6 +30,7 @@ namespace App\Lib\Traits; use Cake\Core\Configure; +use Cake\Database\Schema\TableSchemaInterface; use Cake\ORM\TableRegistry; use Cake\Validation\Validator; @@ -67,20 +68,34 @@ public function registerPrimaryKeyValidation(Validator $validator, array $primar * Register validation rules for the provided field, as a string. * * @since COmanage Registry v5.0.0 - * @param Validator $validator Cake Validator - * @param Schema $schema Cake Schema - * @param string $field Field name - * @param bool $required Whether this field is required + * @param Validator $validator Cake Validator + * @param TableSchemaInterface $schema Cake Schema + * @param string $field Field name + * @param bool $required Whether this field is required * @return Validator Cake Validator */ - public function registerStringValidation(Validator $validator, $schema, string $field, bool $required): Validator { - $validator->add($field, [ + public function registerStringValidation(Validator $validator, + TableSchemaInterface $schema, + string $field, + bool $required, + string $prefix = ''): Validator { + $rules = [ 'size' => ['rule' => ['validateMaxLength', ['column' => $schema->getColumn($field)]], 'provider' => 'table'], 'filter' => ['rule' => ['validateInput'], 'provider' => 'table'] - ]); + ]; + + if(!empty($prefix)) { + $rules['prefix'] = [ + 'rule' => ['validatePrefix'], + 'pass' => [$prefix], + 'provider' => 'table' + ]; + } + + $validator->add($field, $rules); if($required) { $validator->notEmptyString($field); @@ -301,4 +316,27 @@ public function validateTimeZone($value, array $context) { return true; } -} \ No newline at end of file + + /** + * Determine if a string submitted from a form has a valid prefix. + * + * @since COmanage Registry v5.0.0 + * @param string $value Value to validate + * @param string $prefix Prefix value + * @param array $context Validation context + * @return mixed True if $value validates, or an error string otherwise + */ + + public function validatePrefix(string $value, string $prefix, array $context) { + $coid = $context['data']['co_id'] ?? ''; + if($prefix === "co_id") { + $prefix = !empty($coid) ? "co_" . $coid . "." : ""; + } + + if (!preg_match('/^' . $prefix . '(?:.*)/m', $value)) { + return __d('error', 'input.invalid.prefix', [$prefix]); + } + + return true; + } +} diff --git a/app/src/View/Helper/FieldHelper.php b/app/src/View/Helper/FieldHelper.php index bbf752b45..0da6e5aa5 100644 --- a/app/src/View/Helper/FieldHelper.php +++ b/app/src/View/Helper/FieldHelper.php @@ -70,12 +70,14 @@ public function banner(string $info) { * @param string $fieldName Form field * @param array $options FormHelper control options * @param string $labelText Label text (fieldName language key used by default) + * @param array $config Custom FormHelper configuration options * @return string HTML for control */ public function control(string $fieldName, array $options=[], - string $labelText=null) { + string $labelText=null, + array $config=[]){ $coptions = $options; $coptions['label'] = false; $coptions['readonly'] = !$this->editable || (isset($options['readonly']) && $options['readonly']); @@ -84,7 +86,16 @@ public function control(string $fieldName, // Generate HTML for the control itself $liClass = ""; - + + // Remove prefix from field value + if(isset($config['prefix'], $this->getView()->get('vv_obj')->$fieldName)) { + $vv_obj = $this->getView()->get('vv_obj'); + $fieldValue = $vv_obj->$fieldName; + $fieldValueTemp = str_replace($config['prefix'], '', $fieldValue); + $vv_obj->$fieldName = $fieldValueTemp; + $this->getView()->set('vv_obj', $vv_obj); + } + // Handle datetime controls specially if($fieldName == 'valid_from' || $fieldName == 'valid_through') { // Append the timezone to the label @@ -198,7 +209,9 @@ public function control(string $fieldName, return $this->startLine($liClass) . $this->formNameDiv($fieldName, $labelText) - . $this->formInfoDiv($controlCode) + . ( !empty($config['prefix']) ? + $this->formInfoWithPrefixDiv($controlCode, $config['prefix']) : + $this->formInfoDiv($controlCode) ) . $this->endLine(); } @@ -239,6 +252,27 @@ protected function formInfoDiv(string $content) { ' . $content . ' '; } + + /** + * Generate a form info (control, value) box with a non editable prefix. + * + * @since COmanage Registry v5.0.0 + * @param string $content Content HTML + * @param string $prefix Prefix value + * @return string Form Info HTML + */ + + protected function formInfoWithPrefixDiv(string $context, string $prefix) { + $div = '
' . PHP_EOL + . '
' . PHP_EOL + . '
' . PHP_EOL + . '' . $prefix . '' + . '
' . PHP_EOL + . $context + . '
'; + + return $div; + } /** * Generate a form name (label, description) box. diff --git a/app/templates/ApiUsers/fields.inc b/app/templates/ApiUsers/fields.inc index 967b63547..e4eb9bc02 100644 --- a/app/templates/ApiUsers/fields.inc +++ b/app/templates/ApiUsers/fields.inc @@ -32,7 +32,7 @@ if($vv_action == 'add' || $vv_action == 'edit') { } // AR-ApiUser-3 For namespacing purposes, API Users are named with a prefix consisting of the string "co_#.". - print $this->Field->control('username', ['default' => "co_" . $vv_cur_co->id .'.']); + print $this->Field->control('username', [], null, ['prefix' => "co_" . $vv_cur_co->id .'.']); // We link to the "Generate" button on edit only $generateLink = []; diff --git a/app/webroot/css/co-base.css b/app/webroot/css/co-base.css index 1d58a8619..978e82466 100644 --- a/app/webroot/css/co-base.css +++ b/app/webroot/css/co-base.css @@ -1133,6 +1133,18 @@ ul.fields li.fields-datepicker .field-info { display: flex; align-items: center; } +.field-info .input-group { + flex-wrap: unset; +} +.field-info .input-group .input.text { + width: inherit; +} +.field-info .input-group .input-group-text{ + border-radius: unset; + font-size: inherit; + line-height: inherit; + padding: .25rem .75rem; +} .cm-time-picker-panel { position: absolute; z-index: 100;