Extensions

This commit is contained in:
Gauvain Boiché
2020-04-04 23:28:30 +02:00
parent 3a964fe237
commit 155e626426
286 changed files with 10757 additions and 2 deletions

View File

@@ -0,0 +1,288 @@
<?php
/**
* phpBB Studio's Dice extension for the phpBB Forum Software package.
*
* @copyright (c) 2019 phpBB Studio <https://www.phpbbstudio.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*/
namespace phpbbstudio\dice\event;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* phpBB Studio's Dice ACP listener.
*/
class acp_listener implements EventSubscriberInterface
{
/** @var \phpbb\db\driver\driver_interface */
protected $db;
/** @var \phpbbstudio\dice\core\functions_common */
protected $functions;
/** @var \phpbb\request\request */
protected $request;
/** @var string Dice rolls table */
protected $rolls_table;
/**
* Constructor.
*
* @param \phpbb\db\driver\driver_interface $db Database object
* @param \phpbbstudio\dice\core\functions_common $functions Dice common functions
* @param \phpbb\request\request $request Request object
* @param string $rolls_table Dice rolls table
* @return void
* @access public
*/
public function __construct(
\phpbb\db\driver\driver_interface $db,
\phpbbstudio\dice\core\functions_common $functions,
\phpbb\request\request $request,
$rolls_table
)
{
$this->db = $db;
$this->functions = $functions;
$this->request = $request;
$this->rolls_table = $rolls_table;
}
/**
* Assign functions defined in this class to event listeners in the core.
*
* @static
* @return array
* @access public
*/
static public function getSubscribedEvents()
{
return [
'core.delete_user_after' => 'dice_delete_user_after',
// excluded in order to be able to soft delete posts and rolls and keep rolls quoted elsewhere
//'core.delete_post_after' => 'dice_delete_post_after',
'core.move_posts_after' => 'dice_move_posts_after',
// excluded in order to be able to keep rolls quoted elsewhere
//'core.delete_topics_before_query' => 'dice_add_rolls_table',
'core.move_topics_before_query' => 'dice_add_rolls_table',
// excluded in order to be able to keep rolls quoted elsewhere
//'core.delete_forum_content_before_query' => 'dice_add_rolls_table',
// excluded in order to be able to keep rolls quoted elsewhere
//'core.delete_posts_in_transaction_before' => 'dice_add_rolls_table',
'core.acp_manage_forums_move_content_sql_before' => 'dice_add_rolls_table',
'core.mcp_main_fork_sql_after' => 'dice_mcp_main_fork_sql_after',
'core.acp_manage_forums_request_data' => 'dice_acp_manage_forums_request_data',
'core.acp_manage_forums_initialise_data' => 'dice_acp_manage_forums_initialise_data',
'core.acp_manage_forums_display_form' => 'dice_acp_manage_forums_display_form',
];
}
/**
* Perform actions directly after a user has been deleted
* and "delete their posts" or "retain their posts" has been selected.
*
* @event core.delete_post_after
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function dice_delete_user_after($event)
{
$user_ids = $event['user_ids'];
if (!empty($user_ids))
{
if ($event['mode'] === 'remove' || $event['mode'] === 'retain')
{
/* Change user_id to anonymous for rolls by this user */
$sql = 'UPDATE ' . $this->rolls_table . '
SET user_id = ' . ANONYMOUS . '
WHERE ' . $this->db->sql_in_set('user_id', $user_ids);
$this->db->sql_query($sql);
}
}
}
/**
* Performing actions directly after a post or topic has been deleted.
* On hitting the X button of a post in view topic.
*
* @event core.delete_post_after
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function dice_delete_post_after($event)
{
$sql = 'DELETE FROM ' . $this->rolls_table . ' WHERE post_id = ' . (int) $event['post_id'];
$this->db->sql_query($sql);
}
/**
* Perform actions after the posts have been moved
*
* @event core.move_posts_after
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function dice_move_posts_after($event)
{
$forum_row = $event['forum_row'];
$post_ids = $event['post_ids'];
$topic_id = $event['topic_id'];
$sql = 'UPDATE ' . $this->rolls_table . '
SET forum_id = ' . (int) $forum_row['forum_id'] . ",
topic_id = " . (int) $topic_id . "
WHERE " . $this->db->sql_in_set('post_id', $post_ids);
$this->db->sql_query($sql);
}
/**
* Shared function which adds our rolls table to an array of tables.
*
* @event core.delete_topics_before_query On delete a topic MCP/Quicktools
* @event core.move_topics_before_query On move a topic MCP/Quicktools moves the rolls too
* @event core.delete_forum_content_before_query On delete a forum in ACP
* @event core.acp_manage_forums_move_content_sql_before On move content of a forum in ACP
* @event core.delete_posts_in_transaction_before On delete posts in MCP
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function dice_add_rolls_table($event)
{
$table_ary = $event['table_ary'];
$table_ary[] = $this->rolls_table;
$event['table_ary'] = $table_ary;
}
/**
* Forks the topics (rolls) accordingly to the native functionality
*
* @event core.mcp_main_fork_sql_after
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function dice_mcp_main_fork_sql_after($event)
{
$topic_id = $event['row']['topic_id'];
$post_id = $event['row']['post_id'];
$new_topic_id = $event['new_topic_id'];
$to_forum_id = $event['to_forum_id'];
$new_post_id = $event['new_post_id'];
$sql = 'SELECT *
FROM ' . $this->rolls_table . '
WHERE topic_id = ' . (int) $topic_id . '
AND post_id = ' . (int) $post_id . '
ORDER BY roll_id ASC';
$result = $this->db->sql_query($sql);
$sql_ary = [];
while ($rolls = $this->db->sql_fetchrow($result))
{
$sql_ary[] = [
'roll_id' => (int) $rolls['roll_id'],
'roll_notation' => (string) $rolls['roll_notation'],
'roll_dices' => (string) $rolls['roll_dices'],
'roll_rolls' => (string) $rolls['roll_rolls'],
'roll_output' => (string) $rolls['roll_output'],
'roll_total' => (int) $rolls['roll_total'],
'roll_successes' => (int) $rolls['roll_successes'],
'roll_is_pool' => (int) $rolls['roll_is_pool'],
'roll_time' => (int) $rolls['roll_time'],
'roll_edit_user' => (int) $rolls['roll_edit_user'],
'roll_edit_time' => (int) $rolls['roll_edit_time'],
'roll_edit_count' => (int) $rolls['roll_edit_count'],
'forum_id' => (int) $to_forum_id,
'topic_id' => (int) $new_topic_id,
'post_id' => (int) $new_post_id,
'user_id' => (int) $rolls['user_id'],
];
}
$this->db->sql_freeresult($result);
if (!empty($sql_ary))
{
$this->db->sql_multi_insert($this->rolls_table, $sql_ary);
}
}
/* Here begins the ACP/Forums side of things */
/**
* (Add/update actions) - Submit form.
*
* @event core.acp_manage_forums_request_data
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function dice_acp_manage_forums_request_data($event)
{
$forum_data = $event['forum_data'];
$forum_data['dice_enabled'] = $this->request->variable('dice_enabled', 0);
$forum_data['dice_f_skin'] = $this->request->variable('dice_f_skin', '', true);
$forum_data['dice_skin_override'] = $this->request->variable('dice_skin_override', 0);
$event['forum_data'] = $forum_data;
}
/**
* New Forums added (default disabled).
*
* @event core.acp_manage_forums_initialise_data
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function dice_acp_manage_forums_initialise_data($event)
{
if ($event['action'] == 'add')
{
$forum_data = $event['forum_data'];
$forum_data['dice_enabled'] = false;
$forum_data['dice_f_skin'] = '';
$forum_data['dice_skin_override'] = false;
$event['forum_data'] = $forum_data;
}
}
/**
* ACP forums (template data).
*
* @event core.acp_manage_forums_display_form
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function dice_acp_manage_forums_display_form($event)
{
$template_data = $event['template_data'];
$skin = $event['forum_data']['dice_f_skin'];
$skins = $this->functions->get_dice_skins(true);
$template_data['S_DICE_ENABLED'] = $event['forum_data']['dice_enabled'];
$template_data['DICE_F_SKIN'] = $this->functions->build_dice_select($skins, $skin, true);
$template_data['S_DICE_SKIN_OVERRIDE'] = $event['forum_data']['dice_skin_override'];
$event['template_data'] = $template_data;
}
}

View File

@@ -0,0 +1,114 @@
<?php
/**
* phpBB Studio's Dice extension for the phpBB Forum Software package.
*
* @copyright (c) 2019 phpBB Studio <https://www.phpbbstudio.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*/
namespace phpbbstudio\dice\event;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* phpBB Studio's Dice BBCode listener.
*/
class bbcode_listener implements EventSubscriberInterface
{
/** @var \phpbbstudio\dice\core\functions_common */
protected $functions;
/** @var \phpbb\request\request */
protected $request;
/**
* Constructor.
*
* @param \phpbbstudio\dice\core\functions_common $functions Common functions
* @param \phpbb\request\request $request Request object
* @return void
* @access public
*/
public function __construct(
\phpbbstudio\dice\core\functions_common $functions,
\phpbb\request\request $request
)
{
$this->functions = $functions;
$this->request = $request;
}
/**
* Assign functions defined in this class to event listeners in the core.
*
* @static
* @return array
* @access public
*/
static public function getSubscribedEvents()
{
return [
'core.text_formatter_s9e_configure_after' => 'set_dice_bbcode',
'core.text_formatter_s9e_parse_before' => 'set_dice_availability',
];
}
/**
* Add the roll dice bbcode.
*
* @event core.text_formatter_s9e_configure_after
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function set_dice_bbcode($event)
{
/* Get the BBCode configurator */
$configurator = $event['configurator'];
$configurator->attributeFilters->set('#dicenotation', __CLASS__ . '::dice_notation');
/* Let's unset any existing BBCode that might already exist */
unset($configurator->BBCodes['roll']);
unset($configurator->tags['roll']);
/* Let's create the new BBCode */
$configurator->BBCodes->addCustom( '[roll={NUMBER}]{DICENOTATION}[/roll]', '<span class="phpbbstudio-dice" data-dice-id="{NUMBER}">{DICENOTATION}</span>');
}
/**
* Check if the roll dice bbcode should be parsed in this forum.
*
* @event core.text_formatter_s9e_parse_before
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function set_dice_availability($event)
{
/** @var \phpbb\textformatter\s9e\parser $parser */
$parser = $event['parser'];
$forum_id = (int) $this->request->variable('f', 0);
$dice_enabled = (bool) $this->functions->forum_enabled($forum_id);
($dice_enabled) ? $parser->enable_bbcode('roll') : $parser->disable_bbcode('roll');
}
/**
* Set the filter using within the roll dice bbcode.
*
* @param string $string The dice notation from within the bbcode
* @return string $notation The correctly formatted dice notation
* @access public
*/
public static function dice_notation($string)
{
$notation = str_replace(['D', 'f', 'h', 'l', 'P'], ['d', 'F', 'H', 'L', 'p'], $string);
//$notation = preg_replace('[^0-9dFHLp\+\-\*/!\.%=<>\(\)]', '', $notation);
$notation = preg_replace('([^0-9dFHLp\+\-\*/!\.%=<>\(\)])', '', $notation);
return $notation;
}
}

View File

@@ -0,0 +1,624 @@
<?php
/**
* phpBB Studio's Dice extension for the phpBB Forum Software package.
*
* @copyright (c) 2019 phpBB Studio <https://www.phpbbstudio.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*/
namespace phpbbstudio\dice\event;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* phpBB Studio's Dice Display listener.
*/
class display_listener implements EventSubscriberInterface
{
/** @var \phpbb\auth\auth */
protected $auth;
/** @var \phpbb\config\config */
protected $config;
/** @var \phpbbstudio\dice\core\functions_common */
protected $functions;
/** @var \phpbbstudio\dice\operator\roll */
protected $operator;
/** @var \phpbb\template\template */
protected $template;
/**
* Constructor.
*
* @param \phpbb\auth\auth $auth Authentication object
* @param \phpbb\config\config $config Configuration object
* @param \phpbbstudio\dice\core\functions_common $functions Common functions
* @param \phpbbstudio\dice\operator\roll $operator Roll operator object
* @param \phpbb\template\template $template Template object
* @return void
* @access public
*/
public function __construct(
\phpbb\auth\auth $auth,
\phpbb\config\config $config,
\phpbbstudio\dice\core\functions_common $functions,
\phpbbstudio\dice\operator\roll $operator,
\phpbb\template\template $template
)
{
$this->auth = $auth;
$this->config = $config;
$this->functions = $functions;
$this->operator = $operator;
$this->template = $template;
}
/**
* Assign functions defined in this class to event listeners in the core.
*
* @static
* @return array
* @access public
*/
static public function getSubscribedEvents()
{
return [
'core.viewtopic_assign_template_vars_before' => 'set_dice_display',
'core.viewtopic_modify_post_data' => 'get_dice_rolls',
'core.viewtopic_modify_post_row' => 'display_dice_rolls',
'core.topic_review_modify_post_list' => 'get_review_dice_rolls',
'core.topic_review_modify_row' => 'display_review_dice_rolls',
'core.mcp_topic_modify_post_data' => 'get_mcp_dice_rolls',
'core.mcp_topic_review_modify_row' => 'display_mcp_dice_rolls',
'core.mcp_post_template_data' => 'display_mcp_post_dice_rolls',
'core.mcp_report_template_data' => 'display_mcp_report_dice_rolls',
];
}
/**
* Assign template variables used for displaying dice rolls.
*
* @event core.viewtopic_assign_template_vars_before
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function set_dice_display($event)
{
$forum_id = (int) $event['forum_id']; // Forum identifier
$topic_data = (array) $event['topic_data']; // Array with topic data
$this->template->assign_vars([
'DICE_IMG_HEIGHT' => (int) $this->config['dice_skins_img_height'],
'DICE_IMG_WIDTH' => (int) $this->config['dice_skins_img_width'],
'S_DICE_DISPLAY' => (bool) ($topic_data['dice_enabled'] && $this->auth->acl_get('f_dice_view', $forum_id)),
]);
}
/**
* Get roll data for a list of posts in a topic page.
*
* @event core.viewtopic_modify_post_data
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function get_dice_rolls($event)
{
// Grab event data
$forum_id = (int) $event['forum_id']; // Forum identifier
$topic_id = (int) $event['topic_id']; // Topic identifier
$topic_data = (array) $event['topic_data']; // Array with topic data
$post_list = (array) $event['post_list']; // Array with post_ids we are going to display
// If the dice extension is not enabled for this forum, we return.
if (!$topic_data['dice_enabled'] || !$this->auth->acl_get('f_dice_view', $forum_id))
{
return;
}
// Get entities for the post list
$entities = $this->operator->get_rolls_for_topic($forum_id, $topic_id, $post_list);
// Get the dice skin
$skin_data = $this->functions->get_dice_skin_data($topic_data['dice_skin_override'], $topic_data['dice_f_skin']);
$topic_data['dice_skin'] = $skin_data;
/** @var \phpbbstudio\dice\entity\roll $entity */
foreach ($entities as $entity)
{
$roll_id = (int) $entity->get_id(); // Roll identifier
// Add the roll data to the topic data
$topic_data['dice_rolls'][$roll_id] = $this->operator->get_roll_data_for_display($entity, $skin_data);
}
$event['topic_data'] = $topic_data;
}
/**
* Display the roll data for a list of posts in a topic page.
*
* @event core.viewtopic_modify_post_row
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function display_dice_rolls($event)
{
// Grab the event data
$row = (array) $event['row']; // Array with original post and user data
$post_row = (array) $event['post_row']; // Template block array of the post
$topic_data = (array) $event['topic_data'];
// Grab the post message and the rolls data
$message = $post_row['MESSAGE'];
$rolls = isset($topic_data['dice_rolls']) ? $topic_data['dice_rolls'] : [];
if ($topic_data['dice_enabled'] && $this->auth->acl_get('f_dice_view', $row['forum_id']))
{
$message = $this->replace_rolls($message, $rolls, $topic_data['dice_skin'], $row, false);
// Lets do the quotes!
$message = preg_replace_callback(
'/<blockquote[^>]*>(.+?)<\/blockquote>/s',
function ($match) use (&$rolls, $topic_data, $row) {
return $this->replace_rolls($match[0], $rolls, $topic_data['dice_skin'], $row, true);
},
$message
);
$outline = $this->display_dice_rolls_not_inline($rolls, $row['post_id']);
$post_row['DICE_ROLLS_OUTLINE'] = $outline;
$post_row['MESSAGE'] = $message;
$event['post_row'] = $post_row;
$topic_data['dice_rolls'] = $rolls;
$event['topic_data'] = $topic_data;
}
}
/**
* Get the dice rolls displayed in the topic review.
*
* @event core.topic_review_modify_post_list
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function get_review_dice_rolls($event)
{
// Grab event data
$forum_id = (int) $event['forum_id']; // Forum identifier
$topic_id = (int) $event['topic_id']; // Topic identifier
$post_list = (array) $event['post_list']; // Array with post_ids we are going to display
$rowset = (array) $event['rowset']; // Array with the posts data
$forum_data = $this->functions->forum_data((int) $forum_id);
// If the dice extension is not enabled for this forum, we return.
if (!$forum_data['dice_enabled'] || !$this->auth->acl_get('f_dice_view', $forum_id))
{
return;
}
// Get entities for the post list
$entities = $this->operator->get_rolls_for_topic($forum_id, $topic_id, $post_list);
// Get the dice skin
$skin_data = $this->functions->get_dice_skin_data($forum_data['dice_skin_override'], $forum_data['dice_f_skin']);
/** @var \phpbbstudio\dice\entity\roll $entity */
foreach ($entities as $entity)
{
// Add the roll data to the topic data
$rowset[$entity->get_post()]['dice_rolls'][$entity->get_id()] = $this->operator->get_roll_data_for_display($entity, $skin_data);
$rowset[$entity->get_post()]['dice_skin'] = $skin_data;
}
$this->template->assign_var('S_DICE_REVIEW', true);
$event['rowset'] = $rowset;
}
/**
* Display the dice rolls in the topic review.
*
* @event core.topic_review_modify_row
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function display_review_dice_rolls($event)
{
// Grab event data
$forum_id = (int) $event['forum_id'];
$post_row = (array) $event['post_row'];
$row = (array) $event['row'];
$message = $post_row['MESSAGE'];
$rolls = isset($row['dice_rolls']) ? $row['dice_rolls'] : [];
$skin_data = isset($row['dice_skin']) ? $row['dice_skin'] : [];
if ($this->auth->acl_get('f_dice_view', $forum_id) && $rolls)
{
if (!$skin_data)
{
$forum_data = $this->functions->forum_data((int) $forum_id);
$skin_data = $this->functions->get_dice_skin_data($forum_data['dice_skin_override'], $forum_data['dice_f_skin']);
}
$message = $this->replace_rolls($message, $rolls, $skin_data, $row, false);
// Lets do the quotes!
$message = preg_replace_callback(
'/<blockquote[^>]*>(.+?)<\/blockquote>/s',
function ($match) use (&$rolls, $skin_data, $row) {
return $this->replace_rolls($match[0], $rolls, $skin_data, $row, true);
},
$message
);
$outline = $this->display_dice_rolls_not_inline($rolls, $row['post_id']);
$post_row['DICE_ROLLS_OUTLINE'] = $outline;
$post_row['MESSAGE'] = $message;
$event['post_row'] = $post_row;
}
}
/**
* Get the dice rolls displayed in the Moderator Control Panel.
*
* @event core.mcp_topic_modify_post_data
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function get_mcp_dice_rolls($event)
{
// Grab event data
$forum_id = (int) $event['forum_id']; // Forum identifier
$topic_id = (int) $event['topic_id']; // Topic identifier
$post_list = (array) $event['post_id_list']; // Array with post_ids we are going to display
$rowset = (array) $event['rowset']; // Array with the posts data
// Forum id might not be directly available from the &f= parameter, so otherwise grab it from the first post data.
$forum_id = (empty($forum_id) && isset($rowset[0]['forum_id'])) ? (int) $rowset[0]['forum_id'] : $forum_id;
$forum_data = $this->functions->forum_data((int) $forum_id);
// If the dice extension is not enabled for this forum, we return.
if (!$forum_data['dice_enabled'] || !$this->auth->acl_get('f_dice_view', $forum_id))
{
return;
}
$rolls = [];
// Get entities for the post list
$entities = $this->operator->get_rolls_for_topic($forum_id, $topic_id, $post_list);
// Get the dice skin
$skin_data = $this->functions->get_dice_skin_data($forum_data['dice_skin_override'], $forum_data['dice_f_skin']);
/** @var \phpbbstudio\dice\entity\roll $entity */
foreach ($entities as $entity)
{
// Add the roll data to the topic data
$rolls[$entity->get_post()][$entity->get_id()] = $this->operator->get_roll_data_for_display($entity, $skin_data);
}
// This rowset does not have post id's as array keys.. :(
for ($i = 0, $count = count($rowset); $i < $count; $i++)
{
$post_id = $rowset[$i]['post_id'];
if (isset($rolls[$post_id]))
{
$rowset[$i]['dice_rolls'] = $rolls[$post_id];
$rowset[$i]['dice_skin'] = $skin_data;
}
}
$this->template->assign_var('S_DICE_MCP_DISPLAY', true);
$event['rowset'] = $rowset;
}
/**
* Display dice rolls in the Moderator Control Panel.
*
* @event core.mcp_topic_review_modify_row
* @param \phpbb\event\data $event The event object
* @access public
* @return void
*/
public function display_mcp_dice_rolls($event)
{
// Grab event data
$forum_id = (int) $event['forum_id'];
$topic_info = (array) $event['topic_info'];
$post_row = (array) $event['post_row'];
$row = (array) $event['row'];
// Forum id might not be directly available from the &f= parameter, so otherwise grab it from the first post data.
$forum_id = empty($forum_id) ? (int) $row['forum_id'] : $forum_id;
$message = $post_row['MESSAGE'];
// Get the dice rolls and merge them with all previously queried from this topic
$topic_rolls = isset($topic_info['dice_rolls']) ? $topic_info['dice_rolls'] : [];
$post_rolls = isset($row['dice_rolls']) ? $row['dice_rolls'] : [];
$rolls = $topic_rolls + $post_rolls;
// Get the dice skin data: stored in topic data? stored in row data? query.
if (isset($topic_info['dice_skin']))
{
$skin_data = $topic_info['dice_skin'];
}
else if (isset($row['dice_skin']))
{
$skin_data = $row['dice_skin'];
}
else
{
$forum_data = $this->functions->forum_data((int) $forum_id);
$skin_data = $this->functions->get_dice_skin_data($forum_data['dice_skin_override'], $forum_data['dice_f_skin']);
}
// Merge the skin data into the topic data
$topic_info['dice_skin'] = $skin_data;
if ($this->auth->acl_get('f_dice_view', $forum_id) && $rolls)
{
$message = $this->replace_rolls($message, $rolls, $skin_data, $row, false);
// Lets do the quotes!
$message = preg_replace_callback(
'/<blockquote[^>]*>(.+?)<\/blockquote>/s',
function ($match) use (&$rolls, $skin_data, $row) {
return $this->replace_rolls($match[0], $rolls, $skin_data, $row, true);
},
$message
);
$outline = $this->display_dice_rolls_not_inline($rolls, $row['post_id']);
$post_row['DICE_ROLLS_OUTLINE'] = $outline;
$post_row['MESSAGE'] = $message;
$event['post_row'] = $post_row;
}
$topic_info['dice_rolls'] = $rolls;
$event['topic_info'] = $topic_info;
}
/**
* Display dice rolls in the Moderator Control Panel's post details.
*
* @event core.mcp_post_template_data
* @param \phpbb\event\data $event The event object
* @retrun void
* @access public
*/
public function display_mcp_post_dice_rolls($event)
{
$post_info = (array) $event['post_info']; // Array with the post information
$post_tpl = (array) $event['mcp_post_template_data']; // Array with the MCP post template data
$message = $post_tpl['POST_PREVIEW'];
$message = $this->replace_mcp_rolls($message, $post_info);
$post_tpl['POST_PREVIEW'] = $message;
$event['mcp_post_template_data'] = $post_tpl;
}
/**
* Display dice rolls in the Moderator Control Panel's report details.
*
* @event core.mcp_report_template_data
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function display_mcp_report_dice_rolls($event)
{
// Grab event data
$post_info = (array) $event['post_info']; // Array with the post information
$report_tpl = (array) $event['report_template']; // Array with the MCP report template data
$message = $report_tpl['POST_PREVIEW'];
$message = $this->replace_mcp_rolls($message, $post_info);
$report_tpl['POST_PREVIEW'] = $message;
$event['report_template'] = $report_tpl;
}
/**
* Replace dice rolls in a message in the Moderator Control Panel.
*
* @param string $message The message with the dice rolls
* @param array $post_info The array with the post data
* @return string The rendered message with the dice rolls replacement
* @access protected
*/
protected function replace_mcp_rolls($message, array $post_info)
{
$forum_id = (int) $post_info['forum_id'];
$topic_id = (int) $post_info['topic_id'];
$post_id = (int) $post_info['post_id'];
$forum_data = $this->functions->forum_data((int) $forum_id);
// If the dice extension is not enabled for this forum, we return.
if (!$forum_data['dice_enabled'] || !$this->auth->acl_get('f_dice_view', $forum_id))
{
return $message;
}
$rolls = [];
// Get the dice skin
$skin_data = $this->functions->get_dice_skin_data($forum_data['dice_skin_override'], $forum_data['dice_f_skin']);
// Get entities for the post list
$entities = $this->operator->get_rolls_for_topic($forum_id, $topic_id, [$post_id]);
/** @var \phpbbstudio\dice\entity\roll $entity */
foreach ($entities as $entity)
{
// Add the roll data to the topic data
$rolls[$entity->get_id()] = $this->operator->get_roll_data_for_display($entity, $skin_data);
}
if ($this->auth->acl_get('f_dice_view', $forum_id) && $rolls)
{
$message = $this->replace_rolls($message, $rolls, $skin_data, $post_info, false);
// Lets do the quotes!
$message = preg_replace_callback(
'/<blockquote[^>]*>(.+?)<\/blockquote>/s',
function ($match) use (&$rolls, $skin_data, $post_info) {
return $this->replace_rolls($match[0], $rolls, $skin_data, $post_info, true);
},
$message
);
$outline = $this->display_dice_rolls_not_inline($rolls, $post_id);
$this->template->assign_vars([
'DICE_ROLLS_OUTLINE' => $outline,
'S_DICE_MCP_DISPLAY' => true,
]);
}
return $message;
}
/**
* Replace dice rolls in a message.
*
* @param string $message The message
* @param array $rolls The dice rolls
* @param array $skin The dice skin data
* @param array $row The post row data
* @param bool $quote Whether we're replacing rolls inside a quote
* @param bool $bbcode Whether we're looking for the BBCode or the HTML replacement
* @return string
* @access protected
*/
protected function replace_rolls($message, array &$rolls, array $skin, array $row, $quote = false, $bbcode = false)
{
$regex = $bbcode ? '/\[roll=([0-9]+)\].+?\[\/roll\]/s' : '/<span class="phpbbstudio-dice" data-dice-id="([0-9]+)">.+?<\/span>/s';
return preg_replace_callback(
$regex,
function($match) use (&$rolls, $skin, $row, $quote)
{
// Capture group 1 is the roll identifier
$roll_id = (int) $match[1];
$roll = isset($rolls[$roll_id]) ? $rolls[$roll_id] : [];
// If the roll exists
if ($roll)
{
// It belongs to this post or is in a quote
if (($roll['post'] == $row['post_id']) || $quote)
{
// Set it as displayed in-line
$rolls[$roll_id]['inline'] = true;
// Assign the roll variables
return $this->operator->assign_roll_vars($roll);
}
else
{
return $match[0];
}
}
else if ($quote)
{
// Lets check if we tried querying this roll before and could not find it.
$not_found = isset($rolls['not_found']) ? $rolls['not_found'] : [];
if (in_array($roll_id, $not_found))
{
return $match[0];
}
try
{
// Try to load the roll from the database
$entity = $this->operator->get_entity()->load($roll_id);
}
catch (\phpbbstudio\dice\exception\out_of_bounds $e)
{
// The roll was not found, so lets add it to the 'not_found' array.
$rolls['not_found'][] = $roll_id;
// The roll does not exist, so return the string
return $match[0];
}
$roll = $this->operator->get_roll_data_for_display($entity, $skin);
// Add the roll to the rolls data
$rolls[$roll_id] = $roll;
return $this->operator->assign_roll_vars($roll);
}
else
{
// Roll was not found, return the entire string
return $match[0];
}
},
$message
);
}
/**
* Display any not in-line dice rolls.
*
* @param array $rolls The dice rolls
* @param int $post_id The post identifier
* @return array Array of the not in-line displayed dice rolls
* @access protected
*/
protected function display_dice_rolls_not_inline(array $rolls, $post_id)
{
// Enforce data type
$post_id = (int) $post_id;
// Set up collection array
$outline = [];
// Make sure we are not iterating over not found rolls
unset($rolls['not_found']);
foreach ($rolls as $roll_id => $roll)
{
// If the roll is already displayed inline or,
// if the the roll does not belong to this post:
if ($roll['inline'] || $roll['post'] !== $post_id)
{
// we continue..
continue;
}
// Else, lets add it to the outline rolls array
$outline[] = $this->operator->assign_roll_vars($roll);
}
return $outline;
}
}

View File

@@ -0,0 +1,203 @@
<?php
/**
* phpBB Studio's Dice extension for the phpBB Forum Software package.
*
* @copyright (c) 2019 phpBB Studio <https://www.phpbbstudio.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*/
namespace phpbbstudio\dice\event;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* phpBB Studio's Dice Posting listener.
*/
class posting_listener implements EventSubscriberInterface
{
/** @var \phpbbstudio\dice\core\functions_common */
protected $functions;
/** @var \phpbb\controller\helper */
protected $helper;
/** @var \phpbbstudio\dice\operator\roll */
protected $operator;
/** @var \phpbb\request\request */
protected $request;
/** @var \phpbb\template\template */
protected $template;
/**
* Constructor.
*
* @param \phpbbstudio\dice\core\functions_common $functions Common functions
* @param \phpbb\controller\helper $helper Controller helper object
* @param \phpbbstudio\dice\operator\roll $operator Roll operator object
* @param \phpbb\request\request $request Request object
* @param \phpbb\template\template $template Template object
* @return void
* @access public
*/
public function __construct(
\phpbbstudio\dice\core\functions_common $functions,
\phpbb\controller\helper $helper,
\phpbbstudio\dice\operator\roll $operator,
\phpbb\request\request $request,
\phpbb\template\template $template
)
{
$this->functions = $functions;
$this->helper = $helper;
$this->operator = $operator;
$this->request = $request;
$this->template = $template;
}
/**
* Assign functions defined in this class to event listeners in the core.
*
* @static
* @return array
* @access public
*/
static public function getSubscribedEvents()
{
return [
'core.posting_modify_post_data' => 'dice_posting_requests',
'core.posting_modify_submit_post_before' => 'dice_posting_submit',
'core.submit_post_end' => 'dice_posting_update',
'core.posting_modify_template_vars' => 'dice_posting_variables',
];
}
/**
* Request dice roll indicator.
*
* @event core.posting_modify_post_data
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function dice_posting_requests($event)
{
$event['post_data'] = array_merge($event['post_data'], [
'dice_indicator' => $this->request->is_set_post('dice_indicator'),
]);
}
/**
* Copy the dice roll indicator so it is available in dice_posting_update()
*
* @event core.posting_modify_submit_post_before
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function dice_posting_submit($event)
{
$event['data'] = array_merge($event['data'], [
'dice_indicator' => $event['post_data']['dice_indicator'],
]);
}
/**
* Update the roll identifiers after the post has been submitted.
*
* @event core.submit_post_end
* @param \phpbb\event\data $event The event object
* @return void
* @access public
* @throws \phpbbstudio\dice\exception\out_of_bounds
*/
public function dice_posting_update($event)
{
// Grab the event data
$data = $event['data'];
$mode = $event['mode'];
// Grab the identifiers
$forum_id = (int) $data['forum_id'];
$topic_id = (int) $data['topic_id'];
$post_id = (int) $data['post_id'];
if ($data['dice_indicator'])
{
switch ($mode)
{
case 'post':
case 'reply':
case 'quote':
// Set identifiers
$this->operator->set_rolls_identifiers($mode, $forum_id, $topic_id, $post_id);
break;
default:
// All identifiers are already set
break;
}
}
}
/**
* Assign roll and extension data to the template.
*
* @event core.posting_modify_template_vars
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function dice_posting_variables($event)
{
// Grab the event data
$mode = $event['mode'];
$post_data = $event['post_data'];
// Grab the identifiers
$forum_id = (int) $event['forum_id'];
$topic_id = (int) $event['topic_id'];
$post_id = (int) $event['post_id'];
$poster_id = (int) $post_data['poster_id'];
// If we are quoting a post, we have to reset the post identifier
$post_id = $mode === 'quote' ? 0 : $post_id;
// Get roll entities for this combination of identifiers
$entities = $this->operator->get_rolls_for_posting($forum_id, $topic_id, $post_id);
// Assign the rolls data to the template
$this->operator->assign_block_vars($entities);
// Count the entities
$count = count($entities);
/**
* @var bool S_DICE_INDICATOR Used to determine if a dice roll was added, needed for other events
* @var string U_DICE_ADD URL to add a dice roll for this post
* @var string U_DICE_DEL Base URL to delete a dice roll, needed for the AJAX callback
* @var string U_DICE_EDIT Base URL to edit a dice roll, needed for the AJAX callback
*/
$this->template->assign_vars([
'S_DICE_ENABLED' => (bool) $post_data['dice_enabled'],
'S_DICE_INDICATOR' => isset($post_data['dice_indicator']) ? (bool) $post_data['dice_indicator'] : false,
'S_DICE_LIMIT' => (bool) $this->functions->dice_limit_reached($count, $forum_id),
'S_ROLL_ADD' => (bool) $this->functions->dice_auth_add($forum_id, $poster_id),
'S_ROLL_DELETE' => (bool) $this->functions->dice_auth_delete($forum_id, $poster_id),
'S_ROLL_EDIT' => (bool) $this->functions->dice_auth_edit($forum_id, $poster_id),
'U_DICE_ADD' => $this->helper->route('phpbbstudio_dice_add', [
'forum_id' => $forum_id,
'topic_id' => $topic_id,
'post_id' => $post_id,
'poster_id' => $poster_id,
'hash' => generate_link_hash('dice_add')
]),
'U_DICE_DELETE' => $this->helper->route('phpbbstudio_dice_del'),
'U_DICE_EDIT' => $this->helper->route('phpbbstudio_dice_edit'),
]);
}
}

View File

@@ -0,0 +1,151 @@
<?php
/**
* phpBB Studio's Dice extension for the phpBB Forum Software package.
*
* @copyright (c) 2019 phpBB Studio <https://www.phpbbstudio.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*/
namespace phpbbstudio\dice\event;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* phpBB Studio's Dice Set up listener.
*/
class setup_listener implements EventSubscriberInterface
{
/** @var \phpbb\auth\auth */
protected $auth;
/** @var \phpbbstudio\dice\core\functions_common */
protected $functions;
/** @var \phpbb\language\language */
protected $lang;
/** @var \phpbb\template\template */
protected $template;
/**
* Constructor.
*
* @param \phpbb\auth\auth $auth Authentication object
* @param \phpbbstudio\dice\core\functions_common $functions Common dice functions
* @param \phpbb\language\language $lang Language object
* @param \phpbb\template\template $template Template object
* @return void
* @access public
*/
public function __construct(
\phpbb\auth\auth $auth,
\phpbbstudio\dice\core\functions_common $functions,
\phpbb\language\language $lang,
\phpbb\template\template $template
)
{
$this->auth = $auth;
$this->functions = $functions;
$this->lang = $lang;
$this->template = $template;
}
/**
* Assign functions defined in this class to event listeners in the core.
*
* @static
* @return array
* @access public
*/
static public function getSubscribedEvents()
{
return [
'core.user_setup_after' => 'dice_setup_lang',
'core.page_header' => 'dice_setup_links',
'core.permissions' => 'dice_setup_permissions',
];
}
/**
* Load extension language file during user set up.
*
* @event core.user_setup_after
* @return void
* @access public
*/
public function dice_setup_lang()
{
$this->lang->add_lang('dice_common', 'phpbbstudio/dice');
}
/**
* Set up dice page links.
*
* @event core.page_header
* @return void
* @access public
*/
public function dice_setup_links()
{
$template_vars = [];
// If the user has the permission to view the page
if ($this->auth->acl_get('u_dice_test'))
{
foreach ($this->functions->get_dice_link_locations() as $link)
{
// Lets only add those links that are enabled to the template
if ($link['status'])
{
$template_vars['S_DICE_' . utf8_strtoupper($link['name'])] = true;
}
}
$this->template->assign_vars($template_vars);
}
}
/**
* Add permissions for DICE - Permission's language file is automatically loaded.
*
* @event core.permissions
* @param \phpbb\event\data $event The event object
* @return void
* @access public
*/
public function dice_setup_permissions($event)
{
$categories = $event['categories'];
$permissions = $event['permissions'];
if (empty($categories['phpbb_studio']))
{
/* Setting up a custom CAT */
$categories['phpbb_studio'] = 'ACL_CAT_PHPBB_STUDIO';
$event['categories'] = $categories;
}
$perms = [
'f_dice_roll',
'f_dice_edit',
'f_dice_delete',
'f_dice_view',
'f_dice_no_limit',
'f_mod_dice_add',
'f_mod_dice_edit',
'f_mod_dice_delete',
'a_dice_admin',
'u_dice_use_ucp',
'u_dice_test',
'u_dice_skin',
];
foreach ($perms as $permission)
{
$permissions[$permission] = ['lang' => 'ACL_' . utf8_strtoupper($permission), 'cat' => 'phpbb_studio'];
}
$event['permissions'] = $permissions;
}
}