]> andersk Git - sql.git/commitdiff
implemented base interface
authorJoe Presbrey <presbrey@mit.edu>
Fri, 13 Mar 2009 11:50:51 +0000 (11:50 +0000)
committerJoe Presbrey <presbrey@mit.edu>
Fri, 13 Mar 2009 11:50:51 +0000 (11:50 +0000)
git-svn-id: svn://presbrey.mit.edu/sql@171 a142d4bd-2cfb-0310-9673-cb33a7e74f58

22 files changed:
etc/mitsql.ini [new file with mode: 0644]
lib/python/mitsql/__init__.py
lib/python/mitsql/config.py [new file with mode: 0644]
lib/python/mitsql/interface/__init__.py
lib/python/mitsql/interface/cheetah.py [moved from lib/python/mitsql/templates.py with 61% similarity]
lib/python/mitsql/interface/display.py [new file with mode: 0644]
lib/python/mitsql/interface/handler.py [new file with mode: 0644]
lib/python/mitsql/interface/main.py [deleted file]
libexec/daily_afs_backups
sbin/start [new file with mode: 0755]
www/etc/devel.conf [new file with mode: 0644]
www/etc/live.conf [new file with mode: 0644]
www/root/assets/css/style.css [new file with mode: 0644]
www/templates/common/_404.tmpl [new file with mode: 0644]
www/templates/common/_500.tmpl [new file with mode: 0644]
www/templates/common/shell.tmpl [new file with mode: 0644]
www/templates/common/skeleton.tmpl [new file with mode: 0644]
www/templates/main/contact.tmpl [new file with mode: 0644]
www/templates/main/db_list.tmpl [new file with mode: 0644]
www/templates/main/index.tmpl [new file with mode: 0644]
www/templates/main/passwd.tmpl [new file with mode: 0644]
www/templates/main/signup.tmpl [new file with mode: 0644]

diff --git a/etc/mitsql.ini b/etc/mitsql.ini
new file mode 100644 (file)
index 0000000..7220cfb
--- /dev/null
@@ -0,0 +1,5 @@
+[_DEFAULT]
+db_host=sql.mit.edu
+db_user=root
+db_pass=
+db_name=mitsql
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4282e02a4da34716e948042840efeb6ff866c4d9 100644 (file)
@@ -0,0 +1,10 @@
+import config
+import os as _os
+if False and config._ENV_BASE in _os.environ.keys():
+    _base = _os.environ[config._ENV_BASE]
+else:
+    _base = _os.path.abspath(_os.path.dirname(_os.path.realpath(__file__)) + '/../../../')
+config = config.Config('mitsql.ini')
+
+import logging
+logging.disable(logging.DEBUG)
\ No newline at end of file
diff --git a/lib/python/mitsql/config.py b/lib/python/mitsql/config.py
new file mode 100644 (file)
index 0000000..4c8e3f0
--- /dev/null
@@ -0,0 +1,83 @@
+"""
+Global configuration objects.
+
+Joe Presbrey  <presbrey@mit.edu>
+"""
+
+from ConfigParser import ConfigParser, NoSectionError, NoOptionError
+import os
+
+_ENV_BASE='_SQL_MIT_EDU'
+
+class Section(object):
+    """Configuration section namespace."""
+    def __init__(self, d):
+        self.items = d
+
+    def __getattr__(self, k):
+        v = self.items.get(k, None)
+        try:
+            if str(int(v)) == str(v): v = int(v)
+        except TypeError: pass
+        except ValueError: pass
+        try:
+            if str(v).lower() == 'true': v = True
+            if str(v).lower() == 'false': v = False
+        except TypeError: pass
+        except ValueError: pass
+        return v
+
+    def __iter__(self):
+        return iter(self.items)
+
+    def __str__(self):
+        return str(self.items)
+
+class Config(object):
+    """Base configuration namespace."""
+    def __init__(self, filename, *args, **kwargs):
+        self._cp = ConfigParser(*args, **kwargs)
+        self.read(filename)
+        self._none = Section({})
+    
+    def _samefile(self, f1, f2):
+        try:
+            return os.path.samefile(f1, f2)
+        except OSError, e:
+            return False
+    
+    def read(self, filename):
+        config_path = [os.path.join(x, filename) for x in [
+            os.path.dirname(__file__),
+            '/etc']]
+        if _ENV_BASE in os.environ:
+            config_path.insert(1, os.path.join(os.environ[_ENV_BASE], 'etc', filename))
+        def append(path):
+            r = os.path.join(path, filename)
+            if not r in config_path:
+                config_path.append(r)
+        if 'HOME' in os.environ:
+            append(os.environ['HOME'])
+        if 'PWD' in os.environ:
+            append(os.environ['PWD'])
+        self._cp.read(config_path)
+        self._sections = dict(map(lambda x: (x, Section(dict(self._cp.items(x)))),
+                                  self._cp.sections()))
+    
+    def get(self, *av, **kw):
+        try: return self._cp.get(*av, **kw)
+        except NoSectionError: return None
+        except NoOptionError: return None
+    
+    def __getattr__(self, k):
+        return self._sections.get(k, self._none)
+    
+    def __str__(self):
+        d = {}
+        for x in self._cp.sections():
+            d[x] = dict(self._cp.items(x))
+        return str(d)
+
+if __name__ == '__main__':
+    import mitsql
+    print mitsql.config
index 41c4f7ac7d6b785bb478d94cd895f7719d70931a..46366077124a57fe2399520ddbab453997fc3f6a 100644 (file)
@@ -1,7 +1,24 @@
-import cherrypy
+import mitsql
+config = mitsql.config.interface
+
+from MySQLdb import Connection as _connect
+from MySQLdb.cursors import DictCursor as _cursor
+
+def _connect(*argv, **kw):
+    return _connect(config.db_host, config.db_user, config.db_pass, config.db_name, cursorclass=_Cursor)
 
-from main import Root as root
-root = root()
+from handler import Root as _root
+root = _root()
+
+from cheetah import load
+load(mitsql._base + '/www/templates')
+
+import cherrypy
+cherrypy.tree.mount(root, '/')
+cherrypy.config.update({'error_page.404': root.error._404,
+                        'error_page.500': root.error._500,
+                        'tools.staticdir.on': True,
+                        'tools.staticdir.dir': mitsql._base + '/www/root'})
 
 def map_uri():
     print root.default()
@@ -11,5 +28,5 @@ def map_uri():
     #    if authorization:
     #        cherrypy.request.login = parseAuthorization(authorization)
 
-cherrypy.tools.map_uri = cherrypy.Tool('on_start_resource', map_uri)
+#cherrypy.tools.map_uri = cherrypy.Tool('on_start_resource', map_uri)
 #cherrypy.tools.map_uri = cherrypy.Tool('before_request_body', map_uri)
similarity index 61%
rename from lib/python/mitsql/templates.py
rename to lib/python/mitsql/interface/cheetah.py
index f72800564dbddc75e689d90f421da396126d130b..22a2b170cf9a25b4c4502ce976a322916324911f 100644 (file)
@@ -1,16 +1,15 @@
-# Joe Presbrey  <presbrey@mit.edu>
-
+import qwobl
 import os, sys, types, time
 import threading 
 from pyinotify import WatchManager, Notifier, EventsCodes
 from Cheetah.Template import Template as _Template
-
-__all__ = ['Templates']
+import logging
 
 class Template(object):
-    def __init__(self, name, ns={}, path=['templates']):
-        self._name, self._ns, self._path = name, ns, path+[name]
-        assert self._template()
+    def __init__(self, name='templates', ns={}, path=[]):
+        self._name, self._ns, self._path = name, ns, len(path) and path+[name] or [name]
+        if len(self._path) > 1:
+            assert self._template()
     
     def _template(self):
         return sys.modules['.'.join(self._path)]
@@ -24,8 +23,7 @@ class Template(object):
         return getattr(self._template(),
                        self._name)(namespaces=namespaces).respond()
 
-class Templates(object):
-    _base = ''
+class Loader(object):
     _mask = EventsCodes.ALL_FLAGS['IN_CREATE'] \
           | EventsCodes.ALL_FLAGS['IN_MODIFY'] \
           | EventsCodes.ALL_FLAGS['IN_DELETE'] \
@@ -38,12 +36,10 @@ class Templates(object):
     _files = {}
     _modules = {}
     
-    def __init__(self, template_path, global_namespace={}):
-        self._base = os.path.abspath(template_path)
+    def __init__(self, global_namespace={}):
         self._event_init()
-        self._assert_module('templates', [template_path])
+        self._assert_module('templates')
         self._globals = global_namespace
-        self.load()
         self._thread = threading.Thread(target=self.loop)
         self._thread.setDaemon(True)
         self._thread.start()
@@ -71,9 +67,9 @@ class Templates(object):
                 self._modules[name].__path__ = path
             sys.modules[name] = self._modules[name]
     
-    def _get_template_path(self, template_file):
-        r = template_file.startswith(self._base) \
-          and template_file[len(self._base)+1:].split(os.path.sep) or []
+    def _get_template_path(self, path_name, template_file):
+        r = template_file.startswith(path_name) \
+          and template_file[len(path_name)+1:].split(os.path.sep) or []
         if r[-1].endswith('.tmpl'):
             r[-1] = r[-1][:-5]
         return tuple(r)
@@ -87,8 +83,8 @@ class Templates(object):
                                      compilerSettings={'useStackFrames':False})
         return template
     
-    def add(self, template_file):
-        template_path = self._get_template_path(template_file)
+    def add(self, path_name, template_file):
+        template_path = self._get_template_path(path_name, template_file)
         template_name = '.'.join(['templates']+list(template_path))
         template_pkg = '.'.join(['templates']+list(template_path[:-1]))
         template_py = os.path.join(os.path.dirname(template_file), '%s.py' % template_path[-1])
@@ -98,47 +94,51 @@ class Templates(object):
         f_code = file(template_py, 'w')
         f_code.write(code)
         f_code.close()
-        if self._loaded and \
-           template_name in sys.modules:
+        if template_name in sys.modules:
             reload(sys.modules[template_name])
     
     def remove(self, template_file):
         #print 'removing', template_file
         pass
     
-    def _walk_load(self, args, dname, fnames):
-        for fname in fnames:
-            if fname.endswith('.tmpl'):
-                template_file = os.path.join(dname, fname)
-                self.add(template_file)
-    
-    def load(self):
-        if not self._loaded:
-            os.path.walk(self._base, self._walk_load, None)
-            for path, filename in self._files.items():
-                __import__('.'.join(['templates']+list(path)))
-            self._loaded = True
-    
-    def _event_handler(self, event):
-        if event.name.endswith('.tmpl') and not event.name.startswith('.'):
-            if event.maskname == 'IN_DELETE':
-                self.remove(event.pathname)
-            else:
-                time.sleep(0.5)
-                self.add(event.pathname)
-                
+    def _walk_path(self, path_name):
+        def _walk_load(args, dname, fnames):
+            for fname in fnames:
+                if fname.endswith('.tmpl'):
+                    template_file = os.path.join(dname, fname)
+                    self.add(path_name, template_file)
+        return _walk_load
+    
+    def load(self, path_name):
+        os.path.walk(path_name, self._walk_path(path_name), None)
+        for path, filename in self._files.items():
+            logging.debug('TEMPLATE LOAD [%s] %s', path, filename)
+            __import__('.'.join(['templates']+list(path)))
+        self._event_add_watch(path_name)
+    
+    def _path_event_handler(self, path_name):
+        def _event_handler(event):
+            logging.debug('TEMPLATE EVENT: %s', repr(event.__dict__.items()))
+            if event.name.endswith('.tmpl') and not event.name.startswith('.'):
+                if event.maskname == 'IN_DELETE':
+                    self.remove(event.pathname)
+                else:
+                    time.sleep(0.5)
+                    self.add(path_name, event.pathname)
+        return _event_handler
     
     def _event_init(self):
         self._watch_manager = WatchManager()
-        self._watch_manager.add_watch(self._base,
-                                      self._mask,
-                                      self._event_handler,
-                                      rec=True,
-                                      auto_add=True)
         self._notifier = Notifier(self._watch_manager)
     
+    def _event_add_watch(self, path_name):
+        r = self._watch_manager.add_watch(path_name,
+                                          self._mask,
+                                          self._path_event_handler(path_name),
+                                          rec=True,
+                                          auto_add=True)
+    
     def loop(self):
-        self.load()
         while True:
             try:
                 self._notifier.process_events()
@@ -147,9 +147,12 @@ class Templates(object):
             except KeyboardInterrupt:
                 self._notifier.stop()
                 break
-    
-    def __getattr__(self, key):
-        return Template(key, self._globals)
+
+_loader = Loader()
+load = _loader.load
+templates = Template()
+
+__all__ = ['load', 'templates']
 
 if __name__ == '__main__':
-    t = Templates('/home/joe/templates')
+    t = Loader('/home/joe/templates')
diff --git a/lib/python/mitsql/interface/display.py b/lib/python/mitsql/interface/display.py
new file mode 100644 (file)
index 0000000..e39d1ae
--- /dev/null
@@ -0,0 +1,2 @@
+def db_list_entry(name, size_tot, size_max):
+    return '%s: %s/%s' % (name, size_tot, size_max)
\ No newline at end of file
diff --git a/lib/python/mitsql/interface/handler.py b/lib/python/mitsql/interface/handler.py
new file mode 100644 (file)
index 0000000..14eac9e
--- /dev/null
@@ -0,0 +1,48 @@
+import mitsql
+from cheetah import templates
+import cherrypy
+
+from pprint import pformat
+
+def _500(*argv, **kw):
+    s_exc = cherrypy._cperror.format_exc()
+    mitsql.logging.error(s_exc)
+    return templates.common.shell(title='%s (CherryPy %s)' % (kw.get('status'), kw.get('version')),
+                                  content=('<p>%s</p>' + (2*'<div><pre>%s</pre></div>'))
+                                  % (kw.get('message'), kw.get('traceback'),
+                                     _phtml(dict(filter(lambda x: not x[0][:2] == '__',
+                                                        cherrypy.request.__dict__.items())))))
+
+class Root(object):
+    class Error(object):
+        @cherrypy.expose
+        def _404(*argv, **kw):
+            return templates.common._404()
+        def _500(*argv, **kw):
+            return _500(*argv, **kw)
+    error = Error()
+    
+    class DB(object):
+        def list(*argv, **kw):
+            r = {'db_list': [],
+                 'size_tot': '1M',
+                 'size_max': '100M',
+                 'user': {
+                 'db_prefix': 'presbrey+'
+                 }}
+            return templates.main.db_list(**r)
+        list.exposed = True
+    db = DB()
+
+    def test(self, *argv, **kw):
+        cherrypy.response.headers['Content-type'] = 'text/plain'
+        return pformat(dict(filter(lambda x: not x[0][:2] == '__', cherrypy.request.__dict__.items())))
+    test.exposed = True
+
+    def index(self, *argv, **kw):
+        return templates.main.index()
+    index.exposed = True
+    
+    def passwd(self, *argv, **kw):
+        return templates.main.passwd()
+    passwd.exposed = True
\ No newline at end of file
diff --git a/lib/python/mitsql/interface/main.py b/lib/python/mitsql/interface/main.py
deleted file mode 100644 (file)
index 39f8591..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-import cherrypy
-from pprint import pformat
-
-class Root(object):
-    def default(self, *args, **kw):
-        cherrypy.response.headers['Content-type'] = 'text/plain'
-        return pformat(dict(filter(lambda x: not x[0][:2] == '__', cherrypy.request.__dict__.items())))
-    default.exposed = True
-
-    def test(self):
-        return 'test'
-    test.exposed = True
-
index 4346483d6cab7b774d436635021105c5ef688508..08b9535916ef74d53a31fe40273a3d8add24cabc 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 
 import os, sys, time
-import sql.db
+from sql import db
 from sql.util import new_cursor, get_dbs, db_backup_pre, db_backup_mkdir
 from Queue import Queue, Empty
 import threading
@@ -21,11 +21,11 @@ def consumer():
         try:
             next = queue.get(timeout=3)
             print next[0] + ':',
-            log = sql.db.Backup.get_by(db=next[0])
+            log = db.Backup.get_by(db=next[0])
             if not log:
-                log = sql.db.Backup(db=next[0])
+                log = db.Backup(db=next[0])
             log.dump_path = next[1]
-            log.dump_date = sql.db.func.now()
+            log.dump_date = db.func.now()
             db_backup_mkdir(next[1])
             args = ['mysqldump', next[0]]
             args.extend(MYSQLDUMP_ARGS)
@@ -40,7 +40,7 @@ def consumer():
                 log.dump_errnum = None
                 log.dump_errstr = None
             log.save_or_update()
-            sql.db.session.flush()
+            db.session.flush()
             print 'Done'
         except (KeyboardInterrupt, SystemExit):
             break
@@ -54,9 +54,9 @@ t_consumer.start()
 def producer():
     c = new_cursor('mysqldump')
     for db in get_dbs(c):
-        log = sql.db.Backup.get_by(db=db)
+        log = db.Backup.get_by(db=db)
         if not log:
-            log = sql.db.Backup(db=db)
+            log = db.Backup(db=db)
         elif log.skip_date:
             if time.mktime(log.skip_date.timetuple()) + 3600 > time.time():
                 # never recheck a db skipped in the past hour
@@ -68,9 +68,9 @@ def producer():
             log.skip_date = None
         else:
             log.skip_reason = d[1]
-            log.skip_date = sql.db.func.now()
+            log.skip_date = db.func.now()
         log.save_or_update()
-        #sql.db.session.flush()
+        #db.session.flush()
 
 try:
     producer()
diff --git a/sbin/start b/sbin/start
new file mode 100755 (executable)
index 0000000..846b03a
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+exec cherryd -c $_SQL_MIT_EDU/www/etc/devel.conf -i mitsql.interface
diff --git a/www/etc/devel.conf b/www/etc/devel.conf
new file mode 100644 (file)
index 0000000..bdb7cfc
--- /dev/null
@@ -0,0 +1,8 @@
+[global]
+server.socket_host: "0.0.0.0"
+server.socket_port: 8336
+tools.encode.on: True
+tools.encode.encoding: 'utf-8'
+#tools.map_uri.on: True
+#tools.header_auth.on: True
+#request.show_tracebacks: True
diff --git a/www/etc/live.conf b/www/etc/live.conf
new file mode 100644 (file)
index 0000000..ef39428
--- /dev/null
@@ -0,0 +1,11 @@
+[global]
+tree.root: mitsql.interface.root
+server.socket_file: '/tmp/mitsql.sock'
+
+tools.encode.on: True
+tools.encode.encoding: 'utf-8'
+#tools.map_uri.on: True
+#autoreload.on: False
+#checker.on: False
+#engine.SIGHUP: None
+#engine.SIGTERM: None
diff --git a/www/root/assets/css/style.css b/www/root/assets/css/style.css
new file mode 100644 (file)
index 0000000..687aeed
--- /dev/null
@@ -0,0 +1,112 @@
+html,body,div,span,form,h1,h2,h3,h4,p,blockquote{margin:0;padding:0;border:0;outline:0;}
+
+/* -------  Layout CSS (Centered Fixed Width) ------ */
+
+body {
+  font-family: Verdana, sans-serif;
+  font-size: 12px;
+  margin: 0;
+  padding: 0;
+  text-align: center; /* IE 5.5 hack */
+}
+#farouter {
+       background: #ffffff;
+       width: 80%;
+       border: 1px solid #3A291F;
+       margin: 10px auto 10px auto;
+       text-align: left; /* IE 5.5 hack part II */
+}
+#outer div#masthead { margin: 1em; }
+#outer div#content_wide { margin: 1em; }
+#content { float: left; width: 490px; }
+#content_wide { padding: 0 35px 0 35px; }
+#content_home { float: left; width: 490px; padding-top: 0px; }
+#menu { float: right; width: 175px; margin-right: 10px; border-left: 1px dashed #2050A0; }
+#nav { padding-left: 10px; }
+#logo { padding-top: 25px; padding-left: 12px; }
+#hmenu { height: 30px; }
+#hnav { margin: 0; padding: 0; }
+#clearer { clear: both; margin: 0; padding: 0; }
+#footer { margin: 8px 8px 8px 8px; }
+
+/* ----------------- Color CSS ------------------------ */
+
+body { background: #2050A0; }
+#footer { background-color: #eee; border-top: 1px solid #ddd; }
+#hnav { background: #2050A0; }
+a { color: #2050A0; text-decoration: none; }
+a:visited { color: #2050A0; text-decoration: none; }
+a:hover { color: #2050A0; text-decoration: underline; }
+h2 { /*color: #17397A; */ font-size: 0.9em; font-weight: normal; }
+h3 { /* color: #17397A; */ }
+h3 a { color: #17397A; }
+h3 a:hover { color: #17397A; }
+h3 a:visited { color: #17397A; }
+h4 { font-size: 16px; font-weight: normal; }
+
+/* -------- Core CSS --------- */
+
+
+a { text-decoration: none; font-weight:bold; }
+a img { border: none; }
+
+h1 { margin: 0; padding: 0; }
+h1#title { float: left; }
+h1#sitename { text-align: right; }
+h1#sitename a:hover { text-decoration: underline; }
+h2#tagline { text-align: right; letter-spacing: 0.2em; }
+#hidden {display:none;}
+
+img { margin: 10px; padding: 10px; border: 0px solid #2F700F; }
+
+p { line-height: 175%; }
+
+.textarea { width:200px; margin:0; }
+
+/*------------- hnav------------*/
+
+#hnav ul {
+       text-align: center;
+       padding-bottom: 5px;
+       padding-top: 5px;
+       padding-left: 0;
+       margin-top: 0;
+       /* cancels gap caused by top padding in Opera 7.54 */
+       margin-left: 0;
+       background-color: #2050A0;
+       color: #F2EEEC;
+       width: 100%;
+       line-height: 18px;
+       /* fixes Firefox 0.9.3 */
+}
+
+#hnav ul li {
+       display: inline;
+       padding-left: 0;
+       padding-right: 0;
+       padding-bottom: 5px;
+       /* matches link padding except for left and right */
+       padding-top: 5px;
+}
+
+#hnav ul li a {
+       padding-left: 10px;
+       padding-right: 10px;
+       padding-bottom: 5px;
+       padding-top: 5px;
+       color: #F2EEEC;
+       text-decoration: none;
+       border-right: 1px solid #F2EEEC;
+}
+
+#hnav ul li.menu_last a {
+    border-right: 0;
+}
+
+#hnav ul li a:hover {
+       background: #F2EEEC;
+       color: #3A291F;
+}
+
+#hnav #active { border-left: 1px solid #F2EEEC; }
+
diff --git a/www/templates/common/_404.tmpl b/www/templates/common/_404.tmpl
new file mode 100644 (file)
index 0000000..3a63713
--- /dev/null
@@ -0,0 +1,7 @@
+#extends templates.common.shell
+
+#def title: Page Not Found
+
+#block content
+<p>We're sorry! The page you requested does not exist. Please return to our <a href="/">homepage</a> or <a href="/contact">contact us</a>.</p>
+#end block content
diff --git a/www/templates/common/_500.tmpl b/www/templates/common/_500.tmpl
new file mode 100644 (file)
index 0000000..265af7a
--- /dev/null
@@ -0,0 +1,8 @@
+#extends templates.common.shell
+
+#def title: Page Error
+
+#block content
+<p>We're sorry! The requested you made caused an internal error we weren't expecting. The support team has been notified.</p>
+<p>Please return to our <a href="/">homepage</a>, go back and try again, or <a href="/contact">contact us</a>.</p>
+#end block content
diff --git a/www/templates/common/shell.tmpl b/www/templates/common/shell.tmpl
new file mode 100644 (file)
index 0000000..d8d043d
--- /dev/null
@@ -0,0 +1 @@
+#extends skeleton
diff --git a/www/templates/common/skeleton.tmpl b/www/templates/common/skeleton.tmpl
new file mode 100644 (file)
index 0000000..761c0d2
--- /dev/null
@@ -0,0 +1,61 @@
+#from mitsql import config
+#import cherrypy, time
+#set global x_agent = cherrypy.request.headers.get('X-Agent', 'Mozilla')
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+    #set page_title = $title.split('|')[0]
+    <title>$page_title</title>
+    <link rel="stylesheet" type="text/css" href="/assets/css/style.css?$time.time" />
+    <link rel="icon" type="image/png" href="/assets/images/favicon.ico" />
+    <script type="text/javascript" src="/assets/js/prototype.js"></script>
+    #block head_append
+    #end block head_append
+</head>
+<body>
+<div id="farouter">
+    <div id="outer">
+        <div id="masthead">
+            <h1 id="title">$title</h1>
+            <h1 id="sitename"><a href="http://sql.mit.edu/" target="_top">sql.mit.edu</a></h1>
+            <h2 id="tagline">MIT SIPB MySQL Service for Athena<br />
+                email: sql@mit.edu</h2>
+        </div>
+        <div id="hmenu">
+            <div id="hnav">
+                <ul id="navlist">
+<div style="float:left;">
+<li><a href="/db/list">Manage DBs</a></li>
+<li><a href="do/setup">Account</a></li>
+<li><a href="do/admin/main">Admin</a></li>
+<li><a href="do/logout">Logout</a></li>
+<li><a href="do/signup">Sign up</a></li>
+<li><a href="https://scripts.mit.edu/~sql/phpMyAdmin/" target="_blank">phpMyAdmin</a></li>
+</div>
+<div style="text-align: right;">
+Login via:
+    <li><a href="do/login?ssl=0">SQL Password</a></li>
+    <li class="menu_last"><a href="do/login?ssl=1">MIT Certificate</a></li>
+</div>
+                </ul>
+            </div>
+        </div>
+        <div id="main">
+            <div id="content_wide">
+      #block body
+      #end block body
+            </div><!-- end#content -->
+        </div><!-- end#main -->
+
+        <!-- footer -->
+        <div id="foot">&nbsp;</div><!-- end#foot -->
+        <div id="clearer">&nbsp;</div><!-- end#clearer -->
+        <div id="footer">
+            <p id="credit" style="text-align: right;">
+                <strong><em>sql.mit.edu v2.0</em></strong>&nbsp;
+            </p>
+        </div><!-- end#footer -->
+    </div><!-- end#outer -->
+</div><!-- end#farouter -->
+</body>
+</html>
diff --git a/www/templates/main/contact.tmpl b/www/templates/main/contact.tmpl
new file mode 100644 (file)
index 0000000..4b212cb
--- /dev/null
@@ -0,0 +1,11 @@
+#extends templates.common.shell
+
+#def title: Contact
+
+#block body
+<h3>Contact/Help</h3>
+
+<p>We welcome all questions, comments, and suggestions.</p>
+<p>Please direct inquiries to <strong>sql@mit.edu</strong></p>
+
+#end block body
\ No newline at end of file
diff --git a/www/templates/main/db_list.tmpl b/www/templates/main/db_list.tmpl
new file mode 100644 (file)
index 0000000..0a3b3ce
--- /dev/null
@@ -0,0 +1,39 @@
+#extends templates.common.shell
+#from mitsql.interface import display
+
+#def title: Manage Databases
+
+#block body
+
+<table width="100%">
+#if len($db_list) == 0:
+<tr><td width="100%"><em>You have no databases. Add one below.</em></td></tr>
+#else:
+#for name, data in $db_list:
+<tr><td width="100%">
+#echo display.db_list_entry($name, $data.size_tot, $data.size_max)
+</td><td>
+<p>drop</p>
+</td></tr>
+#end for
+#end if
+<tr><td colspan=2>
+<hr />
+</td></tr><tr><td colspan=2>
+#echo display.db_list_entry('TOTAL', $size_tot, $size_max)
+</td></tr>
+</table>
+
+<form method="post" action="create">
+<p align="right">
+    <span style="width: 150px; font-style: italic;">
+    <label for="p1">new database:</label>
+    </span> $user.db_prefix<input type="text" name="db_name" />
+    <input type=submit value="create">
+</p>
+</form>
+
+<h3>Manage Data</h3>
+<p>One interface we recommend for managing SQL data is <a href="https://scripts.mit.edu/~sql/phpMyAdmin/" target="_blank">phpMyAdmin</a>. Feel free to use it after you've created your databases.</p>
+
+#end block body
\ No newline at end of file
diff --git a/www/templates/main/index.tmpl b/www/templates/main/index.tmpl
new file mode 100644 (file)
index 0000000..cba7a22
--- /dev/null
@@ -0,0 +1,28 @@
+#extends templates.common.shell
+
+#def title: MySQL Services
+
+#block body
+<p>
+This service provides <a target="_blank" href="http://dev.mysql.com/doc">MySQL</a> databases to <a target="_blank" href="http://ca.mit.edu/">MIT certificate</a> holders.
+You must choose a MySQL password (which should be different from your Athena account password) when you <a href="do/signup">sign up</a>, and
+then use this interface to create and drop databases.  All subsequent SQL commands can be issued from any host, client, and/or script of your choice;
+simply connect to the MySQL server at <b>sql.mit.edu</b> using your username and your new MySQL password.
+You may find it convenient to run scripts using the <a target="_blank" href="http://scripts.mit.edu/web">web script service</a> or
+<a target="_blank" href="http://scripts.mit.edu/cron">shortjobs service</a>.
+</p>
+
+<p>
+All uses of this service must comply with the <a target="_blank" href="http://web.mit.edu/olh/Welcome/rules.html">MITnet rules of use</a>.
+</p>
+
+<p>
+This service has been designed with reliability in mind; we utilize RAID, live server mirroring and periodic offline backups to ensure data reliability.
+However, the SIPB MySQL service should not be used to host critical applications that cannot tolerate downtime.
+One nightly backup is available for your locker at <code>/mit/sql/backup/LOCKER_NAME</code>.  You should perform additional backups of your data using the <a href="http://scripts.mit.edu/cron">shortjobs service</a> or <a href="http://scripts.mit.edu/faq/10/how-can-i-back-up-or-restore-my-sql-data">phpMyAdmin</a>.
+</p>
+
+<div style="text-align:center; font-style: italic;">
+<!-- /afs/athena.mit.edu/contrib/sql/stat/questions -->
+</div>
+#end block body
\ No newline at end of file
diff --git a/www/templates/main/passwd.tmpl b/www/templates/main/passwd.tmpl
new file mode 100644 (file)
index 0000000..0a0773b
--- /dev/null
@@ -0,0 +1,28 @@
+#extends templates.common.shell
+
+#def title: Change Password
+
+#block body
+<p>Your MySQL password should be different from your Athena account password.</p>
+
+<form method="post">
+<table>
+<tr><td align="right">new password:</td><td><input type="password" name="p[1]"></td></tr>
+<tr><td align="right">repeat new password:</td><td><input type="password" name="p[2]"></td></tr>
+<tr><td align="right" colspan=2><br /><input name="chgpw" type="submit" value="change password"></td
+></tr>
+</table>
+</form>
+<hr />
+<p>Note: you need to also <a href="http://scripts.mit.edu/faq/59">update your .my.cnf file on Athena</a> if you want to use SIPB <a href="http://scripts.mit.edu/start/">scripts auto-installers</a> or access the MySQL service from the command-line.</p>
+
+<br />
+<div style="width: 50%">
+<hr />
+This website provides signups for individual user locker
+MySQL accounts.  Groups locker administrators can 
+<a href="http://scripts.mit.edu/faq/66">signup for group locker MySQL accounts</a>
+from any Athena prompt.
+</div>
+
+#end block body
\ No newline at end of file
diff --git a/www/templates/main/signup.tmpl b/www/templates/main/signup.tmpl
new file mode 100644 (file)
index 0000000..2df2c79
--- /dev/null
@@ -0,0 +1,18 @@
+#extends templates.common.shell
+
+#def title: Change Password
+
+#block body
+<p>Your MySQL password should be different from your Athena account password.</p>
+
+<form method="post">
+<table>
+<tr><td align="right">new password:</td><td><input type="password" name="p[1]"></td></tr>
+<tr><td align="right">repeat new password:</td><td><input type="password" name="p[2]"></td></tr>
+<tr><td align="right" colspan=2><br /><input name="chgpw" type="submit" value="change password"></td
+></tr>
+</table>
+</form>
+<hr />
+<p>Note: you need to also <a href="http://scripts.mit.edu/faq/59">update your .my.cnf file on Athena</a> if you want to use SIPB <a href="http://scripts.mit.edu/start/">scripts auto-installers</a> or access the MySQL service from the command-line.</p>
+#end block body
\ No newline at end of file
This page took 0.072047 seconds and 5 git commands to generate.