mirror of
https://github.com/phpbb/phpbb.git
synced 2025-06-07 20:08:53 +00:00
Merge pull request #6206 from marc1706/ticket/13713
[ticket/13713] User Mentions
This commit is contained in:
commit
f3c426389c
61 changed files with 3449 additions and 35 deletions
38
package.json
38
package.json
|
@ -56,6 +56,44 @@
|
|||
"jquery"
|
||||
]
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "xo",
|
||||
"rules": {
|
||||
"quotes": [
|
||||
"error",
|
||||
"single"
|
||||
],
|
||||
"comma-dangle": [
|
||||
"error",
|
||||
"always-multiline"
|
||||
],
|
||||
"block-spacing": "error",
|
||||
"array-bracket-spacing": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"multiline-comment-style": "off",
|
||||
"computed-property-spacing": "off",
|
||||
"space-in-parens": "off",
|
||||
"capitalized-comments": "off",
|
||||
"object-curly-spacing": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"no-lonely-if": "off",
|
||||
"unicorn/prefer-module": "off",
|
||||
"space-before-function-paren": [
|
||||
"error",
|
||||
"never"
|
||||
]
|
||||
},
|
||||
"env": {
|
||||
"es6": true,
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"jquery": true
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"not ie 11",
|
||||
|
|
|
@ -8,10 +8,14 @@
|
|||
// ]]>
|
||||
</script>
|
||||
|
||||
{% include 'mentions_templates.html' %}
|
||||
|
||||
<!-- INCLUDEJS {T_ASSETS_PATH}/javascript/editor.js -->
|
||||
<!-- INCLUDEJS {T_ASSETS_PATH}/javascript/tribute.min.js -->
|
||||
<!-- INCLUDEJS {T_ASSETS_PATH}/javascript/mentions.js -->
|
||||
|
||||
<!-- EVENT acp_posting_buttons_before -->
|
||||
<div id="format-buttons">
|
||||
<div id="format-buttons"<!-- IF S_ALLOW_MENTIONS --> data-mention-url="{U_MENTION_URL}" data-mention-names-limit="{S_MENTION_NAMES_LIMIT}" data-topic-id="{S_TOPIC_ID}" data-user-id="{S_USER_ID}"<!-- ENDIF -->>
|
||||
<input type="button" class="button2" accesskey="b" name="addbbcode0" value=" B " style="font-weight:bold; width: 30px" onclick="bbstyle(0)" title="{L_BBCODE_B_HELP}" />
|
||||
<input type="button" class="button2" accesskey="i" name="addbbcode2" value=" i " style="font-style:italic; width: 30px" onclick="bbstyle(2)" title="{L_BBCODE_I_HELP}" />
|
||||
<input type="button" class="button2" accesskey="u" name="addbbcode4" value=" u " style="text-decoration: underline; width: 30px" onclick="bbstyle(4)" title="{L_BBCODE_U_HELP}" />
|
||||
|
|
|
@ -1670,6 +1670,103 @@ fieldset.submit-buttons legend {
|
|||
}
|
||||
}
|
||||
|
||||
/* Mentions and mention dropdown
|
||||
---------------------------------------- */
|
||||
.mention {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.mention-container {
|
||||
text-align: left;
|
||||
background-color: #ffffff;
|
||||
border-radius: 2px;
|
||||
box-shadow:
|
||||
0 3px 1px -2px rgba(0, 0, 0, 0.2),
|
||||
0 2px 2px 0 rgba(0, 0, 0, 0.14),
|
||||
0 1px 5px 0 rgba(0, 0, 0, 0.12);
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
overflow: auto; /* placed here for list to scroll with arrow key press */
|
||||
max-height: 200px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.rtl .mention-container {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.mention-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.mention-media {
|
||||
color: #757575;
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 8px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.rtl .mention-media {
|
||||
margin-right: 0;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.mention-media-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.mention-item {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
letter-spacing: 0.04em;
|
||||
border-bottom: 1px solid #dddddd;
|
||||
color: #212121;
|
||||
position: relative;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mention-item:hover,
|
||||
.mention-item.is-active {
|
||||
text-decoration: none;
|
||||
background-color: #eeeeee;
|
||||
color: #2d80d2;
|
||||
}
|
||||
|
||||
.mention-item:hover .mention-media-avatar,
|
||||
.mention-item.is-active .mention-media-avatar {
|
||||
color: #2d80d2;
|
||||
}
|
||||
|
||||
.mention-name,
|
||||
.mention-rank {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mention-name {
|
||||
line-height: 1.25;
|
||||
margin-right: 20px; /* needed to account for scrollbar bug on Firefox for Windows */
|
||||
}
|
||||
|
||||
.mention-rank {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1.2871;
|
||||
letter-spacing: 0.04em;
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
/* Input field styles
|
||||
---------------------------------------- */
|
||||
input.radio,
|
||||
|
|
|
@ -1745,6 +1745,31 @@ phpbb.lazyLoadAvatars = function loadAvatars() {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get editor text area element
|
||||
*
|
||||
* @param {string} formName Name of form
|
||||
* @param {string} textareaName Textarea name
|
||||
*
|
||||
* @return {HTMLElement|null} Text area element or null if textarea couldn't be found
|
||||
*/
|
||||
phpbb.getEditorTextArea = function(formName, textareaName) {
|
||||
let doc;
|
||||
|
||||
// find textarea, make sure browser supports necessary functions
|
||||
if (document.forms[formName]) {
|
||||
doc = document;
|
||||
} else {
|
||||
doc = opener.document;
|
||||
}
|
||||
|
||||
if (!doc.forms[formName]) {
|
||||
return;
|
||||
}
|
||||
|
||||
return doc.forms[formName].elements[textareaName];
|
||||
}
|
||||
|
||||
phpbb.recaptcha = {
|
||||
button: null,
|
||||
ready: false,
|
||||
|
|
|
@ -384,28 +384,22 @@ function getCaretPosition(txtarea) {
|
|||
return caretPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow to use tab character when typing code
|
||||
* Keep indentation of last line of code when typing code
|
||||
*/
|
||||
(function($) {
|
||||
$(document).ready(function() {
|
||||
var doc, textarea;
|
||||
'use strict';
|
||||
|
||||
// find textarea, make sure browser supports necessary functions
|
||||
if (document.forms[form_name]) {
|
||||
doc = document;
|
||||
} else {
|
||||
doc = opener.document;
|
||||
}
|
||||
$(document).ready(() => {
|
||||
const textarea = phpbb.getEditorTextArea(form_name, text_name);
|
||||
|
||||
if (!doc.forms[form_name]) {
|
||||
if (typeof textarea === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
textarea = doc.forms[form_name].elements[text_name];
|
||||
|
||||
/**
|
||||
* Allow to use tab character when typing code
|
||||
* Keep indentation of last line of code when typing code
|
||||
*/
|
||||
phpbb.applyCodeEditor(textarea);
|
||||
|
||||
if ($('#attach-panel').length) {
|
||||
phpbb.showDragNDrop(textarea);
|
||||
}
|
||||
|
@ -417,4 +411,3 @@ function getCaretPosition(txtarea) {
|
|||
});
|
||||
});
|
||||
})(jQuery);
|
||||
|
||||
|
|
327
phpBB/assets/javascript/mentions.js
Normal file
327
phpBB/assets/javascript/mentions.js
Normal file
|
@ -0,0 +1,327 @@
|
|||
/* global phpbb */
|
||||
/* import Tribute from './tribute.min'; */
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Mentions data returned from ajax requests
|
||||
* @typedef {Object} MentionsData
|
||||
* @property {string} name User/group name
|
||||
* @property {string} id User/group ID
|
||||
* @property {{img: string, group: string}} avatar Avatar data
|
||||
* @property {string} rank User rank or empty string for groups
|
||||
* @property {number} priority Priority of data entry
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mentions class
|
||||
* @constructor
|
||||
*/
|
||||
function Mentions() {
|
||||
const $mentionDataContainer = $('[data-mention-url]:first');
|
||||
const mentionURL = $mentionDataContainer.data('mentionUrl');
|
||||
const mentionNamesLimit = $mentionDataContainer.data('mentionNamesLimit');
|
||||
const mentionTopicId = $mentionDataContainer.data('topicId');
|
||||
const mentionUserId = $mentionDataContainer.data('userId');
|
||||
let queryInProgress = null;
|
||||
const cachedNames = [];
|
||||
const cachedAll = [];
|
||||
const cachedSearchKey = 'name';
|
||||
let tribute = null;
|
||||
|
||||
/**
|
||||
* Get default avatar
|
||||
* @param {string} type Type of avatar; either 'g' for group or user on any other value
|
||||
* @returns {string} Default avatar svg code
|
||||
*/
|
||||
function defaultAvatar(type) {
|
||||
if (type === 'g') {
|
||||
return $('[data-id="mention-default-avatar-group"]').html();
|
||||
}
|
||||
|
||||
return $('[data-id="mention-default-avatar"]').html();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get avatar HTML for data and type of avatar
|
||||
*
|
||||
* @param {object} data
|
||||
* @param {string} type
|
||||
* @return {string} Avatar HTML
|
||||
*/
|
||||
function getAvatar(data, type) {
|
||||
if (data.html === '' && data.src === '') {
|
||||
return defaultAvatar(type);
|
||||
}
|
||||
|
||||
if (data.html === '') {
|
||||
const $avatarImg = $($('[data-id="mention-media-avatar-img"]').html());
|
||||
$avatarImg.attr({
|
||||
src: data.src,
|
||||
width: data.width,
|
||||
height: data.height,
|
||||
alt: data.title,
|
||||
});
|
||||
return $avatarImg.get(0).outerHTML;
|
||||
}
|
||||
|
||||
const $avatarImg = $(data.html);
|
||||
$avatarImg.addClass('mention-media-avatar');
|
||||
return $avatarImg.get(0).outerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached keyword for query string
|
||||
* @param {string} query Query string
|
||||
* @returns {?string} Cached keyword if one fits query, else empty string if cached keywords exist, null if cached keywords do not exist
|
||||
*/
|
||||
function getCachedKeyword(query) {
|
||||
if (!cachedNames) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let i;
|
||||
|
||||
for (i = query.length; i > 0; i--) {
|
||||
const startString = query.slice(0, i);
|
||||
if (cachedNames[startString]) {
|
||||
return startString;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get names matching query
|
||||
* @param {string} query Query string
|
||||
* @param {Object.<number, MentionsData>} items List of {@link MentionsData} items
|
||||
* @param {string} searchKey Key to use for matching items
|
||||
* @returns {Object.<number, MentionsData>} List of {@link MentionsData} items filtered with query and by searchKey
|
||||
*/
|
||||
function getMatchedNames(query, items, searchKey) {
|
||||
let i;
|
||||
let itemsLength;
|
||||
const matchedNames = [];
|
||||
for (i = 0, itemsLength = items.length; i < itemsLength; i++) {
|
||||
const item = items[i];
|
||||
if (isItemMatched(query, item, searchKey)) {
|
||||
matchedNames.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return matchedNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether item is matched by query
|
||||
*
|
||||
* @param {string} query Search query string
|
||||
* @param {MentionsData} item Mentions data item
|
||||
* @param {string }searchKey Key to use for matching items
|
||||
* @return {boolean} True if items is matched, false otherwise
|
||||
*/
|
||||
function isItemMatched(query, item, searchKey) {
|
||||
return String(item[searchKey]).toLowerCase().indexOf(query.toLowerCase()) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter items by search query
|
||||
*
|
||||
* @param {string} query Search query string
|
||||
* @param {Object.<number, MentionsData>} items List of {@link MentionsData} items
|
||||
* @return {Object.<number, MentionsData>} List of {@link MentionsData} items filtered with query and by searchKey
|
||||
*/
|
||||
function itemFilter(query, items) {
|
||||
let i;
|
||||
let itemsLength;
|
||||
const highestPriorities = { u: 1, g: 1 };
|
||||
const _unsorted = { u: {}, g: {} };
|
||||
const _exactMatch = [];
|
||||
let _results = [];
|
||||
|
||||
// Reduce the items array to the relevant ones
|
||||
items = getMatchedNames(query, items, 'name');
|
||||
|
||||
// Group names by their types and calculate priorities
|
||||
for (i = 0, itemsLength = items.length; i < itemsLength; i++) {
|
||||
const item = items[i];
|
||||
|
||||
// Check for unsupported type - in general, this should never happen
|
||||
if (!_unsorted[item.type]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Current user doesn't want to mention themselves with "@" in most cases -
|
||||
// do not waste list space with their own name
|
||||
if (item.type === 'u' && item.id === String(mentionUserId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exact matches should not be prioritised - they always come first
|
||||
if (item.name === query) {
|
||||
_exactMatch.push(items[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the item hasn't been added yet - add it
|
||||
if (!_unsorted[item.type][item.id]) {
|
||||
_unsorted[item.type][item.id] = item;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Priority is calculated as the sum of priorities from different sources
|
||||
_unsorted[item.type][item.id].priority += Number.parseFloat(item.priority.toString());
|
||||
|
||||
// Calculate the highest priority - we'll give it to group names
|
||||
highestPriorities[item.type] = Math.max(highestPriorities[item.type], _unsorted[item.type][item.id].priority);
|
||||
}
|
||||
|
||||
// All types of names should come at the same level of importance,
|
||||
// otherwise they will be unlikely to be shown
|
||||
// That's why we normalize priorities and push names to a single results array
|
||||
$.each([ 'u', 'g' ], (key, type) => {
|
||||
if (_unsorted[type]) {
|
||||
$.each(_unsorted[type], (name, value) => {
|
||||
// Normalize priority
|
||||
value.priority /= highestPriorities[type];
|
||||
|
||||
// Add item to all results
|
||||
_results.push(value);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Sort names by priorities - higher values come first
|
||||
_results = _results.sort((a, b) => {
|
||||
return b.priority - a.priority;
|
||||
});
|
||||
|
||||
// Exact match is the most important - should come above anything else
|
||||
$.each(_exactMatch, (name, value) => {
|
||||
_results.unshift(value);
|
||||
});
|
||||
|
||||
return _results;
|
||||
}
|
||||
|
||||
/**
|
||||
* remoteFilter callback filter function
|
||||
* @param {string} query Query string
|
||||
* @param {function} callback Callback function for filtered items
|
||||
*/
|
||||
function remoteFilter(query, callback) {
|
||||
/*
|
||||
* Do not make a new request until the previous one for the same query is returned
|
||||
* This fixes duplicate server queries e.g. when arrow keys are pressed
|
||||
*/
|
||||
if (queryInProgress === query) {
|
||||
setTimeout(() => {
|
||||
remoteFilter(query, callback);
|
||||
}, 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
const cachedKeyword = getCachedKeyword(query);
|
||||
const cachedNamesForQuery = cachedKeyword === null ? null : cachedNames[cachedKeyword];
|
||||
|
||||
/*
|
||||
* Use cached values when we can:
|
||||
* 1) There are some names in the cache relevant for the query
|
||||
* (cache for the query with the same first characters contains some data)
|
||||
* 2) We have enough names to display OR
|
||||
* all relevant names have been fetched from the server
|
||||
*/
|
||||
if (cachedNamesForQuery &&
|
||||
(getMatchedNames(query, cachedNamesForQuery, cachedSearchKey).length >= mentionNamesLimit ||
|
||||
cachedAll[cachedKeyword])) {
|
||||
callback(cachedNamesForQuery);
|
||||
return;
|
||||
}
|
||||
|
||||
queryInProgress = query;
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
const parameters = { keyword: query, topic_id: mentionTopicId, _referer: location.href };
|
||||
$.getJSON(mentionURL, parameters, data => {
|
||||
cachedNames[query] = data.names;
|
||||
cachedAll[query] = data.all;
|
||||
callback(data.names);
|
||||
}).always(() => {
|
||||
queryInProgress = null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate menu item HTML representation. Also ensures that mention-list
|
||||
* class is set for unordered list in mention container
|
||||
*
|
||||
* @param {object} data Item data
|
||||
* @returns {string} HTML representation of menu item
|
||||
*/
|
||||
function menuItemTemplate(data) {
|
||||
const itemData = data;
|
||||
const avatar = getAvatar(itemData.avatar, itemData.type);
|
||||
const rank = (itemData.rank) ? $($('[data-id="mention-rank-span"]').html()).text(itemData.rank).get(0).outerHTML : '';
|
||||
const $mentionContainer = $('.' + tribute.current.collection.containerClass);
|
||||
|
||||
if (typeof $mentionContainer !== 'undefined' && $mentionContainer.children('ul').hasClass('mention-list') === false) {
|
||||
$mentionContainer.children('ul').addClass('mention-list');
|
||||
}
|
||||
|
||||
const $avatarSpan = $($('[data-id="mention-media-span"]').html());
|
||||
$avatarSpan.html(avatar);
|
||||
|
||||
const $nameSpan = $($('[data-id="mention-name-span"]').html());
|
||||
$nameSpan.html(itemData.name + rank);
|
||||
|
||||
return $avatarSpan.get(0).outerHTML + $nameSpan.get(0).outerHTML;
|
||||
}
|
||||
|
||||
this.isEnabled = function() {
|
||||
return $mentionDataContainer.length;
|
||||
};
|
||||
|
||||
/* global Tribute */
|
||||
this.handle = function(textarea) {
|
||||
tribute = new Tribute({
|
||||
trigger: '@',
|
||||
allowSpaces: true,
|
||||
containerClass: 'mention-container',
|
||||
selectClass: 'is-active',
|
||||
itemClass: 'mention-item',
|
||||
menuItemTemplate,
|
||||
selectTemplate(item) {
|
||||
return '[mention=' + item.type + ':' + item.id + ']' + item.name + '[/mention]';
|
||||
},
|
||||
menuItemLimit: mentionNamesLimit,
|
||||
values(text, cb) {
|
||||
remoteFilter(text, users => cb(users));
|
||||
},
|
||||
lookup(element) {
|
||||
return Object.prototype.hasOwnProperty.call(element, 'name') ? element.name : '';
|
||||
},
|
||||
});
|
||||
|
||||
tribute.search.filter = itemFilter;
|
||||
|
||||
tribute.attach($(textarea));
|
||||
};
|
||||
}
|
||||
|
||||
phpbb.mentions = new Mentions();
|
||||
|
||||
$(document).ready(() => {
|
||||
/* global form_name, text_name */
|
||||
const textarea = phpbb.getEditorTextArea(form_name, text_name);
|
||||
|
||||
if (typeof textarea === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (phpbb.mentions.isEnabled()) {
|
||||
phpbb.mentions.handle(textarea);
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
2
phpBB/assets/javascript/tribute.min.js
vendored
Normal file
2
phpBB/assets/javascript/tribute.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -15,6 +15,7 @@ imports:
|
|||
- { resource: services_help.yml }
|
||||
- { resource: services_http.yml }
|
||||
- { resource: services_language.yml }
|
||||
- { resource: services_mention.yml }
|
||||
- { resource: services_migrator.yml }
|
||||
- { resource: services_mimetype_guesser.yml }
|
||||
- { resource: services_module.yml }
|
||||
|
|
75
phpBB/config/default/container/services_mention.yml
Normal file
75
phpBB/config/default/container/services_mention.yml
Normal file
|
@ -0,0 +1,75 @@
|
|||
services:
|
||||
# ----- Controller -----
|
||||
mention.controller:
|
||||
class: phpbb\mention\controller\mention
|
||||
arguments:
|
||||
- '@mention.source_collection'
|
||||
- '@request'
|
||||
- '%core.root_path%'
|
||||
- '%core.php_ext%'
|
||||
|
||||
# ----- Sources for mention -----
|
||||
mention.source_collection:
|
||||
class: phpbb\di\service_collection
|
||||
arguments:
|
||||
- '@service_container'
|
||||
tags:
|
||||
- { name: service_collection, tag: mention.source }
|
||||
|
||||
mention.source.base_group:
|
||||
abstract: true
|
||||
arguments:
|
||||
- '@dbal.conn'
|
||||
- '@config'
|
||||
- '@group_helper'
|
||||
- '@user'
|
||||
- '@auth'
|
||||
- '%core.root_path%'
|
||||
- '%core.php_ext%'
|
||||
|
||||
mention.source.base_user:
|
||||
abstract: true
|
||||
arguments:
|
||||
- '@dbal.conn'
|
||||
- '@config'
|
||||
- '@user_loader'
|
||||
- '%core.root_path%'
|
||||
- '%core.php_ext%'
|
||||
|
||||
mention.source.friend:
|
||||
class: phpbb\mention\source\friend
|
||||
parent: mention.source.base_user
|
||||
calls:
|
||||
- [set_user, ['@user']]
|
||||
tags:
|
||||
- { name: mention.source }
|
||||
|
||||
mention.source.group:
|
||||
class: phpbb\mention\source\group
|
||||
parent: mention.source.base_group
|
||||
tags:
|
||||
- { name: mention.source }
|
||||
|
||||
mention.source.team:
|
||||
class: phpbb\mention\source\team
|
||||
parent: mention.source.base_user
|
||||
tags:
|
||||
- { name: mention.source }
|
||||
|
||||
mention.source.topic:
|
||||
class: phpbb\mention\source\topic
|
||||
parent: mention.source.base_user
|
||||
tags:
|
||||
- { name: mention.source }
|
||||
|
||||
mention.source.user:
|
||||
class: phpbb\mention\source\user
|
||||
parent: mention.source.base_user
|
||||
tags:
|
||||
- { name: mention.source }
|
||||
|
||||
mention.source.usergroup:
|
||||
class: phpbb\mention\source\usergroup
|
||||
parent: mention.source.base_group
|
||||
tags:
|
||||
- { name: mention.source }
|
|
@ -95,6 +95,15 @@ services:
|
|||
tags:
|
||||
- { name: notification.type }
|
||||
|
||||
notification.type.mention:
|
||||
class: phpbb\notification\type\mention
|
||||
shared: false
|
||||
parent: notification.type.post
|
||||
calls:
|
||||
- [set_helper, ['@text_formatter.s9e.mention_helper']]
|
||||
tags:
|
||||
- { name: notification.type }
|
||||
|
||||
notification.type.pm:
|
||||
class: phpbb\notification\type\pm
|
||||
shared: false
|
||||
|
|
|
@ -52,6 +52,15 @@ services:
|
|||
text_formatter.s9e.link_helper:
|
||||
class: phpbb\textformatter\s9e\link_helper
|
||||
|
||||
text_formatter.s9e.mention_helper:
|
||||
class: phpbb\textformatter\s9e\mention_helper
|
||||
arguments:
|
||||
- '@dbal.conn'
|
||||
- '@auth'
|
||||
- '@user'
|
||||
- '%core.root_path%'
|
||||
- '%core.php_ext%'
|
||||
|
||||
text_formatter.s9e.parser:
|
||||
class: phpbb\textformatter\s9e\parser
|
||||
arguments:
|
||||
|
@ -76,6 +85,7 @@ services:
|
|||
- '@text_formatter.s9e.factory'
|
||||
- '@dispatcher'
|
||||
calls:
|
||||
- [configure_mention_helper, ['@text_formatter.s9e.mention_helper']]
|
||||
- [configure_quote_helper, ['@text_formatter.s9e.quote_helper']]
|
||||
- [configure_smilies_path, ['@config', '@path_helper']]
|
||||
- [configure_user, ['@user', '@config', '@auth']]
|
||||
|
|
|
@ -24,6 +24,11 @@ phpbb_help_routing:
|
|||
resource: help.yml
|
||||
prefix: /help
|
||||
|
||||
phpbb_mention_controller:
|
||||
path: /mention
|
||||
methods: [GET, POST]
|
||||
defaults: { _controller: mention.controller:handle }
|
||||
|
||||
phpbb_report_routing:
|
||||
resource: report.yml
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ class acp_bbcodes
|
|||
$data = $this->build_regexp($bbcode_match, $bbcode_tpl);
|
||||
|
||||
// Make sure the user didn't pick a "bad" name for the BBCode tag.
|
||||
$hard_coded = array('code', 'quote', 'quote=', 'attachment', 'attachment=', 'b', 'i', 'url', 'url=', 'img', 'size', 'size=', 'color', 'color=', 'u', 'list', 'list=', 'email', 'email=', 'flash', 'flash=');
|
||||
$hard_coded = array('code', 'quote', 'quote=', 'attachment', 'attachment=', 'b', 'i', 'url', 'url=', 'img', 'size', 'size=', 'color', 'color=', 'u', 'list', 'list=', 'email', 'email=', 'flash', 'flash=', 'mention');
|
||||
|
||||
if (($action == 'modify' && strtolower($data['bbcode_tag']) !== strtolower($row['bbcode_tag'])) || ($action == 'create'))
|
||||
{
|
||||
|
|
|
@ -220,7 +220,12 @@ class acp_board
|
|||
'max_post_img_width' => array('lang' => 'MAX_POST_IMG_WIDTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
|
||||
'max_post_img_height' => array('lang' => 'MAX_POST_IMG_HEIGHT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
|
||||
|
||||
'legend3' => 'ACP_SUBMIT_CHANGES',
|
||||
'legend3' => 'MENTIONS',
|
||||
'allow_mentions' => array('lang' => 'ALLOW_MENTIONS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
|
||||
'mention_names_limit' => array('lang' => 'MENTION_NAMES_LIMIT', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false),
|
||||
'mention_batch_size' => array('lang' => 'MENTION_BATCH_SIZE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => true),
|
||||
|
||||
'legend4' => 'ACP_SUBMIT_CHANGES',
|
||||
)
|
||||
);
|
||||
break;
|
||||
|
|
|
@ -575,6 +575,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
|
|||
// Mark all topic notifications read for this user
|
||||
$phpbb_notifications->mark_notifications(array(
|
||||
'notification.type.topic',
|
||||
'notification.type.mention',
|
||||
'notification.type.quote',
|
||||
'notification.type.bookmark',
|
||||
'notification.type.post',
|
||||
|
@ -660,6 +661,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
|
|||
$db->sql_freeresult($result);
|
||||
|
||||
$phpbb_notifications->mark_notifications_by_parent(array(
|
||||
'notification.type.mention',
|
||||
'notification.type.quote',
|
||||
'notification.type.bookmark',
|
||||
'notification.type.post',
|
||||
|
@ -771,6 +773,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
|
|||
), $topic_id, $user->data['user_id'], $post_time);
|
||||
|
||||
$phpbb_notifications->mark_notifications_by_parent(array(
|
||||
'notification.type.mention',
|
||||
'notification.type.quote',
|
||||
'notification.type.bookmark',
|
||||
'notification.type.post',
|
||||
|
@ -3943,6 +3946,10 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
|
|||
'U_RESTORE_PERMISSIONS' => ($user->data['user_perm_from'] && $auth->acl_get('a_switchperm')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm') : '',
|
||||
'U_FEED' => $controller_helper->route('phpbb_feed_index'),
|
||||
|
||||
'S_ALLOW_MENTIONS' => ($config['allow_mentions'] && $auth->acl_get('u_mention') && (empty($forum_id) || $auth->acl_get('f_mention', $forum_id))) ? true : false,
|
||||
'S_MENTION_NAMES_LIMIT' => $config['mention_names_limit'],
|
||||
'U_MENTION_URL' => $controller_helper->route('phpbb_mention_controller'),
|
||||
|
||||
'S_USER_LOGGED_IN' => ($user->data['user_id'] != ANONYMOUS) ? true : false,
|
||||
'S_AUTOLOGIN_ENABLED' => ($config['allow_autologin']) ? true : false,
|
||||
'S_BOARD_DISABLED' => ($config['board_disable']) ? true : false,
|
||||
|
@ -3964,6 +3971,7 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
|
|||
'S_REGISTER_ENABLED' => ($config['require_activation'] != USER_ACTIVATION_DISABLE) ? true : false,
|
||||
'S_FORUM_ID' => $forum_id,
|
||||
'S_TOPIC_ID' => $topic_id,
|
||||
'S_USER_ID' => $user->data['user_id'],
|
||||
|
||||
'S_LOGIN_ACTION' => ((!defined('ADMIN_START')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login') : append_sid("{$phpbb_admin_path}index.$phpEx", false, true, $user->session_id)),
|
||||
'S_LOGIN_REDIRECT' => $s_login_redirect,
|
||||
|
|
|
@ -24,7 +24,7 @@ if (!defined('IN_PHPBB'))
|
|||
*/
|
||||
function adm_page_header($page_title)
|
||||
{
|
||||
global $config, $user, $template;
|
||||
global $config, $user, $template, $auth;
|
||||
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $SID, $_SID;
|
||||
global $phpbb_dispatcher, $phpbb_container;
|
||||
|
||||
|
@ -66,6 +66,9 @@ function adm_page_header($page_title)
|
|||
}
|
||||
}
|
||||
|
||||
/** @var \phpbb\controller\helper $controller_helper */
|
||||
$controller_helper = $phpbb_container->get('controller.helper');
|
||||
|
||||
$phpbb_version_parts = explode('.', PHPBB_VERSION, 3);
|
||||
$phpbb_major = $phpbb_version_parts[0] . '.' . $phpbb_version_parts[1];
|
||||
|
||||
|
@ -86,6 +89,10 @@ function adm_page_header($page_title)
|
|||
'U_ADM_INDEX' => append_sid("{$phpbb_admin_path}index.$phpEx"),
|
||||
'U_INDEX' => append_sid("{$phpbb_root_path}index.$phpEx"),
|
||||
|
||||
'S_ALLOW_MENTIONS' => ($config['allow_mentions'] && $auth->acl_get('u_mention')) ? true : false,
|
||||
'S_MENTION_NAMES_LIMIT' => $config['mention_names_limit'],
|
||||
'U_MENTION_URL' => $controller_helper->route('phpbb_mention_controller'),
|
||||
|
||||
'T_IMAGES_PATH' => "{$phpbb_root_path}images/",
|
||||
'T_SMILIES_PATH' => "{$phpbb_root_path}{$config['smilies_path']}/",
|
||||
'T_AVATAR_GALLERY_PATH' => "{$phpbb_root_path}{$config['avatar_gallery_path']}/",
|
||||
|
@ -108,6 +115,7 @@ function adm_page_header($page_title)
|
|||
'ICON_SYNC' => '<i class="icon acp-icon acp-icon-resync fa-refresh fa-fw" title="' . $user->lang('RESYNC') . '"></i>',
|
||||
'ICON_SYNC_DISABLED' => '<i class="icon acp-icon acp-icon-disabled fa-refresh fa-fw" title="' . $user->lang('RESYNC') . '"></i>',
|
||||
|
||||
'S_USER_ID' => $user->data['user_id'],
|
||||
'S_USER_LANG' => $user->lang['USER_LANG'],
|
||||
'S_CONTENT_DIRECTION' => $user->lang['DIRECTION'],
|
||||
'S_CONTENT_ENCODING' => 'UTF-8',
|
||||
|
|
|
@ -908,6 +908,7 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
|
|||
|
||||
// Notifications types to delete
|
||||
$delete_notifications_types = array(
|
||||
'notification.type.mention',
|
||||
'notification.type.quote',
|
||||
'notification.type.approve_post',
|
||||
'notification.type.post_in_queue',
|
||||
|
|
|
@ -2443,6 +2443,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll_ary, &$data
|
|||
{
|
||||
case 'post':
|
||||
$phpbb_notifications->add_notifications(array(
|
||||
'notification.type.mention',
|
||||
'notification.type.quote',
|
||||
'notification.type.topic',
|
||||
), $notification_data);
|
||||
|
@ -2451,6 +2452,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll_ary, &$data
|
|||
case 'reply':
|
||||
case 'quote':
|
||||
$phpbb_notifications->add_notifications(array(
|
||||
'notification.type.mention',
|
||||
'notification.type.quote',
|
||||
'notification.type.bookmark',
|
||||
'notification.type.post',
|
||||
|
@ -2465,6 +2467,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll_ary, &$data
|
|||
if ($user->data['user_id'] == $poster_id)
|
||||
{
|
||||
$phpbb_notifications->update_notifications(array(
|
||||
'notification.type.mention',
|
||||
'notification.type.quote',
|
||||
), $notification_data);
|
||||
}
|
||||
|
|
|
@ -810,10 +810,14 @@ class mcp_queue
|
|||
), $post_data);
|
||||
}
|
||||
}
|
||||
$phpbb_notifications->add_notifications(array('notification.type.quote'), $post_data);
|
||||
$phpbb_notifications->add_notifications(array(
|
||||
'notification.type.mention',
|
||||
'notification.type.quote',
|
||||
), $post_data);
|
||||
$phpbb_notifications->delete_notifications('notification.type.post_in_queue', $post_id);
|
||||
|
||||
$phpbb_notifications->mark_notifications(array(
|
||||
'notification.type.mention',
|
||||
'notification.type.quote',
|
||||
'notification.type.bookmark',
|
||||
'notification.type.post',
|
||||
|
@ -1045,12 +1049,13 @@ class mcp_queue
|
|||
if ($topic_data['topic_visibility'] == ITEM_UNAPPROVED)
|
||||
{
|
||||
$phpbb_notifications->add_notifications(array(
|
||||
'notification.type.mention',
|
||||
'notification.type.quote',
|
||||
'notification.type.topic',
|
||||
), $topic_data);
|
||||
}
|
||||
|
||||
$phpbb_notifications->mark_notifications('quote', $topic_data['post_id'], $user->data['user_id']);
|
||||
$phpbb_notifications->mark_notifications(array('mention', 'quote'), $topic_data['post_id'], $user->data['user_id']);
|
||||
$phpbb_notifications->mark_notifications('topic', $topic_id, $user->data['user_id']);
|
||||
|
||||
if ($notify_poster)
|
||||
|
|
|
@ -21,6 +21,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_emailreuse',
|
|||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_forum_notify', '1');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_live_searches', '1');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_mass_pm', '1');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_mentions', '1');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_name_chars', 'USERNAME_CHARS_ANY');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_namechange', '0');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_nocensors', '0');
|
||||
|
@ -234,6 +235,8 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_sig_img_height
|
|||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_sig_img_width', '0');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_sig_smilies', '0');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_sig_urls', '5');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('mention_batch_size', '50');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('mention_names_limit', '10');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('mime_triggers', 'body|head|html|img|plaintext|a href|pre|script|table|title');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('min_name_chars', '3');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('min_pass_chars', '6');
|
||||
|
@ -380,6 +383,7 @@ INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_ignoreflood', 1
|
|||
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_img', 1);
|
||||
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_list', 1);
|
||||
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_list_topics', 1);
|
||||
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_mention', 1);
|
||||
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_noapprove', 1);
|
||||
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_poll', 1);
|
||||
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_post', 1);
|
||||
|
@ -478,6 +482,7 @@ INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_hideonline', 1
|
|||
INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_ignoreflood', 1);
|
||||
INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_masspm', 1);
|
||||
INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_masspm_group', 1);
|
||||
INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_mention', 1);
|
||||
INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_pm_attach', 1);
|
||||
INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_pm_bbcode', 1);
|
||||
INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_pm_delete', 1);
|
||||
|
@ -590,7 +595,7 @@ INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT
|
|||
INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 7, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'u_%' AND auth_option NOT IN ('u_attach', 'u_viewonline', 'u_chggrp', 'u_chgname', 'u_ignoreflood', 'u_pm_attach', 'u_pm_emailpm', 'u_pm_flash', 'u_savedrafts', 'u_search', 'u_sendemail', 'u_sendim', 'u_masspm', 'u_masspm_group');
|
||||
|
||||
# No Private Messages (u_)
|
||||
INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 8, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'u_%' AND auth_option IN ('u_', 'u_chgavatar', 'u_chgcensors', 'u_chgemail', 'u_chgpasswd', 'u_download', 'u_hideonline', 'u_sig', 'u_viewprofile');
|
||||
INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 8, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'u_%' AND auth_option IN ('u_', 'u_chgavatar', 'u_chgcensors', 'u_chgemail', 'u_chgpasswd', 'u_download', 'u_hideonline', 'u_mention', 'u_sig', 'u_viewprofile');
|
||||
INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 8, auth_option_id, 0 FROM phpbb_acl_options WHERE auth_option LIKE 'u_%' AND auth_option IN ('u_readpm', 'u_sendpm', 'u_masspm', 'u_masspm_group');
|
||||
|
||||
# No Avatar (u_)
|
||||
|
|
|
@ -157,6 +157,7 @@ $lang = array_merge($lang, array(
|
|||
// Post Settings
|
||||
$lang = array_merge($lang, array(
|
||||
'ACP_POST_SETTINGS_EXPLAIN' => 'Here you can set all default settings for posting.',
|
||||
'ALLOW_MENTIONS' => 'Allow mentions of users and groups boardwide',
|
||||
'ALLOW_POST_LINKS' => 'Allow links in posts/private messages',
|
||||
'ALLOW_POST_LINKS_EXPLAIN' => 'If disallowed the <code>[URL]</code> BBCode tag and automatic/magic URLs are disabled.',
|
||||
'ALLOWED_SCHEMES_LINKS' => 'Allowed schemes in links',
|
||||
|
@ -187,6 +188,10 @@ $lang = array_merge($lang, array(
|
|||
'MAX_POST_IMG_WIDTH_EXPLAIN' => 'Maximum width of a flash file in postings. Set to 0 for unlimited size.',
|
||||
'MAX_POST_URLS' => 'Maximum links per post',
|
||||
'MAX_POST_URLS_EXPLAIN' => 'Maximum number of URLs in a post. Set to 0 for unlimited links.',
|
||||
'MENTIONS' => 'Mentions',
|
||||
'MENTION_BATCH_SIZE' => 'Maximum number of names fetched from each source of names for a single request',
|
||||
'MENTION_BATCH_SIZE_EXPLAIN' => 'Examples of sources: friends, topic repliers, group members etc.',
|
||||
'MENTION_NAMES_LIMIT' => 'Maximum number of names in dropdown list',
|
||||
'MIN_CHAR_LIMIT' => 'Minimum characters per post/message',
|
||||
'MIN_CHAR_LIMIT_EXPLAIN' => 'The minimum number of characters the user need to enter within a post/private message. The minimum for this setting is 1.',
|
||||
'POSTING' => 'Posting',
|
||||
|
|
|
@ -76,6 +76,7 @@ $lang = array_merge($lang, array(
|
|||
|
||||
'ACL_U_ATTACH' => 'Can attach files',
|
||||
'ACL_U_DOWNLOAD' => 'Can download files',
|
||||
'ACL_U_MENTION' => 'Can mention users and groups',
|
||||
'ACL_U_SAVEDRAFTS' => 'Can save drafts',
|
||||
'ACL_U_CHGCENSORS' => 'Can disable word censors',
|
||||
'ACL_U_SIG' => 'Can use signature',
|
||||
|
@ -123,6 +124,7 @@ $lang = array_merge($lang, array(
|
|||
'ACL_F_STICKY' => 'Can post stickies',
|
||||
'ACL_F_ANNOUNCE' => 'Can post announcements',
|
||||
'ACL_F_ANNOUNCE_GLOBAL' => 'Can post global announcements',
|
||||
'ACL_F_MENTION' => 'Can mention users and groups',
|
||||
'ACL_F_REPLY' => 'Can reply to topics',
|
||||
'ACL_F_EDIT' => 'Can edit own posts',
|
||||
'ACL_F_DELETE' => 'Can permanently delete own posts',
|
||||
|
|
|
@ -475,6 +475,9 @@ $lang = array_merge($lang, array(
|
|||
'NOTIFICATION_FORUM' => '<em>Forum:</em> %1$s',
|
||||
'NOTIFICATION_GROUP_REQUEST' => '<strong>Group request</strong> from %1$s to join the group %2$s.',
|
||||
'NOTIFICATION_GROUP_REQUEST_APPROVED' => '<strong>Group request approved</strong> to join the group %1$s.',
|
||||
'NOTIFICATION_MENTION' => array(
|
||||
1 => '<strong>Mentioned</strong> by %1$s in:',
|
||||
),
|
||||
'NOTIFICATION_METHOD_INVALID' => 'The method "%s" does not refer to a valid notification method.',
|
||||
'NOTIFICATION_PM' => '<strong>Private Message</strong> from %1$s:',
|
||||
'NOTIFICATION_POST' => array(
|
||||
|
|
20
phpBB/language/en/email/mention.txt
Normal file
20
phpBB/language/en/email/mention.txt
Normal file
|
@ -0,0 +1,20 @@
|
|||
Subject: Topic reply notification - "{{ TOPIC_TITLE }}"
|
||||
|
||||
Hello {{ USERNAME }},
|
||||
|
||||
You are receiving this notification because "{{ AUTHOR_NAME }}" mentioned 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 post where you have been mentioned, 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 mentioning you, please update your notification settings here:
|
||||
|
||||
{{ U_NOTIFICATION_SETTINGS }}
|
||||
|
||||
{{ EMAIL_SIG }}
|
|
@ -332,6 +332,7 @@ $lang = array_merge($lang, array(
|
|||
'NOTIFICATION_TYPE_GROUP_REQUEST' => 'Someone requests to join a group you lead',
|
||||
'NOTIFICATION_TYPE_FORUM' => 'Someone replies to a topic in a forum to which you are subscribed',
|
||||
'NOTIFICATION_TYPE_IN_MODERATION_QUEUE' => 'A post or topic needs approval',
|
||||
'NOTIFICATION_TYPE_MENTION' => 'Someone mentions you in a post',
|
||||
'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',
|
||||
|
|
43
phpBB/phpbb/db/migration/data/v330/add_mention_settings.php
Normal file
43
phpBB/phpbb/db/migration/data/v330/add_mention_settings.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\migration\data\v330;
|
||||
|
||||
class add_mention_settings extends \phpbb\db\migration\migration
|
||||
{
|
||||
public function update_data()
|
||||
{
|
||||
return array(
|
||||
array('config.add', array('allow_mentions', true)),
|
||||
array('config.add', array('mention_batch_size', 50)),
|
||||
array('config.add', array('mention_names_limit', 10)),
|
||||
|
||||
// Set up user permissions
|
||||
array('permission.add', array('u_mention', true)),
|
||||
array('permission.permission_set', array('ROLE_USER_FULL', 'u_mention')),
|
||||
array('permission.permission_set', array('ROLE_USER_STANDARD', 'u_mention')),
|
||||
array('permission.permission_set', array('ROLE_USER_LIMITED', 'u_mention')),
|
||||
array('permission.permission_set', array('ROLE_USER_NOPM', 'u_mention')),
|
||||
array('permission.permission_set', array('ROLE_USER_NOAVATAR', 'u_mention')),
|
||||
|
||||
// Set up forum permissions
|
||||
array('permission.add', array('f_mention', false)),
|
||||
array('permission.permission_set', array('ROLE_FORUM_FULL', 'f_mention')),
|
||||
array('permission.permission_set', array('ROLE_FORUM_STANDARD', 'f_mention')),
|
||||
array('permission.permission_set', array('ROLE_FORUM_LIMITED', 'f_mention')),
|
||||
array('permission.permission_set', array('ROLE_FORUM_ONQUEUE', 'f_mention')),
|
||||
array('permission.permission_set', array('ROLE_FORUM_POLLS', 'f_mention')),
|
||||
array('permission.permission_set', array('ROLE_FORUM_LIMITED_POLLS', 'f_mention')),
|
||||
);
|
||||
}
|
||||
}
|
78
phpBB/phpbb/mention/controller/mention.php
Normal file
78
phpBB/phpbb/mention/controller/mention.php
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\mention\controller;
|
||||
|
||||
use phpbb\di\service_collection;
|
||||
use phpbb\request\request_interface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
|
||||
class mention
|
||||
{
|
||||
/** @var service_collection */
|
||||
protected $mention_sources;
|
||||
|
||||
/** @var request_interface */
|
||||
protected $request;
|
||||
|
||||
/** @var string */
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/** @var string */
|
||||
protected $php_ext;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param service_collection|array $mention_sources
|
||||
* @param request_interface $request
|
||||
* @param string $phpbb_root_path
|
||||
* @param string $phpEx
|
||||
*/
|
||||
public function __construct($mention_sources, request_interface $request, string $phpbb_root_path, string $phpEx)
|
||||
{
|
||||
$this->mention_sources = $mention_sources;
|
||||
$this->request = $request;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $phpEx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle requests to mention controller
|
||||
*
|
||||
* @return JsonResponse|RedirectResponse
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if (!$this->request->is_ajax())
|
||||
{
|
||||
return new RedirectResponse(append_sid($this->phpbb_root_path . 'index.' . $this->php_ext));
|
||||
}
|
||||
|
||||
$keyword = $this->request->variable('keyword', '', true);
|
||||
$topic_id = $this->request->variable('topic_id', 0);
|
||||
$names = [];
|
||||
$has_names_remaining = false;
|
||||
|
||||
foreach ($this->mention_sources as $source)
|
||||
{
|
||||
$has_names_remaining = !$source->get($names, $keyword, $topic_id) || $has_names_remaining;
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'names' => array_values($names),
|
||||
'all' => !$has_names_remaining,
|
||||
]);
|
||||
}
|
||||
}
|
185
phpBB/phpbb/mention/source/base_group.php
Normal file
185
phpBB/phpbb/mention/source/base_group.php
Normal file
|
@ -0,0 +1,185 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\mention\source;
|
||||
|
||||
use phpbb\auth\auth;
|
||||
use phpbb\config\config;
|
||||
use phpbb\db\driver\driver_interface;
|
||||
use phpbb\group\helper;
|
||||
|
||||
abstract class base_group implements source_interface
|
||||
{
|
||||
/** @var driver_interface */
|
||||
protected $db;
|
||||
|
||||
/** @var config */
|
||||
protected $config;
|
||||
|
||||
/** @var helper */
|
||||
protected $helper;
|
||||
|
||||
/** @var \phpbb\user */
|
||||
protected $user;
|
||||
|
||||
/** @var auth */
|
||||
protected $auth;
|
||||
|
||||
/** @var string */
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/** @var string */
|
||||
protected $php_ext;
|
||||
|
||||
/** @var string|false */
|
||||
protected $cache_ttl = false;
|
||||
|
||||
/** @var array Fetched groups' data */
|
||||
protected $groups = null;
|
||||
|
||||
/**
|
||||
* base_group constructor.
|
||||
*
|
||||
* @param driver_interface $db
|
||||
* @param config $config
|
||||
* @param helper $helper
|
||||
* @param \phpbb\user $user
|
||||
* @param auth $auth
|
||||
* @param string $phpbb_root_path
|
||||
* @param string $phpEx
|
||||
*/
|
||||
public function __construct(driver_interface $db, config $config, helper $helper, \phpbb\user $user, auth $auth, string $phpbb_root_path, string $phpEx)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->config = $config;
|
||||
$this->helper = $helper;
|
||||
$this->user = $user;
|
||||
$this->auth = $auth;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $phpEx;
|
||||
|
||||
if (!function_exists('phpbb_get_user_rank'))
|
||||
{
|
||||
include($this->phpbb_root_path . 'includes/functions_display.' . $this->php_ext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns data for all board groups
|
||||
*
|
||||
* @return array Array of groups' data
|
||||
*/
|
||||
protected function get_groups(): array
|
||||
{
|
||||
if (is_null($this->groups))
|
||||
{
|
||||
$query = $this->db->sql_build_query('SELECT', [
|
||||
'SELECT' => 'g.*, ug.user_id as ug_user_id',
|
||||
'FROM' => [
|
||||
GROUPS_TABLE => 'g',
|
||||
],
|
||||
'LEFT_JOIN' => [
|
||||
[
|
||||
'FROM' => [USER_GROUP_TABLE => 'ug'],
|
||||
'ON' => 'ug.group_id = g.group_id AND ug.user_pending = 0 AND ug.user_id = ' . (int) $this->user->data['user_id'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
// Cache results for 5 minutes
|
||||
$result = $this->db->sql_query($query, 600);
|
||||
|
||||
$this->groups = [];
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
if ($row['group_type'] == GROUP_SPECIAL && !in_array($row['group_name'], ['ADMINISTRATORS', 'GLOBAL_MODERATORS']) || $row['group_type'] == GROUP_HIDDEN && !$this->auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel') && $row['ug_user_id'] != $this->user->data['user_id'])
|
||||
{
|
||||
// Skip the group that we should not be able to mention.
|
||||
continue;
|
||||
}
|
||||
|
||||
$group_name = $this->helper->get_name($row['group_name']);
|
||||
$this->groups['names'][$row['group_id']] = $group_name;
|
||||
$this->groups[$row['group_id']] = $row;
|
||||
$this->groups[$row['group_id']]['group_name'] = $group_name;
|
||||
}
|
||||
|
||||
$this->db->sql_freeresult($result);
|
||||
}
|
||||
return $this->groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a query for getting group IDs based on user input
|
||||
*
|
||||
* @param string $keyword Search string
|
||||
* @param int $topic_id Current topic ID
|
||||
* @return string Query ready for execution
|
||||
*/
|
||||
abstract protected function query(string $keyword, int $topic_id): string;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_priority(array $row): int
|
||||
{
|
||||
// By default every result from the source increases the priority by a fixed value
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(array &$names, string $keyword, int $topic_id): bool
|
||||
{
|
||||
// Grab all group IDs and cache them if needed
|
||||
$result = $this->db->sql_query($this->query($keyword, $topic_id), $this->cache_ttl);
|
||||
|
||||
$group_ids = [];
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$group_ids[] = $row['group_id'];
|
||||
}
|
||||
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
// Grab group data
|
||||
$groups = $this->get_groups();
|
||||
|
||||
$matches = preg_grep('/^' . preg_quote($keyword) . '.*/i', $groups['names']);
|
||||
$group_ids = array_intersect($group_ids, array_flip($matches));
|
||||
|
||||
$i = 0;
|
||||
foreach ($group_ids as $group_id)
|
||||
{
|
||||
if ($i >= $this->config['mention_batch_size'])
|
||||
{
|
||||
// Do not exceed the names limit
|
||||
return false;
|
||||
}
|
||||
|
||||
$group_rank = phpbb_get_user_rank($groups[$group_id], false);
|
||||
array_push($names, [
|
||||
'name' => $groups[$group_id]['group_name'],
|
||||
'type' => 'g',
|
||||
'id' => $group_id,
|
||||
'avatar' => $this->helper->get_avatar($groups[$group_id]),
|
||||
'rank' => (isset($group_rank['title'])) ? $group_rank['title'] : '',
|
||||
'priority' => $this->get_priority($groups[$group_id]),
|
||||
]);
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
173
phpBB/phpbb/mention/source/base_user.php
Normal file
173
phpBB/phpbb/mention/source/base_user.php
Normal file
|
@ -0,0 +1,173 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\mention\source;
|
||||
|
||||
use phpbb\config\config;
|
||||
use phpbb\db\driver\driver_interface;
|
||||
use phpbb\user_loader;
|
||||
|
||||
abstract class base_user implements source_interface
|
||||
{
|
||||
/** @var driver_interface */
|
||||
protected $db;
|
||||
|
||||
/** @var config */
|
||||
protected $config;
|
||||
|
||||
/** @var user_loader */
|
||||
protected $user_loader;
|
||||
|
||||
/** @var string */
|
||||
protected $phpbb_root_path;
|
||||
|
||||
/** @var string */
|
||||
protected $php_ext;
|
||||
|
||||
/** @var string|false */
|
||||
protected $cache_ttl = false;
|
||||
|
||||
/**
|
||||
* base_user constructor.
|
||||
*
|
||||
* @param driver_interface $db
|
||||
* @param config $config
|
||||
* @param user_loader $user_loader
|
||||
* @param string $phpbb_root_path
|
||||
* @param string $phpEx
|
||||
*/
|
||||
public function __construct(driver_interface $db, config $config, user_loader $user_loader, string $phpbb_root_path, string $phpEx)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->config = $config;
|
||||
$this->user_loader = $user_loader;
|
||||
$this->phpbb_root_path = $phpbb_root_path;
|
||||
$this->php_ext = $phpEx;
|
||||
|
||||
if (!function_exists('phpbb_get_user_rank'))
|
||||
{
|
||||
include($this->phpbb_root_path . 'includes/functions_display.' . $this->php_ext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a query based on user input
|
||||
*
|
||||
* @param string $keyword Search string
|
||||
* @param int $topic_id Current topic ID
|
||||
* @return string Query ready for execution
|
||||
*/
|
||||
abstract protected function query(string $keyword, int $topic_id): string;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_priority(array $row): int
|
||||
{
|
||||
// By default every result from the source increases the priority by a fixed value
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get(array &$names, string $keyword, int $topic_id): bool
|
||||
{
|
||||
$fetched_all = false;
|
||||
$keyword = utf8_clean_string($keyword);
|
||||
|
||||
$i = 0;
|
||||
$users = [];
|
||||
$user_ids = [];
|
||||
|
||||
// Grab all necessary user IDs and cache them if needed
|
||||
if ($this->cache_ttl)
|
||||
{
|
||||
$result = $this->db->sql_query($this->query($keyword, $topic_id), $this->cache_ttl);
|
||||
|
||||
while ($i < $this->config['mention_batch_size'])
|
||||
{
|
||||
$row = $this->db->sql_fetchrow($result);
|
||||
|
||||
if (!$row)
|
||||
{
|
||||
$fetched_all = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($keyword) && strpos($row['username_clean'], $keyword) !== 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$i++;
|
||||
$users[] = $row;
|
||||
$user_ids[] = $row['user_id'];
|
||||
}
|
||||
|
||||
// Determine whether all usernames were fetched in current batch
|
||||
if (!$fetched_all)
|
||||
{
|
||||
$fetched_all = true;
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
if (!empty($keyword) && strpos($row['username_clean'], $keyword) !== 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// At least one username hasn't been fetched - exit loop
|
||||
$fetched_all = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = $this->db->sql_query_limit($this->query($keyword, $topic_id), $this->config['mention_batch_size'], 0);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$users[] = $row;
|
||||
$user_ids[] = $row['user_id'];
|
||||
}
|
||||
|
||||
// Determine whether all usernames were fetched in current batch
|
||||
if (count($user_ids) < $this->config['mention_batch_size'])
|
||||
{
|
||||
$fetched_all = true;
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
// Load all user data with a single SQL query, needed for ranks and avatars
|
||||
$this->user_loader->load_users($user_ids);
|
||||
|
||||
foreach ($users as $user)
|
||||
{
|
||||
$user_rank = $this->user_loader->get_rank($user['user_id']);
|
||||
array_push($names, [
|
||||
'name' => $this->user_loader->get_username($user['user_id'], 'username'),
|
||||
'type' => 'u',
|
||||
'id' => $user['user_id'],
|
||||
'avatar' => $this->user_loader->get_avatar($user['user_id']),
|
||||
'rank' => (isset($user_rank['rank_title'])) ? $user_rank['rank_title'] : '',
|
||||
'priority' => $this->get_priority($user),
|
||||
]);
|
||||
}
|
||||
|
||||
return $fetched_all;
|
||||
}
|
||||
}
|
58
phpBB/phpbb/mention/source/friend.php
Normal file
58
phpBB/phpbb/mention/source/friend.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\mention\source;
|
||||
|
||||
class friend extends base_user
|
||||
{
|
||||
/** @var \phpbb\user */
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* Set the user service used to retrieve current user ID
|
||||
*
|
||||
* @param \phpbb\user $user
|
||||
*/
|
||||
public function set_user(\phpbb\user $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function query(string $keyword, int $topic_id): string
|
||||
{
|
||||
/*
|
||||
* For optimization purposes all friends are returned regardless of the keyword
|
||||
* Names filtering is done on the frontend
|
||||
* Results will be cached on a per-user basis
|
||||
*/
|
||||
return $this->db->sql_build_query('SELECT', [
|
||||
'SELECT' => 'u.username_clean, u.user_id',
|
||||
'FROM' => [
|
||||
USERS_TABLE => 'u',
|
||||
],
|
||||
'LEFT_JOIN' => [
|
||||
[
|
||||
'FROM' => [ZEBRA_TABLE => 'z'],
|
||||
'ON' => 'u.user_id = z.zebra_id'
|
||||
]
|
||||
],
|
||||
'WHERE' => 'z.friend = 1 AND z.user_id = ' . (int) $this->user->data['user_id'] . '
|
||||
AND ' . $this->db->sql_in_set('u.user_type', [USER_NORMAL, USER_FOUNDER]) . '
|
||||
AND u.username_clean ' . $this->db->sql_like_expression($keyword . $this->db->get_any_char()),
|
||||
'ORDER_BY' => 'u.user_lastvisit DESC'
|
||||
]);
|
||||
}
|
||||
}
|
48
phpBB/phpbb/mention/source/group.php
Normal file
48
phpBB/phpbb/mention/source/group.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\mention\source;
|
||||
|
||||
class group extends base_group
|
||||
{
|
||||
/** @var string|false */
|
||||
protected $cache_ttl = 300;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_priority(array $row): int
|
||||
{
|
||||
/*
|
||||
* Presence in array with all names for this type should not increase the priority
|
||||
* Otherwise names will not be properly sorted because we fetch them in batches
|
||||
* and the name from 'special' source can be absent from the array with all names
|
||||
* and therefore it will appear lower than needed
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function query(string $keyword, int $topic_id): string
|
||||
{
|
||||
return $this->db->sql_build_query('SELECT', [
|
||||
'SELECT' => 'g.group_id',
|
||||
'FROM' => [
|
||||
GROUPS_TABLE => 'g',
|
||||
],
|
||||
'ORDER_BY' => 'g.group_name',
|
||||
]);
|
||||
}
|
||||
}
|
38
phpBB/phpbb/mention/source/source_interface.php
Normal file
38
phpBB/phpbb/mention/source/source_interface.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\mention\source;
|
||||
|
||||
interface source_interface
|
||||
{
|
||||
/**
|
||||
* Searches database for names to mention
|
||||
* and alters the passed array of found items
|
||||
*
|
||||
* @param array $names Array of already fetched data with names
|
||||
* @param string $keyword Search string
|
||||
* @param int $topic_id Current topic ID
|
||||
* @return bool Whether there are no more satisfying names left
|
||||
*/
|
||||
public function get(array &$names, string $keyword, int $topic_id): bool;
|
||||
|
||||
/**
|
||||
* Returns the priority of the currently selected name
|
||||
* Please note that simple inner priorities for a certain source
|
||||
* can be set with ORDER BY SQL clause
|
||||
*
|
||||
* @param array $row Array of fetched data for the name type (e.g. user row)
|
||||
* @return int Priority (defaults to 1)
|
||||
*/
|
||||
public function get_priority(array $row): int;
|
||||
}
|
46
phpBB/phpbb/mention/source/team.php
Normal file
46
phpBB/phpbb/mention/source/team.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\mention\source;
|
||||
|
||||
class team extends base_user
|
||||
{
|
||||
/** @var string|false */
|
||||
protected $cache_ttl = 300;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function query(string $keyword, int $topic_id): string
|
||||
{
|
||||
/*
|
||||
* Select unique names of team members: each name should be selected only once
|
||||
* regardless of the number of groups the certain user is a member of
|
||||
*
|
||||
* For optimization purposes all team members are returned regardless of the keyword
|
||||
* Names filtering is done on the frontend
|
||||
* Results will be cached in a single file
|
||||
*/
|
||||
return $this->db->sql_build_query('SELECT_DISTINCT', [
|
||||
'SELECT' => 'u.username_clean, u.user_id',
|
||||
'FROM' => [
|
||||
USERS_TABLE => 'u',
|
||||
USER_GROUP_TABLE => 'ug',
|
||||
TEAMPAGE_TABLE => 't',
|
||||
],
|
||||
'WHERE' => 'ug.group_id = t.group_id AND ug.user_id = u.user_id AND ug.user_pending = 0
|
||||
AND ' . $this->db->sql_in_set('u.user_type', [USER_NORMAL, USER_FOUNDER]),
|
||||
'ORDER_BY' => 'u.username_clean'
|
||||
]);
|
||||
}
|
||||
}
|
64
phpBB/phpbb/mention/source/topic.php
Normal file
64
phpBB/phpbb/mention/source/topic.php
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\mention\source;
|
||||
|
||||
class topic extends base_user
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_priority(array $row): int
|
||||
{
|
||||
/*
|
||||
* Topic's open poster is probably the most mentionable user in the topic
|
||||
* so we give him a significant priority
|
||||
*/
|
||||
return $row['user_id'] === $row['topic_poster'] ? 5 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function query(string $keyword, int $topic_id): string
|
||||
{
|
||||
/*
|
||||
* Select poster's username together with topic author's ID
|
||||
* that will be later used for prioritisation
|
||||
*
|
||||
* For optimization purposes all users are returned regardless of the keyword
|
||||
* Names filtering is done on the frontend
|
||||
* Results will be cached on a per-topic basis
|
||||
*/
|
||||
return $this->db->sql_build_query('SELECT', [
|
||||
'SELECT' => 'u.username_clean, u.user_id, t.topic_poster',
|
||||
'FROM' => [
|
||||
USERS_TABLE => 'u',
|
||||
],
|
||||
'LEFT_JOIN' => [
|
||||
[
|
||||
'FROM' => [POSTS_TABLE => 'p'],
|
||||
'ON' => 'u.user_id = p.poster_id'
|
||||
],
|
||||
[
|
||||
'FROM' => [TOPICS_TABLE => 't'],
|
||||
'ON' => 't.topic_id = p.topic_id'
|
||||
],
|
||||
],
|
||||
'WHERE' => 'p.topic_id = ' . (int) $topic_id . '
|
||||
AND ' . $this->db->sql_in_set('u.user_type', [USER_NORMAL, USER_FOUNDER]) . '
|
||||
AND u.username_clean ' . $this->db->sql_like_expression($keyword . $this->db->get_any_char()),
|
||||
'ORDER_BY' => 'p.post_time DESC'
|
||||
]);
|
||||
}
|
||||
}
|
47
phpBB/phpbb/mention/source/user.php
Normal file
47
phpBB/phpbb/mention/source/user.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\mention\source;
|
||||
|
||||
class user extends base_user
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_priority(array $row): int
|
||||
{
|
||||
/*
|
||||
* Presence in array with all names for this type should not increase the priority
|
||||
* Otherwise names will not be properly sorted because we fetch them in batches
|
||||
* and the name from 'special' source can be absent from the array with all names
|
||||
* and therefore it will appear lower than needed
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function query(string $keyword, int $topic_id): string
|
||||
{
|
||||
return $this->db->sql_build_query('SELECT', [
|
||||
'SELECT' => 'u.username_clean, u.user_id',
|
||||
'FROM' => [
|
||||
USERS_TABLE => 'u',
|
||||
],
|
||||
'WHERE' => $this->db->sql_in_set('u.user_type', [USER_NORMAL, USER_FOUNDER]) . '
|
||||
AND u.username_clean ' . $this->db->sql_like_expression($keyword . $this->db->get_any_char()),
|
||||
'ORDER_BY' => 'u.user_lastvisit DESC'
|
||||
]);
|
||||
}
|
||||
}
|
38
phpBB/phpbb/mention/source/usergroup.php
Normal file
38
phpBB/phpbb/mention/source/usergroup.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\mention\source;
|
||||
|
||||
class usergroup extends base_group
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function query(string $keyword, int $topic_id): string
|
||||
{
|
||||
return $this->db->sql_build_query('SELECT', [
|
||||
'SELECT' => 'g.group_id',
|
||||
'FROM' => [
|
||||
GROUPS_TABLE => 'g',
|
||||
],
|
||||
'LEFT_JOIN' => [
|
||||
[
|
||||
'FROM' => [USER_GROUP_TABLE => 'ug'],
|
||||
'ON' => 'g.group_id = ug.group_id'
|
||||
]
|
||||
],
|
||||
'WHERE' => 'ug.user_pending = 0 AND ug.user_id = ' . (int) $this->user->data['user_id'],
|
||||
'ORDER_BY' => 'g.group_name',
|
||||
]);
|
||||
}
|
||||
}
|
157
phpBB/phpbb/notification/type/mention.php
Normal file
157
phpBB/phpbb/notification/type/mention.php
Normal file
|
@ -0,0 +1,157 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\notification\type;
|
||||
|
||||
use phpbb\textformatter\s9e\mention_helper;
|
||||
|
||||
/**
|
||||
* Post mentioning notifications class
|
||||
* This class handles notifying users when they have been mentioned in a post
|
||||
*/
|
||||
|
||||
class mention extends post
|
||||
{
|
||||
/**
|
||||
* @var mention_helper
|
||||
*/
|
||||
protected $helper;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_type()
|
||||
{
|
||||
return 'notification.type.mention';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected $language_key = 'NOTIFICATION_MENTION';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static $notification_option = [
|
||||
'lang' => 'NOTIFICATION_TYPE_MENTION',
|
||||
'group' => 'NOTIFICATION_GROUP_POSTING',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function is_available()
|
||||
{
|
||||
return $this->config['allow_mentions'] && $this->auth->acl_get('u_mention');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function find_users_for_notification($post, $options = array())
|
||||
{
|
||||
$options = array_merge(array(
|
||||
'ignore_users' => array(),
|
||||
), $options);
|
||||
|
||||
$user_ids = $this->helper->get_mentioned_user_ids($post['post_text']);
|
||||
|
||||
$user_ids = array_unique($user_ids);
|
||||
|
||||
$user_ids = array_diff($user_ids, [(int) $post['poster_id']]);
|
||||
|
||||
if (empty($user_ids))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
return $this->get_authorised_recipients($user_ids, $post['forum_id'], $options, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a notification
|
||||
*
|
||||
* @param array $post Data specific for this type that will be updated
|
||||
* @return true
|
||||
*/
|
||||
public function update_notifications($post)
|
||||
{
|
||||
$old_notifications = $this->notification_manager->get_notified_users($this->get_type(), array(
|
||||
'item_id' => static::get_item_id($post),
|
||||
));
|
||||
|
||||
// Find the new users to notify
|
||||
$notifications = $this->find_users_for_notification($post);
|
||||
|
||||
// Find the notifications we must delete
|
||||
$remove_notifications = array_diff(array_keys($old_notifications), array_keys($notifications));
|
||||
|
||||
// Find the notifications we must add
|
||||
$add_notifications = array();
|
||||
foreach (array_diff(array_keys($notifications), array_keys($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))
|
||||
{
|
||||
$this->notification_manager->delete_notifications($this->get_type(), static::get_item_id($post), false, $remove_notifications);
|
||||
}
|
||||
|
||||
// return true to continue with the update code in the notifications service (this will update the rest of the notifications)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_redirect_url()
|
||||
{
|
||||
return $this->get_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_email_template()
|
||||
{
|
||||
return 'mention';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
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']),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the helper service used to retrieve mentioned used
|
||||
*
|
||||
* @param mention_helper $helper
|
||||
*/
|
||||
public function set_helper(mention_helper $helper): void
|
||||
{
|
||||
$this->helper = $helper;
|
||||
}
|
||||
}
|
|
@ -231,6 +231,7 @@ class permissions
|
|||
|
||||
'u_attach' => array('lang' => 'ACL_U_ATTACH', 'cat' => 'post'),
|
||||
'u_download' => array('lang' => 'ACL_U_DOWNLOAD', 'cat' => 'post'),
|
||||
'u_mention' => array('lang' => 'ACL_U_MENTION', 'cat' => 'post'),
|
||||
'u_savedrafts' => array('lang' => 'ACL_U_SAVEDRAFTS', 'cat' => 'post'),
|
||||
'u_chgcensors' => array('lang' => 'ACL_U_CHGCENSORS', 'cat' => 'post'),
|
||||
'u_sig' => array('lang' => 'ACL_U_SIG', 'cat' => 'post'),
|
||||
|
@ -276,6 +277,7 @@ class permissions
|
|||
'f_sticky' => array('lang' => 'ACL_F_STICKY', 'cat' => 'post'),
|
||||
'f_announce' => array('lang' => 'ACL_F_ANNOUNCE', 'cat' => 'post'),
|
||||
'f_announce_global' => array('lang' => 'ACL_F_ANNOUNCE_GLOBAL', 'cat' => 'post'),
|
||||
'f_mention' => array('lang' => 'ACL_F_MENTION', 'cat' => 'post'),
|
||||
'f_reply' => array('lang' => 'ACL_F_REPLY', 'cat' => 'post'),
|
||||
'f_edit' => array('lang' => 'ACL_F_EDIT', 'cat' => 'post'),
|
||||
'f_delete' => array('lang' => 'ACL_F_DELETE', 'cat' => 'post'),
|
||||
|
|
|
@ -89,4 +89,12 @@ interface renderer_interface
|
|||
* @return null
|
||||
*/
|
||||
public function set_viewsmilies($value);
|
||||
|
||||
/**
|
||||
* Set the "usemention" option
|
||||
*
|
||||
* @param bool $value Option's value
|
||||
* @return null
|
||||
*/
|
||||
public function set_usemention($value);
|
||||
}
|
||||
|
|
|
@ -84,6 +84,12 @@ class factory implements \phpbb\textformatter\cache_interface
|
|||
'img' => '[IMG src={IMAGEURL;useContent}]',
|
||||
'list' => '[LIST type={HASHMAP=1:decimal,a:lower-alpha,A:upper-alpha,i:lower-roman,I:upper-roman;optional;postFilter=#simpletext} #createChild=LI]{TEXT}[/LIST]',
|
||||
'li' => '[* $tagName=LI]{TEXT}[/*]',
|
||||
'mention' =>
|
||||
"[MENTION={PARSE=/^g:(?'group_id'\d+)|u:(?'user_id'\d+)$/}
|
||||
group_id={UINT;optional}
|
||||
profile_url={URL;optional;postFilter=#false}
|
||||
user_id={UINT;optional}
|
||||
]{TEXT}[/MENTION]",
|
||||
'quote' =>
|
||||
"[QUOTE
|
||||
author={TEXT1;optional}
|
||||
|
@ -108,13 +114,13 @@ class factory implements \phpbb\textformatter\cache_interface
|
|||
* @var array Default templates, taken from bbcode::bbcode_tpl()
|
||||
*/
|
||||
protected $default_templates = array(
|
||||
'b' => '<span style="font-weight: bold"><xsl:apply-templates/></span>',
|
||||
'i' => '<span style="font-style: italic"><xsl:apply-templates/></span>',
|
||||
'u' => '<span style="text-decoration: underline"><xsl:apply-templates/></span>',
|
||||
'img' => '<img src="{IMAGEURL}" class="postimage" alt="{L_IMAGE}"/>',
|
||||
'size' => '<span><xsl:attribute name="style"><xsl:text>font-size: </xsl:text><xsl:value-of select="substring(@size, 1, 4)"/><xsl:text>%; line-height: normal</xsl:text></xsl:attribute><xsl:apply-templates/></span>',
|
||||
'color' => '<span style="color: {COLOR}"><xsl:apply-templates/></span>',
|
||||
'email' => '<a>
|
||||
'b' => '<span style="font-weight: bold"><xsl:apply-templates/></span>',
|
||||
'i' => '<span style="font-style: italic"><xsl:apply-templates/></span>',
|
||||
'u' => '<span style="text-decoration: underline"><xsl:apply-templates/></span>',
|
||||
'img' => '<img src="{IMAGEURL}" class="postimage" alt="{L_IMAGE}"/>',
|
||||
'size' => '<span><xsl:attribute name="style"><xsl:text>font-size: </xsl:text><xsl:value-of select="substring(@size, 1, 4)"/><xsl:text>%; line-height: normal</xsl:text></xsl:attribute><xsl:apply-templates/></span>',
|
||||
'color' => '<span style="color: {COLOR}"><xsl:apply-templates/></span>',
|
||||
'email' => '<a>
|
||||
<xsl:attribute name="href">
|
||||
<xsl:text>mailto:</xsl:text>
|
||||
<xsl:value-of select="@email"/>
|
||||
|
@ -126,6 +132,19 @@ class factory implements \phpbb\textformatter\cache_interface
|
|||
</xsl:attribute>
|
||||
<xsl:apply-templates/>
|
||||
</a>',
|
||||
'mention' => '<xsl:text>@</xsl:text>
|
||||
<xsl:choose>
|
||||
<xsl:when test="@profile_url">
|
||||
<a class="mention" href="{@profile_url}">
|
||||
<xsl:apply-templates/>
|
||||
</a>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<span class="mention">
|
||||
<xsl:apply-templates/>
|
||||
</span>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>',
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -287,8 +306,8 @@ class factory implements \phpbb\textformatter\cache_interface
|
|||
$configurator->tags['QUOTE']->nestingLimit = PHP_INT_MAX;
|
||||
}
|
||||
|
||||
// Modify the template to disable images/flash depending on user's settings
|
||||
foreach (array('FLASH', 'IMG') as $name)
|
||||
// Modify the template to disable images/flash/mentions depending on user's settings
|
||||
foreach (array('FLASH', 'IMG', 'MENTION') as $name)
|
||||
{
|
||||
$tag = $configurator->tags[$name];
|
||||
$tag->template = '<xsl:choose><xsl:when test="$S_VIEW' . $name . '">' . $tag->template . '</xsl:when><xsl:otherwise><xsl:apply-templates/></xsl:otherwise></xsl:choose>';
|
||||
|
|
203
phpBB/phpbb/textformatter/s9e/mention_helper.php
Normal file
203
phpBB/phpbb/textformatter/s9e/mention_helper.php
Normal file
|
@ -0,0 +1,203 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\textformatter\s9e;
|
||||
|
||||
use s9e\TextFormatter\Utils as TextFormatterUtils;
|
||||
|
||||
class mention_helper
|
||||
{
|
||||
/**
|
||||
* @var \phpbb\db\driver\driver_interface
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* @var \phpbb\auth\auth
|
||||
*/
|
||||
protected $auth;
|
||||
|
||||
/**
|
||||
* @var \phpbb\user
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* @var string Base URL for a user profile link, uses {USER_ID} as placeholder
|
||||
*/
|
||||
protected $user_profile_url;
|
||||
|
||||
/**
|
||||
* @var string Base URL for a group profile link, uses {GROUP_ID} as placeholder
|
||||
*/
|
||||
protected $group_profile_url;
|
||||
|
||||
/**
|
||||
* @var array Array of group IDs allowed to be mentioned by current user
|
||||
*/
|
||||
protected $mentionable_groups = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \phpbb\db\driver\driver_interface $db
|
||||
* @param \phpbb\auth\auth $auth
|
||||
* @param \phpbb\user $user
|
||||
* @param string $root_path
|
||||
* @param string $php_ext
|
||||
*/
|
||||
public function __construct($db, $auth, $user, $root_path, $php_ext)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->auth = $auth;
|
||||
$this->user = $user;
|
||||
$this->user_profile_url = append_sid($root_path . 'memberlist.' . $php_ext, 'mode=viewprofile&u={USER_ID}', false);
|
||||
$this->group_profile_url = append_sid($root_path . 'memberlist.' . $php_ext, 'mode=group&g={GROUP_ID}', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject dynamic metadata into MENTION tags in given XML
|
||||
*
|
||||
* @param string $xml Original XML
|
||||
* @return string Modified XML
|
||||
*/
|
||||
public function inject_metadata($xml)
|
||||
{
|
||||
$profile_urls = [
|
||||
'u' => $this->user_profile_url,
|
||||
'g' => $this->group_profile_url,
|
||||
];
|
||||
|
||||
return TextFormatterUtils::replaceAttributes(
|
||||
$xml,
|
||||
'MENTION',
|
||||
function ($attributes) use ($profile_urls)
|
||||
{
|
||||
if (isset($attributes['user_id']))
|
||||
{
|
||||
$attributes['profile_url'] = str_replace('{USER_ID}', $attributes['user_id'], $profile_urls['u']);
|
||||
}
|
||||
else if (isset($attributes['group_id']))
|
||||
{
|
||||
$attributes['profile_url'] = str_replace('{GROUP_ID}', $attributes['group_id'], $profile_urls['g']);
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get group IDs allowed to be mentioned by current user
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_mentionable_groups()
|
||||
{
|
||||
if (is_array($this->mentionable_groups))
|
||||
{
|
||||
return $this->mentionable_groups;
|
||||
}
|
||||
|
||||
$hidden_restriction = (!$this->auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) ? ' AND (g.group_type <> ' . GROUP_HIDDEN . ' OR (ug.user_pending = 0 AND ug.user_id = ' . (int) $this->user->data['user_id'] . '))' : '';
|
||||
|
||||
$query = $this->db->sql_build_query('SELECT', [
|
||||
'SELECT' => 'g.group_id',
|
||||
'FROM' => [
|
||||
GROUPS_TABLE => 'g',
|
||||
],
|
||||
'LEFT_JOIN' => [[
|
||||
'FROM' => [
|
||||
USER_GROUP_TABLE => 'ug',
|
||||
],
|
||||
'ON' => 'g.group_id = ug.group_id',
|
||||
]],
|
||||
'WHERE' => '(g.group_type <> ' . GROUP_SPECIAL . ' OR ' . $this->db->sql_in_set('g.group_name', ['ADMINISTRATORS', 'GLOBAL_MODERATORS']) . ')' . $hidden_restriction,
|
||||
]);
|
||||
$result = $this->db->sql_query($query);
|
||||
|
||||
$this->mentionable_groups = [];
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
$this->mentionable_groups[] = $row['group_id'];
|
||||
}
|
||||
|
||||
$this->db->sql_freeresult($result);
|
||||
|
||||
return $this->mentionable_groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects IDs of user members of a certain group
|
||||
*
|
||||
* @param array $user_ids Array of already selected user IDs
|
||||
* @param int $group_id ID of the group to search members in
|
||||
*/
|
||||
protected function get_user_ids_for_group(&$user_ids, $group_id)
|
||||
{
|
||||
if (!in_array($group_id, $this->get_mentionable_groups()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$query = $this->db->sql_build_query('SELECT', [
|
||||
'SELECT' => 'ug.user_id, ug.group_id',
|
||||
'FROM' => [
|
||||
USER_GROUP_TABLE => 'ug',
|
||||
GROUPS_TABLE => 'g',
|
||||
],
|
||||
'WHERE' => 'g.group_id = ug.group_id',
|
||||
]);
|
||||
// Cache results for 5 minutes
|
||||
$result = $this->db->sql_query($query, 300);
|
||||
|
||||
while ($row = $this->db->sql_fetchrow($result))
|
||||
{
|
||||
if ($row['group_id'] == $group_id)
|
||||
{
|
||||
$user_ids[] = (int) $row['user_id'];
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->sql_freeresult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of mentioned user IDs
|
||||
*
|
||||
* @param string $xml Parsed text
|
||||
* @return int[] List of user IDs
|
||||
*/
|
||||
public function get_mentioned_user_ids($xml)
|
||||
{
|
||||
$ids = array();
|
||||
if (strpos($xml, '<MENTION ') === false)
|
||||
{
|
||||
return $ids;
|
||||
}
|
||||
|
||||
// Add IDs of users mentioned directly
|
||||
$user_ids = TextFormatterUtils::getAttributeValues($xml, 'MENTION', 'user_id');
|
||||
$ids = array_merge($ids, array_map('intval', $user_ids));
|
||||
|
||||
// Add IDs of users mentioned as group members
|
||||
$group_ids = TextFormatterUtils::getAttributeValues($xml, 'MENTION', 'group_id');
|
||||
foreach ($group_ids as $group_id)
|
||||
{
|
||||
$this->get_user_ids_for_group($ids, (int) $group_id);
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
|
@ -28,6 +28,11 @@ class renderer implements \phpbb\textformatter\renderer_interface
|
|||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
/**
|
||||
* @var mention_helper
|
||||
*/
|
||||
protected $mention_helper;
|
||||
|
||||
/**
|
||||
* @var quote_helper
|
||||
*/
|
||||
|
@ -58,6 +63,11 @@ class renderer implements \phpbb\textformatter\renderer_interface
|
|||
*/
|
||||
protected $viewsmilies = false;
|
||||
|
||||
/**
|
||||
* @var bool Whether the user is allowed to use mentions
|
||||
*/
|
||||
protected $usemention = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
|
@ -117,6 +127,16 @@ class renderer implements \phpbb\textformatter\renderer_interface
|
|||
extract($dispatcher->trigger_event('core.text_formatter_s9e_renderer_setup', compact($vars)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the mention_helper object used to display extended information in mentions
|
||||
*
|
||||
* @param mention_helper $mention_helper
|
||||
*/
|
||||
public function configure_mention_helper(mention_helper $mention_helper)
|
||||
{
|
||||
$this->mention_helper = $mention_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the quote_helper object used to display extended information in quotes
|
||||
*
|
||||
|
@ -162,6 +182,7 @@ class renderer implements \phpbb\textformatter\renderer_interface
|
|||
$this->set_viewflash($user->optionget('viewflash'));
|
||||
$this->set_viewimg($user->optionget('viewimg'));
|
||||
$this->set_viewsmilies($user->optionget('viewsmilies'));
|
||||
$this->set_usemention($config['allow_mentions'] && $auth->acl_get('u_mention'));
|
||||
|
||||
// Set the stylesheet parameters
|
||||
foreach (array_keys($this->renderer->getParameters()) as $param_name)
|
||||
|
@ -229,6 +250,11 @@ class renderer implements \phpbb\textformatter\renderer_interface
|
|||
*/
|
||||
public function render($xml)
|
||||
{
|
||||
if (isset($this->mention_helper))
|
||||
{
|
||||
$xml = $this->mention_helper->inject_metadata($xml);
|
||||
}
|
||||
|
||||
if (isset($this->quote_helper))
|
||||
{
|
||||
$xml = $this->quote_helper->inject_metadata($xml);
|
||||
|
@ -310,4 +336,13 @@ class renderer implements \phpbb\textformatter\renderer_interface
|
|||
$this->viewsmilies = $value;
|
||||
$this->renderer->setParameter('S_VIEWSMILIES', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set_usemention($value)
|
||||
{
|
||||
$this->usemention = $value;
|
||||
$this->renderer->setParameter('S_VIEWMENTION', $value);
|
||||
}
|
||||
}
|
||||
|
|
6
phpBB/styles/prosilver/template/mentions_templates.html
Normal file
6
phpBB/styles/prosilver/template/mentions_templates.html
Normal file
|
@ -0,0 +1,6 @@
|
|||
<template data-id="mention-media-span"><span class="mention-media"></span></template>
|
||||
<template data-id="mention-media-avatar-img"><img class="avatar mention-media-avatar" src="" alt=""></template>
|
||||
<template data-id="mention-name-span"><span class="mention-name"></span></template>
|
||||
<template data-id="mention-default-avatar"><svg class="mention-media-avatar" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path fill-rule="evenodd" d="M12,19.2C9.5,19.2 7.29,17.92 6,16C6.03,14 10,12.9 12,12.9C14,12.9 17.97,14 18,16C16.71,17.92 14.5,19.2 12,19.2M12,5A3,3 0 0,1 15,8A3,3 0 0,1 12,11A3,3 0 0,1 9,8A3,3 0 0,1 12,5M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z"/></svg></template>
|
||||
<template data-id="mention-default-avatar-group"><svg class="mention-media-avatar" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path fill-rule="evenodd" d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></svg></template>
|
||||
<template data-id="mention-rank-span"><span class="mention-rank"></span></template>
|
|
@ -25,7 +25,12 @@
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{% include 'mentions_templates.html' %}
|
||||
|
||||
<!-- INCLUDEJS {T_ASSETS_PATH}/javascript/editor.js -->
|
||||
<!-- INCLUDEJS {T_ASSETS_PATH}/javascript/tribute.min.js -->
|
||||
<!-- INCLUDEJS {T_ASSETS_PATH}/javascript/mentions.js -->
|
||||
|
||||
<!-- IF S_BBCODE_ALLOWED -->
|
||||
<div id="colour_palette" style="display: none;">
|
||||
|
@ -36,7 +41,7 @@
|
|||
</div>
|
||||
|
||||
<!-- EVENT posting_editor_buttons_before -->
|
||||
<div id="format-buttons" class="format-buttons">
|
||||
<div id="format-buttons" class="format-buttons"<!-- IF S_ALLOW_MENTIONS --> data-mention-url="{U_MENTION_URL}" data-mention-names-limit="{S_MENTION_NAMES_LIMIT}" data-topic-id="{S_TOPIC_ID}" data-user-id="{S_USER_ID}"<!-- ENDIF -->>
|
||||
<button type="button" class="button button-icon-only bbcode-b" accesskey="b" name="addbbcode0" value=" B " onclick="bbstyle(0)" title="{L_BBCODE_B_HELP}">
|
||||
{{ Icon('iconify', 'mdi:format-bold', '', true, 'c-button-icon') }}
|
||||
</button>
|
||||
|
|
|
@ -365,6 +365,24 @@
|
|||
float: left;
|
||||
}
|
||||
|
||||
/**
|
||||
* mentions.css
|
||||
*/
|
||||
|
||||
/* Mention block
|
||||
---------------------------------------- */
|
||||
|
||||
/* Mention dropdown
|
||||
---------------------------------------- */
|
||||
.rtl .mention-container { /* mention-container */
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.rtl .mention-media {
|
||||
margin-right: 0;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
/**
|
||||
* content.css
|
||||
*/
|
||||
|
|
|
@ -369,6 +369,41 @@ p.post-notice {
|
|||
background-image: none;
|
||||
}
|
||||
|
||||
/* colours and backgrounds for mentions.css */
|
||||
|
||||
/* mention dropdown */
|
||||
.mention-container { /* mention-container */
|
||||
background-color: #ffffff;
|
||||
box-shadow:
|
||||
0 3px 1px -2px rgba(0, 0, 0, 0.2),
|
||||
0 2px 2px 0 rgba(0, 0, 0, 0.14),
|
||||
0 1px 5px 0 rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.mention-media {
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
.mention-item {
|
||||
border-bottom-color: #dddddd;
|
||||
color: #212121;
|
||||
}
|
||||
|
||||
.mention-item:hover,
|
||||
.mention-item.is-active {
|
||||
background-color: #eeeeee;
|
||||
color: #2d80d2;
|
||||
}
|
||||
|
||||
.mention-item:hover .mention-media-avatar,
|
||||
.mention-item.is-active .mention-media-avatar {
|
||||
color: #2d80d2;
|
||||
}
|
||||
|
||||
.mention-rank {
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
/* colours and backgrounds for content.css */
|
||||
ul.forums {
|
||||
background-color: #edf4f7;
|
||||
|
|
83
phpBB/styles/prosilver/theme/mentions.css
Normal file
83
phpBB/styles/prosilver/theme/mentions.css
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* -------------------------------------------------------------- /*
|
||||
$Mentions
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
/* stylelint-disable selector-max-compound-selectors */
|
||||
/* stylelint-disable selector-no-qualifying-type */
|
||||
|
||||
/* Mention block
|
||||
---------------------------------------- */
|
||||
.mention {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Mention dropdown
|
||||
---------------------------------------- */
|
||||
.mention-container {
|
||||
text-align: left;
|
||||
border-radius: 2px;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
overflow: auto; /* placed here for list to scroll with arrow key press */
|
||||
max-height: 200px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.mention-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.mention-media {
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 8px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.mention-media-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.mention-item {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
letter-spacing: 0.04em;
|
||||
border-bottom: 1px solid transparent;
|
||||
position: relative;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mention-item:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.mention-name,
|
||||
.mention-rank {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mention-name {
|
||||
line-height: 1.25;
|
||||
margin-right: 20px; /* needed to account for scrollbar bug on Firefox for Windows */
|
||||
}
|
||||
|
||||
.mention-rank {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1.2871;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
/* stylelint-enable selector-max-compound-selectors */
|
||||
/* stylelint-enable selector-no-qualifying-type */
|
|
@ -14,6 +14,7 @@
|
|||
@import url("common.css?hash=658f990b");
|
||||
@import url("buttons.css?hash=eb16911f");
|
||||
@import url("links.css?hash=5fec3654");
|
||||
@import url("mentions.css?hash=a67fa183");
|
||||
@import url("content.css?hash=f7bdea58");
|
||||
@import url("cp.css?hash=73c6f37d");
|
||||
@import url("forms.css?hash=5e06dbba");
|
||||
|
|
558
tests/mention/controller_test.php
Normal file
558
tests/mention/controller_test.php
Normal file
|
@ -0,0 +1,558 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
||||
|
||||
class phpbb_mention_controller_test extends phpbb_database_test_case
|
||||
{
|
||||
protected $db, $container, $user, $config, $auth, $cache;
|
||||
|
||||
/**
|
||||
* @var \phpbb\mention\controller\mention
|
||||
*/
|
||||
protected $controller;
|
||||
|
||||
/**
|
||||
* @var PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
public function getDataSet()
|
||||
{
|
||||
return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/mention.xml');
|
||||
}
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
global $auth, $cache, $config, $db, $phpbb_container, $phpbb_dispatcher, $lang, $user, $request, $phpEx, $phpbb_root_path, $user_loader;
|
||||
|
||||
// Database
|
||||
$this->db = $this->new_dbal();
|
||||
$db = $this->db;
|
||||
|
||||
// Auth
|
||||
$auth = $this->createMock('\phpbb\auth\auth');
|
||||
$auth->expects($this->any())
|
||||
->method('acl_gets')
|
||||
->with('a_group', 'a_groupadd', 'a_groupdel')
|
||||
->willReturn(false)
|
||||
;
|
||||
|
||||
// Config
|
||||
$config = new \phpbb\config\config(array(
|
||||
'allow_mentions' => true,
|
||||
'mention_batch_size' => 8,
|
||||
'mention_names_limit' => 3,
|
||||
));
|
||||
|
||||
$cache_driver = new \phpbb\cache\driver\dummy();
|
||||
$cache = new \phpbb\cache\service(
|
||||
$cache_driver,
|
||||
$config,
|
||||
$db,
|
||||
$phpbb_root_path,
|
||||
$phpEx
|
||||
);
|
||||
|
||||
// Event dispatcher
|
||||
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
|
||||
|
||||
// Language
|
||||
$lang = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
|
||||
|
||||
// User
|
||||
$user = $this->createMock('\phpbb\user', array(), array(
|
||||
$lang,
|
||||
'\phpbb\datetime'
|
||||
));
|
||||
$user->ip = '';
|
||||
$user->data = array(
|
||||
'user_id' => 2,
|
||||
'username' => 'myself',
|
||||
'is_registered' => true,
|
||||
'user_colour' => '',
|
||||
);
|
||||
|
||||
// Request
|
||||
$this->request = $request = $this->createMock('\phpbb\request\request');
|
||||
|
||||
$request->expects($this->any())
|
||||
->method('is_ajax')
|
||||
->willReturn(true);
|
||||
$avatar_helper = $this->getMockBuilder('\phpbb\avatar\helper')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$user_loader = new \phpbb\user_loader($avatar_helper, $db, $phpbb_root_path, $phpEx, USERS_TABLE);
|
||||
|
||||
// Container
|
||||
$phpbb_container = new ContainerBuilder();
|
||||
|
||||
$loader = new YamlFileLoader($phpbb_container, new FileLocator(__DIR__ . '/fixtures'));
|
||||
$loader->load('services_mention.yml');
|
||||
$phpbb_container->set('user_loader', $user_loader);
|
||||
$phpbb_container->set('user', $user);
|
||||
$phpbb_container->set('language', $lang);
|
||||
$phpbb_container->set('config', $config);
|
||||
$phpbb_container->set('dbal.conn', $db);
|
||||
$phpbb_container->set('auth', $auth);
|
||||
$phpbb_container->set('cache.driver', $cache_driver);
|
||||
$phpbb_container->set('cache', $cache);
|
||||
$phpbb_container->set('request', $request);
|
||||
$phpbb_container->set('group_helper', new \phpbb\group\helper(
|
||||
$this->getMockBuilder('\phpbb\auth\auth')->disableOriginalConstructor()->getMock(),
|
||||
$avatar_helper,
|
||||
$cache,
|
||||
$config,
|
||||
new \phpbb\language\language(
|
||||
new phpbb\language\language_file_loader($phpbb_root_path, $phpEx)
|
||||
),
|
||||
new phpbb_mock_event_dispatcher(),
|
||||
new \phpbb\path_helper(
|
||||
new \phpbb\symfony_request(
|
||||
new phpbb_mock_request()
|
||||
),
|
||||
$this->getMockBuilder('\phpbb\request\request')->disableOriginalConstructor()->getMock(),
|
||||
$phpbb_root_path,
|
||||
$phpEx
|
||||
),
|
||||
$user
|
||||
));
|
||||
$phpbb_container->set('text_formatter.utils', new \phpbb\textformatter\s9e\utils());
|
||||
$phpbb_container->set(
|
||||
'text_formatter.s9e.mention_helper',
|
||||
new \phpbb\textformatter\s9e\mention_helper(
|
||||
$this->db,
|
||||
$auth,
|
||||
$user,
|
||||
$phpbb_root_path,
|
||||
$phpEx
|
||||
)
|
||||
);
|
||||
$phpbb_container->setParameter('core.root_path', $phpbb_root_path);
|
||||
$phpbb_container->setParameter('core.php_ext', $phpEx);
|
||||
$phpbb_container->addCompilerPass(new phpbb\di\pass\markpublic_pass());
|
||||
$phpbb_container->compile();
|
||||
|
||||
// Mention Sources
|
||||
$mention_sources = array('friend', 'group', 'team', 'topic', 'user', 'usergroup');
|
||||
$mention_sources_array = array();
|
||||
foreach ($mention_sources as $source)
|
||||
{
|
||||
$class = $phpbb_container->get('mention.source.' . $source);
|
||||
$mention_sources_array['mention.source.' . $source] = $class;
|
||||
}
|
||||
|
||||
$this->controller = new \phpbb\mention\controller\mention($mention_sources_array, $request, $phpbb_root_path, $phpEx);
|
||||
}
|
||||
|
||||
public function handle_data()
|
||||
{
|
||||
/**
|
||||
* NOTE:
|
||||
* 1) in production comparison with 'myself' is being done in JS
|
||||
* 2) team members of hidden groups can also be mentioned (because they are shown on teampage)
|
||||
*/
|
||||
return [
|
||||
['', 0, [
|
||||
'names' => [
|
||||
[
|
||||
'name' => 'friend',
|
||||
'type' => 'u',
|
||||
'id' => 7,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 1,
|
||||
],
|
||||
[
|
||||
'name' => 'Group we are a member of',
|
||||
'type' => 'g',
|
||||
'id' => 3,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'Normal group',
|
||||
'type' => 'g',
|
||||
'id' => 1,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'team_member_hidden',
|
||||
'type' => 'u',
|
||||
'id' => 6,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 1,
|
||||
],
|
||||
[
|
||||
'name' => 'team_member_normal',
|
||||
'type' => 'u',
|
||||
'id' => 5,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 1,
|
||||
],
|
||||
[
|
||||
'name' => 'myself',
|
||||
'type' => 'u',
|
||||
'id' => 2,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'poster',
|
||||
'type' => 'u',
|
||||
'id' => 3,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'replier',
|
||||
'type' => 'u',
|
||||
'id' => 4,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'team_member_normal',
|
||||
'type' => 'u',
|
||||
'id' => 5,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'team_member_hidden',
|
||||
'type' => 'u',
|
||||
'id' => 6,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'friend',
|
||||
'type' => 'u',
|
||||
'id' => 7,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'test',
|
||||
'type' => 'u',
|
||||
'id' => 8,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'test1',
|
||||
'type' => 'u',
|
||||
'id' => 9,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'Group we are a member of',
|
||||
'type' => 'g',
|
||||
'id' => 3,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 1,
|
||||
],
|
||||
],
|
||||
'all' => false,
|
||||
]],
|
||||
['', 1, [
|
||||
'names' => [
|
||||
[
|
||||
'name' => 'friend',
|
||||
'type' => 'u',
|
||||
'id' => 7,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 1,
|
||||
],
|
||||
[
|
||||
'name' => 'Group we are a member of',
|
||||
'type' => 'g',
|
||||
'id' => 3,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'Normal group',
|
||||
'type' => 'g',
|
||||
'id' => 1,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'team_member_hidden',
|
||||
'type' => 'u',
|
||||
'id' => 6,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 1,
|
||||
],
|
||||
[
|
||||
'name' => 'team_member_normal',
|
||||
'type' => 'u',
|
||||
'id' => 5,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 1,
|
||||
],
|
||||
[
|
||||
'name' => 'replier',
|
||||
'type' => 'u',
|
||||
'id' => 4,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 1,
|
||||
],
|
||||
[
|
||||
'name' => 'poster',
|
||||
'type' => 'u',
|
||||
'id' => 3,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 5,
|
||||
],
|
||||
[
|
||||
'name' => 'myself',
|
||||
'type' => 'u',
|
||||
'id' => 2,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'poster',
|
||||
'type' => 'u',
|
||||
'id' => 3,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'replier',
|
||||
'type' => 'u',
|
||||
'id' => 4,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'team_member_normal',
|
||||
'type' => 'u',
|
||||
'id' => 5,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'team_member_hidden',
|
||||
'type' => 'u',
|
||||
'id' => 6,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'friend',
|
||||
'type' => 'u',
|
||||
'id' => 7,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'test',
|
||||
'type' => 'u',
|
||||
'id' => 8,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'test1',
|
||||
'type' => 'u',
|
||||
'id' => 9,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'Group we are a member of',
|
||||
'type' => 'g',
|
||||
'id' => 3,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 1,
|
||||
],
|
||||
],
|
||||
'all' => false,
|
||||
]],
|
||||
['t', 1, [
|
||||
'names' => [
|
||||
[
|
||||
'name' => 'team_member_hidden',
|
||||
'type' => 'u',
|
||||
'id' => 6,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 1,
|
||||
],
|
||||
[
|
||||
'name' => 'team_member_normal',
|
||||
'type' => 'u',
|
||||
'id' => 5,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 1,
|
||||
],
|
||||
[
|
||||
'name' => 'team_member_normal',
|
||||
'type' => 'u',
|
||||
'id' => 5,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'team_member_hidden',
|
||||
'type' => 'u',
|
||||
'id' => 6,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'test',
|
||||
'type' => 'u',
|
||||
'id' => 8,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'test1',
|
||||
'type' => 'u',
|
||||
'id' => 9,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'test2',
|
||||
'type' => 'u',
|
||||
'id' => 10,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'test3',
|
||||
'type' => 'u',
|
||||
'id' => 11,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
],
|
||||
'all' => true,
|
||||
]],
|
||||
['test', 1, [
|
||||
'names' => [
|
||||
[
|
||||
'name' => 'test',
|
||||
'type' => 'u',
|
||||
'id' => 8,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'test1',
|
||||
'type' => 'u',
|
||||
'id' => 9,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'test2',
|
||||
'type' => 'u',
|
||||
'id' => 10,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
[
|
||||
'name' => 'test3',
|
||||
'type' => 'u',
|
||||
'id' => 11,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
],
|
||||
],
|
||||
'all' => true,
|
||||
]],
|
||||
['test1', 1, [
|
||||
'names' => [[
|
||||
'name' => 'test1',
|
||||
'type' => 'u',
|
||||
'id' => 9,
|
||||
'avatar' => [],
|
||||
'rank' => '',
|
||||
'priority' => 0,
|
||||
]],
|
||||
'all' => true,
|
||||
]],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider handle_data
|
||||
*/
|
||||
public function test_handle($keyword, $topic_id, $expected_result)
|
||||
{
|
||||
$this->request->expects($this->atLeast(2))
|
||||
->method('variable')
|
||||
->withConsecutive(
|
||||
['keyword', '', true],
|
||||
['topic_id', 0])
|
||||
->willReturnOnConsecutiveCalls(
|
||||
$keyword,
|
||||
$topic_id
|
||||
);
|
||||
$data = json_decode($this->controller->handle()->getContent(), true);
|
||||
$this->assertEquals($expected_result, $data);
|
||||
}
|
||||
}
|
204
tests/mention/fixtures/mention.xml
Normal file
204
tests/mention/fixtures/mention.xml
Normal file
|
@ -0,0 +1,204 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<dataset>
|
||||
<table name="phpbb_groups">
|
||||
<column>group_id</column>
|
||||
<column>group_name</column>
|
||||
<column>group_type</column>
|
||||
<column>group_desc</column>
|
||||
<row>
|
||||
<value>1</value>
|
||||
<value>Normal group</value>
|
||||
<value>0</value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>2</value>
|
||||
<value>Hidden group</value>
|
||||
<value>2</value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>3</value>
|
||||
<value>Group we are a member of</value>
|
||||
<value>0</value>
|
||||
<value></value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_posts">
|
||||
<column>post_id</column>
|
||||
<column>topic_id</column>
|
||||
<column>forum_id</column>
|
||||
<column>poster_id</column>
|
||||
<column>post_time</column>
|
||||
<column>post_text</column>
|
||||
<row>
|
||||
<value>1</value>
|
||||
<value>1</value>
|
||||
<value>1</value>
|
||||
<value>3</value>
|
||||
<value>1</value>
|
||||
<value>Topic's initial post.</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>2</value>
|
||||
<value>1</value>
|
||||
<value>1</value>
|
||||
<value>4</value>
|
||||
<value>2</value>
|
||||
<value>A reply.</value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_teampage">
|
||||
<column>teampage_id</column>
|
||||
<column>group_id</column>
|
||||
<row>
|
||||
<value>1</value>
|
||||
<value>1</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>2</value>
|
||||
<value>2</value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_topics">
|
||||
<column>topic_id</column>
|
||||
<column>forum_id</column>
|
||||
<column>topic_poster</column>
|
||||
<row>
|
||||
<value>1</value>
|
||||
<value>1</value>
|
||||
<value>3</value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_users">
|
||||
<column>user_id</column>
|
||||
<column>username</column>
|
||||
<column>username_clean</column>
|
||||
<column>user_type</column>
|
||||
<column>user_lastvisit</column>
|
||||
<column>user_permissions</column>
|
||||
<column>user_sig</column>
|
||||
<row>
|
||||
<value>2</value>
|
||||
<value>myself</value>
|
||||
<value>myself</value>
|
||||
<value>0</value>
|
||||
<value>19</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>3</value>
|
||||
<value>poster</value>
|
||||
<value>poster</value>
|
||||
<value>0</value>
|
||||
<value>18</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>4</value>
|
||||
<value>replier</value>
|
||||
<value>replier</value>
|
||||
<value>0</value>
|
||||
<value>17</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>5</value>
|
||||
<value>team_member_normal</value>
|
||||
<value>team_member_normal</value>
|
||||
<value>0</value>
|
||||
<value>16</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>6</value>
|
||||
<value>team_member_hidden</value>
|
||||
<value>team_member_hidden</value>
|
||||
<value>0</value>
|
||||
<value>15</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>7</value>
|
||||
<value>friend</value>
|
||||
<value>friend</value>
|
||||
<value>0</value>
|
||||
<value>14</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>8</value>
|
||||
<value>test</value>
|
||||
<value>test</value>
|
||||
<value>0</value>
|
||||
<value>13</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>9</value>
|
||||
<value>test1</value>
|
||||
<value>test1</value>
|
||||
<value>0</value>
|
||||
<value>12</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>10</value>
|
||||
<value>test2</value>
|
||||
<value>test2</value>
|
||||
<value>0</value>
|
||||
<value>11</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>11</value>
|
||||
<value>test3</value>
|
||||
<value>test3</value>
|
||||
<value>0</value>
|
||||
<value>10</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_user_group">
|
||||
<column>user_id</column>
|
||||
<column>group_id</column>
|
||||
<column>user_pending</column>
|
||||
<row>
|
||||
<value>2</value>
|
||||
<value>3</value>
|
||||
<value>0</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>5</value>
|
||||
<value>1</value>
|
||||
<value>0</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>6</value>
|
||||
<value>2</value>
|
||||
<value>0</value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_zebra">
|
||||
<column>user_id</column>
|
||||
<column>zebra_id</column>
|
||||
<column>friend</column>
|
||||
<column>foe</column>
|
||||
<row>
|
||||
<value>2</value>
|
||||
<value>7</value>
|
||||
<value>1</value>
|
||||
<value>0</value>
|
||||
</row>
|
||||
</table>
|
||||
</dataset>
|
2
tests/mention/fixtures/services_mention.yml
Normal file
2
tests/mention/fixtures/services_mention.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
imports:
|
||||
- { resource: ../../../phpBB/config/default/container/services_mention.yml }
|
|
@ -33,6 +33,7 @@ abstract class phpbb_tests_notification_base extends phpbb_database_test_case
|
|||
'notification.type.disapprove_post',
|
||||
'notification.type.disapprove_topic',
|
||||
'notification.type.forum',
|
||||
'notification.type.mention',
|
||||
'notification.type.pm',
|
||||
'notification.type.post',
|
||||
'notification.type.post_in_queue',
|
||||
|
@ -73,6 +74,7 @@ abstract class phpbb_tests_notification_base extends phpbb_database_test_case
|
|||
'allow_topic_notify' => true,
|
||||
'allow_forum_notify' => true,
|
||||
'allow_board_notifications' => true,
|
||||
'allow_mentions' => true,
|
||||
));
|
||||
$lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
|
||||
$lang = new \phpbb\language\language($lang_loader);
|
||||
|
@ -105,6 +107,16 @@ abstract class phpbb_tests_notification_base extends phpbb_database_test_case
|
|||
$phpbb_container->set('cache.driver', $cache_driver);
|
||||
$phpbb_container->set('cache', $cache);
|
||||
$phpbb_container->set('text_formatter.utils', new \phpbb\textformatter\s9e\utils());
|
||||
$phpbb_container->set(
|
||||
'text_formatter.s9e.mention_helper',
|
||||
new \phpbb\textformatter\s9e\mention_helper(
|
||||
$this->db,
|
||||
$auth,
|
||||
$this->user,
|
||||
$phpbb_root_path,
|
||||
$phpEx
|
||||
)
|
||||
);
|
||||
$phpbb_container->set('dispatcher', $this->phpbb_dispatcher);
|
||||
$phpbb_container->setParameter('core.root_path', $phpbb_root_path);
|
||||
$phpbb_container->setParameter('core.php_ext', $phpEx);
|
||||
|
|
|
@ -44,6 +44,9 @@ services:
|
|||
text_formatter.s9e.quote_helper:
|
||||
synthetic: true
|
||||
|
||||
text_formatter.s9e.mention_helper:
|
||||
synthetic: true
|
||||
|
||||
text_formatter.parser:
|
||||
synthetic: true
|
||||
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<dataset>
|
||||
<table name="phpbb_groups">
|
||||
<column>group_id</column>
|
||||
<column>group_name</column>
|
||||
<column>group_type</column>
|
||||
<column>group_desc</column>
|
||||
<row>
|
||||
<value>1</value>
|
||||
<value>Normal group</value>
|
||||
<value>0</value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>2</value>
|
||||
<value>Hidden group</value>
|
||||
<value>2</value>
|
||||
<value></value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_notifications">
|
||||
<column>notification_id</column>
|
||||
<column>notification_type_id</column>
|
||||
<column>user_id</column>
|
||||
<column>item_id</column>
|
||||
<column>item_parent_id</column>
|
||||
<column>notification_read</column>
|
||||
<column>notification_data</column>
|
||||
<row>
|
||||
<value>1</value>
|
||||
<value>1</value>
|
||||
<value>5</value>
|
||||
<value>1</value>
|
||||
<value>1</value>
|
||||
<value>0</value>
|
||||
<value></value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_notification_types">
|
||||
<column>notification_type_id</column>
|
||||
<column>notification_type_name</column>
|
||||
<column>notification_type_enabled</column>
|
||||
<row>
|
||||
<value>1</value>
|
||||
<value>notification.type.mention</value>
|
||||
<value>1</value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_posts">
|
||||
<column>post_id</column>
|
||||
<column>topic_id</column>
|
||||
<column>forum_id</column>
|
||||
<column>post_text</column>
|
||||
<row>
|
||||
<value>1</value>
|
||||
<value>1</value>
|
||||
<value>1</value>
|
||||
<value></value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_topics">
|
||||
<column>topic_id</column>
|
||||
<column>forum_id</column>
|
||||
<row>
|
||||
<value>1</value>
|
||||
<value>1</value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_users">
|
||||
<column>user_id</column>
|
||||
<column>username_clean</column>
|
||||
<column>user_permissions</column>
|
||||
<column>user_sig</column>
|
||||
<row>
|
||||
<value>2</value>
|
||||
<value>poster</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>3</value>
|
||||
<value>test</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>4</value>
|
||||
<value>unauthorized</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>5</value>
|
||||
<value>notified</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>6</value>
|
||||
<value>disabled</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>7</value>
|
||||
<value>default</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>8</value>
|
||||
<value>member of normal group</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>9</value>
|
||||
<value>member of hidden group</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_user_group">
|
||||
<column>user_id</column>
|
||||
<column>group_id</column>
|
||||
<column>user_pending</column>
|
||||
<row>
|
||||
<value>8</value>
|
||||
<value>1</value>
|
||||
<value>0</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>9</value>
|
||||
<value>2</value>
|
||||
<value>0</value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_user_notifications">
|
||||
<column>item_type</column>
|
||||
<column>item_id</column>
|
||||
<column>user_id</column>
|
||||
<column>method</column>
|
||||
<column>notify</column>
|
||||
<row>
|
||||
<value>notification.type.mention</value>
|
||||
<value>0</value>
|
||||
<value>2</value>
|
||||
<value>notification.method.board</value>
|
||||
<value>1</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>notification.type.mention</value>
|
||||
<value>0</value>
|
||||
<value>3</value>
|
||||
<value>notification.method.board</value>
|
||||
<value>1</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>notification.type.mention</value>
|
||||
<value>0</value>
|
||||
<value>4</value>
|
||||
<value>notification.method.board</value>
|
||||
<value>1</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>notification.type.mention</value>
|
||||
<value>0</value>
|
||||
<value>5</value>
|
||||
<value>notification.method.board</value>
|
||||
<value>1</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>notification.type.mention</value>
|
||||
<value>0</value>
|
||||
<value>6</value>
|
||||
<value>notification.method.board</value>
|
||||
<value>0</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>notification.type.mention</value>
|
||||
<value>0</value>
|
||||
<value>8</value>
|
||||
<value>notification.method.board</value>
|
||||
<value>1</value>
|
||||
</row>
|
||||
</table>
|
||||
</dataset>
|
|
@ -91,6 +91,16 @@ class notification_method_email_test extends phpbb_tests_notification_base
|
|||
$phpbb_container->setParameter('tables.user_notifications', 'phpbb_user_notifications');
|
||||
$phpbb_container->setParameter('tables.notification_types', 'phpbb_notification_types');
|
||||
$phpbb_container->setParameter('tables.notification_emails', 'phpbb_notification_emails');
|
||||
$phpbb_container->set(
|
||||
'text_formatter.s9e.mention_helper',
|
||||
new \phpbb\textformatter\s9e\mention_helper(
|
||||
$this->db,
|
||||
$auth,
|
||||
$this->user,
|
||||
$phpbb_root_path,
|
||||
$phpEx
|
||||
)
|
||||
);
|
||||
|
||||
$this->notification_method_email = $this->getMockBuilder('\phpbb\notification\method\email')
|
||||
->setConstructorArgs([
|
||||
|
|
|
@ -59,6 +59,7 @@ class phpbb_notification_test extends phpbb_tests_notification_base
|
|||
self::assertArrayHasKey('NOTIFICATION_GROUP_POSTING', $subscription_types);
|
||||
|
||||
self::assertArrayHasKey('notification.type.bookmark', $subscription_types['NOTIFICATION_GROUP_POSTING']);
|
||||
self::assertArrayHasKey('notification.type.mention', $subscription_types['NOTIFICATION_GROUP_POSTING']);
|
||||
self::assertArrayHasKey('notification.type.post', $subscription_types['NOTIFICATION_GROUP_POSTING']);
|
||||
self::assertArrayHasKey('notification.type.quote', $subscription_types['NOTIFICATION_GROUP_POSTING']);
|
||||
self::assertArrayHasKey('notification.type.topic', $subscription_types['NOTIFICATION_GROUP_POSTING']);
|
||||
|
@ -73,6 +74,7 @@ class phpbb_notification_test extends phpbb_tests_notification_base
|
|||
{
|
||||
$expected_subscriptions = array(
|
||||
'notification.type.forum' => array('notification.method.board'),
|
||||
'notification.type.mention' => array('notification.method.board'),
|
||||
'notification.type.post' => array('notification.method.board'),
|
||||
'notification.type.topic' => array('notification.method.board'),
|
||||
'notification.type.quote' => array('notification.method.board'),
|
||||
|
|
|
@ -70,6 +70,8 @@ abstract class phpbb_notification_submit_post_base extends phpbb_database_test_c
|
|||
array('f_noapprove', 1, true),
|
||||
array('f_postcount', 1, true),
|
||||
array('m_edit', 1, false),
|
||||
array('f_mention', 1, true),
|
||||
array('u_mention', 0, true),
|
||||
)));
|
||||
|
||||
// Config
|
||||
|
@ -77,6 +79,7 @@ abstract class phpbb_notification_submit_post_base extends phpbb_database_test_c
|
|||
'num_topics' => 1,
|
||||
'num_posts' => 1,
|
||||
'allow_board_notifications' => true,
|
||||
'allow_mentions' => true,
|
||||
));
|
||||
|
||||
$cache_driver = new \phpbb\cache\driver\dummy();
|
||||
|
@ -132,6 +135,16 @@ abstract class phpbb_notification_submit_post_base extends phpbb_database_test_c
|
|||
$phpbb_container->set('cache.driver', $cache_driver);
|
||||
$phpbb_container->set('cache', $cache);
|
||||
$phpbb_container->set('text_formatter.utils', new \phpbb\textformatter\s9e\utils());
|
||||
$phpbb_container->set(
|
||||
'text_formatter.s9e.mention_helper',
|
||||
new \phpbb\textformatter\s9e\mention_helper(
|
||||
$this->db,
|
||||
$auth,
|
||||
$user,
|
||||
$phpbb_root_path,
|
||||
$phpEx
|
||||
)
|
||||
);
|
||||
$phpbb_container->set('dispatcher', $phpbb_dispatcher);
|
||||
$phpbb_container->set('storage.attachment', $storage);
|
||||
$phpbb_container->setParameter('core.root_path', $phpbb_root_path);
|
||||
|
@ -145,7 +158,7 @@ abstract class phpbb_notification_submit_post_base extends phpbb_database_test_c
|
|||
$phpbb_container->compile();
|
||||
|
||||
// Notification Types
|
||||
$notification_types = array('quote', 'bookmark', 'post', 'post_in_queue', 'topic', 'topic_in_queue', 'approve_topic', 'approve_post', 'forum');
|
||||
$notification_types = array('quote', 'mention', 'bookmark', 'post', 'post_in_queue', 'topic', 'topic_in_queue', 'approve_topic', 'approve_post', 'forum');
|
||||
$notification_types_array = array();
|
||||
foreach ($notification_types as $type)
|
||||
{
|
||||
|
|
129
tests/notification/submit_post_type_mention_test.php
Normal file
129
tests/notification/submit_post_type_mention_test.php
Normal file
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
require_once dirname(__FILE__) . '/submit_post_base.php';
|
||||
|
||||
class phpbb_notification_submit_post_type_mention_test extends phpbb_notification_submit_post_base
|
||||
{
|
||||
protected $item_type = 'notification.type.mention';
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
global $auth;
|
||||
|
||||
// Add additional permissions
|
||||
$auth->expects($this->any())
|
||||
->method('acl_get_list')
|
||||
->with($this->anything(),
|
||||
$this->stringContains('_'),
|
||||
$this->greaterThan(0))
|
||||
->will($this->returnValueMap(array(
|
||||
array(
|
||||
array(3, 4, 5, 6, 7, 8, 10),
|
||||
'f_read',
|
||||
1,
|
||||
array(
|
||||
1 => array(
|
||||
'f_read' => array(3, 5, 6, 7, 8),
|
||||
),
|
||||
),
|
||||
),
|
||||
)));
|
||||
$auth->expects($this->any())
|
||||
->method('acl_gets')
|
||||
->with('a_group', 'a_groupadd', 'a_groupdel')
|
||||
->will($this->returnValue(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* submit_post() Notifications test
|
||||
*
|
||||
* submit_post() $mode = 'reply'
|
||||
* Notification item_type = 'mention'
|
||||
*/
|
||||
public function submit_post_data()
|
||||
{
|
||||
// The new mock container is needed because the data providers may be executed before phpunit call setUp()
|
||||
$parser = $this->get_test_case_helpers()->set_s9e_services(new phpbb_mock_container_builder())->get('text_formatter.parser');
|
||||
|
||||
return array(
|
||||
/**
|
||||
* Normal post
|
||||
*
|
||||
* User => State description
|
||||
* 2 => Poster, should NOT receive a notification
|
||||
* 3 => mentioned, should receive a notification
|
||||
* 4 => mentioned, but unauthed to read, should NOT receive a notification
|
||||
* 5 => mentioned, but already notified, should STILL receive a new notification
|
||||
* 6 => mentioned, but option disabled, should NOT receive a notification
|
||||
* 7 => mentioned, option set to default, should receive a notification
|
||||
* 8 => mentioned as a member of group 1, should receive a notification
|
||||
*/
|
||||
array(
|
||||
array(
|
||||
'message' => $parser->parse(implode(' ', array(
|
||||
'[mention=u:2]poster[/mention] poster should not be notified',
|
||||
'[mention=u:3]test[/mention] test should be notified',
|
||||
'[mention=u:4]unauthorized[/mention] unauthorized to read, should not receive a notification',
|
||||
'[mention=u:5]notified[/mention] already notified, should not receive a new notification',
|
||||
'[mention=u:6]disabled[/mention] option disabled, should not receive a notification',
|
||||
'[mention=u:7]default[/mention] option set to default, should receive a notification',
|
||||
'[mention=g:1]normal group[/mention] group members of a normal group shoud receive a notification',
|
||||
'[mention=g:2]hidden group[/mention] group members of a hidden group shoud not receive a notification from a non-member',
|
||||
'[mention=u:10]doesn\'t exist[/mention] user does not exist, should not receive a notification',
|
||||
))),
|
||||
'bbcode_uid' => 'uid',
|
||||
),
|
||||
array(
|
||||
array('user_id' => 5, 'item_id' => 1, 'item_parent_id' => 1),
|
||||
),
|
||||
array(
|
||||
array('user_id' => 3, 'item_id' => 2, 'item_parent_id' => 1),
|
||||
array('user_id' => 5, 'item_id' => 1, 'item_parent_id' => 1),
|
||||
array('user_id' => 5, 'item_id' => 2, 'item_parent_id' => 1),
|
||||
array('user_id' => 7, 'item_id' => 2, 'item_parent_id' => 1),
|
||||
array('user_id' => 8, 'item_id' => 2, 'item_parent_id' => 1),
|
||||
),
|
||||
),
|
||||
|
||||
/**
|
||||
* Unapproved post
|
||||
*
|
||||
* No new notifications
|
||||
*/
|
||||
array(
|
||||
array(
|
||||
'message' => $parser->parse(implode(' ', array(
|
||||
'[mention=u:2]poster[/mention] poster should not be notified',
|
||||
'[mention=u:3]test[/mention] test should be notified',
|
||||
'[mention=u:4]unauthorized[/mention] unauthorized to read, should not receive a notification',
|
||||
'[mention=u:5]notified[/mention] already notified, should not receive a new notification',
|
||||
'[mention=u:6]disabled[/mention] option disabled, should not receive a notification',
|
||||
'[mention=u:7]default[/mention] option set to default, should receive a notification',
|
||||
'[mention=u:8]doesn\'t exist[/mention] user does not exist, should not receive a notification',
|
||||
))),
|
||||
'bbcode_uid' => 'uid',
|
||||
'force_approved_state' => false,
|
||||
),
|
||||
array(
|
||||
array('user_id' => 5, 'item_id' => 1, 'item_parent_id' => 1),
|
||||
),
|
||||
array(
|
||||
array('user_id' => 5, 'item_id' => 1, 'item_parent_id' => 1),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -579,6 +579,9 @@ class phpbb_test_case_helpers
|
|||
}
|
||||
$user->add_lang('common');
|
||||
|
||||
// Get an auth interface
|
||||
$auth = ($container->has('auth')) ? $container->get('auth') : new \phpbb\auth\auth;
|
||||
|
||||
// Create and register a quote_helper
|
||||
$quote_helper = new \phpbb\textformatter\s9e\quote_helper(
|
||||
$container->get('user'),
|
||||
|
@ -587,6 +590,16 @@ class phpbb_test_case_helpers
|
|||
);
|
||||
$container->set('text_formatter.s9e.quote_helper', $quote_helper);
|
||||
|
||||
// Create and register a mention_helper
|
||||
$mention_helper = new \phpbb\textformatter\s9e\mention_helper(
|
||||
($container->has('dbal.conn')) ? $container->get('dbal.conn') : $db_driver,
|
||||
$auth,
|
||||
$container->get('user'),
|
||||
$phpbb_root_path,
|
||||
$phpEx
|
||||
);
|
||||
$container->set('text_formatter.s9e.mention_helper', $mention_helper);
|
||||
|
||||
// Create and register the text_formatter.s9e.parser service and its alias
|
||||
$parser = new \phpbb\textformatter\s9e\parser(
|
||||
$cache,
|
||||
|
@ -607,8 +620,8 @@ class phpbb_test_case_helpers
|
|||
);
|
||||
|
||||
// Calls configured in services.yml
|
||||
$auth = ($container->has('auth')) ? $container->get('auth') : new \phpbb\auth\auth;
|
||||
$renderer->configure_quote_helper($quote_helper);
|
||||
$renderer->configure_mention_helper($mention_helper);
|
||||
$renderer->configure_smilies_path($config, $path_helper);
|
||||
$renderer->configure_user($user, $config, $auth);
|
||||
|
||||
|
|
116
tests/text_formatter/s9e/fixtures/mention.xml
Normal file
116
tests/text_formatter/s9e/fixtures/mention.xml
Normal file
|
@ -0,0 +1,116 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<dataset>
|
||||
<table name="phpbb_groups">
|
||||
<column>group_id</column>
|
||||
<column>group_name</column>
|
||||
<column>group_type</column>
|
||||
<column>group_colour</column>
|
||||
<column>group_desc</column>
|
||||
<row>
|
||||
<value>1</value>
|
||||
<value>Normal group</value>
|
||||
<value>0</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>2</value>
|
||||
<value>Hidden group</value>
|
||||
<value>2</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>3</value>
|
||||
<value>Hidden group we are a member of</value>
|
||||
<value>2</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_users">
|
||||
<column>user_id</column>
|
||||
<column>username</column>
|
||||
<column>username_clean</column>
|
||||
<column>user_type</column>
|
||||
<column>user_lastvisit</column>
|
||||
<column>user_colour</column>
|
||||
<column>user_permissions</column>
|
||||
<column>user_sig</column>
|
||||
<row>
|
||||
<value>2</value>
|
||||
<value>myself</value>
|
||||
<value>myself</value>
|
||||
<value>0</value>
|
||||
<value>0</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>3</value>
|
||||
<value>test</value>
|
||||
<value>test</value>
|
||||
<value>0</value>
|
||||
<value>0</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>4</value>
|
||||
<value>group_member_normal</value>
|
||||
<value>group_member_normal</value>
|
||||
<value>0</value>
|
||||
<value>0</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>5</value>
|
||||
<value>group_member_hidden</value>
|
||||
<value>group_member_hidden</value>
|
||||
<value>0</value>
|
||||
<value>0</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
<row>
|
||||
<value>6</value>
|
||||
<value>group_member_visible</value>
|
||||
<value>group_member_visible</value>
|
||||
<value>0</value>
|
||||
<value>0</value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
<value></value>
|
||||
</row>
|
||||
</table>
|
||||
<table name="phpbb_user_group">
|
||||
<column>user_id</column>
|
||||
<column>group_id</column>
|
||||
<column>user_pending</column>
|
||||
<row>
|
||||
<value>2</value>
|
||||
<value>3</value>
|
||||
<value>0</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>4</value>
|
||||
<value>1</value>
|
||||
<value>0</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>5</value>
|
||||
<value>2</value>
|
||||
<value>0</value>
|
||||
</row>
|
||||
<row>
|
||||
<value>6</value>
|
||||
<value>3</value>
|
||||
<value>0</value>
|
||||
</row>
|
||||
</table>
|
||||
</dataset>
|
123
tests/text_formatter/s9e/mention_helper_test.php
Normal file
123
tests/text_formatter/s9e/mention_helper_test.php
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class mention_helper_test extends phpbb_database_test_case
|
||||
{
|
||||
protected $db, $container, $user, $auth;
|
||||
|
||||
/**
|
||||
* @var \phpbb\textformatter\s9e\mention_helper
|
||||
*/
|
||||
protected $mention_helper;
|
||||
|
||||
public function getDataSet()
|
||||
{
|
||||
return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/mention.xml');
|
||||
}
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
global $auth, $db, $cache, $phpbb_container, $phpEx, $phpbb_root_path;
|
||||
|
||||
// Disable caching for this test class
|
||||
$cache = null;
|
||||
|
||||
// Database
|
||||
$this->db = $this->new_dbal();
|
||||
$db = $this->db;
|
||||
|
||||
// Auth
|
||||
$auth = $this->createMock('\phpbb\auth\auth');
|
||||
$auth->expects($this->any())
|
||||
->method('acl_gets')
|
||||
->with('a_group', 'a_groupadd', 'a_groupdel')
|
||||
->willReturn(false)
|
||||
;
|
||||
|
||||
// Language
|
||||
$lang = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
|
||||
|
||||
// User
|
||||
$user = $this->createMock('\phpbb\user', array(), array(
|
||||
$lang,
|
||||
'\phpbb\datetime'
|
||||
));
|
||||
$user->ip = '';
|
||||
$user->data = array(
|
||||
'user_id' => 2,
|
||||
'username' => 'myself',
|
||||
'is_registered' => true,
|
||||
'user_colour' => '',
|
||||
);
|
||||
|
||||
// Container
|
||||
$phpbb_container = new phpbb_mock_container_builder();
|
||||
|
||||
$phpbb_container->set('dbal.conn', $db);
|
||||
$phpbb_container->set('auth', $auth);
|
||||
$phpbb_container->set('user', $user);
|
||||
|
||||
$this->get_test_case_helpers()->set_s9e_services($phpbb_container);
|
||||
|
||||
$this->mention_helper = $phpbb_container->get('text_formatter.s9e.mention_helper');
|
||||
}
|
||||
|
||||
public function inject_metadata_data()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'<r><MENTION user_id="3"><s>[mention=u:3]</s>test<e>[/mention]</e></MENTION></r>',
|
||||
'mode=viewprofile&u=3',
|
||||
],
|
||||
[
|
||||
'<r><MENTION group_id="3"><s>[mention=g:3]</s>test<e>[/mention]</e></MENTION></r>',
|
||||
'mode=group&g=3',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider inject_metadata_data
|
||||
*/
|
||||
public function test_inject_metadata($incoming_xml, $expected_profile_substring)
|
||||
{
|
||||
$result = $this->mention_helper->inject_metadata($incoming_xml);
|
||||
$this->assertStringContainsString($expected_profile_substring, $result);
|
||||
}
|
||||
|
||||
public function get_mentioned_user_ids_data()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'<r><MENTION user_id="3"><s>[mention=u:3]</s>test<e>[/mention]</e></MENTION><MENTION user_id="4"><s>[mention=u:4]</s>test<e>[/mention]</e></MENTION><MENTION user_id="5"><s>[mention=u:5]</s>test<e>[/mention]</e></MENTION></r>',
|
||||
[3, 4, 5],
|
||||
],
|
||||
[
|
||||
'<r><MENTION group_id="1"><s>[mention=g:1]</s>test<e>[/mention]</e></MENTION><MENTION group_id="2"><s>[mention=g:2]</s>test<e>[/mention]</e></MENTION><MENTION group_id="3"><s>[mention=g:3]</s>test<e>[/mention]</e></MENTION></r>',
|
||||
[4, 2, 6],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider get_mentioned_user_ids_data
|
||||
*/
|
||||
public function test_get_mentioned_user_ids($incoming_xml, $expected_result)
|
||||
{
|
||||
$this->assertSame($expected_result, $this->mention_helper->get_mentioned_user_ids($incoming_xml));
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue