Skip to content

Commit

Permalink
Merge pull request #1096 from YesWiki/doryphore-dev
Browse files Browse the repository at this point in the history
dump for version 4.4.1
  • Loading branch information
mrflos committed Sep 6, 2023
2 parents 8086f53 + 94e7e79 commit 50316ff
Show file tree
Hide file tree
Showing 221 changed files with 7,997 additions and 5,106 deletions.
48 changes: 25 additions & 23 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ module.exports = {
'class-methods-use-this': 'off',
'import/no-unresolved': 'off',
'import/extensions': ['error', 'always'],
'import/prefer-default-export': ['off'],
'no-use-before-define': ['off'],
eqeqeq: ['error', 'smart'],
'comma-dangle': ['error', 'never'],
'object-curly-newline': ['error', { multiline: true }],
Expand All @@ -32,28 +34,28 @@ module.exports = {
'lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true }]
},
ignorePatterns: [
"vendor/",
"!/custom",
"!/javascripts",
"javascripts/vendor",
"!/styles",
"!/tools",
"/tools/*",
"!tools/autoupdate",
"!tools/aceditor",
"!tools/attach",
"!tools/bazar",
"!tools/contact",
"!tools/helloworld",
"!tools/lang",
"!tools/login",
"!tools/progressbar",
"!tools/rss",
"!tools/security",
"!tools/syndication",
"!tools/tableau",
"!tools/tags",
"!tools/templates",
"!tools/toc"
'vendor/',
'!/custom',
'!/javascripts',
'javascripts/vendor',
'!/styles',
'!/tools',
'/tools/*',
'!tools/autoupdate',
'!tools/aceditor',
'!tools/attach',
'!tools/bazar',
'!tools/contact',
'!tools/helloworld',
'!tools/lang',
'!tools/login',
'!tools/progressbar',
'!tools/rss',
'!tools/security',
'!tools/syndication',
'!tools/tableau',
'!tools/tags',
'!tools/templates',
'!tools/toc'
]
}
1 change: 1 addition & 0 deletions actions/EditConfigAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class EditConfigAction extends YesWikiAction
'default_comment_avatar' => 'core',
'htmlPurifierActivated' => 'core',
'favorites_activated' => 'core',
'preview_before_save' => 'core',

'default_read_acl' => 'access',
'default_write_acl' => 'access',
Expand Down
257 changes: 134 additions & 123 deletions actions/EditGroupsAction.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<?php


use Symfony\Component\Security\Csrf\Exception\TokenNotFoundException;
use YesWiki\Core\Controller\CsrfTokenController;
use YesWiki\Core\Service\DbService;
use YesWiki\Core\Service\TripleStore;
use YesWiki\Core\YesWikiAction;

class EditGroupsAction extends YesWikiAction
Expand All @@ -13,140 +18,146 @@ public function run()
]) ;
}

// Form definition
$wiki = &$this->wiki;
$list = $wiki->GetGroupsList(); // retrieves an array of group names from table 'triples' (content of 'resource' starts with 'ThisWikiGroup' and content of 'property' equals 'http://www.wikini.net/_vocabulary/acls')
if (!$wiki->UserIsAdmin()) { // If user not in admin group, remove admin group from the list
$list = array_diff($list, array(ADMIN_GROUP));
}
sort($list);
// Start of group edition
$res = $wiki->FormOpen('', '', 'get', 'form-inline');
$res .= '<label>'._t('EDIT_EXISTING_GROUP').'</label><p><select class="form-control" name="groupname">';
foreach ($list as $group) {
$res .= '<option value="' . htmlspecialchars($group, ENT_COMPAT, YW_CHARSET) . '"';
if (!empty($_GET['groupname']) && $_GET['groupname'] == $group) {
$res .= ' selected="selected"';
$message = '';
$type = 'danger';
$currentGroupAcl = '';
$selectedGroupName = '';
$action = '';
if (!empty($_POST['groupname'])){
if (!is_string($_POST['groupname'])){
$message = 'Action not possible because \'groupname\' should be a string !';
} else if (preg_match('/[^A-Za-z0-9]/', $_POST['groupname'])){
$message = _t('ONLY_ALPHANUM_FOR_GROUP_NAME');
} else {
$selectedGroupName = strval($_POST['groupname']);
$action = !empty($_POST['action-save'])
? 'save'
: (
!empty($_POST['action-delete'])
? 'delete'
: ''
);
try {
if ($action === 'save'){
list('message' => $message, 'type' => $type) = $this->saveAcl($selectedGroupName);
} else if ($action === 'delete') {
list('message' => $message, 'type' => $type) = $this->deleteGroup($selectedGroupName);
}
} catch (TokenNotFoundException $th) {
$message = _t('ERROR_WHILE_SAVING_GROUP') .':<br/>'. $th->getMessage();
}
}
$res .= '>' . htmlspecialchars($group, ENT_COMPAT, YW_CHARSET) . '</option>';
}
$res .= '</select>'."\n".'<input class="btn btn-primary btn-edit-group" type="submit" value="'.htmlspecialchars(_t('SEE_EDIT')).'" /></p>'."\n" . $wiki->FormClose();
// End of group edition
// Start of group creation
$res .= $wiki->FormOpen('', '', 'get', 'form-inline') . '<label>' . _t('CREATE_NEW_GROUP').'</label><p> <input type="text" name="groupname" placeholder="'.htmlspecialchars(_t('GROUP_NAME')).'" class="form-control" />';
$res .= '<input class="btn btn-primary btn-create-group" type="submit" value="'._t('DEFINE').'" /></p>' . $wiki->FormClose();
// End of group creation
// Start of group deletion
$res .= $wiki->FormOpen('', '', 'get', 'form-inline');
$res .= '<label>'.htmlspecialchars(_t('DELETE_EXISTING_GROUP')).'</label>';
$res .= '<p><select class="form-control" name="deletegroup">';
foreach ($list as $group) {
$res .= '<option value="' . htmlspecialchars($group, ENT_COMPAT, YW_CHARSET) . '"';
if (!empty($_GET['deletegroup']) && $_GET['deletegroup'] == $group) {
$res .= ' selected="selected"';
}
$res .= '>' . htmlspecialchars($group, ENT_COMPAT, YW_CHARSET) . '</option>';

// retrieves an array of group names from table 'triples' (content of 'resource' starts with 'ThisWikiGroup' and content of 'property' equals 'http://www.wikini.net/_vocabulary/acls')
$list = $this->wiki->GetGroupsList();
sort($list);

if (!empty($selectedGroupName) && in_array($selectedGroupName, $list)){
$currentGroupAcl = $this->wiki->GetGroupACL($selectedGroupName);
}
$res .= '</select>'."\n".'<input class="btn btn-danger btn-delete-group" type="submit" value="'.htmlspecialchars(_t('DELETE')).'" /></p>'."\n" . $wiki->FormClose();
// End of group deletion
// End of form definition

// Form action handling
if ($_POST && !empty($_POST['groupname']) && isset($_POST['acl'])) { // save ACL's
// The form method is 'post'
// it returns a groupname and list of users (acl), therefore
// The group has been edited
$name = $_POST['groupname'];
$newacl = $_POST['acl'];
if (strtolower($name) == ADMIN_GROUP) {
if (!$wiki->UserIsAdmin()) {
return $res . _t('ONLY_ADMINS_CAN_CHANGE_MEMBERS') .'.<br/>';
}
if (!$wiki->CheckACL($newacl)) {
return $res . _t('YOU_CANNOT_REMOVE_YOURSELF').'.<br/>';
}
}
$result = $wiki->SetGroupACL($name, $newacl);
if ($result) {
if ($result == 1000) {
return $res . _t('ERROR_RECURSIVE_GROUP').' !<br />';

return $this->render(
'@core/actions/edit-group-action.twig',
compact(['list','message','type','currentGroupAcl','selectedGroupName','action'])
);
}

protected function saveAcl(string $selectedGroupName): array
{
$this->confirmToken();

$message = '';
$type = 'danger';

if (!isset($_POST['acl']) || !is_string($_POST['acl'])){
$message = '$_POST[\'acl\'] must be a string';
} else {
$newacl = strval($_POST['acl']);
if (strtolower($selectedGroupName) == ADMIN_GROUP && !$this->wiki->CheckACL($newacl)) {
$message = _t('YOU_CANNOT_REMOVE_YOURSELF');
} else {
$result = $this->wiki->SetGroupACL($selectedGroupName, $newacl);

if ($result) {
if ($result == 1000) {
$message = _t('ERROR_RECURSIVE_GROUP').' !';
} else {
$message = _t('ERROR_WHILE_SAVING_GROUP') . ' ' . ucfirst($selectedGroupName) . ' ('._t('ERROR_CODE').' ' . $result . ')';
}
} else {
return $res . _t('ERROR_WHILE_SAVING_GROUP') . ' ' . ucfirst($name) . ' ('._t('ERROR_CODE').' ' . $result . ')<br />';
//
$this->wiki->LogAdministrativeAction($this->wiki->GetUserName(), _t('NEW_ACL_FOR_GROUP')." " . ucfirst($selectedGroupName) . ' : ' . $newacl . "\n");
$message = _t('NEW_ACL_SUCCESSFULLY_SAVED_FOR_THE_GROUP').' ' . ucfirst($selectedGroupName);
$type = 'success';
}
} else {
$wiki->LogAdministrativeAction($wiki->GetUserName(), _t('NEW_ACL_FOR_GROUP')." " . ucfirst($name) . ' : ' . $newacl . "\n");
return $res . _t('NEW_ACL_SUCCESSFULLY_SAVED_FOR_THE_GROUP').' ' . ucfirst($name) . '.<br />';
}
// The group has been edited – End
} elseif (!empty($_GET['deletegroup'])) {
// The form returns a groupname to delete, therefore
// There is a request to delete the group
$name = $_GET['deletegroup'];
if ($wiki->GetGroupACL($name) != '') { // The group is not empty
$res .= _t('ONLY_EMPTY_GROUP_FOR_DELETION').'.';
}

return compact(['message','type']);
}


protected function deleteGroup(string &$selectedGroupName): array
{
$message = '';
$type = 'danger';

$this->confirmToken();

if ($this->wiki->GetGroupACL($selectedGroupName) != '') { // The group is not empty
$message = _t('ONLY_EMPTY_GROUP_FOR_DELETION');
} else {
// Check if acls table contains at least one line (page)
// for which this group is the only one to have some privilege
$dbService = $this->getService(DbService::class);
$vocAcsl = WIKINI_VOC_ACLS;
$sql = "SELECT page_tag FROM {$dbService->prefixTable($vocAcsl)} WHERE list = \"@{$dbService->escape($selectedGroupName)}\"";
$ownedPages = $dbService->loadAll($sql); // if group owns no pages, then empty
if (!empty($ownedPages)) {
// Array is not empty because the query returns at least one page
$message = _t('ONLY_NO_PAGES_GROUP_FOR_DELETION').'<br/>';
$message .= implode('<br/>',array_map(function($acl){
return "<a href=\"{$this->wiki->Href('',$acl['page_tag'])}\">{$acl['page_tag']}</a>";
},$ownedPages));
} else {
// Check if acls table contains at least one line (page)
// for which this group is the only one to have some privilege
$sql = 'SELECT page_tag FROM ' . $wiki->GetConfigValue('table_prefix') . 'acls WHERE list = "@' . $name . '"';
$ownedPages = array();
$ownedPages = $wiki->LoadAll($sql); // if group owns no pages, then empty
if ($ownedPages) {
// Array is not empty because the query returns at least one page
$res .= _t('ONLY_NO_PAGES_GROUP_FOR_DELETION').'.';
foreach ($ownedPages as $ownedPage) {
$res .= '<br/>' . $ownedPage['page_tag'];
// Group is empty AND is not alone having privileges on any page
$sql = <<<SQL
UPDATE {$dbService->prefixTable($vocAcsl)}
SET `list` = REPLACE(REPLACE (`list`, '@{$dbService->escape($selectedGroupName)}\\n', ''),'\\n@{$dbService->escape($selectedGroupName)}','')
WHERE `list` LIKE '%@{$dbService->escape($selectedGroupName)}%'
SQL;

$dbService->query($sql);

$tripleStore = $this->getService(TripleStore::class);
$previous = $tripleStore->getMatching(GROUP_PREFIX.$selectedGroupName,WIKINI_VOC_PREFIX.WIKINI_VOC_ACLS,'','=');
$deletionOk = false;
if (!empty($previous)){
$deletionOk = true;
foreach ($previous as $triple) {
if (!$tripleStore->delete($selectedGroupName,WIKINI_VOC_ACLS,$triple['value'],GROUP_PREFIX)){
$deletionOk = false;
}
}
return $res;
}

if ($deletionOk){
$message = "groupe $selectedGroupName supprimé";
$type = 'success';
$selectedGroupName = '';
} else {
// Group is empty AND is not alone having privvileges on any page
/* create sql connection*/
$link = mysqli_connect(
$GLOBALS["wiki"]->config['mysql_host'],
$GLOBALS["wiki"]->config['mysql_user'],
$GLOBALS["wiki"]->config['mysql_password'],
$GLOBALS["wiki"]->config['mysql_database']
);
/* Build sql query*/
// ACLS part
$aclsTable = $GLOBALS["wiki"]->config['table_prefix'].WIKINI_VOC_ACLS;
$searched_value = '%@' . $name . '%';
$seek_value_bf = '@' . $name . '\n'; // groupname to delete can be followed by another groupname
$seek_value_af = '\n@' . $name; // groupname to delete can follow another groupname
// get rid of this groupname everytime it's followed by another
$sql = "UPDATE ".$aclsTable." SET list = REPLACE (list, '".$seek_value_bf."', '') WHERE list LIKE '" . $searched_value . "';";
// in the remaining get rid of this groupname everytime it follows another
$sql .= "\nUPDATE ".$aclsTable." SET list = REPLACE (list, '".$seek_value_af."', '') WHERE list LIKE '" . $searched_value . "';";
// End of ACLS part
// Triples part
$triplesTable = $GLOBALS["wiki"]->config['table_prefix'].'triples';
$groupName = GROUP_PREFIX . $name;
$sql .= "\nDELETE FROM ".$triplesTable." WHERE resource = '".$groupName."' AND value = '';";
// End of triples part
/* Execute queries */
mysqli_multi_query($link, $sql);
do {
;
} while (mysqli_next_result($link));
return $res . 'groupe ' . $name . ' supprimé' . '<br/>';
$message = "Une erreur s'est poduite lors de la suppression du groupe $selectedGroupName (triple non supprimé)";
$type = 'warning';
}
}
} elseif (!empty($_GET['groupname'])) {
// The form returns a groupname and no list of users (acl), therefore
// Request to edit the group
$name = $_GET['groupname'];
if (!preg_match('/[^A-Za-z0-9]/', $name)) { // only alphanumeric characters
$res .= $wiki->FormOpen(); // form method is 'post' by default
$res .= '<hr><label class="edit-group">'.str_replace("{groupName}",'<strong>' . htmlspecialchars($name, ENT_COMPAT, YW_CHARSET) . '</strong>',htmlspecialchars(_t('LIST_GROUP_MEMBERS'))).'</label> ('. htmlspecialchars(_t('ONE_NAME_BY_LINE')).')';
$res .= '<input type="hidden" name="groupname" value="'. $name . '" />';
$res .= '<textarea name="acl" rows="3" class="form-control">' . (in_array($name, $list) ? $wiki->GetGroupACL($name) : '') . '</textarea><br />';
$res .= '<input type="submit" value="'._t('SAVE').'" class="btn btn-primary" accesskey="s" />';
return $res . $wiki->FormClose();
} else { // groupname contains characters other than alphanumeric
$res .= _t('ONLY_ALPHANUM_FOR_GROUP_NAME').'.';
}
}
// Request to edit the group – End
return $res;
// Form action handling – End

return compact(['message','type']);
}

protected function confirmToken()
{
$this->getService(CsrfTokenController::class)->checkToken('main', 'POST', 'confirmToken',false);
}
}
14 changes: 10 additions & 4 deletions actions/EraseSpamedCommentsAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
*
*/
use YesWiki\Bazar\Controller\EntryController;
use YesWiki\Bazar\Service\EntryManager;
use YesWiki\Core\Service\PageManager;
use YesWiki\Core\YesWikiAction;

class EraseSpamedCommentsAction extends YesWikiAction
Expand Down Expand Up @@ -84,10 +86,14 @@ public function run()
// (si DeleteOrphanedPage ne convient pas, soit on créé
// une autre, soit on la modifie
echo "Effacement de : " . $page . "<br />\n";
$wiki->services->get(EntryController::class)->triggerDeletedEventIfNeeded(function()use($page,$wiki){
$wiki->DeleteOrphanedPage($page);
},$page);
$deletedPages .= $page . ", ";
if ($wiki->services->get(EntryManager::class)->isEntry($page)){
if($wiki->services->get(EntryController::class)->delete($page)){
$deletedPages .= $page . ", ";
}
} else {
$wiki->services->get(PageManager::class)->deleteOrphaned($page);
$deletedPages .= $page . ", ";
}
}
$deletedPages = trim($deletedPages, ", ");
echo "<p><a href=\"".$wiki->Href()."\">"._t('FORM_RETURN').".</a></p>";
Expand Down
2 changes: 1 addition & 1 deletion actions/UsersTableAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ private function managePostActions(array $post, bool $isAdmin): ?string
$userName = in_array($username, [false,null], true) ? "" : htmlspecialchars(strip_tags($userName));
try {
$rawUserName = str_replace(['&#039;','&#39;'], ['\'','\''], $userName);
$this->csrfTokenController->checkToken("action\\userstable\\deleteUser\\{$rawUserName}", 'POST', 'csrf-token-delete');
$this->csrfTokenController->checkToken('main', 'POST', 'csrf-token-delete',false);
$user = $this->userManager->getOneByName($rawUserName);
if (empty($user)) {
return $this->render("@templates/alert-message.twig", [
Expand Down
Loading

0 comments on commit 50316ff

Please sign in to comment.