diff --git a/phpBB/assets/javascript/core.js b/phpBB/assets/javascript/core.js
index 424989a9f3..8bbea8b8c9 100644
--- a/phpBB/assets/javascript/core.js
+++ b/phpBB/assets/javascript/core.js
@@ -308,8 +308,8 @@ phpbb.ajaxify = function(options) {
}, res.REFRESH_DATA.time * 1000); // Server specifies time in seconds
}
} else {
- // If confirmation is required, display a diologue to the user.
- phpbb.confirm(res.MESSAGE_TEXT, function(del) {
+ // If confirmation is required, display a dialog to the user.
+ phpbb.confirm(res.MESSAGE_BODY, function(del) {
if (del) {
phpbb.loadingAlert();
data = $('
' + res.S_HIDDEN_FIELDS + '
').serialize();
@@ -489,6 +489,19 @@ phpbb.timezonePreselectSelect = function(forceSelector) {
}
};
+// Toggle notification list
+$('#notification_list_button').click(function(e) {
+ $('#notification_list').toggle();
+ e.preventDefault();
+});
+$('#phpbb').click(function(e) {
+ var target = $(e.target);
+
+ if (!target.is('#notification_list') && !target.is('#notification_list_button') && !target.parents().is('#notification_list')) {
+ $('#notification_list').hide();
+ }
+});
+
phpbb.ajaxCallbacks = {};
/**
diff --git a/phpBB/common.php b/phpBB/common.php
index f502d37c8f..c33e2cbb1f 100644
--- a/phpBB/common.php
+++ b/phpBB/common.php
@@ -73,6 +73,7 @@ require($phpbb_root_path . 'includes/class_loader.' . $phpEx);
require($phpbb_root_path . 'includes/functions.' . $phpEx);
require($phpbb_root_path . 'includes/functions_content.' . $phpEx);
require($phpbb_root_path . 'includes/functions_container.' . $phpEx);
+include($phpbb_root_path . 'includes/functions_compatibility.' . $phpEx);
require($phpbb_root_path . 'includes/constants.' . $phpEx);
require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
@@ -110,6 +111,8 @@ $config = $phpbb_container->get('config');
set_config(null, null, null, $config);
set_config_count(null, null, null, $config);
+$phpbb_log = $phpbb_container->get('log');
+
// load extensions
$phpbb_extension_manager = $phpbb_container->get('ext.manager');
$phpbb_subscriber_loader = $phpbb_container->get('event.subscriber_loader');
diff --git a/phpBB/config/avatars.yml b/phpBB/config/avatars.yml
new file mode 100644
index 0000000000..fa0f07372a
--- /dev/null
+++ b/phpBB/config/avatars.yml
@@ -0,0 +1,55 @@
+services:
+ avatar.driver.gravatar:
+ class: phpbb_avatar_driver_gravatar
+ arguments:
+ - @config
+ - %core.root_path%
+ - .%core.php_ext%
+ - @cache.driver
+ calls:
+ - [set_name, [avatar.driver.gravatar]]
+ tags:
+ - { name: avatar.driver }
+
+ avatar.driver.local:
+ class: phpbb_avatar_driver_local
+ arguments:
+ - @config
+ - %core.root_path%
+ - .%core.php_ext%
+ - @cache.driver
+ calls:
+ - [set_name, [avatar.driver.local]]
+ tags:
+ - { name: avatar.driver }
+
+ avatar.driver.remote:
+ class: phpbb_avatar_driver_remote
+ arguments:
+ - @config
+ - %core.root_path%
+ - .%core.php_ext%
+ - @cache.driver
+ calls:
+ - [set_name, [avatar.driver.remote]]
+ tags:
+ - { name: avatar.driver }
+
+ avatar.driver.upload:
+ class: phpbb_avatar_driver_upload
+ arguments:
+ - @config
+ - %core.root_path%
+ - .%core.php_ext%
+ - @cache.driver
+ calls:
+ - [set_name, [avatar.driver.upload]]
+ tags:
+ - { name: avatar.driver }
+
+ avatar.driver_collection:
+ class: phpbb_di_service_collection
+ arguments:
+ - @service_container
+ tags:
+ - { name: service_collection, tag: avatar.driver }
diff --git a/phpBB/config/notifications.yml b/phpBB/config/notifications.yml
new file mode 100644
index 0000000000..60aa63a854
--- /dev/null
+++ b/phpBB/config/notifications.yml
@@ -0,0 +1,314 @@
+services:
+ notification.type_collection:
+ class: phpbb_di_service_collection
+ arguments:
+ - @service_container
+ tags:
+ - { name: service_collection, tag: notification.type }
+
+ notification.method_collection:
+ class: phpbb_di_service_collection
+ arguments:
+ - @service_container
+ tags:
+ - { name: service_collection, tag: notification.method }
+
+ notification.type.approve_post:
+ class: phpbb_notification_type_approve_post
+ scope: prototype # scope MUST be prototype for this to work! # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.type.approve_topic:
+ class: phpbb_notification_type_approve_topic
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.type.bookmark:
+ class: phpbb_notification_type_bookmark
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.type.disapprove_post:
+ class: phpbb_notification_type_disapprove_post
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.type.disapprove_topic:
+ class: phpbb_notification_type_disapprove_topic
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.type.pm:
+ class: phpbb_notification_type_pm
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.type.post:
+ class: phpbb_notification_type_post
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.type.post_in_queue:
+ class: phpbb_notification_type_post_in_queue
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.type.quote:
+ class: phpbb_notification_type_quote
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.type.report_pm:
+ class: phpbb_notification_type_report_pm
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.type.report_pm_closed:
+ class: phpbb_notification_type_report_pm_closed
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.type.report_post:
+ class: phpbb_notification_type_report_post
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.type.report_post_closed:
+ class: phpbb_notification_type_report_post
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.type.topic:
+ class: phpbb_notification_type_topic
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.type.topic_in_queue:
+ class: phpbb_notification_type_topic_in_queue
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+ tags:
+ - { name: notification.type }
+
+ notification.method.email:
+ class: phpbb_notification_method_email
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ tags:
+ - { name: notification.method }
+
+ notification.method.jabber:
+ class: phpbb_notification_method_jabber
+ scope: prototype # scope MUST be prototype for this to work!
+ arguments:
+ - @user_loader
+ - @dbal.conn
+ - @cache.driver
+ - @user
+ - @auth
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ tags:
+ - { name: notification.method }
diff --git a/phpBB/config/services.yml b/phpBB/config/services.yml
index ef5359129f..b9c71844dc 100644
--- a/phpBB/config/services.yml
+++ b/phpBB/config/services.yml
@@ -1,12 +1,21 @@
imports:
- { resource: tables.yml }
- { resource: cron_tasks.yml }
+ - { resource: notifications.yml }
- { resource: migrator.yml }
+ - { resource: avatars.yml }
services:
auth:
class: phpbb_auth
+ avatar.manager:
+ class: phpbb_avatar_manager
+ arguments:
+ - @config
+ - @avatar.driver_collection
+ - @service_container
+
cache:
class: phpbb_cache_service
arguments:
@@ -49,6 +58,12 @@ services:
- @cache.driver
- %tables.config%
+ config_text:
+ class: phpbb_config_db_text
+ arguments:
+ - @dbal.conn
+ - %tables.config_text%
+
controller.helper:
class: phpbb_controller_helper
arguments:
@@ -130,6 +145,19 @@ services:
- .%core.php_ext%
- _ext_finder
+ groupposition.legend:
+ class: phpbb_groupposition_legend
+ arguments:
+ - @dbal.conn
+ - @user
+
+ groupposition.teampage:
+ class: phpbb_groupposition_teampage
+ arguments:
+ - @dbal.conn
+ - @user
+ - @cache.driver
+
http_kernel:
class: Symfony\Component\HttpKernel\HttpKernel
arguments:
@@ -165,6 +193,33 @@ services:
tags:
- { name: kernel.event_subscriber }
+ log:
+ class: phpbb_log
+ arguments:
+ - @dbal.conn
+ - @user
+ - @auth
+ - @dispatcher
+ - %core.root_path%
+ - %core.adm_relative_path%
+ - %core.php_ext%
+ - %tables.log%
+
+ notification_manager:
+ class: phpbb_notification_manager
+ arguments:
+ - @notification.type_collection
+ - @notification.method_collection
+ - @service_container
+ - @user_loader
+ - @dbal.conn
+ - @user
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.notification_types%
+ - %tables.notifications%
+ - %tables.user_notifications%
+
request:
class: phpbb_request
@@ -207,3 +262,11 @@ services:
user:
class: phpbb_user
+
+ user_loader:
+ class: phpbb_user_loader
+ arguments:
+ - @dbal.conn
+ - %core.root_path%
+ - %core.php_ext%
+ - %tables.users%
diff --git a/phpBB/config/tables.yml b/phpBB/config/tables.yml
index dd53417b1c..ec5fec23ad 100644
--- a/phpBB/config/tables.yml
+++ b/phpBB/config/tables.yml
@@ -1,5 +1,11 @@
parameters:
tables.config: %core.table_prefix%config
+ tables.config_text: %core.table_prefix%config_text
tables.ext: %core.table_prefix%ext
+ tables.log: %core.table_prefix%log
tables.migrations: %core.table_prefix%migrations
tables.modules: %core.table_prefix%modules
+ tables.notification_types: %core.table_prefix%notification_types
+ tables.notifications: %core.table_prefix%notifications
+ tables.user_notifications: %core.table_prefix%user_notifications
+ tables.users: %core.table_prefix%users
diff --git a/phpBB/develop/create_schema_files.php b/phpBB/develop/create_schema_files.php
index 550396c7ea..b454fb2c16 100644
--- a/phpBB/develop/create_schema_files.php
+++ b/phpBB/develop/create_schema_files.php
@@ -998,6 +998,14 @@ function get_schema_struct()
),
);
+ $schema_data['phpbb_config_text'] = array(
+ 'COLUMNS' => array(
+ 'config_name' => array('VCHAR', ''),
+ 'config_value' => array('MTEXT', ''),
+ ),
+ 'PRIMARY_KEY' => 'config_name',
+ );
+
$schema_data['phpbb_confirm'] = array(
'COLUMNS' => array(
'confirm_id' => array('CHAR:32', ''),
@@ -1168,7 +1176,7 @@ function get_schema_struct()
'group_desc_uid' => array('VCHAR:8', ''),
'group_display' => array('BOOL', 0),
'group_avatar' => array('VCHAR', ''),
- 'group_avatar_type' => array('TINT:2', 0),
+ 'group_avatar_type' => array('VCHAR:255', ''),
'group_avatar_width' => array('USINT', 0),
'group_avatar_height' => array('USINT', 0),
'group_rank' => array('UINT', 0),
@@ -1178,7 +1186,6 @@ function get_schema_struct()
'group_message_limit' => array('UINT', 0),
'group_max_recipients' => array('UINT', 0),
'group_legend' => array('UINT', 0),
- 'group_teampage' => array('UINT', 0),
),
'PRIMARY_KEY' => 'group_id',
'KEYS' => array(
@@ -1308,6 +1315,32 @@ function get_schema_struct()
),
);
+ $schema_data['phpbb_notification_types'] = array(
+ 'COLUMNS' => array(
+ 'notification_type' => array('VCHAR:255', ''),
+ 'notification_type_enabled' => array('BOOL', 1),
+ ),
+ 'PRIMARY_KEY' => array('notification_type', 'notification_type_enabled'),
+ );
+
+ $schema_data['phpbb_notifications'] = array(
+ 'COLUMNS' => array(
+ 'notification_id' => array('UINT', NULL, 'auto_increment'),
+ 'item_type' => array('VCHAR:255', ''),
+ 'item_id' => array('UINT', 0),
+ 'item_parent_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'notification_read' => array('BOOL', 0),
+ 'notification_time' => array('TIMESTAMP', 1),
+ 'notification_data' => array('TEXT_UNI', ''),
+ ),
+ 'PRIMARY_KEY' => 'notification_id',
+ 'KEYS' => array(
+ 'item_ident' => array('INDEX', array('item_type', 'item_id')),
+ 'user' => array('INDEX', array('user_id', 'notification_read')),
+ ),
+ );
+
$schema_data['phpbb_poll_options'] = array(
'COLUMNS' => array(
'poll_option_id' => array('TINT:4', 0),
@@ -1685,6 +1718,17 @@ function get_schema_struct()
),
);
+ $schema_data['phpbb_teampage'] = array(
+ 'COLUMNS' => array(
+ 'teampage_id' => array('UINT', NULL, 'auto_increment'),
+ 'group_id' => array('UINT', 0),
+ 'teampage_name' => array('VCHAR_UNI:255', ''),
+ 'teampage_position' => array('UINT', 0),
+ 'teampage_parent' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'teampage_id',
+ );
+
$schema_data['phpbb_topics'] = array(
'COLUMNS' => array(
'topic_id' => array('UINT', NULL, 'auto_increment'),
@@ -1769,6 +1813,16 @@ function get_schema_struct()
),
);
+ $schema_data['phpbb_user_notifications'] = array(
+ 'COLUMNS' => array(
+ 'item_type' => array('VCHAR:255', ''),
+ 'item_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'method' => array('VCHAR:255', ''),
+ 'notify' => array('BOOL', 1),
+ ),
+ );
+
$schema_data['phpbb_user_group'] = array(
'COLUMNS' => array(
'group_id' => array('UINT', 0),
@@ -1839,7 +1893,7 @@ function get_schema_struct()
'user_allow_massemail' => array('BOOL', 1),
'user_options' => array('UINT:11', 230271),
'user_avatar' => array('VCHAR', ''),
- 'user_avatar_type' => array('TINT:2', 0),
+ 'user_avatar_type' => array('VCHAR:255', ''),
'user_avatar_width' => array('USINT', 0),
'user_avatar_height' => array('USINT', 0),
'user_sig' => array('MTEXT_UNI', ''),
diff --git a/phpBB/docs/sphinx.sample.conf b/phpBB/docs/sphinx.sample.conf
index fcaba6dcf3..d1b98d6cbc 100644
--- a/phpBB/docs/sphinx.sample.conf
+++ b/phpBB/docs/sphinx.sample.conf
@@ -1,46 +1,31 @@
source source_phpbb_{SPHINX_ID}_main
{
- type = mysql #mysql or pgsql
- sql_host = localhost #SQL server host sphinx connects to
+ type = mysql # mysql or pgsql
+ sql_host = localhost # SQL server host sphinx connects to
sql_user = username
sql_pass = password
sql_db = db_name
- sql_port = 3306 #optional, default is 3306 for mysql and 5432 for pgsql
+ sql_port = 3306 # optional, default is 3306 for mysql and 5432 for pgsql
sql_query_pre = SET NAMES 'utf8'
- sql_query_pre = UPDATE phpbb_sphinx SET max_doc_id = MAX(post_id) WHERE counter_id = 1
+ sql_query_pre = UPDATE phpbb_sphinx SET max_doc_id = (SELECT MAX(post_id) FROM phpbb_posts) WHERE counter_id = 1
sql_query_range = SELECT MIN(post_id), MAX(post_id) FROM phpbb_posts
sql_range_step = 5000
- sql_query = SELECT
-\
- p.post_id AS id,
-\
- p.forum_id,
-\
- p.topic_id,
-\
- p.poster_id,
-\
- CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post,
-\
- p.post_time,
-\
- p.post_subject,
-\
- p.post_subject as title,
-\
- p.post_text as data,
-\
- t.topic_last_post_time,
-\
- 0 as deleted
-\
- FROM phpbb_posts p, phpbb_topics t
-\
- WHERE
-\
- p.topic_id = t.topic_id
-\
- AND p.post_id >= $start AND p.post_id <= $end
+ sql_query = SELECT \
+ p.post_id AS id, \
+ p.forum_id, \
+ p.topic_id, \
+ p.poster_id, \
+ CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post, \
+ p.post_time, \
+ p.post_subject, \
+ p.post_subject as title, \
+ p.post_text as data, \
+ t.topic_last_post_time, \
+ 0 as deleted\
+ FROM phpbb_posts p, phpbb_topics t \
+ WHERE \
+ p.topic_id = t.topic_id \
+ AND p.post_id >= $start AND p.post_id <= $end
sql_query_post =
sql_query_post_index = UPDATE phpbb_sphinx SET max_doc_id = $maxid WHERE counter_id = 1
sql_query_info = SELECT * FROM phpbb_posts WHERE post_id = $id
@@ -55,39 +40,25 @@ source source_phpbb_{SPHINX_ID}_main
}
source source_phpbb_{SPHINX_ID}_delta : source_phpbb_{SPHINX_ID}_main
{
+ sql_query_pre =
sql_query_range =
sql_range_step =
- sql_query = SELECT
-\
- p.post_id AS id,
-\
- p.forum_id,
-\
- p.topic_id,
-\
- p.poster_id,
-\
- CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post,
-\
- p.post_time,
-\
- p.post_subject,
-\
- p.post_subject as title,
-\
- p.post_text as data,
-\
- t.topic_last_post_time,
-\
- 0 as deleted
-\
- FROM phpbb_posts p, phpbb_topics t
-\
- WHERE
-\
- p.topic_id = t.topic_id
-\
- AND p.post_id >= ( SELECT max_doc_id FROM phpbb_sphinx WHERE counter_id=1 )
+ sql_query = SELECT \
+ p.post_id AS id, \
+ p.forum_id, \
+ p.topic_id, \
+ p.poster_id, \
+ CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post, \
+ p.post_time, \
+ p.post_subject, \
+ p.post_subject as title, \
+ p.post_text as data, \
+ t.topic_last_post_time, \
+ 0 as deleted \
+ FROM phpbb_posts p, phpbb_topics t \
+ WHERE \
+ p.topic_id = t.topic_id \
+ AND p.post_id >= ( SELECT max_doc_id FROM phpbb_sphinx WHERE counter_id=1 )
sql_query_pre =
}
index index_phpbb_{SPHINX_ID}_main
diff --git a/phpBB/download/file.php b/phpBB/download/file.php
index 4a392b002d..91c05586a5 100644
--- a/phpBB/download/file.php
+++ b/phpBB/download/file.php
@@ -67,6 +67,7 @@ if (isset($_GET['avatar']))
$phpbb_dispatcher = $phpbb_container->get('dispatcher');
$request = $phpbb_container->get('request');
$db = $phpbb_container->get('dbal.conn');
+ $phpbb_log = $phpbb_container->get('log');
// Connect to DB
if (!@$db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false))
@@ -88,6 +89,8 @@ if (isset($_GET['avatar']))
// worst-case default
$browser = strtolower($request->header('User-Agent', 'msie 6.0'));
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+
$filename = request_var('avatar', '');
$avatar_group = false;
$exit = false;
diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php
index 960cc89db5..6543427677 100644
--- a/phpBB/includes/acp/acp_board.php
+++ b/phpBB/includes/acp/acp_board.php
@@ -28,7 +28,7 @@ class acp_board
{
global $db, $user, $auth, $template;
global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
- global $cache;
+ global $cache, $phpbb_container;
$user->add_lang('acp/board');
@@ -107,6 +107,23 @@ class acp_board
break;
case 'avatar':
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $avatar_drivers = $phpbb_avatar_manager->get_all_drivers();
+
+ $avatar_vars = array();
+ foreach ($avatar_drivers as $current_driver)
+ {
+ $driver = $phpbb_avatar_manager->get_driver($current_driver, false);
+
+ /*
+ * First grab the settings for enabling/disabling the avatar
+ * driver and afterwards grab additional settings the driver
+ * might have.
+ */
+ $avatar_vars += $phpbb_avatar_manager->get_avatar_settings($driver);
+ $avatar_vars += $driver->prepare_form_acp($user);
+ }
+
$display_vars = array(
'title' => 'ACP_AVATAR_SETTINGS',
'vars' => array(
@@ -118,17 +135,15 @@ class acp_board
'avatar_max_height' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false),
'allow_avatar' => array('lang' => 'ALLOW_AVATARS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'allow_avatar_local' => array('lang' => 'ALLOW_LOCAL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
- 'allow_avatar_remote' => array('lang' => 'ALLOW_REMOTE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'allow_avatar_upload' => array('lang' => 'ALLOW_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
- 'allow_avatar_remote_upload'=> array('lang' => 'ALLOW_REMOTE_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'avatar_filesize' => array('lang' => 'MAX_FILESIZE', 'validate' => 'int:0', 'type' => 'text:4:10', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']),
'avatar_min' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
'avatar_max' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
- 'avatar_path' => array('lang' => 'AVATAR_STORAGE_PATH', 'validate' => 'rwpath', 'type' => 'text:20:255', 'explain' => true),
- 'avatar_gallery_path' => array('lang' => 'AVATAR_GALLERY_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true),
)
);
+
+ if (!empty($avatar_vars))
+ {
+ $display_vars['vars'] += $avatar_vars;
+ }
break;
case 'message':
@@ -314,6 +329,7 @@ class acp_board
'load_online_time' => array('lang' => 'ONLINE_LENGTH', 'validate' => 'int:0', 'type' => 'text:4:3', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']),
'legend2' => 'GENERAL_OPTIONS',
+ 'load_notifications' => array('lang' => 'LOAD_NOTIFICATIONS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'load_db_track' => array('lang' => 'YES_POST_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'load_db_lastread' => array('lang' => 'YES_READ_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'load_anon_lastread' => array('lang' => 'YES_ANON_READ_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
diff --git a/phpBB/includes/acp/acp_groups.php b/phpBB/includes/acp/acp_groups.php
index 21b1d4b837..8cae0151c8 100644
--- a/phpBB/includes/acp/acp_groups.php
+++ b/phpBB/includes/acp/acp_groups.php
@@ -26,7 +26,7 @@ class acp_groups
{
global $config, $db, $user, $auth, $template, $cache;
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix, $file_uploads;
- global $request;
+ global $request, $phpbb_container;
$user->add_lang('acp/groups');
$this->tpl_name = 'acp_groups';
@@ -55,15 +55,16 @@ class acp_groups
// Clear some vars
- $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false;
$group_row = array();
// Grab basic data for group, if group_id is set and exists
if ($group_id)
{
- $sql = 'SELECT *
- FROM ' . GROUPS_TABLE . "
- WHERE group_id = $group_id";
+ $sql = 'SELECT g.*, t.teampage_position AS group_teampage
+ FROM ' . GROUPS_TABLE . ' g
+ LEFT JOIN ' . TEAMPAGE_TABLE . ' t
+ ON (t.group_id = g.group_id)
+ WHERE g.group_id = ' . $group_id;
$result = $db->sql_query($sql);
$group_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
@@ -300,8 +301,21 @@ class acp_groups
$error = array();
$user->add_lang('ucp');
- $avatar_select = basename(request_var('avatar_select', ''));
- $category = basename(request_var('category', ''));
+ // Setup avatar data for later
+ $avatars_enabled = false;
+ $avatar_drivers = null;
+ $avatar_data = null;
+ $avatar_error = array();
+
+ if ($config['allow_avatar'])
+ {
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers();
+
+ // This is normalised data, without the group_ prefix
+ $avatar_data = phpbb_avatar_manager::clean_row($group_row);
+ }
+
// Did we submit?
if ($update)
@@ -319,12 +333,6 @@ class acp_groups
$allow_desc_urls = request_var('desc_parse_urls', false);
$allow_desc_smilies = request_var('desc_parse_smilies', false);
- $data['uploadurl'] = request_var('uploadurl', '');
- $data['remotelink'] = request_var('remotelink', '');
- $data['width'] = request_var('width', '');
- $data['height'] = request_var('height', '');
- $delete = request_var('delete', '');
-
$submit_ary = array(
'colour' => request_var('group_colour', ''),
'rank' => request_var('group_rank', 0),
@@ -342,81 +350,35 @@ class acp_groups
$submit_ary['founder_manage'] = isset($_REQUEST['group_founder_manage']) ? 1 : 0;
}
- $uploadfile = $request->file('uploadfile');
- if (!empty($uploadfile['tmp_name']) || $data['uploadurl'] || $data['remotelink'])
+ if ($config['allow_avatar'])
{
- // Avatar stuff
- $var_ary = array(
- 'uploadurl' => array('string', true, 5, 255),
- 'remotelink' => array('string', true, 5, 255),
- 'width' => array('string', true, 1, 3),
- 'height' => array('string', true, 1, 3),
- );
+ // Handle avatar
+ $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', ''));
- if (!($error = validate_data($data, $var_ary)))
+ if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete'))
{
- $data['user_id'] = "g$group_id";
+ $driver = $phpbb_avatar_manager->get_driver($driver_name);
+ $result = $driver->process_form($request, $template, $user, $avatar_data, $avatar_error);
- if ((!empty($uploadfile['tmp_name']) || $data['uploadurl']) && $can_upload)
+ if ($result && empty($avatar_error))
{
- list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_upload($data, $error);
- }
- else if ($data['remotelink'])
- {
- list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_remote($data, $error);
+ $result['avatar_type'] = $driver_name;
+ $submit_ary = array_merge($submit_ary, $result);
}
}
- }
- else if ($avatar_select && $config['allow_avatar_local'])
- {
- // check avatar gallery
- if (is_dir($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category))
+ else
{
- $submit_ary['avatar_type'] = AVATAR_GALLERY;
-
- list($submit_ary['avatar_width'], $submit_ary['avatar_height']) = getimagesize($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category . '/' . $avatar_select);
- $submit_ary['avatar'] = $category . '/' . $avatar_select;
- }
- }
- else if ($delete)
- {
- $submit_ary['avatar'] = '';
- $submit_ary['avatar_type'] = $submit_ary['avatar_width'] = $submit_ary['avatar_height'] = 0;
- }
- else if ($data['width'] && $data['height'])
- {
- // Only update the dimensions?
- if ($config['avatar_max_width'] || $config['avatar_max_height'])
- {
- if ($data['width'] > $config['avatar_max_width'] || $data['height'] > $config['avatar_max_height'])
+ $driver = $phpbb_avatar_manager->get_driver($user->data['user_avatar_type']);
+ if ($driver)
{
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
+ $driver->delete($avatar_data);
}
- }
- if (!sizeof($error))
- {
- if ($config['avatar_min_width'] || $config['avatar_min_height'])
- {
- if ($data['width'] < $config['avatar_min_width'] || $data['height'] < $config['avatar_min_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
- }
- }
- }
-
- if (!sizeof($error))
- {
- $submit_ary['avatar_width'] = $data['width'];
- $submit_ary['avatar_height'] = $data['height'];
- }
- }
-
- if ((isset($submit_ary['avatar']) && $submit_ary['avatar'] && (!isset($group_row['group_avatar']))) || $delete)
- {
- if (isset($group_row['group_avatar']) && $group_row['group_avatar'])
- {
- avatar_delete('group', $group_row, true);
+ // Removing the avatar
+ $submit_ary['avatar_type'] = '';
+ $submit_ary['avatar'] = '';
+ $submit_ary['avatar_width'] = 0;
+ $submit_ary['avatar_height'] = 0;
}
}
@@ -443,7 +405,7 @@ class acp_groups
'rank' => 'int',
'colour' => 'string',
'avatar' => 'string',
- 'avatar_type' => 'int',
+ 'avatar_type' => 'string',
'avatar_width' => 'int',
'avatar_height' => 'int',
'receive_pm' => 'int',
@@ -514,7 +476,7 @@ class acp_groups
}
}
- $cache->destroy('sql', GROUPS_TABLE);
+ $cache->destroy('sql', array(GROUPS_TABLE, TEAMPAGE_TABLE));
$message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED';
trigger_error($user->lang[$message] . adm_back_link($this->u_action));
@@ -573,15 +535,43 @@ class acp_groups
$type_closed = ($group_type == GROUP_CLOSED) ? ' checked="checked"' : '';
$type_hidden = ($group_type == GROUP_HIDDEN) ? ' checked="checked"' : '';
- $avatar_img = (!empty($group_row['group_avatar'])) ? get_user_avatar($group_row['group_avatar'], $group_row['group_avatar_type'], $group_row['group_avatar_width'], $group_row['group_avatar_height'], 'GROUP_AVATAR') : '';
-
- $display_gallery = (isset($_POST['display_gallery'])) ? true : false;
-
- if ($config['allow_avatar_local'] && $display_gallery)
+ // Load up stuff for avatars
+ if ($config['allow_avatar'])
{
- avatar_gallery($category, $avatar_select, 4);
+ $avatars_enabled = false;
+ $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $avatar_data['avatar_type']));
+
+ foreach ($avatar_drivers as $current_driver)
+ {
+ $driver = $phpbb_avatar_manager->get_driver($current_driver);
+
+ $avatars_enabled = true;
+ $config_name = $phpbb_avatar_manager->get_driver_config_name($driver);
+ $template->set_filenames(array(
+ 'avatar' => "acp_avatar_options_{$config_name}.html",
+ ));
+
+ if ($driver->prepare_form($request, $template, $user, $avatar_data, $avatar_error))
+ {
+ $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver);
+ $driver_upper = strtoupper($driver_name);
+ $template->assign_block_vars('avatar_drivers', array(
+ 'L_TITLE' => $user->lang($driver_upper . '_TITLE'),
+ 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'),
+
+ 'DRIVER' => $driver_name,
+ 'SELECTED' => $current_driver == $selected_driver,
+ 'OUTPUT' => $template->assign_display('avatar'),
+ ));
+ }
+ }
}
+ $avatar = phpbb_get_group_avatar($group_row, 'GROUP_AVATAR', true);
+
+ // Merge any avatar errors into the primary error array
+ $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error));
+
$back_link = request_var('back_link', '');
switch ($back_link)
@@ -600,12 +590,10 @@ class acp_groups
'S_ADD_GROUP' => ($action == 'add') ? true : false,
'S_GROUP_PERM' => ($action == 'add' && $auth->acl_get('a_authgroups') && $auth->acl_gets('a_aauth', 'a_fauth', 'a_mauth', 'a_uauth')) ? true : false,
'S_INCLUDE_SWATCH' => true,
- 'S_CAN_UPLOAD' => $can_upload,
'S_ERROR' => (sizeof($error)) ? true : false,
'S_SPECIAL_GROUP' => ($group_type == GROUP_SPECIAL) ? true : false,
- 'S_DISPLAY_GALLERY' => ($config['allow_avatar_local'] && !$display_gallery) ? true : false,
- 'S_IN_GALLERY' => ($config['allow_avatar_local'] && $display_gallery) ? true : false,
'S_USER_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false,
+ 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled),
'ERROR_MSG' => (sizeof($error)) ? implode(' ', $error) : '',
'GROUP_NAME' => ($group_type == GROUP_SPECIAL) ? $user->lang['G_' . $group_name] : $group_name,
@@ -626,8 +614,7 @@ class acp_groups
'S_RANK_OPTIONS' => $rank_options,
'S_GROUP_OPTIONS' => group_select_options(false, false, (($user->data['user_type'] == USER_FOUNDER) ? false : 0)),
- 'AVATAR' => $avatar_img,
- 'AVATAR_IMAGE' => $avatar_img,
+ 'AVATAR' => empty($avatar) ? '' : $avatar,
'AVATAR_MAX_FILESIZE' => $config['avatar_filesize'],
'AVATAR_WIDTH' => (isset($group_row['group_avatar_width'])) ? $group_row['group_avatar_width'] : '',
'AVATAR_HEIGHT' => (isset($group_row['group_avatar_height'])) ? $group_row['group_avatar_height'] : '',
@@ -829,56 +816,112 @@ class acp_groups
public function manage_position()
{
- global $config, $db, $template, $user;
+ global $config, $db, $template, $user, $request, $phpbb_container;
$this->tpl_name = 'acp_groups_position';
$this->page_title = 'ACP_GROUPS_POSITION';
- $field = request_var('field', '');
- $action = request_var('action', '');
- $group_id = request_var('g', 0);
+ $field = $request->variable('field', '');
+ $action = $request->variable('action', '');
+ $group_id = $request->variable('g', 0);
+ $teampage_id = $request->variable('t', 0);
+ $category_id = $request->variable('c', 0);
if ($field && !in_array($field, array('legend', 'teampage')))
{
// Invalid mode
trigger_error($user->lang['NO_MODE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
- else if ($field)
+ else if ($field && in_array($field, array('legend', 'teampage')))
{
- $group_position = new phpbb_group_positions($db, $field, $this->u_action);
+
+ $group_position = $phpbb_container->get('groupposition.' . $field);
}
- switch ($action)
+ if ($field == 'teampage')
{
- case 'set_config_legend':
- set_config('legend_sort_groupname', request_var('legend_sort_groupname', 0));
- break;
+ try
+ {
+ switch ($action)
+ {
+ case 'add':
+ $group_position->add_group_teampage($group_id, $category_id);
+ break;
- case 'set_config_teampage':
- set_config('teampage_forums', request_var('teampage_forums', 0));
- set_config('teampage_memberships', request_var('teampage_memberships', 0));
- break;
+ case 'add_category':
+ $group_position->add_category_teampage($request->variable('category_name', '', true));
+ break;
- case 'add':
- $group_position->add_group($group_id);
- break;
+ case 'delete':
+ $group_position->delete_teampage($teampage_id);
+ break;
- case 'delete':
- $group_position->delete_group($group_id);
- break;
+ case 'move_up':
+ $group_position->move_up_teampage($teampage_id);
+ break;
- case 'move_up':
- $group_position->move_up($group_id);
- break;
+ case 'move_down':
+ $group_position->move_down_teampage($teampage_id);
+ break;
+ }
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()) . adm_back_link($this->u_action), E_USER_WARNING);
+ }
+ }
+ else if ($field == 'legend')
+ {
+ try
+ {
+ switch ($action)
+ {
+ case 'add':
+ $group_position->add_group($group_id);
+ break;
- case 'move_down':
- $group_position->move_down($group_id);
- break;
+ case 'delete':
+ $group_position->delete_group($group_id);
+ break;
+
+ case 'move_up':
+ $group_position->move_up($group_id);
+ break;
+
+ case 'move_down':
+ $group_position->move_down($group_id);
+ break;
+ }
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()) . adm_back_link($this->u_action), E_USER_WARNING);
+ }
+ }
+ else
+ {
+ switch ($action)
+ {
+ case 'set_config_teampage':
+ $config->set('teampage_forums', $request->variable('teampage_forums', 0));
+ $config->set('teampage_memberships', $request->variable('teampage_memberships', 0));
+ break;
+
+ case 'set_config_legend':
+ $config->set('legend_sort_groupname', $request->variable('legend_sort_groupname', 0));
+ break;
+ }
+ }
+
+ if (($action == 'move_up' || $action == 'move_down') && $request->is_ajax())
+ {
+ $json_response = new phpbb_json_response;
+ $json_response->send(array('success' => true));
}
$sql = 'SELECT group_id, group_name, group_colour, group_type, group_legend
FROM ' . GROUPS_TABLE . '
- ORDER BY group_legend, group_name ASC';
+ ORDER BY group_legend ASC, group_type DESC, group_name ASC';
$result = $db->sql_query($sql);
$s_group_select_legend = '';
@@ -888,57 +931,99 @@ class acp_groups
if ($row['group_legend'])
{
$template->assign_block_vars('legend', array(
- 'GROUP_NAME' => $group_name,
- 'GROUP_COLOUR' => ($row['group_colour']) ? ' style="color: #' . $row['group_colour'] . '"' : '',
- 'GROUP_TYPE' => $user->lang[phpbb_group_positions::group_type_language($row['group_type'])],
+ 'GROUP_NAME' => $group_name,
+ 'GROUP_COLOUR' => ($row['group_colour']) ? '#' . $row['group_colour'] : '',
+ 'GROUP_TYPE' => $user->lang[phpbb_groupposition_legend::group_type_language($row['group_type'])],
- 'U_MOVE_DOWN' => "{$this->u_action}&field=legend&action=move_down&g=" . $row['group_id'],
- 'U_MOVE_UP' => "{$this->u_action}&field=legend&action=move_up&g=" . $row['group_id'],
- 'U_DELETE' => "{$this->u_action}&field=legend&action=delete&g=" . $row['group_id'],
+ 'U_MOVE_DOWN' => "{$this->u_action}&field=legend&action=move_down&g=" . $row['group_id'],
+ 'U_MOVE_UP' => "{$this->u_action}&field=legend&action=move_up&g=" . $row['group_id'],
+ 'U_DELETE' => "{$this->u_action}&field=legend&action=delete&g=" . $row['group_id'],
));
}
else
{
- $s_group_select_legend .= '';
+ $template->assign_block_vars('add_legend', array(
+ 'GROUP_ID' => (int) $row['group_id'],
+ 'GROUP_NAME' => $group_name,
+ 'GROUP_SPECIAL' => ($row['group_type'] == GROUP_SPECIAL),
+ ));
}
}
$db->sql_freeresult($result);
- $sql = 'SELECT group_id, group_name, group_colour, group_type, group_teampage
- FROM ' . GROUPS_TABLE . '
- ORDER BY group_teampage, group_name ASC';
+ $category_url_param = (($category_id) ? '&c=' . $category_id : '');
+
+ $sql = 'SELECT t.*, g.group_name, g.group_colour, g.group_type
+ FROM ' . TEAMPAGE_TABLE . ' t
+ LEFT JOIN ' . GROUPS_TABLE . ' g
+ ON (t.group_id = g.group_id)
+ WHERE t.teampage_parent = ' . $category_id . '
+ OR t.teampage_id = ' . $category_id . '
+ ORDER BY t.teampage_position ASC';
+ $result = $db->sql_query($sql);
+
+ $category_data = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ if ($row['teampage_id'] == $category_id)
+ {
+ $template->assign_vars(array(
+ 'CURRENT_CATEGORY_NAME' => $row['teampage_name'],
+ ));
+ continue;
+ }
+
+ if ($row['group_id'])
+ {
+ $group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
+ $group_type = $user->lang[phpbb_groupposition_teampage::group_type_language($row['group_type'])];
+ }
+ else
+ {
+ $group_name = $row['teampage_name'];
+ $group_type = '';
+ }
+
+ $template->assign_block_vars('teampage', array(
+ 'GROUP_NAME' => $group_name,
+ 'GROUP_COLOUR' => ($row['group_colour']) ? '#' . $row['group_colour'] : '',
+ 'GROUP_TYPE' => $group_type,
+
+ 'U_CATEGORY' => (!$row['group_id']) ? "{$this->u_action}&c=" . $row['teampage_id'] : '',
+ 'U_MOVE_DOWN' => "{$this->u_action}&field=teampage&action=move_down{$category_url_param}&t=" . $row['teampage_id'],
+ 'U_MOVE_UP' => "{$this->u_action}&field=teampage&action=move_up{$category_url_param}&t=" . $row['teampage_id'],
+ 'U_DELETE' => "{$this->u_action}&field=teampage&action=delete{$category_url_param}&t=" . $row['teampage_id'],
+ ));
+ }
+ $db->sql_freeresult($result);
+
+ $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type
+ FROM ' . GROUPS_TABLE . ' g
+ LEFT JOIN ' . TEAMPAGE_TABLE . ' t
+ ON (t.group_id = g.group_id)
+ WHERE t.teampage_id IS NULL
+ ORDER BY g.group_type DESC, g.group_name ASC';
$result = $db->sql_query($sql);
$s_group_select_teampage = '';
while ($row = $db->sql_fetchrow($result))
{
$group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
- if ($row['group_teampage'])
- {
- $template->assign_block_vars('teampage', array(
- 'GROUP_NAME' => $group_name,
- 'GROUP_COLOUR' => ($row['group_colour']) ? ' style="color: #' . $row['group_colour'] . '"' : '',
- 'GROUP_TYPE' => $user->lang[phpbb_group_positions::group_type_language($row['group_type'])],
-
- 'U_MOVE_DOWN' => "{$this->u_action}&field=teampage&action=move_down&g=" . $row['group_id'],
- 'U_MOVE_UP' => "{$this->u_action}&field=teampage&action=move_up&g=" . $row['group_id'],
- 'U_DELETE' => "{$this->u_action}&field=teampage&action=delete&g=" . $row['group_id'],
- ));
- }
- else
- {
- $s_group_select_teampage .= '';
- }
+ $template->assign_block_vars('add_teampage', array(
+ 'GROUP_ID' => (int) $row['group_id'],
+ 'GROUP_NAME' => $group_name,
+ 'GROUP_SPECIAL' => ($row['group_type'] == GROUP_SPECIAL),
+ ));
}
$db->sql_freeresult($result);
$template->assign_vars(array(
- 'U_ACTION' => $this->u_action,
- 'U_ACTION_LEGEND' => $this->u_action . '&field=legend',
- 'U_ACTION_TEAMPAGE' => $this->u_action . '&field=teampage',
+ 'U_ACTION' => $this->u_action,
+ 'U_ACTION_LEGEND' => $this->u_action . '&field=legend',
+ 'U_ACTION_TEAMPAGE' => $this->u_action . '&field=teampage' . $category_url_param,
+ 'U_ACTION_TEAMPAGE_CAT' => $this->u_action . '&field=teampage_cat',
- 'S_GROUP_SELECT_LEGEND' => $s_group_select_legend,
- 'S_GROUP_SELECT_TEAMPAGE' => $s_group_select_teampage,
+ 'S_TEAMPAGE_CATEGORY' => $category_id,
'DISPLAY_FORUMS' => ($config['teampage_forums']) ? true : false,
'DISPLAY_MEMBERSHIPS' => $config['teampage_memberships'],
'LEGEND_SORT_GROUPNAME' => ($config['legend_sort_groupname']) ? true : false,
diff --git a/phpBB/includes/acp/acp_modules.php b/phpBB/includes/acp/acp_modules.php
index 52a82004e8..7c2ea86122 100644
--- a/phpBB/includes/acp/acp_modules.php
+++ b/phpBB/includes/acp/acp_modules.php
@@ -535,8 +535,14 @@ class acp_modules
/**
* Get available module information from module files
+ *
+ * @param string $module
+ * @param bool|string $module_class
+ * @param bool $use_all_available Use all available instead of just all
+ * enabled extensions
+ * @return array
*/
- function get_module_infos($module = '', $module_class = false)
+ function get_module_infos($module = '', $module_class = false, $use_all_available = false)
{
global $phpbb_root_path, $phpEx;
@@ -556,7 +562,7 @@ class acp_modules
->extension_directory("/$module_class")
->core_path("includes/$module_class/info/")
->core_prefix($module_class . '_')
- ->get_classes();
+ ->get_classes(true, $use_all_available);
foreach ($modules as $module)
{
@@ -594,11 +600,11 @@ class acp_modules
if (!class_exists($info_class))
{
- if (file_exists($directory . $module . '.' . $phpEx))
+ $info_class = $module . '_info';
+ if (!class_exists($info_class) && file_exists($directory . $module . '.' . $phpEx))
{
include($directory . $module . '.' . $phpEx);
}
- $info_class = $module . '_info';
}
// Get module title tag
diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php
index 266495972b..094d84de40 100644
--- a/phpBB/includes/acp/acp_styles.php
+++ b/phpBB/includes/acp/acp_styles.php
@@ -68,13 +68,20 @@ class acp_styles
$action = $this->request->variable('action', '');
$post_actions = array('install', 'activate', 'deactivate', 'uninstall');
+
+ if ($action && in_array($action, $post_actions) && !check_link_hash($request->variable('hash', ''), $action))
+ {
+ trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+ }
+
foreach ($post_actions as $key)
{
- if (isset($_POST[$key]))
+ if ($this->request->is_set_post($key))
{
$action = $key;
}
}
+
if ($action != '')
{
$this->s_hidden_fields['action'] = $action;
@@ -921,21 +928,23 @@ class acp_styles
'L_ACTION' => $this->user->lang['DETAILS']
);
- // Activate
+ // Activate/Deactive
+ $action_name = ($style['style_active'] ? 'de' : '') . 'activate';
+
$actions[] = array(
- 'U_ACTION' => $this->u_action . '&action=' . ($style['style_active'] ? 'de' : '') . 'activate&id=' . $style['style_id'],
+ 'U_ACTION' => $this->u_action . '&action=' . $action_name . '&hash=' . generate_link_hash($action_name) . '&id=' . $style['style_id'],
'L_ACTION' => $this->user->lang['STYLE_' . ($style['style_active'] ? 'DE' : '') . 'ACTIVATE']
);
/* // Export
$actions[] = array(
- 'U_ACTION' => $this->u_action . '&action=export&id=' . $style['style_id'],
+ 'U_ACTION' => $this->u_action . '&action=export&hash=' . generate_link_hash('export') . '&id=' . $style['style_id'],
'L_ACTION' => $this->user->lang['EXPORT']
); */
// Uninstall
$actions[] = array(
- 'U_ACTION' => $this->u_action . '&action=uninstall&id=' . $style['style_id'],
+ 'U_ACTION' => $this->u_action . '&action=uninstall&hash=' . generate_link_hash('uninstall') . '&id=' . $style['style_id'],
'L_ACTION' => $this->user->lang['STYLE_UNINSTALL']
);
@@ -957,7 +966,7 @@ class acp_styles
else
{
$actions[] = array(
- 'U_ACTION' => $this->u_action . '&action=install&dir=' . urlencode($style['style_path']),
+ 'U_ACTION' => $this->u_action . '&action=install&hash=' . generate_link_hash('install') . '&dir=' . urlencode($style['style_path']),
'L_ACTION' => $this->user->lang['INSTALL_STYLE']
);
}
diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php
index 82d8ef5cbb..8f4a22b61f 100644
--- a/phpBB/includes/acp/acp_users.php
+++ b/phpBB/includes/acp/acp_users.php
@@ -33,6 +33,7 @@ class acp_users
global $config, $db, $user, $auth, $template, $cache;
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix, $file_uploads;
global $phpbb_dispatcher, $request;
+ global $phpbb_container;
$user->add_lang(array('posting', 'ucp', 'acp/users'));
$this->tpl_name = 'acp_users';
@@ -456,7 +457,7 @@ class acp_users
$sql_ary = array(
'user_avatar' => '',
- 'user_avatar_type' => 0,
+ 'user_avatar_type' => '',
'user_avatar_width' => 0,
'user_avatar_height' => 0,
);
@@ -467,9 +468,11 @@ class acp_users
$db->sql_query($sql);
// Delete old avatar if present
- if ($user_row['user_avatar'] && $user_row['user_avatar_type'] != AVATAR_GALLERY)
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $driver = $phpbb_avatar_manager->get_driver($user_row['user_avatar_type']);
+ if ($driver)
{
- avatar_delete('user', $user_row);
+ $driver->delete($user_row);
}
add_log('admin', 'LOG_USER_DEL_AVATAR', $user_row['username']);
@@ -1728,65 +1731,120 @@ class acp_users
case 'avatar':
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
- include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
- $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false;
+ $avatars_enabled = false;
- if ($submit)
+ if ($config['allow_avatar'])
{
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers();
- if (!check_form_key($form_name))
+ // This is normalised data, without the user_ prefix
+ $avatar_data = phpbb_avatar_manager::clean_row($user_row);
+
+ if ($submit)
{
+ if (check_form_key($form_name))
+ {
+ $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', ''));
+
+ if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete'))
+ {
+ $driver = $phpbb_avatar_manager->get_driver($driver_name);
+ $result = $driver->process_form($request, $template, $user, $avatar_data, $error);
+
+ if ($result && empty($error))
+ {
+ // Success! Lets save the result in the database
+ $result = array(
+ 'user_avatar_type' => $driver_name,
+ 'user_avatar' => $result['avatar'],
+ 'user_avatar_width' => $result['avatar_width'],
+ 'user_avatar_height' => $result['avatar_height'],
+ );
+
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $result) . '
+ WHERE user_id = ' . (int) $user_id;
+
+ $db->sql_query($sql);
+ trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id));
+ }
+ }
+ else
+ {
+ $driver = $phpbb_avatar_manager->get_driver($user->data['user_avatar_type']);
+ if ($driver)
+ {
+ $driver->delete($avatar_data);
+ }
+
+ // Removing the avatar
+ $result = array(
+ 'user_avatar' => '',
+ 'user_avatar_type' => '',
+ 'user_avatar_width' => 0,
+ 'user_avatar_height' => 0,
+ );
+
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $result) . '
+ WHERE user_id = ' . (int) $user_id;
+
+ $db->sql_query($sql);
+ trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id));
+ }
+ }
+ else
+ {
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING);
+ }
}
- if (avatar_process_user($error, $user_row, $can_upload))
+ $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $user_row['user_avatar_type']));
+
+ foreach ($avatar_drivers as $current_driver)
{
- trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_row['user_id']));
+ $driver = $phpbb_avatar_manager->get_driver($current_driver);
+
+ $avatars_enabled = true;
+ $config_name = $phpbb_avatar_manager->get_driver_config_name($driver);
+ $template->set_filenames(array(
+ 'avatar' => "acp_avatar_options_{$config_name}.html",
+ ));
+
+ if ($driver->prepare_form($request, $template, $user, $avatar_data, $error))
+ {
+ $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver);
+ $driver_upper = strtoupper($driver_name);
+
+ $template->assign_block_vars('avatar_drivers', array(
+ 'L_TITLE' => $user->lang($driver_upper . '_TITLE'),
+ 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'),
+
+ 'DRIVER' => $driver_name,
+ 'SELECTED' => $current_driver == $selected_driver,
+ 'OUTPUT' => $template->assign_display('avatar'),
+ ));
+ }
}
-
- // Replace "error" strings with their real, localised form
- $error = array_map(array($user, 'lang'), $error);
}
- if (!$config['allow_avatar'] && $user_row['user_avatar_type'])
- {
- $error[] = $user->lang['USER_AVATAR_NOT_ALLOWED'];
- }
- else if ((($user_row['user_avatar_type'] == AVATAR_UPLOAD) && !$config['allow_avatar_upload']) ||
- (($user_row['user_avatar_type'] == AVATAR_REMOTE) && !$config['allow_avatar_remote']) ||
- (($user_row['user_avatar_type'] == AVATAR_GALLERY) && !$config['allow_avatar_local']))
- {
- $error[] = $user->lang['USER_AVATAR_TYPE_NOT_ALLOWED'];
- }
+ // Replace "error" strings with their real, localised form
+ $error = $phpbb_avatar_manager->localize_errors($user, $error);
- // Generate users avatar
- $avatar_img = ($user_row['user_avatar']) ? get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height'], 'USER_AVATAR', true) : '';
-
- $display_gallery = (isset($_POST['display_gallery'])) ? true : false;
- $avatar_select = basename(request_var('avatar_select', ''));
- $category = basename(request_var('category', ''));
-
- if ($config['allow_avatar_local'] && $display_gallery)
- {
- avatar_gallery($category, $avatar_select, 4);
- }
+ $avatar = phpbb_get_user_avatar($user_row, 'USER_AVATAR', true);
$template->assign_vars(array(
- 'S_AVATAR' => true,
- 'S_CAN_UPLOAD' => $can_upload,
- 'S_UPLOAD_FILE' => ($config['allow_avatar'] && $can_upload && $config['allow_avatar_upload']) ? true : false,
- 'S_REMOTE_UPLOAD' => ($config['allow_avatar'] && $can_upload && $config['allow_avatar_remote_upload']) ? true : false,
- 'S_ALLOW_REMOTE' => ($config['allow_avatar'] && $config['allow_avatar_remote']) ? true : false,
- 'S_DISPLAY_GALLERY' => ($config['allow_avatar'] && $config['allow_avatar_local'] && !$display_gallery) ? true : false,
- 'S_IN_GALLERY' => ($config['allow_avatar'] && $config['allow_avatar_local'] && $display_gallery) ? true : false,
+ 'S_AVATAR' => true,
+ 'ERROR' => (!empty($error)) ? implode(' ', $error) : '',
+ 'AVATAR' => (empty($avatar) ? '' : $avatar),
- 'AVATAR_IMAGE' => $avatar_img,
- 'AVATAR_MAX_FILESIZE' => $config['avatar_filesize'],
- 'USER_AVATAR_WIDTH' => $user_row['user_avatar_width'],
- 'USER_AVATAR_HEIGHT' => $user_row['user_avatar_height'],
+ 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"',
- 'L_AVATAR_EXPLAIN' => phpbb_avatar_explanation_string(),
+ 'L_AVATAR_EXPLAIN' => sprintf($user->lang['AVATAR_EXPLAIN'], $config['avatar_max_width'], $config['avatar_max_height'], $config['avatar_filesize'] / 1024),
+
+ 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled),
));
break;
diff --git a/phpBB/includes/avatar/driver/driver.php b/phpBB/includes/avatar/driver/driver.php
new file mode 100644
index 0000000000..29c58d4e62
--- /dev/null
+++ b/phpBB/includes/avatar/driver/driver.php
@@ -0,0 +1,138 @@
+config = $config;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+ $this->cache = $cache;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function get_custom_html($user, $row, $alt = '')
+ {
+ return '';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepare_form_acp($user)
+ {
+ return array();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function delete($row)
+ {
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function get_template_name()
+ {
+ $driver = preg_replace('#^phpbb_avatar_driver_#', '', get_class($this));
+ $template = "ucp_avatar_options_$driver.html";
+
+ return $template;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function get_name()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Sets the name of the driver.
+ *
+ * @param string $name Driver name
+ */
+ public function set_name($name)
+ {
+ $this->name = $name;
+ }
+}
diff --git a/phpBB/includes/avatar/driver/gravatar.php b/phpBB/includes/avatar/driver/gravatar.php
new file mode 100644
index 0000000000..2e2ae2071f
--- /dev/null
+++ b/phpBB/includes/avatar/driver/gravatar.php
@@ -0,0 +1,172 @@
+ $row['avatar'],
+ 'width' => $row['avatar_width'],
+ 'height' => $row['avatar_height'],
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function get_custom_html($user, $row, $alt = '')
+ {
+ return 'lang[$alt])) ? $user->lang[$alt] : $alt) . '" />';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepare_form($request, $template, $user, $row, &$error)
+ {
+ $template->assign_vars(array(
+ 'AVATAR_GRAVATAR_WIDTH' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_gravatar_width', 0),
+ 'AVATAR_GRAVATAR_HEIGHT' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_gravatar_width', 0),
+ 'AVATAR_GRAVATAR_EMAIL' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar']) ? $row['avatar'] : '',
+ ));
+
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function process_form($request, $template, $user, $row, &$error)
+ {
+ $row['avatar'] = $request->variable('avatar_gravatar_email', '');
+ $row['avatar_width'] = $request->variable('avatar_gravatar_width', 0);
+ $row['avatar_height'] = $request->variable('avatar_gravatar_height', 0);
+
+ if (!function_exists('validate_data'))
+ {
+ require($this->phpbb_root_path . 'includes/functions_user' . $this->php_ext);
+ }
+
+ $validate_array = validate_data(
+ array(
+ 'email' => $row['avatar'],
+ ),
+ array(
+ 'email' => array(
+ array('string', false, 6, 60),
+ array('email'))
+ )
+ );
+
+ $error = array_merge($error, $validate_array);
+
+ if (!empty($error))
+ {
+ return false;
+ }
+
+ // Make sure getimagesize works...
+ if (function_exists('getimagesize') && ($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0))
+ {
+ /**
+ * default to the minimum of the maximum allowed avatar size if the size
+ * is not or only partially entered
+ */
+ $row['avatar_width'] = $row['avatar_height'] = min($this->config['avatar_max_width'], $this->config['avatar_max_height']);
+ $url = $this->get_gravatar_url($row);
+
+ if (($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0) && (($image_data = getimagesize($url)) === false))
+ {
+ $error[] = 'UNABLE_GET_IMAGE_SIZE';
+ return false;
+ }
+
+ if (!empty($image_data) && ($image_data[0] <= 0 || $image_data[1] <= 0))
+ {
+ $error[] = 'AVATAR_NO_SIZE';
+ return false;
+ }
+
+ $row['avatar_width'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_width'] : $image_data[0];
+ $row['avatar_height'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_height'] : $image_data[1];
+ }
+
+ if ($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0)
+ {
+ $error[] = 'AVATAR_NO_SIZE';
+ return false;
+ }
+
+ if ($this->config['avatar_max_width'] || $this->config['avatar_max_height'])
+ {
+ if ($row['avatar_width'] > $this->config['avatar_max_width'] || $row['avatar_height'] > $this->config['avatar_max_height'])
+ {
+ $error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $row['avatar_width'], $row['avatar_height']);
+ return false;
+ }
+ }
+
+ if ($this->config['avatar_min_width'] || $this->config['avatar_min_height'])
+ {
+ if ($row['avatar_width'] < $this->config['avatar_min_width'] || $row['avatar_height'] < $this->config['avatar_min_height'])
+ {
+ $error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $row['avatar_width'], $row['avatar_height']);
+ return false;
+ }
+ }
+
+ return array(
+ 'avatar' => $row['avatar'],
+ 'avatar_width' => $row['avatar_width'],
+ 'avatar_height' => $row['avatar_height'],
+ );
+ }
+
+ /**
+ * Build gravatar URL for output on page
+ *
+ * @return string Gravatar URL
+ */
+ protected function get_gravatar_url($row)
+ {
+ $url = self::GRAVATAR_URL;
+ $url .= md5(strtolower(trim($row['avatar'])));
+
+ if ($row['avatar_width'] || $row['avatar_height'])
+ {
+ $url .= '?s=' . max($row['avatar_width'], $row['avatar_height']);
+ }
+
+ return $url;
+ }
+}
diff --git a/phpBB/includes/avatar/driver/interface.php b/phpBB/includes/avatar/driver/interface.php
new file mode 100644
index 0000000000..3d62969aef
--- /dev/null
+++ b/phpBB/includes/avatar/driver/interface.php
@@ -0,0 +1,116 @@
+ '', 'width' => 0, 'height' => 0]
+ */
+ public function get_data($row);
+
+ /**
+ * Returns custom html if it is needed for displaying this avatar
+ *
+ * @param phpbb_user $user phpBB user object
+ * @param array $row User data or group data that has been cleaned with
+ * phpbb_avatar_manager::clean_row
+ * @param string $alt Alternate text for avatar image
+ *
+ * @return string HTML
+ */
+ public function get_custom_html($user, $row, $alt = '');
+
+ /**
+ * Prepare form for changing the settings of this avatar
+ *
+ * @param phpbb_request $request Request object
+ * @param phpbb_template $template Template object
+ * @param phpbb_user $user User object
+ * @param array $row User data or group data that has been cleaned with
+ * phpbb_avatar_manager::clean_row
+ * @param array &$error Reference to an error array that is filled by this
+ * function. Key values can either be a string with a language key or
+ * an array that will be passed to vsprintf() with the language key in
+ * the first array key.
+ *
+ * @return bool True if form has been successfully prepared
+ */
+ public function prepare_form($request, $template, $user, $row, &$error);
+
+ /**
+ * Prepare form for changing the acp settings of this avatar
+ *
+ * @param phpbb_user $user phpBB user object
+ *
+ * @return array Array of configuration options as consumed by acp_board.
+ * The setting for enabling/disabling the avatar will be handled by
+ * the avatar manager.
+ */
+ public function prepare_form_acp($user);
+
+ /**
+ * Process form data
+ *
+ * @param phpbb_request $request Request object
+ * @param phpbb_template $template Template object
+ * @param phpbb_user $user User object
+ * @param array $row User data or group data that has been cleaned with
+ * phpbb_avatar_manager::clean_row
+ * @param array &$error Reference to an error array that is filled by this
+ * function. Key values can either be a string with a language key or
+ * an array that will be passed to vsprintf() with the language key in
+ * the first array key.
+ *
+ * @return array Array containing the avatar data as follows:
+ * ['avatar'], ['avatar_width'], ['avatar_height']
+ */
+ public function process_form($request, $template, $user, $row, &$error);
+
+ /**
+ * Delete avatar
+ *
+ * @param array $row User data or group data that has been cleaned with
+ * phpbb_avatar_manager::clean_row
+ *
+ * @return bool True if avatar has been deleted or there is no need to delete,
+ * i.e. when the avatar is not hosted locally.
+ */
+ public function delete($row);
+
+ /**
+ * Get the avatar driver's template name
+ *
+ * @return string Avatar driver's template name
+ */
+ public function get_template_name();
+}
diff --git a/phpBB/includes/avatar/driver/local.php b/phpBB/includes/avatar/driver/local.php
new file mode 100644
index 0000000000..f4bcd4ce74
--- /dev/null
+++ b/phpBB/includes/avatar/driver/local.php
@@ -0,0 +1,197 @@
+ $this->phpbb_root_path . $this->config['avatar_gallery_path'] . '/' . $row['avatar'],
+ 'width' => $row['avatar_width'],
+ 'height' => $row['avatar_height'],
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepare_form($request, $template, $user, $row, &$error)
+ {
+ $avatar_list = $this->get_avatar_list($user);
+ $category = $request->variable('avatar_local_cat', '');
+
+ foreach ($avatar_list as $cat => $null)
+ {
+ if (!empty($avatar_list[$cat]))
+ {
+ $template->assign_block_vars('avatar_local_cats', array(
+ 'NAME' => $cat,
+ 'SELECTED' => ($cat == $category),
+ ));
+ }
+
+ if ($cat != $category)
+ {
+ unset($avatar_list[$cat]);
+ }
+ }
+
+ if (!empty($avatar_list[$category]))
+ {
+ $template->assign_vars(array(
+ 'AVATAR_LOCAL_SHOW' => true,
+ ));
+
+ $table_cols = isset($row['avatar_gallery_cols']) ? $row['avatar_gallery_cols'] : 4;
+ $row_count = $col_count = $avatar_pos = 0;
+ $avatar_count = sizeof($avatar_list[$category]);
+
+ reset($avatar_list[$category]);
+
+ while ($avatar_pos < $avatar_count)
+ {
+ $img = current($avatar_list[$category]);
+ next($avatar_list[$category]);
+
+ if ($col_count == 0)
+ {
+ ++$row_count;
+ $template->assign_block_vars('avatar_local_row', array(
+ ));
+ }
+
+ $template->assign_block_vars('avatar_local_row.avatar_local_col', array(
+ 'AVATAR_IMAGE' => $this->phpbb_root_path . $this->config['avatar_gallery_path'] . '/' . $img['file'],
+ 'AVATAR_NAME' => $img['name'],
+ 'AVATAR_FILE' => $img['filename'],
+ ));
+
+ $template->assign_block_vars('avatar_local_row.avatar_local_option', array(
+ 'AVATAR_FILE' => $img['filename'],
+ 'S_OPTIONS_AVATAR' => $img['filename']
+ ));
+
+ $col_count = ($col_count + 1) % $table_cols;
+
+ ++$avatar_pos;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepare_form_acp($user)
+ {
+ return array(
+ 'avatar_gallery_path' => array('lang' => 'AVATAR_GALLERY_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true),
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function process_form($request, $template, $user, $row, &$error)
+ {
+ $avatar_list = $this->get_avatar_list($user);
+ $category = $request->variable('avatar_local_cat', '');
+
+ $file = $request->variable('avatar_local_file', '');
+
+ if (empty($category) || empty($file))
+ {
+ $error[] = 'NO_AVATAR_SELECTED';
+ return false;
+ }
+
+ if (!isset($avatar_list[$category][urldecode($file)]))
+ {
+ $error[] = 'AVATAR_URL_NOT_FOUND';
+ return false;
+ }
+
+ return array(
+ 'avatar' => ($category != $user->lang['MAIN']) ? $category . '/' . $file : $file,
+ 'avatar_width' => $avatar_list[$category][urldecode($file)]['width'],
+ 'avatar_height' => $avatar_list[$category][urldecode($file)]['height'],
+ );
+ }
+
+ /**
+ * Get a list of avatars that are locally available
+ * Results get cached for 24 hours (86400 seconds)
+ *
+ * @param phpbb_user $user User object
+ *
+ * @return array Array containing the locally available avatars
+ */
+ protected function get_avatar_list($user)
+ {
+ $avatar_list = ($this->cache == null) ? false : $this->cache->get('avatar_local_list');
+
+ if ($avatar_list === false)
+ {
+ $avatar_list = array();
+ $path = $this->phpbb_root_path . $this->config['avatar_gallery_path'];
+
+ $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS | FilesystemIterator::UNIX_PATHS), RecursiveIteratorIterator::SELF_FIRST);
+ foreach ($iterator as $file_info)
+ {
+ $file_path = $file_info->getPath();
+ $image = $file_info->getFilename();
+
+ // Match all images in the gallery folder
+ if (preg_match('#^[^&\'"<>]+\.(?:' . implode('|', $this->allowed_extensions) . ')$#i', $image) && is_file($file_path . '/' . $image))
+ {
+ if (function_exists('getimagesize'))
+ {
+ $dims = getimagesize($file_path . '/' . $image);
+ }
+ else
+ {
+ $dims = array(0, 0);
+ }
+ $cat = ($path == $file_path) ? $user->lang['MAIN'] : str_replace("$path/", '', $file_path);
+ $avatar_list[$cat][$image] = array(
+ 'file' => ($cat != $user->lang['MAIN']) ? rawurlencode($cat) . '/' . rawurlencode($image) : rawurlencode($image),
+ 'filename' => rawurlencode($image),
+ 'name' => ucfirst(str_replace('_', ' ', preg_replace('#^(.*)\..*$#', '\1', $image))),
+ 'width' => $dims[0],
+ 'height' => $dims[1],
+ );
+ }
+ }
+ ksort($avatar_list);
+
+ if ($this->cache != null)
+ {
+ $this->cache->put('avatar_local_list', $avatar_list, 86400);
+ }
+ }
+
+ return $avatar_list;
+ }
+}
diff --git a/phpBB/includes/avatar/driver/remote.php b/phpBB/includes/avatar/driver/remote.php
new file mode 100644
index 0000000000..3661e16160
--- /dev/null
+++ b/phpBB/includes/avatar/driver/remote.php
@@ -0,0 +1,164 @@
+ $row['avatar'],
+ 'width' => $row['avatar_width'],
+ 'height' => $row['avatar_height'],
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepare_form($request, $template, $user, $row, &$error)
+ {
+ $template->assign_vars(array(
+ 'AVATAR_REMOTE_WIDTH' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_remote_width', 0),
+ 'AVATAR_REMOTE_HEIGHT' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_remote_width', 0),
+ 'AVATAR_REMOTE_URL' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar']) ? $row['avatar'] : '',
+ ));
+
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function process_form($request, $template, $user, $row, &$error)
+ {
+ $url = $request->variable('avatar_remote_url', '');
+ $width = $request->variable('avatar_remote_width', 0);
+ $height = $request->variable('avatar_remote_height', 0);
+
+ if (!preg_match('#^(http|https|ftp)://#i', $url))
+ {
+ $url = 'http://' . $url;
+ }
+
+ if (!function_exists('validate_data'))
+ {
+ require($this->phpbb_root_path . 'includes/functions_user' . $this->php_ext);
+ }
+
+ $validate_array = validate_data(
+ array(
+ 'url' => $url,
+ ),
+ array(
+ 'url' => array('string', true, 5, 255),
+ )
+ );
+
+ $error = array_merge($error, $validate_array);
+
+ if (!empty($error))
+ {
+ return false;
+ }
+
+ // Check if this url looks alright
+ // This isn't perfect, but it's what phpBB 3.0 did, and might as well make sure everything is compatible
+ if (!preg_match('#^(http|https|ftp)://(?:(.*?\.)*?[a-z0-9\-]+?\.[a-z]{2,4}|(?:\d{1,3}\.){3,5}\d{1,3}):?([0-9]*?).*?\.('. implode('|', $this->allowed_extensions) . ')$#i', $url))
+ {
+ $error[] = 'AVATAR_URL_INVALID';
+ return false;
+ }
+
+ // Make sure getimagesize works...
+ if (function_exists('getimagesize'))
+ {
+ if (($width <= 0 || $height <= 0) && (($image_data = getimagesize($url)) === false))
+ {
+ $error[] = 'UNABLE_GET_IMAGE_SIZE';
+ return false;
+ }
+
+ if (!empty($image_data) && ($image_data[0] <= 0 || $image_data[1] <= 0))
+ {
+ $error[] = 'AVATAR_NO_SIZE';
+ return false;
+ }
+
+ $width = ($width && $height) ? $width : $image_data[0];
+ $height = ($width && $height) ? $height : $image_data[1];
+ }
+
+ if ($width <= 0 || $height <= 0)
+ {
+ $error[] = 'AVATAR_NO_SIZE';
+ return false;
+ }
+
+ if (!class_exists('fileupload'))
+ {
+ include($this->phpbb_root_path . 'includes/functions_upload' . $this->php_ext);
+ }
+
+ $types = fileupload::image_types();
+ $extension = strtolower(filespec::get_extension($url));
+
+ if (!empty($image_data) && (!isset($types[$image_data[2]]) || !in_array($extension, $types[$image_data[2]])))
+ {
+ if (!isset($types[$image_data[2]]))
+ {
+ $error[] = 'UNABLE_GET_IMAGE_SIZE';
+ }
+ else
+ {
+ $error[] = array('IMAGE_FILETYPE_MISMATCH', $types[$image_data[2]][0], $extension);
+ }
+
+ return false;
+ }
+
+ if ($this->config['avatar_max_width'] || $this->config['avatar_max_height'])
+ {
+ if ($width > $this->config['avatar_max_width'] || $height > $this->config['avatar_max_height'])
+ {
+ $error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $width, $height);
+ return false;
+ }
+ }
+
+ if ($this->config['avatar_min_width'] || $this->config['avatar_min_height'])
+ {
+ if ($width < $this->config['avatar_min_width'] || $height < $this->config['avatar_min_height'])
+ {
+ $error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $width, $height);
+ return false;
+ }
+ }
+
+ return array(
+ 'avatar' => $url,
+ 'avatar_width' => $width,
+ 'avatar_height' => $height,
+ );
+ }
+}
diff --git a/phpBB/includes/avatar/driver/upload.php b/phpBB/includes/avatar/driver/upload.php
new file mode 100644
index 0000000000..f91d170d7c
--- /dev/null
+++ b/phpBB/includes/avatar/driver/upload.php
@@ -0,0 +1,159 @@
+ $this->phpbb_root_path . 'download/file' . $this->php_ext . '?avatar=' . $row['avatar'],
+ 'width' => $row['avatar_width'],
+ 'height' => $row['avatar_height'],
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepare_form($request, $template, $user, $row, &$error)
+ {
+ if (!$this->can_upload())
+ {
+ return false;
+ }
+
+ $template->assign_vars(array(
+ 'S_UPLOAD_AVATAR_URL' => ($this->config['allow_avatar_remote_upload']) ? true : false,
+ 'AVATAR_UPLOAD_SIZE' => $this->config['avatar_filesize'],
+ ));
+
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function process_form($request, $template, $user, $row, &$error)
+ {
+ if (!$this->can_upload())
+ {
+ return false;
+ }
+
+ if (!class_exists('fileupload'))
+ {
+ include($this->phpbb_root_path . 'includes/functions_upload' . $this->php_ext);
+ }
+
+ $upload = new fileupload('AVATAR_', $this->allowed_extensions, $this->config['avatar_filesize'], $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], (isset($this->config['mime_triggers']) ? explode('|', $this->config['mime_triggers']) : false));
+
+ $url = $request->variable('avatar_upload_url', '');
+ $upload_file = $request->file('avatar_upload_file');
+
+ if (!empty($upload_file['name']))
+ {
+ $file = $upload->form_upload('avatar_upload_file');
+ }
+ elseif (!empty($this->config['allow_avatar_remote_upload']) && !empty($url))
+ {
+ $file = $upload->remote_upload($url);
+ }
+ else
+ {
+ $error[] = 'NO_AVATAR_SELECTED';
+ return false;
+ }
+
+ $prefix = $this->config['avatar_salt'] . '_';
+ $file->clean_filename('avatar', $prefix, $row['id']);
+
+ $destination = $this->config['avatar_path'];
+
+ // Adjust destination path (no trailing slash)
+ if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\')
+ {
+ $destination = substr($destination, 0, -1);
+ }
+
+ $destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination);
+ if ($destination && ($destination[0] == '/' || $destination[0] == "\\"))
+ {
+ $destination = '';
+ }
+
+ // Move file and overwrite any existing image
+ $file->move_file($destination, true);
+
+ if (sizeof($file->error))
+ {
+ $file->remove();
+ $error = array_merge($error, $file->error);
+ return false;
+ }
+
+ return array(
+ 'avatar' => $row['id'] . '_' . time() . '.' . $file->get('extension'),
+ 'avatar_width' => $file->get('width'),
+ 'avatar_height' => $file->get('height'),
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepare_form_acp($user)
+ {
+ return array(
+ 'allow_avatar_remote_upload'=> array('lang' => 'ALLOW_REMOTE_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
+ 'avatar_filesize' => array('lang' => 'MAX_FILESIZE', 'validate' => 'int:0', 'type' => 'text:4:10', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']),
+ 'avatar_path' => array('lang' => 'AVATAR_STORAGE_PATH', 'validate' => 'rwpath', 'type' => 'text:20:255', 'explain' => true),
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function delete($row)
+ {
+ $ext = substr(strrchr($row['avatar'], '.'), 1);
+ $filename = $this->phpbb_root_path . $this->config['avatar_path'] . '/' . $this->config['avatar_salt'] . '_' . $row['id'] . '.' . $ext;
+
+ if (file_exists($filename))
+ {
+ @unlink($filename);
+ }
+
+ return true;
+ }
+
+ /**
+ * Check if user is able to upload an avatar
+ *
+ * @return bool True if user can upload, false if not
+ */
+ protected function can_upload()
+ {
+ return (file_exists($this->phpbb_root_path . $this->config['avatar_path']) && phpbb_is_writable($this->phpbb_root_path . $this->config['avatar_path']) && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on'));
+ }
+}
diff --git a/phpBB/includes/avatar/manager.php b/phpBB/includes/avatar/manager.php
new file mode 100644
index 0000000000..58d994c3c0
--- /dev/null
+++ b/phpBB/includes/avatar/manager.php
@@ -0,0 +1,309 @@
+ '',
+ 'avatar_type' => '',
+ 'avatar_width' => '',
+ 'avatar_height' => '',
+ );
+
+ /**
+ * Construct an avatar manager object
+ *
+ * @param phpbb_config $config phpBB configuration
+ * @param array $avatar_drivers Avatar drivers passed via the service container
+ * @param object $container Container object
+ */
+ public function __construct(phpbb_config $config, $avatar_drivers, $container)
+ {
+ $this->config = $config;
+ $this->avatar_drivers = $avatar_drivers;
+ $this->container = $container;
+ }
+
+ /**
+ * Get the driver object specified by the avatar type
+ *
+ * @param string $avatar_type Avatar type; by default an avatar's service container name
+ * @param bool $load_enabled Load only enabled avatars
+ *
+ * @return object Avatar driver object
+ */
+ public function get_driver($avatar_type, $load_enabled = true)
+ {
+ if (self::$enabled_drivers === false)
+ {
+ $this->load_enabled_drivers();
+ }
+
+ $avatar_drivers = ($load_enabled) ? self::$enabled_drivers : $this->get_all_drivers();
+
+ // Legacy stuff...
+ switch ($avatar_type)
+ {
+ case AVATAR_GALLERY:
+ $avatar_type = 'avatar.driver.local';
+ break;
+ case AVATAR_UPLOAD:
+ $avatar_type = 'avatar.driver.upload';
+ break;
+ case AVATAR_REMOTE:
+ $avatar_type = 'avatar.driver.remote';
+ break;
+ }
+
+ if (!isset($avatar_drivers[$avatar_type]))
+ {
+ return null;
+ }
+
+ /*
+ * There is no need to handle invalid avatar types as the following code
+ * will cause a ServiceNotFoundException if the type does not exist
+ */
+ $driver = $this->container->get($avatar_type);
+
+ return $driver;
+ }
+
+ /**
+ * Load the list of enabled drivers
+ * This is executed once and fills self::$enabled_drivers
+ */
+ protected function load_enabled_drivers()
+ {
+ if (!empty($this->avatar_drivers))
+ {
+ self::$enabled_drivers = array();
+ foreach ($this->avatar_drivers as $driver)
+ {
+ if ($this->is_enabled($driver))
+ {
+ self::$enabled_drivers[$driver->get_name()] = $driver->get_name();
+ }
+ }
+ asort(self::$enabled_drivers);
+ }
+ }
+
+ /**
+ * Get a list of all avatar drivers
+ *
+ * As this function will only be called in the ACP avatar settings page, it
+ * doesn't make much sense to cache the list of all avatar drivers like the
+ * list of the enabled drivers.
+ *
+ * @return array Array containing a list of all avatar drivers
+ */
+ public function get_all_drivers()
+ {
+ $drivers = array();
+
+ if (!empty($this->avatar_drivers))
+ {
+ foreach ($this->avatar_drivers as $driver)
+ {
+ $drivers[$driver->get_name()] = $driver->get_name();
+ }
+ asort($drivers);
+ }
+
+ return $drivers;
+ }
+
+ /**
+ * Get a list of enabled avatar drivers
+ *
+ * @return array Array containing a list of the enabled avatar drivers
+ */
+ public function get_enabled_drivers()
+ {
+ if (self::$enabled_drivers === false)
+ {
+ $this->load_enabled_drivers();
+ }
+
+ return self::$enabled_drivers;
+ }
+
+ /**
+ * Strip out user_ and group_ prefixes from keys
+ *
+ * @param array $row User data or group data
+ *
+ * @return array User data or group data with keys that have been
+ * stripped from the preceding "user_" or "group_"
+ */
+ static public function clean_row($row)
+ {
+ // Upon creation of a user/group $row might be empty
+ if (empty($row))
+ {
+ return self::$default_row;
+ }
+
+ $keys = array_keys($row);
+ $values = array_values($row);
+
+ $keys = array_map(array('phpbb_avatar_manager', 'strip_prefix'), $keys);
+
+ return array_combine($keys, $values);
+ }
+
+ /**
+ * Strip prepending user_ or group_ prefix from key
+ *
+ * @param string Array key
+ * @return string Key that has been stripped from its prefix
+ */
+ static protected function strip_prefix($key)
+ {
+ return preg_replace('#^(?:user_|group_)#', '', $key);
+ }
+
+ /**
+ * Clean driver names that are returned from template files
+ * Underscores are replaced with dots
+ *
+ * @param string $name Driver name
+ *
+ * @return string Cleaned driver name
+ */
+ static public function clean_driver_name($name)
+ {
+ return str_replace('_', '.', $name);
+ }
+
+ /**
+ * Prepare driver names for use in template files
+ * Dots are replaced with underscores
+ *
+ * @param string $name Clean driver name
+ *
+ * @return string Prepared driver name
+ */
+ static public function prepare_driver_name($name)
+ {
+ return str_replace('.', '_', $name);
+ }
+
+ /**
+ * Check if avatar is enabled
+ *
+ * @param object $driver Avatar driver object
+ *
+ * @return bool True if avatar is enabled, false if it's disabled
+ */
+ public function is_enabled($driver)
+ {
+ $config_name = $this->get_driver_config_name($driver);
+
+ return $this->config["allow_avatar_{$config_name}"];
+ }
+
+ /**
+ * Get the settings array for enabling/disabling an avatar driver
+ *
+ * @param object $driver Avatar driver object
+ *
+ * @return array Array of configuration options as consumed by acp_board
+ */
+ public function get_avatar_settings($driver)
+ {
+ $config_name = $this->get_driver_config_name($driver);
+
+ return array(
+ 'allow_avatar_' . $config_name => array('lang' => 'ALLOW_' . strtoupper($config_name), 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
+ );
+ }
+
+ /**
+ * Get the config name of an avatar driver
+ *
+ * @param object $driver Avatar driver object
+ *
+ * @return string Avatar driver config name
+ */
+ public function get_driver_config_name($driver)
+ {
+ return preg_replace('#^phpbb_avatar_driver_#', '', get_class($driver));
+ }
+
+ /**
+ * Replace "error" strings with their real, localized form
+ *
+ * @param phpbb_user phpBB User object
+ * @param array $error Array containing error strings
+ * Key values can either be a string with a language key or an array
+ * that will be passed to vsprintf() with the language key in the
+ * first array key.
+ *
+ * @return array Array containing the localized error strings
+ */
+ public function localize_errors(phpbb_user $user, $error)
+ {
+ foreach ($error as $key => $lang)
+ {
+ if (is_array($lang))
+ {
+ $lang_key = array_shift($lang);
+ $error[$key] = vsprintf($user->lang($lang_key), $lang);
+ }
+ else
+ {
+ $error[$key] = $user->lang("$lang");
+ }
+ }
+
+ return $error;
+ }
+}
diff --git a/phpBB/includes/config/db_text.php b/phpBB/includes/config/db_text.php
new file mode 100644
index 0000000000..b365cb5c77
--- /dev/null
+++ b/phpBB/includes/config/db_text.php
@@ -0,0 +1,163 @@
+db = $db;
+ $this->table = $this->db->sql_escape($table);
+ }
+
+ /**
+ * Sets the configuration option with the name $key to $value.
+ *
+ * @param string $key The configuration option's name
+ * @param string $value New configuration value
+ *
+ * @return null
+ */
+ public function set($key, $value)
+ {
+ $this->set_array(array($key => $value));
+ }
+
+ /**
+ * Gets the configuration value for the name $key.
+ *
+ * @param string $key The configuration option's name
+ *
+ * @return string|null String result on success
+ * null if there is no such option
+ */
+ public function get($key)
+ {
+ $map = $this->get_array(array($key));
+
+ return isset($map[$key]) ? $map[$key] : null;
+ }
+
+ /**
+ * Removes the configuration option with the name $key.
+ *
+ * @param string $key The configuration option's name
+ *
+ * @return null
+ */
+ public function delete($key)
+ {
+ $this->delete_array(array($key));
+ }
+
+ /**
+ * Mass set configuration options: Receives an associative array,
+ * treats array keys as configuration option names and associated
+ * array values as their configuration option values.
+ *
+ * @param array $map Map from configuration names to values
+ *
+ * @return null
+ */
+ public function set_array(array $map)
+ {
+ $this->db->sql_transaction('begin');
+
+ foreach ($map as $key => $value)
+ {
+ $sql = 'UPDATE ' . $this->table . "
+ SET config_value = '" . $this->db->sql_escape($value) . "'
+ WHERE config_name = '" . $this->db->sql_escape($key) . "'";
+ $result = $this->db->sql_query($sql);
+
+ if (!$this->db->sql_affectedrows($result))
+ {
+ $sql = 'INSERT INTO ' . $this->table . ' ' . $this->db->sql_build_array('INSERT', array(
+ 'config_name' => $key,
+ 'config_value' => $value,
+ ));
+ $this->db->sql_query($sql);
+ }
+ }
+
+ $this->db->sql_transaction('commit');
+ }
+
+ /**
+ * Mass get configuration options: Receives a set of configuration
+ * option names and returns the result as a key => value map where
+ * array keys are configuration option names and array values are
+ * associated config option values.
+ *
+ * @param array $keys Set of configuration option names
+ *
+ * @return array Map from configuration names to values
+ */
+ public function get_array(array $keys)
+ {
+ $sql = 'SELECT *
+ FROM ' . $this->table . '
+ WHERE ' . $this->db->sql_in_set('config_name', $keys, false, true);
+ $result = $this->db->sql_query($sql);
+
+ $map = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $map[$row['config_name']] = $row['config_value'];
+ }
+ $this->db->sql_freeresult($result);
+
+ return $map;
+ }
+
+ /**
+ * Mass delete configuration options.
+ *
+ * @param array $keys Set of configuration option names
+ *
+ * @return null
+ */
+ public function delete_array(array $keys)
+ {
+ $sql = 'DELETE
+ FROM ' . $this->table . '
+ WHERE ' . $this->db->sql_in_set('config_name', $keys, false, true);
+ $result = $this->db->sql_query($sql);
+ }
+}
diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php
index 68c96a2759..8c27d3fd0c 100644
--- a/phpBB/includes/constants.php
+++ b/phpBB/includes/constants.php
@@ -240,6 +240,8 @@ define('LOGIN_ATTEMPT_TABLE', $table_prefix . 'login_attempts');
define('MIGRATIONS_TABLE', $table_prefix . 'migrations');
define('MODERATOR_CACHE_TABLE', $table_prefix . 'moderator_cache');
define('MODULES_TABLE', $table_prefix . 'modules');
+define('NOTIFICATION_TYPES_TABLE', $table_prefix . 'notification_types');
+define('NOTIFICATIONS_TABLE', $table_prefix . 'notifications');
define('POLL_OPTIONS_TABLE', $table_prefix . 'poll_options');
define('POLL_VOTES_TABLE', $table_prefix . 'poll_votes');
define('POSTS_TABLE', $table_prefix . 'posts');
@@ -268,11 +270,13 @@ define('STYLES_TEMPLATE_DATA_TABLE',$table_prefix . 'styles_template_data');
define('STYLES_THEME_TABLE', $table_prefix . 'styles_theme');
define('STYLES_IMAGESET_TABLE', $table_prefix . 'styles_imageset');
define('STYLES_IMAGESET_DATA_TABLE',$table_prefix . 'styles_imageset_data');
+define('TEAMPAGE_TABLE', $table_prefix . 'teampage');
define('TOPICS_TABLE', $table_prefix . 'topics');
define('TOPICS_POSTED_TABLE', $table_prefix . 'topics_posted');
define('TOPICS_TRACK_TABLE', $table_prefix . 'topics_track');
define('TOPICS_WATCH_TABLE', $table_prefix . 'topics_watch');
define('USER_GROUP_TABLE', $table_prefix . 'user_group');
+define('USER_NOTIFICATIONS_TABLE', $table_prefix . 'user_notifications');
define('USERS_TABLE', $table_prefix . 'users');
define('WARNINGS_TABLE', $table_prefix . 'warnings');
define('WORDS_TABLE', $table_prefix . 'words');
diff --git a/phpBB/includes/db/migration/data/310/avatars.php b/phpBB/includes/db/migration/data/310/avatars.php
new file mode 100644
index 0000000000..79547337f7
--- /dev/null
+++ b/phpBB/includes/db/migration/data/310/avatars.php
@@ -0,0 +1,67 @@
+config['allow_avatar_gravatar']);
+ }
+
+ static public function depends_on()
+ {
+ return array('phpbb_db_migration_data_30x_3_0_11');
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'change_columns' => array(
+ $this->table_prefix . 'users' => array(
+ 'user_avatar_type' => array('VCHAR:255', ''),
+ ),
+ $this->table_prefix . 'groups' => array(
+ 'group_avatar_type' => array('VCHAR:255', ''),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'change_columns' => array(
+ $this->table_prefix . 'users' => array(
+ 'user_avatar_type' => array('TINT:2', ''),
+ ),
+ $this->table_prefix . 'groups' => array(
+ 'group_avatar_type' => array('TINT:2', ''),
+ ),
+ ),
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('allow_avatar_gravatar', 0)),
+ array('custom', array(array($this, 'update_module_auth'))),
+ );
+ }
+
+ public function update_module_auth()
+ {
+ $sql = 'UPDATE ' . $this->table_prefix . "modules
+ SET module_auth = 'cfg_allow_avatar'
+ WHERE module_class = 'ucp'
+ AND module_basename = 'ucp_profile'
+ AND module_mode = 'avatar'";
+ $this->db->sql_query($sql);
+ }
+}
diff --git a/phpBB/includes/db/migration/data/310/config_db_text.php b/phpBB/includes/db/migration/data/310/config_db_text.php
new file mode 100644
index 0000000000..89f211adda
--- /dev/null
+++ b/phpBB/includes/db/migration/data/310/config_db_text.php
@@ -0,0 +1,45 @@
+db_tools->sql_table_exists($this->table_prefix . 'config_text');
+ }
+
+ static public function depends_on()
+ {
+ return array('phpbb_db_migration_data_30x_3_0_11');
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'add_tables' => array(
+ $this->table_prefix . 'config_text' => array(
+ 'COLUMNS' => array(
+ 'config_name' => array('VCHAR', ''),
+ 'config_value' => array('MTEXT', ''),
+ ),
+ 'PRIMARY_KEY' => 'config_name',
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_tables' => array(
+ $this->table_prefix . 'config_text',
+ ),
+ );
+ }
+}
diff --git a/phpBB/includes/db/migration/data/310/notifications.php b/phpBB/includes/db/migration/data/310/notifications.php
new file mode 100644
index 0000000000..82bfd4cb2d
--- /dev/null
+++ b/phpBB/includes/db/migration/data/310/notifications.php
@@ -0,0 +1,160 @@
+db_tools->sql_table_exists($this->table_prefix . 'notifications');
+ }
+
+ static public function depends_on()
+ {
+ return array('phpbb_db_migration_data_310_dev');
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'add_tables' => array(
+ $this->table_prefix . 'notification_types' => array(
+ 'COLUMNS' => array(
+ 'notification_type' => array('VCHAR:255', ''),
+ 'notification_type_enabled' => array('BOOL', 1),
+ ),
+ 'PRIMARY_KEY' => array('notification_type', 'notification_type_enabled'),
+ ),
+ $this->table_prefix . 'notifications' => array(
+ 'COLUMNS' => array(
+ 'notification_id' => array('UINT', NULL, 'auto_increment'),
+ 'item_type' => array('VCHAR:255', ''),
+ 'item_id' => array('UINT', 0),
+ 'item_parent_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'notification_read' => array('BOOL', 0),
+ 'notification_time' => array('TIMESTAMP', 1),
+ 'notification_data' => array('TEXT_UNI', ''),
+ ),
+ 'PRIMARY_KEY' => 'notification_id',
+ 'KEYS' => array(
+ 'item_ident' => array('INDEX', array('item_type', 'item_id')),
+ 'user' => array('INDEX', array('user_id', 'notification_read')),
+ ),
+ ),
+ $this->table_prefix . 'user_notifications' => array(
+ 'COLUMNS' => array(
+ 'item_type' => array('VCHAR:255', ''),
+ 'item_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'method' => array('VCHAR:255', ''),
+ 'notify' => array('BOOL', 1),
+ ),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_tables' => array(
+ $this->table_prefix . 'notification_types',
+ $this->table_prefix . 'notifications',
+ $this->table_prefix . 'user_notifications',
+ ),
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('module.add', array(
+ 'ucp',
+ 'UCP_MAIN',
+ array(
+ 'module_basename' => 'ucp_notifications',
+ 'modes' => array('notification_list'),
+ ),
+ )),
+ array('module.add', array(
+ 'ucp',
+ 'UCP_PREFS',
+ array(
+ 'module_basename' => 'ucp_notifications',
+ 'modes' => array('notification_options'),
+ ),
+ )),
+ array('config.add', array('load_notifications', 1)),
+ array('custom', array(array($this, 'convert_notifications'))),
+ );
+ }
+
+ public function convert_notifications()
+ {
+ $convert_notifications = array(
+ array(
+ 'check' => ($this->config['allow_topic_notify']),
+ 'item_type' => 'post',
+ ),
+ array(
+ 'check' => ($this->config['allow_forum_notify']),
+ 'item_type' => 'topic',
+ ),
+ array(
+ 'check' => ($this->config['allow_bookmarks']),
+ 'item_type' => 'bookmark',
+ ),
+ array(
+ 'check' => ($this->config['allow_privmsg']),
+ 'item_type' => 'pm',
+ ),
+ );
+
+ foreach ($convert_notifications as $convert_data)
+ {
+ if ($convert_data['check'])
+ {
+ $sql = 'SELECT user_id, user_notify_type
+ FROM ' . USERS_TABLE . '
+ WHERE user_notify = 1';
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $this->sql_query('INSERT INTO ' . $this->table_prefix . 'user_notifications ' . $this->db->sql_build_array('INSERT', array(
+ 'item_type' => $convert_data['item_type'],
+ 'item_id' => 0,
+ 'user_id' => $row['user_id'],
+ 'method' => '',
+ )));
+
+ if ($row['user_notify_type'] == NOTIFY_EMAIL || $row['user_notify_type'] == NOTIFY_BOTH)
+ {
+ $this->sql_query('INSERT INTO ' . $this->table_prefix . 'user_notifications ' . $this->db->sql_build_array('INSERT', array(
+ 'item_type' => $convert_data['item_type'],
+ 'item_id' => 0,
+ 'user_id' => $row['user_id'],
+ 'method' => 'email',
+ )));
+ }
+
+ if ($row['user_notify_type'] == NOTIFY_IM || $row['user_notify_type'] == NOTIFY_BOTH)
+ {
+ $this->sql_query('INSERT INTO ' . $this->table_prefix . 'user_notifications ' . $this->db->sql_build_array('INSERT', array(
+ 'item_type' => $convert_data['item_type'],
+ 'item_id' => 0,
+ 'user_id' => $row['user_id'],
+ 'method' => 'jabber',
+ )));
+ }
+ }
+ $this->db->sql_freeresult($result);
+ }
+ }
+ }
+}
diff --git a/phpBB/includes/db/migration/data/310/teampage.php b/phpBB/includes/db/migration/data/310/teampage.php
new file mode 100644
index 0000000000..4e77da17b7
--- /dev/null
+++ b/phpBB/includes/db/migration/data/310/teampage.php
@@ -0,0 +1,104 @@
+db_tools->sql_table_exists($this->table_prefix . 'teampage');
+ }
+
+ static public function depends_on()
+ {
+ return array('phpbb_db_migration_data_310_dev');
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'add_tables' => array(
+ $this->table_prefix . 'teampage' => array(
+ 'COLUMNS' => array(
+ 'teampage_id' => array('UINT', NULL, 'auto_increment'),
+ 'group_id' => array('UINT', 0),
+ 'teampage_name' => array('VCHAR_UNI:255', ''),
+ 'teampage_position' => array('UINT', 0),
+ 'teampage_parent' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'teampage_id',
+ ),
+ ),
+ 'drop_columns' => array(
+ $this->table_prefix . 'groups' => array(
+ 'group_teampage',
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_tables' => array(
+ $this->table_prefix . 'teampage',
+ ),
+ 'add_columns' => array(
+ $this->table_prefix . 'groups' => array(
+ 'group_teampage' => array('UINT', 0, 'after' => 'group_legend'),
+ ),
+ ),
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('custom', array(array($this, 'add_groups_teampage'))),
+ );
+ }
+
+ public function add_groups_teampage()
+ {
+ $sql = 'SELECT teampage_id
+ FROM ' . TEAMPAGE_TABLE;
+ $result = $this->db->sql_query_limit($sql, 1);
+ $added_groups_teampage = (bool) $this->db->sql_fetchfield('teampage_id');
+ $this->db->sql_freeresult($result);
+
+ if (!$added_groups_teampage)
+ {
+ $sql = 'SELECT *
+ FROM ' . GROUPS_TABLE . '
+ WHERE group_type = ' . GROUP_SPECIAL . "
+ AND (group_name = 'ADMINISTRATORS'
+ OR group_name = 'GLOBAL_MODERATORS')
+ ORDER BY group_name ASC";
+ $result = $this->db->sql_query($sql);
+
+ $teampage_entries = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $teampage_entries[] = array(
+ 'group_id' => (int) $row['group_id'],
+ 'teampage_name' => '',
+ 'teampage_position' => sizeof($teampage_entries) + 1,
+ 'teampage_parent' => 0,
+ );
+ }
+ $this->db->sql_freeresult($result);
+
+ if (sizeof($teampage_entries))
+ {
+ $this->db->sql_multi_insert(TEAMPAGE_TABLE, $teampage_entries);
+ }
+ unset($teampage_entries);
+ }
+
+ }
+}
diff --git a/phpBB/includes/db/migration/tool/config.php b/phpBB/includes/db/migration/tool/config.php
index 458a25fb66..0b626bf455 100644
--- a/phpBB/includes/db/migration/tool/config.php
+++ b/phpBB/includes/db/migration/tool/config.php
@@ -49,7 +49,7 @@ class phpbb_db_migration_tool_config implements phpbb_db_migration_tool_interfac
{
if (isset($this->config[$config_name]))
{
- throw new phpbb_db_migration_exception('CONFIG_ALREADY_EXIST', $config_name);
+ return;
}
$this->config->set($config_name, $config_value, !$is_dynamic);
@@ -105,7 +105,7 @@ class phpbb_db_migration_tool_config implements phpbb_db_migration_tool_interfac
{
if (!isset($this->config[$config_name]))
{
- throw new phpbb_db_migration_exception('CONFIG_NOT_EXIST', $config_name);
+ return;
}
$this->config->delete($config_name);
diff --git a/phpBB/includes/db/migration/tool/module.php b/phpBB/includes/db/migration/tool/module.php
index 4d7fae2bb0..ec683d36af 100644
--- a/phpBB/includes/db/migration/tool/module.php
+++ b/phpBB/includes/db/migration/tool/module.php
@@ -183,25 +183,7 @@ class phpbb_db_migration_tool_module implements phpbb_db_migration_tool_interfac
$basename = str_replace(array('/', '\\'), '', $basename);
$class = str_replace(array('/', '\\'), '', $class);
- $include_path = ($include_path === false) ? $this->phpbb_root_path . 'includes/' : $include_path;
- $info_file = "$class/info/$basename.{$this->php_ext}";
-
- // The manual and automatic ways both failed...
- if (!file_exists($include_path . $info_file))
- {
- throw new phpbb_db_migration_exception('MODULE_INFO_FILE_NOT_EXIST', $class, $info_file);
- }
-
- $classname = "{$basename}_info";
-
- if (!class_exists($classname))
- {
- include($include_path . $info_file);
- }
-
- $info = new $classname;
- $module = $info->module();
- unset($info);
+ $module = $this->get_module_info($class, $basename);
$result = '';
foreach ($module['modes'] as $mode => $module_info)
@@ -254,7 +236,7 @@ class phpbb_db_migration_tool_module implements phpbb_db_migration_tool_interfac
if ($this->exists($class, $parent, $data['module_langname']))
{
- throw new phpbb_db_migration_exception('MODULE_ALREADY_EXIST', $data['module_langname']);
+ return;
}
if (!class_exists('acp_modules'))
@@ -373,30 +355,13 @@ class phpbb_db_migration_tool_module implements phpbb_db_migration_tool_interfac
$basename = str_replace(array('/', '\\'), '', $module['module_basename']);
$class = str_replace(array('/', '\\'), '', $class);
- $include_path = ($include_path === false) ? $this->phpbb_root_path . 'includes/' : $include_path;
- $info_file = "$class/info/$basename.{$this->php_ext}";
-
- if (!file_exists($include_path . $info_file))
- {
- throw new phpbb_db_migration_exception('MODULE_NOT_EXIST', $info_file);
- }
-
- $classname = "{$basename}_info";
-
- if (!class_exists($classname))
- {
- include($include_path . $info_file);
- }
-
- $info = new $classname;
- $module_info = $info->module();
- unset($info);
+ $module_info = $this->get_module_info($class, $basename);
foreach ($module_info['modes'] as $mode => $info)
{
if (!isset($module['modes']) || in_array($mode, $module['modes']))
{
- $this->remove($class, $parent, $info['title']) . ' ';
+ $this->remove($class, $parent, $info['title']);
}
}
}
@@ -404,7 +369,7 @@ class phpbb_db_migration_tool_module implements phpbb_db_migration_tool_interfac
{
if (!$this->exists($class, $parent, $module))
{
- throw new phpbb_db_migration_exception('MODULE_NOT_EXIST', ((isset($this->user->lang[$module])) ? $this->user->lang[$module] : $module));
+ return;
}
$parent_sql = '';
@@ -477,7 +442,7 @@ class phpbb_db_migration_tool_module implements phpbb_db_migration_tool_interfac
$result = $acp_modules->delete_module($module_id);
if (!empty($result))
{
- throw new phpbb_db_migration_exception('MODULE_NOT_REMOVABLE', $module_id, $result);
+ return;
}
}
@@ -510,4 +475,28 @@ class phpbb_db_migration_tool_module implements phpbb_db_migration_tool_interfac
return call_user_func_array(array(&$this, $call), $arguments);
}
}
+
+ /**
+ * Wrapper for acp_modules::get_module_infos()
+ *
+ * @param string $class Module Class
+ * @param string $basename Module Basename
+ * @return array Module Information
+ */
+ protected function get_module_info($class, $basename)
+ {
+ if (!class_exists('acp_modules'))
+ {
+ include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext);
+ }
+ $acp_modules = new acp_modules();
+ $module = $acp_modules->get_module_infos($basename, $class, true);
+
+ if (empty($module))
+ {
+ throw new phpbb_db_migration_exception('MODULE_INFO_FILE_NOT_EXIST', $class, $basename);
+ }
+
+ return array_pop($module);
+ }
}
diff --git a/phpBB/includes/db/migration/tool/permission.php b/phpBB/includes/db/migration/tool/permission.php
index 4231fbe1dd..2f09c0ac72 100644
--- a/phpBB/includes/db/migration/tool/permission.php
+++ b/phpBB/includes/db/migration/tool/permission.php
@@ -107,7 +107,7 @@ class phpbb_db_migration_tool_permission implements phpbb_db_migration_tool_inte
{
if ($this->exists($auth_option, $global))
{
- throw new phpbb_db_migration_exception('PERMISSION_ALREADY_EXIST', $auth_option);
+ return;
}
// We've added permissions, so set to true to notify the user.
@@ -190,7 +190,7 @@ class phpbb_db_migration_tool_permission implements phpbb_db_migration_tool_inte
{
if (!$this->exists($auth_option, $global))
{
- throw new phpbb_db_migration_exception('PERMISSION_NOT_EXIST', $auth_option);
+ return;
}
if ($global)
@@ -315,7 +315,7 @@ class phpbb_db_migration_tool_permission implements phpbb_db_migration_tool_inte
if (!$role_id)
{
- throw new phpbb_db_migration_exception('ROLE_NOT_EXIST', $role_name);
+ return;
}
$sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . '
@@ -422,7 +422,7 @@ class phpbb_db_migration_tool_permission implements phpbb_db_migration_tool_inte
$this->db->sql_query($sql);
$role_name = $this->db->sql_fetchfield('role_name');
- return $this->set($role_name, $auth_option, 'role', $has_permission);
+ return $this->permission_set($role_name, $auth_option, 'role', $has_permission);
}
$sql = 'SELECT auth_option_id, auth_setting
diff --git a/phpBB/includes/db/migrator.php b/phpBB/includes/db/migrator.php
index 74f71775f3..ca3ffc8043 100644
--- a/phpBB/includes/db/migrator.php
+++ b/phpBB/includes/db/migrator.php
@@ -60,7 +60,9 @@ class phpbb_db_migrator
protected $migrations = array();
/**
- * 'name' and 'class' of the last migration run
+ * 'name,' 'class,' and 'state' of the last migration run
+ *
+ * 'effectively_installed' set and set to true if the migration was effectively_installed
*
* @var array
*/
@@ -132,121 +134,6 @@ class phpbb_db_migrator
$this->migrations = $class_names;
}
- /**
- * This function adds all migrations in a specified directory to the migrations table
- *
- * THIS SHOULD NOT GENERALLY BE USED! THIS IS FOR THE PHPBB INSTALLER.
- * THIS WILL THROW ERRORS IF MIGRATIONS ALREADY EXIST IN THE TABLE, DO NOT CALL MORE THAN ONCE!
- *
- * @param string $path Path to migration data files
- * @param bool $recursive Set to true to also load data files from subdirectories
- * @return null
- */
- public function populate_migrations_from_directory($path, $recursive = true)
- {
- $existing_migrations = $this->migrations;
-
- $this->migrations = array();
- $this->load_migrations($path, true, $recursive);
-
- foreach ($this->migrations as $name)
- {
- if ($this->migration_state($name) === false)
- {
- $state = array(
- 'migration_depends_on' => $name::depends_on(),
- 'migration_schema_done' => true,
- 'migration_data_done' => true,
- 'migration_data_state' => '',
- 'migration_start_time' => time(),
- 'migration_end_time' => time(),
- );
- $this->insert_migration($name, $state);
- }
- }
-
- $this->migrations = $existing_migrations;
- }
-
- /**
- * Load migration data files from a directory
- *
- * Migration data files loaded with this function MUST contain
- * ONLY ONE class in them (or an exception will be thrown).
- *
- * @param string $path Path to migration data files
- * @param bool $check_fulfillable If TRUE (default), we will check
- * if all of the migrations are fulfillable after loading them.
- * If FALSE, we will not check. You SHOULD check at least once
- * to prevent errors (if including multiple directories, check
- * with the last call to prevent throwing errors unnecessarily).
- * @param bool $recursive Set to true to also load data files from subdirectories
- * @return array Array of migration names
- */
- public function load_migrations($path, $check_fulfillable = true, $recursive = true)
- {
- if (!is_dir($path))
- {
- throw new phpbb_db_migration_exception('DIRECTORY INVALID', $path);
- }
-
- $handle = opendir($path);
- while (($file = readdir($handle)) !== false)
- {
- if ($file == '.' || $file == '..')
- {
- continue;
- }
-
- // Recursion through subdirectories
- if (is_dir($path . $file) && $recursive)
- {
- $this->load_migrations($path . $file . '/', $check_fulfillable, $recursive);
- }
-
- if (strpos($file, '_') !== 0 && strrpos($file, '.' . $this->php_ext) === (strlen($file) - strlen($this->php_ext) - 1))
- {
- // We try to find what class existed by comparing the classes declared before and after including the file.
- $declared_classes = get_declared_classes();
-
- include ($path . $file);
-
- $added_classes = array_diff(get_declared_classes(), $declared_classes);
-
- if (
- // If two classes have been added and phpbb_db_migration is one of them, we've only added one real migration
- !(sizeof($added_classes) == 2 && in_array('phpbb_db_migration', $added_classes)) &&
- // Otherwise there should only be one class added
- sizeof($added_classes) != 1
- )
- {
- throw new phpbb_db_migration_exception('MIGRATION DATA FILE INVALID', $path . $file);
- }
-
- $name = array_pop($added_classes);
-
- if (!in_array($name, $this->migrations))
- {
- $this->migrations[] = $name;
- }
- }
- }
-
- if ($check_fulfillable)
- {
- foreach ($this->migrations as $name)
- {
- $unfulfillable = $this->unfulfillable($name);
- if ($unfulfillable !== false)
- {
- throw new phpbb_db_migration_exception('MIGRATION_NOT_FULFILLABLE', $name, $unfulfillable);
- }
- }
- }
-
- return $this->migrations;
- }
-
/**
* Runs a single update step from the next migration to be applied.
*
@@ -314,25 +201,27 @@ class phpbb_db_migrator
$this->last_run_migration = array(
'name' => $name,
'class' => $migration,
+ 'state' => $state,
);
- if ($migration->effectively_installed())
+ if (!isset($this->migration_state[$name]))
{
- $state = array(
- 'migration_depends_on' => $migration->depends_on(),
- 'migration_schema_done' => true,
- 'migration_data_done' => true,
- 'migration_data_state' => '',
- 'migration_start_time' => 0,
- 'migration_end_time' => 0,
- );
- }
- else
- {
- if (!isset($this->migration_state[$name]))
+ if ($migration->effectively_installed())
+ {
+ $state = array(
+ 'migration_depends_on' => $migration->depends_on(),
+ 'migration_schema_done' => true,
+ 'migration_data_done' => true,
+ 'migration_data_state' => '',
+ 'migration_start_time' => 0,
+ 'migration_end_time' => 0,
+ );
+
+ $this->last_run_migration['effectively_installed'] = true;
+ }
+ else
{
$state['migration_start_time'] = time();
- $this->insert_migration($name, $state);
}
}
@@ -361,14 +250,7 @@ class phpbb_db_migrator
}
}
- $insert = $state;
- $insert['migration_depends_on'] = serialize($state['migration_depends_on']);
- $sql = 'UPDATE ' . $this->migrations_table . '
- SET ' . $this->db->sql_build_array('UPDATE', $insert) . "
- WHERE migration_name = '" . $this->db->sql_escape($name) . "'";
- $this->db->sql_query($sql);
-
- $this->migration_state[$name] = $state;
+ $this->set_migration_state($name, $state);
return true;
}
@@ -434,20 +316,13 @@ class phpbb_db_migrator
}
else
{
- $result = $this->process_data_step($migration->revert_data(), $state['migration_data_state'], false);
+ $result = $this->process_data_step($migration->revert_data(), '', false);
$state['migration_data_state'] = ($result === true) ? '' : $result;
$state['migration_data_done'] = ($result === true) ? false : true;
}
- $insert = $state;
- $insert['migration_depends_on'] = serialize($state['migration_depends_on']);
- $sql = 'UPDATE ' . $this->migrations_table . '
- SET ' . $this->db->sql_build_array('UPDATE', $insert) . "
- WHERE migration_name = '" . $this->db->sql_escape($name) . "'";
- $this->db->sql_query($sql);
-
- $this->migration_state[$name] = $state;
+ $this->set_migration_state($name, $state);
}
else
{
@@ -487,6 +362,12 @@ class phpbb_db_migrator
{
$state = ($state) ? unserialize($state) : false;
+ // reverse order of steps if reverting
+ if ($revert === true)
+ {
+ $steps = array_reverse($steps);
+ }
+
foreach ($steps as $step_identifier => $step)
{
$last_result = false;
@@ -660,23 +541,35 @@ class phpbb_db_migrator
}
/**
- * Insert migration row into the database
+ * Insert/Update migration row into the database
*
* @param string $name Name of the migration
* @param array $state
* @return null
*/
- protected function insert_migration($name, $state)
+ protected function set_migration_state($name, $state)
{
$migration_row = $state;
- $migration_row['migration_name'] = $name;
$migration_row['migration_depends_on'] = serialize($state['migration_depends_on']);
- $sql = 'INSERT INTO ' . $this->migrations_table . '
- ' . $this->db->sql_build_array('INSERT', $migration_row);
- $this->db->sql_query($sql);
+ if (isset($this->migration_state[$name]))
+ {
+ $sql = 'UPDATE ' . $this->migrations_table . '
+ SET ' . $this->db->sql_build_array('UPDATE', $migration_row) . "
+ WHERE migration_name = '" . $this->db->sql_escape($name) . "'";
+ $this->db->sql_query($sql);
+ }
+ else
+ {
+ $migration_row['migration_name'] = $name;
+ $sql = 'INSERT INTO ' . $this->migrations_table . '
+ ' . $this->db->sql_build_array('INSERT', $migration_row);
+ $this->db->sql_query($sql);
+ }
$this->migration_state[$name] = $state;
+
+ $this->last_run_migration['state'] = $state;
}
/**
@@ -769,4 +662,85 @@ class phpbb_db_migrator
{
return new $name($this->config, $this->db, $this->db_tools, $this->phpbb_root_path, $this->php_ext, $this->table_prefix);
}
+
+ /**
+ * This function adds all migrations sent to it to the migrations table
+ *
+ * THIS SHOULD NOT GENERALLY BE USED! THIS IS FOR THE PHPBB INSTALLER.
+ * THIS WILL THROW ERRORS IF MIGRATIONS ALREADY EXIST IN THE TABLE, DO NOT CALL MORE THAN ONCE!
+ *
+ * @param array $migrations Array of migrations (names) to add to the migrations table
+ * @return null
+ */
+ public function populate_migrations($migrations)
+ {
+ foreach ($migrations as $name)
+ {
+ if ($this->migration_state($name) === false)
+ {
+ $state = array(
+ 'migration_depends_on' => $name::depends_on(),
+ 'migration_schema_done' => true,
+ 'migration_data_done' => true,
+ 'migration_data_state' => '',
+ 'migration_start_time' => time(),
+ 'migration_end_time' => time(),
+ );
+ $this->set_migration_state($name, $state);
+ }
+ }
+ }
+
+ /**
+ * Load migration data files from a directory
+ *
+ * @param phpbb_extension_finder $finder
+ * @param string $path Path to migration data files
+ * @param bool $check_fulfillable If TRUE (default), we will check
+ * if all of the migrations are fulfillable after loading them.
+ * If FALSE, we will not check. You SHOULD check at least once
+ * to prevent errors (if including multiple directories, check
+ * with the last call to prevent throwing errors unnecessarily).
+ * @return array Array of migration names
+ */
+ public function load_migrations(phpbb_extension_finder $finder, $path, $check_fulfillable = true)
+ {
+ if (!is_dir($path))
+ {
+ throw new phpbb_db_migration_exception('DIRECTORY INVALID', $path);
+ }
+
+ $migrations = array();
+
+ $files = $finder
+ ->extension_directory("/")
+ ->find_from_paths(array('/' => $path));
+ foreach ($files as $file)
+ {
+ $migrations[$file['path'] . $file['filename']] = '';
+ }
+ $migrations = $finder->get_classes_from_files($migrations);
+
+ foreach ($migrations as $migration)
+ {
+ if (!in_array($migration, $this->migrations))
+ {
+ $this->migrations[] = $migration;
+ }
+ }
+
+ if ($check_fulfillable)
+ {
+ foreach ($this->migrations as $name)
+ {
+ $unfulfillable = $this->unfulfillable($name);
+ if ($unfulfillable !== false)
+ {
+ throw new phpbb_db_migration_exception('MIGRATION_NOT_FULFILLABLE', $name, $unfulfillable);
+ }
+ }
+ }
+
+ return $this->migrations;
+ }
}
diff --git a/phpBB/includes/extension/finder.php b/phpBB/includes/extension/finder.php
index fb19b98429..f71e32bc8d 100644
--- a/phpBB/includes/extension/finder.php
+++ b/phpBB/includes/extension/finder.php
@@ -247,15 +247,28 @@ class phpbb_extension_finder
* phpBB naming rules an incorrect class name will be returned.
*
* @param bool $cache Whether the result should be cached
+ * @param bool $use_all_available Use all available instead of just all
+ * enabled extensions
* @return array An array of found class names
*/
- public function get_classes($cache = true)
+ public function get_classes($cache = true, $use_all_available = false)
{
$this->query['extension_suffix'] .= $this->php_ext;
$this->query['core_suffix'] .= $this->php_ext;
- $files = $this->find($cache, false);
+ $files = $this->find($cache, false, $use_all_available);
+ return $this->get_classes_from_files($files);
+ }
+
+ /**
+ * Get class names from a list of files
+ *
+ * @param array $files Array of files (from find())
+ * @return array Array of class names
+ */
+ public function get_classes_from_files($files)
+ {
$classes = array();
foreach ($files as $file => $ext_name)
{
@@ -270,23 +283,27 @@ class phpbb_extension_finder
* Finds all directories matching the configured options
*
* @param bool $cache Whether the result should be cached
+ * @param bool $use_all_available Use all available instead of just all
+ * enabled extensions
* @param bool $extension_keys Whether the result should have extension name as array key
* @return array An array of paths to found directories
*/
- public function get_directories($cache = true, $extension_keys = false)
+ public function get_directories($cache = true, $use_all_available = false, $extension_keys = false)
{
- return $this->find_with_root_path($cache, true, $extension_keys);
+ return $this->find_with_root_path($cache, true, $use_all_available, $extension_keys);
}
/**
* Finds all files matching the configured options.
*
* @param bool $cache Whether the result should be cached
+ * @param bool $use_all_available Use all available instead of just all
+ * enabled extensions
* @return array An array of paths to found files
*/
- public function get_files($cache = true)
+ public function get_files($cache = true, $use_all_available = false)
{
- return $this->find_with_root_path($cache, false);
+ return $this->find_with_root_path($cache, false, $use_all_available);
}
/**
@@ -295,13 +312,15 @@ class phpbb_extension_finder
* @param bool $cache Whether the result should be cached
* @param bool $is_dir Directories will be returned when true, only files
* otherwise
+ * @param bool $use_all_available Use all available instead of just all
+ * enabled extensions
* @param bool $extension_keys If true, result will be associative array
* with extension name as key
* @return array An array of paths to found items
*/
- protected function find_with_root_path($cache = true, $is_dir = false, $extension_keys = false)
+ protected function find_with_root_path($cache = true, $is_dir = false, $use_all_available = false, $extension_keys = false)
{
- $items = $this->find($cache, $is_dir);
+ $items = $this->find($cache, $is_dir, $use_all_available);
$result = array();
foreach ($items as $item => $ext_name)
@@ -325,12 +344,51 @@ class phpbb_extension_finder
* @param bool $cache Whether the result should be cached
* @param bool $is_dir Directories will be returned when true, only files
* otherwise
+ * @param bool $use_all_available Use all available instead of just all
+ * enabled extensions
* @return array An array of paths to found items
*/
- public function find($cache = true, $is_dir = false)
+ public function find($cache = true, $is_dir = false, $use_all_available = false)
+ {
+ if ($use_all_available)
+ {
+ $extensions = $this->extension_manager->all_available();
+ }
+ else
+ {
+ $extensions = $this->extension_manager->all_enabled();
+ }
+
+ if ($this->query['core_path'])
+ {
+ $extensions['/'] = $this->phpbb_root_path . $this->query['core_path'];
+ }
+
+ $files = array();
+ $file_list = $this->find_from_paths($extensions, $cache, $is_dir);
+
+ foreach ($file_list as $file)
+ {
+ $files[$file['named_path']] = $file['ext_name'];
+ }
+
+ return $files;
+ }
+
+ /**
+ * Finds all file system entries matching the configured options from
+ * an array of paths
+ *
+ * @param array $extensions Array of extensions (name => full relative path)
+ * @param bool $cache Whether the result should be cached
+ * @param bool $is_dir Directories will be returned when true, only files
+ * otherwise
+ * @return array An array of paths to found items
+ */
+ public function find_from_paths($extensions, $cache = true, $is_dir = false)
{
$this->query['is_dir'] = $is_dir;
- $query = md5(serialize($this->query));
+ $query = md5(serialize($this->query) . serialize($extensions));
if (!defined('DEBUG') && $cache && isset($this->cached_queries[$query]))
{
@@ -339,13 +397,6 @@ class phpbb_extension_finder
$files = array();
- $extensions = $this->extension_manager->all_enabled();
-
- if ($this->query['core_path'])
- {
- $extensions['/'] = $this->phpbb_root_path . $this->query['core_path'];
- }
-
foreach ($extensions as $name => $path)
{
$ext_name = $name;
@@ -419,7 +470,12 @@ class phpbb_extension_finder
(!$prefix || substr($filename, 0, strlen($prefix)) === $prefix) &&
(!$directory || preg_match($directory_pattern, $relative_path)))
{
- $files[str_replace(DIRECTORY_SEPARATOR, '/', $location . $name . substr($relative_path, 1))] = $ext_name;
+ $files[] = array(
+ 'named_path' => str_replace(DIRECTORY_SEPARATOR, '/', $location . $name . substr($relative_path, 1)),
+ 'ext_name' => $ext_name,
+ 'path' => str_replace(array(DIRECTORY_SEPARATOR, $this->phpbb_root_path), array('/', ''), $file_info->getPath()) . '/',
+ 'filename' => $filename,
+ );
}
}
}
diff --git a/phpBB/includes/extension/manager.php b/phpBB/includes/extension/manager.php
index 21a9ec1370..44a30c6280 100644
--- a/phpBB/includes/extension/manager.php
+++ b/phpBB/includes/extension/manager.php
@@ -43,6 +43,7 @@ class phpbb_extension_manager
* @param ContainerInterface $container A container
* @param phpbb_db_driver $db A database connection
* @param phpbb_config $config phpbb_config
+ * @param phpbb_db_migrator $migrator
* @param string $extension_table The name of the table holding extensions
* @param string $phpbb_root_path Path to the phpbb includes directory.
* @param string $php_ext php file extension
@@ -521,13 +522,27 @@ class phpbb_extension_manager
*/
protected function handle_migrations($extension_name, $mode)
{
- $migrations_path = $this->phpbb_root_path . $this->get_extension_path($extension_name) . 'migrations/';
- if (!file_exists($migrations_path) || !is_dir($migrations_path))
+ $extensions = array(
+ $extension_name => $this->phpbb_root_path . $this->get_extension_path($extension_name),
+ );
+
+ $finder = $this->get_finder();
+ $migrations = array();
+ $file_list = $finder
+ ->extension_directory('/migrations')
+ ->find_from_paths($extensions);
+
+ if (empty($file_list))
{
return true;
}
- $migrations = $this->migrator->load_migrations($migrations_path);
+ foreach ($file_list as $file)
+ {
+ $migrations[$file['named_path']] = $file['ext_name'];
+ }
+ $migrations = $finder->get_classes_from_files($migrations);
+ $this->migrator->set_migrations($migrations);
// What is a safe limit of execution time? Half the max execution time should be safe.
$safe_time_limit = (ini_get('max_execution_time') / 2);
diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php
index d9af268f80..98a2c0db79 100644
--- a/phpBB/includes/functions.php
+++ b/phpBB/includes/functions.php
@@ -1347,7 +1347,7 @@ function phpbb_timezone_select($user, $default = '', $truncate = false)
function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $user_id = 0)
{
global $db, $user, $config;
- global $request;
+ global $request, $phpbb_container;
$post_time = ($post_time === 0 || $post_time > time()) ? time() : (int) $post_time;
@@ -1355,6 +1355,20 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
{
if ($forum_id === false || !sizeof($forum_id))
{
+ // Mark all forums read (index page)
+
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ // Mark all topic notifications read for this user
+ $phpbb_notifications->mark_notifications_read(array(
+ 'topic',
+ 'quote',
+ 'bookmark',
+ 'post',
+ 'approve_topic',
+ 'approve_post',
+ ), false, $user->data['user_id'], $post_time);
+
if ($config['load_db_lastread'] && $user->data['is_registered'])
{
// Mark all forums read (index page)
@@ -1409,6 +1423,32 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
$forum_id = array($forum_id);
}
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $phpbb_notifications->mark_notifications_read_by_parent(array(
+ 'topic',
+ 'approve_topic',
+ ), $forum_id, $user->data['user_id'], $post_time);
+
+ // Mark all post/quote notifications read for this user in this forum
+ $topic_ids = array();
+ $sql = 'SELECT topic_id
+ FROM ' . TOPICS_TABLE . '
+ WHERE ' . $db->sql_in_set('forum_id', $forum_id);
+ $result = $db->sql_query($sql);
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $topic_ids[] = $row['topic_id'];
+ }
+ $db->sql_freeresult($result);
+
+ $phpbb_notifications->mark_notifications_read_by_parent(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ 'approve_post',
+ ), $topic_ids, $user->data['user_id'], $post_time);
+
// Add 0 to forums array to mark global announcements correctly
// $forum_id[] = 0;
@@ -1506,6 +1546,21 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
return;
}
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ // Mark post notifications read for this user in this topic
+ $phpbb_notifications->mark_notifications_read(array(
+ 'topic',
+ 'approve_topic',
+ ), $topic_id, $user->data['user_id'], $post_time);
+
+ $phpbb_notifications->mark_notifications_read_by_parent(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ 'approve_post',
+ ), $topic_id, $user->data['user_id'], $post_time);
+
if ($config['load_db_lastread'] && $user->data['is_registered'])
{
$sql = 'UPDATE ' . TOPICS_TRACK_TABLE . "
@@ -3103,8 +3158,9 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo
'YES_VALUE' => $user->lang['YES'],
'S_CONFIRM_ACTION' => $u_action,
- 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields)
- );
+ 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields,
+ 'S_AJAX_REQUEST' => $request->is_ajax(),
+ ));
$sql = 'UPDATE ' . USERS_TABLE . " SET user_last_confirm_key = '" . $db->sql_escape($confirm_key) . "'
WHERE user_id = " . $user->data['user_id'];
@@ -3116,8 +3172,9 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo
$u_action .= '&confirm_uid=' . $user->data['user_id'] . '&sess=' . $user->session_id . '&sid=' . $user->session_id;
$json_response = new phpbb_json_response;
$json_response->send(array(
+ 'MESSAGE_BODY' => $template->assign_display('body'),
'MESSAGE_TITLE' => (!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title],
- 'MESSAGE_TEXT' => (!isset($user->lang[$title . '_CONFIRM'])) ? $title : $user->lang[$title . '_CONFIRM'],
+ 'MESSAGE_TEXT' => (!isset($user->lang[$title . '_CONFIRM'])) ? $title : $user->lang[$title . '_CONFIRM'],
'YES_VALUE' => $user->lang['YES'],
'S_CONFIRM_ACTION' => str_replace('&', '&', $u_action), //inefficient, rewrite whole function
@@ -3527,69 +3584,49 @@ function parse_cfg_file($filename, $lines = false)
}
/**
-* Add log event
+* Add log entry
+*
+* @param string $mode The mode defines which log_type is used and from which log the entry is retrieved
+* @param int $forum_id Mode 'mod' ONLY: forum id of the related item, NOT INCLUDED otherwise
+* @param int $topic_id Mode 'mod' ONLY: topic id of the related item, NOT INCLUDED otherwise
+* @param int $reportee_id Mode 'user' ONLY: user id of the reportee, NOT INCLUDED otherwise
+* @param string $log_operation Name of the operation
+* @param array $additional_data More arguments can be added, depending on the log_type
+*
+* @return int|bool Returns the log_id, if the entry was added to the database, false otherwise.
+*
+* @deprecated Use $phpbb_log->add() instead
*/
function add_log()
{
- global $db, $user;
-
- // In phpBB 3.1.x i want to have logging in a class to be able to control it
- // For now, we need a quite hakish approach to circumvent logging for some actions
- // @todo implement cleanly
- if (!empty($GLOBALS['skip_add_log']))
- {
- return false;
- }
+ global $phpbb_log, $user;
$args = func_get_args();
+ $mode = array_shift($args);
- $mode = array_shift($args);
- $reportee_id = ($mode == 'user') ? intval(array_shift($args)) : '';
- $forum_id = ($mode == 'mod') ? intval(array_shift($args)) : '';
- $topic_id = ($mode == 'mod') ? intval(array_shift($args)) : '';
- $action = array_shift($args);
- $data = (!sizeof($args)) ? '' : serialize($args);
-
- $sql_ary = array(
- 'user_id' => (empty($user->data)) ? ANONYMOUS : $user->data['user_id'],
- 'log_ip' => $user->ip,
- 'log_time' => time(),
- 'log_operation' => $action,
- 'log_data' => $data,
- );
-
+ // This looks kind of dirty, but add_log has some additional data before the log_operation
+ $additional_data = array();
switch ($mode)
{
case 'admin':
- $sql_ary['log_type'] = LOG_ADMIN;
- break;
-
- case 'mod':
- $sql_ary += array(
- 'log_type' => LOG_MOD,
- 'forum_id' => $forum_id,
- 'topic_id' => $topic_id
- );
- break;
-
- case 'user':
- $sql_ary += array(
- 'log_type' => LOG_USERS,
- 'reportee_id' => $reportee_id
- );
- break;
-
case 'critical':
- $sql_ary['log_type'] = LOG_CRITICAL;
break;
-
- default:
- return false;
+ case 'mod':
+ $additional_data['forum_id'] = array_shift($args);
+ $additional_data['topic_id'] = array_shift($args);
+ break;
+ case 'user':
+ $additional_data['reportee_id'] = array_shift($args);
+ break;
}
- $db->sql_query('INSERT INTO ' . LOG_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
+ $log_operation = array_shift($args);
+ $additional_data = array_merge($additional_data, $args);
- return $db->sql_nextid();
+ $user_id = (empty($user->data)) ? ANONYMOUS : $user->data['user_id'];
+ $user_ip = (empty($user->ip)) ? '' : $user->ip;
+
+ return $phpbb_log->add($mode, $user_id, $user_ip, $log_operation, time(), $additional_data);
}
/**
@@ -5013,7 +5050,7 @@ function phpbb_build_hidden_fields_for_query_params($request, $exclude = null)
function page_header($page_title = '', $display_online_list = true, $item_id = 0, $item = 'forum')
{
global $db, $config, $template, $SID, $_SID, $_EXTRA_URL, $user, $auth, $phpEx, $phpbb_root_path;
- global $phpbb_dispatcher, $request;
+ global $phpbb_dispatcher, $request, $phpbb_container;
if (defined('HEADER_INC'))
{
@@ -5202,8 +5239,26 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0
$timezone_name = $user->lang['timezones'][$timezone_name];
}
+ // Output the notifications
+ $notifications = false;
+ if ($config['load_notifications'] && $user->data['user_id'] != ANONYMOUS && $user->data['user_type'] != USER_IGNORE)
+ {
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $notifications = $phpbb_notifications->load_notifications(array(
+ 'all_unread' => true,
+ 'limit' => 5,
+ ));
+
+ foreach ($notifications['notifications'] as $notification)
+ {
+ $template->assign_block_vars('notifications', $notification->prepare_for_display());
+ }
+ }
+
$hidden_fields_for_jumpbox = phpbb_build_hidden_fields_for_query_params($request, array('f'));
+
// The following assigns all _common_ variables that may be used at any point in a template.
$template->assign_vars(array(
'SITENAME' => $config['sitename'],
@@ -5220,6 +5275,12 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0
'PRIVATE_MESSAGE_INFO_UNREAD' => $l_privmsgs_text_unread,
'HIDDEN_FIELDS_FOR_JUMPBOX' => $hidden_fields_for_jumpbox,
+ 'UNREAD_NOTIFICATIONS_COUNT' => ($notifications !== false) ? $notifications['unread_count'] : '',
+ 'NOTIFICATIONS_COUNT' => ($notifications !== false) ? $user->lang('NOTIFICATIONS_COUNT', $notifications['unread_count']) : '',
+ 'U_VIEW_ALL_NOTIFICATIONS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_notifications'),
+ 'U_NOTIFICATION_SETTINGS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_notifications&mode=notification_options'),
+ 'S_NOTIFICATIONS_DISPLAY' => $config['load_notifications'],
+
'S_USER_NEW_PRIVMSG' => $user->data['user_new_privmsg'],
'S_USER_UNREAD_PRIVMSG' => $user->data['user_unread_privmsg'],
'S_USER_NEW' => $user->data['user_new'],
diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php
index 5529f2af46..d273b9fb3a 100644
--- a/phpBB/includes/functions_admin.php
+++ b/phpBB/includes/functions_admin.php
@@ -618,7 +618,7 @@ function move_posts($post_ids, $topic_id, $auto_sync = true)
*/
function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_sync = true, $call_delete_posts = true)
{
- global $db, $config;
+ global $db, $config, $phpbb_container;
$approved_topics = 0;
$forum_ids = $topic_ids = array();
@@ -715,6 +715,14 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s
set_config_count('num_topics', $approved_topics * (-1), true);
}
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $phpbb_notifications->delete_notifications(array(
+ 'topic',
+ 'approve_topic',
+ 'topic_in_queue',
+ ), $topic_ids);
+
return $return;
}
@@ -723,7 +731,7 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s
*/
function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = true, $post_count_sync = true, $call_delete_topics = true)
{
- global $db, $config, $phpbb_root_path, $phpEx, $auth, $user;
+ global $db, $config, $phpbb_root_path, $phpEx, $auth, $user, $phpbb_container;
if ($where_type === 'range')
{
@@ -892,6 +900,16 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
delete_topics('topic_id', $remove_topics, $auto_sync, $post_count_sync, false);
}
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $phpbb_notifications->delete_notifications(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ 'approve_post',
+ 'post_in_queue',
+ ), $post_ids);
+
return sizeof($post_ids);
}
@@ -2488,273 +2506,32 @@ function cache_moderators()
/**
* View log
-* If $log_count is set to false, we will skip counting all entries in the database.
+*
+* @param string $mode The mode defines which log_type is used and from which log the entry is retrieved
+* @param array &$log The result array with the logs
+* @param mixed &$log_count If $log_count is set to false, we will skip counting all entries in the database.
+* Otherwise an integer with the number of total matching entries is returned.
+* @param int $limit Limit the number of entries that are returned
+* @param int $offset Offset when fetching the log entries, f.e. when paginating
+* @param mixed $forum_id Restrict the log entries to the given forum_id (can also be an array of forum_ids)
+* @param int $topic_id Restrict the log entries to the given topic_id
+* @param int $user_id Restrict the log entries to the given user_id
+* @param int $log_time Only get log entries newer than the given timestamp
+* @param string $sort_by SQL order option, e.g. 'l.log_time DESC'
+* @param string $keywords Will only return log entries that have the keywords in log_operation or log_data
+*
+* @return int Returns the offset of the last valid page, if the specified offset was invalid (too high)
*/
function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $limit_days = 0, $sort_by = 'l.log_time DESC', $keywords = '')
{
- global $db, $user, $auth, $phpEx, $phpbb_root_path, $phpbb_admin_path;
+ global $phpbb_log;
- $topic_id_list = $reportee_id_list = $is_auth = $is_mod = array();
+ $count_logs = ($log_count !== false);
- $profile_url = (defined('IN_ADMIN')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&mode=overview') : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile');
+ $log = $phpbb_log->get_logs($mode, $count_logs, $limit, $offset, $forum_id, $topic_id, $user_id, $limit_days, $sort_by, $keywords);
+ $log_count = $phpbb_log->get_log_count();
- switch ($mode)
- {
- case 'admin':
- $log_type = LOG_ADMIN;
- $sql_forum = '';
- break;
-
- case 'mod':
- $log_type = LOG_MOD;
- $sql_forum = '';
-
- if ($topic_id)
- {
- $sql_forum = 'AND l.topic_id = ' . (int) $topic_id;
- }
- else if (is_array($forum_id))
- {
- $sql_forum = 'AND ' . $db->sql_in_set('l.forum_id', array_map('intval', $forum_id));
- }
- else if ($forum_id)
- {
- $sql_forum = 'AND l.forum_id = ' . (int) $forum_id;
- }
- break;
-
- case 'user':
- $log_type = LOG_USERS;
- $sql_forum = 'AND l.reportee_id = ' . (int) $user_id;
- break;
-
- case 'users':
- $log_type = LOG_USERS;
- $sql_forum = '';
- break;
-
- case 'critical':
- $log_type = LOG_CRITICAL;
- $sql_forum = '';
- break;
-
- default:
- return;
- }
-
- // Use no preg_quote for $keywords because this would lead to sole backslashes being added
- // We also use an OR connection here for spaces and the | string. Currently, regex is not supported for searching (but may come later).
- $keywords = preg_split('#[\s|]+#u', utf8_strtolower($keywords), 0, PREG_SPLIT_NO_EMPTY);
- $sql_keywords = '';
-
- if (!empty($keywords))
- {
- $keywords_pattern = array();
-
- // Build pattern and keywords...
- for ($i = 0, $num_keywords = sizeof($keywords); $i < $num_keywords; $i++)
- {
- $keywords_pattern[] = preg_quote($keywords[$i], '#');
- $keywords[$i] = $db->sql_like_expression($db->any_char . $keywords[$i] . $db->any_char);
- }
-
- $keywords_pattern = '#' . implode('|', $keywords_pattern) . '#ui';
-
- $operations = array();
- foreach ($user->lang as $key => $value)
- {
- if (substr($key, 0, 4) == 'LOG_' && preg_match($keywords_pattern, $value))
- {
- $operations[] = $key;
- }
- }
-
- $sql_keywords = 'AND (';
- if (!empty($operations))
- {
- $sql_keywords .= $db->sql_in_set('l.log_operation', $operations) . ' OR ';
- }
- $sql_lower = $db->sql_lower_text('l.log_data');
- $sql_keywords .= "$sql_lower " . implode(" OR $sql_lower ", $keywords) . ')';
- }
-
- if ($log_count !== false)
- {
- $sql = 'SELECT COUNT(l.log_id) AS total_entries
- FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . " u
- WHERE l.log_type = $log_type
- AND l.user_id = u.user_id
- AND l.log_time >= $limit_days
- $sql_keywords
- $sql_forum";
- $result = $db->sql_query($sql);
- $log_count = (int) $db->sql_fetchfield('total_entries');
- $db->sql_freeresult($result);
- }
-
- // $log_count may be false here if false was passed in for it,
- // because in this case we did not run the COUNT() query above.
- // If we ran the COUNT() query and it returned zero rows, return;
- // otherwise query for logs below.
- if ($log_count === 0)
- {
- // Save the queries, because there are no logs to display
- return 0;
- }
-
- if ($offset >= $log_count)
- {
- $offset = ($offset - $limit < 0) ? 0 : $offset - $limit;
- }
-
- $sql = "SELECT l.*, u.username, u.username_clean, u.user_colour
- FROM " . LOG_TABLE . " l, " . USERS_TABLE . " u
- WHERE l.log_type = $log_type
- AND u.user_id = l.user_id
- " . (($limit_days) ? "AND l.log_time >= $limit_days" : '') . "
- $sql_keywords
- $sql_forum
- ORDER BY $sort_by";
- $result = $db->sql_query_limit($sql, $limit, $offset);
-
- $i = 0;
- $log = array();
- while ($row = $db->sql_fetchrow($result))
- {
- if ($row['topic_id'])
- {
- $topic_id_list[] = $row['topic_id'];
- }
-
- if ($row['reportee_id'])
- {
- $reportee_id_list[] = $row['reportee_id'];
- }
-
- $log[$i] = array(
- 'id' => $row['log_id'],
-
- 'reportee_id' => $row['reportee_id'],
- 'reportee_username' => '',
- 'reportee_username_full'=> '',
-
- 'user_id' => $row['user_id'],
- 'username' => $row['username'],
- 'username_full' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url),
-
- 'ip' => $row['log_ip'],
- 'time' => $row['log_time'],
- 'forum_id' => $row['forum_id'],
- 'topic_id' => $row['topic_id'],
-
- 'viewforum' => ($row['forum_id'] && $auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : false,
- 'action' => (isset($user->lang[$row['log_operation']])) ? $user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}',
- );
-
- if (!empty($row['log_data']))
- {
- $log_data_ary = @unserialize($row['log_data']);
- $log_data_ary = ($log_data_ary === false) ? array() : $log_data_ary;
-
- if (isset($user->lang[$row['log_operation']]))
- {
- // Check if there are more occurrences of % than arguments, if there are we fill out the arguments array
- // It doesn't matter if we add more arguments than placeholders
- if ((substr_count($log[$i]['action'], '%') - sizeof($log_data_ary)) > 0)
- {
- $log_data_ary = array_merge($log_data_ary, array_fill(0, substr_count($log[$i]['action'], '%') - sizeof($log_data_ary), ''));
- }
-
- $log[$i]['action'] = vsprintf($log[$i]['action'], $log_data_ary);
-
- // If within the admin panel we do not censor text out
- if (defined('IN_ADMIN'))
- {
- $log[$i]['action'] = bbcode_nl2br($log[$i]['action']);
- }
- else
- {
- $log[$i]['action'] = bbcode_nl2br(censor_text($log[$i]['action']));
- }
- }
- else if (!empty($log_data_ary))
- {
- $log[$i]['action'] .= ' ' . implode('', $log_data_ary);
- }
-
- /* Apply make_clickable... has to be seen if it is for good. :/
- // Seems to be not for the moment, reconsider later...
- $log[$i]['action'] = make_clickable($log[$i]['action']);
- */
- }
-
- $i++;
- }
- $db->sql_freeresult($result);
-
- if (sizeof($topic_id_list))
- {
- $topic_id_list = array_unique($topic_id_list);
-
- // This query is not really needed if move_topics() updates the forum_id field,
- // although it's also used to determine if the topic still exists in the database
- $sql = 'SELECT topic_id, forum_id
- FROM ' . TOPICS_TABLE . '
- WHERE ' . $db->sql_in_set('topic_id', array_map('intval', $topic_id_list));
- $result = $db->sql_query($sql);
-
- $default_forum_id = 0;
-
- while ($row = $db->sql_fetchrow($result))
- {
- if ($auth->acl_get('f_read', $row['forum_id']))
- {
- $is_auth[$row['topic_id']] = $row['forum_id'];
- }
-
- if ($auth->acl_gets('a_', 'm_', $row['forum_id']))
- {
- $is_mod[$row['topic_id']] = $row['forum_id'];
- }
- }
- $db->sql_freeresult($result);
-
- foreach ($log as $key => $row)
- {
- $log[$key]['viewtopic'] = (isset($is_auth[$row['topic_id']])) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $is_auth[$row['topic_id']] . '&t=' . $row['topic_id']) : false;
- $log[$key]['viewlogs'] = (isset($is_mod[$row['topic_id']])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=logs&mode=topic_logs&t=' . $row['topic_id'], true, $user->session_id) : false;
- }
- }
-
- if (sizeof($reportee_id_list))
- {
- $reportee_id_list = array_unique($reportee_id_list);
- $reportee_names_list = array();
-
- $sql = 'SELECT user_id, username, user_colour
- FROM ' . USERS_TABLE . '
- WHERE ' . $db->sql_in_set('user_id', $reportee_id_list);
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $reportee_names_list[$row['user_id']] = $row;
- }
- $db->sql_freeresult($result);
-
- foreach ($log as $key => $row)
- {
- if (!isset($reportee_names_list[$row['reportee_id']]))
- {
- continue;
- }
-
- $log[$key]['reportee_username'] = $reportee_names_list[$row['reportee_id']]['username'];
- $log[$key]['reportee_username_full'] = get_username_string('full', $row['reportee_id'], $reportee_names_list[$row['reportee_id']]['username'], $reportee_names_list[$row['reportee_id']]['user_colour'], false, $profile_url);
- }
- }
-
- return $offset;
+ return $phpbb_log->get_valid_offset();
}
/**
diff --git a/phpBB/includes/functions_compatibility.php b/phpBB/includes/functions_compatibility.php
new file mode 100644
index 0000000000..2197815087
--- /dev/null
+++ b/phpBB/includes/functions_compatibility.php
@@ -0,0 +1,50 @@
+ $avatar,
+ 'avatar_type' => $avatar_type,
+ 'avatar_width' => $avatar_width,
+ 'avatar_height' => $avatar_height,
+ );
+
+ if (!function_exists('phpbb_get_avatar'))
+ {
+ global $phpbb_root_path, $phpEx;
+
+ include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ }
+
+ return phpbb_get_avatar($row, $alt, $ignore_config);
+}
diff --git a/phpBB/includes/functions_container.php b/phpBB/includes/functions_container.php
index a3ed21c35b..106b7d75cc 100644
--- a/phpBB/includes/functions_container.php
+++ b/phpBB/includes/functions_container.php
@@ -57,6 +57,7 @@ function phpbb_create_install_container($phpbb_root_path, $php_ext)
$container = phpbb_create_container(array($core), $phpbb_root_path, $php_ext);
$container->setParameter('core.root_path', $phpbb_root_path);
+ $container->setParameter('core.adm_relative_path', $phpbb_adm_relative_path);
$container->setParameter('core.php_ext', $php_ext);
$container->setParameter('core.table_prefix', '');
diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php
index cd4c901b58..9854cd6d70 100644
--- a/phpBB/includes/functions_display.php
+++ b/phpBB/includes/functions_display.php
@@ -1341,79 +1341,87 @@ function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank
/**
* Get user avatar
*
-* @param string $avatar Users assigned avatar name
-* @param int $avatar_type Type of avatar
-* @param string $avatar_width Width of users avatar
-* @param string $avatar_height Height of users avatar
+* @param array $user_row Row from the users table
* @param string $alt Optional language string for alt tag within image, can be a language key or text
* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP
*
-* @return string Avatar image
+* @return string Avatar html
*/
-function get_user_avatar($avatar, $avatar_type, $avatar_width, $avatar_height, $alt = 'USER_AVATAR', $ignore_config = false)
+function phpbb_get_user_avatar($user_row, $alt = 'USER_AVATAR', $ignore_config = false)
{
- global $user, $config, $phpbb_root_path, $phpEx;
- global $phpbb_dispatcher;
+ $row = phpbb_avatar_manager::clean_row($user_row);
+ return phpbb_get_avatar($row, $alt, $ignore_config);
+}
- $overwrite_avatar = '';
+/**
+* Get group avatar
+*
+* @param array $group_row Row from the groups table
+* @param string $alt Optional language string for alt tag within image, can be a language key or text
+* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP
+*
+* @return string Avatar html
+*/
+function phpbb_get_group_avatar($user_row, $alt = 'GROUP_AVATAR', $ignore_config = false)
+{
+ $row = phpbb_avatar_manager::clean_row($user_row);
+ return phpbb_get_avatar($row, $alt, $ignore_config);
+}
- /**
- * Overwrite users avatar
- *
- * @event core.display_custom_bbcodes_modify_row
- * @var string avatar Users assigned avatar name
- * @var int avatar_type Type of avatar
- * @var string avatar_width Width of users avatar
- * @var string avatar_height Height of users avatar
- * @var string alt Language string for alt tag within image
- * Can be a language key or text
- * @var bool ignore_config Ignores config and force displaying avatar
- * @var string overwrite_avatar If set, this string will be the avatar
- * @since 3.1-A1
- */
- $vars = array('avatar', 'avatar_type', 'avatar_width', 'avatar_height', 'alt', 'ignore_config', 'overwrite_avatar');
- extract($phpbb_dispatcher->trigger_event('core.user_get_avatar', compact($vars)));
+/**
+* Get avatar
+*
+* @param array $row Row cleaned by phpbb_avatar_driver::clean_row
+* @param string $alt Optional language string for alt tag within image, can be a language key or text
+* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP
+*
+* @return string Avatar html
+*/
+function phpbb_get_avatar($row, $alt, $ignore_config = false)
+{
+ global $user, $config, $cache, $phpbb_root_path, $phpEx;
+ global $request;
+ global $phpbb_container;
- if ($overwrite_avatar)
- {
- return $overwrite_avatar;
- }
-
- if (empty($avatar) || !$avatar_type || (!$config['allow_avatar'] && !$ignore_config))
+ if (!$config['allow_avatar'] && !$ignore_config)
{
return '';
}
- $avatar_img = '';
+ $avatar_data = array(
+ 'src' => $row['avatar'],
+ 'width' => $row['avatar_width'],
+ 'height' => $row['avatar_height'],
+ );
- switch ($avatar_type)
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $driver = $phpbb_avatar_manager->get_driver($row['avatar_type'], $ignore_config);
+ $html = '';
+
+ if ($driver)
{
- case AVATAR_UPLOAD:
- if (!$config['allow_avatar_upload'] && !$ignore_config)
- {
- return '';
- }
- $avatar_img = $phpbb_root_path . "download/file.$phpEx?avatar=";
- break;
+ $html = $driver->get_custom_html($user, $row, $alt);
+ if (!empty($html))
+ {
+ return $html;
+ }
- case AVATAR_GALLERY:
- if (!$config['allow_avatar_local'] && !$ignore_config)
- {
- return '';
- }
- $avatar_img = $phpbb_root_path . $config['avatar_gallery_path'] . '/';
- break;
-
- case AVATAR_REMOTE:
- if (!$config['allow_avatar_remote'] && !$ignore_config)
- {
- return '';
- }
- break;
+ $avatar_data = $driver->get_data($row, $ignore_config);
+ }
+ else
+ {
+ $avatar_data['src'] = '';
}
- $avatar_img .= $avatar;
- return '';
+ if (!empty($avatar_data['src']))
+ {
+ $html = 'lang[$alt])) ? $user->lang[$alt] : $alt) . '" />';
+ }
+
+ return $html;
}
/**
diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php
index 8aea27a9ef..baef7bcda5 100644
--- a/phpBB/includes/functions_posting.php
+++ b/phpBB/includes/functions_posting.php
@@ -61,7 +61,7 @@ function generate_smilies($mode, $forum_id)
'body' => 'posting_smilies.html')
);
- generate_pagination(append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&f=' . $forum_id), $smiley_count, $config['smilies_per_page'], $start);
+ generate_pagination(append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&f=' . $forum_id), $smiley_count, $config['smilies_per_page'], $start);
}
$display_link = false;
@@ -1175,238 +1175,6 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id
return true;
}
-/**
-* User Notification
-*/
-function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id, $topic_id, $post_id, $author_name = '')
-{
- global $db, $user, $config, $phpbb_root_path, $phpEx, $auth;
-
- $topic_notification = ($mode == 'reply' || $mode == 'quote') ? true : false;
- $forum_notification = ($mode == 'post') ? true : false;
-
- if (!$topic_notification && !$forum_notification)
- {
- trigger_error('NO_MODE');
- }
-
- if (($topic_notification && !$config['allow_topic_notify']) || ($forum_notification && !$config['allow_forum_notify']))
- {
- return;
- }
-
- $topic_title = ($topic_notification) ? $topic_title : $subject;
- $topic_title = censor_text($topic_title);
-
- // Exclude guests, current user and banned users from notifications
- if (!function_exists('phpbb_get_banned_user_ids'))
- {
- include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
- }
- $sql_ignore_users = phpbb_get_banned_user_ids();
- $sql_ignore_users[ANONYMOUS] = ANONYMOUS;
- $sql_ignore_users[$user->data['user_id']] = $user->data['user_id'];
-
- $notify_rows = array();
-
- // -- get forum_userids || topic_userids
- $sql = 'SELECT u.user_id, u.username, u.user_email, u.user_lang, u.user_notify_type, u.user_jabber
- FROM ' . (($topic_notification) ? TOPICS_WATCH_TABLE : FORUMS_WATCH_TABLE) . ' w, ' . USERS_TABLE . ' u
- WHERE w.' . (($topic_notification) ? 'topic_id' : 'forum_id') . ' = ' . (($topic_notification) ? $topic_id : $forum_id) . '
- AND ' . $db->sql_in_set('w.user_id', $sql_ignore_users, true) . '
- AND w.notify_status = ' . NOTIFY_YES . '
- AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')
- AND u.user_id = w.user_id';
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $notify_user_id = (int) $row['user_id'];
- $notify_rows[$notify_user_id] = array(
- 'user_id' => $notify_user_id,
- 'username' => $row['username'],
- 'user_email' => $row['user_email'],
- 'user_jabber' => $row['user_jabber'],
- 'user_lang' => $row['user_lang'],
- 'notify_type' => ($topic_notification) ? 'topic' : 'forum',
- 'template' => ($topic_notification) ? 'topic_notify' : 'newtopic_notify',
- 'method' => $row['user_notify_type'],
- 'allowed' => false
- );
-
- // Add users who have been already notified to ignore list
- $sql_ignore_users[$notify_user_id] = $notify_user_id;
- }
- $db->sql_freeresult($result);
-
- // forum notification is sent to those not already receiving topic notifications
- if ($topic_notification)
- {
- $sql = 'SELECT u.user_id, u.username, u.user_email, u.user_lang, u.user_notify_type, u.user_jabber
- FROM ' . FORUMS_WATCH_TABLE . ' fw, ' . USERS_TABLE . " u
- WHERE fw.forum_id = $forum_id
- AND " . $db->sql_in_set('fw.user_id', $sql_ignore_users, true) . '
- AND fw.notify_status = ' . NOTIFY_YES . '
- AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')
- AND u.user_id = fw.user_id';
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $notify_user_id = (int) $row['user_id'];
- $notify_rows[$notify_user_id] = array(
- 'user_id' => $notify_user_id,
- 'username' => $row['username'],
- 'user_email' => $row['user_email'],
- 'user_jabber' => $row['user_jabber'],
- 'user_lang' => $row['user_lang'],
- 'notify_type' => 'forum',
- 'template' => 'forum_notify',
- 'method' => $row['user_notify_type'],
- 'allowed' => false
- );
- }
- $db->sql_freeresult($result);
- }
-
- if (!sizeof($notify_rows))
- {
- return;
- }
-
- // Make sure users are allowed to read the forum
- foreach ($auth->acl_get_list(array_keys($notify_rows), 'f_read', $forum_id) as $forum_id => $forum_ary)
- {
- foreach ($forum_ary as $auth_option => $user_ary)
- {
- foreach ($user_ary as $user_id)
- {
- $notify_rows[$user_id]['allowed'] = true;
- }
- }
- }
-
- // Now, we have to do a little step before really sending, we need to distinguish our users a little bit. ;)
- $msg_users = $delete_ids = $update_notification = array();
- foreach ($notify_rows as $user_id => $row)
- {
- if (!$row['allowed'] || !trim($row['user_email']))
- {
- $delete_ids[$row['notify_type']][] = $row['user_id'];
- }
- else
- {
- $msg_users[] = $row;
- $update_notification[$row['notify_type']][] = $row['user_id'];
-
- /*
- * We also update the forums watch table for this user when we are
- * sending out a topic notification to prevent sending out another
- * notification in case this user is also subscribed to the forum
- * this topic was posted in.
- * Since an UPDATE query is used, this has no effect on users only
- * subscribed to the topic (i.e. no row is created) and should not
- * be a performance issue.
- */
- if ($row['notify_type'] === 'topic')
- {
- $update_notification['forum'][] = $row['user_id'];
- }
- }
- }
- unset($notify_rows);
-
- // Now, we are able to really send out notifications
- if (sizeof($msg_users))
- {
- include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
- $messenger = new messenger();
-
- $msg_list_ary = array();
- foreach ($msg_users as $row)
- {
- $pos = (!isset($msg_list_ary[$row['template']])) ? 0 : sizeof($msg_list_ary[$row['template']]);
-
- $msg_list_ary[$row['template']][$pos]['method'] = $row['method'];
- $msg_list_ary[$row['template']][$pos]['email'] = $row['user_email'];
- $msg_list_ary[$row['template']][$pos]['jabber'] = $row['user_jabber'];
- $msg_list_ary[$row['template']][$pos]['name'] = $row['username'];
- $msg_list_ary[$row['template']][$pos]['lang'] = $row['user_lang'];
- $msg_list_ary[$row['template']][$pos]['user_id']= $row['user_id'];
- }
- unset($msg_users);
-
- foreach ($msg_list_ary as $email_template => $email_list)
- {
- foreach ($email_list as $addr)
- {
- $messenger->template($email_template, $addr['lang']);
-
- $messenger->to($addr['email'], $addr['name']);
- $messenger->im($addr['jabber'], $addr['name']);
-
- $messenger->assign_vars(array(
- 'USERNAME' => htmlspecialchars_decode($addr['name']),
- 'TOPIC_TITLE' => htmlspecialchars_decode($topic_title),
- 'FORUM_NAME' => htmlspecialchars_decode($forum_name),
- 'AUTHOR_NAME' => htmlspecialchars_decode($author_name),
-
- 'U_FORUM' => generate_board_url() . "/viewforum.$phpEx?f=$forum_id",
- 'U_TOPIC' => generate_board_url() . "/viewtopic.$phpEx?f=$forum_id&t=$topic_id",
- 'U_NEWEST_POST' => generate_board_url() . "/viewtopic.$phpEx?f=$forum_id&t=$topic_id&p=$post_id&e=$post_id",
- 'U_STOP_WATCHING_TOPIC' => generate_board_url() . "/viewtopic.$phpEx?uid={$addr['user_id']}&f=$forum_id&t=$topic_id&unwatch=topic",
- 'U_STOP_WATCHING_FORUM' => generate_board_url() . "/viewforum.$phpEx?uid={$addr['user_id']}&f=$forum_id&unwatch=forum",
- ));
-
- $messenger->send($addr['method']);
- }
- }
- unset($msg_list_ary);
-
- $messenger->save_queue();
- }
-
- // Handle the DB updates
- $db->sql_transaction('begin');
-
- if (!empty($update_notification['topic']))
- {
- $sql = 'UPDATE ' . TOPICS_WATCH_TABLE . '
- SET notify_status = ' . NOTIFY_NO . "
- WHERE topic_id = $topic_id
- AND " . $db->sql_in_set('user_id', $update_notification['topic']);
- $db->sql_query($sql);
- }
-
- if (!empty($update_notification['forum']))
- {
- $sql = 'UPDATE ' . FORUMS_WATCH_TABLE . '
- SET notify_status = ' . NOTIFY_NO . "
- WHERE forum_id = $forum_id
- AND " . $db->sql_in_set('user_id', $update_notification['forum']);
- $db->sql_query($sql);
- }
-
- // Now delete the user_ids not authorised to receive notifications on this topic/forum
- if (!empty($delete_ids['topic']))
- {
- $sql = 'DELETE FROM ' . TOPICS_WATCH_TABLE . "
- WHERE topic_id = $topic_id
- AND " . $db->sql_in_set('user_id', $delete_ids['topic']);
- $db->sql_query($sql);
- }
-
- if (!empty($delete_ids['forum']))
- {
- $sql = 'DELETE FROM ' . FORUMS_WATCH_TABLE . "
- WHERE forum_id = $forum_id
- AND " . $db->sql_in_set('user_id', $delete_ids['forum']);
- $db->sql_query($sql);
- }
-
- $db->sql_transaction('commit');
-}
-
//
// Post handling functions
//
@@ -1642,7 +1410,7 @@ function delete_post($forum_id, $topic_id, $post_id, &$data)
*/
function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $update_message = true, $update_search_index = true)
{
- global $db, $auth, $user, $config, $phpEx, $template, $phpbb_root_path;
+ global $db, $auth, $user, $config, $phpEx, $template, $phpbb_root_path, $phpbb_container;
// We do not handle erasing posts here
if ($mode == 'delete')
@@ -2454,10 +2222,76 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
}
// Send Notifications
- if (($mode == 'reply' || $mode == 'quote' || $mode == 'post') && $post_approval)
+ $notification_data = array_merge($data, array(
+ 'topic_title' => (isset($data['topic_title'])) ? $data['topic_title'] : $subject,
+ 'post_username' => $username,
+ 'poster_id' => $poster_id,
+ 'post_text' => $data['message'],
+ 'post_time' => $current_time,
+ 'post_subject' => $subject,
+ ));
+
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ if ($post_approval)
{
- $username = ($username) ? $username : $user->data['username'];
- user_notification($mode, $subject, $data['topic_title'], $data['forum_name'], $data['forum_id'], $data['topic_id'], $data['post_id'], $username);
+ switch ($mode)
+ {
+ case 'post':
+ $phpbb_notifications->add_notifications(array(
+ 'quote',
+ 'topic',
+ ), $notification_data);
+ break;
+
+ case 'reply':
+ case 'quote':
+ $phpbb_notifications->add_notifications(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ ), $notification_data);
+ break;
+
+ case 'edit_topic':
+ case 'edit_first_post':
+ case 'edit':
+ case 'edit_last_post':
+ $phpbb_notifications->update_notifications(array(
+ 'quote',
+ 'bookmark',
+ 'topic',
+ 'post',
+ ), $notification_data);
+ break;
+ }
+ }
+ else
+ {
+ switch ($mode)
+ {
+ case 'post':
+ $phpbb_notifications->add_notifications('topic_in_queue', $notification_data);
+ break;
+
+ case 'reply':
+ case 'quote':
+ $phpbb_notifications->add_notifications('post_in_queue', $notification_data);
+ break;
+
+ case 'edit_topic':
+ case 'edit_first_post':
+ case 'edit':
+ case 'edit_last_post':
+ $phpbb_notifications->delete_notifications('topic', $data['topic_id']);
+
+ $phpbb_notifications->delete_notifications(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ ), $data['post_id']);
+ break;
+ }
}
$params = $add_anchor = '';
diff --git a/phpBB/includes/functions_privmsgs.php b/phpBB/includes/functions_privmsgs.php
index ba939d490e..14278a2529 100644
--- a/phpBB/includes/functions_privmsgs.php
+++ b/phpBB/includes/functions_privmsgs.php
@@ -876,7 +876,11 @@ function update_unread_status($unread, $msg_id, $user_id, $folder_id)
return;
}
- global $db, $user;
+ global $db, $user, $phpbb_container;
+
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $phpbb_notifications->mark_notifications_read('pm', $msg_id, $user_id);
$sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
SET pm_unread = 0
@@ -981,7 +985,7 @@ function handle_mark_actions($user_id, $mark_action)
*/
function delete_pm($user_id, $msg_ids, $folder_id)
{
- global $db, $user, $phpbb_root_path, $phpEx;
+ global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container;
$user_id = (int) $user_id;
$folder_id = (int) $folder_id;
@@ -1093,6 +1097,10 @@ function delete_pm($user_id, $msg_ids, $folder_id)
$user->data['user_unread_privmsg'] -= $num_unread;
}
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $phpbb_notifications->delete_notifications('pm', array_keys($delete_rows));
+
// Now we have to check which messages we can delete completely
$sql = 'SELECT msg_id
FROM ' . PRIVMSGS_TO_TABLE . '
@@ -1157,7 +1165,7 @@ function phpbb_delete_user_pms($user_id)
*/
function phpbb_delete_users_pms($user_ids)
{
- global $db, $user, $phpbb_root_path, $phpEx;
+ global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container;
$user_id_sql = $db->sql_in_set('user_id', $user_ids);
$author_id_sql = $db->sql_in_set('author_id', $user_ids);
@@ -1202,6 +1210,8 @@ function phpbb_delete_users_pms($user_ids)
$db->sql_transaction('begin');
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
if (!empty($undelivered_msg))
{
// A pm is delivered, if for any recipient the message was moved
@@ -1270,6 +1280,8 @@ function phpbb_delete_users_pms($user_ids)
WHERE folder_id = ' . PRIVMSGS_NO_BOX . '
AND ' . $db->sql_in_set('msg_id', $delivered_msg);
$db->sql_query($sql);
+
+ $phpbb_notifications->delete_notifications('pm', $delivered_msg);
}
if (!empty($undelivered_msg))
@@ -1281,6 +1293,8 @@ function phpbb_delete_users_pms($user_ids)
$sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg);
$db->sql_query($sql);
+
+ $phpbb_notifications->delete_notifications('pm', $undelivered_msg);
}
}
@@ -1323,6 +1337,8 @@ function phpbb_delete_users_pms($user_ids)
$sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
$db->sql_query($sql);
+
+ $phpbb_notifications->delete_notifications('pm', $delete_ids);
}
}
@@ -1559,7 +1575,7 @@ function get_folder_status($folder_id, $folder)
*/
function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
{
- global $db, $auth, $config, $phpEx, $template, $user, $phpbb_root_path;
+ global $db, $auth, $config, $phpEx, $template, $user, $phpbb_root_path, $phpbb_container;
// We do not handle erasing pms here
if ($mode == 'delete')
@@ -1859,97 +1875,25 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
$db->sql_transaction('commit');
// Send Notifications
- if ($mode != 'edit')
+ $pm_data = array_merge($data, array(
+ 'message_subject' => $subject,
+ 'recipients' => $recipients,
+ ));
+
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ if ($mode == 'edit')
{
- pm_notification($mode, $data['from_username'], $recipients, $subject, $data['message'], $data['msg_id']);
+ $phpbb_notifications->update_notifications('pm', $pm_data);
+ }
+ else
+ {
+ $phpbb_notifications->add_notifications('pm', $pm_data);
}
return $data['msg_id'];
}
-/**
-* PM Notification
-*/
-function pm_notification($mode, $author, $recipients, $subject, $message, $msg_id)
-{
- global $db, $user, $config, $phpbb_root_path, $phpEx, $auth;
-
- $subject = censor_text($subject);
-
- // Exclude guests, current user and banned users from notifications
- unset($recipients[ANONYMOUS], $recipients[$user->data['user_id']]);
-
- if (!sizeof($recipients))
- {
- return;
- }
-
- if (!function_exists('phpbb_get_banned_user_ids'))
- {
- include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
- }
- $banned_users = phpbb_get_banned_user_ids(array_keys($recipients));
- $recipients = array_diff(array_keys($recipients), $banned_users);
-
- if (!sizeof($recipients))
- {
- return;
- }
-
- $sql = 'SELECT user_id, username, user_email, user_lang, user_notify_pm, user_notify_type, user_jabber
- FROM ' . USERS_TABLE . '
- WHERE ' . $db->sql_in_set('user_id', $recipients);
- $result = $db->sql_query($sql);
-
- $msg_list_ary = array();
- while ($row = $db->sql_fetchrow($result))
- {
- if ($row['user_notify_pm'] == 1 && trim($row['user_email']))
- {
- $msg_list_ary[] = array(
- 'method' => $row['user_notify_type'],
- 'email' => $row['user_email'],
- 'jabber' => $row['user_jabber'],
- 'name' => $row['username'],
- 'lang' => $row['user_lang']
- );
- }
- }
- $db->sql_freeresult($result);
-
- if (!sizeof($msg_list_ary))
- {
- return;
- }
-
- include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
- $messenger = new messenger();
-
- foreach ($msg_list_ary as $pos => $addr)
- {
- $messenger->template('privmsg_notify', $addr['lang']);
-
- $messenger->to($addr['email'], $addr['name']);
- $messenger->im($addr['jabber'], $addr['name']);
-
- $messenger->assign_vars(array(
- 'SUBJECT' => htmlspecialchars_decode($subject),
- 'AUTHOR_NAME' => htmlspecialchars_decode($author),
- 'USERNAME' => htmlspecialchars_decode($addr['name']),
-
- 'U_INBOX' => generate_board_url() . "/ucp.$phpEx?i=pm&folder=inbox",
- 'U_VIEW_MESSAGE' => generate_board_url() . "/ucp.$phpEx?i=pm&mode=view&p=$msg_id",
- ));
-
- $messenger->send($addr['method']);
- }
- unset($msg_list_ary);
-
- $messenger->save_queue();
-
- unset($messenger);
-}
-
/**
* Display Message History
*/
diff --git a/phpBB/includes/functions_user.php b/phpBB/includes/functions_user.php
index b7878ddfc7..bc636acabb 100644
--- a/phpBB/includes/functions_user.php
+++ b/phpBB/includes/functions_user.php
@@ -310,8 +310,10 @@ function user_add($user_row, $cp_data = false)
if ($add_group_id)
{
- // Because these actions only fill the log unneccessarily we skip the add_log() entry with a little hack. :/
- $GLOBALS['skip_add_log'] = true;
+ global $phpbb_log;
+
+ // Because these actions only fill the log unneccessarily we skip the add_log() entry.
+ $phpbb_log->disable('admin');
// Add user to "newly registered users" group and set to default group if admin specified so.
if ($config['new_member_group_default'])
@@ -324,7 +326,7 @@ function user_add($user_row, $cp_data = false)
group_user_add($add_group_id, $user_id);
}
- unset($GLOBALS['skip_add_log']);
+ $phpbb_log->enable('admin');
}
}
@@ -2048,6 +2050,7 @@ function avatar_delete($mode, $row, $clean_db = false)
avatar_remove_db($row[$mode . '_avatar']);
}
$filename = get_avatar_filename($row[$mode . '_avatar']);
+
if (file_exists($phpbb_root_path . $config['avatar_path'] . '/' . $filename))
{
@unlink($phpbb_root_path . $config['avatar_path'] . '/' . $filename);
@@ -2057,134 +2060,6 @@ function avatar_delete($mode, $row, $clean_db = false)
return false;
}
-/**
-* Remote avatar linkage
-*/
-function avatar_remote($data, &$error)
-{
- global $config, $db, $user, $phpbb_root_path, $phpEx;
-
- if (!preg_match('#^(http|https|ftp)://#i', $data['remotelink']))
- {
- $data['remotelink'] = 'http://' . $data['remotelink'];
- }
- if (!preg_match('#^(http|https|ftp)://(?:(.*?\.)*?[a-z0-9\-]+?\.[a-z]{2,4}|(?:\d{1,3}\.){3,5}\d{1,3}):?([0-9]*?).*?\.(gif|jpg|jpeg|png)$#i', $data['remotelink']))
- {
- $error[] = $user->lang['AVATAR_URL_INVALID'];
- return false;
- }
-
- // Make sure getimagesize works...
- if (($image_data = @getimagesize($data['remotelink'])) === false && (empty($data['width']) || empty($data['height'])))
- {
- $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
- return false;
- }
-
- if (!empty($image_data) && ($image_data[0] < 2 || $image_data[1] < 2))
- {
- $error[] = $user->lang['AVATAR_NO_SIZE'];
- return false;
- }
-
- $width = ($data['width'] && $data['height']) ? $data['width'] : $image_data[0];
- $height = ($data['width'] && $data['height']) ? $data['height'] : $image_data[1];
-
- if ($width < 2 || $height < 2)
- {
- $error[] = $user->lang['AVATAR_NO_SIZE'];
- return false;
- }
-
- // Check image type
- include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx);
- $types = fileupload::image_types();
- $extension = strtolower(filespec::get_extension($data['remotelink']));
-
- if (!empty($image_data) && (!isset($types[$image_data[2]]) || !in_array($extension, $types[$image_data[2]])))
- {
- if (!isset($types[$image_data[2]]))
- {
- $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
- }
- else
- {
- $error[] = sprintf($user->lang['IMAGE_FILETYPE_MISMATCH'], $types[$image_data[2]][0], $extension);
- }
- return false;
- }
-
- if ($config['avatar_max_width'] || $config['avatar_max_height'])
- {
- if ($width > $config['avatar_max_width'] || $height > $config['avatar_max_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($width, $height);
- return false;
- }
- }
-
- if ($config['avatar_min_width'] || $config['avatar_min_height'])
- {
- if ($width < $config['avatar_min_width'] || $height < $config['avatar_min_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($width, $height);
- return false;
- }
- }
-
- return array(AVATAR_REMOTE, $data['remotelink'], $width, $height);
-}
-
-/**
-* Avatar upload using the upload class
-*/
-function avatar_upload($data, &$error)
-{
- global $phpbb_root_path, $config, $db, $user, $phpEx, $request;
-
- // Init upload class
- include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx);
- $upload = new fileupload('AVATAR_', array('jpg', 'jpeg', 'gif', 'png'), $config['avatar_filesize'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], (isset($config['mime_triggers']) ? explode('|', $config['mime_triggers']) : false));
-
- $uploadfile = $request->file('uploadfile');
- if (!empty($uploadfile['name']))
- {
- $file = $upload->form_upload('uploadfile');
- }
- else
- {
- $file = $upload->remote_upload($data['uploadurl']);
- }
-
- $prefix = $config['avatar_salt'] . '_';
- $file->clean_filename('avatar', $prefix, $data['user_id']);
-
- $destination = $config['avatar_path'];
-
- // Adjust destination path (no trailing slash)
- if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\')
- {
- $destination = substr($destination, 0, -1);
- }
-
- $destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination);
- if ($destination && ($destination[0] == '/' || $destination[0] == "\\"))
- {
- $destination = '';
- }
-
- // Move file and overwrite any existing image
- $file->move_file($destination, true);
-
- if (sizeof($file->error))
- {
- $file->remove();
- $error = array_merge($error, $file->error);
- }
-
- return array(AVATAR_UPLOAD, $data['user_id'] . '_' . time() . '.' . $file->get('extension'), $file->get('width'), $file->get('height'));
-}
-
/**
* Generates avatar filename from the database entry
*/
@@ -2207,344 +2082,6 @@ function get_avatar_filename($avatar_entry)
return $config['avatar_salt'] . '_' . (($avatar_group) ? 'g' : '') . $avatar_entry . '.' . $ext;
}
-/**
-* Avatar Gallery
-*/
-function avatar_gallery($category, $avatar_select, $items_per_column, $block_var = 'avatar_row')
-{
- global $user, $cache, $template;
- global $config, $phpbb_root_path;
-
- $avatar_list = array();
-
- $path = $phpbb_root_path . $config['avatar_gallery_path'];
-
- if (!file_exists($path) || !is_dir($path))
- {
- $avatar_list = array($user->lang['NO_AVATAR_CATEGORY'] => array());
- }
- else
- {
- // Collect images
- $dp = @opendir($path);
-
- if (!$dp)
- {
- return array($user->lang['NO_AVATAR_CATEGORY'] => array());
- }
-
- while (($file = readdir($dp)) !== false)
- {
- if ($file[0] != '.' && preg_match('#^[^&"\'<>]+$#i', $file) && is_dir("$path/$file"))
- {
- $avatar_row_count = $avatar_col_count = 0;
-
- if ($dp2 = @opendir("$path/$file"))
- {
- while (($sub_file = readdir($dp2)) !== false)
- {
- if (preg_match('#^[^&\'"<>]+\.(?:gif|png|jpe?g)$#i', $sub_file))
- {
- $avatar_list[$file][$avatar_row_count][$avatar_col_count] = array(
- 'file' => rawurlencode($file) . '/' . rawurlencode($sub_file),
- 'filename' => rawurlencode($sub_file),
- 'name' => ucfirst(str_replace('_', ' ', preg_replace('#^(.*)\..*$#', '\1', $sub_file))),
- );
- $avatar_col_count++;
- if ($avatar_col_count == $items_per_column)
- {
- $avatar_row_count++;
- $avatar_col_count = 0;
- }
- }
- }
- closedir($dp2);
- }
- }
- }
- closedir($dp);
- }
-
- if (!sizeof($avatar_list))
- {
- $avatar_list = array($user->lang['NO_AVATAR_CATEGORY'] => array());
- }
-
- @ksort($avatar_list);
-
- $category = (!$category) ? key($avatar_list) : $category;
- $avatar_categories = array_keys($avatar_list);
-
- $s_category_options = '';
- foreach ($avatar_categories as $cat)
- {
- $s_category_options .= '';
- }
-
- $template->assign_vars(array(
- 'S_AVATARS_ENABLED' => true,
- 'S_IN_AVATAR_GALLERY' => true,
- 'S_CAT_OPTIONS' => $s_category_options)
- );
-
- $avatar_list = (isset($avatar_list[$category])) ? $avatar_list[$category] : array();
-
- foreach ($avatar_list as $avatar_row_ary)
- {
- $template->assign_block_vars($block_var, array());
-
- foreach ($avatar_row_ary as $avatar_col_ary)
- {
- $template->assign_block_vars($block_var . '.avatar_column', array(
- 'AVATAR_IMAGE' => $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar_col_ary['file'],
- 'AVATAR_NAME' => $avatar_col_ary['name'],
- 'AVATAR_FILE' => $avatar_col_ary['filename'])
- );
-
- $template->assign_block_vars($block_var . '.avatar_option_column', array(
- 'AVATAR_IMAGE' => $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar_col_ary['file'],
- 'S_OPTIONS_AVATAR' => $avatar_col_ary['filename'])
- );
- }
- }
-
- return $avatar_list;
-}
-
-
-/**
-* Tries to (re-)establish avatar dimensions
-*/
-function avatar_get_dimensions($avatar, $avatar_type, &$error, $current_x = 0, $current_y = 0)
-{
- global $config, $phpbb_root_path, $user;
-
- switch ($avatar_type)
- {
- case AVATAR_REMOTE :
- break;
-
- case AVATAR_UPLOAD :
- $avatar = $phpbb_root_path . $config['avatar_path'] . '/' . get_avatar_filename($avatar);
- break;
-
- case AVATAR_GALLERY :
- $avatar = $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar ;
- break;
- }
-
- // Make sure getimagesize works...
- if (($image_data = @getimagesize($avatar)) === false)
- {
- $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
- return false;
- }
-
- if ($image_data[0] < 2 || $image_data[1] < 2)
- {
- $error[] = $user->lang['AVATAR_NO_SIZE'];
- return false;
- }
-
- // try to maintain ratio
- if (!(empty($current_x) && empty($current_y)))
- {
- if ($current_x != 0)
- {
- $image_data[1] = (int) floor(($current_x / $image_data[0]) * $image_data[1]);
- $image_data[1] = min($config['avatar_max_height'], $image_data[1]);
- $image_data[1] = max($config['avatar_min_height'], $image_data[1]);
- }
- if ($current_y != 0)
- {
- $image_data[0] = (int) floor(($current_y / $image_data[1]) * $image_data[0]);
- $image_data[0] = min($config['avatar_max_width'], $image_data[1]);
- $image_data[0] = max($config['avatar_min_width'], $image_data[1]);
- }
- }
- return array($image_data[0], $image_data[1]);
-}
-
-/**
-* Uploading/Changing user avatar
-*/
-function avatar_process_user(&$error, $custom_userdata = false, $can_upload = null)
-{
- global $config, $phpbb_root_path, $auth, $user, $db, $request;
-
- $data = array(
- 'uploadurl' => request_var('uploadurl', ''),
- 'remotelink' => request_var('remotelink', ''),
- 'width' => request_var('width', 0),
- 'height' => request_var('height', 0),
- );
-
- $error = validate_data($data, array(
- 'uploadurl' => array('string', true, 5, 255),
- 'remotelink' => array('string', true, 5, 255),
- 'width' => array('string', true, 1, 3),
- 'height' => array('string', true, 1, 3),
- ));
-
- if (sizeof($error))
- {
- return false;
- }
-
- $sql_ary = array();
-
- if ($custom_userdata === false)
- {
- $userdata = &$user->data;
- }
- else
- {
- $userdata = &$custom_userdata;
- }
-
- $data['user_id'] = $userdata['user_id'];
- $change_avatar = ($custom_userdata === false) ? $auth->acl_get('u_chgavatar') : true;
- $avatar_select = basename(request_var('avatar_select', ''));
-
- // Can we upload?
- if (is_null($can_upload))
- {
- $can_upload = ($config['allow_avatar_upload'] && file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $change_avatar && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')) ? true : false;
- }
-
- $uploadfile = $request->file('uploadfile');
- if ((!empty($uploadfile['name']) || $data['uploadurl']) && $can_upload)
- {
- list($sql_ary['user_avatar_type'], $sql_ary['user_avatar'], $sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = avatar_upload($data, $error);
- }
- else if ($data['remotelink'] && $change_avatar && $config['allow_avatar_remote'])
- {
- list($sql_ary['user_avatar_type'], $sql_ary['user_avatar'], $sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = avatar_remote($data, $error);
- }
- else if ($avatar_select && $change_avatar && $config['allow_avatar_local'])
- {
- $category = basename(request_var('category', ''));
-
- $sql_ary['user_avatar_type'] = AVATAR_GALLERY;
- $sql_ary['user_avatar'] = $avatar_select;
-
- // check avatar gallery
- if (!is_dir($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category))
- {
- $sql_ary['user_avatar'] = '';
- $sql_ary['user_avatar_type'] = $sql_ary['user_avatar_width'] = $sql_ary['user_avatar_height'] = 0;
- }
- else
- {
- list($sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = getimagesize($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category . '/' . urldecode($sql_ary['user_avatar']));
- $sql_ary['user_avatar'] = $category . '/' . $sql_ary['user_avatar'];
- }
- }
- else if (isset($_POST['delete']) && $change_avatar)
- {
- $sql_ary['user_avatar'] = '';
- $sql_ary['user_avatar_type'] = $sql_ary['user_avatar_width'] = $sql_ary['user_avatar_height'] = 0;
- }
- else if (!empty($userdata['user_avatar']))
- {
- // Only update the dimensions
-
- if (empty($data['width']) || empty($data['height']))
- {
- if ($dims = avatar_get_dimensions($userdata['user_avatar'], $userdata['user_avatar_type'], $error, $data['width'], $data['height']))
- {
- list($guessed_x, $guessed_y) = $dims;
- if (empty($data['width']))
- {
- $data['width'] = $guessed_x;
- }
- if (empty($data['height']))
- {
- $data['height'] = $guessed_y;
- }
- }
- }
- if (($config['avatar_max_width'] || $config['avatar_max_height']) &&
- (($data['width'] != $userdata['user_avatar_width']) || $data['height'] != $userdata['user_avatar_height']))
- {
- if ($data['width'] > $config['avatar_max_width'] || $data['height'] > $config['avatar_max_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
- }
- }
-
- if (!sizeof($error))
- {
- if ($config['avatar_min_width'] || $config['avatar_min_height'])
- {
- if ($data['width'] < $config['avatar_min_width'] || $data['height'] < $config['avatar_min_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
- }
- }
- }
-
- if (!sizeof($error))
- {
- $sql_ary['user_avatar_width'] = $data['width'];
- $sql_ary['user_avatar_height'] = $data['height'];
- }
- }
-
- if (!sizeof($error))
- {
- // Do we actually have any data to update?
- if (sizeof($sql_ary))
- {
- $ext_new = $ext_old = '';
- if (isset($sql_ary['user_avatar']))
- {
- $userdata = ($custom_userdata === false) ? $user->data : $custom_userdata;
- $ext_new = (empty($sql_ary['user_avatar'])) ? '' : substr(strrchr($sql_ary['user_avatar'], '.'), 1);
- $ext_old = (empty($userdata['user_avatar'])) ? '' : substr(strrchr($userdata['user_avatar'], '.'), 1);
-
- if ($userdata['user_avatar_type'] == AVATAR_UPLOAD)
- {
- // Delete old avatar if present
- if ((!empty($userdata['user_avatar']) && empty($sql_ary['user_avatar']))
- || ( !empty($userdata['user_avatar']) && !empty($sql_ary['user_avatar']) && $ext_new !== $ext_old))
- {
- avatar_delete('user', $userdata);
- }
- }
- }
-
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
- WHERE user_id = ' . (($custom_userdata === false) ? $user->data['user_id'] : $custom_userdata['user_id']);
- $db->sql_query($sql);
-
- }
- }
-
- return (sizeof($error)) ? false : true;
-}
-
-/**
-* Returns a language string with the avatar size of the new avatar and the allowed maximum and minimum
-*
-* @param $width int The width of the new uploaded/selected avatar
-* @param $height int The height of the new uploaded/selected avatar
-* @return string
-*/
-function phpbb_avatar_error_wrong_size($width, $height)
-{
- global $config, $user;
-
- return $user->lang('AVATAR_WRONG_SIZE',
- $user->lang('PIXELS', (int) $config['avatar_min_width']),
- $user->lang('PIXELS', (int) $config['avatar_min_height']),
- $user->lang('PIXELS', (int) $config['avatar_max_width']),
- $user->lang('PIXELS', (int) $config['avatar_max_height']),
- $user->lang('PIXELS', (int) $width),
- $user->lang('PIXELS', (int) $height));
-}
-
/**
* Returns an explanation string with maximum avatar settings
*
@@ -2570,7 +2107,7 @@ function phpbb_avatar_explanation_string()
*/
function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow_desc_bbcode = false, $allow_desc_urls = false, $allow_desc_smilies = false)
{
- global $phpbb_root_path, $config, $db, $user, $file_upload;
+ global $phpbb_root_path, $config, $db, $user, $file_upload, $phpbb_container;
$error = array();
@@ -2594,22 +2131,32 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
$error[] = $user->lang['GROUP_ERR_TYPE'];
}
+ $group_teampage = !empty($group_attributes['group_teampage']);
+ unset($group_attributes['group_teampage']);
+
if (!sizeof($error))
{
- $current_legend = phpbb_group_positions::GROUP_DISABLED;
- $current_teampage = phpbb_group_positions::GROUP_DISABLED;
+ $current_legend = phpbb_groupposition_legend::GROUP_DISABLED;
+ $current_teampage = phpbb_groupposition_teampage::GROUP_DISABLED;
- $legend = new phpbb_group_positions($db, 'legend');
- $teampage = new phpbb_group_positions($db, 'teampage');
+ $legend = $phpbb_container->get('groupposition.legend');
+ $teampage = $phpbb_container->get('groupposition.teampage');
if ($group_id)
{
- $current_legend = $legend->get_group_value($group_id);
- $current_teampage = $teampage->get_group_value($group_id);
+ try
+ {
+ $current_legend = $legend->get_group_value($group_id);
+ $current_teampage = $teampage->get_group_value($group_id);
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()));
+ }
}
if (!empty($group_attributes['group_legend']))
{
- if (($group_id && ($current_legend == phpbb_group_positions::GROUP_DISABLED)) || !$group_id)
+ if (($group_id && ($current_legend == phpbb_groupposition_legend::GROUP_DISABLED)) || !$group_id)
{
// Old group currently not in the legend or new group, add at the end.
$group_attributes['group_legend'] = 1 + $legend->get_group_count();
@@ -2620,44 +2167,26 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
$group_attributes['group_legend'] = $current_legend;
}
}
- else if ($group_id && ($current_legend > phpbb_group_positions::GROUP_DISABLED))
+ else if ($group_id && ($current_legend != phpbb_groupposition_legend::GROUP_DISABLED))
{
// Group is removed from the legend
- $legend->delete_group($group_id, true);
- $group_attributes['group_legend'] = phpbb_group_positions::GROUP_DISABLED;
+ try
+ {
+ $legend->delete_group($group_id, true);
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()));
+ }
+ $group_attributes['group_legend'] = phpbb_groupposition_legend::GROUP_DISABLED;
}
else
{
- $group_attributes['group_legend'] = phpbb_group_positions::GROUP_DISABLED;
- }
-
- if (!empty($group_attributes['group_teampage']))
- {
- if (($group_id && ($current_teampage == phpbb_group_positions::GROUP_DISABLED)) || !$group_id)
- {
- // Old group currently not on the teampage or new group, add at the end.
- $group_attributes['group_teampage'] = 1 + $teampage->get_group_count();
- }
- else
- {
- // Group stayes on the teampage
- $group_attributes['group_teampage'] = $current_teampage;
- }
- }
- else if ($group_id && ($current_teampage > phpbb_group_positions::GROUP_DISABLED))
- {
- // Group is removed from the teampage
- $teampage->delete_group($group_id, true);
- $group_attributes['group_teampage'] = phpbb_group_positions::GROUP_DISABLED;
- }
- else
- {
- $group_attributes['group_teampage'] = phpbb_group_positions::GROUP_DISABLED;
+ $group_attributes['group_legend'] = phpbb_groupposition_legend::GROUP_DISABLED;
}
// Unset the objects, we don't need them anymore.
unset($legend);
- unset($teampage);
$user_ary = array();
$sql_ary = array(
@@ -2751,6 +2280,20 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
$db->sql_query($sql);
}
+ // Remove the group from the teampage, only if unselected and we are editing a group,
+ // which is currently displayed.
+ if (!$group_teampage && $group_id && $current_teampage != phpbb_groupposition_teampage::GROUP_DISABLED)
+ {
+ try
+ {
+ $teampage->delete_group($group_id);
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()));
+ }
+ }
+
if (!$group_id)
{
$group_id = $db->sql_nextid();
@@ -2761,6 +2304,31 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
}
}
+ try
+ {
+ if ($group_teampage && $current_teampage == phpbb_groupposition_teampage::GROUP_DISABLED)
+ {
+ $teampage->add_group($group_id);
+ }
+
+ if ($group_teampage)
+ {
+ if ($current_teampage == phpbb_groupposition_teampage::GROUP_DISABLED)
+ {
+ $teampage->add_group($group_id);
+ }
+ }
+ else if ($group_id && ($current_teampage != phpbb_groupposition_teampage::GROUP_DISABLED))
+ {
+ $teampage->delete_group($group_id);
+ }
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()));
+ }
+ unset($teampage);
+
// Set user attributes
$sql_ary = array();
if (sizeof($group_attributes))
@@ -2842,7 +2410,7 @@ function avatar_remove_db($avatar_name)
*/
function group_delete($group_id, $group_name = false)
{
- global $db, $cache, $auth, $phpbb_root_path, $phpEx, $phpbb_dispatcher;
+ global $db, $cache, $auth, $user, $phpbb_root_path, $phpEx, $phpbb_dispatcher, $phpbb_container;
if (!$group_name)
{
@@ -2884,12 +2452,31 @@ function group_delete($group_id, $group_name = false)
while ($start);
// Delete group from legend and teampage
- $legend = new phpbb_group_positions($db, 'legend');
- $legend->delete_group($group_id);
- unset($legend);
- $teampage = new phpbb_group_positions($db, 'teampage');
- $teampage->delete_group($group_id);
- unset($teampage);
+ try
+ {
+ $legend = $phpbb_container->get('groupposition.legend');
+ $legend->delete_group($group_id);
+ unset($legend);
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ // The group we want to delete does not exist.
+ // No reason to worry, we just continue the deleting process.
+ //trigger_error($user->lang($exception->getMessage()));
+ }
+
+ try
+ {
+ $teampage = $phpbb_container->get('groupposition.teampage');
+ $teampage->delete_group($group_id);
+ unset($teampage);
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ // The group we want to delete does not exist.
+ // No reason to worry, we just continue the deleting process.
+ //trigger_error($user->lang($exception->getMessage()));
+ }
// Delete group
$sql = 'DELETE FROM ' . GROUPS_TABLE . "
diff --git a/phpBB/includes/groupposition/exception.php b/phpBB/includes/groupposition/exception.php
new file mode 100644
index 0000000000..e4ff09c703
--- /dev/null
+++ b/phpBB/includes/groupposition/exception.php
@@ -0,0 +1,23 @@
+adm_back_link = $adm_back_link;
-
- if (!in_array($field, array('teampage', 'legend')))
- {
- $this->error('NO_MODE');
- }
-
$this->db = $db;
- $this->field = $field;
+ $this->user = $user;
}
/**
- * Returns the group_{$this->field} for a given group, if the group exists.
- * @param int $group_id group_id of the group to be selected
- * @return int position of the group
+ * Returns the group_legend for a given group, if the group exists.
+ *
+ * {@inheritDoc}
*/
public function get_group_value($group_id)
{
- $sql = 'SELECT group_' . $this->field . '
+ $sql = 'SELECT group_legend
FROM ' . GROUPS_TABLE . '
WHERE group_id = ' . (int) $group_id;
$result = $this->db->sql_query($sql);
- $current_value = $this->db->sql_fetchfield('group_' . $this->field);
+ $current_value = $this->db->sql_fetchfield('group_legend');
$this->db->sql_freeresult($result);
if ($current_value === false)
{
// Group not found.
- $this->error('NO_GROUP');
+ throw new phpbb_groupposition_exception('NO_GROUP');
}
return (int) $current_value;
}
/**
- * Get number of groups, displayed on the teampage/legend
+ * Get number of groups, displayed on the legend
*
- * @return int value of the last group displayed
+ * {@inheritDoc}
*/
public function get_group_count()
{
- $sql = 'SELECT group_' . $this->field . '
+ $sql = 'SELECT group_legend
FROM ' . GROUPS_TABLE . '
- ORDER BY group_' . $this->field . ' DESC';
+ ORDER BY group_legend DESC';
$result = $this->db->sql_query_limit($sql, 1);
- $group_count = (int) $this->db->sql_fetchfield('group_' . $this->field);
+ $group_count = (int) $this->db->sql_fetchfield('group_legend');
$this->db->sql_freeresult($result);
return $group_count;
}
/**
- * Addes a group by group_id
+ * Adds a group by group_id
*
- * @param int $group_id group_id of the group to be added
- * @return null
+ * {@inheritDoc}
*/
public function add_group($group_id)
{
@@ -116,19 +109,20 @@ class phpbb_group_positions
$next_value = 1 + $this->get_group_count();
$sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = ' . $next_value . '
- WHERE group_' . $this->field . ' = ' . self::GROUP_DISABLED . '
+ SET group_legend = ' . $next_value . '
+ WHERE group_legend = ' . self::GROUP_DISABLED . '
AND group_id = ' . (int) $group_id;
$this->db->sql_query($sql);
+ return true;
}
+
+ return false;
}
/**
* Deletes a group by setting the field to self::GROUP_DISABLED and closing the gap in the list.
*
- * @param int $group_id group_id of the group to be deleted
- * @param bool $skip_group Skip setting the group to GROUP_DISABLED, to save the query, when you need to update it anyway.
- * @return null
+ * {@inheritDoc}
*/
public function delete_group($group_id, $skip_group = false)
{
@@ -139,58 +133,57 @@ class phpbb_group_positions
$this->db->sql_transaction('begin');
$sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = group_' . $this->field . ' - 1
- WHERE group_' . $this->field . ' > ' . $current_value;
+ SET group_legend = group_legend - 1
+ WHERE group_legend > ' . $current_value;
$this->db->sql_query($sql);
if (!$skip_group)
{
$sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = ' . self::GROUP_DISABLED . '
+ SET group_legend = ' . self::GROUP_DISABLED . '
WHERE group_id = ' . (int) $group_id;
$this->db->sql_query($sql);
}
$this->db->sql_transaction('commit');
+
+ return true;
}
+
+ return false;
}
/**
* Moves a group up by group_id
*
- * @param int $group_id group_id of the group to be moved
- * @return null
+ * {@inheritDoc}
*/
public function move_up($group_id)
{
- $this->move($group_id, 1);
+ return $this->move($group_id, 1);
}
/**
* Moves a group down by group_id
*
- * @param int $group_id group_id of the group to be moved
- * @return null
+ * {@inheritDoc}
*/
public function move_down($group_id)
{
- $this->move($group_id, -1);
+ return $this->move($group_id, -1);
}
/**
* Moves a group up/down
*
- * @param int $group_id group_id of the group to be moved
- * @param int $delta number of steps:
- * - positive = move up
- * - negative = move down
- * @return null
+ * {@inheritDoc}
*/
public function move($group_id, $delta)
{
- if (!is_int($delta) || !$delta)
+ $delta = (int) $delta;
+ if (!$delta)
{
- return;
+ return false;
}
$move_up = ($delta > 0) ? true : false;
@@ -203,10 +196,10 @@ class phpbb_group_positions
// First we move all groups between our current value and the target value up/down 1,
// so we have a gap for our group to move.
$sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = group_' . $this->field . (($move_up) ? ' + 1' : ' - 1') . '
- WHERE group_' . $this->field . ' > ' . self::GROUP_DISABLED . '
- AND group_' . $this->field . (($move_up) ? ' >= ' : ' <= ') . ($current_value - $delta) . '
- AND group_' . $this->field . (($move_up) ? ' < ' : ' > ') . $current_value;
+ SET group_legend = group_legend' . (($move_up) ? ' + 1' : ' - 1') . '
+ WHERE group_legend > ' . self::GROUP_DISABLED . '
+ AND group_legend' . (($move_up) ? ' >= ' : ' <= ') . ($current_value - $delta) . '
+ AND group_legend' . (($move_up) ? ' < ' : ' > ') . $current_value;
$this->db->sql_query($sql);
// Because there might be fewer groups above/below the group than we wanted to move,
@@ -218,20 +211,26 @@ class phpbb_group_positions
// And now finally, when we moved some other groups and built a gap,
// we can move the desired group to it.
$sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = group_' . $this->field . (($move_up) ? ' - ' : ' + ') . $delta . '
+ SET group_legend = group_legend ' . (($move_up) ? ' - ' : ' + ') . $delta . '
WHERE group_id = ' . (int) $group_id;
$this->db->sql_query($sql);
+
+ $this->db->sql_transaction('commit');
+
+ return true;
}
$this->db->sql_transaction('commit');
}
+
+ return false;
}
/**
* Get group type language var
*
* @param int $group_type group_type from the groups-table
- * @return string name of the language variable for the given group-type.
+ * @return string name of the language variable for the given group-type.
*/
static public function group_type_language($group_type)
{
@@ -249,13 +248,4 @@ class phpbb_group_positions
return 'GROUP_OPEN';
}
}
-
- /**
- * Error
- */
- public function error($message)
- {
- global $user;
- trigger_error($user->lang[$message] . (($this->adm_back_link) ? adm_back_link($this->adm_back_link) : ''), E_USER_WARNING);
- }
}
diff --git a/phpBB/includes/groupposition/teampage.php b/phpBB/includes/groupposition/teampage.php
new file mode 100644
index 0000000000..7c758199e7
--- /dev/null
+++ b/phpBB/includes/groupposition/teampage.php
@@ -0,0 +1,604 @@
+db = $db;
+ $this->user = $user;
+ $this->cache = $cache;
+ }
+
+ /**
+ * Returns the teampage position for a given group, if the group exists.
+ *
+ * {@inheritDoc}
+ */
+ public function get_group_value($group_id)
+ {
+ // The join is required to ensure that the group itself exists
+ $sql = 'SELECT g.group_id, t.teampage_position
+ FROM ' . GROUPS_TABLE . ' g
+ LEFT JOIN ' . TEAMPAGE_TABLE . ' t
+ ON (t.group_id = g.group_id)
+ WHERE g.group_id = ' . (int) $group_id;
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if ($row === false)
+ {
+ // Group not found.
+ throw new phpbb_groupposition_exception('NO_GROUP');
+ }
+
+ return (int) $row['teampage_position'];
+ }
+
+ /**
+ * Returns the row for a given group, if the group exists.
+ *
+ * @param int $group_id group_id of the group to be selected
+ * @return array Data row of the group
+ */
+ public function get_group_values($group_id)
+ {
+ // The join is required to ensure that the group itself exists
+ $sql = 'SELECT *
+ FROM ' . GROUPS_TABLE . ' g
+ LEFT JOIN ' . TEAMPAGE_TABLE . ' t
+ ON (t.group_id = g.group_id)
+ WHERE g.group_id = ' . (int) $group_id;
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if ($row === false)
+ {
+ // Group not found.
+ throw new phpbb_groupposition_exception('NO_GROUP');
+ }
+
+ return $row;
+ }
+
+ /**
+ * Returns the teampage position for a given teampage item, if the item exists.
+ *
+ * @param int $teampage_id Teampage_id of the selected item
+ * @return int Teampage position of the item
+ */
+ public function get_teampage_value($teampage_id)
+ {
+ $sql = 'SELECT teampage_position
+ FROM ' . TEAMPAGE_TABLE . '
+ WHERE teampage_id = ' . (int) $teampage_id;
+ $result = $this->db->sql_query($sql);
+ $current_value = $this->db->sql_fetchfield('teampage_position');
+ $this->db->sql_freeresult($result);
+
+ if ($current_value === false)
+ {
+ // Group not found.
+ throw new phpbb_groupposition_exception('NO_GROUP');
+ }
+
+ return (int) $current_value;
+ }
+
+ /**
+ * Returns the teampage row for a given teampage item, if the item exists.
+ *
+ * @param int $teampage_id Teampage_id of the selected item
+ * @return array Teampage row of the item
+ */
+ public function get_teampage_values($teampage_id)
+ {
+ $sql = 'SELECT teampage_position, teampage_parent
+ FROM ' . TEAMPAGE_TABLE . '
+ WHERE teampage_id = ' . (int) $teampage_id;
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if ($row === false)
+ {
+ // Group not found.
+ throw new phpbb_groupposition_exception('NO_GROUP');
+ }
+
+ return $row;
+ }
+
+
+ /**
+ * Get number of items displayed
+ *
+ * {@inheritDoc}
+ */
+ public function get_group_count()
+ {
+ $sql = 'SELECT teampage_position
+ FROM ' . TEAMPAGE_TABLE . '
+ ORDER BY teampage_position DESC';
+ $result = $this->db->sql_query_limit($sql, 1);
+ $group_count = (int) $this->db->sql_fetchfield('teampage_position');
+ $this->db->sql_freeresult($result);
+
+ return $group_count;
+ }
+
+ /**
+ * Adds a group by group_id
+ *
+ * {@inheritDoc}
+ */
+ public function add_group($group_id)
+ {
+ return $this->add_group_teampage($group_id, self::NO_PARENT);
+ }
+
+ /**
+ * Adds a group by group_id
+ *
+ * @param int $group_id group_id of the group to be added
+ * @param int $parent_id Teampage ID of the parent item
+ * @return bool True if the group was added successfully
+ */
+ public function add_group_teampage($group_id, $parent_id)
+ {
+ $current_value = $this->get_group_value($group_id);
+
+ if ($current_value == self::GROUP_DISABLED)
+ {
+ if ($parent_id != self::NO_PARENT)
+ {
+ // Check, whether the given parent is a category
+ $sql = 'SELECT teampage_id
+ FROM ' . TEAMPAGE_TABLE . '
+ WHERE group_id = 0
+ AND teampage_id = ' . (int) $parent_id;
+ $result = $this->db->sql_query_limit($sql, 1);
+ $parent_is_category = (bool) $this->db->sql_fetchfield('teampage_id');
+ $this->db->sql_freeresult($result);
+
+ if ($parent_is_category)
+ {
+ // Get value of last child from this parent and add group there
+ $sql = 'SELECT teampage_position
+ FROM ' . TEAMPAGE_TABLE . '
+ WHERE teampage_parent = ' . (int) $parent_id . '
+ OR teampage_id = ' . (int) $parent_id . '
+ ORDER BY teampage_position DESC';
+ $result = $this->db->sql_query_limit($sql, 1);
+ $new_position = (int) $this->db->sql_fetchfield('teampage_position');
+ $this->db->sql_freeresult($result);
+
+ $sql = 'UPDATE ' . TEAMPAGE_TABLE . '
+ SET teampage_position = teampage_position + 1
+ WHERE teampage_position > ' . $new_position;
+ $this->db->sql_query($sql);
+ }
+ }
+ else
+ {
+ // Add group at the end
+ $new_position = $this->get_group_count();
+ }
+
+ $sql_ary = array(
+ 'group_id' => $group_id,
+ 'teampage_position' => $new_position + 1,
+ 'teampage_parent' => $parent_id,
+ );
+
+ $sql = 'INSERT INTO ' . TEAMPAGE_TABLE . ' ' . $this->db->sql_build_array('INSERT', $sql_ary);
+ $this->db->sql_query($sql);
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return true;
+ }
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return false;
+ }
+
+ /**
+ * Adds a new category
+ *
+ * @param string $category_name Name of the category to be added
+ * @return bool True if the category was added successfully
+ */
+ public function add_category_teampage($category_name)
+ {
+ if ($category_name === '')
+ {
+ return false;
+ }
+
+ $num_entries = $this->get_group_count();
+
+ $sql_ary = array(
+ 'group_id' => 0,
+ 'teampage_position' => $num_entries + 1,
+ 'teampage_parent' => 0,
+ 'teampage_name' => truncate_string($category_name, 255, 255),
+ );
+
+ $sql = 'INSERT INTO ' . TEAMPAGE_TABLE . ' ' . $this->db->sql_build_array('INSERT', $sql_ary);
+ $this->db->sql_query($sql);
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return true;
+ }
+
+ /**
+ * Deletes a group from the list and closes the gap in the position list.
+ *
+ * {@inheritDoc}
+ */
+ public function delete_group($group_id, $skip_group = false)
+ {
+ $current_value = $this->get_group_value($group_id);
+
+ if ($current_value != self::GROUP_DISABLED)
+ {
+ $sql = 'UPDATE ' . TEAMPAGE_TABLE . '
+ SET teampage_position = teampage_position - 1
+ WHERE teampage_position > ' . $current_value;
+ $this->db->sql_query($sql);
+
+ $sql = 'DELETE FROM ' . TEAMPAGE_TABLE . '
+ WHERE group_id = ' . $group_id;
+ $this->db->sql_query($sql);
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return true;
+ }
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return false;
+ }
+
+ /**
+ * Deletes an item from the list and closes the gap in the position list.
+ *
+ * @param int $teampage_id teampage_id of the item to be deleted
+ * @param bool $skip_group Skip setting the group to GROUP_DISABLED, to save the query, when you need to update it anyway.
+ * @return bool True if the item was deleted successfully
+ */
+ public function delete_teampage($teampage_id, $skip_group = false)
+ {
+ $current_value = $this->get_teampage_value($teampage_id);
+
+ if ($current_value != self::GROUP_DISABLED)
+ {
+ $sql = 'DELETE FROM ' . TEAMPAGE_TABLE . '
+ WHERE teampage_id = ' . $teampage_id . '
+ OR teampage_parent = ' . $teampage_id;
+ $this->db->sql_query($sql);
+
+ $delta = (int) $this->db->sql_affectedrows();
+
+ $sql = 'UPDATE ' . TEAMPAGE_TABLE . '
+ SET teampage_position = teampage_position - ' . $delta . '
+ WHERE teampage_position > ' . $current_value;
+ $this->db->sql_query($sql);
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return true;
+ }
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return false;
+ }
+
+ /**
+ * Moves a group up by group_id
+ *
+ * {@inheritDoc}
+ */
+ public function move_up($group_id)
+ {
+ return $this->move($group_id, 1);
+ }
+
+ /**
+ * Moves an item up by teampage_id
+ *
+ * @param int $group_id group_id of the group to be moved
+ * @return bool True if the group was moved successfully
+ */
+ public function move_up_teampage($teampage_id)
+ {
+ return $this->move_teampage($teampage_id, 1);
+ }
+
+ /**
+ * Moves a group down by group_id
+ *
+ * {@inheritDoc}
+ */
+ public function move_down($group_id)
+ {
+ return $this->move($group_id, -1);
+ }
+
+ /**
+ * Movesan item down by teampage_id
+ *
+ * @param int $group_id group_id of the group to be moved
+ * @return bool True if the group was moved successfully
+ */
+ public function move_down_teampage($teampage_id)
+ {
+ return $this->move_teampage($teampage_id, -1);
+ }
+
+ /**
+ * Moves a group up/down
+ *
+ * {@inheritDoc}
+ */
+ public function move($group_id, $delta)
+ {
+ $delta = (int) $delta;
+ if (!$delta)
+ {
+ return false;
+ }
+
+ $move_up = ($delta > 0) ? true : false;
+ $data = $this->get_group_values($group_id);
+
+ $current_value = (int) $data['teampage_position'];
+ if ($current_value != self::GROUP_DISABLED)
+ {
+ $this->db->sql_transaction('begin');
+
+ if (!$move_up && $data['teampage_parent'] == self::NO_PARENT)
+ {
+ // If we move items down, we need to grab the one sibling more,
+ // so we do not ignore the children of the previous sibling.
+ // We will remove the additional sibling later on.
+ $delta = abs($delta) + 1;
+ }
+
+ $sql = 'SELECT teampage_position
+ FROM ' . TEAMPAGE_TABLE . '
+ WHERE teampage_parent = ' . (int) $data['teampage_parent'] . '
+ AND teampage_position' . (($move_up) ? ' < ' : ' > ') . $current_value . '
+ ORDER BY teampage_position' . (($move_up) ? ' DESC' : ' ASC');
+ $result = $this->db->sql_query_limit($sql, $delta);
+
+ $sibling_count = 0;
+ $sibling_limit = $delta;
+
+ // Reset the delta, as we recalculate the new real delta
+ $delta = 0;
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $sibling_count++;
+ $delta = $current_value - $row['teampage_position'];
+
+ if (!$move_up && $data['teampage_parent'] == self::NO_PARENT && $sibling_count == $sibling_limit)
+ {
+ // Remove the additional sibling we added previously
+ $delta++;
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ if ($delta)
+ {
+ // First we move all items between our current value and the target value up/down 1,
+ // so we have a gap for our item to move.
+ $sql = 'UPDATE ' . TEAMPAGE_TABLE . '
+ SET teampage_position = teampage_position' . (($move_up) ? ' + 1' : ' - 1') . '
+ WHERE teampage_position' . (($move_up) ? ' >= ' : ' <= ') . ($current_value - $delta) . '
+ AND teampage_position' . (($move_up) ? ' < ' : ' > ') . $current_value;
+ $this->db->sql_query($sql);
+
+ // And now finally, when we moved some other items and built a gap,
+ // we can move the desired item to it.
+ $sql = 'UPDATE ' . TEAMPAGE_TABLE . '
+ SET teampage_position = teampage_position ' . (($move_up) ? ' - ' : ' + ') . abs($delta) . '
+ WHERE group_id = ' . (int) $group_id;
+ $this->db->sql_query($sql);
+
+ $this->db->sql_transaction('commit');
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+
+ return true;
+ }
+
+ $this->db->sql_transaction('commit');
+ }
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return false;
+ }
+
+ /**
+ * Moves an item up/down
+ *
+ * @param int $teampage_id teampage_id of the item to be moved
+ * @param int $delta number of steps:
+ * - positive = move up
+ * - negative = move down
+ * @return bool True if the group was moved successfully
+ */
+ public function move_teampage($teampage_id, $delta)
+ {
+ $delta = (int) $delta;
+ if (!$delta)
+ {
+ return false;
+ }
+
+ $move_up = ($delta > 0) ? true : false;
+ $data = $this->get_teampage_values($teampage_id);
+
+ $current_value = (int) $data['teampage_position'];
+ if ($current_value != self::GROUP_DISABLED)
+ {
+ $this->db->sql_transaction('begin');
+
+ if (!$move_up && $data['teampage_parent'] == self::NO_PARENT)
+ {
+ // If we move items down, we need to grab the one sibling more,
+ // so we do not ignore the children of the previous sibling.
+ // We will remove the additional sibling later on.
+ $delta = abs($delta) + 1;
+ }
+
+ $sql = 'SELECT teampage_id, teampage_position
+ FROM ' . TEAMPAGE_TABLE . '
+ WHERE teampage_parent = ' . (int) $data['teampage_parent'] . '
+ AND teampage_position' . (($move_up) ? ' < ' : ' > ') . $current_value . '
+ ORDER BY teampage_position' . (($move_up) ? ' DESC' : ' ASC');
+ $result = $this->db->sql_query_limit($sql, $delta);
+
+ $sibling_count = 0;
+ $sibling_limit = $delta;
+
+ // Reset the delta, as we recalculate the new real delta
+ $delta = 0;
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $sibling_count++;
+ $delta = $current_value - $row['teampage_position'];
+
+ // Remove the additional sibling we added previously
+ // But only, if we included it, this is not be the case
+ // when we reached the end of our list
+ if (!$move_up && $data['teampage_parent'] == self::NO_PARENT && $sibling_count == $sibling_limit)
+ {
+ $delta++;
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ if ($delta)
+ {
+ $sql = 'SELECT COUNT(teampage_id) as num_items
+ FROM ' . TEAMPAGE_TABLE . '
+ WHERE teampage_id = ' . (int) $teampage_id . '
+ OR teampage_parent = ' . (int) $teampage_id;
+ $result = $this->db->sql_query($sql);
+ $num_items = (int) $this->db->sql_fetchfield('num_items');
+ $this->db->sql_freeresult($result);
+
+ // First we move all items between our current value and the target value up/down 1,
+ // so we have a gap for our item to move.
+ $sql = 'UPDATE ' . TEAMPAGE_TABLE . '
+ SET teampage_position = teampage_position' . (($move_up) ? ' + ' : ' - ') . $num_items . '
+ WHERE teampage_position' . (($move_up) ? ' >= ' : ' <= ') . ($current_value - $delta) . '
+ AND teampage_position' . (($move_up) ? ' < ' : ' > ') . $current_value . '
+ AND NOT (teampage_id = ' . (int) $teampage_id . '
+ OR teampage_parent = ' . (int) $teampage_id . ')';
+ $this->db->sql_query($sql);
+
+ $delta = (!$move_up && $data['teampage_parent'] == self::NO_PARENT) ? (abs($delta) - ($num_items - 1)) : abs($delta);
+
+ // And now finally, when we moved some other items and built a gap,
+ // we can move the desired item to it.
+ $sql = 'UPDATE ' . TEAMPAGE_TABLE . '
+ SET teampage_position = teampage_position ' . (($move_up) ? ' - ' : ' + ') . $delta . '
+ WHERE teampage_id = ' . (int) $teampage_id . '
+ OR teampage_parent = ' . (int) $teampage_id;
+ $this->db->sql_query($sql);
+
+ $this->db->sql_transaction('commit');
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+
+ return true;
+ }
+
+ $this->db->sql_transaction('commit');
+ }
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return false;
+ }
+
+ /**
+ * Get group type language var
+ *
+ * @param int $group_type group_type from the groups-table
+ * @return string name of the language variable for the given group-type.
+ */
+ static public function group_type_language($group_type)
+ {
+ switch ($group_type)
+ {
+ case GROUP_OPEN:
+ return 'GROUP_REQUEST';
+ case GROUP_CLOSED:
+ return 'GROUP_CLOSED';
+ case GROUP_HIDDEN:
+ return 'GROUP_HIDDEN';
+ case GROUP_SPECIAL:
+ return 'GROUP_SPECIAL';
+ case GROUP_FREE:
+ return 'GROUP_OPEN';
+ }
+ }
+}
diff --git a/phpBB/includes/log/interface.php b/phpBB/includes/log/interface.php
new file mode 100644
index 0000000000..3b459c9bdf
--- /dev/null
+++ b/phpBB/includes/log/interface.php
@@ -0,0 +1,106 @@
+db = $db;
+ $this->user = $user;
+ $this->auth = $auth;
+ $this->dispatcher = $phpbb_dispatcher;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->phpbb_admin_path = $this->phpbb_root_path . $relative_admin_path;
+ $this->php_ext = $php_ext;
+ $this->log_table = $log_table;
+
+ /*
+ * IN_ADMIN is set after the session is created,
+ * so we need to take ADMIN_START into account as well, otherwise
+ * it will not work for the phpbb_log object we create in common.php
+ */
+ $this->set_is_admin((defined('ADMIN_START') && ADMIN_START) || (defined('IN_ADMIN') && IN_ADMIN));
+ $this->enable();
+ }
+
+ /**
+ * Set is_in_admin in order to return administrative user profile links
+ * in get_logs()
+ *
+ * @param bool $is_in_admin Are we called from within the acp?
+ * @return null
+ */
+ public function set_is_admin($is_in_admin)
+ {
+ $this->is_in_admin = (bool) $is_in_admin;
+ }
+
+ /**
+ * Returns the is_in_admin option
+ *
+ * @return bool
+ */
+ public function get_is_admin()
+ {
+ return $this->is_in_admin;
+ }
+
+ /**
+ * Set table name
+ *
+ * @param string $log_table Can overwrite the table to use for the logs
+ * @return null
+ */
+ public function set_log_table($log_table)
+ {
+ $this->log_table = $log_table;
+ }
+
+ /**
+ * This function returns the state of the log system.
+ *
+ * {@inheritDoc}
+ */
+ public function is_enabled($type = '')
+ {
+ if ($type == '' || $type == 'all')
+ {
+ return !isset($this->disabled_types['all']);
+ }
+ return !isset($this->disabled_types[$type]) && !isset($this->disabled_types['all']);
+ }
+
+ /**
+ * Disable log
+ *
+ * This function allows disabling the log system or parts of it, for this
+ * page call. When add_log is called and the type is disabled,
+ * the log will not be added to the database.
+ *
+ * {@inheritDoc}
+ */
+ public function disable($type = '')
+ {
+ if (is_array($type))
+ {
+ foreach ($type as $disable_type)
+ {
+ $this->disable($disable_type);
+ }
+ return;
+ }
+
+ // Empty string is an equivalent for all types.
+ if ($type == '')
+ {
+ $type = 'all';
+ }
+ $this->disabled_types[$type] = true;
+ }
+
+ /**
+ * Enable log
+ *
+ * This function allows re-enabling the log system.
+ *
+ * {@inheritDoc}
+ */
+ public function enable($type = '')
+ {
+ if (is_array($type))
+ {
+ foreach ($type as $enable_type)
+ {
+ $this->enable($enable_type);
+ }
+ return;
+ }
+
+ if ($type == '' || $type == 'all')
+ {
+ $this->disabled_types = array();
+ return;
+ }
+ unset($this->disabled_types[$type]);
+ }
+
+ /**
+ * Adds a log to the database
+ *
+ * {@inheritDoc}
+ */
+ public function add($mode, $user_id, $log_ip, $log_operation, $log_time = false, $additional_data = array())
+ {
+ if (!$this->is_enabled($mode))
+ {
+ return false;
+ }
+
+ if ($log_time == false)
+ {
+ $log_time = time();
+ }
+
+ $sql_ary = array(
+ 'user_id' => $user_id,
+ 'log_ip' => $log_ip,
+ 'log_time' => $log_time,
+ 'log_operation' => $log_operation,
+ );
+
+ switch ($mode)
+ {
+ case 'admin':
+ $sql_ary += array(
+ 'log_type' => LOG_ADMIN,
+ 'log_data' => (!empty($additional_data)) ? serialize($additional_data) : '',
+ );
+ break;
+
+ case 'mod':
+ $forum_id = (int) $additional_data['forum_id'];
+ unset($additional_data['forum_id']);
+ $topic_id = (int) $additional_data['topic_id'];
+ unset($additional_data['topic_id']);
+ $sql_ary += array(
+ 'log_type' => LOG_MOD,
+ 'forum_id' => $forum_id,
+ 'topic_id' => $topic_id,
+ 'log_data' => (!empty($additional_data)) ? serialize($additional_data) : '',
+ );
+ break;
+
+ case 'user':
+ $reportee_id = (int) $additional_data['reportee_id'];
+ unset($additional_data['reportee_id']);
+
+ $sql_ary += array(
+ 'log_type' => LOG_USERS,
+ 'reportee_id' => $reportee_id,
+ 'log_data' => (!empty($additional_data)) ? serialize($additional_data) : '',
+ );
+ break;
+
+ case 'critical':
+ $sql_ary += array(
+ 'log_type' => LOG_CRITICAL,
+ 'log_data' => (!empty($additional_data)) ? serialize($additional_data) : '',
+ );
+ break;
+ }
+
+ /**
+ * Allows to modify log data before we add it to the database
+ *
+ * NOTE: if sql_ary does not contain a log_type value, the entry will
+ * not be stored in the database. So ensure to set it, if needed.
+ *
+ * @event core.add_log
+ * @var string mode Mode of the entry we log
+ * @var int user_id ID of the user who triggered the log
+ * @var string log_ip IP of the user who triggered the log
+ * @var string log_operation Language key of the log operation
+ * @var int log_time Timestamp, when the log was added
+ * @var array additional_data Array with additional log data
+ * @var array sql_ary Array with log data we insert into the
+ * database. If sql_ary[log_type] is not set,
+ * we won't add the entry to the database.
+ * @since 3.1-A1
+ */
+ $vars = array('mode', 'user_id', 'log_ip', 'log_operation', 'log_time', 'additional_data', 'sql_ary');
+ extract($this->dispatcher->trigger_event('core.add_log', $vars));
+
+ // We didn't find a log_type, so we don't save it in the database.
+ if (!isset($sql_ary['log_type']))
+ {
+ return false;
+ }
+
+ $this->db->sql_query('INSERT INTO ' . $this->log_table . ' ' . $this->db->sql_build_array('INSERT', $sql_ary));
+
+ return $this->db->sql_nextid();
+ }
+
+ /**
+ * Grab the logs from the database
+ *
+ * {@inheritDoc}
+ */
+ public function get_logs($mode, $count_logs = true, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $log_time = 0, $sort_by = 'l.log_time DESC', $keywords = '')
+ {
+ $this->entry_count = 0;
+ $this->last_page_offset = $offset;
+
+ $topic_id_list = $reportee_id_list = array();
+
+ $profile_url = ($this->get_is_admin() && $this->phpbb_admin_path) ? append_sid("{$this->phpbb_admin_path}index.{$this->php_ext}", 'i=users&mode=overview') : append_sid("{$this->phpbb_root_path}memberlist.{$this->php_ext}", 'mode=viewprofile');
+
+ switch ($mode)
+ {
+ case 'admin':
+ $log_type = LOG_ADMIN;
+ $sql_additional = '';
+ break;
+
+ case 'mod':
+ $log_type = LOG_MOD;
+ $sql_additional = '';
+
+ if ($topic_id)
+ {
+ $sql_additional = 'AND l.topic_id = ' . (int) $topic_id;
+ }
+ else if (is_array($forum_id))
+ {
+ $sql_additional = 'AND ' . $this->db->sql_in_set('l.forum_id', array_map('intval', $forum_id));
+ }
+ else if ($forum_id)
+ {
+ $sql_additional = 'AND l.forum_id = ' . (int) $forum_id;
+ }
+ break;
+
+ case 'user':
+ $log_type = LOG_USERS;
+ $sql_additional = 'AND l.reportee_id = ' . (int) $user_id;
+ break;
+
+ case 'users':
+ $log_type = LOG_USERS;
+ $sql_additional = '';
+ break;
+
+ case 'critical':
+ $log_type = LOG_CRITICAL;
+ $sql_additional = '';
+ break;
+
+ default:
+ $log_type = false;
+ $sql_additional = '';
+ }
+
+ /**
+ * Overwrite log type and limitations before we count and get the logs
+ *
+ * NOTE: if log_type is false, no entries will be returned.
+ *
+ * @event core.get_logs_modify_type
+ * @var string mode Mode of the entries we display
+ * @var bool count_logs Do we count all matching entries?
+ * @var int limit Limit the number of entries
+ * @var int offset Offset when fetching the entries
+ * @var mixed forum_id Limit entries to the forum_id,
+ * can also be an array of forum_ids
+ * @var int topic_id Limit entries to the topic_id
+ * @var int user_id Limit entries to the user_id
+ * @var int log_time Limit maximum age of log entries
+ * @var string sort_by SQL order option
+ * @var string keywords Will only return entries that have the
+ * keywords in log_operation or log_data
+ * @var string profile_url URL to the users profile
+ * @var int log_type Limit logs to a certain type. If log_type
+ * is false, no entries will be returned.
+ * @var string sql_additional Additional conditions for the entries,
+ * e.g.: 'AND l.forum_id = 1'
+ * @since 3.1-A1
+ */
+ $vars = array('mode', 'count_logs', 'limit', 'offset', 'forum_id', 'topic_id', 'user_id', 'log_time', 'sort_by', 'keywords', 'profile_url', 'log_type', 'sql_additional');
+ extract($this->dispatcher->trigger_event('core.get_logs_modify_type', $vars));
+
+ if ($log_type === false)
+ {
+ $this->last_page_offset = 0;
+ return array();
+ }
+
+ $sql_keywords = '';
+ if (!empty($keywords))
+ {
+ // Get the SQL condition for our keywords
+ $sql_keywords = $this->generate_sql_keyword($keywords);
+ }
+
+ if ($count_logs)
+ {
+ $sql = 'SELECT COUNT(l.log_id) AS total_entries
+ FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . ' u
+ WHERE l.log_type = ' . (int) $log_type . '
+ AND l.user_id = u.user_id
+ AND l.log_time >= ' . (int) $log_time . "
+ $sql_keywords
+ $sql_additional";
+ $result = $this->db->sql_query($sql);
+ $this->entry_count = (int) $this->db->sql_fetchfield('total_entries');
+ $this->db->sql_freeresult($result);
+
+ if ($this->entry_count == 0)
+ {
+ // Save the queries, because there are no logs to display
+ $this->last_page_offset = 0;
+ return array();
+ }
+
+ // Return the user to the last page that is valid
+ while ($this->last_page_offset >= $this->entry_count)
+ {
+ $this->last_page_offset = max(0, $this->last_page_offset - $limit);
+ }
+ }
+
+ $sql = 'SELECT l.*, u.username, u.username_clean, u.user_colour
+ FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . ' u
+ WHERE l.log_type = ' . (int) $log_type . '
+ AND u.user_id = l.user_id
+ ' . (($log_time) ? 'AND l.log_time >= ' . (int) $log_time : '') . "
+ $sql_keywords
+ $sql_additional
+ ORDER BY $sort_by";
+ $result = $this->db->sql_query_limit($sql, $limit, $this->last_page_offset);
+
+ $i = 0;
+ $log = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $row['forum_id'] = (int) $row['forum_id'];
+ if ($row['topic_id'])
+ {
+ $topic_id_list[] = (int) $row['topic_id'];
+ }
+
+ if ($row['reportee_id'])
+ {
+ $reportee_id_list[] = (int) $row['reportee_id'];
+ }
+
+ $log_entry_data = array(
+ 'id' => (int) $row['log_id'],
+
+ 'reportee_id' => (int) $row['reportee_id'],
+ 'reportee_username' => '',
+ 'reportee_username_full'=> '',
+
+ 'user_id' => (int) $row['user_id'],
+ 'username' => $row['username'],
+ 'username_full' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url),
+
+ 'ip' => $row['log_ip'],
+ 'time' => (int) $row['log_time'],
+ 'forum_id' => (int) $row['forum_id'],
+ 'topic_id' => (int) $row['topic_id'],
+
+ 'viewforum' => ($row['forum_id'] && $this->auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$this->phpbb_root_path}viewforum.{$this->php_ext}", 'f=' . $row['forum_id']) : false,
+ 'action' => (isset($this->user->lang[$row['log_operation']])) ? $this->user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}',
+ );
+
+ /**
+ * Modify the entry's data before it is returned
+ *
+ * @event core.get_logs_modify_entry_data
+ * @var array row Entry data from the database
+ * @var array log_entry_data Entry's data which is returned
+ * @since 3.1-A1
+ */
+ $vars = array('row', 'log_entry_data');
+ extract($this->dispatcher->trigger_event('core.get_logs_modify_entry_data', $vars));
+
+ $log[$i] = $log_entry_data;
+
+ if (!empty($row['log_data']))
+ {
+ $log_data_ary = unserialize($row['log_data']);
+ $log_data_ary = ($log_data_ary !== false) ? $log_data_ary : array();
+
+ if (isset($this->user->lang[$row['log_operation']]))
+ {
+ // Check if there are more occurrences of % than
+ // arguments, if there are we fill out the arguments
+ // array. It doesn't matter if we add more arguments than
+ // placeholders.
+ if ((substr_count($log[$i]['action'], '%') - sizeof($log_data_ary)) > 0)
+ {
+ $log_data_ary = array_merge($log_data_ary, array_fill(0, substr_count($log[$i]['action'], '%') - sizeof($log_data_ary), ''));
+ }
+
+ $log[$i]['action'] = vsprintf($log[$i]['action'], $log_data_ary);
+
+ // If within the admin panel we do not censor text out
+ if ($this->get_is_admin())
+ {
+ $log[$i]['action'] = bbcode_nl2br($log[$i]['action']);
+ }
+ else
+ {
+ $log[$i]['action'] = bbcode_nl2br(censor_text($log[$i]['action']));
+ }
+ }
+ else if (!empty($log_data_ary))
+ {
+ $log[$i]['action'] .= ' ' . implode('', $log_data_ary);
+ }
+
+ /* Apply make_clickable... has to be seen if it is for good. :/
+ // Seems to be not for the moment, reconsider later...
+ $log[$i]['action'] = make_clickable($log[$i]['action']);
+ */
+ }
+
+ $i++;
+ }
+ $this->db->sql_freeresult($result);
+
+ /**
+ * Get some additional data after we got all log entries
+ *
+ * @event core.get_logs_get_additional_data
+ * @var array log Array with all our log entries
+ * @var array topic_id_list Array of topic ids, for which we
+ * get the permission data
+ * @var array reportee_id_list Array of additional user IDs we
+ * get the username strings for
+ * @since 3.1-A1
+ */
+ $vars = array('log', 'topic_id_list', 'reportee_id_list');
+ extract($this->dispatcher->trigger_event('core.get_logs_get_additional_data', $vars));
+
+ if (sizeof($topic_id_list))
+ {
+ $topic_auth = $this->get_topic_auth($topic_id_list);
+
+ foreach ($log as $key => $row)
+ {
+ $log[$key]['viewtopic'] = (isset($topic_auth['f_read'][$row['topic_id']])) ? append_sid("{$this->phpbb_root_path}viewtopic.{$this->php_ext}", 'f=' . $topic_auth['f_read'][$row['topic_id']] . '&t=' . $row['topic_id']) : false;
+ $log[$key]['viewlogs'] = (isset($topic_auth['m_'][$row['topic_id']])) ? append_sid("{$this->phpbb_root_path}mcp.{$this->php_ext}", 'i=logs&mode=topic_logs&t=' . $row['topic_id'], true, $this->user->session_id) : false;
+ }
+ }
+
+ if (sizeof($reportee_id_list))
+ {
+ $reportee_data_list = $this->get_reportee_data($reportee_id_list);
+
+ foreach ($log as $key => $row)
+ {
+ if (!isset($reportee_data_list[$row['reportee_id']]))
+ {
+ continue;
+ }
+
+ $log[$key]['reportee_username'] = $reportee_data_list[$row['reportee_id']]['username'];
+ $log[$key]['reportee_username_full'] = get_username_string('full', $row['reportee_id'], $reportee_data_list[$row['reportee_id']]['username'], $reportee_data_list[$row['reportee_id']]['user_colour'], false, $profile_url);
+ }
+ }
+
+ return $log;
+ }
+
+ /**
+ * Generates a sql condition for the specified keywords
+ *
+ * @param string $keywords The keywords the user specified to search for
+ *
+ * @return string Returns the SQL condition searching for the keywords
+ */
+ protected function generate_sql_keyword($keywords)
+ {
+ // Use no preg_quote for $keywords because this would lead to sole
+ // backslashes being added. We also use an OR connection here for
+ // spaces and the | string. Currently, regex is not supported for
+ // searching (but may come later).
+ $keywords = preg_split('#[\s|]+#u', utf8_strtolower($keywords), 0, PREG_SPLIT_NO_EMPTY);
+ $sql_keywords = '';
+
+ if (!empty($keywords))
+ {
+ $keywords_pattern = array();
+
+ // Build pattern and keywords...
+ for ($i = 0, $num_keywords = sizeof($keywords); $i < $num_keywords; $i++)
+ {
+ $keywords_pattern[] = preg_quote($keywords[$i], '#');
+ $keywords[$i] = $this->db->sql_like_expression($this->db->any_char . $keywords[$i] . $this->db->any_char);
+ }
+
+ $keywords_pattern = '#' . implode('|', $keywords_pattern) . '#ui';
+
+ $operations = array();
+ foreach ($this->user->lang as $key => $value)
+ {
+ if (substr($key, 0, 4) == 'LOG_' && preg_match($keywords_pattern, $value))
+ {
+ $operations[] = $key;
+ }
+ }
+
+ $sql_keywords = 'AND (';
+ if (!empty($operations))
+ {
+ $sql_keywords .= $this->db->sql_in_set('l.log_operation', $operations) . ' OR ';
+ }
+ $sql_lower = $this->db->sql_lower_text('l.log_data');
+ $sql_keywords .= " $sql_lower " . implode(" OR $sql_lower ", $keywords) . ')';
+ }
+
+ return $sql_keywords;
+ }
+
+ /**
+ * Determine whether the user is allowed to read and/or moderate the forum of the topic
+ *
+ * @param array $topic_ids Array with the topic ids
+ *
+ * @return array Returns an array with two keys 'm_' and 'read_f' which are also an array of topic_id => forum_id sets when the permissions are given. Sample:
+ * array(
+ * 'permission' => array(
+ * topic_id => forum_id
+ * ),
+ * ),
+ */
+ protected function get_topic_auth(array $topic_ids)
+ {
+ $forum_auth = array('f_read' => array(), 'm_' => array());
+ $topic_ids = array_unique($topic_ids);
+
+ $sql = 'SELECT topic_id, forum_id
+ FROM ' . TOPICS_TABLE . '
+ WHERE ' . $this->db->sql_in_set('topic_id', array_map('intval', $topic_ids));
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $row['topic_id'] = (int) $row['topic_id'];
+ $row['forum_id'] = (int) $row['forum_id'];
+
+ if ($this->auth->acl_get('f_read', $row['forum_id']))
+ {
+ $forum_auth['f_read'][$row['topic_id']] = $row['forum_id'];
+ }
+
+ if ($this->auth->acl_gets('a_', 'm_', $row['forum_id']))
+ {
+ $forum_auth['m_'][$row['topic_id']] = $row['forum_id'];
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ return $forum_auth;
+ }
+
+ /**
+ * Get the data for all reportee from the database
+ *
+ * @param array $reportee_ids Array with the user ids of the reportees
+ *
+ * @return array Returns an array with the reportee data
+ */
+ protected function get_reportee_data(array $reportee_ids)
+ {
+ $reportee_ids = array_unique($reportee_ids);
+ $reportee_data_list = array();
+
+ $sql = 'SELECT user_id, username, user_colour
+ FROM ' . USERS_TABLE . '
+ WHERE ' . $this->db->sql_in_set('user_id', $reportee_ids);
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $reportee_data_list[$row['user_id']] = $row;
+ }
+ $this->db->sql_freeresult($result);
+
+ return $reportee_data_list;
+ }
+
+ /**
+ * Get total log count
+ *
+ * {@inheritDoc}
+ */
+ public function get_log_count()
+ {
+ return ($this->entry_count) ? $this->entry_count : 0;
+ }
+
+ /**
+ * Get offset of the last valid log page
+ *
+ * {@inheritDoc}
+ */
+ public function get_valid_offset()
+ {
+ return ($this->last_page_offset) ? $this->last_page_offset : 0;
+ }
+}
diff --git a/phpBB/includes/mcp/mcp_notes.php b/phpBB/includes/mcp/mcp_notes.php
index 59cdf3c27e..12fcbfe91e 100644
--- a/phpBB/includes/mcp/mcp_notes.php
+++ b/phpBB/includes/mcp/mcp_notes.php
@@ -173,13 +173,13 @@ class mcp_notes
}
// Generate the appropriate user information for the user we are looking at
- if (!function_exists('get_user_avatar'))
+ if (!function_exists('phpbb_get_user_avatar'))
{
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
$rank_title = $rank_img = '';
- $avatar_img = get_user_avatar($userrow['user_avatar'], $userrow['user_avatar_type'], $userrow['user_avatar_width'], $userrow['user_avatar_height']);
+ $avatar_img = phpbb_get_user_avatar($userrow);
$limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('a' => $user->lang['SORT_USERNAME'], 'b' => $user->lang['SORT_DATE'], 'c' => $user->lang['SORT_IP'], 'd' => $user->lang['SORT_ACTION']);
diff --git a/phpBB/includes/mcp/mcp_pm_reports.php b/phpBB/includes/mcp/mcp_pm_reports.php
index 86650947c7..99ff397a66 100644
--- a/phpBB/includes/mcp/mcp_pm_reports.php
+++ b/phpBB/includes/mcp/mcp_pm_reports.php
@@ -33,7 +33,7 @@ class mcp_pm_reports
function main($id, $mode)
{
global $auth, $db, $user, $template, $cache;
- global $config, $phpbb_root_path, $phpEx, $action;
+ global $config, $phpbb_root_path, $phpEx, $action, $phpbb_container;
include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
include_once($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx);
@@ -89,6 +89,10 @@ class mcp_pm_reports
trigger_error('NO_REPORT');
}
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $phpbb_notifications->mark_notifications_read_by_parent('report_pm', $report_id, $user->data['user_id']);
+
$pm_id = $report['pm_id'];
$report_id = $report['report_id'];
diff --git a/phpBB/includes/mcp/mcp_queue.php b/phpBB/includes/mcp/mcp_queue.php
index 0b195aa9d8..24afa1f210 100644
--- a/phpBB/includes/mcp/mcp_queue.php
+++ b/phpBB/includes/mcp/mcp_queue.php
@@ -33,7 +33,7 @@ class mcp_queue
function main($id, $mode)
{
global $auth, $db, $user, $template, $cache;
- global $config, $phpbb_root_path, $phpEx, $action;
+ global $config, $phpbb_root_path, $phpEx, $action, $phpbb_container;
include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
@@ -78,12 +78,16 @@ class mcp_queue
$post_id = request_var('p', 0);
$topic_id = request_var('t', 0);
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
if ($topic_id)
{
$topic_info = get_topic_data(array($topic_id), 'm_approve');
if (isset($topic_info[$topic_id]['topic_first_post_id']))
{
$post_id = (int) $topic_info[$topic_id]['topic_first_post_id'];
+
+ $phpbb_notifications->mark_notifications_read('topic_in_queue', $topic_id, $user->data['user_id']);
}
else
{
@@ -91,6 +95,8 @@ class mcp_queue
}
}
+ $phpbb_notifications->mark_notifications_read('post_in_queue', $post_id, $user->data['user_id']);
+
$post_info = get_post_data(array($post_id), 'm_approve', true);
if (!sizeof($post_info))
@@ -451,7 +457,7 @@ function approve_post($post_id_list, $id, $mode)
{
global $db, $template, $user, $config;
global $phpEx, $phpbb_root_path;
- global $request;
+ global $request, $phpbb_container;
if (!check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_approve')))
{
@@ -597,54 +603,51 @@ function approve_post($post_id_list, $id, $mode)
sync('forum', 'forum_id', array_keys($forum_id_list), true, true);
unset($topic_id_list, $forum_id_list);
- $messenger = new messenger();
-
- // Notify Poster?
- if ($notify_poster)
- {
- foreach ($post_info as $post_id => $post_data)
- {
- if ($post_data['poster_id'] == ANONYMOUS)
- {
- continue;
- }
-
- $email_template = ($post_data['post_id'] == $post_data['topic_first_post_id'] && $post_data['post_id'] == $post_data['topic_last_post_id']) ? 'topic_approved' : 'post_approved';
-
- $messenger->template($email_template, $post_data['user_lang']);
-
- $messenger->to($post_data['user_email'], $post_data['username']);
- $messenger->im($post_data['user_jabber'], $post_data['username']);
-
- $messenger->assign_vars(array(
- 'USERNAME' => htmlspecialchars_decode($post_data['username']),
- 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($post_data['post_subject'])),
- 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($post_data['topic_title'])),
-
- 'U_VIEW_TOPIC' => generate_board_url() . "/viewtopic.$phpEx?f={$post_data['forum_id']}&t={$post_data['topic_id']}&e=0",
- 'U_VIEW_POST' => generate_board_url() . "/viewtopic.$phpEx?f={$post_data['forum_id']}&t={$post_data['topic_id']}&p=$post_id&e=$post_id")
- );
-
- $messenger->send($post_data['user_notify_type']);
- }
- }
-
- $messenger->save_queue();
-
// Send out normal user notifications
$email_sig = str_replace(' ', "\n", "-- \n" . $config['board_email_sig']);
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ // Handle notifications
foreach ($post_info as $post_id => $post_data)
{
if ($post_id == $post_data['topic_first_post_id'] && $post_id == $post_data['topic_last_post_id'])
{
- // Forum Notifications
- user_notification('post', $post_data['topic_title'], $post_data['topic_title'], $post_data['forum_name'], $post_data['forum_id'], $post_data['topic_id'], $post_id);
+ $phpbb_notifications->delete_notifications('topic_in_queue', $post_data['topic_id']);
+
+ $phpbb_notifications->add_notifications(array(
+ 'quote',
+ 'topic',
+ ), $post_data);
+
+ $phpbb_notifications->mark_notifications_read('quote', $post_data['post_id'], $user->data['user_id']);
+ $phpbb_notifications->mark_notifications_read('topic', $post_data['topic_id'], $user->data['user_id']);
+
+ if ($notify_poster)
+ {
+ $phpbb_notifications->add_notifications('approve_topic', $post_data);
+ }
}
else
{
- // Topic Notifications
- user_notification('reply', $post_data['post_subject'], $post_data['topic_title'], $post_data['forum_name'], $post_data['forum_id'], $post_data['topic_id'], $post_id);
+ $phpbb_notifications->delete_notifications('post_in_queue', $post_id);
+
+ $phpbb_notifications->add_notifications(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ ), $post_data);
+
+ $phpbb_notifications->mark_notifications_read(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ ),$post_data['post_id'], $user->data['user_id']);
+
+ if ($notify_poster)
+ {
+ $phpbb_notifications->add_notifications('approve_post', $post_data);
+ }
}
}
@@ -734,7 +737,7 @@ function disapprove_post($post_id_list, $id, $mode)
{
global $db, $template, $user, $config;
global $phpEx, $phpbb_root_path;
- global $request;
+ global $request, $phpbb_container;
if (!check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_approve')))
{
@@ -867,20 +870,29 @@ function disapprove_post($post_id_list, $id, $mode)
}
}
- $messenger = new messenger();
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ foreach ($post_info as $post_id => $post_data)
+ {
+ if ($post_id == $post_data['topic_first_post_id'] && $post_id == $post_data['topic_last_post_id'])
+ {
+ $phpbb_notifications->delete_notifications('topic_in_queue', $post_data['topic_id']);
+ }
+ else
+ {
+ $phpbb_notifications->delete_notifications('post_in_queue', $post_id);
+ }
+ }
// Notify Poster?
if ($notify_poster)
{
$lang_reasons = array();
+ // Handle notifications
foreach ($post_info as $post_id => $post_data)
{
- if ($post_data['poster_id'] == ANONYMOUS)
- {
- continue;
- }
-
+ $post_data['disapprove_reason'] = '';
if (isset($disapprove_reason_lang))
{
// Okay we need to get the reason from the posters language
@@ -906,33 +918,30 @@ function disapprove_post($post_id_list, $id, $mode)
}
}
- $email_disapprove_reason = $lang_reasons[$post_data['user_lang']];
- $email_disapprove_reason .= ($reason) ? "\n\n" . $reason : '';
+ $post_data['disapprove_reason'] = $lang_reasons[$post_data['user_lang']];
+ $post_data['disapprove_reason'] .= ($reason) ? "\n\n" . $reason : '';
}
- $email_template = ($post_data['post_id'] == $post_data['topic_first_post_id'] && $post_data['post_id'] == $post_data['topic_last_post_id']) ? 'topic_disapproved' : 'post_disapproved';
-
- $messenger->template($email_template, $post_data['user_lang']);
-
- $messenger->to($post_data['user_email'], $post_data['username']);
- $messenger->im($post_data['user_jabber'], $post_data['username']);
-
- $messenger->assign_vars(array(
- 'USERNAME' => htmlspecialchars_decode($post_data['username']),
- 'REASON' => htmlspecialchars_decode($email_disapprove_reason),
- 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($post_data['post_subject'])),
- 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($post_data['topic_title'])))
- );
-
- $messenger->send($post_data['user_notify_type']);
+ if ($post_id == $post_data['topic_first_post_id'] && $post_id == $post_data['topic_last_post_id'])
+ {
+ if ($notify_poster)
+ {
+ $phpbb_notifications->add_notifications('disapprove_topic', $post_data);
+ }
+ }
+ else
+ {
+ if ($notify_poster)
+ {
+ $phpbb_notifications->add_notifications('disapprove_post', $post_data);
+ }
+ }
}
unset($lang_reasons);
}
unset($post_info, $disapprove_reason, $email_disapprove_reason, $disapprove_reason_lang);
- $messenger->save_queue();
-
if ($num_disapproved_topics)
{
$success_msg = ($num_disapproved_topics == 1) ? 'TOPIC_DISAPPROVED_SUCCESS' : 'TOPICS_DISAPPROVED_SUCCESS';
diff --git a/phpBB/includes/mcp/mcp_reports.php b/phpBB/includes/mcp/mcp_reports.php
index 8da303f6e3..0a600d7057 100644
--- a/phpBB/includes/mcp/mcp_reports.php
+++ b/phpBB/includes/mcp/mcp_reports.php
@@ -33,7 +33,7 @@ class mcp_reports
function main($id, $mode)
{
global $auth, $db, $user, $template, $cache;
- global $config, $phpbb_root_path, $phpEx, $action;
+ global $config, $phpbb_root_path, $phpEx, $action, $phpbb_container;
include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
@@ -87,6 +87,10 @@ class mcp_reports
trigger_error('NO_REPORT');
}
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $phpbb_notifications->mark_notifications_read('report_post', $post_id, $user->data['user_id']);
+
if (!$report_id && $report['report_closed'])
{
trigger_error('REPORT_CLOSED');
@@ -436,7 +440,7 @@ class mcp_reports
function close_report($report_id_list, $mode, $action, $pm = false)
{
global $db, $template, $user, $config, $auth;
- global $phpEx, $phpbb_root_path;
+ global $phpEx, $phpbb_root_path, $phpbb_container;
$pm_where = ($pm) ? ' AND r.post_id = 0 ' : ' AND r.pm_id = 0 ';
$id_column = ($pm) ? 'pm_id' : 'post_id';
@@ -622,11 +626,11 @@ function close_report($report_id_list, $mode, $action, $pm = false)
}
}
- $messenger = new messenger();
-
// Notify reporters
if (sizeof($notify_reporters))
{
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
foreach ($notify_reporters as $report_id => $reporter)
{
if ($reporter['user_id'] == ANONYMOUS)
@@ -636,30 +640,25 @@ function close_report($report_id_list, $mode, $action, $pm = false)
$post_id = $reporter[$id_column];
- $messenger->template((($pm) ? 'pm_report_' : 'report_') . $action . 'd', $reporter['user_lang']);
-
- $messenger->to($reporter['user_email'], $reporter['username']);
- $messenger->im($reporter['user_jabber'], $reporter['username']);
-
if ($pm)
{
- $messenger->assign_vars(array(
- 'USERNAME' => htmlspecialchars_decode($reporter['username']),
- 'CLOSER_NAME' => htmlspecialchars_decode($user->data['username']),
- 'PM_SUBJECT' => htmlspecialchars_decode(censor_text($post_info[$post_id]['message_subject'])),
- ));
+ $phpbb_notifications->add_notifications('report_pm_closed', array_merge($post_info[$post_id], array(
+ 'reporter' => $reporter['user_id'],
+ 'closer_id' => $user->data['user_id'],
+ 'from_user_id' => $post_info[$post_id]['author_id'],
+ )));
+
+ $phpbb_notifications->delete_notifications('report_pm', $post_id);
}
else
{
- $messenger->assign_vars(array(
- 'USERNAME' => htmlspecialchars_decode($reporter['username']),
- 'CLOSER_NAME' => htmlspecialchars_decode($user->data['username']),
- 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($post_info[$post_id]['post_subject'])),
- 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($post_info[$post_id]['topic_title'])))
- );
- }
+ $phpbb_notifications->add_notifications('report_post_closed', array_merge($post_info[$post_id], array(
+ 'reporter' => $reporter['user_id'],
+ 'closer_id' => $user->data['user_id'],
+ )));
- $messenger->send($reporter['user_notify_type']);
+ $phpbb_notifications->delete_notifications('report_post', $post_id);
+ }
}
}
@@ -674,8 +673,6 @@ function close_report($report_id_list, $mode, $action, $pm = false)
unset($notify_reporters, $post_info, $reports);
- $messenger->save_queue();
-
$success_msg = (sizeof($report_id_list) == 1) ? "{$pm_prefix}REPORT_" . strtoupper($action) . 'D_SUCCESS' : "{$pm_prefix}REPORTS_" . strtoupper($action) . 'D_SUCCESS';
}
else
diff --git a/phpBB/includes/mcp/mcp_warn.php b/phpBB/includes/mcp/mcp_warn.php
index 6a8fb4c5d5..4ef477775d 100644
--- a/phpBB/includes/mcp/mcp_warn.php
+++ b/phpBB/includes/mcp/mcp_warn.php
@@ -304,13 +304,13 @@ class mcp_warn
$message = smiley_text($message);
// Generate the appropriate user information for the user we are looking at
- if (!function_exists('get_user_avatar'))
+ if (!function_exists('phpbb_get_user_avatar'))
{
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
get_user_rank($user_row['user_rank'], $user_row['user_posts'], $rank_title, $rank_img, $rank_img_src);
- $avatar_img = get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height']);
+ $avatar_img = phpbb_get_user_avatar($user_row);
$template->assign_vars(array(
'U_POST_ACTION' => $this->u_action,
@@ -409,13 +409,13 @@ class mcp_warn
}
// Generate the appropriate user information for the user we are looking at
- if (!function_exists('get_user_avatar'))
+ if (!function_exists('phpbb_get_user_avatar'))
{
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
get_user_rank($user_row['user_rank'], $user_row['user_posts'], $rank_title, $rank_img, $rank_img_src);
- $avatar_img = get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height']);
+ $avatar_img = phpbb_get_user_avatar($user_row);
// OK, they didn't submit a warning so lets build the page for them to do so
$template->assign_vars(array(
diff --git a/phpBB/includes/notification/manager.php b/phpBB/includes/notification/manager.php
new file mode 100644
index 0000000000..ff83d4bb37
--- /dev/null
+++ b/phpBB/includes/notification/manager.php
@@ -0,0 +1,853 @@
+notification_types = $notification_types;
+ $this->notification_methods = $notification_methods;
+ $this->phpbb_container = $phpbb_container;
+
+ $this->user_loader = $user_loader;
+ $this->db = $db;
+ $this->user = $user;
+
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ $this->notification_types_table = $notification_types_table;
+ $this->notifications_table = $notifications_table;
+ $this->user_notifications_table = $user_notifications_table;
+ }
+
+ /**
+ * Load the user's notifications
+ *
+ * @param array $options Optional options to control what notifications are loaded
+ * notification_id Notification id to load (or array of notification ids)
+ * user_id User id to load notifications for (Default: $user->data['user_id'])
+ * order_by Order by (Default: notification_time)
+ * order_dir Order direction (Default: DESC)
+ * limit Number of notifications to load (Default: 5)
+ * start Notifications offset (Default: 0)
+ * all_unread Load all unread notifications? If set to true, count_unread is set to true (Default: false)
+ * count_unread Count all unread notifications? (Default: false)
+ * count_total Count all notifications? (Default: false)
+ * @return array Array of information based on the request with keys:
+ * 'notifications' array of notification type objects
+ * 'unread_count' number of unread notifications the user has if count_unread is true in the options
+ * 'total_count' number of notifications the user has if count_total is true in the options
+ */
+ public function load_notifications(array $options = array())
+ {
+ // Merge default options
+ $options = array_merge(array(
+ 'notification_id' => false,
+ 'user_id' => $this->user->data['user_id'],
+ 'order_by' => 'notification_time',
+ 'order_dir' => 'DESC',
+ 'limit' => 0,
+ 'start' => 0,
+ 'all_unread' => false,
+ 'count_unread' => false,
+ 'count_total' => false,
+ ), $options);
+
+ // If all_unread, count_unread must be true
+ $options['count_unread'] = ($options['all_unread']) ? true : $options['count_unread'];
+
+ // Anonymous users and bots never receive notifications
+ if ($options['user_id'] == $this->user->data['user_id'] && ($this->user->data['user_id'] == ANONYMOUS || $this->user->data['user_type'] == USER_IGNORE))
+ {
+ return array(
+ 'notifications' => array(),
+ 'unread_count' => 0,
+ 'total_count' => 0,
+ );
+ }
+
+ $notifications = $user_ids = array();
+ $load_special = array();
+ $total_count = $unread_count = 0;
+
+ if ($options['count_unread'])
+ {
+ // Get the total number of unread notifications
+ $sql = 'SELECT COUNT(n.notification_id) AS unread_count
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
+ WHERE n.user_id = ' . (int) $options['user_id'] . '
+ AND n.notification_read = 0
+ AND nt.notification_type = n.item_type
+ AND nt.notification_type_enabled = 1';
+ $result = $this->db->sql_query($sql);
+ $unread_count = (int) $this->db->sql_fetchfield('unread_count', $result);
+ $this->db->sql_freeresult($result);
+ }
+
+ if ($options['count_total'])
+ {
+ // Get the total number of notifications
+ $sql = 'SELECT COUNT(n.notification_id) AS total_count
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
+ WHERE n.user_id = ' . (int) $options['user_id'] . '
+ AND nt.notification_type = n.item_type
+ AND nt.notification_type_enabled = 1';
+ $result = $this->db->sql_query($sql);
+ $total_count = (int) $this->db->sql_fetchfield('total_count', $result);
+ $this->db->sql_freeresult($result);
+ }
+
+ if (!$options['count_total'] || $total_count)
+ {
+ $rowset = array();
+
+ // Get the main notifications
+ $sql = 'SELECT n.*
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
+ WHERE n.user_id = ' . (int) $options['user_id'] .
+ (($options['notification_id']) ? ((is_array($options['notification_id'])) ? ' AND ' . $this->db->sql_in_set('n.notification_id', $options['notification_id']) : ' AND n.notification_id = ' . (int) $options['notification_id']) : '') . '
+ AND nt.notification_type = n.item_type
+ AND nt.notification_type_enabled = 1
+ ORDER BY n.' . $this->db->sql_escape($options['order_by']) . ' ' . $this->db->sql_escape($options['order_dir']);
+ $result = $this->db->sql_query_limit($sql, $options['limit'], $options['start']);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $rowset[$row['notification_id']] = $row;
+ }
+ $this->db->sql_freeresult($result);
+
+ // Get all unread notifications
+ if ($unread_count && $options['all_unread'] && !empty($rowset))
+ {
+ $sql = 'SELECT n.*
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
+ WHERE n.user_id = ' . (int) $options['user_id'] . '
+ AND n.notification_read = 0
+ AND ' . $this->db->sql_in_set('n.notification_id', array_keys($rowset), true) . '
+ AND nt.notification_type = n.item_type
+ AND nt.notification_type_enabled = 1
+ ORDER BY n.' . $this->db->sql_escape($options['order_by']) . ' ' . $this->db->sql_escape($options['order_dir']);
+ $result = $this->db->sql_query_limit($sql, $options['limit'], $options['start']);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $rowset[$row['notification_id']] = $row;
+ }
+ $this->db->sql_freeresult($result);
+ }
+
+ foreach ($rowset as $row)
+ {
+ $notification = $this->get_item_type_class($row['item_type'], $row);
+
+ // Array of user_ids to query all at once
+ $user_ids = array_merge($user_ids, $notification->users_to_query());
+
+ // Some notification types also require querying additional tables themselves
+ if (!isset($load_special[$row['item_type']]))
+ {
+ $load_special[$row['item_type']] = array();
+ }
+ $load_special[$row['item_type']] = array_merge($load_special[$row['item_type']], $notification->get_load_special());
+
+ $notifications[$row['notification_id']] = $notification;
+ }
+
+ $this->user_loader->load_users($user_ids);
+
+ // Allow each type to load its own special items
+ foreach ($load_special as $item_type => $data)
+ {
+ $item_class = $this->get_item_type_class($item_type);
+
+ $item_class->load_special($data, $notifications);
+ }
+ }
+
+ return array(
+ 'notifications' => $notifications,
+ 'unread_count' => $unread_count,
+ 'total_count' => $total_count,
+ );
+ }
+
+ /**
+ * Mark notifications read
+ *
+ * @param bool|string|array $item_type Type identifier or array of item types (only acceptable if the $data is identical for the specified types). False to mark read for all item types
+ * @param bool|int|array $item_id Item id or array of item ids. False to mark read for all item ids
+ * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
+ * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
+ */
+ public function mark_notifications_read($item_type, $item_id, $user_id, $time = false)
+ {
+ $time = ($time !== false) ? $time : time();
+
+ $sql = 'UPDATE ' . $this->notifications_table . "
+ SET notification_read = 1
+ WHERE notification_time <= " . (int) $time .
+ (($item_type !== false) ? ' AND ' . (is_array($item_type) ? $this->db->sql_in_set('item_type', $item_type) : " item_type = '" . $this->db->sql_escape($item_type) . "'") : '') .
+ (($item_id !== false) ? ' AND ' . (is_array($item_id) ? $this->db->sql_in_set('item_id', $item_id) : 'item_id = ' . (int) $item_id) : '');
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * Mark notifications read from a parent identifier
+ *
+ * @param string|array $item_type Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
+ * @param bool|int|array $item_parent_id Item parent id or array of item parent ids. False to mark read for all item parent ids
+ * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
+ * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
+ */
+ public function mark_notifications_read_by_parent($item_type, $item_parent_id, $user_id, $time = false)
+ {
+ if (is_array($item_type))
+ {
+ foreach ($item_type as $type)
+ {
+ $this->mark_notifications_read_by_parent($type, $item_parent_id, $user_id, $time);
+ }
+
+ return;
+ }
+
+ $time = ($time !== false) ? $time : time();
+
+ $sql = 'UPDATE ' . $this->notifications_table . "
+ SET notification_read = 1
+ WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
+ AND notification_time <= " . (int) $time .
+ (($item_parent_id !== false) ? ' AND ' . (is_array($item_parent_id) ? $this->db->sql_in_set('item_parent_id', $item_parent_id) : 'item_parent_id = ' . (int) $item_parent_id) : '') .
+ (($user_id !== false) ? ' AND ' . (is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id) : '');
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * Mark notifications read
+ *
+ * @param int|array $notification_id Notification id or array of notification ids.
+ * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
+ */
+ public function mark_notifications_read_by_id($notification_id, $time = false)
+ {
+ $time = ($time !== false) ? $time : time();
+
+ $sql = 'UPDATE ' . $this->notifications_table . "
+ SET notification_read = 1
+ WHERE notification_time <= " . (int) $time . '
+ AND ' . ((is_array($notification_id)) ? $this->db->sql_in_set('notification_id', $notification_id) : 'notification_id = ' . (int) $notification_id);
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * Add a notification
+ *
+ * @param string|array $item_type Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
+ * Note: If you send an array of types, any user who could receive multiple notifications from this single item will only receive
+ * a single notification. If they MUST receive multiple notifications, call this function multiple times instead of sending an array
+ * @param array $data Data specific for this type that will be inserted
+ * @param array $options Optional options to control what notifications are loaded
+ * ignore_users array of data to specify which users should not receive certain types of notifications
+ * @return array Information about what users were notified and how they were notified
+ */
+ public function add_notifications($item_type, $data, array $options = array())
+ {
+ $options = array_merge(array(
+ 'ignore_users' => array(),
+ ), $options);
+
+ if (is_array($item_type))
+ {
+ $notified_users = array();
+ $temp_options = $options;
+
+ foreach ($item_type as $type)
+ {
+ $temp_options['ignore_users'] = $options['ignore_users'] + $notified_users;
+ $notified_users += $this->add_notifications($type, $data, $temp_options);
+ }
+
+ return $notified_users;
+ }
+
+ $item_id = $this->get_item_type_class($item_type)->get_item_id($data);
+
+ // find out which users want to receive this type of notification
+ $notify_users = $this->get_item_type_class($item_type)->find_users_for_notification($data, $options);
+
+ $this->add_notifications_for_users($item_type, $data, $notify_users);
+
+ return $notify_users;
+ }
+
+ /**
+ * Add a notification for specific users
+ *
+ * @param string|array $item_type Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
+ * @param array $data Data specific for this type that will be inserted
+ * @param array $notify_users User list to notify
+ */
+ public function add_notifications_for_users($item_type, $data, $notify_users)
+ {
+ if (is_array($item_type))
+ {
+ foreach ($item_type as $type)
+ {
+ $this->add_notifications_for_users($type, $data, $notify_users);
+ }
+
+ return;
+ }
+
+ $sql = 'SELECT notification_type
+ FROM ' . $this->notification_types_table . "
+ WHERE notification_type = '" . $this->db->sql_escape($item_type) . "'";
+ $result = $this->db->sql_query($sql);
+
+ if ($this->db->sql_fetchrow($result) === false)
+ {
+ // Does not exist in the database, must add the item type
+ $sql = 'INSERT INTO ' . $this->notification_types_table . ' ' . $this->db->sql_build_array('INSERT', array(
+ 'notification_type' => $item_type,
+ 'notification_type_enabled' => 1,
+ ));
+ $this->db->sql_query($sql);
+ }
+
+ $this->db->sql_freeresult($result);
+
+ $item_id = $this->get_item_type_class($item_type)->get_item_id($data);
+
+ $user_ids = array();
+ $notification_objects = $notification_methods = array();
+ $new_rows = array();
+
+ // Never send notifications to the anonymous user!
+ unset($notify_users[ANONYMOUS]);
+
+ // Make sure not to send new notifications to users who've already been notified about this item
+ // This may happen when an item was added, but now new users are able to see the item
+ $sql = 'SELECT n.user_id
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . " nt
+ WHERE n.item_type = '" . $this->db->sql_escape($item_type) . "'
+ AND n.item_id = " . (int) $item_id . '
+ AND nt.notification_type = n.item_type
+ AND nt.notification_type_enabled = 1';
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ unset($notify_users[$row['user_id']]);
+ }
+ $this->db->sql_freeresult($result);
+
+ if (!sizeof($notify_users))
+ {
+ return;
+ }
+
+ // Allow notifications to perform actions before creating the insert array (such as run a query to cache some data needed for all notifications)
+ $notification = $this->get_item_type_class($item_type);
+ $pre_create_data = $notification->pre_create_insert_array($data, $notify_users);
+ unset($notification);
+
+ // Go through each user so we can insert a row in the DB and then notify them by their desired means
+ foreach ($notify_users as $user => $methods)
+ {
+ $notification = $this->get_item_type_class($item_type);
+
+ $notification->user_id = (int) $user;
+
+ // Store the creation array in our new rows that will be inserted later
+ $new_rows[] = $notification->create_insert_array($data, $pre_create_data);
+
+ // Users are needed to send notifications
+ $user_ids = array_merge($user_ids, $notification->users_to_query());
+
+ foreach ($methods as $method)
+ {
+ // setup the notification methods and add the notification to the queue
+ if ($method) // blank means we just insert it as a notification, but do not notify them by any other means
+ {
+ if (!isset($notification_methods[$method]))
+ {
+ $notification_methods[$method] = $this->get_method_class($method);
+ }
+
+ $notification_methods[$method]->add_to_queue($notification);
+ }
+ }
+ }
+
+ // insert into the db
+ $this->db->sql_multi_insert($this->notifications_table, $new_rows);
+
+ // We need to load all of the users to send notifications
+ $this->user_loader->load_users($user_ids);
+
+ // run the queue for each method to send notifications
+ foreach ($notification_methods as $method)
+ {
+ $method->notify();
+ }
+ }
+
+ /**
+ * Update a notification
+ *
+ * @param string|array $item_type Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
+ * @param array $data Data specific for this type that will be updated
+ */
+ public function update_notifications($item_type, $data)
+ {
+ if (is_array($item_type))
+ {
+ foreach ($item_type as $type)
+ {
+ $this->update_notifications($type, $data);
+ }
+
+ return;
+ }
+
+ $notification = $this->get_item_type_class($item_type);
+
+ // Allow the notifications class to over-ride the update_notifications functionality
+ if (method_exists($notification, 'update_notifications'))
+ {
+ // Return False to over-ride the rest of the update
+ if ($notification->update_notifications($data) === false)
+ {
+ return;
+ }
+ }
+
+ $item_id = $notification->get_item_id($data);
+ $update_array = $notification->create_update_array($data);
+
+ $sql = 'UPDATE ' . $this->notifications_table . '
+ SET ' . $this->db->sql_build_array('UPDATE', $update_array) . "
+ WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
+ AND item_id = " . (int) $item_id;
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * Delete a notification
+ *
+ * @param string|array $item_type Type identifier or array of item types (only acceptable if the $item_id is identical for the specified types)
+ * @param int|array $item_id Identifier within the type (or array of ids)
+ * @param array $data Data specific for this type that will be updated
+ */
+ public function delete_notifications($item_type, $item_id)
+ {
+ if (is_array($item_type))
+ {
+ foreach ($item_type as $type)
+ {
+ $this->delete_notifications($type, $item_id);
+ }
+
+ return;
+ }
+
+ $sql = 'DELETE FROM ' . $this->notifications_table . "
+ WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
+ AND " . (is_array($item_id) ? $this->db->sql_in_set('item_id', $item_id) : 'item_id = ' . (int) $item_id);
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * Get all of the subscription types
+ *
+ * @return array Array of item types
+ */
+ public function get_subscription_types()
+ {
+ $subscription_types = array();
+
+ foreach ($this->notification_types as $type_name => $data)
+ {
+ $type = $this->get_item_type_class($type_name);
+
+ if ($type instanceof phpbb_notification_type_interface && $type->is_available())
+ {
+ $options = array_merge(array(
+ 'id' => $type->get_type(),
+ 'lang' => 'NOTIFICATION_TYPE_' . strtoupper($type->get_type()),
+ 'group' => 'NOTIFICATION_GROUP_MISCELLANEOUS',
+ ), (($type::$notification_option !== false) ? $type::$notification_option : array()));
+
+ $subscription_types[$options['group']][$options['id']] = $options;
+ }
+ }
+
+ // Move Miscellaneous to the very last section
+ if (isset($subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS']))
+ {
+ $miscellaneous = $subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS'];
+ unset($subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS']);
+ $subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS'] = $miscellaneous;
+ }
+
+ return $subscription_types;
+ }
+
+ /**
+ * Get all of the subscription methods
+ *
+ * @return array Array of methods
+ */
+ public function get_subscription_methods()
+ {
+ $subscription_methods = array();
+
+ foreach ($this->notification_methods as $method_name => $data)
+ {
+ $method = $this->get_method_class($method_name);
+
+ if ($method instanceof phpbb_notification_method_interface && $method->is_available())
+ {
+ $subscription_methods[$method_name] = array(
+ 'id' => $method->get_type(),
+ 'lang' => 'NOTIFICATION_METHOD_' . strtoupper($method->get_type()),
+ );
+ }
+ }
+
+ return $subscription_methods;
+ }
+
+ /**
+ * Get global subscriptions (item_id = 0)
+ *
+ * @param bool|int $user_id The user_id to add the subscription for (bool false for current user)
+ *
+ * @return array Subscriptions
+ */
+ public function get_global_subscriptions($user_id = false)
+ {
+ $user_id = ($user_id === false) ? $this->user->data['user_id'] : $user_id;
+
+ $subscriptions = array();
+
+ foreach ($this->get_subscription_types() as $group_name => $types)
+ {
+ foreach ($types as $id => $type)
+ {
+ $sql = 'SELECT method, notify
+ FROM ' . $this->user_notifications_table . '
+ WHERE user_id = ' . (int) $user_id . "
+ AND item_type = '" . $this->db->sql_escape($id) . "'
+ AND item_id = 0";
+ $result = $this->db->sql_query($sql);
+
+ $row = $this->db->sql_fetchrow($result);
+ if (!$row)
+ {
+ // No rows at all, default to ''
+ $subscriptions[$id] = array('');
+ }
+ else
+ {
+ do
+ {
+ if (!$row['notify'])
+ {
+ continue;
+ }
+
+ if (!isset($subscriptions[$id]))
+ {
+ $subscriptions[$id] = array();
+ }
+
+ $subscriptions[$id][] = $row['method'];
+ }
+ while ($row = $this->db->sql_fetchrow($result));
+ }
+
+ $this->db->sql_freeresult($result);
+ }
+ }
+
+ return $subscriptions;
+ }
+
+ /**
+ * Add a subscription
+ *
+ * @param string $item_type Type identifier of the subscription
+ * @param int $item_id The id of the item
+ * @param string $method The method of the notification e.g. '', 'email', or 'jabber'
+ * @param bool|int $user_id The user_id to add the subscription for (bool false for current user)
+ */
+ public function add_subscription($item_type, $item_id = 0, $method = '', $user_id = false)
+ {
+ if ($method !== '')
+ {
+ $this->add_subscription($item_type, $item_type, '', $user_id);
+ }
+
+ $user_id = ($user_id === false) ? $this->user->data['user_id'] : $user_id;
+
+ $sql = 'SELECT notify
+ FROM ' . $this->user_notifications_table . "
+ WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
+ AND item_id = " . (int) $item_id . '
+ AND user_id = ' .(int) $user_id . "
+ AND method = '" . $this->db->sql_escape($method) . "'";
+ $this->db->sql_query($sql);
+ $current = $this->db->sql_fetchfield('notify');
+ $this->db->sql_freeresult();
+
+ if ($current === false)
+ {
+ $sql = 'INSERT INTO ' . $this->user_notifications_table . ' ' .
+ $this->db->sql_build_array('INSERT', array(
+ 'item_type' => $item_type,
+ 'item_id' => (int) $item_id,
+ 'user_id' => (int) $user_id,
+ 'method' => $method,
+ 'notify' => 1,
+ ));
+ $this->db->sql_query($sql);
+ }
+ else if (!$current)
+ {
+ $sql = 'UPDATE ' . $this->user_notifications_table . "
+ SET notify = 1
+ WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
+ AND item_id = " . (int) $item_id . '
+ AND user_id = ' .(int) $user_id . "
+ AND method = '" . $this->db->sql_escape($method) . "'";
+ $this->db->sql_query($sql);
+ }
+ }
+
+ /**
+ * Delete a subscription
+ *
+ * @param string $item_type Type identifier of the subscription
+ * @param int $item_id The id of the item
+ * @param string $method The method of the notification e.g. '', 'email', or 'jabber'
+ * @param bool|int $user_id The user_id to add the subscription for (bool false for current user)
+ */
+ public function delete_subscription($item_type, $item_id = 0, $method = '', $user_id = false)
+ {
+ $user_id = ($user_id === false) ? $this->user->data['user_id'] : $user_id;
+
+ // If no method, make sure that no other notification methods for this item are selected before deleting
+ if ($method === '')
+ {
+ $sql = 'SELECT COUNT(*) as num_notifications
+ FROM ' . $this->user_notifications_table . "
+ WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
+ AND item_id = " . (int) $item_id . '
+ AND user_id = ' .(int) $user_id . "
+ AND method <> ''
+ AND notify = 1";
+ $this->db->sql_query($sql);
+ $num_notifications = $this->db->sql_fetchfield('num_notifications');
+ $this->db->sql_freeresult();
+
+ if ($num_notifications)
+ {
+ return;
+ }
+ }
+
+ $sql = 'UPDATE ' . $this->user_notifications_table . "
+ SET notify = 0
+ WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
+ AND item_id = " . (int) $item_id . '
+ AND user_id = ' .(int) $user_id . "
+ AND method = '" . $this->db->sql_escape($method) . "'";
+ $this->db->sql_query($sql);
+
+ if (!$this->db->sql_affectedrows())
+ {
+ $sql = 'INSERT INTO ' . $this->user_notifications_table . ' ' .
+ $this->db->sql_build_array('INSERT', array(
+ 'item_type' => $item_type,
+ 'item_id' => (int) $item_id,
+ 'user_id' => (int) $user_id,
+ 'method' => $method,
+ 'notify' => 0,
+ ));
+ $this->db->sql_query($sql);
+ }
+ }
+
+ /**
+ * Disable all notifications of a certain type
+ *
+ * This should be called when an extension which has notification types
+ * is disabled so that all those notifications are hidden and do not
+ * cause errors
+ *
+ * @param string $item_type Type identifier of the subscription
+ */
+ public function disable_notifications($item_type)
+ {
+ $sql = 'UPDATE ' . $this->notification_types_table . "
+ SET notification_type_enabled = 0
+ WHERE notification_type = '" . $this->db->sql_escape($item_type) . "'";
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * Purge all notifications of a certain type
+ *
+ * This should be called when an extension which has notification types
+ * is purged so that all those notifications are removed
+ *
+ * @param string $item_type Type identifier of the subscription
+ */
+ public function purge_notifications($item_type)
+ {
+ $sql = 'DELETE FROM ' . $this->notifications_table . "
+ WHERE item_type = '" . $this->db->sql_escape($item_type) . "'";
+ $this->db->sql_query($sql);
+
+ $sql = 'DELETE FROM ' . $this->notification_types_table . "
+ WHERE notification_type = '" . $this->db->sql_escape($item_type) . "'";
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * Enable all notifications of a certain type
+ *
+ * This should be called when an extension which has notification types
+ * that was disabled is re-enabled so that all those notifications that
+ * were hidden are shown again
+ *
+ * @param string $item_type Type identifier of the subscription
+ */
+ public function enable_notifications($item_type)
+ {
+ $sql = 'UPDATE ' . $this->notification_types_table . "
+ SET notification_type_enabled = 1
+ WHERE notification_type = '" . $this->db->sql_escape($item_type) . "'";
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * Delete all notifications older than a certain time
+ *
+ * @param int $timestamp Unix timestamp to delete all notifications that were created before
+ */
+ public function prune_notifications($timestamp)
+ {
+ $sql = 'DELETE FROM ' . $this->notifications_table . '
+ WHERE notification_time < ' . (int) $timestamp;
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * Helper to get the notifications item type class and set it up
+ */
+ public function get_item_type_class($item_type, $data = array())
+ {
+ $item_type = (strpos($item_type, 'notification.type.') === 0) ? $item_type : 'notification.type.' . $item_type;
+
+ $item = $this->load_object($item_type);
+
+ $item->set_initial_data($data);
+
+ return $item;
+ }
+
+ /**
+ * Helper to get the notifications method class and set it up
+ */
+ public function get_method_class($method_name)
+ {
+ $method_name = (strpos($method_name, 'notification.method.') === 0) ? $method_name : 'notification.method.' . $method_name;
+
+ return $this->load_object($method_name);
+ }
+
+ /**
+ * Helper to load objects (notification types/methods)
+ */
+ protected function load_object($object_name)
+ {
+ $object = $this->phpbb_container->get($object_name);
+
+ if (method_exists($object, 'set_notification_manager'))
+ {
+ $object->set_notification_manager($this);
+ }
+
+ return $object;
+ }
+}
diff --git a/phpBB/includes/notification/method/base.php b/phpBB/includes/notification/method/base.php
new file mode 100644
index 0000000000..22418c9be8
--- /dev/null
+++ b/phpBB/includes/notification/method/base.php
@@ -0,0 +1,116 @@
+user_loader = $user_loader;
+ $this->db = $db;
+ $this->cache = $cache;
+ $this->user = $user;
+ $this->auth = $auth;
+ $this->config = $config;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+ }
+
+ /**
+ * Set notification manager (required)
+ *
+ * @param phpbb_notification_manager $notification_manager
+ */
+ public function set_notification_manager(phpbb_notification_manager $notification_manager)
+ {
+ $this->notification_manager = $notification_manager;
+ }
+
+ /**
+ * Add a notification to the queue
+ *
+ * @param phpbb_notification_type_interface $notification
+ */
+ public function add_to_queue(phpbb_notification_type_interface $notification)
+ {
+ $this->queue[] = $notification;
+ }
+
+ /**
+ * Empty the queue
+ */
+ protected function empty_queue()
+ {
+ $this->queue = array();
+ }
+}
diff --git a/phpBB/includes/notification/method/email.php b/phpBB/includes/notification/method/email.php
new file mode 100644
index 0000000000..4a7fea6df3
--- /dev/null
+++ b/phpBB/includes/notification/method/email.php
@@ -0,0 +1,128 @@
+config['email_enable'];
+ }
+
+ /**
+ * Parse the queue and notify the users
+ */
+ public function notify()
+ {
+ if (!sizeof($this->queue))
+ {
+ return;
+ }
+
+ // Load all users we want to notify (we need their email address)
+ $user_ids = $users = array();
+ foreach ($this->queue as $notification)
+ {
+ $user_ids[] = $notification->user_id;
+ }
+
+ // We do not send emails to banned users
+ if (!function_exists('phpbb_get_banned_user_ids'))
+ {
+ include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
+ }
+ $banned_users = phpbb_get_banned_user_ids($user_ids);
+
+ // Load all the users we need
+ $this->user_loader->load_users($user_ids);
+
+ // Load the messenger
+ if (!class_exists('messenger'))
+ {
+ include($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext);
+ }
+ $messenger = new messenger();
+ $board_url = generate_board_url();
+
+ // Time to go through the queue and send emails
+ foreach ($this->queue as $notification)
+ {
+ if ($notification->get_email_template() === false)
+ {
+ continue;
+ }
+
+ $user = $this->user_loader->get_user($notification->user_id);
+
+ if ($user['user_type'] == USER_IGNORE || in_array($notification->user_id, $banned_users))
+ {
+ continue;
+ }
+
+ $messenger->template($this->email_template_base_dir . $notification->get_email_template(), $user['user_lang']);
+
+ $messenger->to($user['user_email'], $user['username']);
+
+ $messenger->assign_vars(array_merge(array(
+ 'USERNAME' => $user['username'],
+
+ 'U_NOTIFICATION_SETTINGS' => generate_board_url() . '/ucp.' . $this->php_ext . '?i=ucp_notifications',
+ ), $notification->get_email_template_variables()));
+
+ $messenger->send($this->notify_method);
+ }
+
+ // Save the queue in the messenger class (has to be called or these emails could be lost?)
+ $messenger->save_queue();
+
+ // We're done, empty the queue
+ $this->empty_queue();
+ }
+}
diff --git a/phpBB/includes/notification/method/interface.php b/phpBB/includes/notification/method/interface.php
new file mode 100644
index 0000000000..ef875942cc
--- /dev/null
+++ b/phpBB/includes/notification/method/interface.php
@@ -0,0 +1,48 @@
+global_available() && $this->user->data['user_jabber']);
+ }
+
+ /**
+ * Is this method available at all?
+ * This is checked before notifications are sent
+ */
+ public function global_available()
+ {
+ return ($this->config['jab_enable'] && @extension_loaded('xml'));
+ }
+
+ public function notify()
+ {
+ if (!$this->global_available())
+ {
+ return;
+ }
+
+ return parent::notify();
+ }
+}
diff --git a/phpBB/includes/notification/type/approve_post.php b/phpBB/includes/notification/type/approve_post.php
new file mode 100644
index 0000000000..1a30781c35
--- /dev/null
+++ b/phpBB/includes/notification/type/approve_post.php
@@ -0,0 +1,140 @@
+ 'moderation_queue',
+ 'lang' => 'NOTIFICATION_TYPE_MODERATION_QUEUE',
+ 'group' => 'NOTIFICATION_GROUP_POSTING',
+ );
+
+ /**
+ * Is available
+ */
+ public function is_available()
+ {
+ return !$this->auth->acl_get('m_approve');
+ }
+
+ /**
+ * Find the users who want to receive notifications
+ *
+ * @param array $post Data from
+ *
+ * @return array
+ */
+ public function find_users_for_notification($post, $options = array())
+ {
+ $options = array_merge(array(
+ 'ignore_users' => array(),
+ ), $options);
+
+ $users = array();
+ $users[$post['poster_id']] = array('');
+
+ $auth_read = $this->auth->acl_get_list(array_keys($users), 'f_read', $post['forum_id']);
+
+ if (empty($auth_read))
+ {
+ return array();
+ }
+
+ return $this->check_user_notification_options($auth_read[$post['forum_id']]['f_read'], array_merge($options, array(
+ 'item_type' => self::$notification_option['id'],
+ )));
+ }
+
+ /**
+ * Pre create insert array function
+ * This allows you to perform certain actions, like run a query
+ * and load data, before create_insert_array() is run. The data
+ * returned from this function will be sent to create_insert_array().
+ *
+ * @param array $post Post data from submit_post
+ * @param array $notify_users Notify users list
+ * Formated from find_users_for_notification()
+ * @return array Whatever you want to send to create_insert_array().
+ */
+ public function pre_create_insert_array($post, $notify_users)
+ {
+ // In the parent class, this is used to check if the post is already
+ // read by a user and marks the notification read if it was marked read.
+ // Returning an empty array in effect, forces it to be marked as unread
+ // (and also saves a query)
+ return array();
+ }
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $post Data from submit_post
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ *
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($post, $pre_create_data = array())
+ {
+ $this->set_data('post_subject', $post['post_subject']);
+
+ $data = parent::create_insert_array($post, $pre_create_data);
+
+ $this->notification_time = $data['notification_time'] = time();
+
+ return $data;
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return 'post_approved';
+ }
+}
diff --git a/phpBB/includes/notification/type/approve_topic.php b/phpBB/includes/notification/type/approve_topic.php
new file mode 100644
index 0000000000..e728e9ac30
--- /dev/null
+++ b/phpBB/includes/notification/type/approve_topic.php
@@ -0,0 +1,138 @@
+ 'moderation_queue',
+ 'lang' => 'NOTIFICATION_TYPE_MODERATION_QUEUE',
+ 'group' => 'NOTIFICATION_GROUP_POSTING',
+ );
+
+ /**
+ * Is available
+ */
+ public function is_available()
+ {
+ return !$this->auth->acl_get('m_approve');
+ }
+
+ /**
+ * Find the users who want to receive notifications
+ *
+ * @param array $post Data from
+ *
+ * @return array
+ */
+ public function find_users_for_notification($post, $options = array())
+ {
+ $options = array_merge(array(
+ 'ignore_users' => array(),
+ ), $options);
+
+ $users = array();
+ $users[$post['poster_id']] = array('');
+
+ $auth_read = $this->auth->acl_get_list(array_keys($users), 'f_read', $post['forum_id']);
+
+ if (empty($auth_read))
+ {
+ return array();
+ }
+
+ return $this->check_user_notification_options($auth_read[$post['forum_id']]['f_read'], array_merge($options, array(
+ 'item_type' => self::$notification_option['id'],
+ )));
+ }
+
+ /**
+ * Pre create insert array function
+ * This allows you to perform certain actions, like run a query
+ * and load data, before create_insert_array() is run. The data
+ * returned from this function will be sent to create_insert_array().
+ *
+ * @param array $post Post data from submit_post
+ * @param array $notify_users Notify users list
+ * Formated from find_users_for_notification()
+ * @return array Whatever you want to send to create_insert_array().
+ */
+ public function pre_create_insert_array($post, $notify_users)
+ {
+ // In the parent class, this is used to check if the post is already
+ // read by a user and marks the notification read if it was marked read.
+ // Returning an empty array in effect, forces it to be marked as unread
+ // (and also saves a query)
+ return array();
+ }
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $post Data from submit_post
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ *
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($post, $pre_create_data = array())
+ {
+ $data = parent::create_insert_array($post, $pre_create_data);
+
+ $this->notification_time = $data['notification_time'] = time();
+
+ return $data;
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return 'topic_approved';
+ }
+}
diff --git a/phpBB/includes/notification/type/base.php b/phpBB/includes/notification/type/base.php
new file mode 100644
index 0000000000..600ef7c965
--- /dev/null
+++ b/phpBB/includes/notification/type/base.php
@@ -0,0 +1,479 @@
+ forum_id, for post => topic_id, etc)
+ * user_id
+ * notification_read
+ * notification_time
+ * notification_data (special serialized field that each notification type can use to store stuff)
+ *
+ * @var array $data Notification row from the database
+ * This must be private, all interaction should use __get(), __set(), get_data(), set_data()
+ */
+ private $data = array();
+
+ /**
+ * Notification Type Base Constructor
+ *
+ * @param phpbb_user_loader $user_loader
+ * @param phpbb_db_driver $db
+ * @param phpbb_cache_driver_interface $cache
+ * @param phpbb_user $user
+ * @param phpbb_auth $auth
+ * @param phpbb_config $config
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ * @param string $notification_types_table
+ * @param string $notifications_table
+ * @param string $user_notifications_table
+ * @return phpbb_notification_type_base
+ */
+ public function __construct(phpbb_user_loader $user_loader, phpbb_db_driver $db, phpbb_cache_driver_interface $cache, $user, phpbb_auth $auth, phpbb_config $config, $phpbb_root_path, $php_ext, $notification_types_table, $notifications_table, $user_notifications_table)
+ {
+ $this->user_loader = $user_loader;
+ $this->db = $db;
+ $this->cache = $cache;
+ $this->user = $user;
+ $this->auth = $auth;
+ $this->config = $config;
+
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ $this->notification_types_table = $notification_types_table;
+ $this->notifications_table = $notifications_table;
+ $this->user_notifications_table = $user_notifications_table;
+ }
+
+ /**
+ * Set notification manager (required)
+ *
+ * @param phpbb_notification_manager $notification_manager
+ */
+ public function set_notification_manager(phpbb_notification_manager $notification_manager)
+ {
+ $this->notification_manager = $notification_manager;
+ }
+
+ /**
+ * Set initial data from the database
+ *
+ * @param array $data Row directly from the database
+ */
+ public function set_initial_data($data = array())
+ {
+ // The row from the database (unless this is a new notification we're going to add)
+ $this->data = $data;
+ $this->data['notification_data'] = (isset($this->data['notification_data'])) ? unserialize($this->data['notification_data']) : array();
+ }
+
+ /**
+ * Magic method to get data from this notification
+ *
+ * @param mixed $name
+ * @return mixed
+ */
+ public function __get($name)
+ {
+ return (!isset($this->data[$name])) ? null : $this->data[$name];
+ }
+
+
+ /**
+ * Magic method to set data on this notification
+ *
+ * @param mixed $name
+ * @return null
+ */
+ public function __set($name, $value)
+ {
+ $this->data[$name] = $value;
+ }
+
+
+ /**
+ * Magic method to get a string of this notification
+ *
+ * Primarily for testing
+ *
+ * @param string $name
+ * @return mixed
+ */
+ public function __toString()
+ {
+ return (!empty($this->data)) ? var_export($this->data, true) : $this->get_type();
+ }
+
+ /**
+ * Get special data (only important for the classes that extend this)
+ *
+ * @param string $name Name of the variable to get
+ * @return mixed
+ */
+ protected function get_data($name)
+ {
+ return ($name === false) ? $this->data['notification_data'] : ((isset($this->data['notification_data'][$name])) ? $this->data['notification_data'][$name] : null);
+ }
+
+ /**
+ * Set special data (only important for the classes that extend this)
+ *
+ * @param string $name Name of the variable to set
+ * @param mixed $value Value to set to the variable
+ * @return mixed
+ */
+ protected function set_data($name, $value)
+ {
+ $this->data['notification_data'][$name] = $value;
+ }
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $type_data Data unique to this notification type
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($type_data, $pre_create_data = array())
+ {
+ // Defaults
+ $this->data = array_merge(array(
+ 'item_id' => static::get_item_id($type_data),
+ 'item_type' => $this->get_type(),
+ 'item_parent_id' => static::get_item_parent_id($type_data),
+
+ 'notification_time' => time(),
+ 'notification_read' => false,
+
+ 'notification_data' => array(),
+ ), $this->data);
+
+ $data = $this->data;
+
+ $data['notification_data'] = serialize($data['notification_data']);
+
+ return $data;
+ }
+
+ /**
+ * Function for preparing the data for update in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $type_data Data unique to this notification type
+ * @return array Array of data ready to be updated in the database
+ */
+ public function create_update_array($type_data)
+ {
+ $data = $this->create_insert_array($type_data);
+
+ // Unset data unique to each row
+ unset(
+ $data['notification_time'], // Also unsetting time, since it always tries to change the time to current (if you actually need to change the time, over-ride this function)
+ $data['notification_id'],
+ $data['notification_read'],
+ $data['user_id']
+ );
+
+ return $data;
+ }
+
+ /**
+ * Mark this item read
+ *
+ * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False)
+ * @return string|null If $return is False, nothing will be returned, else the sql code to update this item
+ */
+ public function mark_read($return = false)
+ {
+ return $this->mark(false, $return);
+ }
+
+ /**
+ * Mark this item unread
+ *
+ * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False)
+ * @return string|null If $return is False, nothing will be returned, else the sql code to update this item
+ */
+ public function mark_unread($return = false)
+ {
+ return $this->mark(true, $return);
+ }
+
+ /**
+ * Prepare to output the notification to the template
+ *
+ * @return array Template variables
+ */
+ public function prepare_for_display()
+ {
+ if ($this->get_url())
+ {
+ $u_mark_read = append_sid($this->phpbb_root_path . 'index.' . $this->php_ext, 'mark_notification=' . $this->notification_id);
+ }
+ else
+ {
+ $redirect = (($this->user->page['page_dir']) ? $this->user->page['page_dir'] . '/' : '') . $this->user->page['page_name'] . (($this->user->page['query_string']) ? '?' . $this->user->page['query_string'] : '');
+
+ $u_mark_read = append_sid($this->phpbb_root_path . 'index.' . $this->php_ext, 'mark_notification=' . $this->notification_id . '&redirect=' . urlencode($redirect));
+ }
+
+ return array(
+ 'NOTIFICATION_ID' => $this->notification_id,
+
+ 'AVATAR' => $this->get_avatar(),
+
+ 'FORMATTED_TITLE' => $this->get_title(),
+
+ 'URL' => $this->get_url(),
+ 'TIME' => $this->user->format_date($this->notification_time),
+
+ 'UNREAD' => !$this->notification_read,
+
+ 'U_MARK_READ' => (!$this->notification_read) ? $u_mark_read : '',
+ );
+ }
+
+ /**
+ * -------------- Fall back functions -------------------
+ */
+
+ /**
+ * URL to unsubscribe to this notification (fall back)
+ *
+ * @param string|bool $method Method name to unsubscribe from (email|jabber|etc), False to unsubscribe from all notifications for this item
+ */
+ public function get_unsubscribe_url($method = false)
+ {
+ return false;
+ }
+
+ /**
+ * Get the user's avatar (fall back)
+ *
+ * @return string
+ */
+ public function get_avatar()
+ {
+ return '';
+ }
+
+ /**
+ * Get the special items to load (fall back)
+ *
+ * @return array
+ */
+ public function get_load_special()
+ {
+ return array();
+ }
+
+ /**
+ * Load the special items (fall back)
+ */
+ public function load_special($data, $notifications)
+ {
+ return;
+ }
+
+ /**
+ * Is available (fall back)
+ *
+ * @return bool
+ */
+ public function is_available()
+ {
+ return true;
+ }
+
+ /**
+ * Pre create insert array function (fall back)
+ *
+ * @return array
+ */
+ public function pre_create_insert_array($type_data, $notify_users)
+ {
+ return array();
+ }
+
+ /**
+ * -------------- Helper functions -------------------
+ */
+
+ /**
+ * Find the users who want to receive notifications (helper)
+ *
+ * @param array $user_ids User IDs to check if they want to receive notifications
+ * (Bool False to check all users besides anonymous and bots (USER_IGNORE))
+ *
+ * @return array
+ */
+ protected function check_user_notification_options($user_ids = false, $options = array())
+ {
+ $options = array_merge(array(
+ 'ignore_users' => array(),
+ 'item_type' => $this->get_type(),
+ 'item_id' => 0, // Global by default
+ ), $options);
+
+ if ($user_ids === false)
+ {
+ $user_ids = array();
+
+ $sql = 'SELECT user_id
+ FROM ' . USERS_TABLE . '
+ WHERE user_id <> ' . ANONYMOUS . '
+ AND user_type <> ' . USER_IGNORE;
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $user_ids[] = $row['user_id'];
+ }
+ $this->db->sql_freeresult($result);
+ }
+
+ if (empty($user_ids))
+ {
+ return array();
+ }
+
+ $rowset = $resulting_user_ids = array();
+
+ $sql = 'SELECT user_id, method, notify
+ FROM ' . $this->user_notifications_table . '
+ WHERE ' . $this->db->sql_in_set('user_id', $user_ids) . "
+ AND item_type = '" . $this->db->sql_escape($options['item_type']) . "'
+ AND item_id = " . (int) $options['item_id'];
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $resulting_user_ids[] = $row['user_id'];
+
+ if (!$row['notify'] || (isset($options['ignore_users'][$row['user_id']]) && in_array($row['method'], $options['ignore_users'][$row['user_id']])))
+ {
+ continue;
+ }
+
+ if (!isset($rowset[$row['user_id']]))
+ {
+ $rowset[$row['user_id']] = array();
+ }
+
+ $rowset[$row['user_id']][] = $row['method'];
+ }
+
+ $this->db->sql_freeresult($result);
+
+ foreach ($user_ids as $user_id)
+ {
+ if (!in_array($user_id, $resulting_user_ids) && !isset($options['ignore_users'][$user_id]))
+ {
+ // No rows at all for this user, default to ''
+ $rowset[$user_id] = array('');
+ }
+ }
+
+ return $rowset;
+ }
+
+ /**
+ * Mark this item read/unread helper
+ *
+ * @param bool $unread Unread (True/False) (Default: False)
+ * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False)
+ * @return string|null If $return is False, nothing will be returned, else the sql code to update this item
+ */
+ protected function mark($unread = true, $return = false)
+ {
+ $this->notification_read = (bool) !$unread;
+
+ $where = array(
+ "item_type = '" . $this->db->sql_escape($this->item_type) . "'",
+ 'item_id = ' . (int) $this->item_id,
+ 'user_id = ' . (int) $this->user_id,
+ );
+ $where = implode(' AND ', $where);
+
+ if ($return)
+ {
+ return $where;
+ }
+
+ $sql = 'UPDATE ' . $this->notifications_table . '
+ SET notification_read = ' . (int) $this->notification_read . '
+ WHERE ' . $where;
+ $this->db->sql_query($sql);
+ }
+}
diff --git a/phpBB/includes/notification/type/bookmark.php b/phpBB/includes/notification/type/bookmark.php
new file mode 100644
index 0000000000..4e48a967d0
--- /dev/null
+++ b/phpBB/includes/notification/type/bookmark.php
@@ -0,0 +1,137 @@
+ 'NOTIFICATION_TYPE_BOOKMARK',
+ 'group' => 'NOTIFICATION_GROUP_POSTING',
+ );
+
+ /**
+ * Is available
+ */
+ public function is_available()
+ {
+ return $this->config['allow_bookmarks'];
+ }
+
+ /**
+ * Find the users who want to receive notifications
+ *
+ * @param array $post Data from
+ *
+ * @return array
+ */
+ public function find_users_for_notification($post, $options = array())
+ {
+ $options = array_merge(array(
+ 'ignore_users' => array(),
+ ), $options);
+
+ $users = array();
+
+ $sql = 'SELECT user_id
+ FROM ' . BOOKMARKS_TABLE . '
+ WHERE ' . $this->db->sql_in_set('topic_id', $post['topic_id']) . '
+ AND user_id <> ' . (int) $post['poster_id'];
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $users[] = $row['user_id'];
+ }
+ $this->db->sql_freeresult($result);
+
+ if (empty($users))
+ {
+ return array();
+ }
+
+ $auth_read = $this->auth->acl_get_list($users, 'f_read', $post['forum_id']);
+
+ if (empty($auth_read))
+ {
+ return array();
+ }
+
+ $notify_users = $this->check_user_notification_options($auth_read[$post['forum_id']]['f_read'], $options);
+
+ // Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications
+ $update_notifications = array();
+ $sql = 'SELECT n.*
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . " nt
+ WHERE n.item_type = '" . $this->get_type() . "'
+ AND n.item_parent_id = " . (int) self::get_item_parent_id($post) . '
+ AND n.notification_read = 0
+ AND nt.notification_type = n.item_type
+ AND nt.notification_type_enabled = 1';
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ // Do not create a new notification
+ unset($notify_users[$row['user_id']]);
+
+ $notification = $this->notification_manager->get_item_type_class($this->get_type(), $row);
+ $sql = 'UPDATE ' . $this->notifications_table . '
+ SET ' . $this->db->sql_build_array('UPDATE', $notification->add_responders($post)) . '
+ WHERE notification_id = ' . $row['notification_id'];
+ $this->db->sql_query($sql);
+ }
+ $this->db->sql_freeresult($result);
+
+ return $notify_users;
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return 'bookmark';
+ }
+}
diff --git a/phpBB/includes/notification/type/disapprove_post.php b/phpBB/includes/notification/type/disapprove_post.php
new file mode 100644
index 0000000000..951c7e0254
--- /dev/null
+++ b/phpBB/includes/notification/type/disapprove_post.php
@@ -0,0 +1,120 @@
+ 'moderation_queue',
+ 'lang' => 'NOTIFICATION_TYPE_MODERATION_QUEUE',
+ 'group' => 'NOTIFICATION_GROUP_POSTING',
+ );
+
+ /**
+ * Get the HTML formatted title of this notification
+ *
+ * @return string
+ */
+ public function get_title()
+ {
+ return $this->user->lang(
+ $this->language_key,
+ censor_text($this->get_data('topic_title')),
+ $this->get_data('disapprove_reason')
+ );
+ }
+
+ /**
+ * Get the url to this item
+ *
+ * @return string URL
+ */
+ public function get_url()
+ {
+ return '';
+ }
+
+ /**
+ * Get email template variables
+ *
+ * @return array
+ */
+ public function get_email_template_variables()
+ {
+ return array_merge(parent::get_email_template_variables(), array(
+ 'REASON' => htmlspecialchars_decode($this->get_data('disapprove_reason')),
+ ));
+ }
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $post Data from submit_post
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ *
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($post, $pre_create_data = array())
+ {
+ $this->set_data('disapprove_reason', $post['disapprove_reason']);
+
+ $data = parent::create_insert_array($post);
+
+ $this->notification_time = $data['notification_time'] = time();
+
+ return $data;
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return 'post_disapproved';
+ }
+}
diff --git a/phpBB/includes/notification/type/disapprove_topic.php b/phpBB/includes/notification/type/disapprove_topic.php
new file mode 100644
index 0000000000..038e528797
--- /dev/null
+++ b/phpBB/includes/notification/type/disapprove_topic.php
@@ -0,0 +1,120 @@
+ 'moderation_queue',
+ 'lang' => 'NOTIFICATION_TYPE_MODERATION_QUEUE',
+ 'group' => 'NOTIFICATION_GROUP_POSTING',
+ );
+
+ /**
+ * Get the HTML formatted title of this notification
+ *
+ * @return string
+ */
+ public function get_title()
+ {
+ return $this->user->lang(
+ $this->language_key,
+ censor_text($this->get_data('topic_title')),
+ $this->get_data('disapprove_reason')
+ );
+ }
+
+ /**
+ * Get the url to this item
+ *
+ * @return string URL
+ */
+ public function get_url()
+ {
+ return '';
+ }
+
+ /**
+ * Get email template variables
+ *
+ * @return array
+ */
+ public function get_email_template_variables()
+ {
+ return array_merge(parent::get_email_template_variables(), array(
+ 'REASON' => htmlspecialchars_decode($this->get_data('disapprove_reason')),
+ ));
+ }
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $post Data from submit_post
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ *
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($post, $pre_create_data = array())
+ {
+ $this->set_data('disapprove_reason', $post['disapprove_reason']);
+
+ $data = parent::create_insert_array($post, $pre_create_data);
+
+ $this->notification_time = $data['notification_time'] = time();
+
+ return $data;
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return 'topic_disapproved';
+ }
+}
diff --git a/phpBB/includes/notification/type/interface.php b/phpBB/includes/notification/type/interface.php
new file mode 100644
index 0000000000..a40fdafd09
--- /dev/null
+++ b/phpBB/includes/notification/type/interface.php
@@ -0,0 +1,189 @@
+ array of users and user types that should not receive notifications from this type because they've already been notified
+ * e.g.: array(2 => array(''), 3 => array('', 'email'), ...)
+ *
+ * @return array
+ */
+ public function find_users_for_notification($type_data, $options);
+
+ /**
+ * Users needed to query before this notification can be displayed
+ *
+ * @return array Array of user_ids
+ */
+ public function users_to_query();
+
+ /**
+ * Get the special items to load
+ *
+ * @return array Data will be combined sent to load_special() so you can run a single query and get data required for this notification type
+ */
+ public function get_load_special();
+
+ /**
+ * Load the special items
+ *
+ * @param array $data Data from get_load_special()
+ * @param array $notifications Array of notifications (key is notification_id, value is the notification objects)
+ */
+ public function load_special($data, $notifications);
+
+ /**
+ * Get the HTML formatted title of this notification
+ *
+ * @return string
+ */
+ public function get_title();
+
+ /**
+ * Get the url to this item
+ *
+ * @return string URL
+ */
+ public function get_url();
+
+ /**
+ * URL to unsubscribe to this notification
+ *
+ * @param string|bool $method Method name to unsubscribe from (email|jabber|etc), False to unsubscribe from all notifications for this item
+ */
+ public function get_unsubscribe_url($method);
+
+ /**
+ * Get the user's avatar (the user who caused the notification typically)
+ *
+ * @return string
+ */
+ public function get_avatar();
+
+ /**
+ * Prepare to output the notification to the template
+ */
+ public function prepare_for_display();
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template();
+
+ /**
+ * Get email template variables
+ *
+ * @return array
+ */
+ public function get_email_template_variables();
+
+ /**
+ * Pre create insert array function
+ * This allows you to perform certain actions, like run a query
+ * and load data, before create_insert_array() is run. The data
+ * returned from this function will be sent to create_insert_array().
+ *
+ * @param array $type_data The type specific data
+ * @param array $notify_users Notify users list
+ * Formated from find_users_for_notification()
+ * @return array Whatever you want to send to create_insert_array().
+ */
+ public function pre_create_insert_array($type_data, $notify_users);
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $type_data The type specific data
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ *
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($type_data, $pre_create_data);
+
+ /**
+ * Function for preparing the data for update in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $type_data Data unique to this notification type
+ *
+ * @return array Array of data ready to be updated in the database
+ */
+ public function create_update_array($type_data);
+
+ /**
+ * Mark this item read
+ *
+ * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False)
+ * @return string
+ */
+ public function mark_read($return);
+
+ /**
+ * Mark this item unread
+ *
+ * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False)
+ * @return string
+ */
+ public function mark_unread($return);
+}
diff --git a/phpBB/includes/notification/type/pm.php b/phpBB/includes/notification/type/pm.php
new file mode 100644
index 0000000000..b3db7ad5ad
--- /dev/null
+++ b/phpBB/includes/notification/type/pm.php
@@ -0,0 +1,184 @@
+ 'NOTIFICATION_TYPE_PM',
+ );
+
+ /**
+ * Is available
+ */
+ public function is_available()
+ {
+ return ($this->config['allow_privmsg'] && $this->auth->acl_get('u_readpm'));
+ }
+
+ /**
+ * Get the id of the
+ *
+ * @param array $pm The data from the private message
+ */
+ public static function get_item_id($pm)
+ {
+ return (int) $pm['msg_id'];
+ }
+
+ /**
+ * Get the id of the parent
+ *
+ * @param array $pm The data from the pm
+ */
+ public static function get_item_parent_id($pm)
+ {
+ // No parent
+ return 0;
+ }
+
+ /**
+ * Find the users who want to receive notifications
+ *
+ * @param array $pm Data from
+ *
+ * @return array
+ */
+ public function find_users_for_notification($pm, $options = array())
+ {
+ $options = array_merge(array(
+ 'ignore_users' => array(),
+ ), $options);
+
+ if (!sizeof($pm['recipients']))
+ {
+ return array();
+ }
+
+ unset($pm['recipients'][$pm['from_user_id']]);
+
+ $this->user_loader->load_users(array_keys($pm['recipients']));
+
+ return $this->check_user_notification_options(array_keys($pm['recipients']), $options);
+ }
+
+ /**
+ * Get the user's avatar
+ */
+ public function get_avatar()
+ {
+ return $this->user_loader->get_avatar($this->get_data('from_user_id'));
+ }
+
+ /**
+ * Get the HTML formatted title of this notification
+ *
+ * @return string
+ */
+ public function get_title()
+ {
+ $username = $this->user_loader->get_username($this->get_data('from_user_id'), 'no_profile');
+
+ return $this->user->lang('NOTIFICATION_PM', $username, $this->get_data('message_subject'));
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return 'privmsg_notify';
+ }
+
+ /**
+ * Get email template variables
+ *
+ * @return array
+ */
+ public function get_email_template_variables()
+ {
+ $user_data = $this->user_loader->get_user($this->get_data('from_user_id'));
+
+ return array(
+ 'AUTHOR_NAME' => htmlspecialchars_decode($user_data['username']),
+ 'SUBJECT' => htmlspecialchars_decode(censor_text($this->get_data('message_subject'))),
+
+ 'U_VIEW_MESSAGE' => generate_board_url() . '/ucp.' . $this->php_ext . "?i=pm&mode=view&p={$this->item_id}",
+ );
+ }
+
+ /**
+ * Get the url to this item
+ *
+ * @return string URL
+ */
+ public function get_url()
+ {
+ return append_sid($this->phpbb_root_path . 'ucp.' . $this->php_ext, "i=pm&mode=view&p={$this->item_id}");
+ }
+
+ /**
+ * Users needed to query before this notification can be displayed
+ *
+ * @return array Array of user_ids
+ */
+ public function users_to_query()
+ {
+ return array($this->get_data('from_user_id'));
+ }
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $post Data from submit_post
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ *
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($pm, $pre_create_data = array())
+ {
+ $this->set_data('from_user_id', $pm['from_user_id']);
+
+ $this->set_data('message_subject', $pm['message_subject']);
+
+ return parent::create_insert_array($pm, $pre_create_data);
+ }
+}
diff --git a/phpBB/includes/notification/type/post.php b/phpBB/includes/notification/type/post.php
new file mode 100644
index 0000000000..d8ffdea81d
--- /dev/null
+++ b/phpBB/includes/notification/type/post.php
@@ -0,0 +1,370 @@
+ 'NOTIFICATION_TYPE_POST',
+ 'group' => 'NOTIFICATION_GROUP_POSTING',
+ );
+
+ /**
+ * Is available
+ */
+ public function is_available()
+ {
+ return $this->config['allow_topic_notify'];
+ }
+
+ /**
+ * Get the id of the item
+ *
+ * @param array $post The data from the post
+ */
+ public static function get_item_id($post)
+ {
+ return (int) $post['post_id'];
+ }
+
+ /**
+ * Get the id of the parent
+ *
+ * @param array $post The data from the post
+ */
+ public static function get_item_parent_id($post)
+ {
+ return (int) $post['topic_id'];
+ }
+
+ /**
+ * Find the users who want to receive notifications
+ *
+ * @param array $post Data from
+ *
+ * @return array
+ */
+ public function find_users_for_notification($post, $options = array())
+ {
+ $options = array_merge(array(
+ 'ignore_users' => array(),
+ ), $options);
+
+ $users = array();
+
+ $sql = 'SELECT user_id
+ FROM ' . TOPICS_WATCH_TABLE . '
+ WHERE topic_id = ' . (int) $post['topic_id'] . '
+ AND notify_status = ' . NOTIFY_YES . '
+ AND user_id <> ' . (int) $post['poster_id'];
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $users[] = $row['user_id'];
+ }
+ $this->db->sql_freeresult($result);
+
+ if (empty($users))
+ {
+ return array();
+ }
+
+ $auth_read = $this->auth->acl_get_list($users, 'f_read', $post['forum_id']);
+
+ if (empty($auth_read))
+ {
+ return array();
+ }
+
+ $notify_users = $this->check_user_notification_options($auth_read[$post['forum_id']]['f_read'], $options);
+
+ // Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications
+ $update_notifications = array();
+ $sql = 'SELECT n.*
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . " nt
+ WHERE n.item_type = '" . $this->get_type() . "'
+ AND n.item_parent_id = " . (int) self::get_item_parent_id($post) . '
+ AND n.notification_read = 0
+ AND nt.notification_type = n.item_type
+ AND nt.notification_type_enabled = 1';
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ // Do not create a new notification
+ unset($notify_users[$row['user_id']]);
+
+ $notification = $this->notification_manager->get_item_type_class($this->get_type(), $row);
+ $sql = 'UPDATE ' . $this->notifications_table . '
+ SET ' . $this->db->sql_build_array('UPDATE', $notification->add_responders($post)) . '
+ WHERE notification_id = ' . $row['notification_id'];
+ $this->db->sql_query($sql);
+ }
+ $this->db->sql_freeresult($result);
+
+ return $notify_users;
+ }
+
+ /**
+ * Get the user's avatar
+ */
+ public function get_avatar()
+ {
+ return $this->user_loader->get_avatar($this->get_data('poster_id'));
+ }
+
+ /**
+ * Get the HTML formatted title of this notification
+ *
+ * @return string
+ */
+ public function get_title()
+ {
+ $responders = $this->get_data('responders');
+ $usernames = array();
+
+ if (!is_array($responders))
+ {
+ $responders = array();
+ }
+
+ $responders = array_merge(array(array(
+ 'poster_id' => $this->get_data('poster_id'),
+ 'username' => $this->get_data('post_username'),
+ )), $responders);
+
+ foreach ($responders as $responder)
+ {
+ if ($responder['username'])
+ {
+ $usernames[] = $responder['username'];
+ }
+ else
+ {
+ $usernames[] = $this->user_loader->get_username($responder['poster_id'], 'no_profile');
+ }
+ }
+
+ return $this->user->lang(
+ $this->language_key,
+ implode(', ', $usernames),
+ censor_text($this->get_data('topic_title'))
+ );
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return 'topic_notify';
+ }
+
+ /**
+ * Get email template variables
+ *
+ * @return array
+ */
+ public function get_email_template_variables()
+ {
+ if ($this->get_data('post_username'))
+ {
+ $username = $this->get_data('post_username');
+ }
+ else
+ {
+ $username = $this->user_loader->get_username($this->get_data('poster_id'), 'username');
+ }
+
+ return array(
+ 'AUTHOR_NAME' => htmlspecialchars_decode($username),
+ 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($this->get_data('post_subject'))),
+ 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($this->get_data('topic_title'))),
+
+ 'U_VIEW_POST' => generate_board_url() . "/viewtopic.{$this->php_ext}?p={$this->item_id}#p{$this->item_id}",
+ 'U_NEWEST_POST' => generate_board_url() . "/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}&view=unread#unread",
+ 'U_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}",
+ 'U_VIEW_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}",
+ 'U_FORUM' => generate_board_url() . "/viewforum.{$this->php_ext}?f={$this->get_data('forum_id')}",
+ 'U_STOP_WATCHING_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?uid={$this->user_id}&f={$this->get_data('forum_id')}&t={$this->item_parent_id}&unwatch=topic",
+ );
+ }
+
+ /**
+ * Get the url to this item
+ *
+ * @return string URL
+ */
+ public function get_url()
+ {
+ return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "p={$this->item_id}#p{$this->item_id}");
+ }
+
+ /**
+ * Users needed to query before this notification can be displayed
+ *
+ * @return array Array of user_ids
+ */
+ public function users_to_query()
+ {
+ $responders = $this->get_data('responders');
+ $users = array(
+ $this->get_data('poster_id'),
+ );
+
+ if (is_array($responders))
+ {
+ foreach ($responders as $responder)
+ {
+ $users[] = $responder['poster_id'];
+ }
+ }
+
+ return $users;
+ }
+
+ /**
+ * Pre create insert array function
+ * This allows you to perform certain actions, like run a query
+ * and load data, before create_insert_array() is run. The data
+ * returned from this function will be sent to create_insert_array().
+ *
+ * @param array $post Post data from submit_post
+ * @param array $notify_users Notify users list
+ * Formated from find_users_for_notification()
+ * @return array Whatever you want to send to create_insert_array().
+ */
+ public function pre_create_insert_array($post, $notify_users)
+ {
+ if (!sizeof($notify_users))
+ {
+ return array();
+ }
+
+ $tracking_data = array();
+ $sql = 'SELECT user_id, mark_time FROM ' . TOPICS_TRACK_TABLE . '
+ WHERE topic_id = ' . (int) $post['topic_id'] . '
+ AND ' . $this->db->sql_in_set('user_id', array_keys($notify_users));
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $tracking_data[$row['user_id']] = $row['mark_time'];
+ }
+
+ return $tracking_data;
+ }
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $post Data from submit_post
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ *
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($post, $pre_create_data = array())
+ {
+ $this->set_data('poster_id', $post['poster_id']);
+
+ $this->set_data('topic_title', $post['topic_title']);
+
+ $this->set_data('post_subject', $post['post_subject']);
+
+ $this->set_data('post_username', (($post['poster_id'] == ANONYMOUS) ? $post['post_username'] : ''));
+
+ $this->set_data('forum_id', $post['forum_id']);
+
+ $this->set_data('forum_name', $post['forum_name']);
+
+ $this->notification_time = $post['post_time'];
+
+ // Topics can be "read" before they are public (while awaiting approval).
+ // Make sure that if the user has read the topic, it's marked as read in the notification
+ if (isset($pre_create_data[$this->user_id]) && $pre_create_data[$this->user_id] >= $this->notification_time)
+ {
+ $this->notification_read = true;
+ }
+
+ return parent::create_insert_array($post, $pre_create_data);
+ }
+
+ /**
+ * Add responders to the notification
+ *
+ * @param mixed $post
+ */
+ public function add_responders($post)
+ {
+ // Do not add them as a responder if they were the original poster that created the notification
+ if ($this->get_data('poster_id') == $post['poster_id'])
+ {
+ return array('notification_data' => serialize($this->get_data(false)));
+ }
+
+ $responders = $this->get_data('responders');
+
+ $responders = ($responders === null) ? array() : $responders;
+
+ foreach ($responders as $responder)
+ {
+ // Do not add them as a responder multiple times
+ if ($responder['poster_id'] == $post['poster_id'])
+ {
+ return array('notification_data' => serialize($this->get_data(false)));
+ }
+ }
+
+ $responders[] = array(
+ 'poster_id' => $post['poster_id'],
+ 'username' => (($post['poster_id'] == ANONYMOUS) ? $post['post_username'] : ''),
+ );
+
+ $this->set_data('responders', $responders);
+
+ return array('notification_data' => serialize($this->get_data(false)));
+ }
+}
diff --git a/phpBB/includes/notification/type/post_in_queue.php b/phpBB/includes/notification/type/post_in_queue.php
new file mode 100644
index 0000000000..9c719205e6
--- /dev/null
+++ b/phpBB/includes/notification/type/post_in_queue.php
@@ -0,0 +1,147 @@
+ 'needs_approval',
+ 'lang' => 'NOTIFICATION_TYPE_IN_MODERATION_QUEUE',
+ 'group' => 'NOTIFICATION_GROUP_MODERATION',
+ );
+
+ /**
+ * Permission to check for (in find_users_for_notification)
+ *
+ * @var string Permission name
+ */
+ protected $permission = 'm_approve';
+
+ /**
+ * Is available
+ */
+ public function is_available()
+ {
+ $has_permission = $this->auth->acl_getf($this->permission, true);
+
+ return (!empty($has_permission));
+ }
+
+ /**
+ * Find the users who want to receive notifications
+ *
+ * @param array $post Data from the post
+ *
+ * @return array
+ */
+ public function find_users_for_notification($post, $options = array())
+ {
+ $options = array_merge(array(
+ 'ignore_users' => array(),
+ ), $options);
+
+ // 0 is for global
+ $auth_approve = $this->auth->acl_get_list(false, $this->permission, array($post['forum_id'], 0));
+
+ if (empty($auth_approve))
+ {
+ return array();
+ }
+
+ $has_permission = array();
+
+ if (isset($auth_approve[$post['forum_id']][$this->permission]))
+ {
+ $has_permission = $auth_approve[$post['forum_id']][$this->permission];
+ }
+
+ if (isset($auth_approve[0][$this->permission]))
+ {
+ $has_permission = array_unique(array_merge($has_permission, $auth_approve[0][$this->permission]));
+ }
+
+ return $this->check_user_notification_options($has_permission, array_merge($options, array(
+ 'item_type' => self::$notification_option['id'],
+ )));
+ }
+
+ /**
+ * Get the url to this item
+ *
+ * @return string URL
+ */
+ public function get_url()
+ {
+ return append_sid($this->phpbb_root_path . 'mcp.' . $this->php_ext, "i=queue&mode=approve_details&f={$this->get_data('forum_id')}&p={$this->item_id}");
+ }
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $post Data from submit_post
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ *
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($post, $pre_create_data = array())
+ {
+ $data = parent::create_insert_array($post, $pre_create_data);
+
+ $this->notification_time = $data['notification_time'] = time();
+
+ return $data;
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return 'post_in_queue';
+ }
+}
diff --git a/phpBB/includes/notification/type/quote.php b/phpBB/includes/notification/type/quote.php
new file mode 100644
index 0000000000..5453b267c8
--- /dev/null
+++ b/phpBB/includes/notification/type/quote.php
@@ -0,0 +1,221 @@
+ 'NOTIFICATION_TYPE_QUOTE',
+ 'group' => 'NOTIFICATION_GROUP_POSTING',
+ );
+
+ /**
+ * Is available
+ */
+ public function is_available()
+ {
+ return true;
+ }
+
+ /**
+ * Find the users who want to receive notifications
+ *
+ * @param array $post Data from
+ *
+ * @return array
+ */
+ public function find_users_for_notification($post, $options = array())
+ {
+ $options = array_merge(array(
+ 'ignore_users' => array(),
+ ), $options);
+
+ $usernames = false;
+ preg_match_all(self::$regular_expression_match, $post['post_text'], $usernames);
+
+ if (empty($usernames[1]))
+ {
+ return array();
+ }
+
+ $usernames[1] = array_unique($usernames[1]);
+
+ $usernames = array_map('utf8_clean_string', $usernames[1]);
+
+ $users = array();
+
+ $sql = 'SELECT user_id
+ FROM ' . USERS_TABLE . '
+ WHERE ' . $this->db->sql_in_set('username_clean', $usernames) . '
+ AND user_id <> ' . (int) $post['poster_id'];
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $users[] = $row['user_id'];
+ }
+ $this->db->sql_freeresult($result);
+
+ if (empty($users))
+ {
+ return array();
+ }
+
+ $auth_read = $this->auth->acl_get_list($users, 'f_read', $post['forum_id']);
+
+ if (empty($auth_read))
+ {
+ return array();
+ }
+
+ $notify_users = $this->check_user_notification_options($auth_read[$post['forum_id']]['f_read'], $options);
+
+ // Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications
+ $update_notifications = array();
+ $sql = 'SELECT n.*
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . " nt
+ WHERE n.item_type = '" . $this->get_type() . "'
+ AND n.item_parent_id = " . (int) self::get_item_parent_id($post) . '
+ AND n.notification_read = 0
+ AND nt.notification_type = n.item_type
+ AND nt.notification_type_enabled = 1';
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ // Do not create a new notification
+ unset($notify_users[$row['user_id']]);
+
+ $notification = $this->notification_manager->get_item_type_class($this->get_type(), $row);
+ $sql = 'UPDATE ' . $this->notifications_table . '
+ SET ' . $this->db->sql_build_array('UPDATE', $notification->add_responders($post)) . '
+ WHERE notification_id = ' . $row['notification_id'];
+ $this->db->sql_query($sql);
+ }
+ $this->db->sql_freeresult($result);
+
+ return $notify_users;
+ }
+
+ /**
+ * Update a notification
+ *
+ * @param array $data Data specific for this type that will be updated
+ */
+ public function update_notifications($post)
+ {
+ $old_notifications = array();
+ $sql = 'SELECT n.user_id
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . " nt
+ WHERE n.item_type = '" . $this->get_type() . "'
+ AND n.item_id = " . self::get_item_id($post) . '
+ AND nt.notification_type = n.item_type
+ AND nt.notification_type_enabled = 1';
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $old_notifications[] = $row['user_id'];
+ }
+ $this->db->sql_freeresult($result);
+
+ // Find the new users to notify
+ $notifications = $this->find_users_for_notification($post);
+
+ // Find the notifications we must delete
+ $remove_notifications = array_diff($old_notifications, array_keys($notifications));
+
+ // Find the notifications we must add
+ $add_notifications = array();
+ foreach (array_diff(array_keys($notifications), $old_notifications) as $user_id)
+ {
+ $add_notifications[$user_id] = $notifications[$user_id];
+ }
+
+ // Add the necessary notifications
+ $this->notification_manager->add_notifications_for_users($this->get_type(), $post, $add_notifications);
+
+ // Remove the necessary notifications
+ if (!empty($remove_notifications))
+ {
+ $sql = 'DELETE FROM ' . $this->notifications_table . "
+ WHERE item_type = '" . $this->get_type() . "'
+ AND item_id = " . self::get_item_id($post) . '
+ AND ' . $this->db->sql_in_set('user_id', $remove_notifications);
+ $this->db->sql_query($sql);
+ }
+
+ // return true to continue with the update code in the notifications service (this will update the rest of the notifications)
+ return true;
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return 'quote';
+ }
+
+ /**
+ * Get email template variables
+ *
+ * @return array
+ */
+ public function get_email_template_variables()
+ {
+ $user_data = $this->user_loader->get_user($this->get_data('poster_id'));
+
+ return array_merge(parent::get_email_template_variables(), array(
+ 'AUTHOR_NAME' => htmlspecialchars_decode($user_data['username']),
+ ));
+ }
+}
diff --git a/phpBB/includes/notification/type/report_pm.php b/phpBB/includes/notification/type/report_pm.php
new file mode 100644
index 0000000000..3fa73bab41
--- /dev/null
+++ b/phpBB/includes/notification/type/report_pm.php
@@ -0,0 +1,229 @@
+ 'report',
+ 'lang' => 'NOTIFICATION_TYPE_REPORT',
+ 'group' => 'NOTIFICATION_GROUP_MODERATION',
+ );
+
+ /**
+ * Get the id of the parent
+ *
+ * @param array $pm The data from the pm
+ */
+ public static function get_item_parent_id($pm)
+ {
+ return (int) $pm['report_id'];
+ }
+
+ /**
+ * Is this type available to the current user (defines whether or not it will be shown in the UCP Edit notification options)
+ *
+ * @return bool True/False whether or not this is available to the user
+ */
+ public function is_available()
+ {
+ $m_approve = $this->auth->acl_getf($this->permission, true);
+
+ return (!empty($m_approve));
+ }
+
+
+ /**
+ * Find the users who want to receive notifications
+ * (copied from post_in_queue)
+ *
+ * @param array $post Data from the post
+ *
+ * @return array
+ */
+ public function find_users_for_notification($post, $options = array())
+ {
+ $options = array_merge(array(
+ 'ignore_users' => array(),
+ ), $options);
+
+ // Global
+ $post['forum_id'] = 0;
+
+ $auth_approve = $this->auth->acl_get_list(false, $this->permission, $post['forum_id']);
+
+ if (empty($auth_approve))
+ {
+ return array();
+ }
+
+ if (($key = array_search($this->user->data['user_id'], $auth_approve[$post['forum_id']][$this->permission])))
+ {
+ unset($auth_approve[$post['forum_id']][$this->permission][$key]);
+ }
+
+ return $this->check_user_notification_options($auth_approve[$post['forum_id']][$this->permission], array_merge($options, array(
+ 'item_type' => self::$notification_option['id'],
+ )));
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return 'report_pm';
+ }
+
+ /**
+ * Get email template variables
+ *
+ * @return array
+ */
+ public function get_email_template_variables()
+ {
+ return array(
+ 'AUTHOR_NAME' => htmlspecialchars_decode($user_data['username']),
+ 'SUBJECT' => htmlspecialchars_decode(censor_text($this->get_data('message_subject'))),
+
+ 'U_VIEW_REPORT' => generate_board_url() . "mcp.{$this->php_ext}?r={$this->item_parent_id}&i=pm_reports&mode=pm_report_details",
+ );
+ }
+
+ /**
+ * Get the url to this item
+ *
+ * @return string URL
+ */
+ public function get_url()
+ {
+ return append_sid($this->phpbb_root_path . 'mcp.' . $this->php_ext, "r={$this->item_parent_id}&i=pm_reports&mode=pm_report_details");
+ }
+
+ /**
+ * Get the HTML formatted title of this notification
+ *
+ * @return string
+ */
+ public function get_title()
+ {
+ $this->user->add_lang('mcp');
+
+ $username = $this->user_loader->get_username($this->get_data('reporter_id'), 'no_profile');
+
+ if ($this->get_data('report_text'))
+ {
+ return $this->user->lang(
+ $this->language_key,
+ $username,
+ censor_text($this->get_data('message_subject')),
+ $this->get_data('report_text')
+ );
+ }
+
+ if (isset($this->user->lang[$this->get_data('reason_title')]))
+ {
+ return $this->user->lang(
+ $this->language_key,
+ $username,
+ censor_text($this->get_data('message_subject')),
+ $this->user->lang[$this->get_data('reason_title')]
+ );
+ }
+
+ return $this->user->lang(
+ $this->language_key,
+ $username,
+ censor_text($this->get_data('message_subject')),
+ $this->get_data('reason_description')
+ );
+ }
+
+ /**
+ * Get the user's avatar
+ */
+ public function get_avatar()
+ {
+ return $this->user_loader->get_avatar($this->get_data('reporter_id'));
+ }
+
+ /**
+ * Users needed to query before this notification can be displayed
+ *
+ * @return array Array of user_ids
+ */
+ public function users_to_query()
+ {
+ return array($this->get_data('reporter_id'));
+ }
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $post Data from submit_post
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ *
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($post, $pre_create_data = array())
+ {
+ $this->set_data('reporter_id', $this->user->data['user_id']);
+ $this->set_data('reason_title', strtoupper($post['reason_title']));
+ $this->set_data('reason_description', $post['reason_description']);
+ $this->set_data('report_text', $post['report_text']);
+
+ return parent::create_insert_array($post, $pre_create_data);
+ }
+}
diff --git a/phpBB/includes/notification/type/report_pm_closed.php b/phpBB/includes/notification/type/report_pm_closed.php
new file mode 100644
index 0000000000..63dfa92064
--- /dev/null
+++ b/phpBB/includes/notification/type/report_pm_closed.php
@@ -0,0 +1,155 @@
+user->data['user_id'])
+ {
+ return array();
+ }
+
+ return array($pm['reporter'] => array(''));
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return false;
+ }
+
+ /**
+ * Get email template variables
+ *
+ * @return array
+ */
+ public function get_email_template_variables()
+ {
+ return array();
+ }
+
+ /**
+ * Get the url to this item
+ *
+ * @return string URL
+ */
+ public function get_url()
+ {
+ return '';
+ }
+
+ /**
+ * Get the HTML formatted title of this notification
+ *
+ * @return string
+ */
+ public function get_title()
+ {
+ $username = $this->user_loader->get_username($this->get_data('closer_id'), 'no_profile');
+
+ return $this->user->lang(
+ $this->language_key,
+ $username,
+ censor_text($this->get_data('message_subject'))
+ );
+ }
+
+ /**
+ * Get the user's avatar
+ */
+ public function get_avatar()
+ {
+ return $this->get_user_avatar($this->get_data('closer_id'));
+ }
+
+ /**
+ * Users needed to query before this notification can be displayed
+ *
+ * @return array Array of user_ids
+ */
+ public function users_to_query()
+ {
+ return array($this->get_data('closer_id'));
+ }
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $pm PM Data
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ *
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($pm, $pre_create_data = array())
+ {
+ $this->set_data('closer_id', $pm['closer_id']);
+
+ $data = parent::create_insert_array($pm, $pre_create_data);
+
+ $this->notification_time = $data['notification_time'] = time();
+
+ return $data;
+ }
+}
diff --git a/phpBB/includes/notification/type/report_post.php b/phpBB/includes/notification/type/report_post.php
new file mode 100644
index 0000000000..de5c54a291
--- /dev/null
+++ b/phpBB/includes/notification/type/report_post.php
@@ -0,0 +1,196 @@
+ 'report',
+ 'lang' => 'NOTIFICATION_TYPE_REPORT',
+ 'group' => 'NOTIFICATION_GROUP_MODERATION',
+ );
+
+ /**
+ * Find the users who want to receive notifications
+ *
+ * @param array $post Data from the post
+ *
+ * @return array
+ */
+ public function find_users_for_notification($post, $options = array())
+ {
+ $notify_users = parent::find_users_for_notification($post, $options);
+
+ // never notify reporter
+ unset($notify_users[$this->user->data['user_id']]);
+
+ return $notify_users;
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return 'report_post';
+ }
+
+ /**
+ * Get email template variables
+ *
+ * @return array
+ */
+ public function get_email_template_variables()
+ {
+ $board_url = generate_board_url();
+
+ return array(
+ 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($this->get_data('post_subject'))),
+ 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($this->get_data('topic_title'))),
+
+ 'U_VIEW_REPORT' => "{$board_url}/mcp.{$this->php_ext}?f={$this->get_data('forum_id')}&p={$this->item_id}&i=reports&mode=report_details#reports",
+ 'U_VIEW_POST' => "{$board_url}/viewtopic.{$this->php_ext}?p={$this->item_id}#p{$this->item_id}",
+ 'U_NEWEST_POST' => "{$board_url}/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}&view=unread#unread",
+ 'U_TOPIC' => "{$board_url}/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}",
+ 'U_VIEW_TOPIC' => "{$board_url}/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}",
+ 'U_FORUM' => "{$board_url}/viewforum.{$this->php_ext}?f={$this->get_data('forum_id')}",
+ );
+ }
+
+ /**
+ * Get the url to this item
+ *
+ * @return string URL
+ */
+ public function get_url()
+ {
+ return append_sid($this->phpbb_root_path . 'mcp.' . $this->php_ext, "f={$this->get_data('forum_id')}&p={$this->item_id}&i=reports&mode=report_details#reports");
+ }
+
+ /**
+ * Get the HTML formatted title of this notification
+ *
+ * @return string
+ */
+ public function get_title()
+ {
+ $this->user->add_lang('mcp');
+
+ $username = $this->user_loader->get_username($this->get_data('reporter_id'), 'no_profile');
+
+ if ($this->get_data('report_text'))
+ {
+ return $this->user->lang(
+ $this->language_key,
+ $username,
+ censor_text($this->get_data('post_subject')),
+ $this->get_data('report_text')
+ );
+ }
+
+ if (isset($this->user->lang[$this->get_data('reason_title')]))
+ {
+ return $this->user->lang(
+ $this->language_key,
+ $username,
+ censor_text($this->get_data('post_subject')),
+ $this->user->lang[$this->get_data('reason_title')]
+ );
+ }
+
+ return $this->user->lang(
+ $this->language_key,
+ $username,
+ censor_text($this->get_data('post_subject')),
+ $this->get_data('reason_description')
+ );
+ }
+
+ /**
+ * Get the user's avatar
+ */
+ public function get_avatar()
+ {
+ return $this->user_loader->get_avatar($this->get_data('reporter_id'));
+ }
+
+ /**
+ * Users needed to query before this notification can be displayed
+ *
+ * @return array Array of user_ids
+ */
+ public function users_to_query()
+ {
+ return array($this->get_data('reporter_id'));
+ }
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $post Data from submit_post
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ *
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($post, $pre_create_data = array())
+ {
+ $this->set_data('reporter_id', $this->user->data['user_id']);
+ $this->set_data('reason_title', strtoupper($post['reason_title']));
+ $this->set_data('reason_description', $post['reason_description']);
+ $this->set_data('report_text', $post['report_text']);
+
+ return parent::create_insert_array($post, $pre_create_data);
+ }
+}
diff --git a/phpBB/includes/notification/type/report_post_closed.php b/phpBB/includes/notification/type/report_post_closed.php
new file mode 100644
index 0000000000..3916cd8db7
--- /dev/null
+++ b/phpBB/includes/notification/type/report_post_closed.php
@@ -0,0 +1,155 @@
+user->data['user_id'])
+ {
+ return array();
+ }
+
+ return array($post['reporter'] => array(''));
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return false;
+ }
+
+ /**
+ * Get email template variables
+ *
+ * @return array
+ */
+ public function get_email_template_variables()
+ {
+ return array();
+ }
+
+ /**
+ * Get the url to this item
+ *
+ * @return string URL
+ */
+ public function get_url()
+ {
+ return '';
+ }
+
+ /**
+ * Get the HTML formatted title of this notification
+ *
+ * @return string
+ */
+ public function get_title()
+ {
+ $username = $this->user_loader->get_username($this->get_data('closer_id'), 'no_profile');
+
+ return $this->user->lang(
+ $this->language_key,
+ $username,
+ censor_text($this->get_data('post_subject'))
+ );
+ }
+
+ /**
+ * Get the user's avatar
+ */
+ public function get_avatar()
+ {
+ return $this->user_loader->get_avatar($this->get_data('closer_id'));
+ }
+
+ /**
+ * Users needed to query before this notification can be displayed
+ *
+ * @return array Array of user_ids
+ */
+ public function users_to_query()
+ {
+ return array($this->get_data('closer_id'));
+ }
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $post Data from submit_post
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ *
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($post, $pre_create_data = array())
+ {
+ $this->set_data('closer_id', $post['closer_id']);
+
+ $data = parent::create_insert_array($post, $pre_create_data);
+
+ $this->notification_time = $data['notification_time'] = time();
+
+ return $data;
+ }
+}
diff --git a/phpBB/includes/notification/type/topic.php b/phpBB/includes/notification/type/topic.php
new file mode 100644
index 0000000000..22436d3fb1
--- /dev/null
+++ b/phpBB/includes/notification/type/topic.php
@@ -0,0 +1,277 @@
+ 'NOTIFICATION_TYPE_TOPIC',
+ 'group' => 'NOTIFICATION_GROUP_POSTING',
+ );
+
+ /**
+ * Is available
+ */
+ public function is_available()
+ {
+ return $this->config['allow_forum_notify'];
+ }
+
+ /**
+ * Get the id of the item
+ *
+ * @param array $post The data from the post
+ */
+ public static function get_item_id($post)
+ {
+ return (int) $post['topic_id'];
+ }
+
+ /**
+ * Get the id of the parent
+ *
+ * @param array $post The data from the post
+ */
+ public static function get_item_parent_id($post)
+ {
+ return (int) $post['forum_id'];
+ }
+
+ /**
+ * Find the users who want to receive notifications
+ *
+ * @param array $topic Data from the topic
+ *
+ * @return array
+ */
+ public function find_users_for_notification($topic, $options = array())
+ {
+ $options = array_merge(array(
+ 'ignore_users' => array(),
+ ), $options);
+
+ $users = array();
+
+ $sql = 'SELECT user_id
+ FROM ' . FORUMS_WATCH_TABLE . '
+ WHERE forum_id = ' . (int) $topic['forum_id'] . '
+ AND notify_status = ' . NOTIFY_YES . '
+ AND user_id <> ' . (int) $topic['poster_id'];
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $users[] = $row['user_id'];
+ }
+ $this->db->sql_freeresult($result);
+
+ if (empty($users))
+ {
+ return array();
+ }
+
+ $auth_read = $this->auth->acl_get_list($users, 'f_read', $topic['forum_id']);
+
+ if (empty($auth_read))
+ {
+ return array();
+ }
+
+ return $this->check_user_notification_options($auth_read[$topic['forum_id']]['f_read'], $options);
+ }
+
+ /**
+ * Get the user's avatar
+ */
+ public function get_avatar()
+ {
+ return $this->user_loader->get_avatar($this->get_data('poster_id'));
+ }
+
+ /**
+ * Get the HTML formatted title of this notification
+ *
+ * @return string
+ */
+ public function get_title()
+ {
+ if ($this->get_data('post_username'))
+ {
+ $username = $this->get_data('post_username');
+ }
+ else
+ {
+ $username = $this->user_loader->get_username($this->get_data('poster_id'), 'no_profile');
+ }
+
+ return $this->user->lang(
+ $this->language_key,
+ $username,
+ censor_text($this->get_data('topic_title')),
+ $this->get_data('forum_name')
+ );
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return 'newtopic_notify';
+ }
+
+ /**
+ * Get email template variables
+ *
+ * @return array
+ */
+ public function get_email_template_variables()
+ {
+ $board_url = generate_board_url();
+
+ if ($this->get_data('post_username'))
+ {
+ $username = $this->get_data('post_username');
+ }
+ else
+ {
+ $username = $this->user_loader->get_username($this->get_data('poster_id'), 'username');
+ }
+
+ return array(
+ 'AUTHOR_NAME' => htmlspecialchars_decode($username),
+ 'FORUM_NAME' => htmlspecialchars_decode($this->get_data('forum_name')),
+ 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($this->get_data('topic_title'))),
+
+ 'U_TOPIC' => "{$board_url}/viewtopic.{$this->php_ext}?f={$this->item_parent_id}&t={$this->item_id}",
+ 'U_VIEW_TOPIC' => "{$board_url}/viewtopic.{$this->php_ext}?f={$this->item_parent_id}&t={$this->item_id}",
+ 'U_FORUM' => "{$board_url}/viewforum.{$this->php_ext}?f={$this->item_parent_id}",
+ 'U_STOP_WATCHING_FORUM' => "{$board_url}/viewforum.{$this->php_ext}?uid={$this->user_id}&f={$this->item_parent_id}&unwatch=forum",
+ );
+ }
+
+ /**
+ * Get the url to this item
+ *
+ * @return string URL
+ */
+ public function get_url()
+ {
+ return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "f={$this->item_parent_id}&t={$this->item_id}");
+ }
+
+ /**
+ * Users needed to query before this notification can be displayed
+ *
+ * @return array Array of user_ids
+ */
+ public function users_to_query()
+ {
+ return array($this->get_data('poster_id'));
+ }
+
+ /**
+ * Pre create insert array function
+ * This allows you to perform certain actions, like run a query
+ * and load data, before create_insert_array() is run. The data
+ * returned from this function will be sent to create_insert_array().
+ *
+ * @param array $post Post data from submit_post
+ * @param array $notify_users Notify users list
+ * Formated from find_users_for_notification()
+ * @return array Whatever you want to send to create_insert_array().
+ */
+ public function pre_create_insert_array($post, $notify_users)
+ {
+ if (!sizeof($notify_users))
+ {
+ return array();
+ }
+
+ $tracking_data = array();
+ $sql = 'SELECT user_id, mark_time FROM ' . TOPICS_TRACK_TABLE . '
+ WHERE topic_id = ' . (int) $post['topic_id'] . '
+ AND ' . $this->db->sql_in_set('user_id', array_keys($notify_users));
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $tracking_data[$row['user_id']] = $row['mark_time'];
+ }
+
+ return $tracking_data;
+ }
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $post Data from submit_post
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ *
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($post, $pre_create_data = array())
+ {
+ $this->set_data('poster_id', $post['poster_id']);
+
+ $this->set_data('topic_title', $post['topic_title']);
+
+ $this->set_data('post_username', (($post['poster_id'] == ANONYMOUS) ? $post['post_username'] : ''));
+
+ $this->set_data('forum_name', $post['forum_name']);
+
+ $this->notification_time = $post['post_time'];
+
+ // Topics can be "read" before they are public (while awaiting approval).
+ // Make sure that if the user has read the topic, it's marked as read in the notification
+ if (isset($pre_create_data[$this->user_id]) && $pre_create_data[$this->user_id] >= $this->notification_time)
+ {
+ $this->notification_read = true;
+ }
+
+ return parent::create_insert_array($post, $pre_create_data);
+ }
+}
diff --git a/phpBB/includes/notification/type/topic_in_queue.php b/phpBB/includes/notification/type/topic_in_queue.php
new file mode 100644
index 0000000000..c501434c43
--- /dev/null
+++ b/phpBB/includes/notification/type/topic_in_queue.php
@@ -0,0 +1,147 @@
+ 'needs_approval',
+ 'lang' => 'NOTIFICATION_TYPE_IN_MODERATION_QUEUE',
+ 'group' => 'NOTIFICATION_GROUP_MODERATION',
+ );
+
+ /**
+ * Permission to check for (in find_users_for_notification)
+ *
+ * @var string Permission name
+ */
+ protected $permission = 'm_approve';
+
+ /**
+ * Is available
+ */
+ public function is_available()
+ {
+ $has_permission = $this->auth->acl_getf($this->permission, true);
+
+ return (!empty($has_permission));
+ }
+
+ /**
+ * Find the users who want to receive notifications
+ *
+ * @param array $topic Data from the topic
+ *
+ * @return array
+ */
+ public function find_users_for_notification($topic, $options = array())
+ {
+ $options = array_merge(array(
+ 'ignore_users' => array(),
+ ), $options);
+
+ // 0 is for global
+ $auth_approve = $this->auth->acl_get_list(false, 'm_approve', array($topic['forum_id'], 0));
+
+ if (empty($auth_approve))
+ {
+ return array();
+ }
+
+ $has_permission = array();
+
+ if (isset($auth_approve[$topic['forum_id']][$this->permission]))
+ {
+ $has_permission = $auth_approve[$topic['forum_id']][$this->permission];
+ }
+
+ if (isset($auth_approve[0][$this->permission]))
+ {
+ $has_permission = array_unique(array_merge($has_permission, $auth_approve[0][$this->permission]));
+ }
+
+ return $this->check_user_notification_options($has_permission, array_merge($options, array(
+ 'item_type' => self::$notification_option['id'],
+ )));
+ }
+
+ /**
+ * Get the url to this item
+ *
+ * @return string URL
+ */
+ public function get_url()
+ {
+ return append_sid($this->phpbb_root_path . 'mcp.' . $this->php_ext, "i=queue&mode=approve_details&f={$this->item_parent_id}&t={$this->item_id}");
+ }
+
+ /**
+ * Function for preparing the data for insertion in an SQL query
+ * (The service handles insertion)
+ *
+ * @param array $topic Data from submit_post
+ * @param array $pre_create_data Data from pre_create_insert_array()
+ *
+ * @return array Array of data ready to be inserted into the database
+ */
+ public function create_insert_array($topic, $pre_create_data = array())
+ {
+ $data = parent::create_insert_array($topic, $pre_create_data);
+
+ $this->notification_time = $data['notification_time'] = time();
+
+ return $data;
+ }
+
+ /**
+ * Get email template
+ *
+ * @return string|bool
+ */
+ public function get_email_template()
+ {
+ return 'topic_in_queue';
+ }
+}
diff --git a/phpBB/includes/search/fulltext_sphinx.php b/phpBB/includes/search/fulltext_sphinx.php
index 48445d0794..28761792ec 100644
--- a/phpBB/includes/search/fulltext_sphinx.php
+++ b/phpBB/includes/search/fulltext_sphinx.php
@@ -258,13 +258,13 @@ class phpbb_search_fulltext_sphinx
$config_object = new phpbb_search_sphinx_config($this->config_file_data);
$config_data = array(
'source source_phpbb_' . $this->id . '_main' => array(
- array('type', $this->dbtype),
+ array('type', $this->dbtype . ' # mysql or pgsql'),
// This config value sql_host needs to be changed incase sphinx and sql are on different servers
- array('sql_host', $dbhost),
+ array('sql_host', $dbhost . ' # SQL server host sphinx connects to'),
array('sql_user', $dbuser),
array('sql_pass', $dbpasswd),
array('sql_db', $dbname),
- array('sql_port', $dbport),
+ array('sql_port', $dbport . ' # optional, default is 3306 for mysql and 5432 for pgsql'),
array('sql_query_pre', 'SET NAMES \'utf8\''),
array('sql_query_pre', 'UPDATE ' . SPHINX_TABLE . ' SET max_doc_id = (SELECT MAX(post_id) FROM ' . POSTS_TABLE . ') WHERE counter_id = 1'),
array('sql_query_range', 'SELECT MIN(post_id), MAX(post_id) FROM ' . POSTS_TABLE . ''),
diff --git a/phpBB/includes/search/sphinx/config_variable.php b/phpBB/includes/search/sphinx/config_variable.php
index 35abe281cb..2c1d35a49c 100644
--- a/phpBB/includes/search/sphinx/config_variable.php
+++ b/phpBB/includes/search/sphinx/config_variable.php
@@ -75,6 +75,6 @@ class phpbb_search_sphinx_config_variable
*/
function to_string()
{
- return "\t" . $this->name . ' = ' . str_replace("\n", "\\\n", $this->value) . ' ' . $this->comment . "\n";
+ return "\t" . $this->name . ' = ' . str_replace("\n", " \\\n", $this->value) . ' ' . $this->comment . "\n";
}
}
diff --git a/phpBB/includes/style/extension_path_provider.php b/phpBB/includes/style/extension_path_provider.php
index 4eac300424..6976a45ed0 100644
--- a/phpBB/includes/style/extension_path_provider.php
+++ b/phpBB/includes/style/extension_path_provider.php
@@ -92,7 +92,7 @@ class phpbb_style_extension_path_provider extends phpbb_extension_provider imple
if ($path && !phpbb_is_absolute($path))
{
$result = $finder->directory('/' . $this->ext_dir_prefix . $path)
- ->get_directories(true, true);
+ ->get_directories(true, false, true);
foreach ($result as $ext => $ext_path)
{
$directories[$ext][] = $ext_path;
diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php
index f73ad28ba1..9e8ad2fef0 100644
--- a/phpBB/includes/template/filter.php
+++ b/phpBB/includes/template/filter.php
@@ -843,7 +843,18 @@ class phpbb_template_filter extends php_user_filter
return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');';
}
- $parsed_statement = implode(' ', $this->compile_expression($match[3]));
+ /*
+ * Define tags that contain template variables (enclosed in curly brackets)
+ * need to be treated differently.
+ */
+ if (substr($match[3], 1, 1) == '{' && substr($match[3], -2, 1) == '}')
+ {
+ $parsed_statement = implode(' ', $this->compile_expression(substr($match[3], 2, -2)));
+ }
+ else
+ {
+ $parsed_statement = implode(' ', $this->compile_expression($match[3]));
+ }
return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $parsed_statement . ';';
}
diff --git a/phpBB/includes/ucp/info/ucp_notifications.php b/phpBB/includes/ucp/info/ucp_notifications.php
new file mode 100644
index 0000000000..98d8b9db61
--- /dev/null
+++ b/phpBB/includes/ucp/info/ucp_notifications.php
@@ -0,0 +1,35 @@
+ 'ucp_notifications',
+ 'title' => 'UCP_NOTIFICATION_OPTIONS',
+ 'version' => '1.0.0',
+ 'modes' => array(
+ 'notification_options' => array('title' => 'UCP_NOTIFICATION_OPTIONS', 'auth' => '', 'cat' => array('UCP_PREFS')),
+ 'notification_list' => array('title' => 'UCP_NOTIFICATION_LIST', 'auth' => '', 'cat' => array('UCP_MAIN')),
+ ),
+ );
+ }
+
+ function install()
+ {
+ }
+
+ function uninstall()
+ {
+ }
+}
diff --git a/phpBB/includes/ucp/info/ucp_profile.php b/phpBB/includes/ucp/info/ucp_profile.php
index 3581a7f533..e974cea713 100644
--- a/phpBB/includes/ucp/info/ucp_profile.php
+++ b/phpBB/includes/ucp/info/ucp_profile.php
@@ -21,7 +21,7 @@ class ucp_profile_info
'modes' => array(
'profile_info' => array('title' => 'UCP_PROFILE_PROFILE_INFO', 'auth' => 'acl_u_chgprofileinfo', 'cat' => array('UCP_PROFILE')),
'signature' => array('title' => 'UCP_PROFILE_SIGNATURE', 'auth' => 'acl_u_sig', 'cat' => array('UCP_PROFILE')),
- 'avatar' => array('title' => 'UCP_PROFILE_AVATAR', 'auth' => 'cfg_allow_avatar && (cfg_allow_avatar_local || cfg_allow_avatar_remote || cfg_allow_avatar_upload || cfg_allow_avatar_remote_upload)', 'cat' => array('UCP_PROFILE')),
+ 'avatar' => array('title' => 'UCP_PROFILE_AVATAR', 'auth' => 'cfg_allow_avatar', 'cat' => array('UCP_PROFILE')),
'reg_details' => array('title' => 'UCP_PROFILE_REG_DETAILS', 'auth' => '', 'cat' => array('UCP_PROFILE')),
'autologin_keys'=> array('title' => 'UCP_PROFILE_AUTOLOGIN_KEYS', 'auth' => '', 'cat' => array('UCP_PROFILE')),
),
diff --git a/phpBB/includes/ucp/ucp_groups.php b/phpBB/includes/ucp/ucp_groups.php
index b9a06bc3b4..8516682633 100644
--- a/phpBB/includes/ucp/ucp_groups.php
+++ b/phpBB/includes/ucp/ucp_groups.php
@@ -27,7 +27,7 @@ class ucp_groups
{
global $config, $phpbb_root_path, $phpEx, $phpbb_admin_path;
global $db, $user, $auth, $cache, $template;
- global $request;
+ global $request, $phpbb_container;
$user->add_lang('groups');
@@ -438,7 +438,7 @@ class ucp_groups
$group_name = $group_row['group_name'];
$group_type = $group_row['group_type'];
- $avatar_img = (!empty($group_row['group_avatar'])) ? get_user_avatar($group_row['group_avatar'], $group_row['group_avatar_type'], $group_row['group_avatar_width'], $group_row['group_avatar_height'], 'GROUP_AVATAR') : '';
+ $avatar = phpbb_get_group_avatar($group_row, 'GROUP_AVATAR', true);
$template->assign_vars(array(
'GROUP_NAME' => ($group_type == GROUP_SPECIAL) ? $user->lang['G_' . $group_name] : $group_name,
@@ -447,8 +447,8 @@ class ucp_groups
'GROUP_DESC_DISP' => generate_text_for_display($group_row['group_desc'], $group_row['group_desc_uid'], $group_row['group_desc_bitfield'], $group_row['group_desc_options']),
'GROUP_TYPE' => $group_row['group_type'],
- 'AVATAR' => $avatar_img,
- 'AVATAR_IMAGE' => $avatar_img,
+ 'AVATAR' => (empty($avatar) ? '' : $avatar),
+ 'AVATAR_IMAGE' => (empty($avatar) ? '' : $avatar),
'AVATAR_WIDTH' => (isset($group_row['group_avatar_width'])) ? $group_row['group_avatar_width'] : '',
'AVATAR_HEIGHT' => (isset($group_row['group_avatar_height'])) ? $group_row['group_avatar_height'] : '',
));
@@ -483,10 +483,20 @@ class ucp_groups
$error = array();
- $avatar_select = basename(request_var('avatar_select', ''));
- $category = basename(request_var('category', ''));
+ // Setup avatar data for later
+ $avatars_enabled = false;
+ $avatar_drivers = null;
+ $avatar_data = null;
+ $avatar_error = array();
- $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false;
+ if ($config['allow_avatar'])
+ {
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers();
+
+ // This is normalised data, without the group_ prefix
+ $avatar_data = phpbb_avatar_manager::clean_row($group_row);
+ }
// Did we submit?
if ($update)
@@ -507,87 +517,36 @@ class ucp_groups
'max_recipients'=> request_var('group_max_recipients', 0),
);
- $data['uploadurl'] = request_var('uploadurl', '');
- $data['remotelink'] = request_var('remotelink', '');
- $data['width'] = request_var('width', '');
- $data['height'] = request_var('height', '');
- $delete = request_var('delete', '');
-
- $uploadfile = $request->file('uploadfile');
- if (!empty($uploadfile['tmp_name']) || $data['uploadurl'] || $data['remotelink'])
+ if ($config['allow_avatar'])
{
- // Avatar stuff
- $var_ary = array(
- 'uploadurl' => array('string', true, 5, 255),
- 'remotelink' => array('string', true, 5, 255),
- 'width' => array('string', true, 1, 3),
- 'height' => array('string', true, 1, 3),
- );
+ // Handle avatar
+ $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', ''));
+ $config_name = preg_replace('#^avatar\.driver.#', '', $driver_name);
- if (!($error = validate_data($data, $var_ary)))
+ if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete'))
{
- $data['user_id'] = "g$group_id";
+ $driver = $phpbb_avatar_manager->get_driver($driver_name);
+ $result = $driver->process_form($request, $template, $user, $avatar_data, $avatar_error);
- if ((!empty($uploadfile['tmp_name']) || $data['uploadurl']) && $can_upload)
+ if ($result && empty($avatar_error))
{
- list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_upload($data, $error);
- }
- else if ($data['remotelink'])
- {
- list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_remote($data, $error);
+ $result['avatar_type'] = $driver_name;
+
+ $submit_ary = array_merge($submit_ary, $result);
}
}
- }
- else if ($avatar_select && $config['allow_avatar_local'])
- {
- // check avatar gallery
- if (is_dir($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category))
+ else
{
- $submit_ary['avatar_type'] = AVATAR_GALLERY;
-
- list($submit_ary['avatar_width'], $submit_ary['avatar_height']) = getimagesize($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category . '/' . $avatar_select);
- $submit_ary['avatar'] = $category . '/' . $avatar_select;
- }
- }
- else if ($delete)
- {
- $submit_ary['avatar'] = '';
- $submit_ary['avatar_type'] = $submit_ary['avatar_width'] = $submit_ary['avatar_height'] = 0;
- }
- else if ($data['width'] && $data['height'])
- {
- // Only update the dimensions?
- if ($config['avatar_max_width'] || $config['avatar_max_height'])
- {
- if ($data['width'] > $config['avatar_max_width'] || $data['height'] > $config['avatar_max_height'])
+ if ($driver = $phpbb_avatar_manager->get_driver($user->data['user_avatar_type']))
{
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
+ $driver->delete($avatar_data);
}
- }
- if (!sizeof($error))
- {
- if ($config['avatar_min_width'] || $config['avatar_min_height'])
- {
- if ($data['width'] < $config['avatar_min_width'] || $data['height'] < $config['avatar_min_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
- }
- }
- }
-
- if (!sizeof($error))
- {
- $submit_ary['avatar_width'] = $data['width'];
- $submit_ary['avatar_height'] = $data['height'];
- }
- }
-
- if ((isset($submit_ary['avatar']) && $submit_ary['avatar'] && (!isset($group_row['group_avatar']))) || $delete)
- {
- if (isset($group_row['group_avatar']) && $group_row['group_avatar'])
- {
- avatar_delete('group', $group_row, true);
+ // Removing the avatar
+ $submit_ary['avatar_type'] = '';
+ $submit_ary['avatar'] = '';
+ $submit_ary['avatar_width'] = 0;
+ $submit_ary['avatar_height'] = 0;
}
}
@@ -607,7 +566,7 @@ class ucp_groups
'rank' => 'int',
'colour' => 'string',
'avatar' => 'string',
- 'avatar_type' => 'int',
+ 'avatar_type' => 'string',
'avatar_width' => 'int',
'avatar_height' => 'int',
'receive_pm' => 'int',
@@ -683,28 +642,48 @@ class ucp_groups
$type_closed = ($group_type == GROUP_CLOSED) ? ' checked="checked"' : '';
$type_hidden = ($group_type == GROUP_HIDDEN) ? ' checked="checked"' : '';
- $display_gallery = (isset($_POST['display_gallery'])) ? true : false;
-
- if ($config['allow_avatar'] && $config['allow_avatar_local'] && $display_gallery)
+ // Load up stuff for avatars
+ if ($config['allow_avatar'])
{
- avatar_gallery($category, $avatar_select, 4);
+ $avatars_enabled = false;
+ $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $avatar_data['avatar_type']));
+
+ foreach ($avatar_drivers as $current_driver)
+ {
+ $driver = $phpbb_avatar_manager->get_driver($current_driver);
+
+ $avatars_enabled = true;
+ $template->set_filenames(array(
+ 'avatar' => $driver->get_template_name(),
+ ));
+
+ if ($driver->prepare_form($request, $template, $user, $avatar_data, $avatar_error))
+ {
+ $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver);
+ $driver_upper = strtoupper($driver_name);
+ $template->assign_block_vars('avatar_drivers', array(
+ 'L_TITLE' => $user->lang($driver_upper . '_TITLE'),
+ 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'),
+
+ 'DRIVER' => $driver_name,
+ 'SELECTED' => $current_driver == $selected_driver,
+ 'OUTPUT' => $template->assign_display('avatar'),
+ ));
+ }
+ }
}
- $avatars_enabled = ($config['allow_avatar'] && (($can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) || ($config['allow_avatar_local'] || $config['allow_avatar_remote']))) ? true : false;
+ // Merge any avatars errors into the primary error array
+ $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error));
$template->assign_vars(array(
'S_EDIT' => true,
'S_INCLUDE_SWATCH' => true,
- 'S_FORM_ENCTYPE' => ($config['allow_avatar'] && $can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) ? ' enctype="multipart/form-data"' : '',
+ 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"',
'S_ERROR' => (sizeof($error)) ? true : false,
'S_SPECIAL_GROUP' => ($group_type == GROUP_SPECIAL) ? true : false,
- 'S_AVATARS_ENABLED' => $avatars_enabled,
- 'S_DISPLAY_GALLERY' => ($config['allow_avatar'] && $config['allow_avatar_local'] && !$display_gallery) ? true : false,
- 'S_IN_GALLERY' => ($config['allow_avatar_local'] && $display_gallery) ? true : false,
-
- 'S_UPLOAD_AVATAR_FILE' => ($config['allow_avatar'] && $config['allow_avatar_upload'] && $can_upload) ? true : false,
- 'S_UPLOAD_AVATAR_URL' => ($config['allow_avatar'] && $config['allow_avatar_remote_upload'] && $can_upload) ? true : false,
- 'S_LINK_AVATAR' => ($config['allow_avatar'] && $config['allow_avatar_remote']) ? true : false,
+ 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled),
+ 'S_GROUP_MANAGE' => true,
'ERROR_MSG' => (sizeof($error)) ? implode(' ', $error) : '',
'GROUP_RECEIVE_PM' => (isset($group_row['group_receive_pm']) && $group_row['group_receive_pm']) ? ' checked="checked"' : '',
@@ -717,7 +696,6 @@ class ucp_groups
'S_DESC_SMILIES_CHECKED'=> $group_desc_data['allow_smilies'],
'S_RANK_OPTIONS' => $rank_options,
- 'AVATAR_MAX_FILESIZE' => $config['avatar_filesize'],
'GROUP_TYPE_FREE' => GROUP_FREE,
'GROUP_TYPE_OPEN' => GROUP_OPEN,
diff --git a/phpBB/includes/ucp/ucp_notifications.php b/phpBB/includes/ucp/ucp_notifications.php
new file mode 100644
index 0000000000..338c921e94
--- /dev/null
+++ b/phpBB/includes/ucp/ucp_notifications.php
@@ -0,0 +1,226 @@
+variable('start', 0);
+ $form_time = min($request->variable('form_time', 0), time());
+
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ switch ($mode)
+ {
+ case 'notification_options':
+ $subscriptions = $phpbb_notifications->get_global_subscriptions(false);
+
+ // Add/remove subscriptions
+ if ($request->is_set_post('submit'))
+ {
+ if (!check_form_key('ucp_notification'))
+ {
+ trigger_error('FORM_INVALID');
+ }
+
+ $notification_methods = $phpbb_notifications->get_subscription_methods();
+
+ foreach($phpbb_notifications->get_subscription_types() as $group => $subscription_types)
+ {
+ foreach($subscription_types as $type => $data)
+ {
+ foreach($notification_methods as $method => $method_data)
+ {
+ if ($request->is_set_post($type . '_' . $method_data['id']) && (!isset($subscriptions[$type]) || !in_array($method_data['id'], $subscriptions[$type])))
+ {
+ $phpbb_notifications->add_subscription($type, 0, $method_data['id']);
+ }
+ else if (!$request->is_set_post($type . '_' . $method_data['id']) && isset($subscriptions[$type]) && in_array($method_data['id'], $subscriptions[$type]))
+ {
+ $phpbb_notifications->delete_subscription($type, 0, $method_data['id']);
+ }
+ }
+
+ if ($request->is_set_post($type . '_notification') && !isset($subscriptions[$type]))
+ {
+ $phpbb_notifications->add_subscription($type);
+ }
+ else if (!$request->is_set_post($type . '_notification') && isset($subscriptions[$type]))
+ {
+ $phpbb_notifications->delete_subscription($type);
+ }
+ }
+ }
+
+ meta_refresh(3, $this->u_action);
+ $message = $user->lang['PREFERENCES_UPDATED'] . '
' . sprintf($user->lang['RETURN_UCP'], '', '');
+ trigger_error($message);
+ }
+ }
+ else
+ {
+ $error[] = 'FORM_INVALID';
}
}
- else
+
+ $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $user->data['user_avatar_type']));
+
+ foreach ($avatar_drivers as $current_driver)
{
- $error[] = 'FORM_INVALID';
+ $driver = $phpbb_avatar_manager->get_driver($current_driver);
+
+ $avatars_enabled = true;
+ $template->set_filenames(array(
+ 'avatar' => $driver->get_template_name(),
+ ));
+
+ if ($driver->prepare_form($request, $template, $user, $avatar_data, $error))
+ {
+ $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver);
+ $driver_upper = strtoupper($driver_name);
+
+ $template->assign_block_vars('avatar_drivers', array(
+ 'L_TITLE' => $user->lang($driver_upper . '_TITLE'),
+ 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'),
+
+ 'DRIVER' => $driver_name,
+ 'SELECTED' => $current_driver == $selected_driver,
+ 'OUTPUT' => $template->assign_display('avatar'),
+ ));
+ }
}
- // Replace "error" strings with their real, localised form
- $error = array_map(array($user, 'lang'), $error);
}
- if (!$config['allow_avatar'] && $user->data['user_avatar_type'])
- {
- $error[] = $user->lang['AVATAR_NOT_ALLOWED'];
- }
- else if ((($user->data['user_avatar_type'] == AVATAR_UPLOAD) && !$config['allow_avatar_upload']) ||
- (($user->data['user_avatar_type'] == AVATAR_REMOTE) && !$config['allow_avatar_remote']) ||
- (($user->data['user_avatar_type'] == AVATAR_GALLERY) && !$config['allow_avatar_local']))
- {
- $error[] = $user->lang['AVATAR_TYPE_NOT_ALLOWED'];
- }
+ // Replace "error" strings with their real, localised form
+ $error = $phpbb_avatar_manager->localize_errors($user, $error);
+
+ $avatar = phpbb_get_user_avatar($user->data, 'USER_AVATAR', true);
$template->assign_vars(array(
'ERROR' => (sizeof($error)) ? implode(' ', $error) : '',
- 'AVATAR' => get_user_avatar($user->data['user_avatar'], $user->data['user_avatar_type'], $user->data['user_avatar_width'], $user->data['user_avatar_height'], 'USER_AVATAR', true),
- 'AVATAR_SIZE' => $config['avatar_filesize'],
+ 'AVATAR' => $avatar,
- 'U_GALLERY' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=profile&mode=avatar&display_gallery=1'),
-
- 'S_FORM_ENCTYPE' => ($can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) ? ' enctype="multipart/form-data"' : '',
+ 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"',
'L_AVATAR_EXPLAIN' => phpbb_avatar_explanation_string(),
+
+ 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled),
));
- if ($config['allow_avatar'] && $display_gallery && $auth->acl_get('u_chgavatar') && $config['allow_avatar_local'])
- {
- avatar_gallery($category, $avatar_select, 4);
- }
- else if ($config['allow_avatar'])
- {
- $avatars_enabled = (($can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) || ($auth->acl_get('u_chgavatar') && ($config['allow_avatar_local'] || $config['allow_avatar_remote']))) ? true : false;
-
- $template->assign_vars(array(
- 'AVATAR_WIDTH' => request_var('width', $user->data['user_avatar_width']),
- 'AVATAR_HEIGHT' => request_var('height', $user->data['user_avatar_height']),
-
- 'S_AVATARS_ENABLED' => $avatars_enabled,
- 'S_UPLOAD_AVATAR_FILE' => ($can_upload && $config['allow_avatar_upload']) ? true : false,
- 'S_UPLOAD_AVATAR_URL' => ($can_upload && $config['allow_avatar_remote_upload']) ? true : false,
- 'S_LINK_AVATAR' => ($auth->acl_get('u_chgavatar') && $config['allow_avatar_remote']) ? true : false,
- 'S_DISPLAY_GALLERY' => ($auth->acl_get('u_chgavatar') && $config['allow_avatar_local']) ? true : false)
- );
- }
-
break;
case 'autologin_keys':
diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php
index c57aec00a0..1de38fddb7 100644
--- a/phpBB/includes/ucp/ucp_register.php
+++ b/phpBB/includes/ucp/ucp_register.php
@@ -457,6 +457,7 @@ class ucp_register
'S_LANG_OPTIONS' => language_select($data['lang']),
'S_TZ_OPTIONS' => $timezone_selects['tz_select'],
'S_TZ_DATE_OPTIONS' => $timezone_selects['tz_dates'],
+ 'S_TZ_PRESELECT' => !$submit,
'S_CONFIRM_REFRESH' => ($config['enable_confirm'] && $config['confirm_refresh']) ? true : false,
'S_REGISTRATION' => true,
'S_COPPA' => $coppa,
diff --git a/phpBB/includes/user_loader.php b/phpBB/includes/user_loader.php
new file mode 100644
index 0000000000..77128d6570
--- /dev/null
+++ b/phpBB/includes/user_loader.php
@@ -0,0 +1,231 @@
+db = $db;
+
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ $this->users_table = $users_table;
+ }
+
+ /**
+ * Load user helper
+ *
+ * @param array $user_ids
+ */
+ public function load_users(array $user_ids)
+ {
+ $user_ids[] = ANONYMOUS;
+
+ // Load the users
+ $user_ids = array_unique($user_ids);
+
+ // Do not load users we already have in $this->users
+ $user_ids = array_diff($user_ids, array_keys($this->users));
+
+ if (sizeof($user_ids))
+ {
+ $sql = 'SELECT *
+ FROM ' . $this->users_table . '
+ WHERE ' . $this->db->sql_in_set('user_id', $user_ids);
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $this->users[$row['user_id']] = $row;
+ }
+ $this->db->sql_freeresult($result);
+ }
+ }
+
+ /**
+ * Load a user by username
+ *
+ * Stores the full data in the user cache so they do not need to be loaded again
+ * Returns the user id so you may use get_user() from the returned value
+ *
+ * @param string $username Raw username to load (will be cleaned)
+ * @return int User ID for the username
+ */
+ public function load_user_by_username($username)
+ {
+ $sql = 'SELECT *
+ FROM ' . $this->users_table . "
+ WHERE username_clean = '" . $this->db->sql_escape(utf8_clean_string($username)) . "'";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if ($row)
+ {
+ $this->users[$row['user_id']] = $row;
+
+ return $row['user_id'];
+ }
+
+ return ANONYMOUS;
+ }
+
+ /**
+ * Get a user row from our users cache
+ *
+ * @param int $user_id User ID of the user you want to retreive
+ * @param bool $query Should we query the database if this user has not yet been loaded?
+ * Typically this should be left as false and you should make sure
+ * you load users ahead of time with load_users()
+ * @return array|bool Row from the database of the user or Anonymous if the user wasn't loaded/does not exist
+ * or bool False if the anonymous user was not loaded
+ */
+ public function get_user($user_id, $query = false)
+ {
+ if (isset($this->users[$user_id]))
+ {
+ return $this->users[$user_id];
+ }
+ // Query them if we must (if ANONYMOUS is sent as the user_id and we have not loaded Anonymous yet, we must load Anonymous as a last resort)
+ else if ($query || $user_id == ANONYMOUS)
+ {
+ $this->load_users(array($user_id));
+
+ return $this->get_user($user_id);
+ }
+
+ return $this->get_user(ANONYMOUS);
+ }
+
+ /**
+ * Get username
+ *
+ * @param int $user_id User ID of the user you want to retreive the username for
+ * @param string $mode The mode to load (same as get_username_string). One of the following:
+ * profile (for getting an url to the profile)
+ * username (for obtaining the username)
+ * colour (for obtaining the user colour)
+ * full (for obtaining a html string representing a coloured link to the users profile)
+ * no_profile (the same as full but forcing no profile link)
+ * @param string $guest_username Optional parameter to specify the guest username. It will be used in favor of the GUEST language variable then.
+ * @param string $custom_profile_url Optional parameter to specify a profile url. The user id get appended to this url as &u={user_id}
+ * @param bool $query Should we query the database if this user has not yet been loaded?
+ * Typically this should be left as false and you should make sure
+ * you load users ahead of time with load_users()
+ * @return string
+ */
+ public function get_username($user_id, $mode, $guest_username = false, $custom_profile_url = false, $query = false)
+ {
+ if (!($user = $this->get_user($user_id, $query)))
+ {
+ return '';
+ }
+
+ return get_username_string($mode, $user['user_id'], $user['username'], $user['user_colour'], $guest_username, $custom_profile_url);
+ }
+
+ /**
+ * Get avatar
+ *
+ * @param int $user_id User ID of the user you want to retreive the avatar for
+ * @param bool $query Should we query the database if this user has not yet been loaded?
+ * Typically this should be left as false and you should make sure
+ * you load users ahead of time with load_users()
+ * @return string
+ */
+ public function get_avatar($user_id, $query = false)
+ {
+ if (!($user = $this->get_user($user_id, $query)))
+ {
+ return '';
+ }
+
+ if (!function_exists('get_user_avatar'))
+ {
+ include($this->phpbb_root_path . 'includes/functions_display.' . $this->php_ext);
+ }
+
+ return get_user_avatar($user['user_avatar'], $user['user_avatar_type'], $user['user_avatar_width'], $user['user_avatar_height']);
+ }
+
+ /**
+ * Get rank
+ *
+ * @param int $user_id User ID of the user you want to retreive the rank for
+ * @param bool $query Should we query the database if this user has not yet been loaded?
+ * Typically this should be left as false and you should make sure
+ * you load users ahead of time with load_users()
+ * @return array Array with keys 'rank_title', 'rank_img', and 'rank_img_src'
+ */
+ public function get_rank($user_id, $query = false)
+ {
+ if (!($user = $this->get_user($user_id, $query)))
+ {
+ return '';
+ }
+
+ if (!function_exists('get_user_rank'))
+ {
+ include($this->phpbb_root_path . 'includes/functions_display.' . $this->php_ext);
+ }
+
+ $rank = array(
+ 'rank_title',
+ 'rank_img',
+ 'rank_img_src',
+ );
+
+ get_user_rank($user['user_rank'], (($user['user_id'] == ANONYMOUS) ? false : $user['user_posts']), $rank['rank_title'], $rank['rank_img'], $rank['rank_img_src']);
+
+ return $rank;
+ }
+}
diff --git a/phpBB/index.php b/phpBB/index.php
index 845d0f0c02..74fc1b9bda 100644
--- a/phpBB/index.php
+++ b/phpBB/index.php
@@ -24,6 +24,30 @@ $user->session_begin();
$auth->acl($user->data);
$user->setup('viewforum');
+// Mark notifications read
+if (($mark_notification = $request->variable('mark_notification', 0)))
+{
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $notification = $phpbb_notifications->load_notifications(array(
+ 'notification_id' => $mark_notification
+ ));
+
+ if (isset($notification['notifications'][$mark_notification]))
+ {
+ $notification = $notification['notifications'][$mark_notification];
+
+ $notification->mark_read();
+
+ if (($redirect = $request->variable('redirect', '')))
+ {
+ redirect(append_sid($phpbb_root_path . $redirect));
+ }
+
+ redirect($notification->get_url());
+ }
+}
+
display_forums('', $config['load_moderators']);
$order_legend = ($config['legend_sort_groupname']) ? 'group_name' : 'group_legend';
diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php
index 4938ef0f87..2ecddf49d4 100644
--- a/phpBB/install/database_update.php
+++ b/phpBB/install/database_update.php
@@ -123,6 +123,7 @@ $request = $phpbb_container->get('request');
$user = $phpbb_container->get('user');
$auth = $phpbb_container->get('auth');
$db = $phpbb_container->get('dbal.conn');
+$phpbb_log = $phpbb_container->get('log');
// make sure request_var uses this request instance
request_var('', 0, false, false, $request); // "dependency injection" for a function
@@ -210,7 +211,13 @@ if (!$db_tools->sql_table_exists($table_prefix . 'migrations'))
}
$migrator = $phpbb_container->get('migrator');
-$migrator->load_migrations($phpbb_root_path . 'includes/db/migration/data/');
+$extension_manager = $phpbb_container->get('ext.manager');
+$finder = $extension_manager->get_finder();
+
+$migrations = $finder
+ ->core_path('includes/db/migration/data/')
+ ->get_classes();
+$migrator->set_migrations($migrations);
// What is a safe limit of execution time? Half the max execution time should be safe.
$safe_time_limit = (ini_get('max_execution_time') / 2);
@@ -228,7 +235,28 @@ while (!$migrator->finished())
phpbb_end_update($cache);
}
- echo $migrator->last_run_migration['name'] . ' ';
+ $state = array_merge(array(
+ 'migration_schema_done' => false,
+ 'migration_data_done' => false,
+ ),
+ $migrator->last_run_migration['state']
+ );
+
+ if (isset($migrator->last_run_migration['effectively_installed']) && $migrator->last_run_migration['effectively_installed'])
+ {
+ echo $user->lang('MIGRATION_EFFECTIVELY_INSTALLED', $migrator->last_run_migration['name']) . ' ';
+ }
+ else
+ {
+ if ($state['migration_data_done'])
+ {
+ echo $user->lang('MIGRATION_DATA_DONE', $migrator->last_run_migration['name']) . ' ';
+ }
+ else if ($state['migration_schema_done'])
+ {
+ echo $user->lang('MIGRATION_SCHEMA_DONE', $migrator->last_run_migration['name']) . ' ';
+ }
+ }
// 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/install/install_install.php b/phpBB/install/install_install.php
index f0280acc40..67e368e34d 100644
--- a/phpBB/install/install_install.php
+++ b/phpBB/install/install_install.php
@@ -53,7 +53,7 @@ class install_install extends module
function main($mode, $sub)
{
global $lang, $template, $language, $phpbb_root_path, $phpEx;
- global $phpbb_container, $cache;
+ global $phpbb_container, $cache, $phpbb_log;
switch ($sub)
{
@@ -105,8 +105,9 @@ class install_install extends module
// Create a normal container now
$phpbb_container = phpbb_create_default_container($phpbb_root_path, $phpEx);
- // Sets the global $cache variable
+ // Sets the global variables
$cache = $phpbb_container->get('cache');
+ $phpbb_log = $phpbb_container->get('log');
$this->build_search_index($mode, $sub);
$this->add_modules($mode, $sub);
@@ -114,7 +115,7 @@ class install_install extends module
$this->add_bots($mode, $sub);
$this->email_admin($mode, $sub);
$this->disable_avatars_if_unwritable();
- $this->populate_migrations($phpbb_container->get('migrator'), $phpbb_root_path);
+ $this->populate_migrations($phpbb_container->get('ext.manager'), $phpbb_container->get('migrator'));
// Remove the lock file
@unlink($phpbb_root_path . 'cache/install_lock');
@@ -1888,12 +1889,17 @@ class install_install extends module
* "installs" means it adds all migrations to the migrations table, but does not
* perform any of the actions in the migrations.
*
+ * @param phpbb_extension_manager $extension_manager
* @param phpbb_db_migrator $migrator
- * @param string $phpbb_root_path
*/
- function populate_migrations($migrator, $phpbb_root_path)
+ function populate_migrations($extension_manager, $migrator)
{
- $migrator->populate_migrations_from_directory($phpbb_root_path . 'includes/db/migration/data/');
+ $finder = $extension_manager->get_finder();
+
+ $migrations = $finder
+ ->core_path('includes/db/migration/data/')
+ ->get_classes();
+ $migrator->populate_migrations($migrations);
}
/**
diff --git a/phpBB/install/schemas/firebird_schema.sql b/phpBB/install/schemas/firebird_schema.sql
index c4818215e4..18ca184c65 100644
--- a/phpBB/install/schemas/firebird_schema.sql
+++ b/phpBB/install/schemas/firebird_schema.sql
@@ -222,6 +222,15 @@ ALTER TABLE phpbb_config ADD PRIMARY KEY (config_name);;
CREATE INDEX phpbb_config_is_dynamic ON phpbb_config(is_dynamic);;
+# Table: 'phpbb_config_text'
+CREATE TABLE phpbb_config_text (
+ config_name VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
+ config_value BLOB SUB_TYPE TEXT CHARACTER SET NONE DEFAULT '' NOT NULL
+);;
+
+ALTER TABLE phpbb_config_text ADD PRIMARY KEY (config_name);;
+
+
# Table: 'phpbb_confirm'
CREATE TABLE phpbb_confirm (
confirm_id CHAR(32) CHARACTER SET NONE DEFAULT '' NOT NULL,
@@ -445,7 +454,7 @@ CREATE TABLE phpbb_groups (
group_desc_uid VARCHAR(8) CHARACTER SET NONE DEFAULT '' NOT NULL,
group_display INTEGER DEFAULT 0 NOT NULL,
group_avatar VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
- group_avatar_type INTEGER DEFAULT 0 NOT NULL,
+ group_avatar_type VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
group_avatar_width INTEGER DEFAULT 0 NOT NULL,
group_avatar_height INTEGER DEFAULT 0 NOT NULL,
group_rank INTEGER DEFAULT 0 NOT NULL,
@@ -454,8 +463,7 @@ CREATE TABLE phpbb_groups (
group_receive_pm INTEGER DEFAULT 0 NOT NULL,
group_message_limit INTEGER DEFAULT 0 NOT NULL,
group_max_recipients INTEGER DEFAULT 0 NOT NULL,
- group_legend INTEGER DEFAULT 0 NOT NULL,
- group_teampage INTEGER DEFAULT 0 NOT NULL
+ group_legend INTEGER DEFAULT 0 NOT NULL
);;
ALTER TABLE phpbb_groups ADD PRIMARY KEY (group_id);;
@@ -632,6 +640,43 @@ BEGIN
END;;
+# Table: 'phpbb_notification_types'
+CREATE TABLE phpbb_notification_types (
+ notification_type VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
+ notification_type_enabled INTEGER DEFAULT 1 NOT NULL
+);;
+
+ALTER TABLE phpbb_notification_types ADD PRIMARY KEY (notification_type, notification_type_enabled);;
+
+
+# Table: 'phpbb_notifications'
+CREATE TABLE phpbb_notifications (
+ notification_id INTEGER NOT NULL,
+ item_type VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
+ item_id INTEGER DEFAULT 0 NOT NULL,
+ item_parent_id INTEGER DEFAULT 0 NOT NULL,
+ user_id INTEGER DEFAULT 0 NOT NULL,
+ notification_read INTEGER DEFAULT 0 NOT NULL,
+ notification_time INTEGER DEFAULT 1 NOT NULL,
+ notification_data BLOB SUB_TYPE TEXT CHARACTER SET UTF8 DEFAULT '' NOT NULL
+);;
+
+ALTER TABLE phpbb_notifications ADD PRIMARY KEY (notification_id);;
+
+CREATE INDEX phpbb_notifications_item_ident ON phpbb_notifications(item_type, item_id);;
+CREATE INDEX phpbb_notifications_user ON phpbb_notifications(user_id, notification_read);;
+
+CREATE GENERATOR phpbb_notifications_gen;;
+SET GENERATOR phpbb_notifications_gen TO 0;;
+
+CREATE TRIGGER t_phpbb_notifications FOR phpbb_notifications
+BEFORE INSERT
+AS
+BEGIN
+ NEW.notification_id = GEN_ID(phpbb_notifications_gen, 1);
+END;;
+
+
# Table: 'phpbb_poll_options'
CREATE TABLE phpbb_poll_options (
poll_option_id INTEGER DEFAULT 0 NOT NULL,
@@ -1128,6 +1173,29 @@ BEGIN
END;;
+# Table: 'phpbb_teampage'
+CREATE TABLE phpbb_teampage (
+ teampage_id INTEGER NOT NULL,
+ group_id INTEGER DEFAULT 0 NOT NULL,
+ teampage_name VARCHAR(255) CHARACTER SET UTF8 DEFAULT '' NOT NULL COLLATE UNICODE,
+ teampage_position INTEGER DEFAULT 0 NOT NULL,
+ teampage_parent INTEGER DEFAULT 0 NOT NULL
+);;
+
+ALTER TABLE phpbb_teampage ADD PRIMARY KEY (teampage_id);;
+
+
+CREATE GENERATOR phpbb_teampage_gen;;
+SET GENERATOR phpbb_teampage_gen TO 0;;
+
+CREATE TRIGGER t_phpbb_teampage FOR phpbb_teampage
+BEFORE INSERT
+AS
+BEGIN
+ NEW.teampage_id = GEN_ID(phpbb_teampage_gen, 1);
+END;;
+
+
# Table: 'phpbb_topics'
CREATE TABLE phpbb_topics (
topic_id INTEGER NOT NULL,
@@ -1220,6 +1288,16 @@ CREATE INDEX phpbb_topics_watch_topic_id ON phpbb_topics_watch(topic_id);;
CREATE INDEX phpbb_topics_watch_user_id ON phpbb_topics_watch(user_id);;
CREATE INDEX phpbb_topics_watch_notify_stat ON phpbb_topics_watch(notify_status);;
+# Table: 'phpbb_user_notifications'
+CREATE TABLE phpbb_user_notifications (
+ item_type VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
+ item_id INTEGER DEFAULT 0 NOT NULL,
+ user_id INTEGER DEFAULT 0 NOT NULL,
+ method VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
+ notify INTEGER DEFAULT 1 NOT NULL
+);;
+
+
# Table: 'phpbb_user_group'
CREATE TABLE phpbb_user_group (
group_id INTEGER DEFAULT 0 NOT NULL,
@@ -1288,7 +1366,7 @@ CREATE TABLE phpbb_users (
user_allow_massemail INTEGER DEFAULT 1 NOT NULL,
user_options INTEGER DEFAULT 230271 NOT NULL,
user_avatar VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
- user_avatar_type INTEGER DEFAULT 0 NOT NULL,
+ user_avatar_type VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
user_avatar_width INTEGER DEFAULT 0 NOT NULL,
user_avatar_height INTEGER DEFAULT 0 NOT NULL,
user_sig BLOB SUB_TYPE TEXT CHARACTER SET UTF8 DEFAULT '' NOT NULL,
diff --git a/phpBB/install/schemas/mssql_schema.sql b/phpBB/install/schemas/mssql_schema.sql
index 709f83917e..3530f9cd25 100644
--- a/phpBB/install/schemas/mssql_schema.sql
+++ b/phpBB/install/schemas/mssql_schema.sql
@@ -293,6 +293,23 @@ CREATE INDEX [is_dynamic] ON [phpbb_config]([is_dynamic]) ON [PRIMARY]
GO
+/*
+ Table: 'phpbb_config_text'
+*/
+CREATE TABLE [phpbb_config_text] (
+ [config_name] [varchar] (255) DEFAULT ('') NOT NULL ,
+ [config_value] [text] DEFAULT ('') NOT NULL
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
+GO
+
+ALTER TABLE [phpbb_config_text] WITH NOCHECK ADD
+ CONSTRAINT [PK_phpbb_config_text] PRIMARY KEY CLUSTERED
+ (
+ [config_name]
+ ) ON [PRIMARY]
+GO
+
+
/*
Table: 'phpbb_confirm'
*/
@@ -553,7 +570,7 @@ CREATE TABLE [phpbb_groups] (
[group_desc_uid] [varchar] (8) DEFAULT ('') NOT NULL ,
[group_display] [int] DEFAULT (0) NOT NULL ,
[group_avatar] [varchar] (255) DEFAULT ('') NOT NULL ,
- [group_avatar_type] [int] DEFAULT (0) NOT NULL ,
+ [group_avatar_type] [varchar] (255) DEFAULT ('') NOT NULL ,
[group_avatar_width] [int] DEFAULT (0) NOT NULL ,
[group_avatar_height] [int] DEFAULT (0) NOT NULL ,
[group_rank] [int] DEFAULT (0) NOT NULL ,
@@ -562,8 +579,7 @@ CREATE TABLE [phpbb_groups] (
[group_receive_pm] [int] DEFAULT (0) NOT NULL ,
[group_message_limit] [int] DEFAULT (0) NOT NULL ,
[group_max_recipients] [int] DEFAULT (0) NOT NULL ,
- [group_legend] [int] DEFAULT (0) NOT NULL ,
- [group_teampage] [int] DEFAULT (0) NOT NULL
+ [group_legend] [int] DEFAULT (0) NOT NULL
) ON [PRIMARY]
GO
@@ -773,6 +789,53 @@ CREATE INDEX [class_left_id] ON [phpbb_modules]([module_class], [left_id]) ON [
GO
+/*
+ Table: 'phpbb_notification_types'
+*/
+CREATE TABLE [phpbb_notification_types] (
+ [notification_type] [varchar] (255) DEFAULT ('') NOT NULL ,
+ [notification_type_enabled] [int] DEFAULT (1) NOT NULL
+) ON [PRIMARY]
+GO
+
+ALTER TABLE [phpbb_notification_types] WITH NOCHECK ADD
+ CONSTRAINT [PK_phpbb_notification_types] PRIMARY KEY CLUSTERED
+ (
+ [notification_type],
+ [notification_type_enabled]
+ ) ON [PRIMARY]
+GO
+
+
+/*
+ Table: 'phpbb_notifications'
+*/
+CREATE TABLE [phpbb_notifications] (
+ [notification_id] [int] IDENTITY (1, 1) NOT NULL ,
+ [item_type] [varchar] (255) DEFAULT ('') NOT NULL ,
+ [item_id] [int] DEFAULT (0) NOT NULL ,
+ [item_parent_id] [int] DEFAULT (0) NOT NULL ,
+ [user_id] [int] DEFAULT (0) NOT NULL ,
+ [notification_read] [int] DEFAULT (0) NOT NULL ,
+ [notification_time] [int] DEFAULT (1) NOT NULL ,
+ [notification_data] [varchar] (4000) DEFAULT ('') NOT NULL
+) ON [PRIMARY]
+GO
+
+ALTER TABLE [phpbb_notifications] WITH NOCHECK ADD
+ CONSTRAINT [PK_phpbb_notifications] PRIMARY KEY CLUSTERED
+ (
+ [notification_id]
+ ) ON [PRIMARY]
+GO
+
+CREATE INDEX [item_ident] ON [phpbb_notifications]([item_type], [item_id]) ON [PRIMARY]
+GO
+
+CREATE INDEX [user] ON [phpbb_notifications]([user_id], [notification_read]) ON [PRIMARY]
+GO
+
+
/*
Table: 'phpbb_poll_options'
*/
@@ -1369,6 +1432,26 @@ CREATE UNIQUE INDEX [style_name] ON [phpbb_styles]([style_name]) ON [PRIMARY]
GO
+/*
+ Table: 'phpbb_teampage'
+*/
+CREATE TABLE [phpbb_teampage] (
+ [teampage_id] [int] IDENTITY (1, 1) NOT NULL ,
+ [group_id] [int] DEFAULT (0) NOT NULL ,
+ [teampage_name] [varchar] (255) DEFAULT ('') NOT NULL ,
+ [teampage_position] [int] DEFAULT (0) NOT NULL ,
+ [teampage_parent] [int] DEFAULT (0) NOT NULL
+) ON [PRIMARY]
+GO
+
+ALTER TABLE [phpbb_teampage] WITH NOCHECK ADD
+ CONSTRAINT [PK_phpbb_teampage] PRIMARY KEY CLUSTERED
+ (
+ [teampage_id]
+ ) ON [PRIMARY]
+GO
+
+
/*
Table: 'phpbb_topics'
*/
@@ -1501,6 +1584,19 @@ CREATE INDEX [notify_stat] ON [phpbb_topics_watch]([notify_status]) ON [PRIMARY
GO
+/*
+ Table: 'phpbb_user_notifications'
+*/
+CREATE TABLE [phpbb_user_notifications] (
+ [item_type] [varchar] (255) DEFAULT ('') NOT NULL ,
+ [item_id] [int] DEFAULT (0) NOT NULL ,
+ [user_id] [int] DEFAULT (0) NOT NULL ,
+ [method] [varchar] (255) DEFAULT ('') NOT NULL ,
+ [notify] [int] DEFAULT (1) NOT NULL
+) ON [PRIMARY]
+GO
+
+
/*
Table: 'phpbb_user_group'
*/
@@ -1580,7 +1676,7 @@ CREATE TABLE [phpbb_users] (
[user_allow_massemail] [int] DEFAULT (1) NOT NULL ,
[user_options] [int] DEFAULT (230271) NOT NULL ,
[user_avatar] [varchar] (255) DEFAULT ('') NOT NULL ,
- [user_avatar_type] [int] DEFAULT (0) NOT NULL ,
+ [user_avatar_type] [varchar] (255) DEFAULT ('') NOT NULL ,
[user_avatar_width] [int] DEFAULT (0) NOT NULL ,
[user_avatar_height] [int] DEFAULT (0) NOT NULL ,
[user_sig] [text] DEFAULT ('') NOT NULL ,
diff --git a/phpBB/install/schemas/mysql_40_schema.sql b/phpBB/install/schemas/mysql_40_schema.sql
index c905dda77e..8c405677a8 100644
--- a/phpBB/install/schemas/mysql_40_schema.sql
+++ b/phpBB/install/schemas/mysql_40_schema.sql
@@ -157,6 +157,14 @@ CREATE TABLE phpbb_config (
);
+# Table: 'phpbb_config_text'
+CREATE TABLE phpbb_config_text (
+ config_name varbinary(255) DEFAULT '' NOT NULL,
+ config_value mediumblob NOT NULL,
+ PRIMARY KEY (config_name)
+);
+
+
# Table: 'phpbb_confirm'
CREATE TABLE phpbb_confirm (
confirm_id binary(32) DEFAULT '' NOT NULL,
@@ -317,7 +325,7 @@ CREATE TABLE phpbb_groups (
group_desc_uid varbinary(8) DEFAULT '' NOT NULL,
group_display tinyint(1) UNSIGNED DEFAULT '0' NOT NULL,
group_avatar varbinary(255) DEFAULT '' NOT NULL,
- group_avatar_type tinyint(2) DEFAULT '0' NOT NULL,
+ group_avatar_type varbinary(255) DEFAULT '' NOT NULL,
group_avatar_width smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
group_avatar_height smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
group_rank mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
@@ -327,7 +335,6 @@ CREATE TABLE phpbb_groups (
group_message_limit mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
group_max_recipients mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
group_legend mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
- group_teampage mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
PRIMARY KEY (group_id),
KEY group_legend_name (group_legend, group_name(255))
);
@@ -443,6 +450,30 @@ CREATE TABLE phpbb_modules (
);
+# Table: 'phpbb_notification_types'
+CREATE TABLE phpbb_notification_types (
+ notification_type varbinary(255) DEFAULT '' NOT NULL,
+ notification_type_enabled tinyint(1) UNSIGNED DEFAULT '1' NOT NULL,
+ PRIMARY KEY (notification_type, notification_type_enabled)
+);
+
+
+# Table: 'phpbb_notifications'
+CREATE TABLE phpbb_notifications (
+ notification_id mediumint(8) UNSIGNED NOT NULL auto_increment,
+ item_type varbinary(255) DEFAULT '' NOT NULL,
+ item_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ item_parent_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ user_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ notification_read tinyint(1) UNSIGNED DEFAULT '0' NOT NULL,
+ notification_time int(11) UNSIGNED DEFAULT '1' NOT NULL,
+ notification_data blob NOT NULL,
+ PRIMARY KEY (notification_id),
+ KEY item_ident (item_type, item_id),
+ KEY user (user_id, notification_read)
+);
+
+
# Table: 'phpbb_poll_options'
CREATE TABLE phpbb_poll_options (
poll_option_id tinyint(4) DEFAULT '0' NOT NULL,
@@ -789,6 +820,17 @@ CREATE TABLE phpbb_styles (
);
+# Table: 'phpbb_teampage'
+CREATE TABLE phpbb_teampage (
+ teampage_id mediumint(8) UNSIGNED NOT NULL auto_increment,
+ group_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ teampage_name blob NOT NULL,
+ teampage_position mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ teampage_parent mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ PRIMARY KEY (teampage_id)
+);
+
+
# Table: 'phpbb_topics'
CREATE TABLE phpbb_topics (
topic_id mediumint(8) UNSIGNED NOT NULL auto_increment,
@@ -867,6 +909,16 @@ CREATE TABLE phpbb_topics_watch (
);
+# Table: 'phpbb_user_notifications'
+CREATE TABLE phpbb_user_notifications (
+ item_type varbinary(255) DEFAULT '' NOT NULL,
+ item_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ user_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ method varbinary(255) DEFAULT '' NOT NULL,
+ notify tinyint(1) UNSIGNED DEFAULT '1' NOT NULL
+);
+
+
# Table: 'phpbb_user_group'
CREATE TABLE phpbb_user_group (
group_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
@@ -935,7 +987,7 @@ CREATE TABLE phpbb_users (
user_allow_massemail tinyint(1) UNSIGNED DEFAULT '1' NOT NULL,
user_options int(11) UNSIGNED DEFAULT '230271' NOT NULL,
user_avatar varbinary(255) DEFAULT '' NOT NULL,
- user_avatar_type tinyint(2) DEFAULT '0' NOT NULL,
+ user_avatar_type varbinary(255) DEFAULT '' NOT NULL,
user_avatar_width smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
user_avatar_height smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
user_sig mediumblob NOT NULL,
diff --git a/phpBB/install/schemas/mysql_41_schema.sql b/phpBB/install/schemas/mysql_41_schema.sql
index b5d7c70c10..cb259aa57d 100644
--- a/phpBB/install/schemas/mysql_41_schema.sql
+++ b/phpBB/install/schemas/mysql_41_schema.sql
@@ -157,6 +157,14 @@ CREATE TABLE phpbb_config (
) CHARACTER SET `utf8` COLLATE `utf8_bin`;
+# Table: 'phpbb_config_text'
+CREATE TABLE phpbb_config_text (
+ config_name varchar(255) DEFAULT '' NOT NULL,
+ config_value mediumtext NOT NULL,
+ PRIMARY KEY (config_name)
+) CHARACTER SET `utf8` COLLATE `utf8_bin`;
+
+
# Table: 'phpbb_confirm'
CREATE TABLE phpbb_confirm (
confirm_id char(32) DEFAULT '' NOT NULL,
@@ -317,7 +325,7 @@ CREATE TABLE phpbb_groups (
group_desc_uid varchar(8) DEFAULT '' NOT NULL,
group_display tinyint(1) UNSIGNED DEFAULT '0' NOT NULL,
group_avatar varchar(255) DEFAULT '' NOT NULL,
- group_avatar_type tinyint(2) DEFAULT '0' NOT NULL,
+ group_avatar_type varchar(255) DEFAULT '' NOT NULL,
group_avatar_width smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
group_avatar_height smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
group_rank mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
@@ -327,7 +335,6 @@ CREATE TABLE phpbb_groups (
group_message_limit mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
group_max_recipients mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
group_legend mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
- group_teampage mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
PRIMARY KEY (group_id),
KEY group_legend_name (group_legend, group_name)
) CHARACTER SET `utf8` COLLATE `utf8_bin`;
@@ -443,6 +450,30 @@ CREATE TABLE phpbb_modules (
) CHARACTER SET `utf8` COLLATE `utf8_bin`;
+# Table: 'phpbb_notification_types'
+CREATE TABLE phpbb_notification_types (
+ notification_type varchar(255) DEFAULT '' NOT NULL,
+ notification_type_enabled tinyint(1) UNSIGNED DEFAULT '1' NOT NULL,
+ PRIMARY KEY (notification_type, notification_type_enabled)
+) CHARACTER SET `utf8` COLLATE `utf8_bin`;
+
+
+# Table: 'phpbb_notifications'
+CREATE TABLE phpbb_notifications (
+ notification_id mediumint(8) UNSIGNED NOT NULL auto_increment,
+ item_type varchar(255) DEFAULT '' NOT NULL,
+ item_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ item_parent_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ user_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ notification_read tinyint(1) UNSIGNED DEFAULT '0' NOT NULL,
+ notification_time int(11) UNSIGNED DEFAULT '1' NOT NULL,
+ notification_data text NOT NULL,
+ PRIMARY KEY (notification_id),
+ KEY item_ident (item_type, item_id),
+ KEY user (user_id, notification_read)
+) CHARACTER SET `utf8` COLLATE `utf8_bin`;
+
+
# Table: 'phpbb_poll_options'
CREATE TABLE phpbb_poll_options (
poll_option_id tinyint(4) DEFAULT '0' NOT NULL,
@@ -789,6 +820,17 @@ CREATE TABLE phpbb_styles (
) CHARACTER SET `utf8` COLLATE `utf8_bin`;
+# Table: 'phpbb_teampage'
+CREATE TABLE phpbb_teampage (
+ teampage_id mediumint(8) UNSIGNED NOT NULL auto_increment,
+ group_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ teampage_name varchar(255) DEFAULT '' NOT NULL,
+ teampage_position mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ teampage_parent mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ PRIMARY KEY (teampage_id)
+) CHARACTER SET `utf8` COLLATE `utf8_bin`;
+
+
# Table: 'phpbb_topics'
CREATE TABLE phpbb_topics (
topic_id mediumint(8) UNSIGNED NOT NULL auto_increment,
@@ -867,6 +909,16 @@ CREATE TABLE phpbb_topics_watch (
) CHARACTER SET `utf8` COLLATE `utf8_bin`;
+# Table: 'phpbb_user_notifications'
+CREATE TABLE phpbb_user_notifications (
+ item_type varchar(255) DEFAULT '' NOT NULL,
+ item_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ user_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ method varchar(255) DEFAULT '' NOT NULL,
+ notify tinyint(1) UNSIGNED DEFAULT '1' NOT NULL
+) CHARACTER SET `utf8` COLLATE `utf8_bin`;
+
+
# Table: 'phpbb_user_group'
CREATE TABLE phpbb_user_group (
group_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
@@ -935,7 +987,7 @@ CREATE TABLE phpbb_users (
user_allow_massemail tinyint(1) UNSIGNED DEFAULT '1' NOT NULL,
user_options int(11) UNSIGNED DEFAULT '230271' NOT NULL,
user_avatar varchar(255) DEFAULT '' NOT NULL,
- user_avatar_type tinyint(2) DEFAULT '0' NOT NULL,
+ user_avatar_type varchar(255) DEFAULT '' NOT NULL,
user_avatar_width smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
user_avatar_height smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
user_sig mediumtext NOT NULL,
diff --git a/phpBB/install/schemas/oracle_schema.sql b/phpBB/install/schemas/oracle_schema.sql
index e2bdb2385b..35f05e34cd 100644
--- a/phpBB/install/schemas/oracle_schema.sql
+++ b/phpBB/install/schemas/oracle_schema.sql
@@ -331,6 +331,17 @@ CREATE TABLE phpbb_config (
CREATE INDEX phpbb_config_is_dynamic ON phpbb_config (is_dynamic)
/
+/*
+ Table: 'phpbb_config_text'
+*/
+CREATE TABLE phpbb_config_text (
+ config_name varchar2(255) DEFAULT '' ,
+ config_value clob DEFAULT '' ,
+ CONSTRAINT pk_phpbb_config_text PRIMARY KEY (config_name)
+)
+/
+
+
/*
Table: 'phpbb_confirm'
*/
@@ -610,7 +621,7 @@ CREATE TABLE phpbb_groups (
group_desc_uid varchar2(8) DEFAULT '' ,
group_display number(1) DEFAULT '0' NOT NULL,
group_avatar varchar2(255) DEFAULT '' ,
- group_avatar_type number(2) DEFAULT '0' NOT NULL,
+ group_avatar_type varchar2(255) DEFAULT '' ,
group_avatar_width number(4) DEFAULT '0' NOT NULL,
group_avatar_height number(4) DEFAULT '0' NOT NULL,
group_rank number(8) DEFAULT '0' NOT NULL,
@@ -620,7 +631,6 @@ CREATE TABLE phpbb_groups (
group_message_limit number(8) DEFAULT '0' NOT NULL,
group_max_recipients number(8) DEFAULT '0' NOT NULL,
group_legend number(8) DEFAULT '0' NOT NULL,
- group_teampage number(8) DEFAULT '0' NOT NULL,
CONSTRAINT pk_phpbb_groups PRIMARY KEY (group_id)
)
/
@@ -856,6 +866,54 @@ END;
/
+/*
+ Table: 'phpbb_notification_types'
+*/
+CREATE TABLE phpbb_notification_types (
+ notification_type varchar2(255) DEFAULT '' ,
+ notification_type_enabled number(1) DEFAULT '1' NOT NULL,
+ CONSTRAINT pk_phpbb_notification_types PRIMARY KEY (notification_type, notification_type_enabled)
+)
+/
+
+
+/*
+ Table: 'phpbb_notifications'
+*/
+CREATE TABLE phpbb_notifications (
+ notification_id number(8) NOT NULL,
+ item_type varchar2(255) DEFAULT '' ,
+ item_id number(8) DEFAULT '0' NOT NULL,
+ item_parent_id number(8) DEFAULT '0' NOT NULL,
+ user_id number(8) DEFAULT '0' NOT NULL,
+ notification_read number(1) DEFAULT '0' NOT NULL,
+ notification_time number(11) DEFAULT '1' NOT NULL,
+ notification_data clob DEFAULT '' ,
+ CONSTRAINT pk_phpbb_notifications PRIMARY KEY (notification_id)
+)
+/
+
+CREATE INDEX phpbb_notifications_item_ident ON phpbb_notifications (item_type, item_id)
+/
+CREATE INDEX phpbb_notifications_user ON phpbb_notifications (user_id, notification_read)
+/
+
+CREATE SEQUENCE phpbb_notifications_seq
+/
+
+CREATE OR REPLACE TRIGGER t_phpbb_notifications
+BEFORE INSERT ON phpbb_notifications
+FOR EACH ROW WHEN (
+ new.notification_id IS NULL OR new.notification_id = 0
+)
+BEGIN
+ SELECT phpbb_notifications_seq.nextval
+ INTO :new.notification_id
+ FROM dual;
+END;
+/
+
+
/*
Table: 'phpbb_poll_options'
*/
@@ -1493,6 +1551,36 @@ END;
/
+/*
+ Table: 'phpbb_teampage'
+*/
+CREATE TABLE phpbb_teampage (
+ teampage_id number(8) NOT NULL,
+ group_id number(8) DEFAULT '0' NOT NULL,
+ teampage_name varchar2(765) DEFAULT '' ,
+ teampage_position number(8) DEFAULT '0' NOT NULL,
+ teampage_parent number(8) DEFAULT '0' NOT NULL,
+ CONSTRAINT pk_phpbb_teampage PRIMARY KEY (teampage_id)
+)
+/
+
+
+CREATE SEQUENCE phpbb_teampage_seq
+/
+
+CREATE OR REPLACE TRIGGER t_phpbb_teampage
+BEFORE INSERT ON phpbb_teampage
+FOR EACH ROW WHEN (
+ new.teampage_id IS NULL OR new.teampage_id = 0
+)
+BEGIN
+ SELECT phpbb_teampage_seq.nextval
+ INTO :new.teampage_id
+ FROM dual;
+END;
+/
+
+
/*
Table: 'phpbb_topics'
*/
@@ -1610,6 +1698,19 @@ CREATE INDEX phpbb_topics_watch_user_id ON phpbb_topics_watch (user_id)
CREATE INDEX phpbb_topics_watch_notify_stat ON phpbb_topics_watch (notify_status)
/
+/*
+ Table: 'phpbb_user_notifications'
+*/
+CREATE TABLE phpbb_user_notifications (
+ item_type varchar2(255) DEFAULT '' ,
+ item_id number(8) DEFAULT '0' NOT NULL,
+ user_id number(8) DEFAULT '0' NOT NULL,
+ method varchar2(255) DEFAULT '' ,
+ notify number(1) DEFAULT '1' NOT NULL
+)
+/
+
+
/*
Table: 'phpbb_user_group'
*/
@@ -1686,7 +1787,7 @@ CREATE TABLE phpbb_users (
user_allow_massemail number(1) DEFAULT '1' NOT NULL,
user_options number(11) DEFAULT '230271' NOT NULL,
user_avatar varchar2(255) DEFAULT '' ,
- user_avatar_type number(2) DEFAULT '0' NOT NULL,
+ user_avatar_type varchar2(255) DEFAULT '' ,
user_avatar_width number(4) DEFAULT '0' NOT NULL,
user_avatar_height number(4) DEFAULT '0' NOT NULL,
user_sig clob DEFAULT '' ,
diff --git a/phpBB/install/schemas/postgres_schema.sql b/phpBB/install/schemas/postgres_schema.sql
index 41d510e4c3..6dc507b46d 100644
--- a/phpBB/install/schemas/postgres_schema.sql
+++ b/phpBB/install/schemas/postgres_schema.sql
@@ -269,6 +269,16 @@ CREATE TABLE phpbb_config (
CREATE INDEX phpbb_config_is_dynamic ON phpbb_config (is_dynamic);
+/*
+ Table: 'phpbb_config_text'
+*/
+CREATE TABLE phpbb_config_text (
+ config_name varchar(255) DEFAULT '' NOT NULL,
+ config_value TEXT DEFAULT '' NOT NULL,
+ PRIMARY KEY (config_name)
+);
+
+
/*
Table: 'phpbb_confirm'
*/
@@ -463,7 +473,7 @@ CREATE TABLE phpbb_groups (
group_desc_uid varchar(8) DEFAULT '' NOT NULL,
group_display INT2 DEFAULT '0' NOT NULL CHECK (group_display >= 0),
group_avatar varchar(255) DEFAULT '' NOT NULL,
- group_avatar_type INT2 DEFAULT '0' NOT NULL,
+ group_avatar_type varchar(255) DEFAULT '' NOT NULL,
group_avatar_width INT2 DEFAULT '0' NOT NULL CHECK (group_avatar_width >= 0),
group_avatar_height INT2 DEFAULT '0' NOT NULL CHECK (group_avatar_height >= 0),
group_rank INT4 DEFAULT '0' NOT NULL CHECK (group_rank >= 0),
@@ -473,7 +483,6 @@ CREATE TABLE phpbb_groups (
group_message_limit INT4 DEFAULT '0' NOT NULL CHECK (group_message_limit >= 0),
group_max_recipients INT4 DEFAULT '0' NOT NULL CHECK (group_max_recipients >= 0),
group_legend INT4 DEFAULT '0' NOT NULL CHECK (group_legend >= 0),
- group_teampage INT4 DEFAULT '0' NOT NULL CHECK (group_teampage >= 0),
PRIMARY KEY (group_id)
);
@@ -611,6 +620,36 @@ CREATE INDEX phpbb_modules_left_right_id ON phpbb_modules (left_id, right_id);
CREATE INDEX phpbb_modules_module_enabled ON phpbb_modules (module_enabled);
CREATE INDEX phpbb_modules_class_left_id ON phpbb_modules (module_class, left_id);
+/*
+ Table: 'phpbb_notification_types'
+*/
+CREATE TABLE phpbb_notification_types (
+ notification_type varchar(255) DEFAULT '' NOT NULL,
+ notification_type_enabled INT2 DEFAULT '1' NOT NULL CHECK (notification_type_enabled >= 0),
+ PRIMARY KEY (notification_type, notification_type_enabled)
+);
+
+
+/*
+ Table: 'phpbb_notifications'
+*/
+CREATE SEQUENCE phpbb_notifications_seq;
+
+CREATE TABLE phpbb_notifications (
+ notification_id INT4 DEFAULT nextval('phpbb_notifications_seq'),
+ item_type varchar(255) DEFAULT '' NOT NULL,
+ item_id INT4 DEFAULT '0' NOT NULL CHECK (item_id >= 0),
+ item_parent_id INT4 DEFAULT '0' NOT NULL CHECK (item_parent_id >= 0),
+ user_id INT4 DEFAULT '0' NOT NULL CHECK (user_id >= 0),
+ notification_read INT2 DEFAULT '0' NOT NULL CHECK (notification_read >= 0),
+ notification_time INT4 DEFAULT '1' NOT NULL CHECK (notification_time >= 0),
+ notification_data varchar(4000) DEFAULT '' NOT NULL,
+ PRIMARY KEY (notification_id)
+);
+
+CREATE INDEX phpbb_notifications_item_ident ON phpbb_notifications (item_type, item_id);
+CREATE INDEX phpbb_notifications_user ON phpbb_notifications (user_id, notification_read);
+
/*
Table: 'phpbb_poll_options'
*/
@@ -1025,6 +1064,21 @@ CREATE TABLE phpbb_styles (
CREATE UNIQUE INDEX phpbb_styles_style_name ON phpbb_styles (style_name);
+/*
+ Table: 'phpbb_teampage'
+*/
+CREATE SEQUENCE phpbb_teampage_seq;
+
+CREATE TABLE phpbb_teampage (
+ teampage_id INT4 DEFAULT nextval('phpbb_teampage_seq'),
+ group_id INT4 DEFAULT '0' NOT NULL CHECK (group_id >= 0),
+ teampage_name varchar(255) DEFAULT '' NOT NULL,
+ teampage_position INT4 DEFAULT '0' NOT NULL CHECK (teampage_position >= 0),
+ teampage_parent INT4 DEFAULT '0' NOT NULL CHECK (teampage_parent >= 0),
+ PRIMARY KEY (teampage_id)
+);
+
+
/*
Table: 'phpbb_topics'
*/
@@ -1113,6 +1167,18 @@ CREATE INDEX phpbb_topics_watch_topic_id ON phpbb_topics_watch (topic_id);
CREATE INDEX phpbb_topics_watch_user_id ON phpbb_topics_watch (user_id);
CREATE INDEX phpbb_topics_watch_notify_stat ON phpbb_topics_watch (notify_status);
+/*
+ Table: 'phpbb_user_notifications'
+*/
+CREATE TABLE phpbb_user_notifications (
+ item_type varchar(255) DEFAULT '' NOT NULL,
+ item_id INT4 DEFAULT '0' NOT NULL CHECK (item_id >= 0),
+ user_id INT4 DEFAULT '0' NOT NULL CHECK (user_id >= 0),
+ method varchar(255) DEFAULT '' NOT NULL,
+ notify INT2 DEFAULT '1' NOT NULL CHECK (notify >= 0)
+);
+
+
/*
Table: 'phpbb_user_group'
*/
@@ -1187,7 +1253,7 @@ CREATE TABLE phpbb_users (
user_allow_massemail INT2 DEFAULT '1' NOT NULL CHECK (user_allow_massemail >= 0),
user_options INT4 DEFAULT '230271' NOT NULL CHECK (user_options >= 0),
user_avatar varchar(255) DEFAULT '' NOT NULL,
- user_avatar_type INT2 DEFAULT '0' NOT NULL,
+ user_avatar_type varchar(255) DEFAULT '' NOT NULL,
user_avatar_width INT2 DEFAULT '0' NOT NULL CHECK (user_avatar_width >= 0),
user_avatar_height INT2 DEFAULT '0' NOT NULL CHECK (user_avatar_height >= 0),
user_sig TEXT DEFAULT '' NOT NULL,
diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql
index 7c1a7d40f5..f118d330ba 100644
--- a/phpBB/install/schemas/schema_data.sql
+++ b/phpBB/install/schemas/schema_data.sql
@@ -9,6 +9,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('active_sessions',
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_attachments', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_autologin', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar', '1');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar_gravatar', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar_local', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar_remote', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar_upload', '1');
@@ -175,6 +176,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_jquery_cdn',
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_jquery_url', '//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_jumpbox', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_moderators', '1');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_notifications', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_online', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_online_guests', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_online_time', '5');
@@ -460,13 +462,17 @@ INSERT INTO phpbb_users (user_type, group_id, username, username_clean, user_reg
INSERT INTO phpbb_users (user_type, group_id, username, username_clean, user_regdate, user_password, user_email, user_lang, user_style, user_rank, user_colour, user_posts, user_permissions, user_ip, user_birthday, user_lastpage, user_last_confirm_key, user_post_sortby_type, user_post_sortby_dir, user_topic_sortby_type, user_topic_sortby_dir, user_avatar, user_sig, user_sig_bbcode_uid, user_from, user_icq, user_aim, user_yim, user_msnm, user_jabber, user_website, user_occ, user_interests, user_actkey, user_newpasswd) VALUES (3, 5, 'Admin', 'admin', 0, '21232f297a57a5a743894a0e4a801fc3', 'admin@yourdomain.com', 'en', 1, 1, 'AA0000', 1, '', '', '', '', '', 't', 'a', 't', 'd', '', '', '', '', '', '', '', '', '', '', '', '', '', '');
# -- Groups
-INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_teampage, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('GUESTS', 3, 0, '', 0, 0, '', '', '', 5);
-INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_teampage, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('REGISTERED', 3, 0, '', 0, 0, '', '', '', 5);
-INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_teampage, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('REGISTERED_COPPA', 3, 0, '', 0, 0, '', '', '', 5);
-INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_teampage, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('GLOBAL_MODERATORS', 3, 0, '00AA00', 2, 2, '', '', '', 0);
-INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_teampage, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('ADMINISTRATORS', 3, 1, 'AA0000', 1, 1, '', '', '', 0);
-INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_teampage, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('BOTS', 3, 0, '9E8DA7', 0, 0, '', '', '', 5);
-INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_teampage, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('NEWLY_REGISTERED', 3, 0, '', 0, 0, '', '', '', 5);
+INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('GUESTS', 3, 0, '', 0, '', '', '', 5);
+INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('REGISTERED', 3, 0, '', 0, '', '', '', 5);
+INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('REGISTERED_COPPA', 3, 0, '', 0, '', '', '', 5);
+INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('GLOBAL_MODERATORS', 3, 0, '00AA00', 2, '', '', '', 0);
+INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('ADMINISTRATORS', 3, 1, 'AA0000', 1, '', '', '', 0);
+INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('BOTS', 3, 0, '9E8DA7', 0, '', '', '', 5);
+INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('NEWLY_REGISTERED', 3, 0, '', 0, '', '', '', 5);
+
+# -- Teampage
+INSERT INTO phpbb_teampage (group_id, teampage_name, teampage_position, teampage_parent) VALUES (5, '', 1, 0);
+INSERT INTO phpbb_teampage (group_id, teampage_name, teampage_position, teampage_parent) VALUES (4, '', 2, 0);
# -- User -> Group
INSERT INTO phpbb_user_group (group_id, user_id, user_pending, group_leader) VALUES (1, 1, 0, 0);
@@ -770,4 +776,10 @@ INSERT INTO phpbb_extensions (group_id, extension) VALUES (9, 'mp3');
INSERT INTO phpbb_extensions (group_id, extension) VALUES (9, 'ogg');
INSERT INTO phpbb_extensions (group_id, extension) VALUES (9, 'ogm');
+# User Notification Options (for first user)
+INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('phpbb_notification_type_post', 0, 2, '');
+INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('phpbb_notification_type_post', 0, 2, 'phpbb_notification_method_email');
+INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('phpbb_notification_type_topic', 0, 2, '');
+INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('phpbb_notification_type_topic', 0, 2, 'phpbb_notification_method_email');
+
# POSTGRES COMMIT #
diff --git a/phpBB/install/schemas/sqlite_schema.sql b/phpBB/install/schemas/sqlite_schema.sql
index fe028bd12c..ccb67ad46f 100644
--- a/phpBB/install/schemas/sqlite_schema.sql
+++ b/phpBB/install/schemas/sqlite_schema.sql
@@ -154,6 +154,14 @@ CREATE TABLE phpbb_config (
CREATE INDEX phpbb_config_is_dynamic ON phpbb_config (is_dynamic);
+# Table: 'phpbb_config_text'
+CREATE TABLE phpbb_config_text (
+ config_name varchar(255) NOT NULL DEFAULT '',
+ config_value mediumtext(16777215) NOT NULL DEFAULT '',
+ PRIMARY KEY (config_name)
+);
+
+
# Table: 'phpbb_confirm'
CREATE TABLE phpbb_confirm (
confirm_id char(32) NOT NULL DEFAULT '',
@@ -309,7 +317,7 @@ CREATE TABLE phpbb_groups (
group_desc_uid varchar(8) NOT NULL DEFAULT '',
group_display INTEGER UNSIGNED NOT NULL DEFAULT '0',
group_avatar varchar(255) NOT NULL DEFAULT '',
- group_avatar_type tinyint(2) NOT NULL DEFAULT '0',
+ group_avatar_type varchar(255) NOT NULL DEFAULT '',
group_avatar_width INTEGER UNSIGNED NOT NULL DEFAULT '0',
group_avatar_height INTEGER UNSIGNED NOT NULL DEFAULT '0',
group_rank INTEGER UNSIGNED NOT NULL DEFAULT '0',
@@ -318,8 +326,7 @@ CREATE TABLE phpbb_groups (
group_receive_pm INTEGER UNSIGNED NOT NULL DEFAULT '0',
group_message_limit INTEGER UNSIGNED NOT NULL DEFAULT '0',
group_max_recipients INTEGER UNSIGNED NOT NULL DEFAULT '0',
- group_legend INTEGER UNSIGNED NOT NULL DEFAULT '0',
- group_teampage INTEGER UNSIGNED NOT NULL DEFAULT '0'
+ group_legend INTEGER UNSIGNED NOT NULL DEFAULT '0'
);
CREATE INDEX phpbb_groups_group_legend_name ON phpbb_groups (group_legend, group_name);
@@ -430,6 +437,29 @@ CREATE INDEX phpbb_modules_left_right_id ON phpbb_modules (left_id, right_id);
CREATE INDEX phpbb_modules_module_enabled ON phpbb_modules (module_enabled);
CREATE INDEX phpbb_modules_class_left_id ON phpbb_modules (module_class, left_id);
+# Table: 'phpbb_notification_types'
+CREATE TABLE phpbb_notification_types (
+ notification_type varchar(255) NOT NULL DEFAULT '',
+ notification_type_enabled INTEGER UNSIGNED NOT NULL DEFAULT '1',
+ PRIMARY KEY (notification_type, notification_type_enabled)
+);
+
+
+# Table: 'phpbb_notifications'
+CREATE TABLE phpbb_notifications (
+ notification_id INTEGER PRIMARY KEY NOT NULL ,
+ item_type varchar(255) NOT NULL DEFAULT '',
+ item_id INTEGER UNSIGNED NOT NULL DEFAULT '0',
+ item_parent_id INTEGER UNSIGNED NOT NULL DEFAULT '0',
+ user_id INTEGER UNSIGNED NOT NULL DEFAULT '0',
+ notification_read INTEGER UNSIGNED NOT NULL DEFAULT '0',
+ notification_time INTEGER UNSIGNED NOT NULL DEFAULT '1',
+ notification_data text(65535) NOT NULL DEFAULT ''
+);
+
+CREATE INDEX phpbb_notifications_item_ident ON phpbb_notifications (item_type, item_id);
+CREATE INDEX phpbb_notifications_user ON phpbb_notifications (user_id, notification_read);
+
# Table: 'phpbb_poll_options'
CREATE TABLE phpbb_poll_options (
poll_option_id tinyint(4) NOT NULL DEFAULT '0',
@@ -764,6 +794,16 @@ CREATE TABLE phpbb_styles (
CREATE UNIQUE INDEX phpbb_styles_style_name ON phpbb_styles (style_name);
+# Table: 'phpbb_teampage'
+CREATE TABLE phpbb_teampage (
+ teampage_id INTEGER PRIMARY KEY NOT NULL ,
+ group_id INTEGER UNSIGNED NOT NULL DEFAULT '0',
+ teampage_name varchar(255) NOT NULL DEFAULT '',
+ teampage_position INTEGER UNSIGNED NOT NULL DEFAULT '0',
+ teampage_parent INTEGER UNSIGNED NOT NULL DEFAULT '0'
+);
+
+
# Table: 'phpbb_topics'
CREATE TABLE phpbb_topics (
topic_id INTEGER PRIMARY KEY NOT NULL ,
@@ -841,6 +881,16 @@ CREATE INDEX phpbb_topics_watch_topic_id ON phpbb_topics_watch (topic_id);
CREATE INDEX phpbb_topics_watch_user_id ON phpbb_topics_watch (user_id);
CREATE INDEX phpbb_topics_watch_notify_stat ON phpbb_topics_watch (notify_status);
+# Table: 'phpbb_user_notifications'
+CREATE TABLE phpbb_user_notifications (
+ item_type varchar(255) NOT NULL DEFAULT '',
+ item_id INTEGER UNSIGNED NOT NULL DEFAULT '0',
+ user_id INTEGER UNSIGNED NOT NULL DEFAULT '0',
+ method varchar(255) NOT NULL DEFAULT '',
+ notify INTEGER UNSIGNED NOT NULL DEFAULT '1'
+);
+
+
# Table: 'phpbb_user_group'
CREATE TABLE phpbb_user_group (
group_id INTEGER UNSIGNED NOT NULL DEFAULT '0',
@@ -909,7 +959,7 @@ CREATE TABLE phpbb_users (
user_allow_massemail INTEGER UNSIGNED NOT NULL DEFAULT '1',
user_options INTEGER UNSIGNED NOT NULL DEFAULT '230271',
user_avatar varchar(255) NOT NULL DEFAULT '',
- user_avatar_type tinyint(2) NOT NULL DEFAULT '0',
+ user_avatar_type varchar(255) NOT NULL DEFAULT '',
user_avatar_width INTEGER UNSIGNED NOT NULL DEFAULT '0',
user_avatar_height INTEGER UNSIGNED NOT NULL DEFAULT '0',
user_sig mediumtext(16777215) NOT NULL DEFAULT '',
diff --git a/phpBB/language/en/acp/board.php b/phpBB/language/en/acp/board.php
index 1b99c87938..ff686f2360 100644
--- a/phpBB/language/en/acp/board.php
+++ b/phpBB/language/en/acp/board.php
@@ -99,6 +99,7 @@ $lang = array_merge($lang, array(
'ALLOW_AVATARS' => 'Enable avatars',
'ALLOW_AVATARS_EXPLAIN' => 'Allow general usage of avatars; If you disable avatars in general or avatars of a certain mode, the disabled avatars will no longer be shown on the board, but users will still be able to download their own avatars in the User Control Panel.',
+ 'ALLOW_GRAVATAR' => 'Enable gravatar avatars',
'ALLOW_LOCAL' => 'Enable gallery avatars',
'ALLOW_REMOTE' => 'Enable remote avatars',
'ALLOW_REMOTE_EXPLAIN' => 'Avatars linked to from another website.',
diff --git a/phpBB/language/en/acp/common.php b/phpBB/language/en/acp/common.php
index 427e4f4d98..93f163364b 100644
--- a/phpBB/language/en/acp/common.php
+++ b/phpBB/language/en/acp/common.php
@@ -252,6 +252,8 @@ $lang = array_merge($lang, array(
'IP' => 'User IP',
'IP_HOSTNAME' => 'IP addresses or hostnames',
+ 'LOAD_NOTIFICATIONS' => 'Display Notifications',
+ 'LOAD_NOTIFICATIONS_EXPLAIN' => 'Display the notifications list on every page (typically in the header).',
'LOGGED_IN_AS' => 'You are logged in as:',
'LOGIN_ADMIN' => 'To administer the board you must be an authenticated user.',
'LOGIN_ADMIN_CONFIRM' => 'To administer the board you must re-authenticate yourself.',
diff --git a/phpBB/language/en/acp/groups.php b/phpBB/language/en/acp/groups.php
index a5c0af933c..58101e5f60 100644
--- a/phpBB/language/en/acp/groups.php
+++ b/phpBB/language/en/acp/groups.php
@@ -36,6 +36,7 @@ if (empty($lang) || !is_array($lang))
$lang = array_merge($lang, array(
'ACP_GROUPS_MANAGE_EXPLAIN' => 'From this panel you can administer all your usergroups. You can delete, create and edit existing groups. Furthermore, you may choose group leaders, toggle open/hidden/closed group status and set the group name and description.',
+ 'ADD_GROUP_CATEGORY' => 'Add category',
'ADD_USERS' => 'Add users',
'ADD_USERS_EXPLAIN' => 'Here you can add new users to the group. You may select whether this group becomes the new default for the selected users. Additionally you can define them as group leaders. Please enter each username on a separate line.',
@@ -50,6 +51,7 @@ $lang = array_merge($lang, array(
'GROUP_APPROVED' => 'Approved members',
'GROUP_AVATAR' => 'Group avatar',
'GROUP_AVATAR_EXPLAIN' => 'This image will be displayed in the Group Control Panel.',
+ 'GROUP_CATEGORY_NAME' => 'Category name',
'GROUP_CLOSED' => 'Closed',
'GROUP_COLOR' => 'Group colour',
'GROUP_COLOR_EXPLAIN' => 'Defines the colour members’ usernames will appear in, leave blank for user default.',
@@ -130,6 +132,7 @@ $lang = array_merge($lang, array(
'SPECIAL_GROUPS' => 'Pre-defined groups',
'SPECIAL_GROUPS_EXPLAIN' => 'Pre-defined groups are special groups, they cannot be deleted or directly modified. However you can still add users and alter basic settings.',
+ 'TEAMPAGE' => 'Teampage',
'TEAMPAGE_DISP_ALL' => 'All memberships',
'TEAMPAGE_DISP_DEFAULT' => 'User’s default group only',
'TEAMPAGE_DISP_FIRST' => 'First membership only',
diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php
index ad29965434..5d6fe03b5f 100644
--- a/phpBB/language/en/common.php
+++ b/phpBB/language/en/common.php
@@ -359,9 +359,11 @@ $lang = array_merge($lang, array(
'LOGOUT_USER' => 'Logout [ %s ]',
'LOG_ME_IN' => 'Remember me',
+ 'MAIN' => 'Main',
'MARK' => 'Mark',
'MARK_ALL' => 'Mark all',
'MARK_FORUMS_READ' => 'Mark forums read',
+ 'MARK_READ' => 'Mark read',
'MARK_SUBFORUMS_READ' => 'Mark subforums read',
'MB' => 'MB',
'MIB' => 'MiB',
@@ -396,10 +398,31 @@ $lang = array_merge($lang, array(
'NEXT_STEP' => 'Next',
'NEVER' => 'Never',
'NO' => 'No',
+ 'NO_NOTIFICATIONS' => 'You have no notifications',
'NOT_ALLOWED_MANAGE_GROUP' => 'You are not allowed to manage this group.',
'NOT_AUTHORISED' => 'You are not authorised to access this area.',
'NOT_WATCHING_FORUM' => 'You are no longer subscribed to updates on this forum.',
'NOT_WATCHING_TOPIC' => 'You are no longer subscribed to this topic.',
+ 'NOTIFICATIONS' => 'Notifications',
+ 'NOTIFICATIONS_COUNT' => array(
+ 0 => '%d Notifications',
+ 1 => '%d Notification',
+ 2 => '%d Notifications',
+ ),
+ 'NOTIFICATION_BOOKMARK' => '%1$s replied to the topic "%2$s" you have bookmarked.',
+ 'NOTIFICATION_PM' => '%1$s sent you a Private Message "%2$s".',
+ 'NOTIFICATION_POST' => '%1$s replied to the topic "%2$s".',
+ 'NOTIFICATION_POST_APPROVED' => 'Your post was approved "%2$s".',
+ 'NOTIFICATION_POST_DISAPPROVED' => 'Your post "%1$s" was disapproved for reason: "%2$s".',
+ 'NOTIFICATION_POST_IN_QUEUE' => 'A new post titled "%2$s" was posted by %1$s and needs approval.',
+ 'NOTIFICATION_QUOTE' => '%1$s quoted you in the post "%2$s".',
+ 'NOTIFICATION_REPORT_PM' => '%1$s reported a Private Message "%2$s" for reason: "%3$s".',
+ 'NOTIFICATION_REPORT_POST' => '%1$s reported a post "%2$s" for reason: "%3$s".',
+ 'NOTIFICATION_REPORT_CLOSED' => '%1$s closed the report you made for "%2$s".',
+ 'NOTIFICATION_TOPIC' => '%1$s posted a new topic "%2$s" in the forum "%3$s".',
+ 'NOTIFICATION_TOPIC_APPROVED' => 'Your topic "%2$s" in the forum "%3$s" was approved.',
+ 'NOTIFICATION_TOPIC_DISAPPROVED' => 'Your topic "%1$s" was disapproved for reason: "%2$s".',
+ 'NOTIFICATION_TOPIC_IN_QUEUE' => 'A new topic titled "%2$s" was posted by %1$s and needs approval.',
'NOTIFY_ADMIN' => 'Please notify the board administrator or webmaster.',
'NOTIFY_ADMIN_EMAIL' => 'Please notify the board administrator or webmaster: %1$s',
'NO_ACCESS_ATTACHMENT' => 'You are not allowed to access this file.',
@@ -408,6 +431,8 @@ $lang = array_merge($lang, array(
'NO_AUTH_ADMIN' => 'Access to the Administration Control Panel is not allowed as you do not have administrative permissions.',
'NO_AUTH_ADMIN_USER_DIFFER' => 'You are not able to re-authenticate as a different user.',
'NO_AUTH_OPERATION' => 'You do not have the necessary permissions to complete this operation.',
+ 'NO_AVATARS' => 'No avatars currently available',
+ 'NO_AVATAR_SELECTED' => 'You have not selected any avatar.',
'NO_CONNECT_TO_SMTP_HOST' => 'Could not connect to smtp host : %1$s : %2$s',
'NO_BIRTHDAYS' => 'No birthdays today',
'NO_EMAIL_MESSAGE' => 'Email message was blank.',
@@ -587,6 +612,7 @@ $lang = array_merge($lang, array(
'SEARCH_UNREAD' => 'View unread posts',
'SEARCH_USER_POSTS' => 'Search user’s posts',
'SECONDS' => 'Seconds',
+ 'SEE_ALL' => 'See All',
'SELECT' => 'Select',
'SELECT_ALL_CODE' => 'Select all',
'SELECT_DESTINATION_FORUM' => 'Please select a destination forum',
diff --git a/phpBB/language/en/email/bookmark.txt b/phpBB/language/en/email/bookmark.txt
new file mode 100644
index 0000000000..95f17b5693
--- /dev/null
+++ b/phpBB/language/en/email/bookmark.txt
@@ -0,0 +1,20 @@
+Subject: Topic reply notification - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because a topic you bookmarked, "{TOPIC_TITLE}" at "{SITENAME}", has received a reply since your last visit. You can use the following link to view the replies made, no more notifications will be sent until you visit the topic.
+
+If you want to view the newest post made since your last visit, click the following link:
+{U_NEWEST_POST}
+
+If you want to view the topic, click the following link:
+{U_TOPIC}
+
+If you want to view the forum, click the following link:
+{U_FORUM}
+
+If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
+
+{U_NOTIFICATION_SETTINGS}
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/forum_notify.txt b/phpBB/language/en/email/forum_notify.txt
index 490780a0a6..66f3a68689 100644
--- a/phpBB/language/en/email/forum_notify.txt
+++ b/phpBB/language/en/email/forum_notify.txt
@@ -2,7 +2,7 @@ Subject: Forum post notification - "{FORUM_NAME}"
Hello {USERNAME},
-You are receiving this notification because you are watching the forum, "{FORUM_NAME}" at "{SITENAME}". This forum has received a new reply to the topic "{TOPIC_TITLE}" by {AUTHOR_NAME} since your last visit. You can use the following link to view the last unread reply, no more notifications will be sent until you visit the topic.
+You are receiving this notification because you are watching the forum "{FORUM_NAME}" at "{SITENAME}". This forum has received a new reply to the topic "{TOPIC_TITLE}" by {AUTHOR_NAME} since your last visit. You can use the following link to view the last unread reply, no more notifications will be sent until you visit the topic.
{U_NEWEST_POST}
diff --git a/phpBB/language/en/email/newtopic_notify.txt b/phpBB/language/en/email/newtopic_notify.txt
index eda1370938..bf6799e5be 100644
--- a/phpBB/language/en/email/newtopic_notify.txt
+++ b/phpBB/language/en/email/newtopic_notify.txt
@@ -2,7 +2,7 @@ Subject: New topic notification - "{FORUM_NAME}"
Hello {USERNAME},
-You are receiving this notification because you are watching the forum, "{FORUM_NAME}" at "{SITENAME}". This forum has received a new topic by {AUTHOR_NAME} since your last visit, "{TOPIC_TITLE}". You can use the following link to view the forum, no more notifications will be sent until you visit the forum.
+You are receiving this notification because you are watching the forum "{FORUM_NAME}" at "{SITENAME}". This forum has received a new topic by {AUTHOR_NAME} since your last visit, "{TOPIC_TITLE}". You can use the following link to view the forum, no more notifications will be sent until you visit the forum.
{U_FORUM}
@@ -10,4 +10,4 @@ If you no longer wish to watch this forum you can either click the "Unsubscribe
{U_STOP_WATCHING_FORUM}
-{EMAIL_SIG}
\ No newline at end of file
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/post_disapproved.txt b/phpBB/language/en/email/post_disapproved.txt
index 3bc64bb611..2f8a8381cb 100644
--- a/phpBB/language/en/email/post_disapproved.txt
+++ b/phpBB/language/en/email/post_disapproved.txt
@@ -9,4 +9,4 @@ The following reason was given for the disapproval:
{REASON}
-{EMAIL_SIG}
\ No newline at end of file
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/post_in_queue.txt b/phpBB/language/en/email/post_in_queue.txt
new file mode 100644
index 0000000000..8d56ce6c4d
--- /dev/null
+++ b/phpBB/language/en/email/post_in_queue.txt
@@ -0,0 +1,17 @@
+Subject: Topic reply notification - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because the post "{POST_SUBJECT}" at "{SITENAME}" needs approval.
+
+If you want to view the post, click the following link:
+{U_VIEW_POST}
+
+If you want to view the topic, click the following link:
+{U_TOPIC}
+
+If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
+
+{U_NOTIFICATION_SETTINGS}
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/privmsg_notify.txt b/phpBB/language/en/email/privmsg_notify.txt
index d3a86cc73c..41fdbb782c 100644
--- a/phpBB/language/en/email/privmsg_notify.txt
+++ b/phpBB/language/en/email/privmsg_notify.txt
@@ -12,4 +12,4 @@ You can view your new message by clicking on the following link:
You have requested that you be notified on this event, remember that you can always choose not to be notified of new messages by changing the appropriate setting in your profile.
-{EMAIL_SIG}
\ No newline at end of file
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/quote.txt b/phpBB/language/en/email/quote.txt
new file mode 100644
index 0000000000..2b9525801f
--- /dev/null
+++ b/phpBB/language/en/email/quote.txt
@@ -0,0 +1,20 @@
+Subject: Topic reply notification - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because "{AUTHOR_NAME}" quoted you in the topic "{TOPIC_TITLE}" at "{SITENAME}". You can use the following link to view the reply made.
+
+If you want to view the quoted post, click the following link:
+{U_VIEW_POST}
+
+If you want to view the topic, click the following link:
+{U_TOPIC}
+
+If you want to view the forum, click the following link:
+{U_FORUM}
+
+If you no longer wish to receive updates about replies quoting you, please update your notification settings here:
+
+{U_NOTIFICATION_SETTINGS}
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/report_pm.txt b/phpBB/language/en/email/report_pm.txt
new file mode 100644
index 0000000000..66ae82d074
--- /dev/null
+++ b/phpBB/language/en/email/report_pm.txt
@@ -0,0 +1,14 @@
+Subject: Topic reply notification - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because a Private Message titled "{SUBJECT}" by "{AUTHOR_NAME}" at "{SITENAME}" was reported.
+
+If you want to view the report, click the following link:
+{U_VIEW_REPORT}
+
+If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
+
+{U_NOTIFICATION_SETTINGS}
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/report_post.txt b/phpBB/language/en/email/report_post.txt
new file mode 100644
index 0000000000..46983be1ed
--- /dev/null
+++ b/phpBB/language/en/email/report_post.txt
@@ -0,0 +1,17 @@
+Subject: Topic reply notification - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because the post "{POST_SUBJECT}" at "{SITENAME}" was reported.
+
+If you want to view the report, click the following link:
+{U_VIEW_REPORT}
+
+If you want to view the post, click the following link:
+{U_VIEW_POST}
+
+If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
+
+{U_NOTIFICATION_SETTINGS}
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/bookmark.txt b/phpBB/language/en/email/short/bookmark.txt
new file mode 100644
index 0000000000..95f17b5693
--- /dev/null
+++ b/phpBB/language/en/email/short/bookmark.txt
@@ -0,0 +1,20 @@
+Subject: Topic reply notification - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because a topic you bookmarked, "{TOPIC_TITLE}" at "{SITENAME}", has received a reply since your last visit. You can use the following link to view the replies made, no more notifications will be sent until you visit the topic.
+
+If you want to view the newest post made since your last visit, click the following link:
+{U_NEWEST_POST}
+
+If you want to view the topic, click the following link:
+{U_TOPIC}
+
+If you want to view the forum, click the following link:
+{U_FORUM}
+
+If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
+
+{U_NOTIFICATION_SETTINGS}
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/newtopic_notify.txt b/phpBB/language/en/email/short/newtopic_notify.txt
new file mode 100644
index 0000000000..bf6799e5be
--- /dev/null
+++ b/phpBB/language/en/email/short/newtopic_notify.txt
@@ -0,0 +1,13 @@
+Subject: New topic notification - "{FORUM_NAME}"
+
+Hello {USERNAME},
+
+You are receiving this notification because you are watching the forum "{FORUM_NAME}" at "{SITENAME}". This forum has received a new topic by {AUTHOR_NAME} since your last visit, "{TOPIC_TITLE}". You can use the following link to view the forum, no more notifications will be sent until you visit the forum.
+
+{U_FORUM}
+
+If you no longer wish to watch this forum you can either click the "Unsubscribe forum" link found in the forum above, or by clicking the following link:
+
+{U_STOP_WATCHING_FORUM}
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/post_approved.txt b/phpBB/language/en/email/short/post_approved.txt
new file mode 100644
index 0000000000..e715b54026
--- /dev/null
+++ b/phpBB/language/en/email/short/post_approved.txt
@@ -0,0 +1,14 @@
+Subject: Post approved - "{POST_SUBJECT}"
+
+Hello {USERNAME},
+
+You are receiving this notification because your post "{POST_SUBJECT}" at "{SITENAME}" was approved by a moderator or administrator.
+
+If you want to view the post, click the following link:
+{U_VIEW_POST}
+
+If you want to view the topic, click the following link:
+{U_VIEW_TOPIC}
+
+
+{EMAIL_SIG}
\ No newline at end of file
diff --git a/phpBB/language/en/email/short/post_disapproved.txt b/phpBB/language/en/email/short/post_disapproved.txt
new file mode 100644
index 0000000000..2f8a8381cb
--- /dev/null
+++ b/phpBB/language/en/email/short/post_disapproved.txt
@@ -0,0 +1,12 @@
+Subject: Post disapproved - "{POST_SUBJECT}"
+
+Hello {USERNAME},
+
+You are receiving this notification because your post "{POST_SUBJECT}" at "{SITENAME}" was disapproved by a moderator or administrator.
+
+The following reason was given for the disapproval:
+
+{REASON}
+
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/post_in_queue.txt b/phpBB/language/en/email/short/post_in_queue.txt
new file mode 100644
index 0000000000..8d56ce6c4d
--- /dev/null
+++ b/phpBB/language/en/email/short/post_in_queue.txt
@@ -0,0 +1,17 @@
+Subject: Topic reply notification - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because the post "{POST_SUBJECT}" at "{SITENAME}" needs approval.
+
+If you want to view the post, click the following link:
+{U_VIEW_POST}
+
+If you want to view the topic, click the following link:
+{U_TOPIC}
+
+If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
+
+{U_NOTIFICATION_SETTINGS}
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/privmsg_notify.txt b/phpBB/language/en/email/short/privmsg_notify.txt
new file mode 100644
index 0000000000..41fdbb782c
--- /dev/null
+++ b/phpBB/language/en/email/short/privmsg_notify.txt
@@ -0,0 +1,15 @@
+Subject: New private message has arrived
+
+Hello {USERNAME},
+
+You have received a new private message from "{AUTHOR_NAME}" to your account on "{SITENAME}" with the following subject:
+
+{SUBJECT}
+
+You can view your new message by clicking on the following link:
+
+{U_VIEW_MESSAGE}
+
+You have requested that you be notified on this event, remember that you can always choose not to be notified of new messages by changing the appropriate setting in your profile.
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/quote.txt b/phpBB/language/en/email/short/quote.txt
new file mode 100644
index 0000000000..2b9525801f
--- /dev/null
+++ b/phpBB/language/en/email/short/quote.txt
@@ -0,0 +1,20 @@
+Subject: Topic reply notification - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because "{AUTHOR_NAME}" quoted you in the topic "{TOPIC_TITLE}" at "{SITENAME}". You can use the following link to view the reply made.
+
+If you want to view the quoted post, click the following link:
+{U_VIEW_POST}
+
+If you want to view the topic, click the following link:
+{U_TOPIC}
+
+If you want to view the forum, click the following link:
+{U_FORUM}
+
+If you no longer wish to receive updates about replies quoting you, please update your notification settings here:
+
+{U_NOTIFICATION_SETTINGS}
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/report_pm.txt b/phpBB/language/en/email/short/report_pm.txt
new file mode 100644
index 0000000000..66ae82d074
--- /dev/null
+++ b/phpBB/language/en/email/short/report_pm.txt
@@ -0,0 +1,14 @@
+Subject: Topic reply notification - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because a Private Message titled "{SUBJECT}" by "{AUTHOR_NAME}" at "{SITENAME}" was reported.
+
+If you want to view the report, click the following link:
+{U_VIEW_REPORT}
+
+If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
+
+{U_NOTIFICATION_SETTINGS}
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/report_post.txt b/phpBB/language/en/email/short/report_post.txt
new file mode 100644
index 0000000000..46983be1ed
--- /dev/null
+++ b/phpBB/language/en/email/short/report_post.txt
@@ -0,0 +1,17 @@
+Subject: Topic reply notification - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because the post "{POST_SUBJECT}" at "{SITENAME}" was reported.
+
+If you want to view the report, click the following link:
+{U_VIEW_REPORT}
+
+If you want to view the post, click the following link:
+{U_VIEW_POST}
+
+If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
+
+{U_NOTIFICATION_SETTINGS}
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/topic_approved.txt b/phpBB/language/en/email/short/topic_approved.txt
new file mode 100644
index 0000000000..0b09918b89
--- /dev/null
+++ b/phpBB/language/en/email/short/topic_approved.txt
@@ -0,0 +1,11 @@
+Subject: Topic approved - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because your topic "{TOPIC_TITLE}" at "{SITENAME}" was approved by a moderator or administrator.
+
+If you want to view the topic, click the following link:
+{U_VIEW_TOPIC}
+
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/topic_disapproved.txt b/phpBB/language/en/email/short/topic_disapproved.txt
new file mode 100644
index 0000000000..a4bd9c151e
--- /dev/null
+++ b/phpBB/language/en/email/short/topic_disapproved.txt
@@ -0,0 +1,12 @@
+Subject: Topic disapproved - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because your topic "{TOPIC_TITLE}" at "{SITENAME}" was disapproved by a moderator or administrator.
+
+The following reason was given for the disapproval:
+
+{REASON}
+
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/topic_in_queue.txt b/phpBB/language/en/email/short/topic_in_queue.txt
new file mode 100644
index 0000000000..ae8f9e2484
--- /dev/null
+++ b/phpBB/language/en/email/short/topic_in_queue.txt
@@ -0,0 +1,17 @@
+Subject: Topic reply notification - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because the topic "{TOPIC_TITLE}" at "{SITENAME}" needs approval.
+
+If you want to view the topic, click the following link:
+{U_VIEW_TOPIC}
+
+If you want to view the forum, click the following link:
+{U_FORUM}
+
+If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
+
+{U_NOTIFICATION_SETTINGS}
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/topic_notify.txt b/phpBB/language/en/email/short/topic_notify.txt
new file mode 100644
index 0000000000..472375fb22
--- /dev/null
+++ b/phpBB/language/en/email/short/topic_notify.txt
@@ -0,0 +1,20 @@
+Subject: Topic reply notification - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because you are watching the topic "{TOPIC_TITLE}" at "{SITENAME}". This topic has received a reply by {AUTHOR_NAME} since your last visit. You can use the following link to view the replies made, no more notifications will be sent until you visit the topic.
+
+If you want to view the newest post made since your last visit, click the following link:
+{U_NEWEST_POST}
+
+If you want to view the topic, click the following link:
+{U_TOPIC}
+
+If you want to view the forum, click the following link:
+{U_FORUM}
+
+If you no longer wish to watch this topic you can either click the "Unsubscribe topic" link found at the bottom of the topic above, or by clicking the following link:
+
+{U_STOP_WATCHING_TOPIC}
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/topic_approved.txt b/phpBB/language/en/email/topic_approved.txt
index ffda378d30..0b09918b89 100644
--- a/phpBB/language/en/email/topic_approved.txt
+++ b/phpBB/language/en/email/topic_approved.txt
@@ -8,4 +8,4 @@ If you want to view the topic, click the following link:
{U_VIEW_TOPIC}
-{EMAIL_SIG}
\ No newline at end of file
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/topic_disapproved.txt b/phpBB/language/en/email/topic_disapproved.txt
index 49ef58bf39..a4bd9c151e 100644
--- a/phpBB/language/en/email/topic_disapproved.txt
+++ b/phpBB/language/en/email/topic_disapproved.txt
@@ -9,4 +9,4 @@ The following reason was given for the disapproval:
{REASON}
-{EMAIL_SIG}
\ No newline at end of file
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/topic_in_queue.txt b/phpBB/language/en/email/topic_in_queue.txt
new file mode 100644
index 0000000000..ae8f9e2484
--- /dev/null
+++ b/phpBB/language/en/email/topic_in_queue.txt
@@ -0,0 +1,17 @@
+Subject: Topic reply notification - "{TOPIC_TITLE}"
+
+Hello {USERNAME},
+
+You are receiving this notification because the topic "{TOPIC_TITLE}" at "{SITENAME}" needs approval.
+
+If you want to view the topic, click the following link:
+{U_VIEW_TOPIC}
+
+If you want to view the forum, click the following link:
+{U_FORUM}
+
+If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
+
+{U_NOTIFICATION_SETTINGS}
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/topic_notify.txt b/phpBB/language/en/email/topic_notify.txt
index fcfbcc2abd..472375fb22 100644
--- a/phpBB/language/en/email/topic_notify.txt
+++ b/phpBB/language/en/email/topic_notify.txt
@@ -2,7 +2,7 @@ Subject: Topic reply notification - "{TOPIC_TITLE}"
Hello {USERNAME},
-You are receiving this notification because you are watching the topic, "{TOPIC_TITLE}" at "{SITENAME}". This topic has received a reply by {AUTHOR_NAME} since your last visit. You can use the following link to view the replies made, no more notifications will be sent until you visit the topic.
+You are receiving this notification because you are watching the topic "{TOPIC_TITLE}" at "{SITENAME}". This topic has received a reply by {AUTHOR_NAME} since your last visit. You can use the following link to view the replies made, no more notifications will be sent until you visit the topic.
If you want to view the newest post made since your last visit, click the following link:
{U_NEWEST_POST}
@@ -17,4 +17,4 @@ If you no longer wish to watch this topic you can either click the "Unsubscribe
{U_STOP_WATCHING_TOPIC}
-{EMAIL_SIG}
\ No newline at end of file
+{EMAIL_SIG}
diff --git a/phpBB/language/en/migrator.php b/phpBB/language/en/migrator.php
index 84074c391c..f94c27be8c 100644
--- a/phpBB/language/en/migrator.php
+++ b/phpBB/language/en/migrator.php
@@ -35,21 +35,20 @@ if (empty($lang) || !is_array($lang))
// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine
$lang = array_merge($lang, array(
- 'CONFIG_ALREADY_EXIST' => 'The config setting "%s" unexpectedly already exists.',
'CONFIG_NOT_EXIST' => 'The config setting "%s" unexpectedly does not exist.',
'GROUP_NOT_EXIST' => 'The group "%s" unexpectedly does not exist.',
+ 'MIGRATION_DATA_DONE' => 'Installed Data: %s',
+ 'MIGRATION_EFFECTIVELY_INSTALLED' => 'Migration already effectively installed (skipped): %s',
'MIGRATION_EXCEPTION_ERROR' => 'Something went wrong during the request and an exception was thrown. The changes made before the error occurred were reversed to the best of our abilities, but you should check the board for errors.',
'MIGRATION_NOT_FULFILLABLE' => 'The migration "%1$s" is not fulfillable, missing migration "%2$s".',
+ 'MIGRATION_SCHEMA_DONE' => 'Installed Schema: %s',
- 'MODULE_ALREADY_EXIST' => 'The module "%s" unexpectedly already exists.',
'MODULE_ERROR' => 'An error occured while creating a module: %s',
'MODULE_INFO_FILE_NOT_EXIST' => 'A required module info file is missing: %2$s',
'MODULE_NOT_EXIST' => 'A required module does not exist: %s',
- 'MODULE_NOT_REMOVABLE' => 'Module %1$s was unable to be removed: %2$s',
- 'PERMISSION_ALREADY_EXIST' => 'The permission setting "%s" unexpectedly already exists.',
'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/ucp.php b/phpBB/language/en/ucp.php
index 0609c1d5fe..3e090a8aec 100644
--- a/phpBB/language/en/ucp.php
+++ b/phpBB/language/en/ucp.php
@@ -89,12 +89,22 @@ $lang = array_merge($lang, array(
'ATTACHMENT_DELETED' => 'Attachment successfully deleted.',
'AUTOLOGIN_SESSION_KEYS_DELETED'=> 'The selected "Remember Me" login keys were successfully deleted.',
'AVATAR_CATEGORY' => 'Category',
+ 'AVATAR_DRIVER_GRAVATAR_TITLE' => 'Gravatar',
+ 'AVATAR_DRIVER_GRAVATAR_EXPLAIN'=> 'Gravatar is a service that allows you to maintain the same avatar across multiple websites. Visit Gravatar for more information.',
+ 'AVATAR_DRIVER_LOCAL_TITLE' => 'Gallery avatar',
+ 'AVATAR_DRIVER_LOCAL_EXPLAIN' => 'You can choose your avatar from a locally available set of avatars.',
+ 'AVATAR_DRIVER_REMOTE_TITLE' => 'Remote avatar',
+ 'AVATAR_DRIVER_REMOTE_EXPLAIN' => 'Link to avatar images from another website.',
+ 'AVATAR_DRIVER_UPLOAD_TITLE' => 'Upload avatar',
+ 'AVATAR_DRIVER_UPLOAD_EXPLAIN' => 'Upload your own custom avatar.',
'AVATAR_EXPLAIN' => 'Maximum dimensions; width: %1$s, height: %2$s, file size: %3$.2f KiB.',
'AVATAR_FEATURES_DISABLED' => 'The avatar functionality is currently disabled.',
'AVATAR_GALLERY' => 'Local gallery',
'AVATAR_GENERAL_UPLOAD_ERROR' => 'Could not upload avatar to %s.',
'AVATAR_NOT_ALLOWED' => 'Your avatar cannot be displayed because avatars have been disallowed.',
'AVATAR_PAGE' => 'Page',
+ 'AVATAR_SELECT' => 'Select your avatar',
+ 'AVATAR_TYPE' => 'Avatar type',
'AVATAR_TYPE_NOT_ALLOWED' => 'Your current avatar cannot be displayed because its type has been disallowed.',
'BACK_TO_DRAFTS' => 'Back to saved drafts',
@@ -235,6 +245,11 @@ $lang = array_merge($lang, array(
'GLOBAL_ANNOUNCEMENT' => 'Global announcement',
+ 'GRAVATAR_AVATAR_EMAIL' => 'Gravatar email',
+ 'GRAVATAR_AVATAR_EMAIL_EXPLAIN' => 'Enter the email address you used for registering your account on Gravatar.',
+ 'GRAVATAR_AVATAR_SIZE' => 'Avatar dimensions',
+ 'GRAVATAR_AVATAR_SIZE_EXPLAIN' => 'Specify the width and height of the avatar, leave blank to attempt automatic verification.',
+
'HIDE_ONLINE' => 'Hide my online status',
'HIDE_ONLINE_EXPLAIN' => 'Changing this setting won’t become effective until your next visit to the board.',
'HOLD_NEW_MESSAGES' => 'Do not accept new messages (New messages will be held back until enough space is available)',
@@ -287,6 +302,25 @@ $lang = array_merge($lang, array(
'NEW_PASSWORD' => 'New password',
'NEW_PASSWORD_CONFIRM_EMPTY' => 'You did not enter a confirm password.',
'NEW_PASSWORD_ERROR' => 'The passwords you entered do not match.',
+
+ 'NOTIFICATIONS_MARK_ALL_READ' => 'Mark all notifications read',
+ 'NOTIFICATIONS_MARK_ALL_READ_CONFIRM' => 'Are you sure you want to mark all notifications read?',
+ 'NOTIFICATIONS_MARK_ALL_READ_SUCCESS' => 'All notifications have been marked read.',
+ 'NOTIFICATION_GROUP_MISCELLANEOUS' => 'Miscellaneous Notifications',
+ 'NOTIFICATION_GROUP_MODERATION' => 'Moderation Notifications',
+ 'NOTIFICATION_GROUP_POSTING' => 'Posting Notifications',
+ 'NOTIFICATION_METHOD_EMAIL' => 'Email',
+ 'NOTIFICATION_METHOD_JABBER' => 'Jabber',
+ 'NOTIFICATION_TYPE' => 'Notification type',
+ 'NOTIFICATION_TYPE_BOOKMARK' => 'Someone replies to a topic you have bookmarked',
+ 'NOTIFICATION_TYPE_IN_MODERATION_QUEUE' => 'A post or topic needs approval',
+ 'NOTIFICATION_TYPE_MODERATION_QUEUE' => 'Your topics/posts are approved or disapproved by a moderator',
+ 'NOTIFICATION_TYPE_PM' => 'Someone sends you a private message',
+ 'NOTIFICATION_TYPE_POST' => 'Someone replies to a topic to which you are subscribed',
+ 'NOTIFICATION_TYPE_QUOTE' => 'Someone quotes you in a post',
+ 'NOTIFICATION_TYPE_REPORT' => 'Someone reports a post',
+ 'NOTIFICATION_TYPE_TOPIC' => 'Someone creates a topic in a forum to which you are subscribed',
+
'NOTIFY_METHOD' => 'Notification method',
'NOTIFY_METHOD_BOTH' => 'Both',
'NOTIFY_METHOD_EMAIL' => 'Email only',
@@ -457,6 +491,11 @@ $lang = array_merge($lang, array(
'UCP_MSNM' => 'Windows Live Messenger',
'UCP_NO_ATTACHMENTS' => 'You have posted no files.',
+ 'UCP_NOTIFICATION_LIST' => 'Manage notifications',
+ 'UCP_NOTIFICATION_LIST_EXPLAIN' => 'Here you may view all past notifications.',
+ 'UCP_NOTIFICATION_OPTIONS' => 'Edit notification options',
+ 'UCP_NOTIFICATION_OPTIONS_EXPLAIN' => 'Here you can set your preferred notification methods for the board.',
+
'UCP_PREFS' => 'Board preferences',
'UCP_PREFS_PERSONAL' => 'Edit global settings',
'UCP_PREFS_POST' => 'Edit posting defaults',
diff --git a/phpBB/memberlist.php b/phpBB/memberlist.php
index e222d4478d..d25583b84a 100644
--- a/phpBB/memberlist.php
+++ b/phpBB/memberlist.php
@@ -71,21 +71,28 @@ switch ($mode)
$page_title = $user->lang['THE_TEAM'];
$template_html = 'memberlist_leaders.html';
+ $sql = 'SELECT *
+ FROM ' . TEAMPAGE_TABLE . '
+ ORDER BY teampage_position ASC';
+ $result = $db->sql_query($sql, 3600);
+ $teampage_data = $db->sql_fetchrowset($result);
+ $db->sql_freeresult($result);
+
$sql_ary = array(
- 'SELECT' => 'g.group_id, g.group_name, g.group_colour, g.group_type, g.group_teampage, ug.user_id as ug_user_id',
+ 'SELECT' => 'g.group_id, g.group_name, g.group_colour, g.group_type, ug.user_id as ug_user_id, t.teampage_id',
'FROM' => array(GROUPS_TABLE => 'g'),
'LEFT_JOIN' => array(
+ array(
+ 'FROM' => array(TEAMPAGE_TABLE => 't'),
+ 'ON' => 't.group_id = g.group_id',
+ ),
array(
'FROM' => array(USER_GROUP_TABLE => 'ug'),
'ON' => 'ug.group_id = g.group_id AND ug.user_pending = 0 AND ug.user_id = ' . (int) $user->data['user_id'],
),
),
-
- 'WHERE' => '',
-
- 'ORDER_BY' => 'g.group_teampage ASC',
);
$result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary));
@@ -104,7 +111,7 @@ switch ($mode)
$row['u_group'] = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $row['group_id']);
}
- if ($row['group_teampage'])
+ if ($row['teampage_id'])
{
// Only put groups into the array we want to display.
// We are fetching all groups, to ensure we got all data for default groups.
@@ -204,10 +211,26 @@ switch ($mode)
}
}
- foreach ($groups_ary as $group_id => $group_data)
+ $parent_team = 0;
+ foreach ($teampage_data as $team_data)
{
- if ($group_data['group_teampage'])
+ // If this team entry has no group, it's a category
+ if (!$team_data['group_id'])
{
+ $template->assign_block_vars('group', array(
+ 'GROUP_NAME' => $team_data['teampage_name'],
+ ));
+
+ $parent_team = (int) $team_data['teampage_id'];
+ continue;
+ }
+
+ $group_data = $groups_ary[(int) $team_data['group_id']];
+ $group_id = (int) $team_data['group_id'];
+
+ if (!$team_data['teampage_parent'])
+ {
+ // If the group does not have a parent category, we display the groupname as category
$template->assign_block_vars('group', array(
'GROUP_NAME' => $group_data['group_name'],
'GROUP_COLOR' => $group_data['group_colour'],
@@ -223,7 +246,7 @@ switch ($mode)
if (isset($user_ary[$user_id]))
{
$row = $user_ary[$user_id];
- if ($config['teampage_memberships'] == 1 && ($group_id != $groups_ary[$row['default_group']]['group_id']) && $groups_ary[$row['default_group']]['group_teampage'])
+ if ($config['teampage_memberships'] == 1 && ($group_id != $groups_ary[$row['default_group']]['group_id']) && $groups_ary[$row['default_group']]['teampage_id'])
{
// Display users in their primary group, instead of the first group, when it is displayed on the teampage.
continue;
@@ -549,7 +572,7 @@ switch ($mode)
$member['user_sig'] = smiley_text($member['user_sig']);
}
- $poster_avatar = get_user_avatar($member['user_avatar'], $member['user_avatar_type'], $member['user_avatar_width'], $member['user_avatar_height']);
+ $poster_avatar = phpbb_get_user_avatar($member);
// We need to check if the modules 'zebra' ('friends' & 'foes' mode), 'notes' ('user_notes' mode) and 'warn' ('warn_user' mode) are accessible to decide if we can display appropriate links
$zebra_enabled = $friends_enabled = $foes_enabled = $user_notes_enabled = $warn_user_enabled = false;
@@ -1234,8 +1257,7 @@ switch ($mode)
break;
}
- // Misusing the avatar function for displaying group avatars...
- $avatar_img = get_user_avatar($group_row['group_avatar'], $group_row['group_avatar_type'], $group_row['group_avatar_width'], $group_row['group_avatar_height'], 'GROUP_AVATAR');
+ $avatar_img = phpbb_get_group_avatar($group_row);
// ... same for group rank
$rank_title = $rank_img = $rank_img_src = '';
@@ -1728,7 +1750,7 @@ function show_profile($data, $user_notes_enabled = false, $warn_user_enabled = f
'A_USERNAME' => addslashes(get_username_string('username', $user_id, $username, $data['user_colour'])),
- 'AVATAR_IMG' => get_user_avatar($data['user_avatar'], $data['user_avatar_type'], $data['user_avatar_width'], $data['user_avatar_height']),
+ 'AVATAR_IMG' => phpbb_get_user_avatar($data),
'ONLINE_IMG' => (!$config['load_onlinetrack']) ? '' : (($online) ? $user->img('icon_user_online', 'ONLINE') : $user->img('icon_user_offline', 'OFFLINE')),
'S_ONLINE' => ($config['load_onlinetrack'] && $online) ? true : false,
'RANK_IMG' => $rank_img,
diff --git a/phpBB/report.php b/phpBB/report.php
index be38bad2f3..ce9fae13ef 100644
--- a/phpBB/report.php
+++ b/phpBB/report.php
@@ -180,6 +180,8 @@ if ($submit && $reason_id)
$db->sql_query($sql);
$report_id = $db->sql_nextid();
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
if ($post_id)
{
$sql = 'UPDATE ' . POSTS_TABLE . '
@@ -198,6 +200,10 @@ if ($submit && $reason_id)
$lang_return = $user->lang['RETURN_TOPIC'];
$lang_success = $user->lang['POST_REPORTED_SUCCESS'];
+
+ $phpbb_notifications->add_notifications('report_post', array_merge($report_data, $row, $forum_data, array(
+ 'report_text' => $report_text,
+ )));
}
else
{
@@ -224,6 +230,12 @@ if ($submit && $reason_id)
$lang_return = $user->lang['RETURN_PM'];
$lang_success = $user->lang['PM_REPORTED_SUCCESS'];
+
+ $phpbb_notifications->add_notifications('report_pm', array_merge($report_data, $row, array(
+ 'report_text' => $report_text,
+ 'from_user_id' => $report_data['author_id'],
+ 'report_id' => $report_id,
+ )));
}
meta_refresh(3, $redirect_url);
diff --git a/phpBB/styles/prosilver/template/avatars.js b/phpBB/styles/prosilver/template/avatars.js
new file mode 100644
index 0000000000..26ea24c0db
--- /dev/null
+++ b/phpBB/styles/prosilver/template/avatars.js
@@ -0,0 +1,15 @@
+(function($) { // Avoid conflicts with other libraries
+
+"use strict";
+
+function avatarHide() {
+ $('#avatar_options > div').hide();
+
+ var selected = $('#avatar_driver').val();
+ $('#avatar_option_' + selected).show();
+}
+
+avatarHide();
+$('#avatar_driver').bind('change', avatarHide);
+
+})(jQuery); // Avoid conflicts with other libraries
diff --git a/phpBB/styles/prosilver/template/confirm_body.html b/phpBB/styles/prosilver/template/confirm_body.html
index cddbdee391..eb0cad2597 100644
--- a/phpBB/styles/prosilver/template/confirm_body.html
+++ b/phpBB/styles/prosilver/template/confirm_body.html
@@ -1,3 +1,15 @@
+
+
+