diff --git a/acp/contactadmin_info.php b/acp/contactadmin_info.php index ea39166..f866065 100644 --- a/acp/contactadmin_info.php +++ b/acp/contactadmin_info.php @@ -12,7 +12,7 @@ class contactadmin_info { - function module() + public function module() { return [ 'filename' => '\phpbbmodders\contactadmin\acp\contactadmin_module', diff --git a/acp/contactadmin_module.php b/acp/contactadmin_module.php index b6e4180..1eed0cb 100644 --- a/acp/contactadmin_module.php +++ b/acp/contactadmin_module.php @@ -13,9 +13,16 @@ class contactadmin_module { - public $u_action; + /** @var string Form action URL, set by phpBB's module system */ + public $u_action; - function main($id, $mode) + /** @var string Template file name */ + public $tpl_name; + + /** @var string Page title */ + public $page_title; + + public function main($id, $mode) { global $phpbb_container; diff --git a/adm/style/acp_contactadmin.html b/adm/style/acp_contactadmin.html index 15947e2..dc9d99a 100644 --- a/adm/style/acp_contactadmin.html +++ b/adm/style/acp_contactadmin.html @@ -1,11 +1,5 @@ -{% INCLUDE 'overall_header.html' %} - +{% INCLUDECSS '@phpbbmodders_contactadmin/contactadmin_acp.css' %} +{% include 'overall_header.html' %}

{{ lang('ACP_CAT_CONTACTADMIN') }}

{% if CONTACT_ERROR %}

{{ lang('WARNING') }}

@@ -13,7 +7,7 @@

{{ lang('ACP_CAT_CONTACTADMIN') }}

{% endif %} -
+
{{ lang('CONTACT_US_INFO') }}

{{ lang('CONTACT_US_INFO_EXPLAIN') }}

@@ -25,14 +19,14 @@

{{ lang('ACP_CAT_CONTACTADMIN') }}

{% endif %} {% INCLUDE 'acp_posting_buttons.html' %}
-
+
-
- +
+
-
+
{% if S_BBCODE_ALLOWED %} {% endif %} @@ -43,10 +37,10 @@

{{ lang('ACP_CAT_CONTACTADMIN') }}

{% endif %}
-
{{ lang('OPTIONS') }}{{ lang('COLON') }} {{ BBCODE_STATUS }} :: {{ IMG_STATUS }} :: {{ FLASH_STATUS }} :: {{ URL_STATUS }} :: {{ SMILIES_STATUS }}
+
{{ lang('OPTIONS') }}{{ lang('COLON') }} {{ BBCODE_STATUS }} :: {{ IMG_STATUS }} :: {{ FLASH_STATUS }} :: {{ URL_STATUS }} :: {{ SMILIES_STATUS }}
- +
@@ -124,13 +118,18 @@

{{ lang('ACP_CAT_CONTACTADMIN') }}


{{ lang('CONTACT_BOT_FORUM_EXPLAIN') }}
-
{{ CONTACT_BOT_FORUM }}
+
- + {{ S_FORM_TOKEN }}
-{% INCLUDE 'overall_footer.html' %} +{% INCLUDEJS '@phpbbmodders_contactadmin/contactadmin_acp.js' %} +{% include 'overall_footer.html' %} diff --git a/adm/style/contactadmin_acp.css b/adm/style/contactadmin_acp.css new file mode 100644 index 0000000..ae811ff --- /dev/null +++ b/adm/style/contactadmin_acp.css @@ -0,0 +1,29 @@ +/* Contact Admin ACP settings */ +.contactadmin-palette { + width: 90px; +} + +.contactadmin-editor-row { + margin-left: 90px; +} + +.rtl .contactadmin-editor-row { + margin-left: 0; + margin-right: 90px; +} + +.contactadmin-editor-row textarea { + width: 95%; +} + +.contactadmin-editor-options { + margin-top: 5px; +} + +.contactadmin-editor-status { + margin-top: 10px; +} + +.contactadmin-warning { + color: #e8590c; +} diff --git a/adm/style/contactadmin_acp.js b/adm/style/contactadmin_acp.js new file mode 100644 index 0000000..6163bc2 --- /dev/null +++ b/adm/style/contactadmin_acp.js @@ -0,0 +1,63 @@ +// Globals read by phpBB's BBCode editor (editor.js) +var form_name = 'contactadmin'; +var text_name = 'contact_admin_info'; +var load_draft = false; +var upload = false; +var imageTag = false; + +(function($) { // Avoid conflicts with other libraries + + 'use strict'; + + var $form = $('#contactadmin'); + var settings = $form.data(); + + // Show who the chosen contact bot is, or why that user can't be used + $('#contact_bot_user').change(function() { + var userId = $(this).val(); + + $.ajax({ + url: settings.botInfoUrl.replace(/_bot_info\/[0-9]*/g, '_bot_info/' + userId), + dataType: 'json', + success: function(json) { + var $link = $('#bot_user_link'); + + if (json.error === 'CONTACT_NO_BOT_USER') { + $link.html($('').text(settings.langNoBotUser)).show(); + } else if (json.error === 'CONTACT_BOT_IS_GUEST' || json.error === 'CONTACT_BOT_IS_BOT') { + var warning = (json.error === 'CONTACT_BOT_IS_GUEST') ? settings.langBotIsGuest : settings.langBotIsBot; + $link.html(json.user_link).append('
', $('').text(warning)).show(); + } else { + $link.html(json.user_link).show(); + } + } + }); + }); + + // Hide the options that don't apply to the selected contact method + $("input[name='contact_method']").each(function() { + if ($(this).is(':checked') && this.value == settings.methodEmail) { + $('.contact-options').hide(); + } + if ($(this).is(':checked') && this.value == settings.methodPost) { + $('.contact-who').hide(); + } + }); + + // Show or hide the options when the contact method changes + $("input[name='contact_method']").change(function() { + if (this.value == settings.methodEmail || this.value == settings.methodPm) { + $('.contact-who').show('slow'); + if (this.value == settings.methodEmail) { + $('.contact-options').hide('slow'); + } + } + if (this.value == settings.methodPost || this.value == settings.methodPm) { + $('.contact-options').show('slow'); + if (this.value == settings.methodPost) { + $('.contact-who').hide('slow'); + } + } + }); + +})(jQuery); diff --git a/adm/style/event/acp_overall_footer_after.html b/adm/style/event/acp_overall_footer_after.html deleted file mode 100644 index 77c0441..0000000 --- a/adm/style/event/acp_overall_footer_after.html +++ /dev/null @@ -1,74 +0,0 @@ -{% if AJAX_BOT_USER_INFO %} - -{% endif %} \ No newline at end of file diff --git a/composer.json b/composer.json index a86c5d6..31097aa 100644 --- a/composer.json +++ b/composer.json @@ -1,47 +1,47 @@ { - "name": "phpbbmodders/contactadmin", - "type": "phpbb-extension", - "description": "A contact form that lets guests and members reach the board administrators by email, private message or forum post.", - "homepage": "https://www.phpbbmodders.com/", - "version": "1.5.0", - "time": "2026-10-06", - "keywords": [ - "phpbb", - "extension", - "contact admin", - "contact-form" - ], - "license": "GPL-2.0-only", - "authors": [ - { - "name": "phpBB Modders", - "email": "board@phpbbmodders.com", - "homepage": "https://www.phpbbmodders.com/", - "role": "Extension Developer" - }, - { - "name": "Rich McGirr", - "role": "Past Developer" - } - ], - "require": { - "php": ">=7.4", - "phpbb/phpbb": ">=3.3.19", - "composer/installers": "^1.0 || ^2.0" - }, - "require-dev": { - "phpbb/epv": "dev-master" - }, - "extra": { - "display-name": "Contact Admin", - "soft-require": { - "phpbb/phpbb": ">=3.3.19,<4.0.0@dev" - }, - "version-check": { - "host": "www.phpbb.com", - "directory": "/customise/db/extension/contact_admin", - "filename": "version_check", - "ssl": true - } - } + "name": "phpbbmodders/contactadmin", + "type": "phpbb-extension", + "description": "A contact form that lets guests and members reach the board administrators by email, private message or forum post.", + "homepage": "https://www.phpbbmodders.com/", + "version": "1.5.0", + "time": "2026-10-06", + "keywords": [ + "phpbb", + "extension", + "contact admin", + "contact-form" + ], + "license": "GPL-2.0-only", + "authors": [ + { + "name": "phpBB Modders", + "email": "board@phpbbmodders.com", + "homepage": "https://www.phpbbmodders.com/", + "role": "Extension Developer" + }, + { + "name": "Rich McGirr", + "role": "Past Developer" + } + ], + "require": { + "php": ">=7.4", + "phpbb/phpbb": ">=3.3.19,<4.0.0@dev", + "composer/installers": "^1.0 || ^2.0" + }, + "require-dev": { + "phpbb/epv": "dev-master" + }, + "extra": { + "display-name": "Contact Admin", + "soft-require": { + "phpbb/phpbb": ">=3.3.19,<4.0.0@dev" + }, + "version-check": { + "host": "www.phpbb.com", + "directory": "/customise/db/extension/contact_admin", + "filename": "version_check", + "ssl": true + } + } } diff --git a/config/routing.yml b/config/routing.yml index 099876f..a16b881 100644 --- a/config/routing.yml +++ b/config/routing.yml @@ -4,6 +4,6 @@ phpbbmodders_contactadmin_displayform: phpbbmodders_contactadmin_botuserinfo: path: /contact_bot_info/{user_id} - defaults: { _controller: phpbbmodders.contactadmin.core:bot_user_info } + defaults: { _controller: phpbbmodders.contactadmin.core:bot_user_info_json } requirements: user_id: \d+ \ No newline at end of file diff --git a/controller/admin_controller.php b/controller/admin_controller.php index c5136b9..5264cca 100644 --- a/controller/admin_controller.php +++ b/controller/admin_controller.php @@ -23,6 +23,9 @@ use phpbb\user; use phpbbmodders\contactadmin\core\contactadmin as contactadmin; +/** +* ACP settings page for the contact form +*/ class admin_controller { /** @var auth */ @@ -55,7 +58,7 @@ class admin_controller /** @var user */ protected $user; - /* @var contactadmin */ + /** @var contactadmin */ protected $contactadmin; /** @var string root_path */ @@ -121,6 +124,12 @@ public function __construct( $this->contact_constants = $contact_constants; } + /** + * Display and save the settings page + * + * @return void + * @access public + */ public function display_options() { $this->language->add_lang(['acp/board', 'posting']); @@ -190,11 +199,11 @@ public function display_options() if (in_array($this->request->variable('contact_method', 0), [$contact_method_email, $contact_method_pm])) { - $admins_exist = $this->check_for_admins($this->request->variable('contact_method', 0)); + $admins_exist = $this->check_for_admins(); if (!$admins_exist) { - $error[] = $this->language->lang('ADMINS_NOT_EXIST_FOR_METHOD', $this->request->variable('contact_method', 0)); + $error[] = $this->language->lang(($this->request->variable('contact_method', 0) == $contact_method_email) ? 'ADMINS_NOT_EXIST_EMAIL' : 'ADMINS_NOT_EXIST_PM'); } } @@ -237,39 +246,29 @@ public function display_options() $contact_admin_info_preview = ''; if ($this->request->is_set_post('preview')) { - generate_text_for_storage( - $contact_admin_info_preview, - $contact_admin_info_uid, - $contact_admin_info_bitfield, - $contact_admin_info_flags, - !$this->request->variable('disable_bbcode', false), - !$this->request->variable('disable_magic_url', false), - !$this->request->variable('disable_smilies', false) - ); + // The text was prepared for storage above, together with its uid, bitfield and flags $contact_admin_info_preview = generate_text_for_display($contact_admin_info, $contact_admin_info_uid, $contact_admin_info_bitfield, $contact_admin_info_flags); } $contact_admin_edit = generate_text_for_edit($contact_admin_info, $contact_admin_info_uid, $contact_admin_info_flags); $this->template->assign_vars([ - 'CONTACT_ERROR' => (sizeof($error)) ? implode('
', $error) : false, + 'CONTACT_ERROR' => (count($error)) ? implode('
', $error) : false, 'CONTACT_CONFIRM' => $this->config['contactadmin_confirm'], 'CONTACT_CONFIRM_GUESTS' => $this->config['contactadmin_confirm_guests'], 'CONTACT_ATTACHMENTS' => $this->config['allow_attachments'] ? $this->config['contactadmin_attach_allowed'] : $this->config['allow_attachments'], 'CONTACT_MAX_ATTEMPTS' => $this->config['contactadmin_max_attempts'], - 'CONTACT_FOUNDER' => $this->config['contactadmin_founder_only'], 'CONTACT_USERNAME_CHK' => $this->config['contactadmin_username_chk'], 'CONTACT_EMAIL_CHK' => $this->config['contactadmin_email_chk'], 'CONTACT_GDPR' => $this->config['contactadmin_gdpr'], 'CONTACT_REASONS' => $contact_admin_reasons, 'CONTACT_METHOD' => $this->contactadmin->method_select($this->request->variable('contact_method', $this->config['contactadmin_method'])), 'CONTACT_WHO' => $this->contactadmin->who_select($this->config['contactadmin_who']), - 'CONTACT_METHOD_EMAIL' => json_encode($contact_method_email), - 'CONTACT_METHOD_PM' => json_encode($contact_method_pm), - 'CONTACT_METHOD_POST' => json_encode($contact_method_post), + 'CONTACT_METHOD_EMAIL' => (int) $contact_method_email, + 'CONTACT_METHOD_PM' => (int) $contact_method_pm, + 'CONTACT_METHOD_POST' => (int) $contact_method_post, 'CONTACT_BOT_POSTER' => $this->contactadmin->poster_select($this->config['contactadmin_bot_poster']), - 'CONTACT_BOT_FORUM' => $this->contactadmin->forum_select($this->config['contactadmin_forum']), 'CONTACT_BOT_MAX_ID' => $bot_max_id, 'CONTACT_BOT_USER' => $this->request->variable('contact_bot_user', $this->config['contactadmin_bot_user']), @@ -301,6 +300,16 @@ public function display_options() 'U_ACTION' => $this->u_action, ]); + foreach ($this->contactadmin->forum_options($this->config['contactadmin_forum']) as $forum_id => $forum) + { + $this->template->assign_block_vars('contact_forums', [ + 'FORUM_ID' => $forum_id, + 'FORUM_NAME' => $forum['padding'] . $forum['forum_name'], + 'S_SELECTED' => !empty($forum['selected']), + 'S_DISABLED' => !empty($forum['disabled']), + ]); + } + if (!function_exists('display_custom_bbcodes')) { include($this->root_path . 'includes/functions_display.' . $this->php_ext); @@ -309,22 +318,46 @@ public function display_options() display_custom_bbcodes(); } + /** + * Save the submitted settings + * + * Choices that must be one of a fixed set fall back to their first option + * if anything else is submitted. + * + * @return void + * @access protected + */ protected function set_options() { + $c = $this->contact_constants; + $this->config->set('contactadmin_confirm', $this->request->variable('confirm', 0)); $this->config->set('contactadmin_confirm_guests', $this->request->variable('confirm_guests', 0)); $this->config->set('contactadmin_username_chk', $this->request->variable('username_chk', 0)); $this->config->set('contactadmin_email_chk', $this->request->variable('email_chk', 0)); - $this->config->set('contactadmin_max_attempts', $this->request->variable('max_attempts', 0)); + $this->config->set('contactadmin_max_attempts', max(0, $this->request->variable('max_attempts', 0))); $this->config->set('contactadmin_attach_allowed', $this->request->variable('attach_allowed', 0)); - $this->config->set('contactadmin_who', $this->request->variable('contact_who', 0)); - $this->config->set('contactadmin_method', $this->request->variable('contact_method', 0)); + $this->config->set('contactadmin_who', $this->allowed_value($this->request->variable('contact_who', 0), [$c['CONTACT_WHO_ALL_ADMINS'], $c['CONTACT_WHO_BOARD_DEFAULT'], $c['CONTACT_WHO_BOARD_FOUNDER']])); + $this->config->set('contactadmin_method', $this->allowed_value($this->request->variable('contact_method', 0), [$c['CONTACT_METHOD_EMAIL'], $c['CONTACT_METHOD_POST'], $c['CONTACT_METHOD_PM']])); $this->config->set('contactadmin_bot_user', $this->request->variable('contact_bot_user', 0)); - $this->config->set('contactadmin_bot_poster', $this->request->variable('contact_bot_poster', 0)); + $this->config->set('contactadmin_bot_poster', $this->allowed_value($this->request->variable('contact_bot_poster', 0), [$c['CONTACT_POST_NEITHER'], $c['CONTACT_POST_GUEST'], $c['CONTACT_POST_ALL']])); $this->config->set('contactadmin_forum', $this->request->variable('forum', 0)); $this->config->set('contactadmin_gdpr', $this->request->variable('gdpr', 0)); } + /** + * Return a submitted value if it is one of the allowed values, otherwise the first allowed value + * + * @param int $value submitted value + * @param array $allowed allowed values + * @return int + * @access protected + */ + protected function allowed_value($value, array $allowed) + { + return in_array($value, $allowed) ? $value : reset($allowed); + } + /** * bot_max_id Used to limit the number allowed for the bot user * @@ -333,8 +366,6 @@ protected function set_options() */ protected function bot_max_id() { - $bot_max_id = ''; - $sql = 'SELECT MAX(user_id) as max_id FROM ' . USERS_TABLE; $result = $this->db->sql_query($sql); @@ -344,33 +375,18 @@ protected function bot_max_id() return (int) $bot_max_id; } - /*ensure we have admins that accept emails or pms to be sent via the board + /** + * check_for_admins ensure the board has at least one administrator to send emails or PMs to * - * @param int $method * @return bool * @access protected */ - protected function check_for_admins($method) + protected function check_for_admins() { // Grab an array of user_id's with admin permissions $admin_ary = $this->auth->acl_get_list(false, 'a_', false); - $admin_ary = (!empty($admin_ary[0]['a_'])) ? $admin_ary[0]['a_'] : []; - - $admins = []; - - $sql = 'SELECT user_id, username, user_email, user_lang, user_jabber, user_notify_type - FROM ' . USERS_TABLE . ' - WHERE ' . $this->db->sql_in_set('user_id', $admin_ary); - $result = $this->db->sql_query($sql); - $admins = $this->db->sql_fetchrowset($result); - $this->db->sql_freeresult($result); - - if (!count($admins)) - { - return false; - } - return true; + return !empty($admin_ary[0]['a_']); } /** diff --git a/controller/main_controller.php b/controller/main_controller.php index 097039f..911cccf 100644 --- a/controller/main_controller.php +++ b/controller/main_controller.php @@ -46,7 +46,7 @@ class main_controller protected $db; /** @var dispatcher_interface */ - protected $dispatcher_interface; + protected $dispatcher; /** @var language */ protected $language; @@ -54,7 +54,7 @@ class main_controller /** @var log */ protected $log; - /* @var request */ + /** @var request */ protected $request; /** @var template */ @@ -63,7 +63,7 @@ class main_controller /** @var user */ protected $user; - /* @var contactadmin */ + /** @var contactadmin */ protected $contactadmin; /** @var captcha_factory */ @@ -261,7 +261,7 @@ public function displayform() } // always check email addresses for validity but only if setting in ACP isn't set and only for non-registered users - if (!$this->config['contactadmin_email_check'] && empty($this->user->data['is_registered'])) + if (!$this->config['contactadmin_email_chk'] && empty($this->user->data['is_registered'])) { $validate_email = phpbb_validate_email($data['email']); if ($validate_email) @@ -306,7 +306,7 @@ public function displayform() // Check for Privacy policy check if (empty($this->user->data['is_registered']) && $this->config['contactadmin_gdpr'] && !$this->request->is_set('gdpr')) { - $error[] = $this->user->lang('CONTACT_PRIVACYPOLICY_ERROR'); + $error[] = $this->language->lang('CONTACT_PRIVACYPOLICY_ERROR'); } // CAPTCHA check @@ -335,13 +335,16 @@ public function displayform() $user_name = $data['username']; } + // Name shown on a forum post; $data['username'] keeps the sender's name for listeners + $poster_name = $data['username']; + if (!in_array($this->config['contactadmin_method'], [$this->contact_constants['CONTACT_METHOD_EMAIL']])) { // change the users stuff if ($this->config['contactadmin_bot_poster'] == $this->contact_constants['CONTACT_POST_ALL'] || ($this->config['contactadmin_bot_poster'] == $this->contact_constants['CONTACT_POST_GUEST'] && empty($this->user->data['is_registered']))) { $contact_perms = $this->contactadmin->contact_change_auth($this->config['contactadmin_bot_user']); - $data['username'] = $this->user->data['username']; + $poster_name = $this->user->data['username']; } if (!function_exists('create_thumbnail')) { @@ -400,7 +403,7 @@ public function displayform() extract($this->dispatcher->trigger_event('phpbbmodders.contactadmin.modify_data_and_error', compact($vars))); // no errors, let's proceed - if (!sizeof($error)) + if (!count($error)) { if ($this->config['contactadmin_method'] != $this->contact_constants['CONTACT_METHOD_POST']) { @@ -436,13 +439,9 @@ public function displayform() 'filename_data' => $message_parser->filename_data, ]; - // Loop through our list of users - $size = count($contact_users); - for ($i = 0; $i < $size; $i++) - { - $pm_data['address_list'] = ['u' => [$contact_users[$i]['user_id'] => 'to']]; - submit_pm('post', $subject, $pm_data, false); - } + // One PM to all admins, as blind copies so each sees only their own copy + $pm_data['address_list'] = ['u' => array_fill_keys(array_map('intval', array_column($contact_users, 'user_id')), 'bcc')]; + submit_pm('post', $subject, $pm_data, false); break; @@ -487,7 +486,7 @@ public function displayform() $poll = []; // Submit the post! - submit_post('post', $subject, $data['username'], POST_NORMAL, $poll, $post_data); + submit_post('post', $subject, $poster_name, POST_NORMAL, $poll, $post_data); break; @@ -660,7 +659,7 @@ public function displayform() 'USERNAME' => isset($data['username']) ? $data['username'] : '', 'EMAIL' => isset($data['email']) ? $data['email'] : '', 'EMAIL_CONFIRM' => isset($data['email_confirm']) ? $data['email_confirm'] : '', - 'CONTACT_REASONS' => $this->contactadmin->contact_make_select($contact_reasons, $data['contact_reason']), + 'S_CONTACT_REASONS' => !empty($contact_reasons), 'CONTACT_SUBJECT' => isset($data['contact_subject']) ? $data['contact_subject'] : '', 'CONTACT_MESSAGE' => isset($data['contact_message']) ? $data['contact_message'] : '', 'CONTACT_INFO' => $l_admin_info, @@ -679,6 +678,11 @@ public function displayform() 'S_CONTACT_GDPR' => ($this->config['contactadmin_gdpr'] && empty($this->user->data['is_registered'])) ? true : false, ]); + foreach ($this->contactadmin->contact_reason_options($contact_reasons, $data['contact_reason']) as $option) + { + $this->template->assign_block_vars('contact_reasons', $option); + } + // Send all data to the template file return $this->helper->render('contactadmin_body.html', $this->language->lang('ACP_CAT_CONTACTADMIN')); } diff --git a/core/contactadmin.php b/core/contactadmin.php index 56372cf..da57dfd 100644 --- a/core/contactadmin.php +++ b/core/contactadmin.php @@ -21,6 +21,9 @@ use phpbb\exception\http_exception; use Symfony\Component\HttpFoundation\JsonResponse; +/** +* Shared helpers for the contact form and its ACP settings +*/ class contactadmin { /** @var auth */ @@ -181,7 +184,7 @@ public function contact_check($mode, $forum_id = false, $bot_id = false, $method // send an email to the board default $email_template = '@phpbbmodders_contactadmin/contact_error'; - $email_message = $this->language->lang('CONTACT_BOT_MESSAGE', $this->user->data['username'], $this->config['sitename'], $this->language->lang('FORUM'), $server_url); + $email_message = $this->language->lang('CONTACT_BOT_MESSAGE', $this->user->data['username'], $this->config['sitename'], $this->language->lang('CONTACT_FORUM'), $server_url); $this->contact_send_email($email_template, $email_message); // add an entry into the error log @@ -269,7 +272,7 @@ public function contact_check($mode, $forum_id = false, $bot_id = false, $method $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONTACT_NONE', time(), [$error]); // show a message to the user - $message = $this->language->lang('CONTACT_ERROR', '

' . $this->language->lang('RETURN_INDEX', 'root_path}index.$this->php_ext") . '">', '')); + $message = $this->language->lang('CONTACT_ERROR') . '

' . $this->language->lang('RETURN_INDEX', 'root_path}index.$this->php_ext") . '">', ''); throw new http_exception(503, $message); } @@ -314,8 +317,8 @@ private function contact_send_email($email_template, $email_message) $messenger->headers('X-AntiAbuse: User IP - ' . $this->user->ip); $messenger->template($email_template, $lang); + // No from() call: the messenger sends from the board email address by default $messenger->to($this->config['board_email']); - $messenger->from($this->config['server_name']); $messenger->assign_vars([ 'SUBJECT' => $this->language->lang('CONTACT_BOT_SUBJECT'), @@ -329,38 +332,41 @@ private function contact_send_email($email_template, $email_message) } /** - * contact_make_select + * contact_reason_options * * @param array $input_ary an array of contact reasons * @param string $selected the chosen reason - * @return string Select html - * for drop down reasons in the contact page + * @return array Options for the reasons drop down, empty if there are no reasons */ - public function contact_make_select($input_ary, $selected) + public function contact_reason_options($input_ary, $selected) { // only accept arrays, no empty ones if (!is_array($input_ary) || !count($input_ary)) { - return false; + return []; } // add a default entry asking for user to choose a reason - $default_reason[] = $this->language->lang('REASON_EXPLAIN'); - - $input_ary = array_merge($default_reason, $input_ary); + $input_ary = array_merge([$this->language->lang('REASON_EXPLAIN')], $input_ary); - $select = ''; + $options = []; foreach ($input_ary as $item) { - $item_selected = ($item == $selected) ? ' selected="selected"' : ''; - $select .= ''; + $options[] = [ + 'VALUE' => $item, + 'S_SELECTED' => ($item == $selected), + ]; } - return $select; + return $options; } /** * Create the selection for who gets the message + * + * @param int $value the selected option + * @param string $key config key passed on to h_radio() + * @return string Radio buttons html, built by phpBB's h_radio() */ public function who_select($value, $key = '') { @@ -375,6 +381,10 @@ public function who_select($value, $key = '') /** * Create the selection for the contact method + * + * @param int $value the selected option + * @param string $key config key passed on to h_radio() + * @return string Radio buttons html, built by phpBB's h_radio() */ public function method_select($value, $key = '') { @@ -399,6 +409,10 @@ public function method_select($value, $key = '') /** * Create the selection for the post method + * + * @param int $value the selected option + * @param string $key config key passed on to h_radio() + * @return string Radio buttons html, built by phpBB's h_radio() */ public function poster_select($value, $key = '') { @@ -412,11 +426,14 @@ public function poster_select($value, $key = '') } /** - * Create the selection for the bot forum + * Get the forums for the bot forum drop down + * + * @param int $value the selected forum id + * @return array Forum data keyed by forum id, from make_forum_select() */ - public function forum_select($value) + public function forum_options($value) { - return ''; + return make_forum_select((int) $value, false, true, true, true, false, true); } /** @@ -480,66 +497,81 @@ public function admin_array() } /** - * bot_user_info used in the ACP when choosing the "bot" + * bot_user_info look up the user chosen as the contact "bot" * - * @param user_id user id - * @return array array of user info or error if not found + * @param int $user_id user id + * @return array user_id, username and user_type, or an 'error' message if not found * @access public */ public function bot_user_info($user_id) { - $bot_user_info = []; - $sql = 'SELECT user_id, username, user_type - FROM ' . USERS_TABLE . " - WHERE user_id = " . (int) $user_id; + FROM ' . USERS_TABLE . ' + WHERE user_id = ' . (int) $user_id; $result = $this->db->sql_query($sql); $bot_user_info = $this->db->sql_fetchrow($result); $this->db->sql_freeresult($result); - if (!isset($bot_user_info['username'])) + if (!$bot_user_info) { - $bot_user_info['error'] = $this->language->lang('CONTACT_NO_BOT_USER'); + $bot_user_info = ['error' => $this->language->lang('CONTACT_NO_BOT_USER')]; } - if ($this->request->is_ajax()) + return $bot_user_info; + } + + /** + * bot_user_info_json AJAX lookup used by the ACP settings when choosing the "bot" + * + * Only board administrators may use it: it reveals usernames and account types. + * + * @param int $user_id user id + * @return JsonResponse the user's profile link, plus an error key if the user is unsuitable + * @throws http_exception 403 for anyone without the a_board permission + * @access public + */ + public function bot_user_info_json($user_id) + { + if (!$this->auth->acl_get('a_board')) { - if (!isset($bot_user_info['username'])) - { - $json = new JsonResponse([ - 'error' => 'CONTACT_NO_BOT_USER', - 'user_link' => '', - ]); - } - else if ($bot_user_info['user_id'] == ANONYMOUS) - { - $json = new JsonResponse([ - 'error' => 'CONTACT_BOT_IS_GUEST', - 'user_link' => $bot_user_info['username'], - ]); - } - else if ($bot_user_info['user_type'] == USER_IGNORE) - { - $json = new JsonResponse([ - 'error' => 'CONTACT_BOT_IS_BOT', - 'user_link' => $bot_user_info['username'], - ]); - } - else - { - $json = new JsonResponse([ - 'error' => false, - 'user_link' => 'root_path}memberlist.$this->php_ext", 'mode=viewprofile&u=' . $bot_user_info['user_id']) . '" target="_blank">' . $bot_user_info['username'] . '', - ]); - } - return $json; + throw new http_exception(403, 'NOT_AUTHORISED'); } - return $bot_user_info; + $bot_user_info = $this->bot_user_info($user_id); + + if (isset($bot_user_info['error'])) + { + return new JsonResponse([ + 'error' => 'CONTACT_NO_BOT_USER', + 'user_link' => '', + ]); + } + else if ($bot_user_info['user_id'] == ANONYMOUS) + { + return new JsonResponse([ + 'error' => 'CONTACT_BOT_IS_GUEST', + 'user_link' => $bot_user_info['username'], + ]); + } + else if ($bot_user_info['user_type'] == USER_IGNORE) + { + return new JsonResponse([ + 'error' => 'CONTACT_BOT_IS_BOT', + 'user_link' => $bot_user_info['username'], + ]); + } + + return new JsonResponse([ + 'error' => false, + 'user_link' => 'root_path}memberlist.$this->php_ext", 'mode=viewprofile&u=' . $bot_user_info['user_id']) . '" target="_blank">' . $bot_user_info['username'] . '', + ]); } - /* - * Get an array that represents directory tree + /** + * Get the names of the sub-directories of a directory + * + * @param string $directory path of the directory + * @return array directory names */ public function dir_to_array($directory) { diff --git a/event/listener.php b/event/listener.php index cbf0214..3cf60cf 100644 --- a/event/listener.php +++ b/event/listener.php @@ -35,7 +35,7 @@ class listener implements EventSubscriberInterface /** @var language */ protected $language; - /* @var template */ + /** @var template */ protected $template; /** @var user */ @@ -151,12 +151,9 @@ public function page_header_after($event) { if (empty($this->user->data['is_bot'])) { - $version = phpbb_version_compare($this->config['version'], '3.3', '>='); - $this->template->assign_vars([ 'U_CONTACT_US' => false, 'U_CONTACTADMIN' => $this->helper->route('phpbbmodders_contactadmin_displayform'), - 'S_FORUM_VERSION' => $version, ]); } } diff --git a/language/en/acp/info_acp_contact.php b/language/en/acp/info_acp_contact.php index e59f41e..5e1f826 100644 --- a/language/en/acp/info_acp_contact.php +++ b/language/en/acp/info_acp_contact.php @@ -41,7 +41,6 @@ 'FORUM_EMAIL_INACTIVE' => 'How do you want users to be able to make contact.
No email allowed per forum settings', 'NO_FORUM_ATTACHMENTS' => 'If set attachments will be allowed in posting to the forum and private messages. The extensions allowed are the same as the board configuration.
No attachments allowed per forum settings!', // Log entries - 'LOG_CONFIG_CONTACT_ADMIN' => 'Altered Contact Admin extension page settings', 'LOG_CONTACT_BOT_INVALID' => 'The Contact Admin extension bot has an invalid user id selected:
User ID %1$s', 'LOG_CONTACT_FORUM_INVALID' => 'The Contact Admin extension forum has an invalid forum selected:
Forum ID %1$s', 'LOG_CONTACT_EMAIL_INVALID' => 'The Contact Admin extension is allowing emails but the forum is not setup to allow emails. The extension has been disabled.', diff --git a/language/en/acp_contact.php b/language/en/acp_contact.php index 060f30a..3abea03 100644 --- a/language/en/acp_contact.php +++ b/language/en/acp_contact.php @@ -38,10 +38,8 @@ // $lang = array_merge($lang, [ - 'ADMINS_NOT_EXIST_FOR_METHOD' => [ - 0 => 'There are no Administrators who allow emails. You must choose a different method of contact.', - 2 => 'There are no Administrators who allow private messages. You must choose a different method of contact.', - ], + 'ADMINS_NOT_EXIST_EMAIL' => 'There are no Administrators who allow emails. You must choose a different method of contact.', + 'ADMINS_NOT_EXIST_PM' => 'There are no Administrators who allow private messages. You must choose a different method of contact.', 'CONTACT_CONFIG_SAVED' => 'Contact Admin configuration has been updated', 'CONTACT_ACP_CONFIRM' => 'Enable visual confirmation', 'CONTACT_ACP_CONFIRM_EXPLAIN' => 'If you enable this option, users will have to enter a visual confirmation to send the message.
This is to prevent spam messages. Note that this option is for the contact page only. It does not affect other visual confirmation settings', diff --git a/language/en/contact.php b/language/en/contact.php index 663ecd8..6947496 100644 --- a/language/en/contact.php +++ b/language/en/contact.php @@ -39,7 +39,7 @@ $lang = array_merge($lang, [ 'ACP_CAT_CONTACTADMIN' => 'Contact Admin', - 'ADD_ATTACHMENT_EXPLAIN' => 'If you wish to attach a file enter the details below.', + 'CONTACT_ADD_ATTACHMENT_EXPLAIN' => 'If you wish to attach a file enter the details below.', 'CONTACT_ERROR' => 'You can’t use the contact form at the moment because there is an error in the configuration. An email has been sent to the founder.', 'CONTACT_NONE' => 'The user %1$s tried to use the Contact Admin extension at %2$s to send a %3$s, but there are no Administrators that allow %3$ss by users. Please enter the Contact Admin Configuration in the Admin Extension Panel for the board %4$s and choose a different method for contact', 'CONTACT_BOT_SUBJECT' => 'Contact Admin Extension Error', @@ -52,7 +52,6 @@ 'CONTACT_NO_SUBJ' => 'You didn’t enter a subject', 'CONTACT_REASON' => 'Reason', 'CONTACT_TEMPLATE' => '[b]Name:[/b] %1$s' . "\n" . '[b]Email Address:[/b] %2$s' . "\n" . '[b]IP:[/b] %3$s' . "\n" . '[b]Subject:[/b] %4$s' . "\n" . '[b]Has entered the following message into the contact form:[/b] %5$s', - 'CONTACT_TITLE' => 'Contact Administration', 'CONTACT_YOUR_NAME' => 'Your name', 'CONTACT_YOUR_NAME_EXPLAIN' => 'Please enter your name, so the message has an identity.', @@ -63,14 +62,13 @@ 'TOO_MANY_CONTACT_TRIES' => 'You have exceeded the maximum number of attempts for this session. Please try again later.', 'CONTACT_NO_NAME' => 'You didn’t enter a name', - 'FORUM' => 'forum', + 'CONTACT_FORUM' => 'forum', 'USER' => 'user', 'CONTACT_REGISTERED' => 'Registered User', 'CONTACT_GUEST' => 'Guest User', 'REASON_EXPLAIN' => 'Please choose a reason', 'REASON_ERROR' => 'Please choose an appropriate reason', - 'RETURN_CONTACT' => '%sReturn to the contact page%s', 'CONTACT_PRIVACYPOLICY' => 'Privacy policy', 'CONTACT_PRIVACYPOLICY_EXPLAIN' => 'I confirm that the given name, e-mail address, message text and my IP address will be processed and stored by the owner of the board according to the Privacy Policy', 'CONTACT_PRIVACYPOLICY_ERROR' => 'Please check the privacy policy box. Without your confirmation you won’t able to send us a message.', diff --git a/license.txt b/license.txt index 3912109..b8b347f 100644 --- a/license.txt +++ b/license.txt @@ -1,12 +1,12 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to +the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not @@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE + + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -225,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - NO WARRANTY + NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN @@ -277,64 +277,5 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice + END OF TERMS AND CONDITIONS -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/styles/prosilver/template/contactadmin_body.html b/styles/prosilver/template/contactadmin_body.html index 2b05ffc..7ca80f5 100644 --- a/styles/prosilver/template/contactadmin_body.html +++ b/styles/prosilver/template/contactadmin_body.html @@ -1,4 +1,5 @@ -{% INCLUDE 'overall_header.html' %} +{% INCLUDECSS '@phpbbmodders_contactadmin/contactadmin.css' %} +{% include 'overall_header.html' %}

{{ lang('ACP_CAT_CONTACTADMIN') }}

@@ -33,13 +34,17 @@

{{ lang('ACP_CAT_CONTACTADMIN') }}


{% endif %} - {% if CONTACT_REASONS %} + {% if S_CONTACT_REASONS %}
-
+
{% endif %} - {% if not CONTACT_REASONS %} + {% if not S_CONTACT_REASONS %}
@@ -47,7 +52,7 @@

{{ lang('ACP_CAT_CONTACTADMIN') }}

{% endif %}
-
+
@@ -73,7 +78,7 @@

{{ lang('ACP_CAT_CONTACTADMIN') }}

{% DEFINE CAPTCHA_TAB_INDEX = 8 %} - {% INCLUDE ''~ CONTACT_ADMIN_CAPTCHA_TEMPLATE ~'' %} + {% include CONTACT_ADMIN_CAPTCHA_TEMPLATE %}
@@ -83,7 +88,7 @@

{{ lang('ACP_CAT_CONTACTADMIN') }}

-

{{ lang('ADD_ATTACHMENT_EXPLAIN') }}

+

{{ lang('CONTACT_ADD_ATTACHMENT_EXPLAIN') }}

@@ -107,7 +112,7 @@

{{ lang('ACP_CAT_CONTACTADMIN') }}

{{ S_HIDDEN_FIELDS }} -   +   {{ S_FORM_TOKEN }}
@@ -116,4 +121,4 @@

{{ lang('ACP_CAT_CONTACTADMIN') }}

-{% INCLUDE 'overall_footer.html' %} \ No newline at end of file +{% include 'overall_footer.html' %} \ No newline at end of file diff --git a/styles/prosilver/template/event/overall_footer_teamlink_after.html b/styles/prosilver/template/event/overall_footer_teamlink_after.html index 277c280..591b690 100644 --- a/styles/prosilver/template/event/overall_footer_teamlink_after.html +++ b/styles/prosilver/template/event/overall_footer_teamlink_after.html @@ -1,7 +1,7 @@ {% if U_CONTACTADMIN %} -
  • +
  • - {% if S_FORUM_VERSION %}{% endif %}{{ lang('CONTACT_US') }} + {{ lang('CONTACT_US') }}
  • {% endif %} \ No newline at end of file diff --git a/styles/prosilver/template/event/overall_header_navigation_append.html b/styles/prosilver/template/event/overall_header_navigation_append.html index 42a0fa9..c75b58f 100644 --- a/styles/prosilver/template/event/overall_header_navigation_append.html +++ b/styles/prosilver/template/event/overall_header_navigation_append.html @@ -1,7 +1,7 @@ {% if U_CONTACTADMIN %} -
  • +
  • - {% if S_FORUM_VERSION %}{% endif %}{{ lang('CONTACT_US') }} + {{ lang('CONTACT_US') }}
  • {% endif %} \ No newline at end of file diff --git a/styles/prosilver/template/event/overall_header_stylesheets_after.html b/styles/prosilver/theme/contactadmin.css similarity index 64% rename from styles/prosilver/template/event/overall_header_stylesheets_after.html rename to styles/prosilver/theme/contactadmin.css index 3e3767d..74e8892 100644 --- a/styles/prosilver/template/event/overall_header_stylesheets_after.html +++ b/styles/prosilver/theme/contactadmin.css @@ -1,5 +1,4 @@ -{% if S_CONTACT_ADMIN %} - -{% endif %} + +.contactadmin-message { + width: 98%; + height: 160px; +} diff --git a/styles/scaffoldBB/template/contactadmin_body.html b/styles/scaffoldBB/template/contactadmin_body.html index 3d50562..1dbf727 100644 --- a/styles/scaffoldBB/template/contactadmin_body.html +++ b/styles/scaffoldBB/template/contactadmin_body.html @@ -1,4 +1,4 @@ -{% INCLUDE 'overall_header.html' %} +{% include 'overall_header.html' %}

    {{ lang('ACP_CAT_CONTACTADMIN') }}

    @@ -33,13 +33,17 @@

    {{ lang('ACP_CAT_CONTACTADMIN') }}


    {% endif %} - {% if CONTACT_REASONS %} + {% if S_CONTACT_REASONS %}
    -
    +
    {% endif %} - {% if not CONTACT_REASONS %} + {% if not S_CONTACT_REASONS %}
    @@ -47,7 +51,7 @@

    {{ lang('ACP_CAT_CONTACTADMIN') }}

    {% endif %}
    -
    +
    @@ -73,7 +77,7 @@

    {{ lang('ACP_CAT_CONTACTADMIN') }}

    {% DEFINE CAPTCHA_TAB_INDEX = 8 %} - {% INCLUDE ''~ CONTACT_ADMIN_CAPTCHA_TEMPLATE ~'' %} + {% include CONTACT_ADMIN_CAPTCHA_TEMPLATE %}
    @@ -83,7 +87,7 @@

    {{ lang('ACP_CAT_CONTACTADMIN') }}

    -

    {{ lang('ADD_ATTACHMENT_EXPLAIN') }}

    +

    {{ lang('CONTACT_ADD_ATTACHMENT_EXPLAIN') }}

    @@ -107,7 +111,7 @@

    {{ lang('ACP_CAT_CONTACTADMIN') }}

    {{ S_HIDDEN_FIELDS }} -   +   {{ S_FORM_TOKEN }}
    @@ -116,4 +120,4 @@

    {{ lang('ACP_CAT_CONTACTADMIN') }}

    -{% INCLUDE 'overall_footer.html' %} \ No newline at end of file +{% include 'overall_footer.html' %} \ No newline at end of file diff --git a/styles/scaffoldBB/template/event/overall_footer_teamlink_after.html b/styles/scaffoldBB/template/event/overall_footer_teamlink_after.html index 95cf730..d732797 100644 --- a/styles/scaffoldBB/template/event/overall_footer_teamlink_after.html +++ b/styles/scaffoldBB/template/event/overall_footer_teamlink_after.html @@ -1,7 +1,7 @@ {% if U_CONTACTADMIN %} - {% endif %} \ No newline at end of file diff --git a/styles/scaffoldBB/template/event/overall_header_navigation_append.html b/styles/scaffoldBB/template/event/overall_header_navigation_append.html index 5c5a828..8b408d2 100644 --- a/styles/scaffoldBB/template/event/overall_header_navigation_append.html +++ b/styles/scaffoldBB/template/event/overall_header_navigation_append.html @@ -1,7 +1,7 @@ {% if U_CONTACTADMIN %} - {% endif %} \ No newline at end of file