Skip to content

Commit 0ee072b

Browse files
committed
Merge branch 'master' into dev/4.0
2 parents c608fe9 + 0fae932 commit 0ee072b

39 files changed

Lines changed: 298 additions & 217 deletions

‎controller/admin_controller.php‎

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -555,16 +555,14 @@ public function add_rule($language, $parent_id = 0)
555555
* @param int $rule_id The rule identifier to edit
556556
* @return void
557557
* @access public
558-
* @throws \phpbb\boardrules\exception\base If the rule does not exist or stored rule data is invalid
558+
* @throws \phpbb\boardrules\exception\base If stored rule data is invalid
559559
*/
560560
public function edit_rule($rule_id)
561561
{
562562
// Add form key
563563
add_form_key('add_edit_rule');
564564

565-
// Initiate and load the rule entity
566-
/* @var $entity \phpbb\boardrules\entity\rule */
567-
$entity = $this->container->get('phpbb.boardrules.entity')->load($rule_id);
565+
$entity = $this->load_rule($rule_id);
568566

569567
// Collect the form data
570568
$data = array(
@@ -778,13 +776,10 @@ protected function add_edit_rule_data($entity, $data)
778776
* @param int $rule_id The rule identifier to delete
779777
* @return void
780778
* @access public
781-
* @throws \phpbb\boardrules\exception\out_of_bounds If the rule does not exist
782779
*/
783780
public function delete_rule($rule_id)
784781
{
785-
// Initiate and load the rule entity
786-
/* @var $entity \phpbb\boardrules\entity\rule */
787-
$entity = $this->container->get('phpbb.boardrules.entity')->load($rule_id);
782+
$entity = $this->load_rule($rule_id);
788783

789784
// Use a confirmation box routine when deleting a rule
790785
if (confirm_box(true))
@@ -811,7 +806,7 @@ public function delete_rule($rule_id)
811806
$is_cat = (int) ($entity->get_right_id() - $entity->get_left_id() > 1);
812807

813808
// Request confirmation from the user to delete the rule
814-
confirm_box(false, $this->lang->lang('ACP_DELETE_RULE_CONFIRM', $is_cat), build_hidden_fields(array(
809+
confirm_box(false, $this->lang->lang($is_cat ? 'ACP_DELETE_RULE_CATEGORY_CONFIRM' : 'ACP_DELETE_RULE_CONFIRM'), build_hidden_fields(array(
815810
'mode' => 'manage',
816811
'action' => 'delete',
817812
'rule_id' => $rule_id,
@@ -831,10 +826,11 @@ public function delete_rule($rule_id)
831826
* @param int $amount The number of places to move the rule
832827
* @return void
833828
* @access public
834-
* @throws \phpbb\boardrules\exception\out_of_bounds If the rule does not exist after moving
835829
*/
836830
public function move_rule($rule_id, $direction, $amount = 1)
837831
{
832+
$moved = false;
833+
838834
// If the link hash is invalid, stop and show an error message to the user
839835
if (!check_link_hash($this->request->variable('hash', ''), $direction . $rule_id))
840836
{
@@ -862,9 +858,7 @@ public function move_rule($rule_id, $direction, $amount = 1)
862858
$json_response->send(array('success' => $moved));
863859
}
864860

865-
// Initiate and load the rule entity for no AJAX request
866-
/* @var $entity \phpbb\boardrules\entity\rule */
867-
$entity = $this->container->get('phpbb.boardrules.entity')->load($rule_id);
861+
$entity = $this->load_rule($rule_id);
868862

869863
// Use a redirect to reload the current page
870864
redirect("{$this->u_action}&language={$entity->get_language()}&parent_id={$entity->get_parent_id()}");
@@ -920,6 +914,24 @@ public function set_page_url($u_action)
920914
$this->u_action = $u_action;
921915
}
922916

917+
/**
918+
* Load a rule or display a recoverable ACP error when it no longer exists.
919+
*
920+
* @param int $rule_id Rule identifier
921+
* @return \phpbb\boardrules\entity\rule_interface
922+
*/
923+
protected function load_rule($rule_id)
924+
{
925+
try
926+
{
927+
return $this->container->get('phpbb.boardrules.entity')->load($rule_id);
928+
}
929+
catch (\phpbb\boardrules\exception\out_of_bounds $e)
930+
{
931+
trigger_error($e->get_message($this->lang) . adm_back_link($this->u_action), E_USER_WARNING);
932+
}
933+
}
934+
923935
/**
924936
* Assign installed language options and return their dashboard data.
925937
*

‎controller/main_controller.php‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ public function display()
116116

117117
$item_depth = count($open_categories);
118118

119+
// Build a stable compound number from sibling positions at every nesting level
120+
$compound_counters = array_slice($compound_counters, 0, $item_depth + 1);
121+
$compound_counters[$item_depth] = isset($compound_counters[$item_depth]) ? $compound_counters[$item_depth] + 1 : 1;
122+
$compound_number = implode('.', $compound_counters);
123+
119124
if ($entity->get_right_id() - $entity->get_left_id() > 1)
120125
{
121126
// Rule categories
@@ -131,7 +136,7 @@ public function display()
131136
{
132137
// Rules
133138
$is_category = false;
134-
$anchor = $entity->get_anchor() ?: $this->lang->lang('BOARDRULES_RULE_ANCHOR', ($cat_counter - 1) . $rule_counter);
139+
$anchor = $entity->get_anchor() ?: $this->lang->lang('BOARDRULES_RULE_ANCHOR', $item_depth ? ($cat_counter - 1) . $rule_counter : $compound_number);
135140

136141
// Increment rule counter
137142
$rule_counter++;
@@ -141,11 +146,6 @@ public function display()
141146
// one-based display depth; rules use the containing category count.
142147
$depth = $is_category ? $item_depth + 1 : $item_depth;
143148

144-
// Build a stable compound number from sibling positions at every nesting level
145-
$compound_counters = array_slice($compound_counters, 0, $item_depth + 1);
146-
$compound_counters[$item_depth] = isset($compound_counters[$item_depth]) ? $compound_counters[$item_depth] + 1 : 1;
147-
$compound_number = implode('.', $compound_counters);
148-
149149
// Assign values to template vars for this rule entity
150150
$this->template->assign_block_vars('rules', array(
151151
'TITLE' => $entity->get_title(),

‎entity/rule.php‎

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ public function load($id)
8989
*
9090
* Used when the data is already loaded externally.
9191
* Any existing data on this rule is over-written.
92-
* All data is validated and an exception is thrown if any data is invalid.
92+
* Required fields and basic data types are validated. Values already loaded
93+
* from storage are not passed through write-time transformations again.
9394
*
9495
* @param array $data Data array, typically from the database
9596
* @return rule_interface $this object for chaining calls; load()->set()->save()
@@ -111,7 +112,7 @@ public function import($data)
111112
'rule_parent_id' => 'integer',
112113
'rule_parents' => 'string',
113114
'rule_anchor' => 'string',
114-
'rule_title' => 'set_title', // call set_title()
115+
'rule_title' => 'string',
115116

116117
// We do not pass to set_message() as generate_text_for_storage would run twice
117118
'rule_message' => 'string',
@@ -273,10 +274,13 @@ public function set_title($title)
273274
// Enforce a string
274275
$title = (string) $title;
275276

276-
$title = $this->encode_unicode_for_storage($title);
277+
// MSSQL string literals cannot safely preserve every BMP character.
278+
$title = strpos($this->db->get_sql_layer(), 'mssql') === 0
279+
? utf8_encode_ncr($title)
280+
: utf8_encode_ucr($title);
277281

278-
// Limit both the displayed and stored title lengths to the column size.
279-
if (truncate_string($title, 200, 200) !== $title)
282+
// Enforce the database column length after storage encoding.
283+
if (utf8_strlen($title) > 200)
280284
{
281285
throw new \phpbb\boardrules\exception\unexpected_value(array('title', 'TOO_LONG'));
282286
}
@@ -287,22 +291,6 @@ public function set_title($title)
287291
return $this;
288292
}
289293

290-
/**
291-
* Encode Unicode characters that cannot be stored safely by the DBMS.
292-
*
293-
* @param string $text
294-
* @return string
295-
*/
296-
protected function encode_unicode_for_storage($text)
297-
{
298-
if (strpos($this->db->get_sql_layer(), 'mssql') === 0)
299-
{
300-
return utf8_encode_ncr($text);
301-
}
302-
303-
return utf8_encode_ucr($text);
304-
}
305-
306294
/**
307295
* Get message for edit
308296
*
@@ -497,31 +485,39 @@ public function set_anchor($anchor)
497485
{
498486
// Enforce a string
499487
$anchor = (string) $anchor;
488+
$rule_id = $this->get_id();
500489

501-
// Anchors must begin with a letter and contain only URL-friendly
502-
// letters, marks, numbers, hyphens, and underscores. Four-byte
503-
// characters are rejected even when their Unicode category matches.
504-
if ($anchor !== '' && !preg_match('/^(?!.*[\x{10000}-\x{10FFFF}])\p{L}[\p{L}\p{M}\p{N}_-]*$/u', $anchor))
490+
// Existing anchors may predate current validation rules.
491+
if ($rule_id && $this->get_anchor() === $anchor)
505492
{
506-
throw new \phpbb\boardrules\exception\unexpected_value(array('anchor', 'ILLEGAL_CHARACTERS'));
493+
return $this;
507494
}
508495

509-
// Limit both the displayed and stored anchor lengths to the column size.
510-
if (truncate_string($anchor, 255, 255) !== $anchor)
496+
if ($anchor !== '')
511497
{
512-
throw new \phpbb\boardrules\exception\unexpected_value(array('anchor', 'TOO_LONG'));
513-
}
498+
// HTML5 IDs allow broader values, but these are also URL fragments.
499+
// Restrict them to BMP letters, marks, numbers, hyphens, and underscores.
500+
if (!preg_match('/^(?!.*[\x{10000}-\x{10FFFF}])[\p{L}\p{N}_-][\p{L}\p{M}\p{N}_-]*$/u', $anchor))
501+
{
502+
throw new \phpbb\boardrules\exception\unexpected_value(array('anchor', 'ILLEGAL_CHARACTERS'));
503+
}
514504

515-
// Make sure rule anchors are unique for the current language
516-
// Test if new page and anchor field has data or...
517-
// if existing page and anchor field has new data not equal to existing anchor data
518-
if ((!$this->get_id() && $anchor !== '') || ($this->get_id() && $anchor !== '' && $this->get_anchor() !== $anchor))
519-
{
505+
if (utf8_strlen($anchor) > 255)
506+
{
507+
throw new \phpbb\boardrules\exception\unexpected_value(array('anchor', 'TOO_LONG'));
508+
}
509+
510+
// Make sure the anchor is unique for the current language.
520511
$sql = 'SELECT 1
521512
FROM ' . $this->boardrules_table . "
522513
WHERE rule_anchor = '" . $this->db->sql_escape($anchor) . "'
523-
AND rule_id <> " . $this->get_id() .
524-
($this->get_language() ? " AND rule_language = '" . $this->db->sql_escape($this->get_language()) . "'" : '');
514+
AND rule_id <> " . $rule_id;
515+
$language = $this->get_language();
516+
if ($language !== '')
517+
{
518+
$sql .= " AND rule_language = '" . $this->db->sql_escape($language) . "'";
519+
}
520+
525521
$result = $this->db->sql_query_limit($sql, 1);
526522
$row = $this->db->sql_fetchrow($result);
527523
$this->db->sql_freeresult($result);

‎exception/base.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class base extends \Exception
3333
* @param \Exception|null $previous
3434
* @access public
3535
*/
36-
public function __construct($message = null, $code = 0, \Exception|null $previous = null)
36+
public function __construct($message = null, $code = 0, ?\Exception $previous = null)
3737
{
3838
parent::__construct();
3939

‎language/ar/boardrules_acp.php‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
'ACP_BOARDRULES_DRAFT_NOTICE' => 'هذه القوانين غير مرئية للمستخدمين. يرى المستخدمون حالياً القوانين المكتوبة باللغة الافتراضية للمنتدى.',
9292
'ACP_BOARDRULES_DRAFT_DEFAULT_NOTICE' => 'هذه القوانين غير مرئية للمستخدمين. انشرها لإتاحة قوانين المنتدى الافتراضية.',
9393
'ACP_BOARDRULES_COPY_RULESET' => 'نسخ مجموعة قوانين اللغة',
94-
'ACP_BOARDRULES_COPY_RULESET_EXPLAIN' => 'انسخ كل الفئات والقوانين إلى <strong>%s</strong>. ستُضاف القوانين المنسوخة بعد أي قوانين موجودة، وستظل مجموعة القوانين الكاملة في اللغة الهدف مسودة حتى تنشرها.',
94+
'ACP_BOARDRULES_COPY_RULESET_EXPLAIN' => 'انسخ كل الفئات والقوانين إلى <strong>%s</strong>. ستُضاف القوانين المنسوخة بعد أي قوانين موجودة، وسيتم تعيين مجموعة القوانين الكاملة في اللغة الهدف كمسودة حتى تنشرها.',
9595
'ACP_BOARDRULES_COPY_APPEND' => 'إضافة إلى القوانين الموجودة',
9696
'ACP_BOARDRULES_COPY_APPEND_EXPLAIN' => array(
9797
1 => 'تحتوي اللغة الهدف حالياً على %d قانون. سيبقى دون تغيير، وستُضاف القوانين المنسوخة بعده. ستُضاف لاحقة رقمية إلى المراسي المنسوخة المتعارضة.',
@@ -152,10 +152,8 @@
152152
'ACP_RULE_MESSAGE_EXPLAIN' => 'محتوى كل قانون على حده يظهر في صفحة القوانين ( يتم تعطيل هذا الخيار في الأقسام ).',
153153
'ACP_RULE_MESSAGE_DISABLED' => 'هذا القسم يحتوي على قوانين , وبالتالي يتم تعطيل المحتوى ( محرر الكتابة ).',
154154
'ACP_ADD_RULE' => 'إنشاء قانون جديد ',
155-
'ACP_DELETE_RULE_CONFIRM' => array(
156-
0 => 'متأكد أنك تريد حذف هذا القانون ؟',
157-
1 => 'متأكد أنك تريد حذف هذا القانون ؟<br>تحذير : حذف قسم يعني حذف جميع القوانين الموجودة فيه أيضاً.',
158-
),
155+
'ACP_DELETE_RULE_CONFIRM' => 'متأكد أنك تريد حذف هذا القانون ؟',
156+
'ACP_DELETE_RULE_CATEGORY_CONFIRM' => 'متأكد أنك تريد حذف هذا القانون ؟<br />تحذير : حذف قسم يعني حذف جميع القوانين الموجودة فيه أيضاً.',
159157
'ACP_RULE_ADDED' => 'تم إضافة القانون بنجاح.',
160158
'ACP_RULE_DELETED' => 'تم حذف القانون بنجاح.',
161159
'ACP_RULE_EDITED' => 'تم تعديل القانون بنجاح.',

‎language/bg/boardrules_acp.php‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
'ACP_BOARDRULES_DRAFT_NOTICE' => 'Тези правила не са видими за потребителите. В момента потребителите виждат правилата на езика по подразбиране на форума.',
9191
'ACP_BOARDRULES_DRAFT_DEFAULT_NOTICE' => 'Тези правила не са видими за потребителите. Публикувайте ги, за да направите правилата по подразбиране на форума достъпни.',
9292
'ACP_BOARDRULES_COPY_RULESET' => 'Копирай набора от правила на езика',
93-
'ACP_BOARDRULES_COPY_RULESET_EXPLAIN' => 'Копира всяка категория и правило в <strong>%s</strong>. Копираните правила се добавят след съществуващите, а пълният целеви набор остава чернова, докато не го публикувате.',
93+
'ACP_BOARDRULES_COPY_RULESET_EXPLAIN' => 'Копира всяка категория и правило в <strong>%s</strong>. Копираните правила се добавят след съществуващите, а пълният целеви набор ще бъде зададен като чернова, докато не го публикувате.',
9494
'ACP_BOARDRULES_COPY_APPEND' => 'Добави към съществуващите правила',
9595
'ACP_BOARDRULES_COPY_APPEND_EXPLAIN' => array(
9696
1 => 'В момента целта съдържа %d правило. То ще остане непроменено, а копираните правила ще бъдат добавени след него. Конфликтните копирани котви ще получат цифров суфикс.',
@@ -136,10 +136,8 @@
136136
'ACP_RULE_MESSAGE_EXPLAIN' => 'Съобщението на Правилото се показва на страницата на правилата за всяко правило (Категориите не показват съобщение за правилото).',
137137
'ACP_RULE_MESSAGE_DISABLED' => 'Тази категория съдържа правила, които текстовият редактор е забранил.',
138138
'ACP_ADD_RULE' => 'Създай ново правило',
139-
'ACP_DELETE_RULE_CONFIRM' => array(
140-
0 => 'Сигурни ли сте, че искате да изтриете това правило?',
141-
1 => 'Сигурни ли сте, че искате да изтриете това правило?<br>Предупреждение: Премахвайки категория правила, ще премахнете и всички правила, които тя съдържа.',
142-
),
139+
'ACP_DELETE_RULE_CONFIRM' => 'Сигурни ли сте, че искате да изтриете това правило?',
140+
'ACP_DELETE_RULE_CATEGORY_CONFIRM' => 'Сигурни ли сте, че искате да изтриете това правило?<br />Предупреждение: Премахвайки категория правила, ще премахнете и всички правила, които тя съдържа.',
143141
'ACP_RULE_ADDED' => 'Правилото успешно добавено.',
144142
'ACP_RULE_DELETED' => 'Правилото успешно изтрито.',
145143
'ACP_RULE_EDITED' => 'Правилото успешно редактирано.',

‎language/cs/boardrules_acp.php‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
'ACP_BOARDRULES_DRAFT_NOTICE' => 'Tato pravidla nejsou pro uživatele viditelná. Uživatelé nyní vidí pravidla ve výchozím jazyce fóra.',
9191
'ACP_BOARDRULES_DRAFT_DEFAULT_NOTICE' => 'Tato pravidla nejsou pro uživatele viditelná. Zveřejněte je, aby byla výchozí pravidla fóra dostupná.',
9292
'ACP_BOARDRULES_COPY_RULESET' => 'Kopírovat jazykovou sadu pravidel',
93-
'ACP_BOARDRULES_COPY_RULESET_EXPLAIN' => 'Zkopíruje všechny kategorie a pravidla do <strong>%s</strong>. Zkopírovaná pravidla se přidají za stávající pravidla a celá cílová sada zůstane konceptem, dokud ji nezveřejníte.',
93+
'ACP_BOARDRULES_COPY_RULESET_EXPLAIN' => 'Zkopíruje všechny kategorie a pravidla do <strong>%s</strong>. Zkopírovaná pravidla se přidají za stávající pravidla a celá cílová sada bude nastavena jako koncept, dokud ji nezveřejníte.',
9494
'ACP_BOARDRULES_COPY_APPEND' => 'Přidat ke stávajícím pravidlům',
9595
'ACP_BOARDRULES_COPY_APPEND_EXPLAIN' => array(
9696
1 => 'Cíl nyní obsahuje %d pravidlo. Zůstane beze změny a zkopírovaná pravidla budou přidána za něj. Konfliktní zkopírované odkazy dostanou číselnou příponu.',
@@ -140,10 +140,8 @@
140140
'ACP_RULE_MESSAGE_EXPLAIN' => 'Obsah pravidla je zobrazen u každého z pravidel (toto pole je u kategorií ignorováno).',
141141
'ACP_RULE_MESSAGE_DISABLED' => 'Toto je kategorie pravidel, proto není možné pravidlo upravovat.',
142142
'ACP_ADD_RULE' => 'Vytvořit nové pravidlo',
143-
'ACP_DELETE_RULE_CONFIRM' => array(
144-
0 => 'Opravdu chcete smazat toto pravidlo?',
145-
1 => 'Opravdu chcete smazat toto pravidlo?<br>Varování: Smazáním kategorie odstraníte také všechna vnořená pravidla.',
146-
),
143+
'ACP_DELETE_RULE_CONFIRM' => 'Opravdu chcete smazat toto pravidlo?',
144+
'ACP_DELETE_RULE_CATEGORY_CONFIRM' => 'Opravdu chcete smazat toto pravidlo?<br />Varování: Smazáním kategorie odstraníte také všechna vnořená pravidla.',
147145
'ACP_RULE_ADDED' => 'Pravidlo úspěšně přidáno.',
148146
'ACP_RULE_DELETED' => 'Pravidlo úspěšně odstraněno.',
149147
'ACP_RULE_EDITED' => 'Pravidlo úspěšně upraveno.',

0 commit comments

Comments
 (0)