Commit 7acb04a2 authored by jonnybradley's avatar jonnybradley

[MRG] Automatic merge, trunk 61665 to 61690

Conflicts fixed on lib/setup/prefs.php and property conflict fixed on templates
parent c3022c5c
......@@ -2638,12 +2638,14 @@ lib/core/Services/Draw/Controller.php -text
lib/core/Services/Draw/index.php -text
lib/core/Services/Edit/Controller.php -text
lib/core/Services/Edit/PluginController.php -text
lib/core/Services/Edit/SemaphoreController.php -text
lib/core/Services/Edit/index.php -text
lib/core/Services/Exception.php -text
lib/core/Services/Exception/BadRequest.php -text
lib/core/Services/Exception/Denied.php -text
lib/core/Services/Exception/Disabled.php -text
lib/core/Services/Exception/DuplicateValue.php -text
lib/core/Services/Exception/EditConflict.php -text
lib/core/Services/Exception/FieldError.php -text
lib/core/Services/Exception/MissingValue.php -text
lib/core/Services/Exception/NotAvailable.php -text
......
......@@ -29,7 +29,6 @@ lang/.htaccess
/last.log
lib/.htaccess
lib/core/Tracker/Filter/Control/DateRange[!!-~](1).php
lib/smarty
lib/test/clover.xml
lib/test/core/Search/Index/test_index
lib/test/core/Search/test_index
......
......@@ -55,6 +55,7 @@
<service id="tiki.controller.search_customsearch" class="Services_Search_CustomSearchController"/>
<service id="tiki.controller.search_manifold" class="Services_Search_ManifoldController"/>
<service id="tiki.controller.search_stored" class="Services_Search_StoredController"/>
<service id="tiki.controller.semaphore" class="Services_Edit_SemaphoreController"/>
<service id="tiki.controller.showtikiorg" class="Services_ShowTikiOrg_Controller"/>
<service id="tiki.controller.social" class="Services_User_SocialController"/>
<service id="tiki.controller.suite" class="Services_Suite_Controller"/>
......
......@@ -792,34 +792,42 @@ syntaxHighlighter = {
$(function() {
$('textarea')
.flexibleSyntaxHighlighter();
$('.codelisting')
.flexibleSyntaxHighlighter({
$('.codelisting').each(function () {
$(this).flexibleSyntaxHighlighter({
readOnly: true,
mode: 'null',
width: $(this).width() + 'px',
height: $(this).parent().height() + 'px'
});
})
});
//for plugin code
$(document)
.off('plugin_code_ready')
.on('plugin_code_ready', function(args) {
var colors = args.container.find('#param_colors input:first').hide();
var colorsSelector = $('<select class="form-control"/>')
.insertAfter(colors)
.change(function() {
colors.val(colorsSelector.val());
})
.mousedown(function() {
colorsSelector.change();
})
.mouseup(function() {
colorsSelector.change();
})
.click(function() {
colorsSelector.change();
.on('plugin_code_ready', function (args) {
var updateTextarea = function () {
colors.val(colorsSelector.val());
code.flexibleSyntaxHighlighter({
mode: colorsSelector.val(),
lineNumbers: ln.val() === "1",
theme: theme.val(),
force: true
});
};
var colors = args.modal.find('#param_colors_input').hide(),
ln = args.modal.find('#param_ln_input').change(function () {
updateTextarea.call(this);
}),
theme = args.modal.find('#param_theme_input').change(function () {
updateTextarea.call(this);
}),
code = args.modal.find('textarea[name=content]'),
colorsSelector = $('<select class="form-control"/>')
.insertAfter(colors)
.change(function () {
updateTextarea.call(this);
});
var modes = CodeMirror.modes;
for(var i in modes) {
......@@ -828,15 +836,9 @@ $(function() {
}
}
colorsSelector.val(colors.val());
colorsSelector.val(colors.val()).change();
var code = args.container.find('textarea[name=\"content\"]');
code.flexibleSyntaxHighlighter({
mode: colorsSelector.val(),
lineNumbers: true,
force: true
});
if (codeMirrorTheme == "off") {
if (codeMirrorTheme === "off") {
$(".cm-remove").click(); // cheap fix to have codemirror available but off by default
}
});
......@@ -845,7 +847,7 @@ $(function() {
$(document)
.off('plugin_html_ready')
.on('plugin_html_ready', function(args) {
var code = args.container.find('textarea:first');
var code = args.modal.find('textarea:first');
code.flexibleSyntaxHighlighter({
mode: 'xml',
......@@ -858,7 +860,7 @@ $(function() {
$(document)
.off('plugin_r_ready')
.on('plugin_r_ready', function(args) {
var r = args.container.find('textarea:first');
var r = args.modal.find('textarea:first');
r.flexibleSyntaxHighlighter({
mode: 'r',
......@@ -871,7 +873,7 @@ $(function() {
$(document)
.off('plugin_rr_ready')
.on('plugin_rr_ready', function(args) {
var r = args.container.find('textarea:first');
var r = args.modal.find('textarea:first');
r.flexibleSyntaxHighlighter({
mode: 'r',
......
......@@ -92,7 +92,8 @@ class Services_AutoSave_Controller
if ($referer && count($referer) === 3 && $referer[1] === 'wiki_page') {
$page = rawurldecode($referer[2]); // plugins use global $page for approval
$isok = Perms::get('wiki page', $page)->edit && $user === TikiLib::lib('tiki')->get_semaphore_user($page);
$isok = Perms::get('wiki page', $page)->edit &&
$user === TikiLib::lib('service')->internal('semaphore', 'get_user', ['object_id' => $page, 'check' => 1]);
}
return $isok;
......
......@@ -80,7 +80,7 @@ class Services_Edit_Controller
$page = $autoSaveIdParts[2]; // plugins use global $page for approval
if (!Perms::get('wiki page', $page)->edit || $user != $tikilib->get_semaphore_user($page)) {
if (!Perms::get('wiki page', $page)->edit || $user != TikiLib::lib('service')->internal('semaphore', 'get_user', ['object_id' => $page, 'check' => 1])) {
return '';
}
......@@ -229,7 +229,8 @@ $(window).on("load", function(){
$page = $autoSaveIdParts[2]; // plugins use global $page for approval
}
if (!Perms::get('wiki page', $page)->edit || $user != $tikilib->get_semaphore_user($page)) {
if (!Perms::get('wiki page', $page)->edit || $user != TikiLib::lib('service')->internal('semaphore', 'get_user', ['object_id' => $page, 'check' => 1])
) {
return false;
}
......
......@@ -97,7 +97,7 @@ class Services_Edit_PluginController
$page = $input->page->pagename();
$pluginArgs = $input->pluginArgs->array();
$bodyContent = $input->bodyContent->wikicontent();
$edit_icon = $input->edit_icon->text();
$edit_icon = $input->edit_icon->int();
$selectedMod = $input->selectedMod->text();
$tikilib = TikiLib::lib('tiki');
......@@ -111,11 +111,18 @@ class Services_Edit_PluginController
}
}
Services_Exception_EditConflict::checkSemaphore($page);
if ($edit_icon) {
TikiLib::lib('service')->internal('semaphore', 'set', ['object_id' => $page]);
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$this->action_replace($input);
TikiLib::lib('service')->internal('semaphore', 'unset', ['object_id' => $page]);
return [
'redirect' => TikiLib::lib('wiki')->sefurl($page),
];
......@@ -192,7 +199,7 @@ class Services_Edit_PluginController
'selectedMod' => $selectedMod,
'info' => $info,
'title' => $type,
'title' => $info['name'],
];
}
}
......
<?php
// (c) Copyright 2002-2016 by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
/**
* Class Services_Semaphore_Controller
*
* Controller for warning on edit conflicts
*
*/
class Services_Edit_SemaphoreController
{
/** @var TikiDb_Table */
private $table;
function setUp()
{
Services_Exception_Disabled::check('feature_wiki');
Services_Exception_Disabled::check('feature_warn_on_edit');
$this->table = TikiDb::get()->table('tiki_semaphores');
}
/**
* @param JitFilter $input
* @return mixed
*/
function action_set($input)
{
global $user;
if ($user == '') {
$user = 'anonymous';
}
$object_id = $input->object_id->pagename();
$object_type = $input->object_type->pagename();
$object_type = $object_type ? $object_type : 'wiki page';
$now = TikiLib::lib('tiki')->now;
$this->table->delete(array('semName' => $object_id, 'objectType' => $object_type));
$this->table->insert(
array(
'semName' => $object_id,
'objectType' => $object_type,
'timestamp' => $now,
'user' => $user,
)
);
$_SESSION[$this->getSessionId($input)] = $now;
return $now;
}
/**
* @param JitFilter $input
* @return mixed
*/
function action_unset($input)
{
$object_id = $input->object_id->pagename();
$object_type = $input->object_type->pagename();
$object_type = $object_type ? $object_type : 'wiki page';
$lock = $input->lock->int();
$lock = $lock ? $lock : $_SESSION[$this->getSessionId($input)];
$this->table->delete(
[
'semName' => $object_id,
'timestamp' => (int)$lock,
'objectType' => $object_type,
]
);
unset($_SESSION[$this->getSessionId($input)]);
}
/**
* @param JitFilter $input
* @return mixed
*/
function action_is_set($input)
{
global $prefs;
$object_id = $input->object_id->pagename();
$object_type = $input->object_type->pagename();
$object_type = $object_type ? $object_type : 'wiki page';
$limit = $input->limit->int();
if (! $limit) {
$limit = (int)$prefs['warn_on_edit_time'] * 60;
}
$lim = TikiLib::lib('tiki')->now - $limit;
// remove expired ones
$this->table->deleteMultiple(array('timestamp' => $this->table->lesserThan((int)$lim)));
return (
$this->table->fetchCount([
'semName' => $object_id,
'objectType' => $object_type,
]) > 0
);
}
/**
* @param JitFilter $input
* @return mixed
*/
function action_get_user($input)
{
global $user;
if (! $input->check->int()) {
if (! $this->action_is_set($input)) {
return '';
}
}
$object_id = $input->object_id->pagename();
$object_type = $input->object_type->pagename();
$object_type = $object_type ? $object_type : 'wiki page';
$semUser = $this->table->fetchOne(
'user',
[
'semName' => $object_id,
'objectType' => $object_type,
]
);
if ($semUser && $semUser != $user || (! $user && $semUser === 'anonymous')) {
return $semUser;
} else {
return $user;
}
}
private function getSessionId($input) {
$object_id = $input->object_id->pagename();
$object_type = $input->object_type->pagename();
$object_type = $object_type ? $object_type : 'wiki page';
return 'semaphore_' .
str_replace(' ', '_', TikiLib::remove_non_word_characters_and_accents($object_id)) . '_ ' .
str_replace(' ', '_', $object_type);
}
}
<?php
// (c) Copyright 2002-2016 by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
class Services_Exception_EditConflict extends Services_Exception
{
function __construct($message = null)
{
if (is_null($message)) {
$message = tr('Edit conflict');
}
parent::__construct($message, 403);
}
public static function checkSemaphore($object_id, $object_type = 'wiki page')
{
global $user, $prefs;
if ($prefs['feature_warn_on_edit'] !== 'y') {
return;
}
$otherUser = TikiLib::lib('service')->internal(
'semaphore',
'get_user',
[
'object_id' => $object_id,
'object_type' => $object_type,
'check' => 1,
]
);
if ($user && $user !== $otherUser) {
throw new self(tr('Edit conflict: %0 "%1" is being edited already by %2', $object_type, $object_id, $otherUser));
}
}
}
......@@ -59,12 +59,11 @@ class ImageGalsLib extends TikiLib
$this->havegd = false;
}
// Do we have the imagick PECL module?
// Do we have the imagick 0 PECL module?
// Module can be downloaded at http://pecl.php.net/package/imagick
// Also check on 'imagick_rotate' function because the first check may detect imagick 2.x which has a completely different API
//*** Function is now called imagerotate but the API in Tiki has not been updated to use it.
//*** Therfore this test will falsely show that imagick is not detected even when it is loaded
//*** TODO update API to use imagerotate
//*** TODO update API to use imagerotate or document the disadvantages of GD
if (in_array('imagick', $exts) && function_exists('imagick_rotate')) {
$this->haveimagick = true;
} else {
......
......@@ -92,7 +92,7 @@
page: pageName,
pluginArgs: pluginArgs,
bodyContent: bodyContent,
edit_icon: edit_icon,
edit_icon: !! edit_icon,
selectedMod: selectedMod ? selectedMod : "",
modal: 1
});
......@@ -104,26 +104,37 @@
show: false // if it's the first time the show.bs.modal doesn't trigger sometimes
})
.one('loaded.bs.modal', function () { // Bind remote loaded event
handlePluginFieldsHierarchy(type);
// enables conditional display of inputs with a "parent" selector
handlePluginFieldsHierarchy();
// bind form button events and form validation
handleFormSubmit(this, type, edit_icon, area_id, replaceText);
// Trigger jQuery event 'plugin_#type#_ready' (see plugin_code_ready in codemirror_tiki.js for example)
$document
.trigger({
type: 'plugin_' + type + '_ready',
container: container,
arguments: arguments,
modal: $modal
})
.trigger({
type: 'plugin_ready',
container: container,
arguments: arguments,
modal: $modal
});
})
.modal("show");
// unset semaphore on object/page on cancel
.one("hidden.bs.modal", function () {
if ($("form", this).length && edit_icon) {
$.getJSON($.service("semaphore", "unset"), {
object_id: pageName
});
}
})
.modal("show")
.find('.modal-dialog').addClass("modal-lg");
//This allows users to create plugin snippets for any plugin using the jQuery event 'plugin_#type#_ready' for document
$document
.trigger({
type: 'plugin_' + type + '_ready',
container: container,
arguments: arguments,
modal: $modal
})
.trigger({
type: 'plugin_ready',
container: container,
arguments: arguments,
modal: $modal
});
};
/*
......@@ -131,7 +142,7 @@
* add javascript events to display them when the appropriate
* values are selected in the parent fields.
*/
function handlePluginFieldsHierarchy(type) {
function handlePluginFieldsHierarchy() {
var $container = $('#plugin_params');
var parents = {};
......
......@@ -13,17 +13,17 @@ if (strpos($_SERVER['SCRIPT_NAME'], basename(__FILE__)) !== false) {
function prefs_gal_list()
{
$imagegallib = TikiLib::lib('imagegal');
if ($imagegallib->havegd) {
$gdlib = tr('GD %0 detected.', $imagegallib->gdversion);
if ((extension_loaded('gd') && function_exists('gd_info'))) {
$gdinfo = gd_info();
$gdlib = tr('GD %0 detected.', $gdinfo["GD Version"]);
} else {
$gdlib = tra('GD not detected.');
}
if ($imagegallib->haveimagick) {
if ((extension_loaded('imagick') && function_exists('imagick_rotate'))) {
$imagicklib = tr('Imagick %0 detected.', phpversion('imagick'));
} else {
$imagicklib = tra('Imagick not detected.');
$imagicklib = tra('Imagick 0 not detected.');
}
return [
......@@ -112,10 +112,10 @@ function prefs_gal_list()
],
'gal_use_lib' => [
'name' => tra('Image processing library'),
'type' => 'radio',
'type' => 'list',
'options' => [
'gd' => tra('GD'),
'imagick' => tra('Imagick'),
'imagick' => tra('Imagick'). ' 0',
],
'default' => 'imagick',
'hint' => $gdlib . ' ' . $imagicklib
......
......@@ -129,30 +129,6 @@ function get_default_prefs()
'fgal_list_backlinks_admin' => 'y',
'fgal_show_checked' => 'y',
// imagegals
'feature_gal_batch' => 'n',
'feature_gal_slideshow' => 'n',
'gal_use_db' => 'y',
'gal_use_lib' => 'imagick',
'gal_match_regex' => '',
'gal_nmatch_regex' => '',
'gal_use_dir' => '',
'gal_batch_dir' => '',
'feature_gal_rankings' => 'n',
'feature_image_galleries_comments' => 'n',
'image_galleries_comments_default_order' => 'points_desc',
'image_galleries_comments_per_page' => 10,
'gal_list_name' => 'y',
'gal_list_parent' => 'n',
'gal_list_description' => 'y',
'gal_list_created' => 'n',
'gal_list_lastmodif' => 'y',
'gal_list_user' => 'n',
'gal_list_imgs' => 'y',
'gal_list_visits' => 'y',
'preset_galleries_info' =>'n',
'gal_image_mouseover' => 'n',
// articles
'cms_bot_bar' => 'y',
'cms_left_column' => 'y',
......@@ -287,12 +263,7 @@ function get_default_prefs()
'feature_intertiki_imported_groups' => '',
'feature_contributor_wiki' => '',
'https_login_required' => '',
'maxRowsGalleries' => '',
'replimaster' => '',
'rowImagesGalleries' => '',
'scaleSizeGalleries' => '',
'thumbSizeXGalleries' => '',
'thumbSizeYGalleries' => '',
'javascript_enabled' => 'n',
......
......@@ -403,6 +403,7 @@ class TikiAccessLib extends TikiLib
if (!empty($ticket) && !empty($_SESSION['tickets'][$ticket])) {
$time = $_SESSION['tickets'][$ticket];
if ($time < time() && $time > (time()-(60*15))) {
TikiLib::lib('smarty')->assign('ticket', $ticket);
return true;
}
}
......
......@@ -2194,87 +2194,6 @@ class TikiLib extends TikiDb_Bridge
}
// end of user voting methods
// Semaphore functions ////
/**
* @param $semName
* @param string $objectType
* @return bool|mixed|null|string
*/
function get_semaphore_user($semName, $objectType='wiki page')
{
global $user;
// the old semaphores have been deleted by semaphore_is_set - this function must be called before
$query = "select `user` from `tiki_semaphores` where `semName`=? and `objectType`=?";
$result = $this->fetchAll($query, array($semName, $objectType));
$user_is_in = false;
foreach ( $result as $res ) {
if ($res['user'] != $user || (!$user && $res['user'] == 'anonymous')) {
return $res['user']; // return the other users if exist
} else {
$user_is_in = true;
}
}
if ($user_is_in)
return $user;
else
return '';
}
/**
* @param $semName
* @param $limit
* @param string $objectType
* @return mixed
*/
function semaphore_is_set($semName, $limit, $objectType='wiki page')
{
$lim = $this->now - $limit;
$semaphores = $this->table('tiki_semaphores');
$semaphores->deleteMultiple(array('timestamp' => $semaphores->lesserThan((int) $lim)));
$query = "select `semName` from `tiki_semaphores` where `semName`=? and `objectType`=?";
$result = $this->query($query, array($semName, $objectType));
return $result->numRows();
}
/**
* @param $semName
* @param string $objectType
* @return int
*/
function semaphore_set($semName, $objectType='wiki page')
{
global $user;
if ($user == '') {
$user = 'anonymous';
}
$semaphores = $this->table('tiki_semaphores');
$semaphores->delete(array('semName' => $semName,'objectType' => $objectType));
$semaphores->insert(
array(
'semName' => $semName,
'timestamp' => $this->now,
'user' => $user,
'objectType' => $objectType,
)
);
return $this->now;
}
/**
* @param $semName
* @param $lock
* @param string $objectType
*/
function semaphore_unset($semName, $lock, $objectType='wiki page')
{
$semaphores = $this->table('tiki_semaphores');
$semaphores->delete(array('semName' => $semName,'timestamp' => (int) $lock,'objectType' => $objectType));
}
/**
* @param int $offset
* @param $maxRecords
......
......@@ -642,7 +642,7 @@ function wikiplugin_img( $data, $params )
foreach ($id_list as $i => $value) {
$params[$id] = trim($value);
$params['fgalId'] = '';
$params['type'] = 'fileId';
$params['type'] = $id;
$repl .= wikiplugin_img($data, $params);
}
if (strpos($repl, $notice) !== false) {
......@@ -681,6 +681,8 @@ function wikiplugin_img( $data, $params )
if ($absolute_links) {
$src = TikiLib::tikiUrl($src);
}
} elseif ($prefs['feature_use_fgal_for_wiki_attachments'] === 'y' && ! empty($imgdata['attId'])) {
$src = $filegalpath . $imgdata['attId'];
} else { //only attachments left
$src = $attachpath . $imgdata['attId'];
}
......@@ -733,6 +735,10 @@ function wikiplugin_img( $data, $params )
$filegallib = TikiLib::lib('filegal');
$dbinfo = $filegallib->get_file($imgdata['fileId']);
$basepath = $prefs['fgal_use_dir'];
} elseif ($prefs['feature_use_fgal_for_wiki_attachments'] === 'y' && !isset($dbinfo) && !empty($imgdata['attId'])) {
$filegallib = TikiLib::lib('filegal');
$dbinfo = $filegallib->get_file($imgdata['attId']);
$basepath = $prefs['fgal_use_dir'];
} else { //only attachments left
global $atts;
$wikilib = TikiLib::lib('wiki');
......
......@@ -104,11 +104,27 @@ $("#picker_{{$name|escape}}").parent().click(function () {
{if $type eq 'module'}
{jq}$("#param_module_input").change(function () {
var selectMod = $(this).val();
$.closeModal();
$(document).one("hidden.bs.modal", function () {
popupPluginForm("{{$area_id}}","{{$type}}", {{$index}}, "{{$pageName}}", {{$pluginArgsJSON}}, "{{$bodyContent}}", "{{$edit_icon}}", selectMod);