summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorNick Daly <Nick.M.Daly@gmail.com>2013-04-23 17:49:22 -0500
committerNick Daly <Nick.M.Daly@gmail.com>2013-04-23 17:49:22 -0500
commitf55c7a48ea534e342e6efbd4c7edaf1b1e07f61b (patch)
treefec45d97e4e976ef7ba5dde83f538fcf19092bc0 /modules
parent157226f1b88bc090b677f9896aa62a0c734ebf14 (diff)
Merged with James's upstream.
Hope I did it right. If I screwed up, withsqlite is borked.
Diffstat (limited to 'modules')
l---------modules/first_boot.py1
-rw-r--r--modules/installed/first_boot.py120
-rw-r--r--modules/installed/help/help.py7
-rw-r--r--modules/installed/lib/forms.py33
4 files changed, 153 insertions, 8 deletions
diff --git a/modules/first_boot.py b/modules/first_boot.py
new file mode 120000
index 0000000..ae5c554
--- /dev/null
+++ b/modules/first_boot.py
@@ -0,0 +1 @@
+installed/first_boot.py \ No newline at end of file
diff --git a/modules/installed/first_boot.py b/modules/installed/first_boot.py
new file mode 100644
index 0000000..9cf7474
--- /dev/null
+++ b/modules/installed/first_boot.py
@@ -0,0 +1,120 @@
+from urlparse import urlparse
+import os, cherrypy, re
+from gettext import gettext as _
+from plugin_mount import PagePlugin, PluginMount, FormPlugin
+from modules.auth import require
+from forms import Form
+import util as u
+from vendor.withsqlite.withsqlite import sqlite_db
+import cfg
+
+class FirstBoot(PagePlugin):
+ def __init__(self, *args, **kwargs):
+ PagePlugin.__init__(self, *args, **kwargs)
+ self.register_page("firstboot") # this is the url this page will hang off of (/firstboot)
+
+ @cherrypy.expose
+ def index(self, *args, **kwargs):
+ return self.state0(*args, **kwargs)
+
+ ## TODO: flesh out these tests values
+ def valid_box_name_p(self, name):
+ name = name.strip()
+ if re.search("\W", name):
+ return False
+ return True
+ def valid_box_key_p(self, key):
+ return True
+ def generate_box_key(self):
+ return "fake key"
+
+ @cherrypy.expose
+ def state0(self, message="", box_name="", box_key="", submitted=False):
+ """
+ In this state, we do time config over HTTP, name the box and
+ server key selection.
+
+ All the parameters are form inputs. They get passed in when
+ the form is submitted. This method checks the inputs and if
+ they validate, uses them to take action. If they do not
+ validate, it displays the form to give the user a chance to
+ input correct values. It might display an error message (in
+ the message parameter).
+
+ message is an optional string that we can display to the
+ user. It's a good place to put error messages.
+ """
+
+ ## Until LDAP is in place, we'll put the box name and key in the cfg.store_file
+ ## Must resist the sick temptation to write an LDAP interface to the sqlite file
+ with sqlite_db(cfg.store_file, table="thisbox", autocommit=True) as db:
+ db['about'] = "This table is for information about this FreedomBox"
+ if box_name:
+ if self.valid_box_name_p(box_name):
+ db['box_name'] = box_name
+ else:
+ message += _("Invalid box name.")
+ elif 'box_name' in db and db['box_name']:
+ box_name = db['box_name']
+ #TODO: set /etc/hostname to box name via ex machina
+
+ if box_key:
+ if self.valid_box_key_p(box_key):
+ db['box_key'] = box_key
+ else:
+ message += _("Invalid key!")
+ elif 'box_key' in db and db['box_key']:
+ box_key = _("We already have a key for this box on file.") #TODO: Think this through and handle more gracefully
+ elif submitted and not box_key:
+ box_key = self.generate_box_key()
+ db['box_key'] = box_key
+
+
+ if box_name and box_key and self.valid_box_name_p(box_name) and self.valid_box_key_p(box_key):
+ ## Update state to 1 and head there
+ with sqlite_db(cfg.store_file, table="firstboot", autocommit=True) as db:
+ db['state']=1
+ raise cherrypy.InternalRedirect('/firstboot/state1')
+
+ main = "<p>Welcome. It looks like this FreedomBox isn't set up yet. We'll need to ask you a just few questions to get started.</p>"
+ form = Form(title="Welcome to Your FreedomBox!",
+ action="/firstboot",
+ name="whats_my_name",
+ message=message)
+ if not box_name:
+ box_name = cfg.box_name
+ form.html("<p>For convenience, your FreedomBox needs a name. It should be something short that doesn't contain spaces or punctuation. 'Willard' would be a good name. 'Freestyle McFreedomBox!!!' would not.</p>")
+ form.text_input('Name your FreedomBox', id="box_name", value=box_name)
+ form.html("<p>%(box_name)s uses cryptographic keys so it can prove its identity when talking to you. %(box_name)s can make a key for itself, but if one already exists (from a prior FreedomBox, for example), you can paste it below. This key should not be the same as your key because you are not your FreedomBox!</p>" % {'box_name':cfg.box_name})
+ form.text_box("If you want, paste your box's key here.", id="box_key", value=box_key)
+ form.hidden(name="submitted", value="True")
+ form.submit("Box it up!")
+
+ main += form.render()
+ return self.fill_template(template="base", title=_("First Boot!"), main=main,
+ sidebar_right=_("""<strong>Getting Help</strong><p>We've done our best to make your FreedomBox easy to use. If you have questions during setup, there are a few places to turn for help. TODO: add links to such help.</p>"""))
+
+ @cherrypy.expose
+ def state1(self, message=None):
+ """
+ State 1 is when we have a box name and key. In this state,
+ our task is to provide a certificate and maybe to guide the
+ user through installing it. We automatically move to State 2,
+ which is an HTTPS connection.
+
+ TODO: HTTPS failure in State 2 should returns to state 1.
+ """
+ main = """<p>Here's a certificate.
+TODO: explain all this cert stuff to the user.</p>
+<p>TODO: add instrux for installing certificate.</p>
+<p>After you have installed
+"""
+ if False:
+ ## Update state to 2 and head there
+ with sqlite_db(cfg.store_file, table="firstboot", autocommit=True) as db:
+ db['state']=1
+ #TODO: switch to HTTPS
+ raise cherrypy.InternalRedirect('/firstboot/state1')
+
+ return self.fill_template(template="base", title=_("Installing the Certificate"), main=main,
+ sidebar_right=_("""<strong>Getting Help</strong><p>We've done our best to make your FreedomBox easy to use. If you have questions during setup, there are a few places to turn for help. TODO: add links to such help.</p>"""))
diff --git a/modules/installed/help/help.py b/modules/installed/help/help.py
index 049f600..e05123b 100644
--- a/modules/installed/help/help.py
+++ b/modules/installed/help/help.py
@@ -83,7 +83,6 @@ class View(PagePlugin):
if page not in ['design', 'plinth', 'hacking', 'faq']:
raise cherrypy.HTTPError(404, "The path '/help/view/%s' was not found." % page)
return self.fill_template(template="err", main="<p>Sorry, as much as I would like to show you that page, I don't seem to have a page named %s!</p>" % page)
- IF = open(os.path.join("doc", "%s.part.html" % page), 'r')
- main = IF.read()
- IF.close()
- return self.fill_template(template="two_col", title=_("%s Documentation" % cfg.product_name), main=main)
+ with open(os.path.join("doc", "%s.part.html" % page), 'r') as IF:
+ main = IF.read()
+ return self.fill_template(title=_("%s Documentation" % cfg.product_name), main=main)
diff --git a/modules/installed/lib/forms.py b/modules/installed/lib/forms.py
index df78eea..2be810f 100644
--- a/modules/installed/lib/forms.py
+++ b/modules/installed/lib/forms.py
@@ -1,9 +1,32 @@
+"""
+The Form class is a helper class that takes parameters and method
+calls and can return html for a form with appropriate hooks for css
+styling. It should allow you to display a form but have the
+formatting and styling added by the class. You can worry less about
+how it looks while still getting consistent, decent-looking forms.
+
+Take a look at the FirstBoot class for an example of forms in action.
+
+Copyright 2011-2013 James Vasile
+
+This software is released to you (yes, you) under the terms of the GNU
+Affero General Public License, version 3 or later, available at
+<http://www.gnu.org/licenses/agpl.html>.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+"""
class Form():
def __init__(self, action=None, cls='form', title=None, onsubmit=None, name=None, message='', method="get"):
"""Note that there appears to be a bug in cherrypy whereby
forms submitted via post don't have their fields included in
kwargs for the default index method. So we use get by
- default, though it's not as neat."""
+ default, though it's not as neat.
+
+ TODO: file bug on this w/ CherryPy project
+ """
action = self.get_form_attrib_text('action', action)
onsubmit = self.get_form_attrib_text('onsubmit', onsubmit)
@@ -65,13 +88,15 @@ class Form():
<span>%s</span>
<input type="%s" class="inputtext" name="%s" id="%s" value="%s" size="%s"/>
</label>""" % (label, type, name, id, value, size)
- def text_box(self, label='', name=None, id=None):
+ def hidden(self, name=None, id=None, value=''):
+ self.text_input(type="hidden", name=name, id=id, value=value)
+ def text_box(self, label='', name=None, id=None, value=""):
name, id = self.name_or_id(name, id)
self.text += """
<label>
<span>%s</span>
- <textarea class="textbox" name="%s" id="%s"></textarea>
- </label>""" % (label, name, id)
+ <textarea class="textbox" name="%s" id="%s">%s</textarea>
+ </label>""" % (label, name, id, value)
def submit(self, label='', name=None, id=None):
name, id = self.name_or_id(name, id)
self.text += """