summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEudyptula <eitan@mosenkis.net>2009-07-15 16:16:23 -0400
committerEudyptula <eitan@mosenkis.net>2009-07-15 16:16:23 -0400
commit709c490155509f4c18f79f4d0632ab22ad32cc1a (patch)
tree5836ab01b99be05a05a254eca2e50de51237ae5d
parentAdded 'Show checked' link for package adder, fixed package selector verificat... (diff)
downloadingenue-709c490155509f4c18f79f4d0632ab22ad32cc1a.tar.gz
ingenue-709c490155509f4c18f79f4d0632ab22ad32cc1a.tar.bz2
ingenue-709c490155509f4c18f79f4d0632ab22ad32cc1a.zip
Added config status page, moving forward and back in config wizard; added config control of user registration and invites; added 'No results' in wlca search; cleaned up use of configuration object in wizard API; added step names to module metadata; check configurations for validity before building
-rw-r--r--frontend/classes/module.php3
-rw-r--r--frontend/classes/wizard_api.php146
-rw-r--r--frontend/css/wlca.css2
-rw-r--r--frontend/functions/owner_or_admin.php9
-rw-r--r--frontend/include/header.php10
-rw-r--r--frontend/js/wlca.js6
-rw-r--r--frontend/modules/gentoo_common.php2
-rw-r--r--frontend/pages/configurations/manager.php9
-rw-r--r--frontend/pages/configurations/status.php47
-rw-r--r--frontend/pages/configurations/verifier.php39
-rw-r--r--frontend/pages/configurations/wizard.php13
-rw-r--r--frontend/pages/invite.php12
-rw-r--r--frontend/pages/register.php4
-rw-r--r--frontend/routing.csv2
-rw-r--r--shared/classes/1conf_build_common.php9
-rw-r--r--shared/classes/configuration.php8
-rw-r--r--shared/classes/user.php2
-rw-r--r--shared/config.php2
-rw-r--r--shared/functions/load_config.php2
-rw-r--r--shared/include/defaults.php2
-rw-r--r--todo2
21 files changed, 190 insertions, 141 deletions
diff --git a/frontend/classes/module.php b/frontend/classes/module.php
index 8971c42..9e6f9d0 100644
--- a/frontend/classes/module.php
+++ b/frontend/classes/module.php
@@ -1,11 +1,12 @@
<?php
class module {
- var $id, $name, $steps, $dir;
+ public $id, $name, $numsteps, $steps, $dir;
function __construct($id) {
$this->id=$id;
require(FRONTEND."/modules/$id.info");
$this->name=$name;
$this->steps=$steps;
+ $this->numsteps=count($steps);
$this->dir=FRONTEND.'/modules/'.$dir;
}
}
diff --git a/frontend/classes/wizard_api.php b/frontend/classes/wizard_api.php
index 48fe637..381a267 100644
--- a/frontend/classes/wizard_api.php
+++ b/frontend/classes/wizard_api.php
@@ -1,30 +1,36 @@
<?php
class wizard_step {
- var $module, $step, $title, $next, $data=array();
- function __construct($mod, $step) {
- $this->module=new module($mod);
+ var $configuration, $module, $step, $title, $next, $data=array();
+ function __construct(&$c, $step, $noload=false) {
+ $this->configuration=&$c;
+ $this->module=new module($c->module);
$this->step=$step;
- $file=$this->module->dir."/step$step.php";
- if (!is_readable($file)) {
- throw_exception("$mod step $step doesn't exist!");
+ if (!$noload) {
+ $file=$this->module->dir."/step$step.php";
+ if (!is_readable($file)) {
+ throw_exception("$mod step $step doesn't exist!");
+ }
+ require($file);
}
- require($file);
- $this->title="Step $step/{$this->module->steps}".($title?" - $title":'');
- $this->next=isset($next)?$next:($this->step == $this->module->steps?null:$step+1);
+ $this->title=$this->module->steps[$step-1];
+ $this->next=isset($next)?$next:($this->step == $this->module->numsteps?null:$step+1);
}
public function output() {
global $conf;
- echo "<h3>$this->title</h3>\n";
- $scale=$conf['progressbar_width']/$this->module->steps;
- echo '<img src="'.url('images/full.gif').'" style="border-left: 1px solid black; border-top: 1px solid black; border-bottom: 1px solid black; width: '.$this->step*$scale.'px; height: 15px" /><img src="'.url('images/empty.gif').'" style="border-right: 1px solid black; border-top: 1px solid black; border-bottom: 1px solid black; width: '.($this->module->steps-$this->step)*$scale.'px; height: 15px" /><br/>'."\n";
- echo '<form action="'.url('config/'.wizard::$configuration->id).'" method="post">';
+ echo "<div class=\"wizard\" id=\"step$this->step\">";
+ echo '<form action="'.url('config/'.$this->configuration->id).'" method="post"><a style="float: right" href="'.url('config/'.$this->configuration->id.'/status').'">Status</a><h3>Step '.$this->step.': '.$this->title."</h3>\n";
+ $scale=$conf['progressbar_width']/$this->module->numsteps;
+ echo '<img src="'.url('images/full.gif').'" style="border-left: 1px solid black; border-top: 1px solid black; border-bottom: 1px solid black; width: '.$this->step*$scale.'px; height: 15px" /><img src="'.url('images/empty.gif').'" style="border-right: 1px solid black; border-top: 1px solid black; border-bottom: 1px solid black; width: '.(count($this->module->steps)-$this->step)*$scale.'px; height: 15px" /><br/>'."\n";
+ $this->echo_buttons();
foreach ($this->data as $obj) {
if (!$obj->status) {
echo print_warning('Please complete this field.');
}
$obj->output();
}
- echo '<br/><input type="submit" name="wizard_submit['.$this->step.']" value="Continue" />'."\n";
+ echo '<br/>';
+ $this->echo_buttons();
+ echo '</div>'."\n";
}
public function process() {
global $request;
@@ -41,75 +47,72 @@ class wizard_step {
}
public function verify() {
foreach ($this->data as $obj) {
- if (!$obj->status=$obj->verify()) {
- return false;
+ if (!($obj->status=$obj->verify())) {
+ return $obj->status;
}
}
return true;
}
private function text($text) {
- $this->data[]=new wizard_text($text);
+ $this->data[]=new wizard_text($this->configuration, $text);
}
private function text_input($optname, $htmlname, $label) {
- $this->data[]=new wizard_text_input($optname, $htmlname, $label);
+ $this->data[]=new wizard_text_input($this->configuration, $optname, $htmlname, $label);
}
private function select($optname, $htmlname, $label, $options) {
- $this->data[]=new wizard_select($optname, $htmlname, $label, $options);
+ $this->data[]=new wizard_select($this->configuration, $optname, $htmlname, $label, $options);
}
private function radio($optname, $htmlname, $label, $options) {
- $this->data[]=new wizard_radio($optname, $htmlname, $label, $options);
+ $this->data[]=new wizard_radio($this->configuration, $optname, $htmlname, $label, $options);
}
private function checkbox_array($optname, $htmlname, $label, $array, $delim=' ') {
- $this->data[]=new wizard_checkbox_array($optname, $htmlname, $label, $array, $delim=' ');
+ $this->data[]=new wizard_checkbox_array($this->configuration, $optname, $htmlname, $label, $array, $delim=' ');
}
private function layered_checkbox_array($optname, $htmlname, $label, &$array, $delim=' ', $metadata) {
- $this->data[]=new wizard_layered_checkbox_array($optname, $htmlname, $label, $array, $delim, $metadata);
+ $this->data[]=new wizard_layered_checkbox_array($this->configuration, $optname, $htmlname, $label, $array, $delim, $metadata);
}
private function query($q) {
return $GLOBALS['S']['pdo']->query($q);
}
private function get_opt($opt) {
- return wizard::get_opt($opt);
+ return $this->configuration->get_opt($opt);
+ }
+ private function echo_buttons() {
+ echo '<input type="button" onclick="window.location=\''.url('config/'.$this->configuration->id.'/'.($this->step-1)).'\'" value="Back" /> <input style="float: right" type="submit" name="wizard_submit['.$this->step.']" value="Next" /><br/>';
}
}
abstract class wizard {
- public $status=true;
- public static $configuration;
- public static function set_configuration(&$c) {
- self::$configuration=&$c;
+ public $status=true, $configuration;
+ function __construct(&$c) {
+ $this->configuration=&$c;
}
abstract public function output();
abstract public function process();
abstract public function verify();
abstract public function clear();
- public static function get_opt($name) {
- $opts=self::$configuration->get_opts();
- return isset($opts[$name])?$opts[$name]:null;
+ protected function get_opt($name) {
+ return $this->configuration->get_opt($name);
}
- protected static function set_opt($name, $val) {
+ protected function set_opt($name, $val) {
debug('wizard', "$name=$val");
if (substr($name, 0, 1) == ':') {
- self::$configuration->$name=$val;
- self::$configuration->write();
+ $this->configuration->$name=$val;
+ $this->configuration->write();
} else {
- self::$configuration->set_opt($name, $val);
+ $this->configuration->set_opt($name, $val);
}
}
- protected static function opt_is($name, $val) {
- $opts=self::$configuration->get_opts();
- if (isset($opts[$name]) && $opts[$name] === $val) {
- return true;
- } else {
- return false;
- }
+ protected function opt_is($name, $val) {
+ return $this->configuration->opt_is($name, $val);
}
- protected static function delete_opt($name) {
- self::$configuration->delete_opt($name);
+ protected function delete_opt($name) {
+ return $this->configuration->delete_opt($name);
}
}
class wizard_text extends wizard {
protected $text;
- function __construct($text) {
+ function __construct(&$c, $text) {
+ parent::__construct($c);
$this->text=$text;
}
public function output() {
@@ -125,7 +128,8 @@ class wizard_text extends wizard {
}
abstract class wizard_input extends wizard {
protected $optname, $htmlname, $label;
- function __construct($optname, $htmlname, $label) {
+ function __construct(&$c, $optname, $htmlname, $label) {
+ parent::__construct($c);
$this->optname=$optname;
$this->htmlname=htmlentities($htmlname);
$this->label=htmlentities($label);
@@ -143,10 +147,10 @@ abstract class wizard_input extends wizard {
}
}
public function verify() {
- return self::get_opt($this->optname)!==null;
+ return $this->get_opt($this->optname)!==null;
}
public function clear() {
- self::delete_opt($this->optname);
+ return $this->delete_opt($this->optname);
}
}
class wizard_text_input extends wizard_input {
@@ -157,8 +161,8 @@ class wizard_text_input extends wizard_input {
}
class wizard_select extends wizard_input {
private $options;
- function __construct($optname, $htmlname, $label, $options) {
- parent::__construct($optname, $htmlname, $label);
+ function __construct(&$c, $optname, $htmlname, $label, $options) {
+ parent::__construct($c, $optname, $htmlname, $label);
$this->options=$options;
}
public function output() {
@@ -166,7 +170,7 @@ class wizard_select extends wizard_input {
echo '<select name="'.$this->htmlname.'">'."\n";
$i=0;
foreach ($this->options as $val => $label) {
- echo "\t".'<option value="'.$i++.'"'.(self::opt_is($this->optname, $val)?' selected="selected"':'').'>'.htmlentities($label).'</option>'."\n";
+ echo "\t".'<option value="'.$i++.'"'.($this->opt_is($this->optname, $val)?' selected="selected"':'').'>'.htmlentities($label).'</option>'."\n";
}
echo '</select>'."\n";
}
@@ -174,12 +178,13 @@ class wizard_select extends wizard_input {
global $request;
$vals=array_keys($this->options);
if (isset($request[$this->htmlname]) && is_numeric($request[$this->htmlname]) && isset($vals[$request[$this->htmlname]])) {
- self::set_opt($this->optname, $vals[$request[$this->htmlname]]);
+ $this->set_opt($this->optname, $vals[$request[$this->htmlname]]);
return true;
} else return false;
}
public function verify() {
- return ($val=self::get_opt($this->optname)) !== null && in_array($val, array_keys($this->options));
+ if (($val=$this->get_opt($this->optname)) === null) return null;
+ return isset($this->options[$val]);
}
}
class wizard_radio extends wizard_select {
@@ -187,15 +192,15 @@ class wizard_radio extends wizard_select {
echo "$this->label:<br/>\n";
$i=0;
foreach ($this->options as $val => $label) {
- echo "\t<input type=\"radio\" id=\"$this->htmlname-$i\" name=\"$this->htmlname\" value=\"".$i."\"".(self::opt_is($this->optname, $val)?' checked="checked"':'')."\" /><label for=\"$this->htmlname-$i\">".htmlentities($label)."</label>\n";
+ echo "\t<input type=\"radio\" id=\"$this->htmlname-$i\" name=\"$this->htmlname\" value=\"".$i."\"".($this->opt_is($this->optname, $val)?' checked="checked"':'')."\" /><label for=\"$this->htmlname-$i\">".htmlentities($label)."</label>\n";
$i++;
}
}
}
class wizard_checkbox_array extends wizard_input {
protected $array;
- function __construct($optname, $htmlname, $label, $array, $delim=' ') {
- parent::__construct($optname, $htmlname, $label);
+ function __construct(&$c, $optname, $htmlname, $label, $array, $delim=' ') {
+ parent::__construct($c, $optname, $htmlname, $label);
$this->array=$array;
$this->delim=$delim;
}
@@ -203,22 +208,22 @@ class wizard_checkbox_array extends wizard_input {
echo "$this->label:<br/>\n";
$i=0;
foreach ($this->array as $val => $label) {
- echo "\t<input type=\"checkbox\" id=\"$this->htmlname-$i\" name=\"$this->htmlname[$i]\"".(self::opt_has($this->optname, $val, $this->delim)?' checked="checked"':'')." /><label for=\"$this->htmlname-$i\">$label</label><br/>\n";
+ echo "\t<input type=\"checkbox\" id=\"$this->htmlname-$i\" name=\"$this->htmlname[$i]\"".($this->opt_has($this->optname, $val, $this->delim)?' checked="checked"':'')." /><label for=\"$this->htmlname-$i\">$label</label><br/>\n";
$i++;
}
}
public function process() {
global $request;
$val=array();
- // FIXME we're assuming that array_keys order is determinate and the same as the foreach in output()
$vals=array_keys($this->array);
foreach ($request[$this->htmlname] as $i) {
$val[]=$vals[$i];
}
- self::set_opt($this->optname, implode($this->delim, $vals));
+ $this->set_opt($this->optname, implode($this->delim, $vals));
}
public function verify() {
- if (($vals=self::get_opt($this->optname)) === null) return false;
+ if (($vals=$this->get_opt($this->optname)) === null) return null;
+ if (strlen($vals) == 0) return true;
$vals=explode($this->delim, $vals);
foreach ($vals as $i => $val) {
if (isset($this->array[$val])) {
@@ -227,18 +232,18 @@ class wizard_checkbox_array extends wizard_input {
}
return count($vals) == 0;
}
- protected static function opt_has($name, $val, $delim=' ') {
- static $cache;
- if (!isset($cache[$name][$delim])) {
- $cache[$name][$delim]=explode($delim, self::get_opt($name));
+ private static $opt_cache;
+ protected function opt_has($name, $val, $delim=' ') {
+ if (!isset(self::$opt_cache[$name][$delim])) {
+ self::$opt_cache[$name][$delim]=explode($delim, $this->get_opt($name));
}
- return in_array($val, $cache[$name][$delim]);
+ return in_array($val, self::$opt_cache[$name][$delim]);
}
}
class wizard_layered_checkbox_array extends wizard_checkbox_array {
private $depth=0, $path_delims=array('', '/', '-');
- function __construct($optname, $htmlname, $label, &$array, $delim=' ', $metadata) {
- parent::__construct($optname, $htmlname, $label, &$array, $delim);
+ function __construct(&$c, $optname, $htmlname, $label, &$array, $delim=' ', $metadata) {
+ parent::__construct($c, $optname, $htmlname, $label, &$array, $delim);
$this->metadata=$metadata;
for ($i=current(&$array); is_array($i); $i=current($i)) $this->depth++;
global $S;
@@ -253,11 +258,12 @@ class wizard_layered_checkbox_array extends wizard_checkbox_array {
$this->r_output($this->array);
}
public function process() {
- self::set_opt($this->optname, implode($this->delim, $this->r_process($this->array)));
+ $this->set_opt($this->optname, implode($this->delim, $this->r_process($this->array)));
return true;
}
public function verify() {
- if (($vals=self::get_opt($this->optname)) === null) return false;
+ if (($vals=$this->get_opt($this->optname)) === null) return null;
+ if (strlen($vals) == 0) return true;
$vals=explode($this->delim, $vals);
$r=$this->r_verify($vals, $this->array);
debug('wlca', 'got results: '.implode(' ',$r));
@@ -288,7 +294,7 @@ class wizard_layered_checkbox_array extends wizard_checkbox_array {
$this->r_output($val, $depth+1, $name, $name);
$uid++;
}
- echo '</div>';
+ echo '<h3 style="display: none">No results</h3></div>';
echo "<script type=\"text/javascript\">\n<!--\nif (wlca_show_checked(document.getElementById('{$conf['id']}'), 0, $this->depth) == 0) wlca_search(document.getElementById('{$conf['id']}-q').value, document.getElementById('{$conf['id']}'), 0, $this->depth);\n-->\n</script>\n";
} else {
$meta=$this->metadata[$depth];
@@ -300,7 +306,7 @@ class wizard_layered_checkbox_array extends wizard_checkbox_array {
}
if (isset($meta['checkbox'])) {
$enc=self::b36($ucid++);
- echo '<input type="checkbox" id="-'.$enc.'" name="'.$this->htmlname.'['.$enc.']"'.(self::opt_has($this->optname, $this->format_label($array, $meta['checkbox'], $path, $name), $this->delim)?' checked="checked"':'').' /><label for="-'.$enc.'">'.$this->format_label($array, $meta['label'], $path, $name).'</label>'."\n";
+ echo '<input type="checkbox" id="-'.$enc.'" name="'.$this->htmlname.'['.$enc.']"'.($this->opt_has($this->optname, $this->format_label($array, $meta['checkbox'], $path, $name), $this->delim)?' checked="checked"':'').' /><label for="-'.$enc.'">'.$this->format_label($array, $meta['label'], $path, $name).'</label>'."\n";
} elseif (isset($meta['label'])) {
echo '<span class="wlcal">'.$this->format_label($array, $meta['label'], $path, $name)."</span>\n";
}
diff --git a/frontend/css/wlca.css b/frontend/css/wlca.css
index e090b89..2ff94a9 100644
--- a/frontend/css/wlca.css
+++ b/frontend/css/wlca.css
@@ -5,7 +5,7 @@
padding-left: 2em;
}
#plist {
- height: 400px;
+ max-height: 15em;
overflow: auto;
margin: 10px;
padding: 5px;
diff --git a/frontend/functions/owner_or_admin.php b/frontend/functions/owner_or_admin.php
new file mode 100644
index 0000000..d7b65c2
--- /dev/null
+++ b/frontend/functions/owner_or_admin.php
@@ -0,0 +1,9 @@
+<?php
+function owner_or_admin($id) {
+ global $S;
+ if (!isset($S['user'])) return false;
+ if ($S['user']->id === $id) return true;
+ if ($S['user']->has_flag('a')) return true;
+ return false;
+}
+?>
diff --git a/frontend/include/header.php b/frontend/include/header.php
index 0fa0b3a..81e8d7b 100644
--- a/frontend/include/header.php
+++ b/frontend/include/header.php
@@ -39,9 +39,11 @@ echo '<li><a href="'.url().'">Home</a></li>';
echo '<li><a href="'.url('create').'">New configuration</a></li>';
echo '<li><a href="'.url('configurations').'">Manage configurations</a></li>';
echo '<li><a href="'.url('logs').'">Log viewer</a></li>';
-if (isset($S['user']) && $S['user']->hasflag('a')) {
- echo '<li><a href="'.url('invite').'">Invite</a></li>';
-}
+if (isset($S['user'])) {
+ if ($conf['invite'] && ($S['user']->has_flag('a') || $conf['invite'] != 'admin'))
+ echo '<li><a href="'.url('invite').'">Invite</a></li>';
+} elseif ($conf['registration'])
+ echo '<li><a href="'.url('register').'">Register</a>';
?>
</ul>
</div>
@@ -52,7 +54,7 @@ if (isset($S['user']) && $S['user']->hasflag('a')) {
$links['logout'.(strlen($S['request'])?'/'.$S['request']:'')]='Logout';
} else {
$links['login'.(strlen($S['request'])?'/'.$S['request']:'')]='Login';
- $links['register']='Register';
+ if ($conf['registration']) $links['register']='Register';
}
foreach ($links as $url => $text) {
$links[$url]='<a href="'.url($url).'">'.htmlentities($text).'</a>';
diff --git a/frontend/js/wlca.js b/frontend/js/wlca.js
index d62994b..7c1b13e 100644
--- a/frontend/js/wlca.js
+++ b/frontend/js/wlca.js
@@ -51,6 +51,9 @@ function wlca_search(q, el, depth, maxdepth, t) {
wlca_collapse(el.id);
}
}
+ if (depth == 0) {
+ el.childNodes[el.childNodes.length-1].style.display=found?"none":"";
+ }
return found;
}
function wlca_show_checked(el, depth, maxdepth) {
@@ -69,5 +72,8 @@ function wlca_show_checked(el, depth, maxdepth) {
el.childNodes[i].style.display=(lfound > 0?"":"none");
}
}
+ if (depth == 0) {
+ el.childNodes[el.childNodes.length-1].style.display=found?"none":"";
+ }
return found;
}
diff --git a/frontend/modules/gentoo_common.php b/frontend/modules/gentoo_common.php
index cac9b4b..bc72b0b 100644
--- a/frontend/modules/gentoo_common.php
+++ b/frontend/modules/gentoo_common.php
@@ -1,4 +1,4 @@
<?php
-$steps=3;
+$steps=array('Profile', 'Extra Packages', 'Image Format');
$dir='gentoo';
?>
diff --git a/frontend/pages/configurations/manager.php b/frontend/pages/configurations/manager.php
index 15ab529..148a470 100644
--- a/frontend/pages/configurations/manager.php
+++ b/frontend/pages/configurations/manager.php
@@ -20,7 +20,10 @@ function body_configurations_manager() {
} else {
$name=isset($request['name'])?$request['name']:null;
$build=$c->build($name);
- echo print_success('Submitted for build - <a href="'.url('logs/'.$build->id).'">Logs</a>');
+ if (is_object($build))
+ echo print_success('Submitted for build - <a href="'.url('logs/'.$build->id).'">Logs</a>');
+ else
+ echo print_error('Invalid configuration', 'Your configuration could not be submitted for build. Please return to <a href="'.url("config/$c->id/$build").'">step '.$build.'</a> and continue configuration from there.');
}
}
echo '<form action="'.url('configurations').'" method="post"><table><tr><th>ID</th><th>Name</th>'.(count($conf['modules']) > 1?'<th>Module</th>':'').'<th>Status</th><th>Options</th><th>Builds</th></tr>'."\n";
@@ -39,9 +42,9 @@ function body_configurations_manager() {
echo "$c->module</td><td>";
}
if ($c->status > 0) {
- echo '<a href="'.url("config/$c->id")."\">Step $c->status</a>'";
+ echo '<a href="'.url("config/$c->id")."\">Step $c->status</a>";
} elseif ($c->status == 0) {
- echo '<b>Ready</b> (<a href="'.url('verify/'.$c->id).'">verify</a>)';
+ echo '<b>Ready</b> (<a href="'.url("config/$c->id/status").'">modify</a>)';
} else {
echo $c->status;
}
diff --git a/frontend/pages/configurations/status.php b/frontend/pages/configurations/status.php
new file mode 100644
index 0000000..ebeeab3
--- /dev/null
+++ b/frontend/pages/configurations/status.php
@@ -0,0 +1,47 @@
+<?php
+function init_configurations_status() {
+ global $S, $request;
+ if (!isset($S['user'])) {
+ return 'login';
+ }
+ if (!(isset($request['configuration']) && strlen($request['configuration']) == 6 && ctype_alnum($request['configuration']))) {
+ return '404';
+ }
+ $r=$S['pdo']->query('SELECT * FROM `configurations` WHERE `id`=\''.$request['configuration'].'\'');
+ if ($r->rowCount() == 0) {
+ return '404';
+ }
+ $S['status']['configuration']=new sql_configuration($r->fetch(PDO::FETCH_ASSOC));
+ if ($S['status']['configuration']->owner != $S['user']->id) {
+ return '404';
+ }
+ return array('title' => 'Status');
+}
+function body_configurations_status() {
+ global $S;
+ $c=&$S['status']['configuration'];
+ $module=new module($c->module);
+ $status=true;
+ $good=0;
+ for ($i=1; $i<=$module->numsteps; $i++) {
+ $r[$i]='<li>';
+ $step=new wizard_step($c, $i, !$status);
+ $r[$i].=($status?'<a href="'.url("config/$c->id/$i")."\">$step->title</a>":$step->title);
+ if ($status) {
+ $r[$i].=' - ';
+ $good+=($status=$step->verify())?1:0;
+ if ($status === null)
+ $r[$i].='<span style="color: yellow; background-color: black">Incomplete</span>';
+ elseif ($status)
+ $r[$i].='<span style="color: green">Complete</span>';
+ else
+ $r[$i].='<span style="color: red">INVALID</span>';
+ }
+ $r[$i].='</li>';
+ }
+ echo '<h3>'.($c->name?htmlentities($c->name):$c->id).": $good of $module->numsteps steps complete</h3>\n";
+ echo '<ol>'.implode('', $r).'</ol>';
+ if ($good < $module->numsteps)
+ echo '<a href="'.url("config/$c->id/".($good+1)).'">Finish configuration</a>';
+}
+?>
diff --git a/frontend/pages/configurations/verifier.php b/frontend/pages/configurations/verifier.php
deleted file mode 100644
index ae27c3c..0000000
--- a/frontend/pages/configurations/verifier.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-function init_configurations_verifier() {
- global $S, $request;
- if (!isset($S['user'])) {
- return 'login';
- }
- if (!(isset($request['configuration']) && strlen($request['configuration']) == 6 && ctype_alnum($request['configuration']))) {
- return '404';
- }
- $r=$S['pdo']->query('SELECT * FROM `configurations` WHERE `id`=\''.$request['configuration'].'\'');
- if ($r->rowCount() == 0) {
- return '404';
- }
- $S['verifier']['configuration']=new sql_configuration($r->fetch(PDO::FETCH_ASSOC));
- if ($S['verifier']['configuration']->owner != $S['user']->id) {
- return '404';
- }
- return array('title' => 'Verify');
-}
-function body_configurations_verifier() {
- global $S;
- $c=&$S['verifier']['configuration'];
- wizard::set_configuration($c);
- $module=new module($c->module);
- $status=true;
- echo '<ol>';
- for ($i=1; $i<=$module->steps; $i++) {
- echo '<li>';
- if ($status) {
- $step=new wizard_step($c->module, $i);
- $status=$status && ($r=$step->verify());
- echo $r?'Valid':'INVALID';
- } else {
- echo 'Unavailable';
- }
- echo '</li>';
- }
-}
-?>
diff --git a/frontend/pages/configurations/wizard.php b/frontend/pages/configurations/wizard.php
index 571f803..cc46405 100644
--- a/frontend/pages/configurations/wizard.php
+++ b/frontend/pages/configurations/wizard.php
@@ -10,7 +10,6 @@ function init_configurations_wizard() {
if ($configuration->owner != $S['user']->id) {
return '404';
}
- wizard::set_configuration($S['wizard']['configuration']);
if (isset($request['wizard_submit'])) {
$steps=array_keys($request['wizard_submit']);
$step=$steps[0];
@@ -22,6 +21,7 @@ function init_configurations_wizard() {
} elseif ($result === null) {
debug('wizard', "$configuration->module step $step returned <i>null</i> - config finished");
$configuration->status=0;
+ unset($S['wizard']['step']);
$configuration->write();
} else {
$configuration->status=$result;
@@ -45,7 +45,7 @@ function init_configurations_wizard() {
wizard_load_step(1);
}
if (isset($S['wizard']['step'])) {
- return array('title' => $S['wizard']['step']->title);
+ return array('title' => "Step {$S['wizard']['step']->step}: {$S['wizard']['step']->title}");
} else {
return array('title' => 'Create');
}
@@ -54,11 +54,10 @@ function body_configurations_wizard() {
global $S, $conf;
if (isset($S['wizard']['configuration'])) {
$configuration=&$S['wizard']['configuration'];
- if ($configuration->status == 0) {
- echo print_success('Config finished!', '<form action="'.url('configurations').'" method="post"><input type="hidden" name="configuration" value="'.$configuration->id.'" />Name (optional): <input name="name" value="'.($configuration->name?htmlentities($configuration->name):'').'" /> <input type="submit" name="build" value="Build" /></form>');
- } else {
+ if (isset($S['wizard']['step']))
$S['wizard']['step']->output();
- }
+ else
+ echo print_success('Config finished!', '<form action="'.url('configurations').'" method="post"><input type="hidden" name="configuration" value="'.$configuration->id.'" />Name (optional): <input name="name" value="'.($configuration->name?htmlentities($configuration->name):'').'" /> <input type="submit" name="build" value="Build" /></form>');
} else {
echo '<form action="'.url('create').'" method="post"><h3>Request an image built</h3>Name of your configuration (optional): <input name="name" /><br/>';
if (count($conf['modules']) > 1) {
@@ -76,7 +75,7 @@ function body_configurations_wizard() {
function &wizard_load_step($step) {
global $S;
if (!isset($S['wizard']['steps'][$step])) {
- $S['wizard']['steps'][$step]=new wizard_step($S['wizard']['configuration']->module, $step);
+ $S['wizard']['steps'][$step]=new wizard_step($S['wizard']['configuration'], $step);
}
$S['wizard']['step']=&$S['wizard']['steps'][$step];
return $S['wizard']['steps'];
diff --git a/frontend/pages/invite.php b/frontend/pages/invite.php
index a04a12d..69047ab 100644
--- a/frontend/pages/invite.php
+++ b/frontend/pages/invite.php
@@ -1,12 +1,10 @@
<?php
function init_invite() {
- global $S;
- if (!isset($S['user'])) {
- return 'login';
- }
- if (!$S['user']->hasflag('a')) {
- return 'denied';
- }
+ global $S, $conf;
+ if (!$conf['invite']) return '404';
+ if (!isset($S['user'])) return 'login';
+ if ($conf['invite'] == 'admin' && !$S['user']->has_flag('a')) return '404';
+ return array('title' => 'Invite');
}
function body_invite() {
global $S, $request, $conf;
diff --git a/frontend/pages/register.php b/frontend/pages/register.php
index e624ac1..1f76c69 100644
--- a/frontend/pages/register.php
+++ b/frontend/pages/register.php
@@ -1,6 +1,6 @@
<?php
function init_register() {
- global $S, $request;
+ global $S, $request, $conf;
if (isset($S['user'])) {
header('Location: '.url());
return 'welcome';
@@ -24,7 +24,7 @@ function init_register() {
}
}
}
- }
+ } elseif (!$conf['registration']) return '404';
return array('title' => 'Register');
}
function body_register() {
diff --git a/frontend/routing.csv b/frontend/routing.csv
index 492e59e..7737b69 100644
--- a/frontend/routing.csv
+++ b/frontend/routing.csv
@@ -21,8 +21,8 @@
^create$ configurations/wizard
^config/([a-zA-Z0-9]{6})$ configurations/wizard configuration
^config/([a-zA-Z0-9]{6})/([0-9]+)$ configurations/wizard configuration step
+^config/([a-zA-Z0-9]{6})/status$ configurations/status configuration
^configurations$ configurations/manager
-^verify/([a-zA-Z0-9]{6})$ configurations/verifier configuration
# Download finished image
^download/([a-zA-Z0-9]{6})$ downloadimage build
# Session
diff --git a/shared/classes/1conf_build_common.php b/shared/classes/1conf_build_common.php
index aae1e42..35ba6e6 100644
--- a/shared/classes/1conf_build_common.php
+++ b/shared/classes/1conf_build_common.php
@@ -41,6 +41,15 @@ abstract class conf_build_common extends sql_row_obj {
}
return $opts;
}
+ // Returns the value (or object if $get_obj is true) of the option given by $name, or null if unset
+ public function get_opt($name, $get_obj=false) {
+ $opts=$this->get_opts($get_obj);
+ return isset($opts[$name])?$opts[$name]:null;
+ }
+ // Returns true if the given option is set and equals the given value, false otherwise
+ public function opt_is($name, $val) {
+ return (($r=$this->get_opt($name)) !== null && $r == $val);
+ }
// Generates a unique id and sets status to 1, writes self to db and returns id
public function init() {
global $S;
diff --git a/shared/classes/configuration.php b/shared/classes/configuration.php
index fedef12..2714732 100644
--- a/shared/classes/configuration.php
+++ b/shared/classes/configuration.php
@@ -31,9 +31,15 @@ class sql_configuration extends conf_build_common {
'not_null' => true,
'default' => 0
)
-
);
public function build($name=null) {
+ $module=new module($this->module);
+ for ($i=1; $i<=$module->numsteps; $i++) {
+ $step=new wizard_step($this, $i);
+ if (!$step->verify()) {
+ return $i;
+ }
+ }
$build=new sql_build();
$build->init();
$build->name=$name;
diff --git a/shared/classes/user.php b/shared/classes/user.php
index 91a7a46..eef0977 100644
--- a/shared/classes/user.php
+++ b/shared/classes/user.php
@@ -35,7 +35,7 @@ class sql_user extends sql_row_obj {
)
);
- public function hasflag($flag) {
+ public function has_flag($flag) {
return (strpos($this->flags, $flag) !== false);
}
}
diff --git a/shared/config.php b/shared/config.php
index 1ac1ae7..2f73991 100644
--- a/shared/config.php
+++ b/shared/config.php
@@ -15,6 +15,8 @@ $emailfrom='noreply@gentoo.org'; // Used as the From: field in emails
$check_email_dns=true; // Use DNS to check the domain of submitted emails for validity
// $split_setup=false; // Whether the frontend and backend are running on different hosts
// Frontend options:
+// $registration=false; // Whether users can create new accounts without an invite
+// $invite='admin'; // Who can use the invite function: true or 'user'=users; admin=admins; false=nobody
// $logview_max=1000; // The maximum number of log entries shown on one page (1000 is a good start)
// $progressbar_width=350; // The width, in pixels, of the config wizard progress bar
// Backend options:
diff --git a/shared/functions/load_config.php b/shared/functions/load_config.php
index 27e01bc..7bf94b4 100644
--- a/shared/functions/load_config.php
+++ b/shared/functions/load_config.php
@@ -3,7 +3,7 @@ function load_config() {
require(SHARED.'/include/defaults.php');
require(SHARED.'/config.php');
$modules=explode(' ', $modules);
- foreach (explode(' ', 'title sqlhost sqluser sqlpass sqldb debug modules bundlers cookiename sessionlength mod_rewrite emailfrom check_email_dns split_setup logview_max progressbar_width pkgdir_root emerge_default_opts portdir frontend_location backend_id') as $var) {
+ foreach (explode(' ', 'title sqlhost sqluser sqlpass sqldb debug modules bundlers cookiename sessionlength mod_rewrite emailfrom check_email_dns split_setup registration invite logview_max progressbar_width pkgdir_root emerge_default_opts portdir frontend_location backend_id') as $var) {
if (isset($$var)) {
$GLOBALS['conf'][$var]=$$var;
}
diff --git a/shared/include/defaults.php b/shared/include/defaults.php
index 4065cc0..66862a8 100644
--- a/shared/include/defaults.php
+++ b/shared/include/defaults.php
@@ -24,6 +24,8 @@ $mod_rewrite=true;
$emailfrom='noreply@noreply.net';
$check_email_dns=false;
$split_setup=false;
+$registration=false;
+$invite='admin';
$logview_max=1000;
$progressbar_width=350;
$emerge_default_opts='-t -v -K --color=y --root-deps=rdeps';
diff --git a/todo b/todo
index ef10f65..e8a6bbf 100644
--- a/todo
+++ b/todo
@@ -1,6 +1,5 @@
Have backend handle builds that it finds to already be running (break in to steps and store current status)
Make package adding friendly for browsers without JS/CSS (use ul/li, not div)
-Add configuration verification - each step must be validated before a build is submitted (check selected packages are available, etc.)
Write a live git ebuild
Write an AJAX-based self-updating status viewer
*** Add logging besides just commands ***
@@ -19,7 +18,6 @@ Completely plan out how frontend modules should function - each step needs to re
Allow backend to define bail-out functions to call when it dies (things like unmounting the ISO it was copying)
Add STDERR (maybe STDOUT) only option to log viewer
Simplify status to numeric on builds - varchar isn't necessary
-Add config option to enable/disable user self-registration/invitations/admin-only invites
Move gentoo_profiles setup out of the general setup.php, allow per-module setup
Move bundler selection out of gentoo module and generalize it (switch to builds instead of configurations)
Improve the quality of base system creation (if necessary)