149f2871cSAndreas Gohr<?php 249f2871cSAndreas Gohr/** 349f2871cSAndreas Gohr * DokuWiki Plugin farmer (Admin Component) 449f2871cSAndreas Gohr * 549f2871cSAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 649f2871cSAndreas Gohr * @author Michael Große <grosse@cosmocode.de> 749f2871cSAndreas Gohr */ 849f2871cSAndreas Gohr 949f2871cSAndreas Gohr// must be run within Dokuwiki 1049f2871cSAndreas Gohrif(!defined('DOKU_INC')) die(); 1149f2871cSAndreas Gohr 1249f2871cSAndreas Gohrclass admin_plugin_farmer_new extends DokuWiki_Admin_Plugin { 1349f2871cSAndreas Gohr 1449f2871cSAndreas Gohr /** @var helper_plugin_farmer $helper */ 1549f2871cSAndreas Gohr protected $helper; 1649f2871cSAndreas Gohr 1749f2871cSAndreas Gohr /** 1849f2871cSAndreas Gohr * @return bool true if only access for superuser, false is for superusers and moderators 1949f2871cSAndreas Gohr */ 2049f2871cSAndreas Gohr public function forAdminOnly() { 2149f2871cSAndreas Gohr return true; 2249f2871cSAndreas Gohr } 2349f2871cSAndreas Gohr 2449f2871cSAndreas Gohr /** 2549f2871cSAndreas Gohr * admin_plugin_farmer_new constructor. 2649f2871cSAndreas Gohr */ 2749f2871cSAndreas Gohr public function __construct() { 2849f2871cSAndreas Gohr $this->helper = plugin_load('helper', 'farmer'); 2949f2871cSAndreas Gohr } 3049f2871cSAndreas Gohr 3149f2871cSAndreas Gohr /** 3249f2871cSAndreas Gohr * Should carry out any processing required by the plugin. 3349f2871cSAndreas Gohr */ 3449f2871cSAndreas Gohr public function handle() { 3549f2871cSAndreas Gohr global $INPUT; 3649f2871cSAndreas Gohr global $ID; 3749f2871cSAndreas Gohr if(!$INPUT->has('farmer__submit')) return; 3849f2871cSAndreas Gohr 3949f2871cSAndreas Gohr $data = $this->validateAnimalData(); 4049f2871cSAndreas Gohr if(!$data) return; 41*6348ab5bSMichael Grosse if($this->createNewAnimal($data['name'], $data['admin'], $data['pass'], $data['template'], $data['aclpolicy'], $data['allowreg'])) { 420336ab2aSAndreas Gohr $url = $this->helper->getAnimalURL($data['name']); 430336ab2aSAndreas Gohr $link = '<a href="' . $url . '">' . hsc($data['name']) . '</a>'; 440336ab2aSAndreas Gohr 450336ab2aSAndreas Gohr msg(sprintf($this->getLang('animal creation success'), $link), 1); 4649f2871cSAndreas Gohr $link = wl($ID, array('do' => 'admin', 'page' => 'farmer', 'sub' => 'new'), true, '&'); 4749f2871cSAndreas Gohr send_redirect($link); 4849f2871cSAndreas Gohr } 4949f2871cSAndreas Gohr } 5049f2871cSAndreas Gohr 5149f2871cSAndreas Gohr /** 5249f2871cSAndreas Gohr * Render HTML output, e.g. helpful text and a form 5349f2871cSAndreas Gohr */ 5449f2871cSAndreas Gohr public function html() { 55*6348ab5bSMichael Grosse global $lang; 561272da0cSAndreas Gohr $farmconfig = $this->helper->getConfig(); 5749f2871cSAndreas Gohr 5849f2871cSAndreas Gohr $form = new \dokuwiki\Form\Form(); 5949f2871cSAndreas Gohr $form->addClass('plugin_farmer')->id('farmer__create_animal_form'); 6049f2871cSAndreas Gohr 6149f2871cSAndreas Gohr $form->addFieldsetOpen($this->getLang('animal configuration')); 6223164e01SAndreas Gohr $form->addTextInput('animalname', $this->getLang('animal')); 6349f2871cSAndreas Gohr $form->addFieldsetClose(); 6449f2871cSAndreas Gohr 65801ebaa1SAndreas Gohr $animals = $this->helper->getAllAnimals(); 66801ebaa1SAndreas Gohr array_unshift($animals, ''); 67801ebaa1SAndreas Gohr $form->addFieldsetOpen($this->getLang('animal template')); 68801ebaa1SAndreas Gohr $form->addDropdown('animaltemplate', $animals)->addClass('farmer_choosen_animals'); 69801ebaa1SAndreas Gohr $form->addFieldsetClose(); 70801ebaa1SAndreas Gohr 71*6348ab5bSMichael Grosse $form->addFieldsetOpen($lang['i_policy'])->attr('id', 'aclPolicyFieldset'); 72*6348ab5bSMichael Grosse $policyOptions = array('open' => $lang['i_pol0'],'public' => $lang['i_pol1'], 'closed' => $lang['i_pol2']); 73*6348ab5bSMichael Grosse $form->addDropdown('aclpolicy', $policyOptions)->addClass('acl_chosen'); 74*6348ab5bSMichael Grosse if ($farmconfig['inherit']['main']) { 75*6348ab5bSMichael Grosse $form->addRadioButton('allowreg',$this->getLang('inherit user registration'))->val('inherit')->attr('checked', 'checked'); 76*6348ab5bSMichael Grosse $form->addRadioButton('allowreg',$this->getLang('enable user registration'))->val('allow'); 77*6348ab5bSMichael Grosse $form->addRadioButton('allowreg',$this->getLang('disable user registration'))->val('disable'); 78*6348ab5bSMichael Grosse } else { 79*6348ab5bSMichael Grosse $form->addCheckbox('allowreg', $lang['i_allowreg'])->attr('checked', 'checked'); 80*6348ab5bSMichael Grosse } 81*6348ab5bSMichael Grosse 82*6348ab5bSMichael Grosse $form->addFieldsetClose(); 83*6348ab5bSMichael Grosse 8449f2871cSAndreas Gohr $form->addFieldsetOpen($this->getLang('animal administrator')); 851272da0cSAndreas Gohr $btn = $form->addRadioButton('adminsetup', $this->getLang('noUsers'))->val('noUsers'); 861272da0cSAndreas Gohr if($farmconfig['inherit']['users']) { 871272da0cSAndreas Gohr $btn->attr('checked', 'checked'); // default when inherit available 881a130845SAndreas Gohr } else { 891a130845SAndreas Gohr // no user copying when inheriting 9049f2871cSAndreas Gohr $form->addRadioButton('adminsetup', $this->getLang('importUsers'))->val('importUsers'); 9149f2871cSAndreas Gohr $form->addRadioButton('adminsetup', $this->getLang('currentAdmin'))->val('currentAdmin'); 921a130845SAndreas Gohr } 931272da0cSAndreas Gohr $btn = $form->addRadioButton('adminsetup', $this->getLang('newAdmin'))->val('newAdmin'); 941272da0cSAndreas Gohr if(!$farmconfig['inherit']['users']) { 951272da0cSAndreas Gohr $btn->attr('checked', 'checked'); // default when inherit not available 961272da0cSAndreas Gohr } 9749f2871cSAndreas Gohr $form->addPasswordInput('adminPassword', $this->getLang('admin password')); 9849f2871cSAndreas Gohr $form->addFieldsetClose(); 9949f2871cSAndreas Gohr 10049f2871cSAndreas Gohr $form->addButton('farmer__submit', $this->getLang('submit'))->attr('type', 'submit')->val('newAnimal'); 10149f2871cSAndreas Gohr echo $form->toHTML(); 10249f2871cSAndreas Gohr } 10349f2871cSAndreas Gohr 10449f2871cSAndreas Gohr /** 10549f2871cSAndreas Gohr * Validate the data for a new animal 10649f2871cSAndreas Gohr * 10749f2871cSAndreas Gohr * @return array|bool false on errors, clean data otherwise 10849f2871cSAndreas Gohr */ 10949f2871cSAndreas Gohr protected function validateAnimalData() { 11049f2871cSAndreas Gohr global $INPUT; 11149f2871cSAndreas Gohr 11249f2871cSAndreas Gohr $animalname = $INPUT->filter('trim')->str('animalname'); 11349f2871cSAndreas Gohr $adminsetup = $INPUT->str('adminsetup'); 11449f2871cSAndreas Gohr $adminpass = $INPUT->filter('trim')->str('adminPassword'); 115801ebaa1SAndreas Gohr $template = $INPUT->filter('trim')->str('animaltemplate'); 116*6348ab5bSMichael Grosse $aclpolicy = $INPUT->filter('trim')->str('aclpolicy'); 117*6348ab5bSMichael Grosse $allowreg = $INPUT->str('allowreg'); 11849f2871cSAndreas Gohr 11949f2871cSAndreas Gohr $errors = array(); 12049f2871cSAndreas Gohr 12149f2871cSAndreas Gohr if($animalname === '') { 12249f2871cSAndreas Gohr $errors[] = $this->getLang('animalname_missing'); 12349f2871cSAndreas Gohr } elseif(!$this->helper->validateAnimalName($animalname)) { 12449f2871cSAndreas Gohr $errors[] = $this->getLang('animalname_invalid'); 12549f2871cSAndreas Gohr } 12649f2871cSAndreas Gohr 12749f2871cSAndreas Gohr if($adminsetup === 'newAdmin' && $adminpass === '') { 12849f2871cSAndreas Gohr $errors[] = $this->getLang('adminPassword_empty'); 12949f2871cSAndreas Gohr } 13049f2871cSAndreas Gohr 13149f2871cSAndreas Gohr if($animalname !== '' && file_exists(DOKU_FARMDIR . '/' . $animalname)) { 13249f2871cSAndreas Gohr $errors[] = $this->getLang('animalname_preexisting'); 13349f2871cSAndreas Gohr } 13449f2871cSAndreas Gohr 135*6348ab5bSMichael Grosse if (!is_dir(DOKU_FARMDIR . $template) && !in_array($aclpolicy,array('open', 'public', 'closed'))) { 136*6348ab5bSMichael Grosse $errors[] = $this->getLang('aclpolicy missing/bad'); 137*6348ab5bSMichael Grosse } 138*6348ab5bSMichael Grosse 13949f2871cSAndreas Gohr if($errors) { 14049f2871cSAndreas Gohr foreach($errors as $error) { 14149f2871cSAndreas Gohr msg($error, -1); 14249f2871cSAndreas Gohr } 14349f2871cSAndreas Gohr return false; 14449f2871cSAndreas Gohr } 14549f2871cSAndreas Gohr 1468262a4cbSAndreas Gohr if(!is_dir(DOKU_FARMDIR . $template)) { 147801ebaa1SAndreas Gohr $template = ''; 148801ebaa1SAndreas Gohr } 149*6348ab5bSMichael Grosse if ($template != '') { 150*6348ab5bSMichael Grosse $aclpolicy = ''; 151*6348ab5bSMichael Grosse } 152801ebaa1SAndreas Gohr 15349f2871cSAndreas Gohr return array( 15449f2871cSAndreas Gohr 'name' => $animalname, 15549f2871cSAndreas Gohr 'admin' => $adminsetup, 156801ebaa1SAndreas Gohr 'pass' => $adminpass, 157*6348ab5bSMichael Grosse 'template' => $template, 158*6348ab5bSMichael Grosse 'aclpolicy' => $aclpolicy, 159*6348ab5bSMichael Grosse 'allowreg' => $allowreg 16049f2871cSAndreas Gohr ); 16149f2871cSAndreas Gohr } 16249f2871cSAndreas Gohr 16349f2871cSAndreas Gohr /** 16449f2871cSAndreas Gohr * Create a new animal 16549f2871cSAndreas Gohr * 16649f2871cSAndreas Gohr * @param string $name name/title of the animal, will be the directory name for htaccess setup 16749f2871cSAndreas Gohr * @param string $adminSetup newAdmin, currentAdmin or importUsers 16849f2871cSAndreas Gohr * @param string $adminPassword required if $adminSetup is newAdmin 169801ebaa1SAndreas Gohr * @param string $template name of animal to copy 170*6348ab5bSMichael Grosse * @param $aclpolicy 171*6348ab5bSMichael Grosse * @param $userreg 17249f2871cSAndreas Gohr * @return bool true if successful 173*6348ab5bSMichael Grosse * @throws Exception 17449f2871cSAndreas Gohr */ 175*6348ab5bSMichael Grosse protected function createNewAnimal($name, $adminSetup, $adminPassword, $template, $aclpolicy, $userreg) { 1768262a4cbSAndreas Gohr $animaldir = DOKU_FARMDIR . $name; 17749f2871cSAndreas Gohr 17849f2871cSAndreas Gohr // copy basic template 17949f2871cSAndreas Gohr $ok = $this->helper->io_copyDir(__DIR__ . '/../_animal', $animaldir); 18049f2871cSAndreas Gohr if(!$ok) { 18149f2871cSAndreas Gohr msg($this->getLang('animal creation error'), -1); 18249f2871cSAndreas Gohr return false; 18349f2871cSAndreas Gohr } 18449f2871cSAndreas Gohr 185801ebaa1SAndreas Gohr // copy animal template 186801ebaa1SAndreas Gohr if($template != '') { 187801ebaa1SAndreas Gohr foreach(array('conf', 'data/pages', 'data/media', 'data/meta', 'data/media_meta', 'index') as $dir) { 1888262a4cbSAndreas Gohr $templatedir = DOKU_FARMDIR . $template . '/' . $dir; 189801ebaa1SAndreas Gohr if(!is_dir($templatedir)) continue; 190801ebaa1SAndreas Gohr // do not copy changelogs in meta 191801ebaa1SAndreas Gohr if(substr($dir, -4) == 'meta') { 192801ebaa1SAndreas Gohr $exclude = '/\.changes$/'; 193801ebaa1SAndreas Gohr } else { 194801ebaa1SAndreas Gohr $exclude = ''; 195801ebaa1SAndreas Gohr } 196801ebaa1SAndreas Gohr if(!$this->helper->io_copyDir($templatedir, $animaldir . '/' . $dir, $exclude)) { 197801ebaa1SAndreas Gohr msg(sprintf($this->getLang('animal template copy error'), $dir), -1); 198801ebaa1SAndreas Gohr // we go on anyway 199801ebaa1SAndreas Gohr } 200801ebaa1SAndreas Gohr } 201801ebaa1SAndreas Gohr } 202801ebaa1SAndreas Gohr 20349f2871cSAndreas Gohr // append title to local config 20449f2871cSAndreas Gohr $ok &= io_saveFile($animaldir . '/conf/local.php', "\n" . '$conf[\'title\'] = \'' . $name . '\';' . "\n", true); 20549f2871cSAndreas Gohr 2064eba53bcSAndreas Gohr // create a random logo and favicon 2074eba53bcSAndreas Gohr if(!class_exists('\splitbrain\RingIcon\RingIcon', false)) { 2084eba53bcSAndreas Gohr require(__DIR__ . '/../3rdparty/RingIcon.php'); 2094eba53bcSAndreas Gohr } 2104eba53bcSAndreas Gohr if(!class_exists('\chrisbliss18\phpico\PHPIco', false)) { 2114eba53bcSAndreas Gohr require(__DIR__ . '/../3rdparty/PHPIco.php'); 2124eba53bcSAndreas Gohr } 2134eba53bcSAndreas Gohr try { 214b263debeSAndreas Gohr if(function_exists('imagecreatetruecolor')) { 2154eba53bcSAndreas Gohr $ringicon = new \splitbrain\RingIcon\RingIcon(64); 2164eba53bcSAndreas Gohr $ringicon->createImage($animaldir, $animaldir . '/data/media/wiki/logo.png'); 2174eba53bcSAndreas Gohr $icongen = new \chrisbliss18\phpico\PHPIco($animaldir . '/data/media/wiki/logo.png'); 2184eba53bcSAndreas Gohr $icongen->save_ico($animaldir . '/data/media/wiki/favicon.ico'); 219b263debeSAndreas Gohr } 2204eba53bcSAndreas Gohr } catch(\Exception $ignore) { 2214eba53bcSAndreas Gohr // something went wrong, but we don't care. this is a nice to have feature only 2224eba53bcSAndreas Gohr } 22349f2871cSAndreas Gohr 22449f2871cSAndreas Gohr // create admin user 22549f2871cSAndreas Gohr if($adminSetup === 'newAdmin') { 22649f2871cSAndreas Gohr $users = "# <?php exit()?>\n" . $this->makeAdminLine($adminPassword) . "\n"; 22749f2871cSAndreas Gohr } elseif($adminSetup === 'currentAdmin') { 22849f2871cSAndreas Gohr $users = "# <?php exit()?>\n" . $this->getAdminLine() . "\n"; 2291272da0cSAndreas Gohr } elseif($adminSetup === 'noUsers') { 230801ebaa1SAndreas Gohr if(file_exists($animaldir . '/conf/users.auth.php')) { 231801ebaa1SAndreas Gohr // a user file exists already, probably from animal template - don't overwrite 232801ebaa1SAndreas Gohr $users = ''; 233801ebaa1SAndreas Gohr } else { 234801ebaa1SAndreas Gohr // create empty user file 2351272da0cSAndreas Gohr $users = "# <?php exit()?>\n"; 236801ebaa1SAndreas Gohr } 23749f2871cSAndreas Gohr } else { 23849f2871cSAndreas Gohr $users = io_readFile(DOKU_CONF . 'users.auth.php'); 23949f2871cSAndreas Gohr } 240801ebaa1SAndreas Gohr if($users) { 24149f2871cSAndreas Gohr $ok &= io_saveFile($animaldir . '/conf/users.auth.php', $users); 242801ebaa1SAndreas Gohr } 24349f2871cSAndreas Gohr 244*6348ab5bSMichael Grosse if ($aclpolicy != '') { 245*6348ab5bSMichael Grosse $aclfile = file($animaldir . '/conf/acl.auth.php'); 246*6348ab5bSMichael Grosse array_pop($aclfile); 247*6348ab5bSMichael Grosse switch ($aclpolicy) { 248*6348ab5bSMichael Grosse case 'open': 249*6348ab5bSMichael Grosse $aclfile[] = "* @ALL 8"; 250*6348ab5bSMichael Grosse break; 251*6348ab5bSMichael Grosse case 'public': 252*6348ab5bSMichael Grosse $aclfile[] = "* @ALL 1"; 253*6348ab5bSMichael Grosse $aclfile[] = "* @user 8"; 254*6348ab5bSMichael Grosse break; 255*6348ab5bSMichael Grosse case 'closed': 256*6348ab5bSMichael Grosse $aclfile[] = "* @ALL 0"; 257*6348ab5bSMichael Grosse $aclfile[] = "* @user 8"; 258*6348ab5bSMichael Grosse break; 259*6348ab5bSMichael Grosse default: 260*6348ab5bSMichael Grosse throw new Exception('Undefined aclpolicy given'); 261*6348ab5bSMichael Grosse } 262*6348ab5bSMichael Grosse $ok &= io_saveFile($animaldir . '/conf/acl.auth.php', join("\n", $aclfile)); 263*6348ab5bSMichael Grosse 264*6348ab5bSMichael Grosse global $conf; 265*6348ab5bSMichael Grosse switch ($userreg) { 266*6348ab5bSMichael Grosse case 'allow': 267*6348ab5bSMichael Grosse $disableactions = join(',', array_diff(explode(',', $conf['disableactions']), array('register'))); 268*6348ab5bSMichael Grosse $ok &= io_saveFile($animaldir . '/conf/local.php', "\n" . '$conf[\'disableactions\'] = \''.$disableactions.'\';' . "\n", true); 269*6348ab5bSMichael Grosse break; 270*6348ab5bSMichael Grosse case 'disable': 271*6348ab5bSMichael Grosse $disableactions = join(',', array_merge(explode(',', $conf['disableactions']), array('register'))); 272*6348ab5bSMichael Grosse $ok &= io_saveFile($animaldir . '/conf/local.php', "\n" . '$conf[\'disableactions\'] = \''.$disableactions.'\';' . "\n", true); 273*6348ab5bSMichael Grosse break; 274*6348ab5bSMichael Grosse case 'inherit': 275*6348ab5bSMichael Grosse case true: 276*6348ab5bSMichael Grosse // nothing needs to be done 277*6348ab5bSMichael Grosse break; 278*6348ab5bSMichael Grosse default: 279*6348ab5bSMichael Grosse $ok &= io_saveFile($animaldir . '/conf/local.php', "\n" . '$conf[\'disableactions\'] = \'register\';' . "\n", true); 280*6348ab5bSMichael Grosse } 281*6348ab5bSMichael Grosse } 282*6348ab5bSMichael Grosse 2834664a1d2SAndreas Gohr // deactivate plugins by default FIXME this should be nicer 28449f2871cSAndreas Gohr $deactivatedPluginsList = explode(',', $this->getConf('deactivated plugins')); 2854664a1d2SAndreas Gohr $deactivatedPluginsList = array_map('trim', $deactivatedPluginsList); 2864664a1d2SAndreas Gohr $deactivatedPluginsList = array_unique($deactivatedPluginsList); 2874664a1d2SAndreas Gohr $deactivatedPluginsList = array_filter($deactivatedPluginsList); 28849f2871cSAndreas Gohr foreach($deactivatedPluginsList as $plugin) { 289af1c6dd8SAndreas Gohr $this->helper->setPluginState(trim($plugin), $name, 0); 29049f2871cSAndreas Gohr } 29149f2871cSAndreas Gohr 29249f2871cSAndreas Gohr return $ok; 29349f2871cSAndreas Gohr } 29449f2871cSAndreas Gohr 29549f2871cSAndreas Gohr /** 29649f2871cSAndreas Gohr * Creates a new user line 29749f2871cSAndreas Gohr * 29849f2871cSAndreas Gohr * @param $password 29949f2871cSAndreas Gohr * @return string 30049f2871cSAndreas Gohr */ 30149f2871cSAndreas Gohr protected function makeAdminLine($password) { 30249f2871cSAndreas Gohr $pass = auth_cryptPassword($password); 3031272da0cSAndreas Gohr $line = join( 30465e7bfd1SAndreas Gohr ':', array( 30549f2871cSAndreas Gohr 'admin', 30649f2871cSAndreas Gohr $pass, 30749f2871cSAndreas Gohr 'Administrator', 30849f2871cSAndreas Gohr 'admin@example.org', 30949f2871cSAndreas Gohr 'admin,user' 3101272da0cSAndreas Gohr ) 3111272da0cSAndreas Gohr ); 31249f2871cSAndreas Gohr return $line; 31349f2871cSAndreas Gohr } 31449f2871cSAndreas Gohr 31549f2871cSAndreas Gohr /** 31649f2871cSAndreas Gohr * Copies the current user as new admin line 31749f2871cSAndreas Gohr * 31849f2871cSAndreas Gohr * @return string 31949f2871cSAndreas Gohr */ 32049f2871cSAndreas Gohr protected function getAdminLine() { 32149f2871cSAndreas Gohr $currentAdmin = $_SERVER['REMOTE_USER']; 32249f2871cSAndreas Gohr $masterUsers = file_get_contents(DOKU_CONF . 'users.auth.php'); 32349f2871cSAndreas Gohr $masterUsers = ltrim(strstr($masterUsers, "\n" . $currentAdmin . ":")); 32449f2871cSAndreas Gohr $newAdmin = substr($masterUsers, 0, strpos($masterUsers, "\n") + 1); 32549f2871cSAndreas Gohr return $newAdmin; 32649f2871cSAndreas Gohr } 32749f2871cSAndreas Gohr 32849f2871cSAndreas Gohr} 32949f2871cSAndreas Gohr 33049f2871cSAndreas Gohr// vim:ts=4:sw=4:et: 331