diff options
| author | Jan-Hendrik Willms <tleilax+studip@gmail.com> | 2022-11-24 10:29:24 +0000 |
|---|---|---|
| committer | Jan-Hendrik Willms <tleilax+studip@gmail.com> | 2022-11-24 10:29:24 +0000 |
| commit | 7dddea8ccca601bf2da28960f2e27a223fe60ea6 (patch) | |
| tree | b34ee92f9a4e0e4c1f7e4dcf5f15b396f9097d6f /lib | |
| parent | 1231022837beceedef376e4bb8084ff38fbc7d93 (diff) | |
rework aux lock rules, use sorm model, deprecate old class and let name and description be translatable, fixes #1791
Closes #1791
Merge request studip/studip!1177
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/classes/AuxLockRules.class.php | 3 | ||||
| -rw-r--r-- | lib/classes/Markup.class.php | 2 | ||||
| -rw-r--r-- | lib/classes/StudipArrayObject.class.php | 8 | ||||
| -rw-r--r-- | lib/classes/WidgetContainer.php | 5 | ||||
| -rw-r--r-- | lib/models/AuxLockRule.php | 133 | ||||
| -rw-r--r-- | lib/models/DatafieldEntryModel.class.php | 82 |
6 files changed, 158 insertions, 75 deletions
diff --git a/lib/classes/AuxLockRules.class.php b/lib/classes/AuxLockRules.class.php index 6a6dfd9..4d06ca2 100644 --- a/lib/classes/AuxLockRules.class.php +++ b/lib/classes/AuxLockRules.class.php @@ -23,6 +23,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/** + * @deprecated since Stud.IP 5.3 + */ class AuxLockRules { diff --git a/lib/classes/Markup.class.php b/lib/classes/Markup.class.php index af298be..0f5a5c8 100644 --- a/lib/classes/Markup.class.php +++ b/lib/classes/Markup.class.php @@ -233,7 +233,7 @@ class Markup * Create HTML purifier instance with Stud.IP-specific configuration. * * @param boolean $autoformat Apply the AutoFormat rules - * @return HTMLPurifier A new instance of the HTML purifier. + * @return \HTMLPurifier A new instance of the HTML purifier. */ private static function createPurifier($autoformat) { diff --git a/lib/classes/StudipArrayObject.class.php b/lib/classes/StudipArrayObject.class.php index bb5444c..f025ffb 100644 --- a/lib/classes/StudipArrayObject.class.php +++ b/lib/classes/StudipArrayObject.class.php @@ -436,4 +436,12 @@ class StudipArrayObject implements IteratorAggregate, ArrayAccess, Serializable, throw new InvalidArgumentException("{$key} is a protected property, use a different key"); } } + + /** + * Returns whether the given value is in the underlying array. + */ + public function contains($value): bool + { + return in_array($value, $this->storage); + } } diff --git a/lib/classes/WidgetContainer.php b/lib/classes/WidgetContainer.php index b4aaa8c..108477a 100644 --- a/lib/classes/WidgetContainer.php +++ b/lib/classes/WidgetContainer.php @@ -46,10 +46,11 @@ abstract class WidgetContainer /** * Add a widget to the container. * - * @param Widget $widget The actual widget + * @template W of Widget + * @param W $widget The actual widget * @param String $index Optional index/name of the widget, defaults to * class name without "widget" - * @return Widget The added widget to allow for easier handling + * @return W The added widget to allow for easier handling */ public function addWidget(Widget $widget, $index = null) { diff --git a/lib/models/AuxLockRule.php b/lib/models/AuxLockRule.php index d0686a9..4bf8e8b 100644 --- a/lib/models/AuxLockRule.php +++ b/lib/models/AuxLockRule.php @@ -13,31 +13,75 @@ * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 * @category Stud.IP * @since 3.0 + * * @property string lock_id database column * @property string id alias column for lock_id * @property string name database column * @property string description database column - * @property string attributes database column - * @property string sorting database column + * @property JSONArrayObject attributes database column + * @property JSONArrayObject sorting database column * @property array datafields computed column * @property string order computed column - * @property Course course belongs_to Course + * @property Course[]|SimpleORMapCollection courses has_and_belongs_to_many Courses */ class AuxLockRule extends SimpleORMap { protected static function configure($config = []) { $config['db_table'] = 'aux_lock_rules'; - $config['belongs_to']['course'] = [ - 'class_name' => Course::class, - 'foreign_key' => 'lock_id', - 'assoc_foreign_key' => 'aux_lock_rule', + + $config['has_many'] = [ + 'courses' => [ + 'class_name' => Course::class, + 'foreign_key' => 'lock_id', + 'assoc_foreign_key' => 'aux_lock_rule', + ], + ]; + + $config['additional_fields'] = [ + 'datafields' => true + ]; + + $config['serialized_fields'] = [ + 'attributes' => JSONArrayObject::class, + 'sorting' => JSONArrayObject::class, ]; - $config['additional_fields']['datafields'] = true; - $config['additional_fields']['order'] = true; + + $config['i18n_fields'] = [ + 'name' => true, + 'description' => true, + ]; + + $config['registered_callbacks'] = [ + 'before_store' => [ + function (AuxLockRule $rule) { + $rule->sorting = array_filter($rule->sorting->getArrayCopy(), function ($id) use ($rule) { + return $rule->attributes->contains($id); + }, ARRAY_FILTER_USE_KEY); + }, + ], + 'before_delete' => [ + function (AuxLockRule $rule) { + return count($rule->courses) === 0; + }, + ] + ]; + parent::configure($config); } + public static function findOneByCourse(Course $course): ?AuxLockRule + { + return self::findOneByCourseId($course->id); + } + + public static function findOneByCourseId(string $course_id): ?AuxLockRule + { + $condition = "JOIN seminare ON lock_id = aux_lock_rule + WHERE Seminar_id = ?"; + return self::findOneBySQL($condition, [$course_id]); + } + /** * Cache to avoid loading datafields for a user more than once */ @@ -50,8 +94,8 @@ class AuxLockRule extends SimpleORMap */ public function getDatafields() { - $attributes = json_decode($this->attributes, true) ?: []; - $sorting = json_decode($this->sorting, true) ?: []; + $attributes = $this->attributes->getArrayCopy(); + $sorting = $this->sorting->getArrayCopy(); foreach ($attributes as $key => $attr) { if (!$attr) { @@ -64,11 +108,8 @@ class AuxLockRule extends SimpleORMap /** * Updates a datafield of a courseMember by the given data - * - * @param object $member - * @param object $data */ - public function updateMember($member, $data) + public function updateMember(CourseMember $member, array $data) { foreach ($data as $key => $value) { $datafield = current($this->getDatafield($member, $key)); @@ -88,23 +129,22 @@ class AuxLockRule extends SimpleORMap */ public function getCourseData($course = null, $display_only = false) { - // set course if (!$course) { $course = $this->course; } $mapping = [ - 'vadozent' => join(', ', $course->members->findBy('status', 'dozent')->getUserFullname()), + 'vadozent' => join(', ', $course->members->findBy('status', 'dozent')->getUserFullname()), 'vasemester' => $course->start_semester->name, - 'vatitle' => $course->name, - 'vanr' => $course->VeranstaltungsNummer, + 'vatitle' => $course->name, + 'vanr' => $course->veranstaltungsnummer, ]; $head_mapping = [ - 'vadozent' => _('Dozenten'), + 'vadozent' => _('Dozenten'), 'vasemester' => _('Semester'), - 'vatitle' => _('Veranstaltungstitel'), - 'vanr' => _('Veranstaltungsnummer'), + 'vatitle' => _('Veranstaltungstitel'), + 'vanr' => _('Veranstaltungsnummer'), ]; // start collecting entries @@ -145,38 +185,44 @@ class AuxLockRule extends SimpleORMap return $result; } - public function getMemberData($member) + public function getMemberData(CourseMember $member) { $datafields = SimpleCollection::createFromArray(DatafieldEntryModel::findByModel($member)); $result = []; - foreach (array_keys($this->datafields) as $field) { + foreach ($this->attributes as $field) { // since we have no only datafields we have to filter! - if ($new = $datafields->findOneBy('datafield_id', $field)) { + $new = $datafields->findOneBy('datafield_id', $field); + if ($new) { $result[] = $new; } } + + usort($result, function (DatafieldEntryModel $a, DatafieldEntryModel $b) { + $a_order = $this->sorting[$a->datafield_id] ?? 0; + $b_order = $this->sorting[$b->datafield_id] ?? 0; + return $a_order - $b_order; + }); + return $result; } /** * Caching for the datafields - * @param type $member - * @param type $fieldID - * @return null */ - private function getDatafield($member, $fieldID) + private function getDatafield(CourseMember $member, $field_id): ?array { - if (mb_strlen($fieldID) == 32) { - if (!array_key_exists($fieldID, $this->datafieldCache)) { - $this->datafieldCache[$fieldID] = DataField::find($fieldID); + if (mb_strlen($field_id) === 32) { + if (!array_key_exists($field_id, $this->datafieldCache)) { + $this->datafieldCache[$field_id] = DataField::find($field_id); } - if (isset($this->datafieldCache[$fieldID])) { - if ($this->datafieldCache[$fieldID]->object_type == 'usersemdata') { - $field = current(DatafieldEntryModel::findByModel($member, $fieldID)); + if (isset($this->datafieldCache[$field_id])) { + $field = null; + if ($this->datafieldCache[$field_id]->object_type === 'usersemdata') { + $field = current(DatafieldEntryModel::findByModel($member, $field_id)); } - if ($this->datafieldCache[$fieldID]->object_type == 'user') { - $field = current(DatafieldEntryModel::findByModel(User::find($member->user_id), $fieldID)); + if ($this->datafieldCache[$field_id]->object_type === 'user') { + $field = current(DatafieldEntryModel::findByModel(User::find($member->user_id), $field_id)); } if ($field) { $range_id = $field->sec_range_id ? [$field->range_id, $field->sec_range_id] : $field->range_id; @@ -185,6 +231,19 @@ class AuxLockRule extends SimpleORMap } } } + + return null; } + public static function validateFields(array $fields): bool + { + $entries = DataField::getDataFields('usersemdata'); + foreach ($entries as $entry) { + if (in_array($entry->id, $fields)) { + return true; + } + } + + return false; + } } diff --git a/lib/models/DatafieldEntryModel.class.php b/lib/models/DatafieldEntryModel.class.php index fa7a878..882b37e 100644 --- a/lib/models/DatafieldEntryModel.class.php +++ b/lib/models/DatafieldEntryModel.class.php @@ -48,37 +48,44 @@ class DatafieldEntryModel extends SimpleORMap implements PrivacyObject */ public static function findByModel(SimpleORMap $model, $datafield_id = null) { - $mask = ["user" => 1, "autor" => 2, "tutor" => 4, "dozent" => 8, "admin" => 16, "root" => 32]; + $mask = [ + 'user' => 1, + 'autor' => 2, + 'tutor' => 4, + 'dozent' => 8, + 'admin' => 16, + 'root' => 32, + ]; $sec_range_id = null; - if (is_a($model, "Course")) { + if ($model instanceof Course) { $params[':institution_ids'] = $model->institutes->pluck('institut_id'); $object_class = SeminarCategories::GetByTypeId($model->status)->id; $object_type = 'sem'; - $range_id = $model->getId(); - } elseif(is_a($model, "Institute")) { - $params[':institution_ids'] = [$model->Institut_id]; + $range_id = $model->id; + } elseif ($model instanceof Institute) { + $params[':institution_ids'] = [$model->id]; $object_class = $model->type; $object_type = 'inst'; - $range_id = $model->getId(); - } elseif(is_a($model, "User")) { + $range_id = $model->id; + } elseif ($model instanceof User) { $params[':institution_ids'] = $model->institute_memberships->pluck('institut_id'); $object_class = $mask[$model->perms]; $object_type = 'user'; - $range_id = $model->getId(); - } elseif(is_a($model, "CourseMember")) { + $range_id = $model->id; + } elseif($model instanceof CourseMember) { $params[':institution_ids'] = $model->course->institutes->pluck('institut_id'); $object_class = $mask[$model->status]; $object_type = 'usersemdata'; $range_id = $model->user_id; $sec_range_id = $model->seminar_id; - } elseif(is_a($model, "InstituteMember")) { + } elseif($model instanceof InstituteMember) { $params[':institution_ids'] = [$model->institut_id]; $object_class = $mask[$model->inst_perms]; $object_type = 'userinstrole'; $range_id = $model->user_id; $sec_range_id = $model->institut_id; - } elseif (is_a($model, 'ModulDeskriptor')) { + } elseif ($model instanceof ModulDeskriptor) { $params[':institution_ids'] = ''; if (!empty($model->modul->responsible_institute->institut_id)) { $params[':institution_ids'] = [$model->modul->responsible_institute->institut_id]; @@ -86,7 +93,7 @@ class DatafieldEntryModel extends SimpleORMap implements PrivacyObject $object_class = $model->getVariant(); $object_type = 'moduldeskriptor'; $range_id = $model->deskriptor_id; - } elseif (is_a($model, 'ModulteilDeskriptor')) { + } elseif ($model instanceof ModulteilDeskriptor) { $params[':institution_ids'] = [$model->modulteil->modul->responsible_institute->institut_id]; $object_class = $model->getVariant(); $object_type = 'modulteildeskriptor'; @@ -106,46 +113,50 @@ class DatafieldEntryModel extends SimpleORMap implements PrivacyObject $object_class = $model->getVariant(); $object_type = 'studycourse'; $range_id = $model->studiengang_id; - } - - if (!$object_type) { + } else { throw new InvalidArgumentException('Wrong type of model: ' . get_class($model)); } - $one_datafield = ''; + + $query = "SELECT a.*, b.*, a.datafield_id, b.datafield_id AS isset_content + FROM datafields a + LEFT JOIN datafields_entries b + ON (a.datafield_id=b.datafield_id AND range_id = :range_id AND sec_range_id = :sec_range_id) + WHERE object_type = :object_type + AND (lang IS NULL OR lang = '') + AND (a.institut_id IS NULL OR a.institut_id IN (:institution_ids))"; + if ($datafield_id !== null) { - $one_datafield = ' AND a.datafield_id = ' . DBManager::get()->quote($datafield_id); - } else { - $one_datafield = ''; + $query .= ' AND a.datafield_id = :one_datafield_id'; + $params[':one_datafield_id'] = $datafield_id; } - $query = "SELECT a.*, b.*,a.datafield_id,b.datafield_id as isset_content "; - $query .= "FROM datafields a LEFT JOIN datafields_entries b ON (a.datafield_id=b.datafield_id AND range_id = :range_id AND sec_range_id = :sec_range_id) "; - $query .= "WHERE object_type = :object_type AND (ISNULL(lang) OR lang = '') AND (a.institut_id IS NULL OR a.institut_id IN (:institution_ids))"; - if ($object_type === 'studycourse') { - $query .= "AND (LOCATE(:object_class, object_class) OR LOCATE('all', object_class)) $one_datafield ORDER BY priority"; + $query .= " AND (LOCATE(:object_class, object_class) OR LOCATE('all', object_class)) ORDER BY priority"; $params = array_merge($params,[ - ':range_id' => (string) $range_id, + ':range_id' => (string) $range_id, ':sec_range_id' => (string) $sec_range_id, - ':object_type' => $object_type, - ':object_class' => (string) $object_class]); + ':object_type' => $object_type, + ':object_class' => (string) $object_class, + ]); } elseif ($object_type === 'moduldeskriptor' || $object_type === 'modulteildeskriptor') { // find datafields by language (string) - $query .= "AND (LOCATE(:object_class, object_class) OR object_class IS NULL) $one_datafield ORDER BY priority"; + $query .= " AND (LOCATE(:object_class, object_class) OR object_class IS NULL) ORDER BY priority"; $params = array_merge($params,[ - ':range_id' => (string) $range_id, + ':range_id' => (string) $range_id, ':sec_range_id' => (string) $sec_range_id, - ':object_type' => $object_type, - ':object_class' => (string) $object_class]); + ':object_type' => $object_type, + ':object_class' => (string) $object_class, + ]); } else { // find datafields by perms or status (int) - $query .= "AND ((object_class & :object_class) OR object_class IS NULL) $one_datafield ORDER BY priority"; + $query .= " AND ((object_class & :object_class) OR object_class IS NULL) ORDER BY priority"; $params = array_merge($params, [ - ':range_id' => (string) $range_id, + ':range_id' => (string) $range_id, ':sec_range_id' => (string) $sec_range_id, - ':object_type' => $object_type, - ':object_class' => (int) $object_class]); + ':object_type' => $object_type, + ':object_class' => (int) $object_class, + ]); } $st = DBManager::get()->prepare($query); @@ -181,6 +192,7 @@ class DatafieldEntryModel extends SimpleORMap implements PrivacyObject } return $ret; } + public function setContentLanguage($language) { if (!Config::get()->CONTENT_LANGUAGES[$language]) { |
