aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml3
-rw-r--r--phpBB/adm/style/acp_posting_buttons.html1
-rw-r--r--phpBB/docs/events.md63
-rw-r--r--phpBB/includes/functions_download.php2
-rw-r--r--phpBB/includes/mcp/mcp_forum.php2
-rw-r--r--phpBB/includes/mcp/mcp_main.php18
-rw-r--r--phpBB/install/database_update.php7
-rw-r--r--phpBB/language/en/acp/search.php2
-rw-r--r--phpBB/language/en/migrator.php4
-rw-r--r--phpBB/language/en/posting.php10
-rw-r--r--phpBB/phpbb/content_visibility.php112
-rw-r--r--phpBB/phpbb/db/migration/helper.php32
-rw-r--r--phpBB/phpbb/db/migration/tool/config.php5
-rw-r--r--phpBB/phpbb/db/migration/tool/config_text.php5
-rw-r--r--phpBB/phpbb/db/migration/tool/module.php188
-rw-r--r--phpBB/phpbb/db/migration/tool/permission.php5
-rw-r--r--phpBB/phpbb/db/migrator.php169
-rw-r--r--phpBB/phpbb/db/migrator_output_handler_interface.php10
-rw-r--r--phpBB/phpbb/notification/method/messenger_base.php2
-rw-r--r--phpBB/phpbb/search/fulltext_mysql.php4
-rw-r--r--phpBB/phpbb/search/fulltext_native.php2
-rw-r--r--phpBB/phpbb/session.php2
-rw-r--r--phpBB/posting.php1
-rw-r--r--phpBB/search.php20
-rw-r--r--phpBB/styles/prosilver/template/confirm_delete_body.html4
-rw-r--r--phpBB/styles/prosilver/template/mcp_topic.html5
-rw-r--r--phpBB/styles/prosilver/template/posting_editor.html6
-rw-r--r--phpBB/styles/prosilver/template/posting_topic_review.html3
-rw-r--r--phpBB/styles/prosilver/template/viewforum_body.html4
-rw-r--r--phpBB/styles/subsilver2/template/mcp_topic.html4
-rw-r--r--phpBB/styles/subsilver2/template/posting_body.html6
-rw-r--r--phpBB/styles/subsilver2/template/posting_topic_review.html2
-rw-r--r--phpBB/styles/subsilver2/template/viewforum_body.html4
-rw-r--r--tests/dbal/fixtures/migrator_module.xml54
-rw-r--r--tests/dbal/migration/if.php4
-rw-r--r--tests/dbal/migrator_test.php8
-rw-r--r--tests/dbal/migrator_tool_module_test.php38
-rw-r--r--tests/migrator/reverse_update_data_test.php56
38 files changed, 694 insertions, 173 deletions
diff --git a/.travis.yml b/.travis.yml
index 14cf3e6d6c..a46d825612 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -22,12 +22,9 @@ matrix:
env: DB=mysqli
- php: 5.6
env: DB=mysqli
- - php: 7.0
- env: DB=mysqli
- php: hhvm
env: DB=mysqli
allow_failures:
- - php: 7.0
- php: hhvm
fast_finish: true
diff --git a/phpBB/adm/style/acp_posting_buttons.html b/phpBB/adm/style/acp_posting_buttons.html
index 70b6259689..c3c42f8e82 100644
--- a/phpBB/adm/style/acp_posting_buttons.html
+++ b/phpBB/adm/style/acp_posting_buttons.html
@@ -63,6 +63,7 @@
<!-- ENDIF -->
<!-- ENDIF -->
</select>
+ <!-- EVENT acp_posting_buttons_custom_tags_before -->
<!-- BEGIN custom_tags -->
<input type="button" class="button2" name="addbbcode{custom_tags.BBCODE_ID}" value="{custom_tags.BBCODE_TAG}" onclick="bbstyle({custom_tags.BBCODE_ID})" title="{custom_tags.BBCODE_HELPLINE}" />
<!-- END custom_tags -->
diff --git a/phpBB/docs/events.md b/phpBB/docs/events.md
index 0e71bf5c11..abe702eb25 100644
--- a/phpBB/docs/events.md
+++ b/phpBB/docs/events.md
@@ -343,6 +343,13 @@ acp_posting_buttons_before
* Since: 3.1.0-b4
* Purpose: Add content before BBCode posting buttons in the ACP
+acp_posting_buttons_custom_tags_before
+===
+* Locations:
+ + adm/style/acp_posting_buttons.html
+* Since: 3.1.10-RC1
+* Purpose: Add content before the custom BBCodes in the ACP
+
acp_profile_contact_before
===
* Locations:
@@ -875,6 +882,22 @@ mcp_topic_options_before
* Since: 3.1.6-RC1
* Purpose: Add some options (field, checkbox, ...) before the subject field when split a subject
+mcp_topic_postrow_post_details_after
+===
+* Locations:
+ + styles/prosilver/template/mcp_topic.html
+ + styles/subsilver2/template/mcp_topic.html
+* Since: 3.1.10-RC1
+* Purpose: Add content after post details in topic moderation
+
+mcp_topic_postrow_post_details_before
+===
+* Locations:
+ + styles/prosilver/template/mcp_topic.html
+ + styles/subsilver2/template/mcp_topic.html
+* Since: 3.1.10-RC1
+* Purpose: Add content before post details in topic moderation
+
mcp_topic_topic_title_after
===
* Locations:
@@ -1503,6 +1526,14 @@ posting_editor_subject_after
* Since: 3.1.0-a2
* Purpose: Add field (e.g. textbox) to the posting screen after the subject
+posting_editor_subject_append
+===
+* Locations:
+ + styles/prosilver/template/posting_editor.html
+ + styles/subsilver2/template/posting_body.html
+* Since: 3.1.10-RC1
+* Purpose: Add field, text, etc. to the posting after the subject text box
+
posting_editor_subject_before
===
* Locations:
@@ -1511,6 +1542,14 @@ posting_editor_subject_before
* Since: 3.1.0-a2
* Purpose: Add field (e.g. textbox) to the posting screen before the subject
+posting_editor_subject_prepend
+===
+* Locations:
+ + styles/prosilver/template/posting_editor.html
+ + styles/subsilver2/template/posting_body.html
+* Since: 3.1.10-RC1
+* Purpose: Add field, text, etc. to the posting before the subject text box
+
posting_editor_submit_buttons
===
* Locations:
@@ -1572,6 +1611,22 @@ posting_preview_poll_after
* Since: 3.1.7-RC1
* Purpose: Add content after the poll preview block
+posting_topic_review_row_post_details_after
+===
+* Locations:
+ + styles/prosilver/template/posting_topic_review.html
+ + styles/subsilver2/template/posting_topic_review.html
+* Since: 3.1.10-RC1
+* Purpose: Add content after post details in topic review
+
+posting_topic_review_row_post_details_before
+===
+* Locations:
+ + styles/prosilver/template/posting_topic_review.html
+ + styles/subsilver2/template/posting_topic_review.html
+* Since: 3.1.10-RC1
+* Purpose: Add content before post details in topic review
+
posting_topic_title_after
===
* Locations:
@@ -2255,6 +2310,14 @@ viewforum_body_topic_row_prepend
* Since: 3.1.7-RC1
* Purpose: Add content at the end of the topic list item.
+viewforum_body_topicrow_row_before
+===
+* Locations:
+ + styles/prosilver/template/viewforum_body.html
+ + styles/subsilver2/template/viewforum_body.html
+* Since: 3.1.10-RC1
+* Purpose: Add content before list of topics.
+
viewforum_buttons_bottom_before
===
* Locations:
diff --git a/phpBB/includes/functions_download.php b/phpBB/includes/functions_download.php
index 2c6f62227c..c571de579e 100644
--- a/phpBB/includes/functions_download.php
+++ b/phpBB/includes/functions_download.php
@@ -284,7 +284,7 @@ function header_filename($file)
// There be dragons here.
// Not many follows the RFC...
- if (strpos($user_agent, 'MSIE') !== false || strpos($user_agent, 'Safari') !== false || strpos($user_agent, 'Konqueror') !== false)
+ if (strpos($user_agent, 'MSIE') !== false || strpos($user_agent, 'Konqueror') !== false)
{
return "filename=" . rawurlencode($file);
}
diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php
index 6faf0de35b..9573ecbe0d 100644
--- a/phpBB/includes/mcp/mcp_forum.php
+++ b/phpBB/includes/mcp/mcp_forum.php
@@ -273,7 +273,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
'TOPIC_ICON_IMG_WIDTH' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['width'] : '',
'TOPIC_ICON_IMG_HEIGHT' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['height'] : '',
'UNAPPROVED_IMG' => ($topic_unapproved || $posts_unapproved) ? $user->img('icon_topic_unapproved', ($topic_unapproved) ? 'TOPIC_UNAPPROVED' : 'POSTS_UNAPPROVED') : '',
- 'DELETED_IMG' => ($topic_deleted) ? $user->img('icon_topic_deleted', 'POSTS_DELETED') : '',
+ 'DELETED_IMG' => ($topic_deleted) ? $user->img('icon_topic_deleted', 'TOPIC_DELETED') : '',
'TOPIC_AUTHOR' => get_username_string('username', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
'TOPIC_AUTHOR_COLOUR' => get_username_string('colour', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php
index d0908a0d8b..b2441aed1b 100644
--- a/phpBB/includes/mcp/mcp_main.php
+++ b/phpBB/includes/mcp/mcp_main.php
@@ -877,11 +877,12 @@ function mcp_delete_topic($topic_ids, $is_soft = false, $soft_delete_reason = ''
}
$template->assign_vars(array(
- 'S_SHADOW_TOPICS' => $only_shadow,
- 'S_SOFTDELETED' => $only_softdeleted,
- 'S_TOPIC_MODE' => true,
- 'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id),
- 'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id),
+ 'S_SHADOW_TOPICS' => $only_shadow,
+ 'S_SOFTDELETED' => $only_softdeleted,
+ 'S_TOPIC_MODE' => true,
+ 'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id),
+ 'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id),
+ 'DELETE_TOPIC_PERMANENTLY_EXPLAIN' => $user->lang('DELETE_TOPIC_PERMANENTLY', sizeof($topic_ids)),
));
$l_confirm = (sizeof($topic_ids) == 1) ? 'DELETE_TOPIC' : 'DELETE_TOPICS';
@@ -1116,9 +1117,10 @@ function mcp_delete_post($post_ids, $is_soft = false, $soft_delete_reason = '',
}
$template->assign_vars(array(
- 'S_SOFTDELETED' => $only_softdeleted,
- 'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id),
- 'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id),
+ 'S_SOFTDELETED' => $only_softdeleted,
+ 'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id),
+ 'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id),
+ 'DELETE_POST_PERMANENTLY_EXPLAIN' => $user->lang('DELETE_POST_PERMANENTLY', sizeof($post_ids)),
));
$l_confirm = (sizeof($post_ids) == 1) ? 'DELETE_POST' : 'DELETE_POSTS';
diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php
index 0ea6eeffd7..f367ae1fc0 100644
--- a/phpBB/install/database_update.php
+++ b/phpBB/install/database_update.php
@@ -211,13 +211,6 @@ while (!$migrator->finished())
phpbb_end_update($cache, $config);
}
- $state = array_merge(array(
- 'migration_schema_done' => false,
- 'migration_data_done' => false,
- ),
- $migrator->last_run_migration['state']
- );
-
// Are we approaching the time limit? If so we want to pause the update and continue after refreshing
if ((time() - $update_start_time) >= $safe_time_limit)
{
diff --git a/phpBB/language/en/acp/search.php b/phpBB/language/en/acp/search.php
index bda965b615..c52b71c121 100644
--- a/phpBB/language/en/acp/search.php
+++ b/phpBB/language/en/acp/search.php
@@ -54,7 +54,7 @@ $lang = array_merge($lang, array(
'DELETING_INDEX_IN_PROGRESS_EXPLAIN' => 'The search backend is currently cleaning its index. This can take a few minutes.',
'FULLTEXT_MYSQL_INCOMPATIBLE_DATABASE' => 'The MySQL fulltext backend can only be used with MySQL4 and above.',
- 'FULLTEXT_MYSQL_NOT_SUPPORTED' => 'MySQL fulltext indexes can only be used with MyISAM or InnoDB tables. MySQL 5.6.4 or later is required for fulltext indexes on InnoDB tables.',
+ 'FULLTEXT_MYSQL_NOT_SUPPORTED' => 'MySQL fulltext indexes can only be used with MyISAM or InnoDB tables. MySQL 5.6.8 or later is required for fulltext indexes on InnoDB tables.',
'FULLTEXT_MYSQL_TOTAL_POSTS' => 'Total number of indexed posts',
'FULLTEXT_MYSQL_MIN_SEARCH_CHARS_EXPLAIN' => 'Words with at least this many characters will be indexed for searching. You or your host can only change this setting by changing the mysql configuration.',
'FULLTEXT_MYSQL_MAX_SEARCH_CHARS_EXPLAIN' => 'Words with no more than this many characters will be indexed for searching. You or your host can only change this setting by changing the mysql configuration.',
diff --git a/phpBB/language/en/migrator.php b/phpBB/language/en/migrator.php
index 244a5faadf..b3b5995cc0 100644
--- a/phpBB/language/en/migrator.php
+++ b/phpBB/language/en/migrator.php
@@ -50,6 +50,7 @@ $lang = array_merge($lang, array(
'MIGRATION_NOT_FULFILLABLE' => 'The migration "%1$s" is not fulfillable, missing migration "%2$s".',
'MIGRATION_NOT_VALID' => '%s is not a valid migration.',
'MIGRATION_SCHEMA_DONE' => 'Installed Schema: %1$s; Time: %2$.2f seconds',
+ 'MIGRATION_SCHEMA_IN_PROGRESS' => 'Installing Schema: %1$s; Time: %2$.2f seconds',
'MIGRATION_SCHEMA_RUNNING' => 'Installing Schema: %s.',
'MIGRATION_INVALID_DATA_MISSING_CONDITION' => 'A migration is invalid. An if statement helper is missing a condition.',
@@ -60,9 +61,12 @@ $lang = array_merge($lang, array(
'MIGRATION_INVALID_DATA_UNDEFINED_METHOD' => 'A migration is invalid. An undefined migration tool method was encountered.',
'MODULE_ERROR' => 'An error occurred while creating a module: %s',
+ 'MODULE_EXISTS' => 'A module already exists: %s',
+ 'MODULE_EXIST_MULTIPLE' => 'Several modules with the given parent module langname already exist: %s. Try using before/after keys to clarify the module placement.',
'MODULE_INFO_FILE_NOT_EXIST' => 'A required module info file is missing: %2$s',
'MODULE_NOT_EXIST' => 'A required module does not exist: %s',
+ 'PARENT_MODULE_FIND_ERROR' => 'Unable to determine the parent module identifier: %s',
'PERMISSION_NOT_EXIST' => 'The permission setting "%s" unexpectedly does not exist.',
'ROLE_NOT_EXIST' => 'The permission role "%s" unexpectedly does not exist.',
diff --git a/phpBB/language/en/posting.php b/phpBB/language/en/posting.php
index 924395ed44..ef52f59753 100644
--- a/phpBB/language/en/posting.php
+++ b/phpBB/language/en/posting.php
@@ -90,14 +90,20 @@ $lang = array_merge($lang, array(
'DELETE_PERMANENTLY' => 'Delete permanently',
'DELETE_POST_CONFIRM' => 'Are you sure you want to delete this post?',
'DELETE_POST_PERMANENTLY_CONFIRM' => 'Are you sure you want to <strong>permanently</strong> delete this post?',
- 'DELETE_POST_PERMANENTLY' => 'Permanently delete this post so it can not be recovered',
+ 'DELETE_POST_PERMANENTLY' => array(
+ 1 => 'Permanently delete this post so it can not be recovered',
+ 2 => 'Permanently delete %1$d posts so they can not be recovered',
+ ),
'DELETE_POSTS_CONFIRM' => 'Are you sure you want to delete these posts?',
'DELETE_POSTS_PERMANENTLY_CONFIRM' => 'Are you sure you want to <strong>permanently</strong> delete these posts?',
'DELETE_REASON' => 'Reason for deletion',
'DELETE_REASON_EXPLAIN' => 'The specified reason for deletion will be visible to moderators.',
'DELETE_POST_WARN' => 'Delete this post',
'DELETE_TOPIC_CONFIRM' => 'Are you sure you want to delete this topic?',
- 'DELETE_TOPIC_PERMANENTLY' => 'Permanently delete this topic so it can not be recovered',
+ 'DELETE_TOPIC_PERMANENTLY' => array(
+ 1 => 'Permanently delete this topic so it can not be recovered',
+ 2 => 'Permanently delete %1$d topics so they can not be recovered',
+ ),
'DELETE_TOPIC_PERMANENTLY_CONFIRM' => 'Are you sure you want to <strong>permanently</strong> delete this topic?',
'DELETE_TOPICS_CONFIRM' => 'Are you sure you want to delete these topics?',
'DELETE_TOPICS_PERMANENTLY_CONFIRM' => 'Are you sure you want to <strong>permanently</strong> delete these topics?',
diff --git a/phpBB/phpbb/content_visibility.php b/phpBB/phpbb/content_visibility.php
index 147b8ebbff..bf7dc2c703 100644
--- a/phpBB/phpbb/content_visibility.php
+++ b/phpBB/phpbb/content_visibility.php
@@ -428,7 +428,35 @@ class content_visibility
'post_delete_time' => ((int) $time) ?: time(),
'post_delete_reason' => truncate_string($reason, 255, 255, false),
);
-
+ /**
+ * Perform actions right before the query to change post visibility
+ *
+ * @event core.set_post_visibility_before_sql
+ * @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
+ * @var array post_id Array containing all post IDs to be modified. If blank, all posts within the topic are modified.
+ * @var int topic_id Topic of the post IDs to be modified.
+ * @var int forum_id Forum ID that the topic_id resides in.
+ * @var int user_id User ID doing this action.
+ * @var int timestamp Timestamp of this action.
+ * @var string reason Reason specified by the user for this change.
+ * @var bool is_starter Are we changing the topic's starter?
+ * @var bool is_latest Are we changing the topic's latest post?
+ * @var array data The data array for this action.
+ * @since 3.1.10-RC1
+ */
+ $vars = array(
+ 'visibility',
+ 'post_id',
+ 'topic_id',
+ 'forum_id',
+ 'user_id',
+ 'timestamp',
+ 'reason',
+ 'is_starter',
+ 'is_latest',
+ 'data',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.set_post_visibility_before_sql', compact($vars)));
$sql = 'UPDATE ' . $this->posts_table . '
SET ' . $this->db->sql_build_array('UPDATE', $data) . '
WHERE ' . $this->db->sql_in_set('post_id', $post_ids);
@@ -585,7 +613,35 @@ class content_visibility
WHERE topic_id = ' . (int) $topic_id;
$this->db->sql_query($sql);
}
-
+ /**
+ * Perform actions after all steps to changing post visibility
+ *
+ * @event core.set_post_visibility_after
+ * @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
+ * @var array post_id Array containing all post IDs to be modified. If blank, all posts within the topic are modified.
+ * @var int topic_id Topic of the post IDs to be modified.
+ * @var int forum_id Forum ID that the topic_id resides in.
+ * @var int user_id User ID doing this action.
+ * @var int timestamp Timestamp of this action.
+ * @var string reason Reason specified by the user for this change.
+ * @var bool is_starter Are we changing the topic's starter?
+ * @var bool is_latest Are we changing the topic's latest post?
+ * @var array data The data array for this action.
+ * @since 3.1.10-RC1
+ */
+ $vars = array(
+ 'visibility',
+ 'post_id',
+ 'topic_id',
+ 'forum_id',
+ 'user_id',
+ 'timestamp',
+ 'reason',
+ 'is_starter',
+ 'is_latest',
+ 'data',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.set_post_visibility_after', compact($vars)));
return $data;
}
@@ -645,7 +701,31 @@ class content_visibility
'topic_delete_time' => ((int) $time) ?: time(),
'topic_delete_reason' => truncate_string($reason, 255, 255, false),
);
-
+ /**
+ * Perform actions right before the query to change topic visibility
+ *
+ * @event core.set_topic_visibility_before_sql
+ * @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
+ * @var int topic_id Topic of the post IDs to be modified.
+ * @var int forum_id Forum ID that the topic_id resides in.
+ * @var int user_id User ID doing this action.
+ * @var int timestamp Timestamp of this action.
+ * @var string reason Reason specified by the user for this change.
+ * @var bool force_update_all Force an update on all posts within the topic, regardless of their current approval state.
+ * @var array data The data array for this action.
+ * @since 3.1.10-RC1
+ */
+ $vars = array(
+ 'visibility',
+ 'topic_id',
+ 'forum_id',
+ 'user_id',
+ 'timestamp',
+ 'reason',
+ 'force_update_all',
+ 'data',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.set_topic_visibility_before_sql', compact($vars)));
$sql = 'UPDATE ' . $this->topics_table . '
SET ' . $this->db->sql_build_array('UPDATE', $data) . '
WHERE topic_id = ' . (int) $topic_id;
@@ -670,7 +750,31 @@ class content_visibility
{
$this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true);
}
-
+ /**
+ * Perform actions after all steps to changing topic visibility
+ *
+ * @event core.set_topic_visibility_after
+ * @var int visibility Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
+ * @var int topic_id Topic of the post IDs to be modified.
+ * @var int forum_id Forum ID that the topic_id resides in.
+ * @var int user_id User ID doing this action.
+ * @var int timestamp Timestamp of this action.
+ * @var string reason Reason specified by the user for this change.
+ * @var bool force_update_all Force an update on all posts within the topic, regardless of their current approval state.
+ * @var array data The data array for this action.
+ * @since 3.1.10-RC1
+ */
+ $vars = array(
+ 'visibility',
+ 'topic_id',
+ 'forum_id',
+ 'user_id',
+ 'timestamp',
+ 'reason',
+ 'force_update_all',
+ 'data',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.set_topic_visibility_after', compact($vars)));
return $data;
}
diff --git a/phpBB/phpbb/db/migration/helper.php b/phpBB/phpbb/db/migration/helper.php
index e40deeb37b..bce2efff51 100644
--- a/phpBB/phpbb/db/migration/helper.php
+++ b/phpBB/phpbb/db/migration/helper.php
@@ -81,4 +81,36 @@ class helper
return $steps;
}
+
+ /**
+ * Reverse the update steps from an array of data changes
+ *
+ * 'If' statements and custom methods will be skipped, for all
+ * other calls the reverse method of the tool class will be called
+ *
+ * @param array $steps Update changes from migration
+ *
+ * @return array
+ */
+ public function reverse_update_data($steps)
+ {
+ $reversed_array = array();
+
+ foreach ($steps as $step)
+ {
+ $parts = explode('.', $step[0]);
+ $parameters = $step[1];
+
+ $class = $parts[0];
+ $method = isset($parts[1]) ? $parts[1] : false;
+
+ if ($class !== 'if' && $class !== 'custom')
+ {
+ array_unshift($parameters, $method);
+ $reversed_array[] = array($class . '.reverse', $parameters);
+ }
+ }
+
+ return array_reverse($reversed_array);
+ }
}
diff --git a/phpBB/phpbb/db/migration/tool/config.php b/phpBB/phpbb/db/migration/tool/config.php
index f93e7118c4..33aa8ff026 100644
--- a/phpBB/phpbb/db/migration/tool/config.php
+++ b/phpBB/phpbb/db/migration/tool/config.php
@@ -150,6 +150,11 @@ class config implements \phpbb\db\migration\tool\tool_interface
$arguments[0],
);
break;
+
+ case 'reverse':
+ // Reversing a reverse is just the call itself
+ $call = array_shift($arguments);
+ break;
}
if ($call)
diff --git a/phpBB/phpbb/db/migration/tool/config_text.php b/phpBB/phpbb/db/migration/tool/config_text.php
index bf8ac55023..54b45f6f6d 100644
--- a/phpBB/phpbb/db/migration/tool/config_text.php
+++ b/phpBB/phpbb/db/migration/tool/config_text.php
@@ -115,6 +115,11 @@ class config_text implements \phpbb\db\migration\tool\tool_interface
$arguments[] = '';
}
break;
+
+ case 'reverse':
+ // Reversing a reverse is just the call itself
+ $call = array_shift($arguments);
+ break;
}
if ($call)
diff --git a/phpBB/phpbb/db/migration/tool/module.php b/phpBB/phpbb/db/migration/tool/module.php
index 035625b095..6d5378e35f 100644
--- a/phpBB/phpbb/db/migration/tool/module.php
+++ b/phpBB/phpbb/db/migration/tool/module.php
@@ -36,6 +36,9 @@ class module implements \phpbb\db\migration\tool\tool_interface
/** @var string */
protected $modules_table;
+ /** @var array */
+ protected $module_categories = array();
+
/**
* Constructor
*
@@ -87,30 +90,8 @@ class module implements \phpbb\db\migration\tool\tool_interface
$parent_sql = '';
if ($parent !== false)
{
- // Allows '' to be sent as 0
- $parent = $parent ?: 0;
-
- if (!is_numeric($parent))
- {
- $sql = 'SELECT module_id
- FROM ' . $this->modules_table . "
- WHERE module_langname = '" . $this->db->sql_escape($parent) . "'
- AND module_class = '" . $this->db->sql_escape($class) . "'";
- $result = $this->db->sql_query($sql);
- $module_id = $this->db->sql_fetchfield('module_id');
- $this->db->sql_freeresult($result);
-
- if (!$module_id)
- {
- return false;
- }
-
- $parent_sql = 'AND parent_id = ' . (int) $module_id;
- }
- else
- {
- $parent_sql = 'AND parent_id = ' . (int) $parent;
- }
+ $parent = $this->get_parent_module_id($parent, $module);
+ $parent_sql = 'AND parent_id = ' . (int) $parent;
}
$sql = 'SELECT module_id
@@ -171,15 +152,14 @@ class module implements \phpbb\db\migration\tool\tool_interface
*/
public function add($class, $parent = 0, $data = array())
{
- // Allows '' to be sent as 0
- $parent = $parent ?: 0;
-
// allow sending the name as a string in $data to create a category
if (!is_array($data))
{
$data = array('module_langname' => $data);
}
+ $parent = $data['parent_id'] = $this->get_parent_module_id($parent, $data);
+
if (!isset($data['module_langname']))
{
// The "automatic" way
@@ -210,31 +190,14 @@ class module implements \phpbb\db\migration\tool\tool_interface
}
// The "manual" way
- if (!is_numeric($parent))
- {
- $sql = 'SELECT module_id
- FROM ' . $this->modules_table . "
- WHERE module_langname = '" . $this->db->sql_escape($parent) . "'
- AND module_class = '" . $this->db->sql_escape($class) . "'";
- $result = $this->db->sql_query($sql);
- $module_id = $this->db->sql_fetchfield('module_id');
- $this->db->sql_freeresult($result);
-
- if (!$module_id)
- {
- throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent);
- }
-
- $parent = $data['parent_id'] = $module_id;
- }
- else if (!$this->exists($class, false, $parent))
+ if (!$this->exists($class, false, $parent))
{
throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent);
}
if ($this->exists($class, $parent, $data['module_langname']))
{
- return;
+ throw new \phpbb\db\migration\exception('MODULE_EXISTS', $module_id);
}
if (!class_exists('acp_modules'))
@@ -373,26 +336,8 @@ class module implements \phpbb\db\migration\tool\tool_interface
$parent_sql = '';
if ($parent !== false)
{
- // Allows '' to be sent as 0
- $parent = ($parent) ?: 0;
-
- if (!is_numeric($parent))
- {
- $sql = 'SELECT module_id
- FROM ' . $this->modules_table . "
- WHERE module_langname = '" . $this->db->sql_escape($parent) . "'
- AND module_class = '" . $this->db->sql_escape($class) . "'";
- $result = $this->db->sql_query($sql);
- $module_id = $this->db->sql_fetchfield('module_id');
- $this->db->sql_freeresult($result);
-
- // we know it exists from the module_exists check
- $parent_sql = 'AND parent_id = ' . (int) $module_id;
- }
- else
- {
- $parent_sql = 'AND parent_id = ' . (int) $parent;
- }
+ $parent = $this->get_parent_module_id($parent, $module);
+ $parent_sql = 'AND parent_id = ' . (int) $parent;
}
$module_ids = array();
@@ -454,6 +399,11 @@ class module implements \phpbb\db\migration\tool\tool_interface
case 'remove':
$call = 'add';
break;
+
+ case 'reverse':
+ // Reversing a reverse is just the call itself
+ $call = array_shift($arguments);
+ break;
}
if ($call)
@@ -487,4 +437,110 @@ class module implements \phpbb\db\migration\tool\tool_interface
return array_pop($module);
}
+
+ /**
+ * Get the list of installed module categories
+ * key - module_id
+ * value - module_langname
+ *
+ * @return null
+ */
+ protected function get_categories_list()
+ {
+ // Select the top level categories
+ // and 2nd level [sub]categories which exist for ACP only
+ $sql = 'SELECT m2.module_id, m2.module_langname
+ FROM ' . $this->modules_table . ' m1, ' . $this->modules_table . " m2
+ WHERE m1.parent_id = 0
+ AND (m1.module_id = m2.module_id
+ OR m2.module_class = 'acp' AND m2.parent_id = m1.module_id)
+ ORDER BY m1.module_id, m2.module_id ASC";
+
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $this->module_categories[(int) $row['module_id']] = $row['module_langname'];
+ }
+ $this->db->sql_freeresult($result);
+ }
+
+ /**
+ * Get parent module id
+ *
+ * @param string|int $parent_id The parent module_id|module_langname
+ * @param int|string|array $data The module_id, module_langname for existance checking or module data array for adding
+ * @return int The parent module_id
+ * @throws \phpbb\db\migration\exception
+ */
+ public function get_parent_module_id($parent_id, $data = '')
+ {
+ // Allow '' to be sent as 0
+ $parent_id = $parent_id ?: 0;
+
+ // If automatic adding is in action, convert array back to string to simplify things
+ if (is_array($data) && sizeof($data) == 1)
+ {
+ $data = $data['module_langname'];
+ }
+
+ if (!is_numeric($parent_id))
+ {
+ // Refresh the $module_categories array
+ $this->get_categories_list();
+
+ // Search for the parent module_langname
+ $ids = array_keys($this->module_categories, $parent_id);
+
+ switch (sizeof($ids))
+ {
+ // No parent with the given module_langname exist
+ case 0:
+ throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent_id);
+ break;
+
+ // Return the module id
+ case 1:
+ $parent_id = (int) $ids[0];
+ break;
+
+ // Several modules with the given module_langname were found
+ // Try to determine the parent_id by the neighbour module parent
+ default:
+ if (is_array($data) && (isset($data['before']) || isset($data['after'])))
+ {
+ $neighbour_module_langname = isset($data['before']) ? $data['before'] : $data['after'];
+ $sql = 'SELECT parent_id
+ FROM ' . $this->modules_table . "
+ WHERE module_langname = '" . $this->db->sql_escape($neighbour_module_langname) . "'
+ AND " . $this->db->sql_in_set('parent_id', $ids);
+ $result = $this->db->sql_query($sql);
+ $parent_id = (int) $this->db->sql_fetchfield('parent_id');
+ if (!$parent_id)
+ {
+ throw new \phpbb\db\migration\exception('PARENT_MODULE_FIND_ERROR', $data['parent_id']);
+ }
+ }
+ else if (!empty($data) && !is_array($data))
+ {
+ // The module_langname is set, checking for the module existance
+ // As more than 1 parents were found already, there's no way for null parent_id here
+ $sql = 'SELECT m2.module_id as module_parent_id
+ FROM ' . $this->modules_table . ' m1, ' . $this->modules_table . " m2
+ WHERE " . ((is_numeric($data)) ? 'm1.module_id = ' . (int) $data : "m1.module_langname = '" . $this->db->sql_escape($data)) . "'
+ AND m2.module_id = m1.parent_id
+ AND " . $this->db->sql_in_set('m2.module_id', $ids);
+ $result = $this->db->sql_query($sql);
+ $parent_id = (int) $this->db->sql_fetchfield('module_parent_id');
+ }
+ else
+ {
+ //Unable to get the parent module id, throwing an exception
+ throw new \phpbb\db\migration\exception('MODULE_EXIST_MULTIPLE', $parent_id);
+ }
+ break;
+ }
+ }
+
+ return $parent_id;
+ }
}
diff --git a/phpBB/phpbb/db/migration/tool/permission.php b/phpBB/phpbb/db/migration/tool/permission.php
index ceff6d7d5a..9688420025 100644
--- a/phpBB/phpbb/db/migration/tool/permission.php
+++ b/phpBB/phpbb/db/migration/tool/permission.php
@@ -637,6 +637,11 @@ class permission implements \phpbb\db\migration\tool\tool_interface
$arguments[0],
);
break;
+
+ case 'reverse':
+ // Reversing a reverse is just the call itself
+ $call = array_shift($arguments);
+ break;
}
if ($call)
diff --git a/phpBB/phpbb/db/migrator.php b/phpBB/phpbb/db/migrator.php
index 7fc3e787e2..4c4c0a8672 100644
--- a/phpBB/phpbb/db/migrator.php
+++ b/phpBB/phpbb/db/migrator.php
@@ -80,14 +80,14 @@ class migrator
*
* @var array
*/
- public $last_run_migration = false;
+ protected $last_run_migration = false;
/**
* The output handler. A null handler is configured by default.
*
* @var migrator_output_handler_interface
*/
- public $output_handler;
+ protected $output_handler;
/**
* Constructor of the database migrator
@@ -152,6 +152,7 @@ class migrator
$this->migration_state[$migration['migration_name']] = $migration;
$this->migration_state[$migration['migration_name']]['migration_depends_on'] = unserialize($migration['migration_depends_on']);
+ $this->migration_state[$migration['migration_name']]['migration_data_state'] = !empty($migration['migration_data_state']) ? unserialize($migration['migration_data_state']) : '';
}
}
@@ -161,6 +162,19 @@ class migrator
}
/**
+ * Get an array with information about the last migration run.
+ *
+ * The array contains 'name', 'class' and 'state'. 'effectively_installed' is set
+ * and set to true if the last migration was effectively_installed.
+ *
+ * @return array
+ */
+ public function get_last_run_migration()
+ {
+ return $this->last_run_migration;
+ }
+
+ /**
* Sets the list of available migration class names to the given array.
*
* @param array $class_names An array of migration class names
@@ -297,38 +311,70 @@ class migrator
if (!$state['migration_schema_done'])
{
- $this->output_handler->write(array('MIGRATION_SCHEMA_RUNNING', $name), migrator_output_handler_interface::VERBOSITY_VERBOSE);
+ $verbosity = empty($state['migration_data_state']) ?
+ migrator_output_handler_interface::VERBOSITY_VERBOSE : migrator_output_handler_interface::VERBOSITY_DEBUG;
+ $this->output_handler->write(array('MIGRATION_SCHEMA_RUNNING', $name), $verbosity);
$this->last_run_migration['task'] = 'process_schema_step';
+
+ $total_time = (is_array($state['migration_data_state']) && isset($state['migration_data_state']['_total_time'])) ?
+ $state['migration_data_state']['_total_time'] : 0.0;
$elapsed_time = microtime(true);
+
$steps = $this->helper->get_schema_steps($migration->update_schema());
$result = $this->process_data_step($steps, $state['migration_data_state']);
+
$elapsed_time = microtime(true) - $elapsed_time;
+ $total_time += $elapsed_time;
+
+ if (is_array($result))
+ {
+ $result['_total_time'] = $total_time;
+ }
$state['migration_data_state'] = ($result === true) ? '' : $result;
$state['migration_schema_done'] = ($result === true);
- $this->output_handler->write(array('MIGRATION_SCHEMA_DONE', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_NORMAL);
+ if ($state['migration_schema_done'])
+ {
+ $this->output_handler->write(array('MIGRATION_SCHEMA_DONE', $name, $total_time), migrator_output_handler_interface::VERBOSITY_NORMAL);
+ }
+ else
+ {
+ $this->output_handler->write(array('MIGRATION_SCHEMA_IN_PROGRESS', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_VERY_VERBOSE);
+ }
}
else if (!$state['migration_data_done'])
{
try
{
- $this->output_handler->write(array('MIGRATION_DATA_RUNNING', $name), migrator_output_handler_interface::VERBOSITY_VERBOSE);
+ $verbosity = empty($state['migration_data_state']) ?
+ migrator_output_handler_interface::VERBOSITY_VERBOSE : migrator_output_handler_interface::VERBOSITY_DEBUG;
+ $this->output_handler->write(array('MIGRATION_DATA_RUNNING', $name), $verbosity);
$this->last_run_migration['task'] = 'process_data_step';
+ $total_time = (is_array($state['migration_data_state']) && isset($state['migration_data_state']['_total_time'])) ?
+ $state['migration_data_state']['_total_time'] : 0.0;
$elapsed_time = microtime(true);
+
$result = $this->process_data_step($migration->update_data(), $state['migration_data_state']);
+
$elapsed_time = microtime(true) - $elapsed_time;
+ $total_time += $elapsed_time;
+
+ if (is_array($result))
+ {
+ $result['_total_time'] = $total_time;
+ }
$state['migration_data_state'] = ($result === true) ? '' : $result;
$state['migration_data_done'] = ($result === true);
$state['migration_end_time'] = ($result === true) ? time() : 0;
- if ($state['migration_schema_done'])
+ if ($state['migration_data_done'])
{
- $this->output_handler->write(array('MIGRATION_DATA_DONE', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_NORMAL);
+ $this->output_handler->write(array('MIGRATION_DATA_DONE', $name, $total_time), migrator_output_handler_interface::VERBOSITY_NORMAL);
}
else
{
@@ -337,10 +383,12 @@ class migrator
}
catch (\phpbb\db\migration\exception $e)
{
- // Revert the schema changes
+ // Reset data state and revert the schema changes
+ $state['migration_data_state'] = '';
+ $this->set_migration_state($name, $state);
+
$this->revert_do($name);
- // Rethrow exception
throw $e;
}
}
@@ -416,19 +464,11 @@ class migrator
if ($state['migration_data_done'])
{
- if ($state['migration_data_state'] !== 'revert_data')
- {
- $result = $this->process_data_step($migration->update_data(), $state['migration_data_state'], true);
-
- $state['migration_data_state'] = ($result === true) ? 'revert_data' : $result;
- }
- else
- {
- $result = $this->process_data_step($migration->revert_data(), '', false);
+ $steps = array_merge($this->helper->reverse_update_data($migration->update_data()), $migration->revert_data());
+ $result = $this->process_data_step($steps, $state['migration_data_state']);
- $state['migration_data_state'] = ($result === true) ? '' : $result;
- $state['migration_data_done'] = ($result === true) ? false : true;
- }
+ $state['migration_data_state'] = ($result === true) ? '' : $result;
+ $state['migration_data_done'] = ($result === true) ? false : true;
$this->set_migration_state($name, $state);
}
@@ -446,8 +486,13 @@ class migrator
WHERE migration_name = '" . $this->db->sql_escape($name) . "'";
$this->db->sql_query($sql);
+ $this->last_run_migration = false;
unset($this->migration_state[$name]);
}
+ else
+ {
+ $this->set_migration_state($name, $state);
+ }
}
return true;
@@ -464,7 +509,12 @@ class migrator
*/
protected function process_data_step($steps, $state, $revert = false)
{
- $state = ($state) ? unserialize($state) : false;
+ if (sizeof($steps) === 0)
+ {
+ return true;
+ }
+
+ $state = is_array($state) ? $state : false;
// reverse order of steps if reverting
if ($revert === true)
@@ -472,54 +522,45 @@ class migrator
$steps = array_reverse($steps);
}
- foreach ($steps as $step_identifier => $step)
+ $step = $last_result = 0;
+ if ($state)
{
- $last_result = 0;
- if ($state)
- {
- // Continue until we reach the step that matches the last step called
- if ($state['step'] != $step_identifier)
- {
- continue;
- }
-
- // We send the result from last time to the callable function
- $last_result = $state['result'];
+ $step = $state['step'];
- // Set state to false since we reached the point we were at
- $state = false;
- }
+ // We send the result from last time to the callable function
+ $last_result = $state['result'];
+ }
- try
+ try
+ {
+ // Result will be null or true if everything completed correctly
+ // Stop after each update step, to let the updater control the script runtime
+ $result = $this->run_step($steps[$step], $last_result, $revert);
+ if (($result !== null && $result !== true) || $step + 1 < sizeof($steps))
{
- // Result will be null or true if everything completed correctly
- $result = $this->run_step($step, $last_result, $revert);
- if ($result !== null && $result !== true)
- {
- return serialize(array(
- 'result' => $result,
- 'step' => $step_identifier,
- ));
- }
+ return array(
+ 'result' => $result,
+ // Move on if the last call finished
+ 'step' => ($result !== null && $result !== true) ? $step : $step + 1,
+ );
}
- catch (\phpbb\db\migration\exception $e)
+ }
+ catch (\phpbb\db\migration\exception $e)
+ {
+ // We should try rolling back here
+ foreach ($steps as $reverse_step_identifier => $reverse_step)
{
- // We should try rolling back here
- foreach ($steps as $reverse_step_identifier => $reverse_step)
+ // If we've reached the current step we can break because we reversed everything that was run
+ if ($reverse_step_identifier == $step)
{
- // If we've reached the current step we can break because we reversed everything that was run
- if ($reverse_step_identifier == $step_identifier)
- {
- break;
- }
-
- // Reverse the step that was run
- $result = $this->run_step($reverse_step, false, !$revert);
+ break;
}
- // rethrow the exception
- throw $e;
+ // Reverse the step that was run
+ $result = $this->run_step($reverse_step, false, !$revert);
}
+
+ throw $e;
}
return true;
@@ -587,6 +628,13 @@ class migrator
throw new \phpbb\db\migration\exception('MIGRATION_INVALID_DATA_MISSING_STEP', $step);
}
+ if ($reverse)
+ {
+ // We might get unexpected results when trying
+ // to revert this, so just avoid it
+ return false;
+ }
+
$condition = $parameters[0];
if (!$condition)
@@ -664,6 +712,7 @@ class migrator
{
$migration_row = $state;
$migration_row['migration_depends_on'] = serialize($state['migration_depends_on']);
+ $migration_row['migration_data_state'] = !empty($state['migration_data_state']) ? serialize($state['migration_data_state']) : '';
if (isset($this->migration_state[$name]))
{
diff --git a/phpBB/phpbb/db/migrator_output_handler_interface.php b/phpBB/phpbb/db/migrator_output_handler_interface.php
index a923af99f6..9947b51dcc 100644
--- a/phpBB/phpbb/db/migrator_output_handler_interface.php
+++ b/phpBB/phpbb/db/migrator_output_handler_interface.php
@@ -15,11 +15,11 @@ namespace phpbb\db;
interface migrator_output_handler_interface
{
- const VERBOSITY_QUIET = 0;
- const VERBOSITY_NORMAL = 1;
- const VERBOSITY_VERBOSE = 2;
- const VERBOSITY_VERY_VERBOSE = 3;
- const VERBOSITY_DEBUG = 4;
+ const VERBOSITY_QUIET = 16;
+ const VERBOSITY_NORMAL = 32;
+ const VERBOSITY_VERBOSE = 64;
+ const VERBOSITY_VERY_VERBOSE = 128;
+ const VERBOSITY_DEBUG = 256;
/**
* Write output using the configured closure.
diff --git a/phpBB/phpbb/notification/method/messenger_base.php b/phpBB/phpbb/notification/method/messenger_base.php
index 3c6d617c66..0bfbfd6b02 100644
--- a/phpBB/phpbb/notification/method/messenger_base.php
+++ b/phpBB/phpbb/notification/method/messenger_base.php
@@ -81,7 +81,7 @@ abstract class messenger_base extends \phpbb\notification\method\base
$messenger->assign_vars(array_merge(array(
'USERNAME' => $user['username'],
- 'U_NOTIFICATION_SETTINGS' => generate_board_url() . '/ucp.' . $this->php_ext . '?i=ucp_notifications&amp;mode=notification_options',
+ 'U_NOTIFICATION_SETTINGS' => generate_board_url() . '/ucp.' . $this->php_ext . '?i=ucp_notifications&mode=notification_options',
), $notification->get_email_template_variables()));
$messenger->send($notify_method);
diff --git a/phpBB/phpbb/search/fulltext_mysql.php b/phpBB/phpbb/search/fulltext_mysql.php
index 3ddbd85b36..9faf5ca08b 100644
--- a/phpBB/phpbb/search/fulltext_mysql.php
+++ b/phpBB/phpbb/search/fulltext_mysql.php
@@ -177,8 +177,10 @@ class fulltext_mysql extends \phpbb\search\base
$engine === 'MyISAM' ||
// FULLTEXT is supported on InnoDB since MySQL 5.6.4 according to
// http://dev.mysql.com/doc/refman/5.6/en/innodb-storage-engine.html
+ // We also require https://bugs.mysql.com/bug.php?id=67004 to be
+ // fixed for proper overall operation. Hence we require 5.6.8.
$engine === 'InnoDB' &&
- phpbb_version_compare($this->db->sql_server_info(true), '5.6.4', '>=');
+ phpbb_version_compare($this->db->sql_server_info(true), '5.6.8', '>=');
if (!$fulltext_supported)
{
diff --git a/phpBB/phpbb/search/fulltext_native.php b/phpBB/phpbb/search/fulltext_native.php
index e2c02ffdab..63b0b24edf 100644
--- a/phpBB/phpbb/search/fulltext_native.php
+++ b/phpBB/phpbb/search/fulltext_native.php
@@ -1262,7 +1262,7 @@ class fulltext_native extends \phpbb\search\base
if (!$total_results && $is_mysql)
{
// Count rows for the executed queries. Replace $select within $sql with SQL_CALC_FOUND_ROWS, and run it.
- $sql_calc = str_replace('SELECT ' . $select, 'SELECT DISTINCT SQL_CALC_FOUND_ROWS p.post_id', $sql);
+ $sql_calc = str_replace('SELECT ' . $select, 'SELECT SQL_CALC_FOUND_ROWS ' . $select, $sql);
$result = $this->db->sql_query($sql_calc);
$this->db->sql_freeresult($result);
diff --git a/phpBB/phpbb/session.php b/phpBB/phpbb/session.php
index 83e87b7704..33d8df9cb8 100644
--- a/phpBB/phpbb/session.php
+++ b/phpBB/phpbb/session.php
@@ -1585,7 +1585,7 @@ class session
$this->data = array_merge($this->data, $sql_ary);
- if ($this->data['user_id'] != ANONYMOUS && !empty($config['new_member_post_limit']) && $this->data['user_new'] && $config['new_member_post_limit'] <= $this->data['user_posts'])
+ if ($this->data['user_id'] != ANONYMOUS && isset($config['new_member_post_limit']) && $this->data['user_new'] && $config['new_member_post_limit'] <= $this->data['user_posts'])
{
$this->leave_newly_registered();
}
diff --git a/phpBB/posting.php b/phpBB/posting.php
index 653740ae1c..f1e8452305 100644
--- a/phpBB/posting.php
+++ b/phpBB/posting.php
@@ -1741,6 +1741,7 @@ $page_data = array(
'L_POST_A' => $page_title,
'L_ICON' => ($mode == 'reply' || $mode == 'quote' || ($mode == 'edit' && $post_id != $post_data['topic_first_post_id'])) ? $user->lang['POST_ICON'] : $user->lang['TOPIC_ICON'],
'L_MESSAGE_BODY_EXPLAIN' => $user->lang('MESSAGE_BODY_EXPLAIN', (int) $config['max_post_chars']),
+ 'L_DELETE_POST_PERMANENTLY' => $user->lang('DELETE_POST_PERMANENTLY', 1),
'FORUM_NAME' => $post_data['forum_name'],
'FORUM_DESC' => ($post_data['forum_desc']) ? generate_text_for_display($post_data['forum_desc'], $post_data['forum_desc_uid'], $post_data['forum_desc_bitfield'], $post_data['forum_desc_options']) : '',
diff --git a/phpBB/search.php b/phpBB/search.php
index a0380590c1..cbee369086 100644
--- a/phpBB/search.php
+++ b/phpBB/search.php
@@ -126,6 +126,26 @@ gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
$pagination = $phpbb_container->get('pagination');
+/**
+* This event allows you to alter the above parameters, such as keywords and submit
+*
+* @event core.search_modify_submit_parameters
+* @var string keywords The search keywords
+* @var string author Specifies the author match, when ANONYMOUS is also a search-match
+* @var int author_id ID of the author to search by
+* @var string search_id Predefined search type name
+* @var bool submit Whether or not the form has been submitted
+* @since 3.1.10-RC1
+*/
+$vars = array(
+ 'keywords',
+ 'author',
+ 'author_id',
+ 'search_id',
+ 'submit',
+);
+extract($phpbb_dispatcher->trigger_event('core.search_modify_submit_parameters', compact($vars)));
+
if ($keywords || $author || $author_id || $search_id || $submit)
{
// clear arrays
diff --git a/phpBB/styles/prosilver/template/confirm_delete_body.html b/phpBB/styles/prosilver/template/confirm_delete_body.html
index f0a7ab2bdb..fbd881a940 100644
--- a/phpBB/styles/prosilver/template/confirm_delete_body.html
+++ b/phpBB/styles/prosilver/template/confirm_delete_body.html
@@ -7,7 +7,7 @@
<label>
<strong>{L_DELETE_PERMANENTLY}{L_COLON}</strong>
<input id="delete_permanent" name="delete_permanent" type="checkbox" value="1" {S_CHECKED_PERMANENT} />
- <!-- IF S_TOPIC_MODE -->{L_DELETE_TOPIC_PERMANENTLY}<!-- ELSE -->{L_DELETE_POST_PERMANENTLY}<!-- ENDIF -->
+ <!-- IF S_TOPIC_MODE -->{DELETE_TOPIC_PERMANENTLY_EXPLAIN}<!-- ELSE -->{DELETE_POST_PERMANENTLY_EXPLAIN}<!-- ENDIF -->
</label>
<!-- ENDIF -->
@@ -43,7 +43,7 @@
<dd>
<label for="delete_permanent">
<input id="delete_permanent" name="delete_permanent" type="checkbox" value="1" {S_CHECKED_PERMANENT} />
- <!-- IF S_TOPIC_MODE -->{L_DELETE_TOPIC_PERMANENTLY}<!-- ELSE -->{L_DELETE_POST_PERMANENTLY}<!-- ENDIF -->
+ <!-- IF S_TOPIC_MODE -->{DELETE_TOPIC_PERMANENTLY_EXPLAIN}<!-- ELSE -->{DELETE_POST_PERMANENTLY_EXPLAIN}<!-- ENDIF -->
</label>
</dd>
</dl>
diff --git a/phpBB/styles/prosilver/template/mcp_topic.html b/phpBB/styles/prosilver/template/mcp_topic.html
index e6978191de..22d837b3d1 100644
--- a/phpBB/styles/prosilver/template/mcp_topic.html
+++ b/phpBB/styles/prosilver/template/mcp_topic.html
@@ -73,7 +73,7 @@
<dl>
<dt><label for="to_topic_id">{L_MERGE_TOPIC_ID}{L_COLON}</label></dt>
<dd>
- <input class="inputbox autowidth" type="number" min="0" max="999999" name="to_topic_id" id="to_topic_id" value="{TO_TOPIC_ID}" />
+ <input class="inputbox autowidth" type="number" min="0" max="9999999999" name="to_topic_id" id="to_topic_id" value="{TO_TOPIC_ID}" />
<a href="{U_SELECT_TOPIC}" >{L_SELECT_TOPIC}</a>
</dd>
<!-- IF TO_TOPIC_INFO --><dd>{TO_TOPIC_INFO}</dd><!-- ENDIF -->
@@ -112,7 +112,10 @@
</ul>
<h3><a href="{postrow.U_POST_DETAILS}">{postrow.POST_SUBJECT}</a></h3>
+
+ <!-- EVENT mcp_topic_postrow_post_details_before -->
<p class="author"><a href="#pr{postrow.POST_ID}">{postrow.MINI_POST_IMG}</a> {L_POSTED} {postrow.POST_DATE} {L_POST_BY_AUTHOR} <strong>{postrow.POST_AUTHOR_FULL}</strong><!-- IF postrow.U_MCP_DETAILS --> [ <a href="{postrow.U_MCP_DETAILS}">{L_POST_DETAILS}</a> ]<!-- ENDIF --></p>
+ <!-- EVENT mcp_topic_postrow_post_details_after -->
<!-- IF postrow.S_POST_UNAPPROVED -->
<p class="post-notice unapproved">
diff --git a/phpBB/styles/prosilver/template/posting_editor.html b/phpBB/styles/prosilver/template/posting_editor.html
index f897bf7a3b..5258ea09a2 100644
--- a/phpBB/styles/prosilver/template/posting_editor.html
+++ b/phpBB/styles/prosilver/template/posting_editor.html
@@ -23,7 +23,11 @@
<!-- IF S_POST_ACTION or S_PRIVMSGS or S_EDIT_DRAFT -->
<dl style="clear: left;">
<dt><label for="subject">{L_SUBJECT}{L_COLON}</label></dt>
- <dd><input type="text" name="subject" id="subject" size="45" maxlength="<!-- IF S_NEW_MESSAGE -->120<!-- ELSE -->124<!-- ENDIF -->" tabindex="2" value="{SUBJECT}{DRAFT_SUBJECT}" class="inputbox autowidth" /></dd>
+ <dd>
+ <!-- EVENT posting_editor_subject_prepend -->
+ <input type="text" name="subject" id="subject" size="45" maxlength="<!-- IF S_NEW_MESSAGE -->120<!-- ELSE -->124<!-- ENDIF -->" tabindex="2" value="{SUBJECT}{DRAFT_SUBJECT}" class="inputbox autowidth" />
+ <!-- EVENT posting_editor_subject_append -->
+ </dd>
</dl>
<!-- IF CAPTCHA_TEMPLATE and S_CONFIRM_CODE -->
<!-- DEFINE $CAPTCHA_TAB_INDEX = 3 -->
diff --git a/phpBB/styles/prosilver/template/posting_topic_review.html b/phpBB/styles/prosilver/template/posting_topic_review.html
index 6909877196..c51d8032dc 100644
--- a/phpBB/styles/prosilver/template/posting_topic_review.html
+++ b/phpBB/styles/prosilver/template/posting_topic_review.html
@@ -43,7 +43,10 @@
</ul>
<!-- ENDIF -->
+ <!-- EVENT posting_topic_review_row_post_details_before -->
<p class="author"><!-- IF S_IS_BOT -->{topic_review_row.MINI_POST_IMG}<!-- ELSE --><a href="{topic_review_row.U_MINI_POST}">{topic_review_row.MINI_POST_IMG}</a><!-- ENDIF --> {L_POST_BY_AUTHOR} <strong>{topic_review_row.POST_AUTHOR_FULL}</strong> &raquo; {topic_review_row.POST_DATE} </p>
+ <!-- EVENT posting_topic_review_row_post_details_after -->
+
<div class="content">{topic_review_row.MESSAGE}</div>
<!-- IF topic_review_row.S_HAS_ATTACHMENTS -->
diff --git a/phpBB/styles/prosilver/template/viewforum_body.html b/phpBB/styles/prosilver/template/viewforum_body.html
index bb18a5dd2c..643b78823f 100644
--- a/phpBB/styles/prosilver/template/viewforum_body.html
+++ b/phpBB/styles/prosilver/template/viewforum_body.html
@@ -121,6 +121,8 @@
<!-- ENDIF -->
+<!-- EVENT viewforum_body_topic_row_before -->
+
<!-- BEGIN topicrow -->
<!-- IF not topicrow.S_TOPIC_TYPE_SWITCH and not topicrow.S_FIRST_ROW -->
@@ -145,7 +147,7 @@
<ul class="topiclist topics">
<!-- ENDIF -->
- <!-- EVENT viewforum_body_topic_row_before -->
+ <!-- EVENT viewforum_body_topicrow_row_before -->
<li class="row<!-- IF topicrow.S_ROW_COUNT is even --> bg1<!-- ELSE --> bg2<!-- ENDIF --><!-- IF topicrow.S_POST_GLOBAL --> global-announce<!-- ENDIF --><!-- IF topicrow.S_POST_ANNOUNCE --> announce<!-- ENDIF --><!-- IF topicrow.S_POST_STICKY --> sticky<!-- ENDIF --><!-- IF topicrow.S_TOPIC_REPORTED --> reported<!-- ENDIF -->">
<!-- EVENT viewforum_body_topic_row_prepend -->
<dl class="icon {topicrow.TOPIC_IMG_STYLE}">
diff --git a/phpBB/styles/subsilver2/template/mcp_topic.html b/phpBB/styles/subsilver2/template/mcp_topic.html
index c6a8236b20..eee7fa95ea 100644
--- a/phpBB/styles/subsilver2/template/mcp_topic.html
+++ b/phpBB/styles/subsilver2/template/mcp_topic.html
@@ -44,7 +44,7 @@
</tr>
<tr>
<td class="row1" nowrap="nowrap"><span class="gen">{L_MERGE_TOPIC_ID}</span></td>
- <td class="row2" colspan="2"><input class="post" type="number" min="0" max="999999" name="to_topic_id" value="{TO_TOPIC_ID}" /> <a href="{U_SELECT_TOPIC}">{L_SELECT_TOPIC}</a></td>
+ <td class="row2" colspan="2"><input class="post" type="number" min="0" max="9999999999" name="to_topic_id" value="{TO_TOPIC_ID}" /> <a href="{U_SELECT_TOPIC}">{L_SELECT_TOPIC}</a></td>
</tr>
<!-- IF TO_TOPIC_INFO -->
<tr>
@@ -74,12 +74,14 @@
<td align="center"><b class="postauthor">{postrow.POST_AUTHOR_FULL}</b></td>
<td width="100%">
+ <!-- EVENT mcp_topic_postrow_post_details_before -->
<table width="100%" cellspacing="0" cellpadding="0" border="0">
<tr style="vertical-align: top;">
<td class="gensmall" nowrap="nowrap">&nbsp;<b>{L_POST_SUBJECT}{L_COLON}</b>&nbsp;</td>
<td class="gensmall" width="100%">{postrow.POST_SUBJECT}</td>
</tr>
</table>
+ <!-- EVENT mcp_topic_postrow_post_details_after -->
</td>
<td width="5%" align="center"><a href="{postrow.U_POST_DETAILS}" class="imageset">{INFO_IMG}</a></td>
</tr>
diff --git a/phpBB/styles/subsilver2/template/posting_body.html b/phpBB/styles/subsilver2/template/posting_body.html
index b984c9f96f..95f817e838 100644
--- a/phpBB/styles/subsilver2/template/posting_body.html
+++ b/phpBB/styles/subsilver2/template/posting_body.html
@@ -166,7 +166,11 @@
<!-- EVENT posting_editor_subject_before -->
<tr>
<td class="row1" width="22%"><b class="genmed">{L_SUBJECT}{L_COLON}</b></td>
- <td class="row2" width="78%"><input class="post" style="width:450px" type="text" name="subject" size="45" maxlength="<!-- IF S_NEW_MESSAGE -->120<!-- ELSE -->124<!-- ENDIF -->" tabindex="2" value="{SUBJECT}" /></td>
+ <td class="row2" width="78%">
+ <!-- EVENT posting_editor_subject_prepend -->
+ <input class="post" style="width:450px" type="text" name="subject" size="45" maxlength="<!-- IF S_NEW_MESSAGE -->120<!-- ELSE -->124<!-- ENDIF -->" tabindex="2" value="{SUBJECT}" />
+ <!-- EVENT posting_editor_subject_append -->
+ </td>
</tr>
<!-- EVENT posting_editor_subject_after -->
<tr>
diff --git a/phpBB/styles/subsilver2/template/posting_topic_review.html b/phpBB/styles/subsilver2/template/posting_topic_review.html
index 20976861fc..46329e19fa 100644
--- a/phpBB/styles/subsilver2/template/posting_topic_review.html
+++ b/phpBB/styles/subsilver2/template/posting_topic_review.html
@@ -18,6 +18,7 @@
</tr>
<!-- BEGIN topic_review_row -->
+ <!-- EVENT posting_topic_review_row_post_details_before -->
<!-- IF topic_review_row.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
<!-- IF topic_review_row.S_IGNORE_POST -->
@@ -41,6 +42,7 @@
</table>
</td>
</tr>
+ <!-- EVENT posting_topic_review_row_post_details_after -->
<!-- IF topic_review_row.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
diff --git a/phpBB/styles/subsilver2/template/viewforum_body.html b/phpBB/styles/subsilver2/template/viewforum_body.html
index 2b8268d2c3..c76c081ba7 100644
--- a/phpBB/styles/subsilver2/template/viewforum_body.html
+++ b/phpBB/styles/subsilver2/template/viewforum_body.html
@@ -32,9 +32,11 @@
<th>&nbsp;{L_LAST_POST}&nbsp;</th>
</tr>
+ <!-- EVENT viewforum_body_topic_row_before -->
+
<!-- BEGIN topicrow -->
- <!-- EVENT viewforum_body_topic_row_before -->
+ <!-- EVENT viewforum_body_topicrow_row_before -->
<tr>
<!-- EVENT viewforum_body_topic_row_prepend -->
<td class="row1" width="25" align="center">{topicrow.TOPIC_FOLDER_IMG}</td>
diff --git a/tests/dbal/fixtures/migrator_module.xml b/tests/dbal/fixtures/migrator_module.xml
index 32afe7e6f3..e172d7a145 100644
--- a/tests/dbal/fixtures/migrator_module.xml
+++ b/tests/dbal/fixtures/migrator_module.xml
@@ -20,7 +20,7 @@
<value>acp</value>
<value>0</value>
<value>1</value>
- <value>4</value>
+ <value>6</value>
<value>ACP_CAT</value>
<value></value>
<value></value>
@@ -38,5 +38,57 @@
<value>test</value>
<value></value>
</row>
+ <row>
+ <value>3</value>
+ <value>1</value>
+ <value>1</value>
+ <value></value>
+ <value>acp</value>
+ <value>1</value>
+ <value>4</value>
+ <value>5</value>
+ <value>ACP_FORUM_BASED_PERMISSIONS</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>1</value>
+ <value>1</value>
+ <value></value>
+ <value>acp</value>
+ <value>0</value>
+ <value>7</value>
+ <value>12</value>
+ <value>ACP_CAT_FORUMS</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>1</value>
+ <value>1</value>
+ <value></value>
+ <value>acp</value>
+ <value>4</value>
+ <value>8</value>
+ <value>11</value>
+ <value>ACP_FORUM_BASED_PERMISSIONS</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>6</value>
+ <value>1</value>
+ <value>1</value>
+ <value></value>
+ <value>acp</value>
+ <value>5</value>
+ <value>9</value>
+ <value>10</value>
+ <value>ACP_FORUM_BASED_PERMISSIONS_CHILD_1</value>
+ <value></value>
+ <value></value>
+ </row>
</table>
</dataset>
diff --git a/tests/dbal/migration/if.php b/tests/dbal/migration/if.php
index 98a66526ed..481250ea77 100644
--- a/tests/dbal/migration/if.php
+++ b/tests/dbal/migration/if.php
@@ -36,13 +36,13 @@ class phpbb_dbal_migration_if extends \phpbb\db\migration\migration
{
global $migrator_test_if_true_failed;
- $migrator_test_if_true_failed = false;
+ $migrator_test_if_true_failed = !$migrator_test_if_true_failed;
}
function test_false()
{
global $migrator_test_if_false_failed;
- $migrator_test_if_false_failed = true;
+ $migrator_test_if_false_failed = !$migrator_test_if_false_failed;
}
}
diff --git a/tests/dbal/migrator_test.php b/tests/dbal/migrator_test.php
index 4c4306888c..798200eef1 100644
--- a/tests/dbal/migrator_test.php
+++ b/tests/dbal/migrator_test.php
@@ -156,6 +156,14 @@ class phpbb_dbal_migrator_test extends phpbb_database_test_case
$this->assertFalse($migrator_test_if_true_failed, 'True test failed');
$this->assertFalse($migrator_test_if_false_failed, 'False test failed');
+
+ while ($this->migrator->migration_state('phpbb_dbal_migration_if') !== false)
+ {
+ $this->migrator->revert('phpbb_dbal_migration_if');
+ }
+
+ $this->assertFalse($migrator_test_if_true_failed, 'True test after revert failed');
+ $this->assertFalse($migrator_test_if_false_failed, 'False test after revert failed');
}
public function test_recall()
diff --git a/tests/dbal/migrator_tool_module_test.php b/tests/dbal/migrator_tool_module_test.php
index 08c3e979b8..49dff8b929 100644
--- a/tests/dbal/migrator_tool_module_test.php
+++ b/tests/dbal/migrator_tool_module_test.php
@@ -118,6 +118,44 @@ class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case
$this->fail($e);
}
$this->assertEquals(true, $this->tool->exists('acp', 'ACP_NEW_CAT', 'ACP_NEW_MODULE'));
+
+ // Test adding module when plural parent module_langname exists
+ // PHPBB3-14703
+ // Adding fail
+ try
+ {
+ $this->tool->add('acp', 'ACP_FORUM_BASED_PERMISSIONS', array(
+ 'module_basename' => 'acp_new_permissions_module',
+ 'module_langname' => 'ACP_NEW_PERMISSIONS_MODULE',
+ 'module_mode' => 'test',
+ 'module_auth' => '',
+ ));
+ $this->fail('Exception not thrown');
+ }
+ catch (Exception $e)
+ {
+ $this->assertEquals('phpbb\db\migration\exception', get_class($e));
+ $this->assertEquals('MODULE_EXIST_MULTIPLE', $e->getMessage());
+ }
+
+ // Test adding module when plural parent module_langname exists
+ // PHPBB3-14703
+ // Adding success
+ try
+ {
+ $this->tool->add('acp', 'ACP_FORUM_BASED_PERMISSIONS', array(
+ 'module_basename' => 'acp_new_permissions_module',
+ 'module_langname' => 'ACP_NEW_PERMISSIONS_MODULE',
+ 'module_mode' => 'test',
+ 'module_auth' => '',
+ 'after' => 'ACP_FORUM_BASED_PERMISSIONS_CHILD_1',
+ ));
+ }
+ catch (Exception $e)
+ {
+ $this->fail($e);
+ }
+ $this->assertEquals(true, $this->tool->exists('acp', 'ACP_FORUM_BASED_PERMISSIONS', 'ACP_NEW_PERMISSIONS_MODULE'));
}
public function test_remove()
diff --git a/tests/migrator/reverse_update_data_test.php b/tests/migrator/reverse_update_data_test.php
new file mode 100644
index 0000000000..b85e48c64c
--- /dev/null
+++ b/tests/migrator/reverse_update_data_test.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class reverse_update_data_test extends phpbb_test_case
+{
+ /** @var \phpbb\db\migration\helper */
+ protected $helper;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->helper = new \phpbb\db\migration\helper();
+ }
+
+ public function update_data_provider()
+ {
+ return array(
+ array(
+ array(
+ array('config.add', array('foobar', 1)),
+ array('if', array(
+ (false === true),
+ array('permission.add', array('some_data')),
+ )),
+ array('config.remove', array('foobar')),
+ array('custom', array(array($this, 'foo_bar'))),
+ array('tool.method', array('test_data')),
+ ),
+ array(
+ array('tool.reverse', array('method', 'test_data')),
+ array('config.reverse', array('remove', 'foobar')),
+ array('config.reverse', array('add', 'foobar', 1)),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider update_data_provider
+ */
+ public function test_get_schema_steps($data_changes, $expected)
+ {
+ $this->assertEquals($expected, $this->helper->reverse_update_data($data_changes));
+ }
+}