1<?php 2/** 3 * DokuWiki Plugin farmer (Admin Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Michael Große <grosse@cosmocode.de> 7 */ 8 9// must be run within Dokuwiki 10if(!defined('DOKU_INC')) die(); 11 12class admin_plugin_farmer_new extends DokuWiki_Admin_Plugin { 13 14 /** @var helper_plugin_farmer $helper */ 15 protected $helper; 16 17 /** 18 * @return bool true if only access for superuser, false is for superusers and moderators 19 */ 20 public function forAdminOnly() { 21 return true; 22 } 23 24 /** 25 * admin_plugin_farmer_new constructor. 26 */ 27 public function __construct() { 28 $this->helper = plugin_load('helper', 'farmer'); 29 } 30 31 /** 32 * Should carry out any processing required by the plugin. 33 */ 34 public function handle() { 35 global $INPUT; 36 global $ID; 37 if(!$INPUT->has('farmer__submit')) return; 38 39 $data = $this->validateAnimalData(); 40 if(!$data) return; 41 if($this->createNewAnimal($data['name'], $data['admin'], $data['pass'], $data['template'], $data['aclpolicy'], $data['allowreg'])) { 42 $url = $this->helper->getAnimalURL($data['name']); 43 $link = '<a href="' . $url . '">' . hsc($data['name']) . '</a>'; 44 45 msg(sprintf($this->getLang('animal creation success'), $link), 1); 46 $link = wl($ID, array('do' => 'admin', 'page' => 'farmer', 'sub' => 'new'), true, '&'); 47 send_redirect($link); 48 } 49 } 50 51 /** 52 * Render HTML output, e.g. helpful text and a form 53 */ 54 public function html() { 55 global $lang; 56 $farmconfig = $this->helper->getConfig(); 57 58 $form = new \dokuwiki\Form\Form(); 59 $form->addClass('plugin_farmer')->id('farmer__create_animal_form'); 60 61 $form->addFieldsetOpen($this->getLang('animal configuration')); 62 $form->addTextInput('animalname', $this->getLang('animal')); 63 $form->addFieldsetClose(); 64 65 $animals = $this->helper->getAllAnimals(); 66 array_unshift($animals, ''); 67 $form->addFieldsetOpen($this->getLang('animal template')); 68 $form->addDropdown('animaltemplate', $animals)->addClass('farmer_chosen_animals'); 69 $form->addFieldsetClose(); 70 71 $form->addFieldsetOpen($lang['i_policy'])->attr('id', 'aclPolicyFieldset'); 72 $policyOptions = array('open' => $lang['i_pol0'],'public' => $lang['i_pol1'], 'closed' => $lang['i_pol2']); 73 $form->addDropdown('aclpolicy', $policyOptions)->addClass('acl_chosen'); 74 if ($farmconfig['inherit']['main']) { 75 $form->addRadioButton('allowreg',$this->getLang('inherit user registration'))->val('inherit')->attr('checked', 'checked'); 76 $form->addRadioButton('allowreg',$this->getLang('enable user registration'))->val('allow'); 77 $form->addRadioButton('allowreg',$this->getLang('disable user registration'))->val('disable'); 78 } else { 79 $form->addCheckbox('allowreg', $lang['i_allowreg'])->attr('checked', 'checked'); 80 } 81 82 $form->addFieldsetClose(); 83 84 $form->addFieldsetOpen($this->getLang('animal administrator')); 85 $btn = $form->addRadioButton('adminsetup', $this->getLang('noUsers'))->val('noUsers'); 86 if($farmconfig['inherit']['users']) { 87 $btn->attr('checked', 'checked'); // default when inherit available 88 } else { 89 // no user copying when inheriting 90 $form->addRadioButton('adminsetup', $this->getLang('importUsers'))->val('importUsers'); 91 $form->addRadioButton('adminsetup', $this->getLang('currentAdmin'))->val('currentAdmin'); 92 } 93 $btn = $form->addRadioButton('adminsetup', $this->getLang('newAdmin'))->val('newAdmin'); 94 if(!$farmconfig['inherit']['users']) { 95 $btn->attr('checked', 'checked'); // default when inherit not available 96 } 97 $form->addPasswordInput('adminPassword', $this->getLang('admin password')); 98 $form->addFieldsetClose(); 99 100 $form->addButton('farmer__submit', $this->getLang('submit'))->attr('type', 'submit')->val('newAnimal'); 101 echo $form->toHTML(); 102 } 103 104 /** 105 * Validate the data for a new animal 106 * 107 * @return array|bool false on errors, clean data otherwise 108 */ 109 protected function validateAnimalData() { 110 global $INPUT; 111 112 $animalname = $INPUT->filter('trim')->str('animalname'); 113 $adminsetup = $INPUT->str('adminsetup'); 114 $adminpass = $INPUT->filter('trim')->str('adminPassword'); 115 $template = $INPUT->filter('trim')->str('animaltemplate'); 116 $aclpolicy = $INPUT->filter('trim')->str('aclpolicy'); 117 $allowreg = $INPUT->str('allowreg'); 118 119 $errors = array(); 120 121 if($animalname === '') { 122 $errors[] = $this->getLang('animalname_missing'); 123 } elseif(!$this->helper->validateAnimalName($animalname)) { 124 $errors[] = $this->getLang('animalname_invalid'); 125 } 126 127 if($adminsetup === 'newAdmin' && $adminpass === '') { 128 $errors[] = $this->getLang('adminPassword_empty'); 129 } 130 131 if($animalname !== '' && file_exists(DOKU_FARMDIR . '/' . $animalname)) { 132 $errors[] = $this->getLang('animalname_preexisting'); 133 } 134 135 if (!is_dir(DOKU_FARMDIR . $template) && !in_array($aclpolicy,array('open', 'public', 'closed'))) { 136 $errors[] = $this->getLang('aclpolicy missing/bad'); 137 } 138 139 if($errors) { 140 foreach($errors as $error) { 141 msg($error, -1); 142 } 143 return false; 144 } 145 146 if(!is_dir(DOKU_FARMDIR . $template)) { 147 $template = ''; 148 } 149 if ($template != '') { 150 $aclpolicy = ''; 151 } 152 153 return array( 154 'name' => $animalname, 155 'admin' => $adminsetup, 156 'pass' => $adminpass, 157 'template' => $template, 158 'aclpolicy' => $aclpolicy, 159 'allowreg' => $allowreg 160 ); 161 } 162 163 /** 164 * Create a new animal 165 * 166 * @param string $name name/title of the animal, will be the directory name for htaccess setup 167 * @param string $adminSetup newAdmin, currentAdmin or importUsers 168 * @param string $adminPassword required if $adminSetup is newAdmin 169 * @param string $template name of animal to copy 170 * @param $aclpolicy 171 * @param $userreg 172 * @return bool true if successful 173 * @throws Exception 174 */ 175 protected function createNewAnimal($name, $adminSetup, $adminPassword, $template, $aclpolicy, $userreg) { 176 $animaldir = DOKU_FARMDIR . $name; 177 178 // copy basic template 179 $ok = $this->helper->io_copyDir(__DIR__ . '/../_animal', $animaldir); 180 if(!$ok) { 181 msg($this->getLang('animal creation error'), -1); 182 return false; 183 } 184 185 // copy animal template 186 if($template != '') { 187 foreach(array('conf', 'data/pages', 'data/media', 'data/meta', 'data/media_meta', 'index') as $dir) { 188 $templatedir = DOKU_FARMDIR . $template . '/' . $dir; 189 if(!is_dir($templatedir)) continue; 190 // do not copy changelogs in meta 191 if(substr($dir, -4) == 'meta') { 192 $exclude = '/\.changes$/'; 193 } else { 194 $exclude = ''; 195 } 196 if(!$this->helper->io_copyDir($templatedir, $animaldir . '/' . $dir, $exclude)) { 197 msg(sprintf($this->getLang('animal template copy error'), $dir), -1); 198 // we go on anyway 199 } 200 } 201 } 202 203 // append title to local config 204 $ok &= io_saveFile($animaldir . '/conf/local.php', "\n" . '$conf[\'title\'] = \'' . $name . '\';' . "\n", true); 205 206 // create a random logo and favicon 207 if(!class_exists('\splitbrain\RingIcon\RingIcon', false)) { 208 require(__DIR__ . '/../3rdparty/RingIcon.php'); 209 } 210 if(!class_exists('\chrisbliss18\phpico\PHPIco', false)) { 211 require(__DIR__ . '/../3rdparty/PHPIco.php'); 212 } 213 try { 214 if(function_exists('imagecreatetruecolor')) { 215 $logo = $animaldir . '/data/media/wiki/logo.png'; 216 if(!file_exists($logo)) { 217 $ringicon = new \splitbrain\RingIcon\RingIcon(64); 218 $ringicon->createImage($animaldir, $logo); 219 } 220 221 $icon = $animaldir . '/data/media/wiki/favicon.ico'; 222 if(!file_exists($icon)) { 223 $icongen = new \chrisbliss18\phpico\PHPIco($logo); 224 $icongen->save_ico($icon); 225 } 226 } 227 } catch(\Exception $ignore) { 228 // something went wrong, but we don't care. this is a nice to have feature only 229 } 230 231 // create admin user 232 if($adminSetup === 'newAdmin') { 233 $users = "# <?php exit()?>\n" . $this->makeAdminLine($adminPassword) . "\n"; 234 } elseif($adminSetup === 'currentAdmin') { 235 $users = "# <?php exit()?>\n" . $this->getAdminLine() . "\n"; 236 } elseif($adminSetup === 'noUsers') { 237 if(file_exists($animaldir . '/conf/users.auth.php')) { 238 // a user file exists already, probably from animal template - don't overwrite 239 $users = ''; 240 } else { 241 // create empty user file 242 $users = "# <?php exit()?>\n"; 243 } 244 } else { 245 $users = io_readFile(DOKU_CONF . 'users.auth.php'); 246 } 247 if($users) { 248 $ok &= io_saveFile($animaldir . '/conf/users.auth.php', $users); 249 } 250 251 if ($aclpolicy != '') { 252 $aclfile = file($animaldir . '/conf/acl.auth.php'); 253 $aclfile = array_map('trim', $aclfile); 254 array_pop($aclfile); 255 switch ($aclpolicy) { 256 case 'open': 257 $aclfile[] = "* @ALL 8"; 258 break; 259 case 'public': 260 $aclfile[] = "* @ALL 1"; 261 $aclfile[] = "* @user 8"; 262 break; 263 case 'closed': 264 $aclfile[] = "* @ALL 0"; 265 $aclfile[] = "* @user 8"; 266 break; 267 default: 268 throw new Exception('Undefined aclpolicy given'); 269 } 270 $ok &= io_saveFile($animaldir . '/conf/acl.auth.php', join("\n", $aclfile)."\n"); 271 272 global $conf; 273 switch ($userreg) { 274 case 'allow': 275 $disableactions = join(',', array_diff(explode(',', $conf['disableactions']), array('register'))); 276 $ok &= io_saveFile($animaldir . '/conf/local.php', "\n" . '$conf[\'disableactions\'] = \''.$disableactions.'\';' . "\n", true); 277 break; 278 case 'disable': 279 $disableactions = join(',', array_merge(explode(',', $conf['disableactions']), array('register'))); 280 $ok &= io_saveFile($animaldir . '/conf/local.php', "\n" . '$conf[\'disableactions\'] = \''.$disableactions.'\';' . "\n", true); 281 break; 282 case 'inherit': 283 case true: 284 // nothing needs to be done 285 break; 286 default: 287 $ok &= io_saveFile($animaldir . '/conf/local.php', "\n" . '$conf[\'disableactions\'] = \'register\';' . "\n", true); 288 } 289 } 290 291 // deactivate plugins by default FIXME this should be nicer 292 $deactivatedPluginsList = explode(',', $this->getConf('deactivated plugins')); 293 $deactivatedPluginsList = array_map('trim', $deactivatedPluginsList); 294 $deactivatedPluginsList = array_unique($deactivatedPluginsList); 295 $deactivatedPluginsList = array_filter($deactivatedPluginsList); 296 foreach($deactivatedPluginsList as $plugin) { 297 $this->helper->setPluginState(trim($plugin), $name, 0); 298 } 299 300 return $ok; 301 } 302 303 /** 304 * Creates a new user line 305 * 306 * @param $password 307 * @return string 308 */ 309 protected function makeAdminLine($password) { 310 $pass = auth_cryptPassword($password); 311 $line = join( 312 ':', array( 313 'admin', 314 $pass, 315 'Administrator', 316 'admin@example.org', 317 'admin,user' 318 ) 319 ); 320 return $line; 321 } 322 323 /** 324 * Copies the current user as new admin line 325 * 326 * @return string 327 */ 328 protected function getAdminLine() { 329 $currentAdmin = $_SERVER['REMOTE_USER']; 330 $masterUsers = file_get_contents(DOKU_CONF . 'users.auth.php'); 331 $masterUsers = ltrim(strstr($masterUsers, "\n" . $currentAdmin . ":")); 332 $newAdmin = substr($masterUsers, 0, strpos($masterUsers, "\n") + 1); 333 return $newAdmin; 334 } 335 336} 337 338// vim:ts=4:sw=4:et: 339