From 8e8d2dbba99fc678f2827be519590ef156df1193 Mon Sep 17 00:00:00 2001 From: Dmitrii Metelkin Date: Wed, 6 Mar 2024 12:51:36 +1100 Subject: [PATCH 1/2] issue #8: add conditions API --- classes/condition_base.php | 180 +++++++++++++++++++++++++++++++ classes/condition_manager.php | 60 +++++++++++ classes/condition_sql.php | 103 ++++++++++++++++++ classes/rule_manager.php | 4 - tests/condition_manager_test.php | 44 ++++++++ 5 files changed, 387 insertions(+), 4 deletions(-) create mode 100644 classes/condition_base.php create mode 100644 classes/condition_manager.php create mode 100644 classes/condition_sql.php create mode 100644 tests/condition_manager_test.php diff --git a/classes/condition_base.php b/classes/condition_base.php new file mode 100644 index 0000000..218231a --- /dev/null +++ b/classes/condition_base.php @@ -0,0 +1,180 @@ +. + +namespace tool_dynamic_cohorts; + +/** + * Abstract class that all conditions must extend. + * + * @package tool_dynamic_cohorts + * @copyright 2024 Catalyst IT + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +abstract class condition_base { + + /** + * Condition persistent object. + * + * @var condition $condition + */ + protected $condition; + + /** + * Protected constructor. + */ + protected function __construct() { + } + + /** + * Return an instance of condition object. + * + * @param int $id + * @param \stdClass|null $record + * @return \tool_dynamic_cohorts\condition_base|null + */ + final public static function get_instance(int $id = 0, ?\stdClass $record = null):? condition_base { + $condition = new condition($id, $record); + + // In case we are getting the instance without underlying persistent data. + if (!$classname = $condition->get('classname')) { + $classname = get_called_class(); + $condition->set('classname', $classname); + } + + if (!class_exists($classname) || !is_subclass_of($classname, self::class)) { + return null; + } + + $instance = new $classname(); + $instance->condition = $condition; + + return $instance; + } + + /** + * Gets required config data from submitted condition form data. + * + * @param \stdClass $formdata Form data generated via $mform->get_data() + * @return array + */ + public static function retrieve_config_data(\stdClass $formdata): array { + $configdata = (array)$formdata; + + // Everything except these fields is considered as config data. + unset($configdata['id']); + unset($configdata['ruleid']); + unset($configdata['position']); + + return $configdata; + } + + /** + * A config data for that condition. + * + * @return array + */ + public function get_config_data(): array { + return json_decode($this->condition->get('configdata'), true); + } + + /** + * Sets config data. + * + * @param array $configdata + */ + public function set_config_data(array $configdata): void { + $this->condition->set('configdata', json_encode($configdata)); + } + + /** + * Gets condition persistent record. + * + * @return condition + */ + public function get_record(): condition { + return $this->condition; + } + + /** + * Returns a rule record for the given condition. + * + * @return rule|null + */ + public function get_rule(): ?rule { + return rule::get_record(['id' => $this->get_record()->get('ruleid')]) ?: null; + } + + /** + * Gets a list of event classes the condition will be triggered on. + * + * @return array + */ + public function get_events(): array { + return []; + } + + /** + * Human readable description of the broken condition. + * + * @return string + */ + public function get_broken_description(): string { + return $this->get_record()->get('configdata'); + } + + /** + * Returns the name of the condition + * + * @return string + */ + abstract public function get_name(): string; + + /** + * Add condition config form elements. + * + * @param \MoodleQuickForm $mform The form to add elements to + */ + abstract public function config_form_add(\MoodleQuickForm $mform): void; + + /** + * Validates conditions form elements. + * + * @param array $data Form data. + * @return array Errors array. + */ + abstract public function config_form_validate(array $data): array; + + /** + * Returns elements to extend SQL for filtering users. + * @return condition_sql + */ + abstract public function get_sql(): condition_sql; + + /** + * Human-readable description of the configured condition. + * + * @return string + */ + abstract public function get_config_description(): string; + + /** + * Indicate that condition is broken. + * + * @return bool + */ + abstract public function is_broken(): bool; + +} diff --git a/classes/condition_manager.php b/classes/condition_manager.php new file mode 100644 index 0000000..fc26725 --- /dev/null +++ b/classes/condition_manager.php @@ -0,0 +1,60 @@ +. + +namespace tool_dynamic_cohorts; + +use core_component; + +/** + * Condition manager class. + * + * @package tool_dynamic_cohorts + * @copyright 2024 Catalyst IT + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class condition_manager { + + /** + * Get a list of all exising conditions. + * + * @param bool $excludebroken Do we need to exclude broken condition? + * @return condition_base[] + */ + public static function get_all_conditions(bool $excludebroken = true): array { + $instances = []; + $classes = core_component::get_component_classes_in_namespace(null, '\\local\\tool_dynamic_cohorts\\condition'); + + foreach (array_keys($classes) as $class) { + $reflectionclass = new \ReflectionClass($class); + if (!$reflectionclass->isAbstract()) { + $instance = $class::get_instance(); + + if ($excludebroken && $instance->is_broken()) { + continue; + } + + $instances[$class] = $class::get_instance(); + } + } + + // Sort conditions by name. + uasort($instances, function(condition_base $a, condition_base $b) { + return ($a->get_name() <=> $b->get_name()); + }); + + return $instances; + } +} diff --git a/classes/condition_sql.php b/classes/condition_sql.php new file mode 100644 index 0000000..e290d8d --- /dev/null +++ b/classes/condition_sql.php @@ -0,0 +1,103 @@ +. + +namespace tool_dynamic_cohorts; + +/** + * Condition SQl class for storing condition related SQl to filter out users. + * + * @see condition_base::get_sql + * + * @package tool_dynamic_cohorts + * @copyright 2024 Catalyst IT + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class condition_sql { + + /** + * Join string for SQL. + * @var string + */ + protected $join = ''; + + /** Where string for SQL. + * @var string + */ + protected $where = ''; + + /** + * A list of params for SQL. + * @var array + */ + protected $params = []; + + /** + * condition_sql constructor. + * + * @param string $join Join string for SQL. + * @param string $where Where string for SQL. + * @param array $params A list of params for SQL. + */ + public function __construct(string $join, string $where, array $params) { + $this->join = $join; + $this->where = $where; + $this->params = $params; + } + + /** + * Returns Join string for SQL. + * @return string + */ + public function get_join(): string { + return $this->join; + } + + /** + * Returns Where string for SQL. + * @return string + */ + public function get_where(): string { + return $this->where; + } + + /** + * Returns A list of params for SQL. + * @return array + */ + public function get_params(): array { + return $this->params; + } + + /** + * Generate an alias for prepending parameters in SQL. + * + * @return string + */ + public static function generate_param_alias(): string { + static $cnt = 0; + return 'tcmp' . ($cnt++); + } + + /** + * Generating an alias for tables in SQLs. + * + * @return string + */ + public static function generate_table_alias(): string { + static $cnt = 0; + return 'tcmf' . ($cnt++); + } +} diff --git a/classes/rule_manager.php b/classes/rule_manager.php index 8ba07af..844d6fb 100644 --- a/classes/rule_manager.php +++ b/classes/rule_manager.php @@ -22,10 +22,6 @@ use tool_dynamic_cohorts\event\rule_deleted; use tool_dynamic_cohorts\event\rule_updated; -defined('MOODLE_INTERNAL') || die(); - -require_once($CFG->dirroot.'/cohort/lib.php'); - /** * Rule manager class. * diff --git a/tests/condition_manager_test.php b/tests/condition_manager_test.php new file mode 100644 index 0000000..0ac08d2 --- /dev/null +++ b/tests/condition_manager_test.php @@ -0,0 +1,44 @@ +. + +namespace tool_dynamic_cohorts; + +/** + * Tests for condition manager class. + * + * @package tool_dynamic_cohorts + * @copyright 2024 Catalyst IT + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * + * @covers \tool_dynamic_cohorts\condition_manager + */ +class condition_manager_test extends \advanced_testcase { + + /** + * Test all conditions. + */ + public function test_get_all_conditions() { + $conditions = condition_manager::get_all_conditions(); + $this->assertIsArray($conditions); + $this->assertNotEmpty($conditions); + + foreach ($conditions as $condition) { + $this->assertFalse(is_null($condition)); + $this->assertTrue(is_subclass_of($condition, condition_base::class)); + $this->assertFalse($condition->is_broken()); + } + } +} From f89bf9d2445f23631469efb41ace18fe4f75afb8 Mon Sep 17 00:00:00 2001 From: Dmitrii Metelkin Date: Wed, 6 Mar 2024 12:52:14 +1100 Subject: [PATCH 2/2] issue #16: add user profile condition --- .../condition/user_profile.php | 531 ++++++++++++++++++ lang/en/tool_dynamic_cohorts.php | 5 + 2 files changed, 536 insertions(+) create mode 100644 classes/local/tool_dynamic_cohorts/condition/user_profile.php diff --git a/classes/local/tool_dynamic_cohorts/condition/user_profile.php b/classes/local/tool_dynamic_cohorts/condition/user_profile.php new file mode 100644 index 0000000..e4ddc1c --- /dev/null +++ b/classes/local/tool_dynamic_cohorts/condition/user_profile.php @@ -0,0 +1,531 @@ +. + +namespace tool_dynamic_cohorts\local\tool_dynamic_cohorts\condition; + +use tool_dynamic_cohorts\condition_base; +use tool_dynamic_cohorts\condition_sql; +use core_user; +use core_plugin_manager; + +/** + * Condition using standard user profile. + * + * @package tool_dynamic_cohorts + * @copyright 2024 Catalyst IT + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_profile extends condition_base { + + /** + * Base field nname. + */ + public const FIELD_NAME = 'profilefield'; + + /** + * Value for text field types. + */ + public const FIELD_DATA_TYPE_TEXT = 'text'; + + /** + * Value for menu field types. + */ + public const FIELD_DATA_TYPE_MENU = 'menu'; + + /** + * Value for operator text contains. + */ + public const TEXT_CONTAINS = 1; + + /** + * Value for operator text doesn't contain. + */ + public const TEXT_DOES_NOT_CONTAIN = 2; + + /** + * Value for operator text is equal to. + */ + public const TEXT_IS_EQUAL_TO = 3; + + /** + * Value for operator text starts with. + */ + public const TEXT_STARTS_WITH = 4; + + /** + * Value for operator text ends with. + */ + public const TEXT_ENDS_WITH = 5; + + /** + * Value for operator text is empty. + */ + public const TEXT_IS_EMPTY = 6; + + /** + * Value for operator text is not empty. + */ + public const TEXT_IS_NOT_EMPTY = 7; + + /** + * Value for operator text is not equal to. + */ + public const TEXT_IS_NOT_EQUAL_TO = 8; + + /** + * A list of supported default fields. + */ + protected const SUPPORTED_STANDARD_FIELDS = ['auth', 'firstname', 'lastname', 'username', 'email', 'idnumber', + 'city', 'country', 'institution', 'department']; + + + /** + * Condition name. + * + * @return string + */ + public function get_name(): string { + return get_string('condition_user_profile', 'tool_dynamic_cohorts'); + } + + /** + * Add config form elements. + * + * @param \MoodleQuickForm $mform + */ + public function config_form_add(\MoodleQuickForm $mform): void { + $options = [0 => get_string('select')]; + + $fields = $this->get_fields_info(); + foreach ($fields as $shortname => $field) { + $options[$shortname] = $field->name; + } + + $group = []; + $group[] = $mform->createElement('select', self::FIELD_NAME, '', $options); + + foreach ($fields as $shortname => $field) { + switch ($field->datatype) { + case self::FIELD_DATA_TYPE_TEXT: + $this->add_text_field($mform, $group, $field, $shortname); + break; + case self::FIELD_DATA_TYPE_MENU: + $this->add_menu_field($mform, $group, $field, $shortname); + break; + } + } + + $mform->addGroup($group, 'profilefieldgroup', get_string('profilefield', 'tool_dynamic_cohorts'), '', false); + } + + /** + * Validate config form elements. + * + * @param array $data Data to validate. + * @return array + */ + public function config_form_validate(array $data): array { + $errors = []; + + $fields = $this->get_fields_info(); + if (empty($data[self::FIELD_NAME]) || !isset($data[self::FIELD_NAME]) || !isset($fields[$data[self::FIELD_NAME]])) { + $errors['profilefieldgroup'] = get_string('pleaseselectfield', 'tool_dynamic_cohorts'); + } + + $fieldvalue = $data[self::FIELD_NAME] . '_value'; + $operator = $data[self::FIELD_NAME] . '_operator'; + $datatype = $fields[$data[self::FIELD_NAME]]->datatype ?? ''; + + if (empty($data[$fieldvalue])) { + if ($datatype == 'text' && !in_array($data[$operator], [self::TEXT_IS_EMPTY, self::TEXT_IS_NOT_EMPTY])) { + $errors['profilefieldgroup'] = get_string('invalidfieldvalue', 'tool_dynamic_cohorts'); + } + } + + return $errors; + } + + /** + * Gets required config data from submitted condition form data. + * + * @param \stdClass $formdata + * @return array + */ + public static function retrieve_config_data(\stdClass $formdata): array { + $configdata = parent::retrieve_config_data($formdata); + $fieldname = $configdata[self::FIELD_NAME]; + + $data = []; + + // Get field name itself. + $data[self::FIELD_NAME] = $fieldname; + + // Only get values related to the selected field name, e.g firstname_operator, firstname_value. + foreach ($configdata as $key => $value) { + if (strpos($key, $fieldname . '_') === 0) { + $data[$key] = $value; + } + } + + return $data; + } + + /** + * Gets an list of comparison operators for text fields. + * + * @return array A list of operators. + */ + protected function get_text_operators() : array { + return [ + self::TEXT_CONTAINS => get_string('contains', 'filters'), + self::TEXT_DOES_NOT_CONTAIN => get_string('doesnotcontain', 'filters'), + self::TEXT_IS_EQUAL_TO => get_string('isequalto', 'filters'), + self::TEXT_IS_NOT_EQUAL_TO => get_string('isnotequalto', 'filters'), + self::TEXT_STARTS_WITH => get_string('startswith', 'filters'), + self::TEXT_ENDS_WITH => get_string('endswith', 'filters'), + self::TEXT_IS_EMPTY => get_string('isempty', 'filters'), + self::TEXT_IS_NOT_EMPTY => get_string('isnotempty', 'tool_dynamic_cohorts'), + ]; + } + + /** + * Gets an list of comparison operators for menu fields. + * + * @return array A list of operators. + */ + protected function get_menu_operators() : array { + return [ + self::TEXT_IS_EQUAL_TO => get_string('isequalto', 'filters'), + self::TEXT_IS_NOT_EQUAL_TO => get_string('isnotequalto', 'filters'), + ]; + } + + /** + * Returns a list of all fields with extra data (shortname, name, datatype, param1 and type). + * + * @return \stdClass[] + */ + protected function get_fields_info(): array { + $fields = []; + + foreach (self::SUPPORTED_STANDARD_FIELDS as $field) { + $fields[$field] = new \stdClass(); + $fields[$field]->shortname = $field; + + switch ($field) { + case 'auth': + $options = []; + foreach (core_plugin_manager::instance()->get_plugins_of_type('auth') as $plugin) { + $options[$plugin->name] = $plugin->displayname; + } + $fields[$field]->name = get_string('type_auth', 'plugin'); + $fields[$field]->datatype = self::FIELD_DATA_TYPE_MENU; + $fields[$field]->param1 = $options; + break; + default: + $fields[$field]->name = get_string($field); + $fields[$field]->datatype = self::FIELD_DATA_TYPE_TEXT; + $fields[$field]->paramtype = core_user::get_property_type($field); + break; + } + } + + return $fields; + } + + /** + * Adds a text field to the form. + * + * @param \MoodleQuickForm $mform Form to add the field to. + * @param array $group A group to add the field to. + * @param \stdClass $field Field info. + * @param string $shortname A field shortname. + */ + protected function add_text_field(\MoodleQuickForm $mform, array &$group, \stdClass $field, string $shortname): void { + $elements = []; + $elements[] = $mform->createElement('select', $shortname . '_operator', null, $this->get_text_operators()); + $elements[] = $mform->createElement('text', $shortname . '_value', null); + + $mform->setType($shortname . '_value', $field->paramtype ?? PARAM_TEXT); + $mform->hideIf($shortname . '_value', $shortname . '_operator', 'in', self::TEXT_IS_EMPTY . '|' . self::TEXT_IS_NOT_EMPTY); + + $group[] = $mform->createElement('group', $shortname, '', $elements, '', false); + $mform->hideIf($shortname, self::FIELD_NAME, 'neq', $shortname); + } + + /** + * Adds a menu field to the form. + * + * @param \MoodleQuickForm $mform Form to add the field to. + * @param array $group A group to add the field to. + * @param \stdClass $field Field info. + * @param string $shortname A field shortname. + */ + protected function add_menu_field(\MoodleQuickForm $mform, array &$group, \stdClass $field, string $shortname): void { + $options = (array) $field->param1; + $elements = []; + $elements[] = $mform->createElement('select', $shortname . '_operator', null, $this->get_menu_operators()); + + $elements[] = $mform->createElement('select', $shortname . '_value', $field->name, $options); + $mform->hideIf($shortname . '_value', $shortname . '_operator', 'in', self::TEXT_IS_EMPTY . '|' . self::TEXT_IS_NOT_EMPTY); + + $group[] = $mform->createElement('group', $shortname, '', $elements, '', false); + $mform->hideIf($shortname, self::FIELD_NAME, 'neq', $shortname); + } + + /** + * Returns a field name for the configured field. + * + * @return string + */ + protected function get_field_name(): string { + return $this->get_config_data()[self::FIELD_NAME]; + } + + /** + * Returns a value of the configured field. + * + * @return string|null + */ + protected function get_field_value(): ?string { + $fieldvalue = null; + $field = $this->get_field_name(); + $configdata = $this->get_config_data(); + + if (!empty($field) && isset($configdata[$field . '_value'])) { + $fieldvalue = $configdata[$field . '_value']; + } + + return $fieldvalue; + } + + /** + * Return the field name as a text. + * + * @return string + */ + protected function get_field_text(): string { + return $this->get_fields_info()[$this->get_field_name()]->name ?? '-'; + } + + + /** + * Returns a value for the configured operator. + * + * @return int + */ + protected function get_operator_value(): int { + return $this->get_config_data()[$this->get_field_name() . '_operator'] ?? self::TEXT_IS_EQUAL_TO; + } + + /** + * Returns a text for the configured operator based on a field data type. + * + * @param string $fielddatatype Field data type. + * @return string + */ + protected function get_operator_text(string $fielddatatype): string { + if ($fielddatatype == self::FIELD_DATA_TYPE_TEXT) { + return $this->get_text_operators()[$this->get_operator_value()]; + } + + if ($fielddatatype == self::FIELD_DATA_TYPE_MENU) { + return $this->get_menu_operators()[$this->get_operator_value()]; + } + + return $this->get_text_operators()[$this->get_operator_value()]; + } + + /** + * Human readable description of the configured condition. + * + * @return string + */ + public function get_config_description(): string { + $fieldname = $this->get_field_name(); + + if (empty($fieldname)) { + return ''; + } + + $datatype = $this->get_fields_info()[$fieldname]->datatype; + + if (in_array($this->get_operator_value(), [self::TEXT_IS_EMPTY, self::TEXT_IS_NOT_EMPTY])) { + return $this->get_field_text() . ' ' . $this->get_operator_text($datatype); + } else { + $fieldvalue = $this->get_field_value(); + if ($fieldname == 'auth') { + $authplugins = core_plugin_manager::instance()->get_plugins_of_type('auth'); + $fieldvalue = $authplugins[$fieldvalue]->displayname; + } + + return $this->get_field_text() . ' '. $this->get_operator_text($datatype) . ' ' . $fieldvalue; + } + } + + /** + * Gets SQL for a given condition. + * + * @return condition_sql + */ + public function get_sql(): condition_sql { + $result = new condition_sql('', '1=0', []); + + $datatype = $this->get_fields_info()[$this->get_field_name()]->datatype; + + switch ($datatype) { + case self::FIELD_DATA_TYPE_TEXT: + $result = $this->get_text_sql_data('u', $this->get_field_name()); + break; + case self::FIELD_DATA_TYPE_MENU: + $result = $this->get_menu_sql_data('u', $this->get_field_name()); + break; + } + + return $result; + } + + /** + * Get SQl data for text type fields. + * + * @param string $tablealias Alias for a table. + * @param string $fieldname Field name. + * @return condition_sql + */ + protected function get_text_sql_data(string $tablealias, string $fieldname): condition_sql { + global $DB; + + $fieldvalue = $this->get_field_value(); + $operatorvalue = $this->get_operator_value(); + + if ($this->is_broken()) { + return new condition_sql('', '', []); + } + + $param = condition_sql::generate_param_alias(); + + switch ($operatorvalue) { + case self::TEXT_CONTAINS: + $where = $DB->sql_like("$tablealias.$fieldname", ":$param", false, false); + $value = $DB->sql_like_escape($fieldvalue); + $params[$param] = "%$value%"; + break; + case self::TEXT_DOES_NOT_CONTAIN: + $where = $DB->sql_like("$tablealias.$fieldname", ":$param", false, false, true); + $fieldvalue = $DB->sql_like_escape($fieldvalue); + $params[$param] = "%$fieldvalue%"; + break; + case self::TEXT_IS_EQUAL_TO: + $where = $DB->sql_equal($DB->sql_compare_text("{$tablealias}.{$fieldname}"), ":$param", false, false); + $params[$param] = $fieldvalue; + break; + case self::TEXT_IS_NOT_EQUAL_TO: + $where = $DB->sql_equal($DB->sql_compare_text("{$tablealias}.{$fieldname}"), ":$param", false, false, true); + $params[$param] = $fieldvalue; + break; + case self::TEXT_STARTS_WITH: + $where = $DB->sql_like("$tablealias.$fieldname", ":$param", false, false); + $fieldvalue = $DB->sql_like_escape($fieldvalue); + $params[$param] = "$fieldvalue%"; + break; + case self::TEXT_ENDS_WITH: + $where = $DB->sql_like("$tablealias.$fieldname", ":$param", false, false); + $fieldvalue = $DB->sql_like_escape($fieldvalue); + $params[$param] = "%$fieldvalue"; + break; + case self::TEXT_IS_EMPTY: + $where = $DB->sql_compare_text("$tablealias.$fieldname") . " = " . $DB->sql_compare_text(":$param"); + $params[$param] = ''; + break; + case self::TEXT_IS_NOT_EMPTY: + $where = $DB->sql_compare_text("$tablealias.$fieldname") . " != " . $DB->sql_compare_text(":$param"); + $params[$param] = ''; + break; + default: + return new condition_sql('', '', []); + } + + return new condition_sql('', $where, $params); + } + + /** + * Get SQL data for menu type fields. + * + * @param string $tablealias Alias for a table. + * @param string $fieldname Field name. + * @return condition_sql + */ + protected function get_menu_sql_data(string $tablealias, string $fieldname): condition_sql { + global $DB; + + $fieldvalue = $this->get_field_value(); + $operatorvalue = $this->get_operator_value(); + + if ($this->is_broken()) { + return new condition_sql('', '', []); + } + + $param = condition_sql::generate_param_alias(); + + switch ($operatorvalue) { + case self::TEXT_IS_EQUAL_TO: + $where = $DB->sql_equal($DB->sql_compare_text("{$tablealias}.{$fieldname}"), ":$param", false, false); + $params[$param] = $fieldvalue; + break; + case self::TEXT_IS_NOT_EQUAL_TO: + $where = $DB->sql_equal($DB->sql_compare_text("{$tablealias}.{$fieldname}"), ":$param", false, false, true); + $params[$param] = $fieldvalue; + break; + default: + return new condition_sql('', '', []); + } + + return new condition_sql('', $where, $params); + } + + /** + * A list of events the condition is listening to. + * + * @return string[] + */ + public function get_events(): array { + return [ + '\core\event\user_created', + '\core\event\user_updated', + ]; + } + + /** + * Is condition broken. + * + * @return bool + */ + public function is_broken(): bool { + if ($this->get_config_data()) { + $configuredfield = $this->get_field_name(); + $fieldvalue = $this->get_field_value(); + $operatorvalue = $this->get_operator_value(); + + if ($fieldvalue === '' && $operatorvalue != self::TEXT_IS_EMPTY && $operatorvalue != self::TEXT_IS_NOT_EMPTY) { + return true; + } + + return !array_key_exists($configuredfield, $this->get_fields_info()); + } + + return false; + } +} diff --git a/lang/en/tool_dynamic_cohorts.php b/lang/en/tool_dynamic_cohorts.php index 83bde56..9ef4cca 100644 --- a/lang/en/tool_dynamic_cohorts.php +++ b/lang/en/tool_dynamic_cohorts.php @@ -32,6 +32,7 @@ $string['cohort'] = 'Cohort'; $string['cohortid'] = 'Cohort'; $string['cohortid_help'] = 'A cohort to manage as part of this rule. Only cohorts that are not managed by other plugins are displayed in this list.'; +$string['condition_user_profile'] = 'User standard profile field'; $string['delete_confirm'] = 'Are you sure you want to delete rule {$a}?'; $string['delete_rule'] = 'Delete rule'; $string['description'] = 'Description'; @@ -45,10 +46,13 @@ $string['event:rulecreated'] = 'Rule created'; $string['event:ruleupdated'] = 'Rule updated'; $string['event:ruledeleted'] = 'Rule deleted'; +$string['invalidfieldvalue'] = 'Invalid field value'; +$string['isnotempty'] = 'is not empty'; $string['managerules'] = 'Manage rules'; $string['managecohorts'] = 'Manage cohorts'; $string['name'] = 'Rule name'; $string['name_help'] = 'A human readable name of this rule.'; +$string['pleaseselectfield'] = 'Please select a field'; $string['pluginname'] = 'Dynamic cohort rules'; $string['privacy:metadata:tool_dynamic_cohorts'] = 'Information about rules created or updated by a user'; $string['privacy:metadata:tool_dynamic_cohorts:name'] = 'Rule name'; @@ -56,6 +60,7 @@ $string['privacy:metadata:tool_dynamic_cohorts_c'] = 'Information about conditions created or updated by a user'; $string['privacy:metadata:tool_dynamic_cohorts_c:ruleid'] = 'ID of the rule'; $string['privacy:metadata:tool_dynamic_cohorts_c:usermodified'] = 'The ID of the user who created or updated a condition'; +$string['profilefield'] = 'Profile field'; $string['ruleisbroken'] = 'Rule is broken'; $string['ruledisabledpleasereview'] = 'Newly created or updated rules are disabled by default. Please review the rule below and enable it when ready.'; $string['ruledeleted'] = 'Rule has been deleted';