5 ### (c) 2013 Mark Wooding
8 ###----- Licensing notice ---------------------------------------------------
10 ### This file is part of Chopwood: a password-changing service.
12 ### Chopwood is free software; you can redistribute it and/or modify
13 ### it under the terms of the GNU Affero General Public License as
14 ### published by the Free Software Foundation; either version 3 of the
15 ### License, or (at your option) any later version.
17 ### Chopwood is distributed in the hope that it will be useful,
18 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ### GNU Affero General Public License for more details.
22 ### You should have received a copy of the GNU Affero General Public
23 ### License along with Chopwood; if not, see
24 ### <http://www.gnu.org/licenses/>.
26 from __future__ import with_statement
31 from auto import PACKAGE, VERSION
37 import operation as OP
38 import output as O; OUT = O.OUT; PRINT = O.PRINT
40 import subcommand as SC
43 ###--------------------------------------------------------------------------
46 def operate(what, op, services, *args, **kw):
47 accts = CU.resolve_accounts(CU.USER, services)
48 o, ii, rq, ops = OP.operate(op, accts, *args, **kw)
49 CGI.page('operate.fhtml',
50 header = dict(pragma = 'no-cache', cache_control = 'no-cache'),
51 title = 'Chopwood: %s' % what,
53 outcome = o, info = ii, results = ops)
55 ###--------------------------------------------------------------------------
58 @CGI.subcommand('list', ['cgi-query'], 'List available accounts')
60 CGI.page('list.fhtml',
61 header = dict(pragma = 'no-cache', cache_control = 'no-cache'),
62 title = 'Chopwood: accounts list',
63 accts = CU.list_accounts(CU.USER),
67 'set', ['cgi'], 'Set password for a collection of services.',
68 params = [SC.Arg('first'), SC.Arg('second')],
69 rparam = SC.Arg('services'))
70 def cmd_set_cgi(first, second, services = []):
71 if first != second: raise U.ExpectedError, (400, "Passwords don't match")
72 operate('set passwords', 'set', services, first)
76 'Reset passwords for a collection of services.',
77 rparam = SC.Arg('services'))
78 def cmd_reset_cgi(services = []):
79 operate('reset passwords', 'reset', services)
83 'Clear passwords for a collection of services.',
84 rparam = SC.Arg('services'))
85 def cmd_clear_cgi(services = []):
86 operate('clear passwords', 'clear', services)
89 'fail', ['cgi-noauth'],
90 'Raise an exception, to test the error reporting machinery.',
91 opts = [SC.Opt('partial', '-p', '--partial',
92 'Raise exception after producing partial output.')])
93 def cmd_fail_cgi(partial = False):
95 OUT.header(content_type = 'text/html')
98 <head><title>Chopwood: filler text</title></head>
100 <h1>Failure expected soon
101 <p>This is some normal output which will be rudely interrupted.""")
102 raise Exception, 'You asked for this.'
104 ###--------------------------------------------------------------------------
107 ## A map of file names to content objects. See below.
110 class PlainOutput (O.FileOutput):
111 def header(me, **kw):
114 class StaticContent (object):
115 def __init__(me, type):
118 OUT.header(content_type = me._type)
120 def _write(me, dest):
121 with open(dest, 'w') as f:
122 with OUT.redirect_to(PlainOutput(f)):
128 if e.errno != E.ENOENT: raise
132 class TemplateContent (StaticContent):
133 def __init__(me, template, *args, **kw):
134 super(TemplateContent, me).__init__(*args, **kw)
135 me._template = template
137 CGI.format_tmpl(CGI.TMPL[me._template])
139 class HTMLContent (StaticContent):
140 def __init__(me, title, template, type = 'text/html', *args, **kw):
141 super(HTMLContent, me).__init__(type = type, *args, **kw)
142 me._template = template
145 CGI.page(me._template, title = me._title)
148 'chpwd.css': TemplateContent(template = 'chpwd.css',
150 'chpwd.js': TemplateContent(template = 'chpwd.js',
151 type = 'text/javascript'),
152 'about.html': HTMLContent('Chopwood: about this program',
153 template = 'about.fhtml'),
154 'cookies.html': HTMLContent('Chopwood: use of cookies',
155 template = 'cookies.fhtml')
159 'static', ['cgi-noauth'], 'Output a static file.',
160 rparam = SC.Arg('path'))
161 def cmd_static_cgi(path):
162 name = '/'.join(path)
163 try: content = CONTENT[name]
164 except KeyError: raise U.ExpectedError, (404, "Unknown file `%s'" % name)
168 'static', ['admin'], 'Write the static files to DIR.',
169 params = [SC.Arg('dir')])
170 def cmd_static_admin(dir):
171 try: OS.makedirs(dir, 0777)
173 if e.errno != E.EEXIST: raise
174 for f, c in CONTENT.iteritems():
175 c.write(OS.path.join(dir, f))
177 TARBALL = '%s-%s.tar.gz' % (PACKAGE, VERSION)
178 @CGI.subcommand(TARBALL, ['cgi-noauth'], """\
179 Download source code (in `.tar.gz' format).""")
180 def cmd_source_cgi():
181 OUT.header(content_type = 'application/octet-stream')
184 @CGI.subcommand('source', ['cgi-noauth'], """\
185 Redirect to the source code tarball (so that it's correctly named).""")
186 def cmd_sourceredirect_cgi():
187 CGI.redirect(CGI.action(TARBALL))
189 ###----- That's all, folks --------------------------------------------------