<?php
/**
* SeekQuarry/Yioop --
* Open Source Pure PHP Search Engine, Crawler, and Indexer
*
* Copyright (C) 2009 - 2026 Chris Pollett chris@pollett.org
*
* LICENSE:
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* END LICENSE
*
* @author Chris Pollett chris@pollett.org
* @license https://www.gnu.org/licenses/ GPL3
* @link https://www.seekquarry.com/
* @copyright 2009 - 2026
* @filesource
*/
namespace seekquarry\yioop\controllers\components;
use seekquarry\yioop\configs as C;
use seekquarry\yioop\library as L;
use seekquarry\yioop\library\mail as ML;
/**
* Translate the supplied arguments into the current locale.
*
* This function is a convenience copy of the same function
* @see seekquarry\yioop\library\tl() to this subnamespace
*
* @param string string_identifier identifier to be translated
* @param mixed additional_args used for interpolation in translated string
* @return string translated string
*/
function tl()
{
return call_user_func_array(C\NS_LIB . "tl", func_get_args());
}
/**
* shorthand for echo
*
* @param string $text string to send to the current output
*/
function e($text)
{
echo $text;
}
/**
* Base component class for all components on
* the SeekQuarry site. A component consists of a collection of
* activities and their auxiliary methods that can be used by a controller
*
* @author Chris Pollett
*/
class Component
{
/**
* Reference to the controller this component lives on
*
* @var object
*/
public $parent = null;
/**
* Sets up this component by storing in its parent field a reference to
* controller this component lives on
*
* @param object $parent_controller reference to the controller this
* component lives on
*/
public function __construct($parent_controller)
{
$this->parent = $parent_controller;
}
/**
* Called to include the Javascript Wiki Editor (wiki.js) on a page
* and to send any localizations needed from PHP to Javascript-land
* It is used by both Crawl and SocialComponent
*
* @param array &$data an asscoiative array of data to be used by the
* view and layout that the wiki editor will be drawn on
* This method tacks on to INCLUDE_SCRIPTS to make the layout load
* wiki.js.
* @param $id if "" then all textareas on page will get editor buttons,
* if -1 then sets up translations, but does not add any button,
* otherwise, add buttons to textarea $id will. (Can call this method
* multiple times, if want more than one but not all)
*/
public function initializeWikiEditor(&$data, $id = "")
{
if (!isset($data["WIKI_INITIALIZED"]) || !$data["WIKI_INITIALIZED"]) {
$data["INCLUDE_SCRIPTS"] ??= [];
$data["INCLUDE_SCRIPTS"][] = "wiki";
$data["WIKI_INITIALIZED"] = true;
//set up an array of translation for javascript-land
$data['SCRIPT'] ??= "";
$data['SCRIPT'] .= "\ntl = {".
'wiki_js_small :"'. tl('wiki_js_small') .'",' .
'wiki_js_medium :"'. tl('wiki_js_medium').'",'.
'wiki_js_large :"'. tl('wiki_js_large').'",'.
'wiki_js_search_size :"'. tl('wiki_js_search_size').'",'.
'wiki_js_prompt_heading :"'. tl('wiki_js_prompt_heading').'",'.
'wiki_js_example :"'. tl('wiki_js_example').'",'.
'wiki_js_table_title :"'. tl('wiki_js_table_title').'",'.
'wiki_js_submit :"'. tl('wiki_js_submit').'",'.
'wiki_js_cancel :"'. tl('wiki_js_cancel').'",'.
'wiki_js_bold :"'. tl('wiki_js_bold') . '",' .
'wiki_js_italic :"'. tl('wiki_js_italic').'",'.
'wiki_js_underline :"'. tl('wiki_js_underline').'",'.
'wiki_js_strike :"'. tl('wiki_js_strike').'",'.
'wiki_js_hr :"'. tl('wiki_js_hr').'",'.
'wiki_js_heading :"'. tl('wiki_js_heading').'",'.
'wiki_js_heading1 :"'. tl('wiki_js_heading1').'",'.
'wiki_js_heading2 :"'. tl('wiki_js_heading2').'",'.
'wiki_js_heading3 :"'. tl('wiki_js_heading3').'",'.
'wiki_js_heading4 :"'. tl('wiki_js_heading4').'",'.
'wiki_js_bullets :"'. tl('wiki_js_bullet').'",'.
'wiki_js_bullet :"'. tl('wiki_js_bullet').'",'.
'wiki_js_numbers :"'. tl('wiki_js_enum') .'",'.
'wiki_js_enum :"'. tl('wiki_js_enum') .'",'.
'wiki_js_nowiki :"'. tl('wiki_js_nowiki') .'",'.
'wiki_js_add_search :"'.tl('wiki_js_add_search') .'",'.
'wiki_js_search_size :"'. tl('wiki_js_search_size') .'",'.
'wiki_js_add_wiki_table :"'. tl('wiki_js_add_wiki_table').'",'.
'wiki_js_for_table_cols :"'. tl('wiki_js_for_table_cols').'",'.
'wiki_js_for_table_rows :"'. tl('wiki_js_for_table_rows').'",'.
'wiki_js_hyperlink :"'. tl('wiki_js_add_hyperlink').'",'.
'wiki_js_add_hyperlink :"'. tl('wiki_js_add_hyperlink').'",'.
'wiki_js_link_text :"'. tl('wiki_js_link_text').'",'.
'wiki_js_link_url :"'. tl('wiki_js_link_url').'",'.
'wiki_js_placeholder :"'. tl('wiki_js_placeholder').'",'.
'wiki_js_centeraligned :"'. tl('wiki_js_centeraligned').'",'.
'wiki_js_rightaligned :"'. tl('wiki_js_rightaligned').'",'.
'wiki_js_leftaligned :"'. tl('wiki_js_leftaligned').'",'.
'wiki_js_definitionlist :"'.
tl('wiki_js_definitionlist').'",'.
'wiki_js_definitionlist_item :"'.
tl('wiki_js_definitionlist_item').'",'.
'wiki_js_definitionlist_definition :"'.
tl('wiki_js_definitionlist_definition').'",'.
'wiki_js_slide :"'.
tl('wiki_js_slide').'",'.
'wiki_js_slide_sample_title :"'.
tl('wiki_js_slide_sample_title').'",'.
'wiki_js_slide_sample_bullet :"'.
tl('wiki_js_slide_sample_bullet').'",'.
'wiki_js_resource_description : "'.
tl('wiki_js_resource_description').'", '.
'wiki_element_list_icon :"'. tl('wiki_element_list_icon').'",'.
'wiki_element_grid_icon :"'. tl('wiki_element_grid_icon').'",'.
'wiki_js_summarizing :"'. tl('wiki_js_summarizing').'",'.
'wiki_js_summary_unavailable :"'.
tl('wiki_js_summary_unavailable').'",'.
'wiki_js_render_engine:"'.
($data['RENDER_ENGINE'] ?? 'mediawiki') .'",'.
'};';
}
if ($id != -1) {
if ($id == "") {
$data['SCRIPT'] .= "editorizeAll();\n";
} else {
$data['SCRIPT'] .= "editorize('$id');\n";
}
}
}
/**
* Used to compute statistics for badges related for the manage crawls,
* mix crawls, and manage machine buttons shown typically to admin accounts
*
* @param int $user_id of user - used to determin the mix crawl list
* @param array &$data associative array of data to send to the view.
* This method adds three new field NUM_MIXES, CRAWL_MANAGER,
* "NUM_MACHINES, CRAWLS_RUNNING, and NUM_CLOSED_CRAWLS
*/
public function initCrawlBadges($user_id, &$data)
{
$parent = $this->parent;
$crawl_model = $parent->model("crawl");
$data['NUM_MIXES'] = count($crawl_model->getMixList($user_id));
$data["CRAWL_MANAGER"] = true;
$machine_urls = $parent->model("machine")->getQueueServerUrls();
$data["NUM_MACHINES"] = count($machine_urls);
list($stalled, $status, $recent_crawls) =
$crawl_model->combinedCrawlInfo($machine_urls, true);
$data["CRAWLS_RUNNING"] = 0;
$data["NUM_CLOSED_CRAWLS"] = count($recent_crawls);
foreach ($status as $channel => $channel_status) {
if (!empty($channel_status['CRAWL_TIME'])) {
$data["CRAWLS_RUNNING"]++;
$data["NUM_CLOSED_CRAWLS"]--;
}
}
}
/**
* Used to compute the impression statistics for badges on the
* social controls button for $user_id. These badges
* display the number of unread messages, the number of unread group post
* and the number of groups the user belongs to
* @param int $user_id id of user to compute statistics for
* @param array &$data associative array of data to send to the view.
* This method adds four new fields NUM_GROUPS, UNREAD_POSTS,
* UNREAD_MESSAGES, and UNREAD_MAIL
*/
public function initSocialBadges($user_id, &$data)
{
$parent = $this->parent;
$group_model = $parent->model("group");
$impression_model = $parent->model("impression");
$data['NUM_GROUPS'] = $group_model->countUserGroups($user_id);
$timestamp = $impression_model->mostRecentGroupView($user_id);
$data['UNREAD_POSTS'] = $group_model->getUserPostCount($user_id,
$timestamp);
$personal_group_id = $group_model->getPersonalGroupId($user_id);
$contact_ids = array_diff($group_model->getGroupUserIds(
$personal_group_id), [$user_id]);
$chat_ids = [];
$unread_count = 0;
foreach ($contact_ids as $contact_id) {
$chat_id = $group_model->getGroupThreadId(
$personal_group_id, $user_id,
$group_model->getMessagesThreadTitle(
[$user_id, $contact_id]));
if (empty($chat_id)) {
continue;
}
$chat_stamp = $impression_model->mostRecentThreadView($user_id,
$chat_id);
$unread_count += floor($group_model->getThreadPostCount($chat_id,
$chat_stamp) / 2);
}
$data['UNREAD_MESSAGES'] = $unread_count;
$data['UNREAD_MAIL'] = ML\MailUnreadProbe::cachedCount(
$user_id);
}
}