Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Adds the new admin

git-svn-id: svn://cherokee-project.com/cherokee/trunk@4873 5dc97367-97f1-0310-9951-d761b3857238
  • Loading branch information...
commit ff20af9031e75a4ed65e151df44e5893d2005441 1 parent 116b782
@alobbs alobbs authored
Showing with 10,810 additions and 0 deletions.
  1. +65 −0 admin/Auth.py
  2. +133 −0 admin/Balancer.py
  3. +167 −0 admin/CgiBase.py
  4. +264 −0 admin/Cherokee.py
  5. +341 −0 admin/Flags.py
  6. +180 −0 admin/Graph.py
  7. +51 −0 admin/Handler.py
  8. +367 −0 admin/Icons.py
  9. +96 −0 admin/Makefile.am
  10. +162 −0 admin/Mime.py
  11. +130 −0 admin/Page.py
  12. +200 −0 admin/PageAdvanced.py
  13. +264 −0 admin/PageEntry.py
  14. +140 −0 admin/PageError.py
  15. +115 −0 admin/PageException.py
  16. +245 −0 admin/PageGeneral.py
  17. +197 −0 admin/PageHelp.py
  18. +440 −0 admin/PageIndex.py
  19. +173 −0 admin/PageNewConfig.py
  20. +350 −0 admin/PageRule.py
  21. +378 −0 admin/PageSource.py
  22. +57 −0 admin/PageSources.py
  23. +132 −0 admin/PageStatus.py
  24. +505 −0 admin/PageVServer.py
  25. +336 −0 admin/PageVServers.py
  26. +197 −0 admin/Rule.py
  27. +80 −0 admin/RuleSimple.py
  28. +91 −0 admin/SelectionPanel.py
  29. +260 −0 admin/Wizard.py
  30. +128 −0 admin/XMLServerDigest.py
  31. +101 −0 admin/config_version.py
  32. +25 −0 admin/configured.py.pre
  33. +243 −0 admin/consts.py
  34. +24 −0 admin/exception.html
  35. +25 −0 admin/help.html
  36. +53 −0 admin/plugins/Makefile.am
  37. +35 −0 admin/plugins/admin.py
  38. +110 −0 admin/plugins/authlist.py
  39. +161 −0 admin/plugins/bind.py
  40. +33 −0 admin/plugins/cgi.py
  41. +53 −0 admin/plugins/common.py
  42. +50 −0 admin/plugins/custom_error.py
  43. +69 −0 admin/plugins/dbslayer.py
  44. +31 −0 admin/plugins/directory.py
  45. +91 −0 admin/plugins/dirlist.py
  46. +35 −0 admin/plugins/empty_gif.py
  47. +27 −0 admin/plugins/error_nn.py
  48. +118 −0 admin/plugins/error_redir.py
  49. +46 −0 admin/plugins/evhost.py
  50. +140 −0 admin/plugins/exists.py
  51. +71 −0 admin/plugins/extensions.py
  52. +51 −0 admin/plugins/fcgi.py
  53. +48 −0 admin/plugins/file.py
  54. +122 −0 admin/plugins/from.py
  55. +122 −0 admin/plugins/fullpath.py
  56. +97 −0 admin/plugins/geoip.py
  57. +86 −0 admin/plugins/header.py
  58. +51 −0 admin/plugins/htdigest.py
  59. +50 −0 admin/plugins/htpasswd.py
  60. +31 −0 admin/plugins/ip_hash.py
  61. +66 −0 admin/plugins/ldap.py
  62. +107 −0 admin/plugins/method.py
  63. +90 −0 admin/plugins/mysql.py
  64. +33 −0 admin/plugins/pam.py
  65. +50 −0 admin/plugins/plain.py
  66. +54 −0 admin/plugins/post_report.py
  67. +28 −0 admin/plugins/post_track.py
  68. +276 −0 admin/plugins/proxy.py
  69. +120 −0 admin/plugins/redir.py
  70. +100 −0 admin/plugins/rehost.py
  71. +31 −0 admin/plugins/request.py
  72. +31 −0 admin/plugins/round_robin.py
  73. +48 −0 admin/plugins/rrd.py
  74. +51 −0 admin/plugins/scgi.py
  75. +60 −0 admin/plugins/secdownload.py
  76. +55 −0 admin/plugins/server_info.py
  77. +34 −0 admin/plugins/ssi.py
  78. +73 −0 admin/plugins/streaming.py
  79. +110 −0 admin/plugins/target_ip.py
  80. +113 −0 admin/plugins/url_arg.py
  81. +51 −0 admin/plugins/uwsgi.py
  82. +99 −0 admin/plugins/wildcard.py
  83. +183 −0 admin/server.py
  84. +6 −0 admin/static/Makefile.am
  85. +8 −0 admin/static/css/Makefile.am
  86. +192 −0 admin/static/css/cherokee-admin.css
  87. +11 −0 admin/static/help_404.html
  88. +23 −0 admin/static/images/Makefile.am
  89. BIN  admin/static/images/advanced.png
  90. BIN  admin/static/images/bg-bar.png
  91. BIN  admin/static/images/cherokee-logo-bar.png
  92. +255 −0 admin/static/images/flags/Makefile.am
  93. BIN  admin/static/images/flags/ad.png
  94. BIN  admin/static/images/flags/ae.png
  95. BIN  admin/static/images/flags/af.png
  96. BIN  admin/static/images/flags/ag.png
  97. BIN  admin/static/images/flags/ai.png
  98. BIN  admin/static/images/flags/al.png
  99. BIN  admin/static/images/flags/am.png
  100. BIN  admin/static/images/flags/an.png
  101. BIN  admin/static/images/flags/ao.png
  102. BIN  admin/static/images/flags/ar.png
  103. BIN  admin/static/images/flags/as.png
  104. BIN  admin/static/images/flags/at.png
  105. BIN  admin/static/images/flags/au.png
  106. BIN  admin/static/images/flags/aw.png
  107. BIN  admin/static/images/flags/ax.png
  108. BIN  admin/static/images/flags/az.png
  109. BIN  admin/static/images/flags/ba.png
  110. BIN  admin/static/images/flags/bb.png
  111. BIN  admin/static/images/flags/bd.png
  112. BIN  admin/static/images/flags/be.png
  113. BIN  admin/static/images/flags/bf.png
  114. BIN  admin/static/images/flags/bg.png
  115. BIN  admin/static/images/flags/bh.png
  116. BIN  admin/static/images/flags/bi.png
  117. BIN  admin/static/images/flags/bj.png
  118. BIN  admin/static/images/flags/bm.png
  119. BIN  admin/static/images/flags/bn.png
  120. BIN  admin/static/images/flags/bo.png
  121. BIN  admin/static/images/flags/br.png
  122. BIN  admin/static/images/flags/bs.png
  123. BIN  admin/static/images/flags/bt.png
  124. BIN  admin/static/images/flags/bv.png
  125. BIN  admin/static/images/flags/bw.png
  126. BIN  admin/static/images/flags/by.png
  127. BIN  admin/static/images/flags/bz.png
  128. BIN  admin/static/images/flags/ca.png
  129. BIN  admin/static/images/flags/cc.png
  130. BIN  admin/static/images/flags/cd.png
  131. BIN  admin/static/images/flags/cf.png
  132. BIN  admin/static/images/flags/cg.png
  133. BIN  admin/static/images/flags/ch.png
  134. BIN  admin/static/images/flags/ci.png
  135. BIN  admin/static/images/flags/ck.png
  136. BIN  admin/static/images/flags/cl.png
  137. BIN  admin/static/images/flags/cm.png
  138. BIN  admin/static/images/flags/cn.png
  139. BIN  admin/static/images/flags/co.png
  140. BIN  admin/static/images/flags/cr.png
  141. BIN  admin/static/images/flags/cs.png
  142. BIN  admin/static/images/flags/cu.png
  143. BIN  admin/static/images/flags/cv.png
  144. BIN  admin/static/images/flags/cx.png
  145. BIN  admin/static/images/flags/cy.png
  146. BIN  admin/static/images/flags/cz.png
  147. BIN  admin/static/images/flags/de.png
  148. BIN  admin/static/images/flags/dj.png
  149. BIN  admin/static/images/flags/dk.png
  150. BIN  admin/static/images/flags/dm.png
  151. BIN  admin/static/images/flags/do.png
  152. BIN  admin/static/images/flags/dz.png
  153. BIN  admin/static/images/flags/ec.png
  154. BIN  admin/static/images/flags/ee.png
  155. BIN  admin/static/images/flags/eg.png
  156. BIN  admin/static/images/flags/eh.png
  157. BIN  admin/static/images/flags/england.png
  158. BIN  admin/static/images/flags/er.png
  159. BIN  admin/static/images/flags/es.png
  160. BIN  admin/static/images/flags/et.png
  161. BIN  admin/static/images/flags/europeanunion.png
  162. BIN  admin/static/images/flags/fi.png
  163. BIN  admin/static/images/flags/fj.png
  164. BIN  admin/static/images/flags/fk.png
  165. BIN  admin/static/images/flags/fm.png
  166. BIN  admin/static/images/flags/fo.png
  167. BIN  admin/static/images/flags/fr.png
  168. BIN  admin/static/images/flags/ga.png
  169. BIN  admin/static/images/flags/gb.png
  170. BIN  admin/static/images/flags/gd.png
  171. BIN  admin/static/images/flags/ge.png
  172. BIN  admin/static/images/flags/gf.png
  173. BIN  admin/static/images/flags/gh.png
  174. BIN  admin/static/images/flags/gi.png
  175. BIN  admin/static/images/flags/gl.png
  176. BIN  admin/static/images/flags/gm.png
  177. BIN  admin/static/images/flags/gn.png
  178. BIN  admin/static/images/flags/gp.png
  179. BIN  admin/static/images/flags/gq.png
  180. BIN  admin/static/images/flags/gr.png
  181. BIN  admin/static/images/flags/gs.png
  182. BIN  admin/static/images/flags/gt.png
  183. BIN  admin/static/images/flags/gu.png
  184. BIN  admin/static/images/flags/gw.png
  185. BIN  admin/static/images/flags/gy.png
  186. BIN  admin/static/images/flags/hk.png
  187. BIN  admin/static/images/flags/hm.png
  188. BIN  admin/static/images/flags/hn.png
  189. BIN  admin/static/images/flags/hr.png
  190. BIN  admin/static/images/flags/ht.png
  191. BIN  admin/static/images/flags/hu.png
  192. BIN  admin/static/images/flags/id.png
  193. BIN  admin/static/images/flags/ie.png
  194. BIN  admin/static/images/flags/il.png
  195. BIN  admin/static/images/flags/in.png
  196. BIN  admin/static/images/flags/io.png
  197. BIN  admin/static/images/flags/iq.png
  198. BIN  admin/static/images/flags/ir.png
  199. BIN  admin/static/images/flags/is.png
  200. BIN  admin/static/images/flags/it.png
  201. BIN  admin/static/images/flags/jm.png
  202. BIN  admin/static/images/flags/jo.png
  203. BIN  admin/static/images/flags/jp.png
  204. BIN  admin/static/images/flags/ke.png
  205. BIN  admin/static/images/flags/kg.png
  206. BIN  admin/static/images/flags/kh.png
  207. BIN  admin/static/images/flags/ki.png
  208. BIN  admin/static/images/flags/km.png
  209. BIN  admin/static/images/flags/kn.png
  210. BIN  admin/static/images/flags/kp.png
  211. BIN  admin/static/images/flags/kr.png
  212. BIN  admin/static/images/flags/kw.png
  213. BIN  admin/static/images/flags/ky.png
  214. BIN  admin/static/images/flags/kz.png
  215. BIN  admin/static/images/flags/la.png
  216. BIN  admin/static/images/flags/lb.png
  217. BIN  admin/static/images/flags/lc.png
  218. BIN  admin/static/images/flags/li.png
  219. BIN  admin/static/images/flags/lk.png
  220. BIN  admin/static/images/flags/lr.png
  221. BIN  admin/static/images/flags/ls.png
  222. BIN  admin/static/images/flags/lt.png
  223. BIN  admin/static/images/flags/lu.png
  224. BIN  admin/static/images/flags/lv.png
  225. BIN  admin/static/images/flags/ly.png
  226. BIN  admin/static/images/flags/ma.png
  227. BIN  admin/static/images/flags/mc.png
  228. BIN  admin/static/images/flags/md.png
  229. BIN  admin/static/images/flags/me.png
  230. BIN  admin/static/images/flags/mg.png
  231. BIN  admin/static/images/flags/mh.png
  232. BIN  admin/static/images/flags/mk.png
  233. BIN  admin/static/images/flags/ml.png
  234. BIN  admin/static/images/flags/mm.png
  235. BIN  admin/static/images/flags/mn.png
  236. BIN  admin/static/images/flags/mo.png
  237. BIN  admin/static/images/flags/mp.png
  238. BIN  admin/static/images/flags/mq.png
  239. BIN  admin/static/images/flags/mr.png
  240. BIN  admin/static/images/flags/ms.png
  241. BIN  admin/static/images/flags/mt.png
  242. BIN  admin/static/images/flags/mu.png
  243. BIN  admin/static/images/flags/mv.png
  244. BIN  admin/static/images/flags/mw.png
  245. BIN  admin/static/images/flags/mx.png
  246. BIN  admin/static/images/flags/my.png
  247. BIN  admin/static/images/flags/mz.png
  248. BIN  admin/static/images/flags/na.png
  249. BIN  admin/static/images/flags/nc.png
  250. BIN  admin/static/images/flags/ne.png
  251. BIN  admin/static/images/flags/nf.png
  252. BIN  admin/static/images/flags/ng.png
  253. BIN  admin/static/images/flags/ni.png
  254. BIN  admin/static/images/flags/nl.png
  255. BIN  admin/static/images/flags/no.png
  256. BIN  admin/static/images/flags/np.png
  257. BIN  admin/static/images/flags/nr.png
  258. BIN  admin/static/images/flags/nu.png
  259. BIN  admin/static/images/flags/nz.png
  260. BIN  admin/static/images/flags/om.png
  261. BIN  admin/static/images/flags/pa.png
  262. BIN  admin/static/images/flags/pe.png
  263. BIN  admin/static/images/flags/pf.png
  264. BIN  admin/static/images/flags/pg.png
  265. BIN  admin/static/images/flags/ph.png
  266. BIN  admin/static/images/flags/pk.png
  267. BIN  admin/static/images/flags/pl.png
  268. BIN  admin/static/images/flags/pm.png
  269. BIN  admin/static/images/flags/pn.png
  270. BIN  admin/static/images/flags/pr.png
  271. BIN  admin/static/images/flags/ps.png
  272. BIN  admin/static/images/flags/pt.png
  273. BIN  admin/static/images/flags/pw.png
  274. BIN  admin/static/images/flags/py.png
  275. BIN  admin/static/images/flags/qa.png
  276. BIN  admin/static/images/flags/re.png
  277. +9 −0 admin/static/images/flags/readme.txt
  278. BIN  admin/static/images/flags/ro.png
  279. BIN  admin/static/images/flags/rs.png
  280. BIN  admin/static/images/flags/ru.png
  281. BIN  admin/static/images/flags/rw.png
  282. BIN  admin/static/images/flags/sa.png
  283. BIN  admin/static/images/flags/sb.png
  284. BIN  admin/static/images/flags/sc.png
  285. BIN  admin/static/images/flags/scotland.png
  286. BIN  admin/static/images/flags/sd.png
  287. BIN  admin/static/images/flags/se.png
  288. BIN  admin/static/images/flags/sg.png
  289. BIN  admin/static/images/flags/sh.png
  290. BIN  admin/static/images/flags/si.png
  291. BIN  admin/static/images/flags/sj.png
  292. BIN  admin/static/images/flags/sk.png
  293. BIN  admin/static/images/flags/sl.png
  294. BIN  admin/static/images/flags/sm.png
  295. BIN  admin/static/images/flags/sn.png
  296. BIN  admin/static/images/flags/so.png
  297. BIN  admin/static/images/flags/sr.png
  298. BIN  admin/static/images/flags/st.png
  299. BIN  admin/static/images/flags/sv.png
  300. BIN  admin/static/images/flags/sy.png
Sorry, we could not display the entire diff because too many files (418) changed.
View
65 admin/Auth.py
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+#
+# Cherokee-admin
+#
+# Authors:
+# Alvaro Lopez Ortega <alvaro@alobbs.com>
+#
+# Copyright (C) 2010 Alvaro Lopez Ortega
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License as published by the Free Software Foundation.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+import CTK
+import Cherokee
+import validations
+
+from consts import *
+from configured import *
+
+URL_APPLY = '/plugin/auth/apply'
+
+NOTE_METHODS = N_('Allowed HTTP Authentication methods.')
+NOTE_REALM = N_('Name associated with the protected resource.')
+NOTE_USERS = N_('User filter. List of allowed users.')
+
+
+class PluginAuth (CTK.Plugin):
+ def __init__ (self, key, **kwargs):
+ CTK.Plugin.__init__ (self, key)
+ self.supported_methos = []
+
+ def AddCommon (self, supported_methods):
+ assert type(supported_methods) is tuple
+
+ if len(supported_methods) > 1:
+ methods = VALIDATOR_METHODS
+ else:
+ methods = filter (lambda x: x[0] in supported_methods, VALIDATOR_METHODS)
+
+ table = CTK.PropsTable()
+ table.Add (_("Methods"), CTK.ComboCfg("%s!methods"%(self.key), methods, {'id': 'auth_method'}), _(NOTE_METHODS))
+ table.Add (_("Realm"), CTK.TextCfg("%s!realm" %(self.key), False), _(NOTE_REALM))
+ table.Add (_("Users"), CTK.TextCfg("%s!users" %(self.key), True), _(NOTE_USERS))
+
+ submit = CTK.Submitter (URL_APPLY)
+ submit += table
+
+ self += CTK.RawHTML ('<h2>%s</h2>' %(_('Authentication Details')))
+ self += CTK.Indenter(submit)
+
+ # Publish
+ VALS = [("%s!users"%(self.key), validations.is_safe_id_list)]
+ CTK.publish ('^%s'%(URL_APPLY), CTK.cfg_apply_post, validation=VALS, method="POST")
View
133 admin/Balancer.py
@@ -0,0 +1,133 @@
+# -*- coding: utf-8 -*-
+#
+# Cherokee-admin
+#
+# Authors:
+# Alvaro Lopez Ortega <alvaro@alobbs.com>
+#
+# Copyright (C) 2010 Alvaro Lopez Ortega
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License as published by the Free Software Foundation.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+
+import CTK
+import Cherokee
+import validations
+
+URL_APPLY = '/plugin/balancer/apply'
+
+NOTE_BALANCER = N_('Specifies the policy used to dispatch the connections.')
+NOTE_ALL_SOURCES = N_('It is already balancing among all the configured <a href="%s">Information Sources</a>.')
+NO_GENERAL_SOURCES = N_('There are no Information Sources configured. Please proceed to configure an <a href="/source">Information Source</a>.')
+NO_SOURCE_WARNING = N_('A load balancer must be configured to use at least one information source.')
+
+
+def commit():
+ new_bal = CTK.post.pop ('tmp!new_balancer_node')
+ key = CTK.post.pop ('key')
+
+ # New
+ if new_bal:
+ next = CTK.cfg.get_next_entry_prefix ('%s!source'%(key))
+ CTK.cfg[next] = new_bal
+
+ # Modification
+ return CTK.cfg_apply_post()
+
+
+class PluginBalancer (CTK.Plugin):
+ def __init__ (self, key, **kwargs):
+ CTK.Plugin.__init__ (self, key)
+
+ class ContentSources (CTK.Container):
+ def __init__ (self, refresh, key):
+ CTK.Container.__init__ (self)
+
+ general_sources = CTK.cfg.keys('source')
+ balancer_sources = CTK.cfg.keys('%s!source'%(key))
+
+ if not balancer_sources:
+ self += CTK.Notice ('warning', CTK.RawHTML (_(NO_SOURCE_WARNING)))
+ else:
+ table = CTK.Table()
+ table.set_header(1)
+ table += [CTK.RawHTML(x) for x in (_('Nick'), _('Host'))]
+ for sb in balancer_sources:
+ sg = CTK.cfg.get_val ('%s!source!%s'%(key, sb))
+ nick = CTK.cfg.get_val ('source!%s!nick'%(sg))
+ host = CTK.cfg.get_val ('source!%s!host'%(sg))
+ link = CTK.Link ("/source/%s"%(sg), CTK.RawHTML (nick))
+
+ remove = None
+ if len(balancer_sources) >= 2:
+ remove = CTK.ImageStock('del')
+ remove.bind('click', CTK.JS.Ajax (URL_APPLY,
+ data = {'%s!source!%s'%(key, sb): ''},
+ complete = refresh.JS_to_refresh()))
+
+ table += [link, CTK.RawHTML(host), remove]
+
+ submit = CTK.Submitter (URL_APPLY)
+ submit += table
+ self += submit
+
+ def AddCommon (self):
+ general_sources = CTK.cfg.keys('source')
+ balancer_sources = CTK.cfg.keys('%s!source'%(self.key))
+
+ # These are the sources that have not been added yet
+ general_left = general_sources[:]
+ for sb in balancer_sources:
+ sg = CTK.cfg.get_val('%s!source!%s'%(self.key, sb))
+ if sg in general_left:
+ while True:
+ try: general_left.remove(sg)
+ except: break
+
+ if not balancer_sources and not general_left:
+ self += CTK.Notice ('warning', CTK.RawHTML (_(NO_GENERAL_SOURCES)))
+ return
+
+ # Configured sources List
+ refresh = CTK.Refreshable ({'id': 'balancer'})
+ refresh.register (lambda: self.ContentSources(refresh, self.key).Render())
+
+ self += CTK.RawHTML ("<h2>%s</h2>" %(_('Information Sources')))
+ self += CTK.Indenter (refresh)
+
+ # Assign new sources
+ self += CTK.RawHTML ('<h2>%s</h2>' %(_('Assign Information Sources')))
+
+ if not general_left:
+ self += CTK.Indenter (CTK.Notice('information', CTK.RawHTML (_(NOTE_ALL_SOURCES)%("/source"))))
+ else:
+ options = [('', _('Choose..'))]
+ for s in general_left:
+ nick = CTK.cfg.get_val('source!%s!nick'%(s))
+ options.append((s,nick))
+
+ table = CTK.PropsTable()
+ table.Add (_("Application Server"), CTK.ComboCfg("tmp!new_balancer_node", options), '')
+
+ submit = CTK.Submitter (URL_APPLY)
+ submit += CTK.Hidden ('key', self.key)
+ submit += table
+ submit.bind ('submit_success', refresh.JS_to_refresh())
+
+ self += CTK.Indenter (submit)
+
+
+CTK.publish ('^%s'%(URL_APPLY), commit, method="POST")
View
167 admin/CgiBase.py
@@ -0,0 +1,167 @@
+# -*- coding: utf-8 -*-
+#
+# Cherokee-admin
+#
+# Authors:
+# Alvaro Lopez Ortega <alvaro@alobbs.com>
+#
+# Copyright (C) 2010 Alvaro Lopez Ortega
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License as published by the Free Software Foundation.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+import CTK
+import Cherokee
+import validations
+import Handler
+
+URL_APPLY = '/plugin/handler_cgi_base/apply'
+
+NOTE_SCRIPT_ALIAS = N_('Path to an executable that will be run with the CGI as parameter.')
+NOTE_CHANGE_USER = N_('Execute the CGI under its file owner user ID.')
+NOTE_ERROR_HANDLER = N_('Send errors exactly as they are generated.')
+NOTE_CHECK_FILE = N_('Check whether the file is in place.')
+NOTE_PASS_REQ = N_('Forward all the client headers to the CGI encoded as HTTP_*. headers.')
+NOTE_XSENDFILE = N_('Allow the use of the non-standard X-Sendfile header.')
+NOTE_X_REAL_IP = N_('Whether the handler should read and use the X-Real-IP header and use it in REMOTE_ADDR.')
+NOTE_X_REAL_IP_ALL = N_('Accept all the X-Real-IP headers. WARNING: Turn it on only if you are centain of what you are doing.')
+NOTE_X_REAL_IP_ACCESS = N_('List of IP addresses and subnets that are allowed to send the X-Real-IP header.')
+
+HELPS = [('modules_handlers_cgi', "CGIs")]
+
+
+def commit():
+ new_name = CTK.post.pop('tmp!new_name')
+ new_value = CTK.post.pop('tmp!new_value')
+ key = CTK.post.pop('key')
+
+ # New
+ if new_name:
+ CTK.cfg['%s!%s'%(key, new_name)] = new_value
+ return CTK.cfg_reply_ajax_ok()
+
+ # Modification
+ return CTK.cfg_apply_post()
+
+
+class PluginHandlerCGI (Handler.PluginHandler):
+ class X_Real_IP (CTK.Container):
+ def __init__ (self, refresh, key):
+ CTK.Container.__init__ (self)
+
+ x_real_ip = int(CTK.cfg.get_val('%s!x_real_ip_enabled' %(key), "0"))
+ x_real_ip_all = int(CTK.cfg.get_val('%s!x_real_ip_access_all' %(key), "0"))
+
+ table = CTK.PropsTable()
+ table.Add (_('Read X-Real-IP'), CTK.CheckCfgText('%s!x_real_ip_enabled'%(key), False, _('Enabled')), _(NOTE_X_REAL_IP))
+ if x_real_ip:
+ table.Add (_('Don\'t check origin'), CTK.CheckCfgText('%s!x_real_ip_access_all'%(key), False, _('Enabled')), _(NOTE_X_REAL_IP_ALL))
+ if not x_real_ip_all:
+ table.Add (_('Accept from Hosts'), CTK.TextCfg ('%s!x_real_ip_access'%(key), False), _(NOTE_X_REAL_IP_ACCESS))
+
+ submit = CTK.Submitter (URL_APPLY)
+ submit += table
+ submit.bind ('submit_success', refresh.JS_to_refresh())
+ self += submit
+
+ class Environ (CTK.Container):
+ def __init__ (self, refresh, key):
+ CTK.Container.__init__ (self)
+
+ envs = CTK.cfg.keys('%s!env' %(key))
+ envs.sort()
+ if not envs:
+ return
+
+ table = CTK.Table()
+ table.set_header(1)
+ table += [CTK.RawHTML(x) for x in (_('Name'), _('Value'))]
+
+ for env in envs:
+ pre = '%s!env!%s'%(key, env)
+ value = CTK.TextCfg (pre, False)
+ remove = CTK.ImageStock('del')
+ remove.bind('click', CTK.JS.Ajax (URL_APPLY, data = {pre: ''},
+ complete = refresh.JS_to_refresh()))
+ table += [CTK.RawHTML(env), value, remove]
+
+ submit = CTK.Submitter (URL_APPLY)
+ submit += table
+ submit.bind ('submit_success', refresh.JS_to_refresh())
+ self += submit
+
+ def __init__ (self, key, **kwargs):
+ self.show_script_alias = kwargs.pop ('show_script_alias', True)
+ self.show_change_uid = kwargs.pop ('show_change_uid', True)
+
+ Handler.PluginHandler.__init__ (self, key, **kwargs)
+
+ def AddCommon (self):
+ # Parent's AddComon
+ Handler.PluginHandler.AddCommon (self)
+
+ # Add CGI related stuff
+ table = CTK.PropsTable()
+
+ if self.show_script_alias:
+ table.Add (_("Script Alias"), CTK.TextCfg('%s!script_alias'%(self.key), True), _(NOTE_SCRIPT_ALIAS))
+ if self.show_change_uid:
+ table.Add (_("Change UID"), CTK.CheckCfgText('%s!change_user', False, _('Change')), _(NOTE_CHANGE_USER))
+
+ table.Add (_('Error handler'), CTK.CheckCfgText('%s!error_handler'%(self.key), True, _('Enabled')), _(NOTE_ERROR_HANDLER))
+ table.Add (_('Check file'), CTK.CheckCfgText('%s!check_file'%(self.key), True, _('Enabled')), _(NOTE_CHECK_FILE))
+ table.Add (_('Pass Request Headers'), CTK.CheckCfgText('%s!pass_req_headers'%(self.key), True, _('Enabled')), _(NOTE_PASS_REQ))
+ table.Add (_('Allow X-Sendfile'), CTK.CheckCfgText('%s!xsendfile'%(self.key), False, _('Enabled')), _(NOTE_XSENDFILE))
+
+ submit = CTK.Submitter (URL_APPLY)
+ submit += CTK.Indenter (table)
+
+ self += CTK.RawHTML ("<h2>%s</h2>" %(_('Common CGI Options')))
+ self += submit
+
+ # X-Real-IP
+ refresh = CTK.Refreshable ({'id': 'x_real_ip'})
+ refresh.register (lambda: self.X_Real_IP(refresh, self.key).Render())
+
+ self += CTK.RawHTML ("<h2>%s</h2>" % (_('Fixed Authentication List')))
+ self += CTK.Indenter (refresh)
+
+ # Environment
+ refresh = CTK.Refreshable ({'id': 'cgi_environ_list'})
+ refresh.register (lambda: self.Environ(refresh, self.key).Render())
+
+ self += CTK.RawHTML ("<h2>%s</h2>" % (_('Custom Environment Variables')))
+ self += CTK.Indenter (refresh)
+
+ new_name = CTK.TextField ({'name': 'tmp!new_name', 'class': 'noauto'})
+ new_value = CTK.TextField ({'name': 'tmp!new_value', 'class': 'noauto'})
+ new_add = CTK.SubmitterButton (_('Add'))
+
+ table = CTK.Table()
+ table.set_header(1)
+ table += [CTK.RawHTML(x) for x in (_('Name'), _('Value'))]
+ table += [new_name, new_value, new_add]
+
+ submit = CTK.Submitter (URL_APPLY)
+ submit += CTK.Hidden('key', '%s!env'%(self.key))
+ submit += table
+ submit.bind ('submit_success', refresh.JS_to_refresh() + new_name.JS_to_clean() + new_value.JS_to_clean())
+
+ self += CTK.RawHTML ("<h3>%s</h3>" % (_('Add New Custom Environment Variable')))
+ self += CTK.Indenter(submit)
+
+ # Publish
+ VALS = [("%s!script_alias"%(self.key), validations.is_path)]
+ CTK.publish ('^%s$'%(URL_APPLY), commit, validation=VALS, method="POST")
View
264 admin/Cherokee.py
@@ -0,0 +1,264 @@
+# -*- coding: utf-8 -*-
+#
+# Cherokee-admin
+#
+# Authors:
+# Alvaro Lopez Ortega <alvaro@alobbs.com>
+#
+# Copyright (C) 2001-2010 Alvaro Lopez Ortega
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License as published by the Free Software Foundation.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+import CTK
+
+# Python
+import os
+import time
+import errno
+import signal
+
+from subprocess import *
+from select import select
+
+# Cheroke-admin
+from consts import *
+from configured import *
+from config_version import *
+
+
+DEFAULT_PATH = ['/usr/local/sbin', '/usr/local/bin', '/usr/sbin', '/usr/bin', '/sbin', '/bin']
+LAUNCH_DELAY = 2
+
+
+
+class PID:
+ def __init__ (self):
+ self.pid = None
+ self._pid_file = None
+
+ # Initialize
+ self.refresh()
+
+ def refresh (self):
+ # It might be alive
+ if self.pid and _pid_is_alive (self.pid):
+ return
+
+ self.pid = None
+
+ # Need a PID
+ self._read_pid_file()
+ if not self.pid:
+ self._figure_pid()
+
+ def _read_pid_file (self):
+ # Check the configuration
+ self._pid_file = CTK.cfg.get_val("server!pid_file")
+ if not self._pid_file:
+ return
+
+ # Read the file
+ try:
+ f = open(self._pid_file, 'r')
+ except: return
+
+ self.pid = int(f.readline())
+
+ try: f.close()
+ except: pass
+
+ def _figure_pid (self):
+ # Execture ps
+ try:
+ f = os.popen ("ps aux")
+ except: return
+
+ ps = f.read()
+
+ try: f.close()
+ except: pass
+
+ # Try to find the Cherokee process
+ for l in ps.split("\n"):
+ if "cherokee " in l and "-C %s"%(CTK.cfg.file) in l:
+ pid = filter (lambda x: x.isdigit(), l.split())[0]
+ self.pid = int(pid)
+
+
+class Server:
+ def is_alive (self):
+ return _pid_is_alive(pid.pid)
+
+ def stop (self):
+ if not pid.pid: return
+
+ # Kill the process
+ return _pid_kill(pid.pid)
+
+ def restart (self, graceful=True):
+ if not pid.pid: return
+
+ try:
+ os.kill (pid.pid, (signal.SIGUSR1,signal.SIGHUP)[graceful])
+ except:
+ pass
+
+ def launch (self):
+ def daemonize():
+ os.setsid()
+
+ # Ensure the a minimum $PATH is set
+ environ = os.environ.copy()
+ if not "PATH" in environ:
+ environ["PATH"] = ':'.join(DEFAULT_PATH)
+
+ # Launch the process
+ p = Popen ([CHEROKEE_SERVER, '--admin_child', '-C', CTK.cfg.file],
+ stdout=PIPE, stderr=PIPE, env=environ,
+ preexec_fn=daemonize, close_fds=True)
+
+ stdout_f, stderr_f = (p.stdout, p.stderr)
+ stdout_fd, stderr_fd = stdout_f.fileno(), stderr_f.fileno()
+ stdout, stderr = '', ''
+
+ # Check the first few lines of the output
+ while True:
+ r,w,e = select([stdout_fd, stderr_fd], [], [stdout_fd, stderr_fd], 1)
+
+ if e:
+ return _("Could not access file descriptors: ") + str(e)
+
+ if stdout_fd in r:
+ stdout += stdout_f.read(1)
+ if stderr_fd in r:
+ stderr += stderr_f.read(1)
+
+ nl = stderr.find('\n')
+ if nl != -1:
+ for e in ["{'type': ", 'ERROR', '(error) ', '(critical) ']:
+ if e in stderr:
+ _pid_kill (p.pid)
+ return stderr
+ stderr = stderr[nl+1:]
+
+ if stdout.count('\n') > 1:
+ break
+
+ time.sleep (LAUNCH_DELAY)
+ return None
+
+
+class Support:
+ def __init__ (self):
+ # Get server info
+ try:
+ f = os.popen ("%s -i" % (CHEROKEE_WORKER))
+ self._server_info = f.read()
+ except:
+ self._server_info = ''
+
+ try: f.close()
+ except: pass
+
+ def get_info_section (self, filter):
+ filter_string = " %s: " % (filter)
+
+ for line in self._server_info.split("\n"):
+ if line.startswith (filter_string):
+ line = line.replace (filter_string, "")
+ return line.split(" ")
+ return []
+
+ def has_plugin (self, name):
+ try:
+ mods = filter(lambda x: name in x, os.listdir(CHEROKEE_PLUGINDIR))
+ if len(mods) >= 1:
+ return True
+ except:
+ pass
+
+ return name in self.get_info_section("Built-in")
+
+ def has_polling_method (self, name):
+ return name in self.get_info_section("Polling methods")
+
+ def filter_polling_methods (self, methods_list):
+ polling_methods = []
+
+ for name, desc in methods_list:
+ if not name or self.has_polling_method(name):
+ polling_methods.append((name, desc))
+
+ return polling_methods
+
+ def filter_available (self, module_list):
+ new_module_list = []
+
+ for entry in module_list:
+ assert (type(entry) == tuple)
+ assert (len(entry) == 2)
+ plugin, name = entry
+
+ if (not len(plugin) or
+ self.has_plugin (plugin)):
+ new_module_list.append(entry)
+
+ return new_module_list
+
+
+#
+# Globals
+#
+pid = PID()
+server = Server()
+support = Support()
+
+
+#
+# Helper functions
+#
+def _pid_is_alive (pid):
+ if not pid:
+ return False
+
+ try:
+ os.kill (pid, 0)
+ except OSError:
+ return False
+
+ return True
+
+def _pid_kill (pid):
+ # Kill it
+ try:
+ os.kill (pid, signal.SIGTERM)
+ except:
+ return not _pid_is_alive(pid)
+
+ # Ensure it died
+ retries = 3
+ while retries:
+ try:
+ os.waitpid (pid, 0)
+ return True
+ except OSError, e:
+ if e[0] == errno.ECHILD:
+ return True
+ time.sleep(1)
+ retries -= 1
+
+ # Did not succeed
+ return False
View
341 admin/Flags.py
@@ -0,0 +1,341 @@
+# Cheroke Admin
+#
+# Authors:
+# Alvaro Lopez Ortega <alvaro@alobbs.com>
+#
+# Copyright (C) 2010 Alvaro Lopez Ortega
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License as published by the Free Software Foundation.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+import CTK
+
+ISO_3166 = {
+ "AD" : "Andorra",
+ "AE" : "United Arab Emirates",
+ "AF" : "Afghanistan",
+ "AG" : "Antigua and Barbuda",
+ "AI" : "Anguilla",
+ "AL" : "Albania",
+ "AM" : "Armenia",
+ "AN" : "Netherlands Antilles",
+ "AO" : "Angola",
+ "AR" : "Argentina",
+ "AS" : "American Samoa",
+ "AT" : "Austria",
+ "AU" : "Australia",
+ "AW" : "Aruba",
+ "AX" : "Aland Islands",
+ "AZ" : "Azerbaijan",
+ "BA" : "Bosnia & Herzegovina",
+ "BB" : "Barbados",
+ "BD" : "Bangladesh",
+ "BE" : "Belgium",
+ "BF" : "Burkina Faso",
+ "BG" : "Bulgaria",
+ "BH" : "Bahrain",
+ "BJ" : "Benin",
+ "BM" : "Bermuda",
+ "BN" : "Brunei Darussalam",
+ "BO" : "Bolivia",
+ "BR" : "Brazil",
+ "BS" : "Bahamas",
+ "BT" : "Bhutan",
+ "BV" : "Bouvet Island",
+ "BW" : "Botswana",
+ "BY" : "Belarus",
+ "BZ" : "Belize",
+ "CA" : "Canada",
+ "CC" : "Cocos (Keeling) Islands",
+ "CD" : "Republic of the Congo",
+ "CF" : "Central African Republic",
+ "CG" : "Congo",
+ "CH" : "Switzerland",
+ "CI" : "Cote D'Ivoire",
+ "CK" : "Cook Islands",
+ "CL" : "Chile",
+ "CM" : "Cameroon",
+ "CN" : "China",
+ "CO" : "Colombia",
+ "CR" : "Costa Rica",
+ "CU" : "Cuba",
+ "CV" : "Cape Verde",
+ "CX" : "Christmas Island",
+ "CY" : "Cyprus",
+ "CZ" : "Czech Republic",
+ "DE" : "Germany",
+ "DJ" : "Djibouti",
+ "DK" : "Denmark",
+ "DM" : "Dominica",
+ "DO" : "Dominican Republic",
+ "DZ" : "Algeria",
+ "EC" : "Ecuador",
+ "EE" : "Estonia",
+ "EG" : "Egypt",
+ "EH" : "Western Sahara",
+ "ER" : "Eritrea",
+ "ES" : "Spain",
+ "ET" : "Ethiopia",
+ "FI" : "Finland",
+ "FJ" : "Fiji",
+ "FK" : "Malvinas",
+ "FM" : "Micronesia, States of",
+ "FO" : "Faroe Islands",
+ "FR" : "France",
+ "GA" : "Gabon",
+ "GB" : "United Kingdom",
+ "GD" : "Grenada",
+ "GE" : "Georgia",
+ "GF" : "French Guiana",
+ "GH" : "Ghana",
+ "GI" : "Gibraltar",
+ "GL" : "Greenland",
+ "GM" : "Gambia",
+ "GN" : "Guinea",
+ "GP" : "Guadeloupe",
+ "GQ" : "Equatorial Guinea",
+ "GR" : "Greece",
+ "GS" : "South Georgia",
+ "GT" : "Guatemala",
+ "GU" : "Guam",
+ "GW" : "Guinea-Bissau",
+ "GY" : "Guyana",
+ "HK" : "Hong Kong",
+ "HM" : "Heard & McDonald",
+ "HN" : "Honduras",
+ "HR" : "Croatia",
+ "HT" : "Haiti",
+ "HU" : "Hungary",
+ "ID" : "Indonesia",
+ "IE" : "Ireland",
+ "IL" : "Israel",
+ "IN" : "India",
+ "IO" : "British Indian",
+ "IQ" : "Iraq",
+ "IR" : "Iran, Republic of",
+ "IS" : "Iceland",
+ "IT" : "Italy",
+ "JM" : "Jamaica",
+ "JO" : "Jordan",
+ "JP" : "Japan",
+ "KE" : "Kenya",
+ "KG" : "Kyrgyzstan",
+ "KH" : "Cambodia",
+ "KI" : "Kiribati",
+ "KM" : "Comoros",
+ "KN" : "Saint Kitts and Nevis",
+ "KP" : "Korea, Republic of",
+ "KR" : "Korea, Republic of",
+ "KW" : "Kuwait",
+ "KY" : "Cayman Islands",
+ "KZ" : "Kazakhstan",
+ "LA" : "Lao, Republic",
+ "LB" : "Lebanon",
+ "LC" : "Saint Lucia",
+ "LI" : "Liechtenstein",
+ "LK" : "Sri Lanka",
+ "LR" : "Liberia",
+ "LS" : "Lesotho",
+ "LT" : "Lithuania",
+ "LU" : "Luxembourg",
+ "LV" : "Latvia",
+ "LY" : "Libyan Arab Jamahiriya",
+ "MA" : "Morocco",
+ "MC" : "Monaco",
+ "MD" : "Moldova, Republic of",
+ "ME" : "Montenegro",
+ "MG" : "Madagascar",
+ "MH" : "Marshall Islands",
+ "MK" : "Macedonia",
+ "ML" : "Mali",
+ "MM" : "Myanmar",
+ "MN" : "Mongolia",
+ "MO" : "Macau",
+ "MP" : "N. Mariana Islands",
+ "MQ" : "Martinique",
+ "MR" : "Mauritania",
+ "MS" : "Montserrat",
+ "MT" : "Malta",
+ "MU" : "Mauritius",
+ "MV" : "Maldives",
+ "MW" : "Malawi",
+ "MX" : "Mexico",
+ "MY" : "Malaysia",
+ "MZ" : "Mozambique",
+ "NA" : "Namibia",
+ "NC" : "New Caledonia",
+ "NE" : "Niger",
+ "NF" : "Norfolk Island",
+ "NG" : "Nigeria",
+ "NI" : "Nicaragua",
+ "NL" : "Netherlands",
+ "NO" : "Norway",
+ "NP" : "Nepal",
+ "NR" : "Nauru",
+ "NU" : "Niue",
+ "NZ" : "New Zealand",
+ "OM" : "Oman",
+ "PA" : "Panama",
+ "PE" : "Peru",
+ "PF" : "French Polynesia",
+ "PG" : "Papua New Guinea",
+ "PH" : "Philippines",
+ "PK" : "Pakistan",
+ "PL" : "Poland",
+ "PM" : "S. Pierre & Miquelon",
+ "PN" : "Pitcairn Islands",
+ "PR" : "Puerto Rico",
+ "PS" : "Palestinian Territory",
+ "PT" : "Portugal",
+ "PW" : "Palau",
+ "PY" : "Paraguay",
+ "QA" : "Qatar",
+ "RE" : "Reunion",
+ "RO" : "Romania",
+ "RS" : "Serbia",
+ "RU" : "Russian Federation",
+ "RW" : "Rwanda",
+ "SA" : "Saudi Arabia",
+ "SB" : "Solomon Islands",
+ "SC" : "Seychelles",
+ "SD" : "Sudan",
+ "SE" : "Sweden",
+ "SG" : "Singapore",
+ "SH" : "Saint Helena",
+ "SI" : "Slovenia",
+ "SJ" : "Svalbard and Jan Mayen",
+ "SK" : "Slovakia",
+ "SL" : "Sierra Leone",
+ "SM" : "San Marino",
+ "SN" : "Senegal",
+ "SO" : "Somalia",
+ "SR" : "Suriname",
+ "ST" : "Sao Tome & Principe",
+ "SV" : "El Salvador",
+ "SY" : "Syrian Arab Republic",
+ "SZ" : "Swaziland",
+ "TC" : "Turks & Caicos Islands",
+ "TD" : "Chad",
+ "TF" : "French S. Territories",
+ "TG" : "Togo",
+ "TH" : "Thailand",
+ "TJ" : "Tajikistan",
+ "TK" : "Tokelau",
+ "TL" : "Timor-Leste",
+ "TM" : "Turkmenistan",
+ "TN" : "Tunisia",
+ "TO" : "Tonga",
+ "TR" : "Turkey",
+ "TT" : "Trinidad and Tobago",
+ "TV" : "Tuvalu",
+ "TW" : "Taiwan",
+ "TZ" : "Tanzania, Republic of",
+ "UA" : "Ukraine",
+ "UG" : "Uganda",
+ "UM" : "US Outlying Islands",
+ "US" : "United States",
+ "UY" : "Uruguay",
+ "UZ" : "Uzbekistan",
+ "VA" : "Vatican City State",
+ "VC" : "S. Vincent & Grenadines",
+ "VE" : "Venezuela",
+ "VG" : "Virgin Islands, British",
+ "VI" : "Virgin Islands, U.S.",
+ "VN" : "Vietnam",
+ "VU" : "Vanuatu",
+ "WF" : "Wallis and Futuna",
+ "WS" : "Samoa",
+ "YE" : "Yemen",
+ "YT" : "Mayotte",
+ "ZA" : "South Africa",
+ "ZM" : "Zambia",
+ "ZW" : "Zimbabwe"
+}
+
+EXTRA_OPTIONS = [
+ ("EU", "Europe", "europeanunion.png"),
+ ("AP", "Asia/Pacific Region"),
+ ("AQ", "Antarctica"),
+ ("BI", "Burundi"),
+ ("BL", "Saint Barthelemy"),
+ ("FX", "France, Metropolitan"),
+ ("GG", "Guernsey"),
+ ("IM", "Isle of Man"),
+ ("JE", "Jersey"),
+ ("MF", "Saint Martin"),
+ ("A1", "Anonymous Proxy"),
+ ("A2", "Satellite Provider"),
+ ("O1", "Other")
+]
+
+CSS = "background-image: url(/static/images/flags/%s); background-repeat: no-repeat; background-position:bottom right;"
+
+
+class ComboFlags (CTK.ComboCfg):
+ def __init__ (self, key, _props={}):
+ # Properties
+ props = _props.copy()
+
+ # Contries
+ codes = ISO_3166.keys()
+ codes.sort()
+
+ countries = []
+ for k in codes:
+ countries.append ((k, ISO_3166[k], {'style': CSS%('%s.png'%(k))}))
+
+ # Extra entries
+ extras = []
+ for k in EXTRA_OPTIONS:
+ if len(k) == 2:
+ extras.append ((k[0], k[1]))
+ else:
+ extras.append ((k[0], k[1], {'style': CSS%(k[2])}))
+
+
+ options = [(_('Countries'), countries), (_('Extras'), extras)]
+
+ CTK.ComboCfg.__init__ (self, key, options, props)
+
+
+class CheckListFlags (CTK.Box):
+ def __init__ (self, key, _props={}):
+ CTK.Box.__init__ (self, {'class': 'check-list-flags'})
+
+ # Flags
+ props = _props.copy()
+ codes = ISO_3166.keys()
+ codes.sort()
+ props['class'] = 'flag_checkbox'
+
+ # Initial values
+ selected = filter (lambda x: x, [x.strip() for x in CTK.cfg.get_val (key,'').split(',')])
+
+ self += CTK.RawHTML ('<b>%s</b>' %(_("Countries")))
+ for k in codes:
+ box = CTK.Box({'class': 'check-list-flags-entry'})
+ box += CTK.CheckCfg ('%s!%s' %(key, k), k in selected, props)
+ box += CTK.Image ({'src': "/static/images/flags/%s.png"%(k)})
+ box += CTK.RawHTML (ISO_3166[k])
+ self += box
+
+ self += CTK.RawHTML ('<b>%s</b>' %(_("Extras")))
+ for k in EXTRA_OPTIONS:
+ box = CTK.Box({'class': 'check-list-flags-entry'})
+ box += CTK.CheckCfg ('%s!%s' %(key, k[0]), k[0] in selected, props)
+ if len(k) == 3:
+ box += CTK.Image ({'src': "/static/images/flags/%s"%(k[2])})
+ box += CTK.RawHTML (k[1])
+ self += box
View
180 admin/Graph.py
@@ -0,0 +1,180 @@
+# -*- coding: utf-8 -*-
+#
+# Cherokee-admin
+#
+# Authors:
+# Alvaro Lopez Ortega <alvaro@alobbs.com>
+# Taher Shihadeh <taher@unixwars.com>
+#
+# Copyright (C) 2001-2010 Alvaro Lopez Ortega
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License as published by the Free Software Foundation.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+import CTK
+import Cherokee
+import validations
+
+from consts import *
+from configured import *
+
+
+URL_APPLY = '/graph/apply'
+
+GRAPH_VSERVER = '/graphs/%(prefix)s_%(type)s_%(vserver)s_%(interval)s.png'
+GRAPH_SERVER = '/graphs/%(prefix)s_%(type)s_%(interval)s.png'
+
+GRAPH_TYPES = [('traffic', N_('Server Traffic')),
+ ('accepts', N_('Connections / Requests')),
+ ('timeouts', N_('Connection Timeouts')),]
+
+GRAPH_INTERVALS = [('1h', N_('1 Hour')),
+ ('6h', N_('6 Hours')),
+ ('1d', N_('1 Day')),
+ ('1w', N_('1 Week')),
+ ('1m', N_('1 Month'))]
+
+URL_RRD = '/general#Network-1'
+RRD_NOTICE = N_('You need to enable the <a href="%s">Information Collector</a> setting in order to render usage graphics.'%URL_RRD)
+NOTE_COLLECTOR = N_('Whether or not it should collect statistics about the traffic of this virtual server.')
+
+UPDATE_JS = """
+function updateGraph() {
+ var timeout = $(window).data('graph-timeout');
+
+ if ((timeout != null) &&
+ (timeout != undefined))
+ {
+ clearTimeout (timeout);
+ $(window).data('graph-timeout', null);
+ }
+
+ %s
+}
+
+var tmp = setTimeout (updateGraph, 60000);
+$(window).data('graph-timeout', tmp);
+""" #%(JS_to_refresh)
+
+def apply ():
+ graph_type = CTK.post.get_val('graph_type')
+ if graph_type:
+ CTK.cfg['tmp!graph_type'] = graph_type
+ return CTK.cfg_reply_ajax_ok()
+
+ # Modifications
+ return CTK.cfg_apply_post()
+
+
+class Graph (CTK.Box):
+ def __init__ (self, refreshable, **kwargs):
+ CTK.Box.__init__ (self)
+ self.graph = {}
+ self.graph['type'], self.graph['type_txt'] = GRAPH_TYPES[0]
+ self.refresh = refreshable
+
+ def build_graph (self):
+ if CTK.cfg.get_val('server!collector') != 'rrd':
+ notice = CTK.Notice()
+ notice += CTK.RawHTML(_(RRD_NOTICE))
+ self += CTK.Indenter(notice)
+ return False
+
+ tabs = CTK.Tab ()
+ for x in GRAPH_INTERVALS:
+ self.graph['interval'] = x[0]
+ props = {'src': self.template % self.graph,
+ 'alt': '%s: %s' %(self.graph['type_txt'], x[1])}
+ image = CTK.Image(props)
+ tabs.Add (_(x[1]), image)
+ self += tabs
+ return True
+
+ def Render (self):
+ render = CTK.Box.Render (self)
+ render.js += UPDATE_JS % (self.refresh.JS_to_refresh())
+ return render
+
+
+class GraphVServer_Instancer (CTK.Container):
+ class GraphVServer (Graph):
+ def __init__ (self, refreshable, vsrv_num, **kwargs):
+ Graph.__init__ (self, refreshable, **kwargs)
+ self.template = GRAPH_VSERVER
+ self.graph['prefix'] = 'vserver'
+ self.graph['vserver'] = CTK.cfg.get_val ("vserver!%s!nick" %(vsrv_num), _("Unknown"))
+ self.graph['num'] = vsrv_num
+ self.collector = bool(int(CTK.cfg.get_val ('vserver!%s!collector!enabled'%(vsrv_num),'0')))
+ self.build()
+
+ def build (self):
+ table = CTK.PropsTable()
+ table.Add (_('Collect Statistics'), CTK.CheckCfgText('vserver!%s!collector!enabled'%(self.graph['num']), self.collector), _(NOTE_COLLECTOR))
+
+ submit = CTK.Submitter (URL_APPLY)
+ submit += table
+ submit.bind('submit_success', self.refresh.JS_to_refresh())
+
+ if self.collector:
+ self.build_graph ()
+ props = {'class': 'graph_props_bottom'}
+ else:
+ props = {'class': 'graph_props_top'}
+
+ if CTK.cfg.get_val('server!collector') == 'rrd':
+ self += CTK.Indenter (CTK.Box(props, submit))
+
+ def __init__ (self, vserver):
+ CTK.Container.__init__ (self)
+
+ # Refresher
+ refresh = CTK.Refreshable ({'id': 'grapharea'})
+ refresh.register (lambda: self.GraphVServer(refresh, vserver).Render())
+ self += refresh
+
+
+class GraphServer_Instancer (CTK.Container):
+ class GraphServer (Graph):
+ def __init__ (self, refreshable, **kwargs):
+ Graph.__init__ (self, refreshable, **kwargs)
+ self.template = GRAPH_SERVER
+ self.graph['prefix'] = 'server'
+ self.graph['type'] = CTK.cfg.get_val('tmp!graph_type', self.graph['type'])
+ self.build()
+
+ def build (self):
+ rrd = self.build_graph ()
+ if rrd:
+ props = {'class': 'graph_type', 'name': 'graph_type', 'selected': self.graph['type']}
+ combo = CTK.Combobox (props, GRAPH_TYPES)
+ submit = CTK.Submitter (URL_APPLY)
+ submit += combo
+ submit.bind('submit_success', self.refresh.JS_to_refresh())
+
+ for x in GRAPH_TYPES:
+ if x[0] == self.graph['type']:
+ self.graph['type_txt'] = x[1]
+
+ self += submit
+
+ def __init__ (self):
+ CTK.Container.__init__ (self)
+
+ # Refresher
+ refresh = CTK.Refreshable ({'id': 'grapharea'})
+ refresh.register (lambda: self.GraphServer(refresh).Render())
+ self += refresh
+
+CTK.publish ('^%s'%(URL_APPLY), apply, method="POST")
View
51 admin/Handler.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+#
+# Cherokee-admin
+#
+# Authors:
+# Alvaro Lopez Ortega <alvaro@alobbs.com>
+#
+# Copyright (C) 2010 Alvaro Lopez Ortega
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License as published by the Free Software Foundation.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+import CTK
+import Cherokee
+import validations
+
+URL_APPLY = '/plugin/handler/apply'
+
+NOTE_DOCUMENT_ROOT = N_('Allows to specify an alternative Document Root path.')
+
+
+class PluginHandler (CTK.Plugin):
+ def __init__ (self, key, **kwargs):
+ CTK.Plugin.__init__ (self, key)
+ self.show_document_root = kwargs.pop('show_document_root', True)
+ self.key_rule = '!'.join(self.key.split('!')[:-1])
+
+ def AddCommon (self):
+ if self.show_document_root:
+ table = CTK.PropsTable()
+ table.Add (_('Document Root'), CTK.TextCfg('%s!document_root'%(self.key_rule), True), _(NOTE_DOCUMENT_ROOT))
+
+ submit = CTK.Submitter (URL_APPLY)
+ submit += CTK.Indenter (table)
+ self += submit
+
+ # Publish
+ VALS = [("%s!document_root"%(self.key_rule), validations.is_dev_null_or_local_dir_exists)]
+ CTK.publish ('^%s'%(URL_APPLY), CTK.cfg_apply_post, validation=VALS, method="POST")
View
367 admin/Icons.py
@@ -0,0 +1,367 @@
+# -*- coding: utf-8 -*-
+#
+# Cherokee-admin
+#
+# Authors:
+# Alvaro Lopez Ortega <alvaro@alobbs.com>
+# Taher Shihadeh <taher@unixwars.com>
+#
+# Copyright (C) 2001-2010 Alvaro Lopez Ortega
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License as published by the Free Software Foundation.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+import CTK
+import Page
+import Cherokee
+import os
+import validations
+import util
+
+from consts import *
+from configured import *
+
+URL_APPLY = '/icons/apply'
+
+ICON_ROW_SIZE = 9
+
+VALIDATIONS = [
+ ('new_exts', validations.is_safe_icons_suffix),
+ ('new_file', validations.is_safe_icons_file),
+]
+
+def modify():
+ updates = {}
+ for k in CTK.post:
+ validator = None
+ if k.startswith('icons!suffix') and CTK.post['k']:
+ validator = validations.is_safe_icons_suffix
+ elif k.startswith ('icons!file') and CTK.post['k']:
+ validator = validations.is_safe_icons_file
+
+ if validator:
+ new = CTK.post[k]
+ try:
+ val = validator (new, CTK.cfg.get_val(k))
+ if util.lists_differ (val, new):
+ updates[k] = val
+ except ValueError, e:
+ return { "ret": "error", "errors": { k: str(e) }}
+
+ CTK.cfg[k] = CTK.post[k]
+
+ if updates:
+ return {'ret': 'unsatisfactory', 'updates': updates}
+
+
+def commit():
+ # New extension
+ new_exts = CTK.post.pop('new_exts')
+ if new_exts:
+ icon = CTK.post.get_val('new_exts_icon')
+ if not icon:
+ return CTK.cfg_reply_ajax_ok()
+
+ CTK.cfg['icons!suffix!%s'%(icon)] = new_exts
+ return CTK.cfg_reply_ajax_ok()
+
+ # New file
+ new_file = CTK.post.pop('new_file')
+ if new_file:
+ icon = CTK.post.get_val('new_file_icon')
+ if not icon:
+ return CTK.cfg_reply_ajax_ok()
+
+ CTK.cfg['icons!file!%s'%(icon)] = new_file
+ return CTK.cfg_reply_ajax_ok()
+
+ # Modifications
+ updates = modify()
+ if updates:
+ return updates
+ return CTK.cfg_reply_ajax_ok()
+
+
+def prettyfier (filen):
+ # Remove extension
+ if '.' in filen:
+ filen = filen[:filen.rindex('.')]
+
+ # Remove underscores
+ filen = filen.replace('_',' ').replace('.',' ')
+
+ # Capitalize
+ return filen.capitalize()
+
+
+class ExtensionsTable (CTK.Container):
+ def __init__ (self, refreshable, **kwargs):
+ CTK.Container.__init__ (self, **kwargs)
+
+ # List
+ icons = CTK.cfg.keys('icons!suffix')
+ if icons:
+ table = CTK.Table()
+ table.id = "icon_extensions"
+ table += [None, CTK.RawHTML(_('Extensions'))]
+ table.set_header(1)
+
+ icons.sort()
+ for k in icons:
+ pre = 'icons!suffix!%s'%(k)
+ desc = prettyfier(k)
+ image = CTK.Image ({'alt' : desc, 'title': desc, 'src': os.path.join('/icons_local', k)})
+ delete = CTK.ImageStock('del')
+ submit = CTK.Submitter (URL_APPLY)
+ submit += CTK.TextCfg (pre, props={'size': '46'})
+ table += [image, submit, delete]
+
+ delete.bind('click', CTK.JS.Ajax (URL_APPLY, data = {pre: ''},
+ complete = refreshable.JS_to_refresh()))
+
+ self += CTK.RawHTML ("<h2>%s</h2>" %_('Extension List'))
+ self += CTK.Indenter (table)
+
+ # Add New
+ button = AdditionDialogButton ('new_exts', 'Extensions', submit_label=_('Add New Extension'))
+ button.bind ('submit_success', refreshable.JS_to_refresh())
+ self += button
+
+
+class FilesTable (CTK.Container):
+ def __init__ (self, refreshable, **kwargs):
+ CTK.Container.__init__ (self, **kwargs)
+
+ # List
+ icons = CTK.cfg.keys('icons!file')
+ if icons:
+ table = CTK.Table()
+ table.id = "icon_files"
+ table += [None, CTK.RawHTML(_('Files'))]
+ table.set_header(1)
+
+ for k in icons:
+ pre = 'icons!file!%s'%(k)
+ desc = prettyfier(k)
+ image = CTK.Image ({'alt' : desc, 'title': desc, 'src': os.path.join('/icons_local', k)})
+ submit = CTK.Submitter (URL_APPLY)
+ submit += CTK.TextCfg (pre, props={'size': '46'})
+ delete = CTK.ImageStock('del')
+ table += [image, submit, delete]
+
+ delete.bind('click', CTK.JS.Ajax (URL_APPLY, data = {pre: ''},
+ complete = refreshable.JS_to_refresh()))
+
+ self += CTK.RawHTML ("<h2>%s</h2>" %_('File Matches'))
+ self += CTK.Indenter (table)
+
+ # Add New
+ button = AdditionDialogButton ('new_file', 'File', submit_label=_('Add New File'))
+ button.bind ('submit_success', refreshable.JS_to_refresh())
+ self += button
+
+
+class SpecialTable (CTK.Container):
+ def __init__ (self, refreshable, **kwargs):
+ CTK.Container.__init__ (self, **kwargs)
+
+ table = CTK.Table()
+
+ for k, desc in [('default', _('Default')),
+ ('directory', _('Directory')),
+ ('parent_directory', _('Go to Parent'))]:
+
+ icon = CTK.cfg.get_val('icons!%s'%(k))
+ props = {'alt' : desc,
+ 'title': desc,
+ 'src' : '/icons_local/%s'%(icon)}
+ image = CTK.Image (props)
+ button = AdditionDialogButton (k, k, selected = icon, submit_label = _('Modify'))
+ button.bind ('submit_success', refreshable.JS_to_refresh())
+ table += [image, CTK.RawHTML(desc), button]
+
+ submit = CTK.Submitter(URL_APPLY)
+ submit += table
+
+ self += CTK.RawHTML ("<h2>%s</h2>" %_('Special Files'))
+ self += CTK.Indenter (submit)
+
+
+class SpecialWidget_Instancer (CTK.Container):
+ def __init__ (self):
+ CTK.Container.__init__ (self)
+
+ # Refresher
+ refresh = CTK.Refreshable ({'id': 'icons_special'})
+ refresh.register (lambda: SpecialTable(refresh).Render())
+ self += refresh
+
+
+class ExtensionsWidget_Instancer (CTK.Container):
+ def __init__ (self):
+ CTK.Container.__init__ (self)
+
+ # Refresher
+ refresh = CTK.Refreshable ({'id': 'icons_extensions'})
+ refresh.register (lambda: ExtensionsTable(refresh).Render())
+ self += refresh
+
+
+class FilesWidget_Instancer (CTK.Container):
+ def __init__ (self):
+ CTK.Container.__init__ (self)
+
+ # Refresher
+ refresh = CTK.Refreshable ({'id': 'icons_files'})
+ refresh.register (lambda: FilesTable(refresh).Render())
+ self += refresh
+
+
+ICON_CHOOSER_JS = """
+$('#%(iconchooserbox_id)s').each(function() {
+ var chooser = $(this);
+ var hidden = chooser.find('input:hidden');
+
+ chooser.find('img.icon_chooser_entry').each(function() {
+ $(this).bind('click', function(event) {
+ var image = $(this);
+ hidden.val(image.attr('file'));
+ chooser.find('.icon_chooser_entry').removeClass("icon_chooser_selected");
+ image.addClass("icon_chooser_selected");
+ });
+ });
+});
+"""
+
+class IconChooser (CTK.Box):
+ def __init__ (self, field_name, prefix, **kwargs):
+ CTK.Box.__init__ (self, {'class': 'icon-chooser-box'})
+ selected = kwargs.get('selected')
+
+ # Get the file list
+ files, unused = self.get_files (prefix)
+ total = len(files)
+
+ # Build the table
+ row = []
+ table = CTK.Table()
+ for x in range(total):
+ filename = files[x]
+ desc = prettyfier (filename)
+
+ props = {'alt' : desc,
+ 'title': desc,
+ 'file' : filename,
+ 'src' : '/icons_local/%s'%(filename),
+ 'class': 'icon_chooser_entry icon_chooser_used'}
+
+ if filename in unused:
+ props['class'] = 'icon_chooser_entry icon_chooser_unused'
+ if filename == selected:
+ props['class'] = 'icon_chooser_entry icon_chooser_selected'
+
+ image = CTK.Image(props)
+ row.append (image)
+ if (x+1) % ICON_ROW_SIZE == 0 or (x+1) == total:
+ table += row
+ row = []
+
+ hidden = CTK.Hidden(field_name, '')
+ self += hidden
+ self += table
+
+ def Render (self):
+ render = CTK.Box.Render (self)
+ render.js += ICON_CHOOSER_JS %({'iconchooserbox_id': self.id})
+ return render
+
+
+ def get_files (self, prefix = None):
+ listdir = os.listdir (CHEROKEE_ICONSDIR)
+ files = []
+ for filename in listdir:
+ ext = filename.lower().split('.')[-1]
+ if ext in ('jpg', 'png', 'gif', 'svg'):
+ files.append(filename)
+
+ if not prefix:
+ return (files, files)
+
+ icons = CTK.cfg.keys(prefix)
+ unused = list(set(files) - set(icons))
+ unused.sort()
+ return (files, unused)
+
+
+class AddIcon (CTK.Container):
+ def __init__ (self, key, **kwargs):
+ CTK.Container.__init__ (self)
+ descs = {'new_file': _('File'),
+ 'new_exts': _('Extensions'),
+ 'default': _('Default'),
+ 'directory': _('Directory'),
+ 'parent_directory': _('Go to Parent')}
+ assert key in descs.keys()
+ label = descs[key]
+
+ table = CTK.Table()
+ row = [CTK.Box ({'class': 'icon_label'}, CTK.RawHTML (label))]
+
+ if key in ['new_file','new_exts']:
+ field = CTK.TextField({'name': key, 'class': 'noauto'})
+ row.append(CTK.Box ({'class': 'icon_field'}, field))
+ hidden_name = '%s_icon' %(key)
+ prefix = ['icons!suffix', 'icons!file'][key == 'new_file']
+ else:
+ hidden_name = 'icons!%s' %(key)
+ prefix = None
+
+ table += row
+ submit = CTK.Submitter(URL_APPLY)
+ submit += table
+ submit += IconChooser(hidden_name, prefix, **kwargs)
+ self += submit
+
+
+class AdditionDialogButton (CTK.Box):
+ def __init__ (self, key, name, **kwargs):
+ CTK.Box.__init__ (self, {'class': '%s-button' %(name)})
+ submit_label = kwargs.get('submit_label', _('Add'))
+ button_label = kwargs.get('button_label', '%s'%(submit_label))
+
+ # Dialog
+ dialog = CTK.Dialog ({'title': _('Add new %s'%(name)), 'width': 375})
+ dialog.AddButton (submit_label, dialog.JS_to_trigger('submit'))
+ dialog.AddButton (_('Cancel'), "close")
+ dialog += AddIcon(key, **kwargs)
+
+ # Button
+ button = CTK.Button (button_label)
+ button.bind ('click', dialog.JS_to_show())
+ dialog.bind ('submit_success', dialog.JS_to_close())
+ dialog.bind ('submit_success', self.JS_to_trigger('submit_success'));
+
+ self += button
+ self += dialog
+
+
+class Icons_Widget (CTK.Container):
+ def __init__ (self, **kwargs):
+ CTK.Container.__init__ (self, **kwargs)
+ self += SpecialWidget_Instancer()
+ self += FilesWidget_Instancer()
+ self += ExtensionsWidget_Instancer()
+
+CTK.publish ('^%s'%(URL_APPLY), commit, validation=VALIDATIONS, method="POST")
View
96 admin/Makefile.am
@@ -0,0 +1,96 @@
+## Cherokee: Makefile.am -*- makefile -*-
+
+SUBDIRS = plugins wizards
+
+if INSTALL_ADMIN
+SUBDIRS += static
+endif
+
+SUFFIXES = .py.pre .py
+
+.py.pre.py:
+ sed -e "s|%sysconfdir%|${sysconfdir}|g; s|%sbindir%|${sbindir}|g; s|%docdir%|${docdir}|g; s|%prefix%|${prefix}|g; s|%localstatedir%|${localstatedir}|g; s|%libdir%|${libdir}|g; s|%wwwroot%|${WWW_ROOT}|g; s|%version%|${PACKAGE_VERSION}|g; s|%phpcgi%|${PHPCGI}|g; s|%datadir%|${datadir}|g; s|%localedir%|${localedir}|g" $< > $@
+
+PY_PRE = \
+configured.py.pre
+
+
+if INSTALL_ADMIN
+gen_data = $(PY_PRE:.py.pre=.py)
+endif
+
+generateddir = "$(datadir)/cherokee/admin"
+generated_DATA = $(gen_data)
+
+
+if INSTALL_ADMIN
+admin_scripts = server.py upgrade_config.py
+endif
+
+adminpydir = "$(datadir)/cherokee/admin"
+adminpy_SCRIPTS = $(admin_scripts)
+
+
+if INSTALL_ADMIN
+admin_data = \
+Auth.py \
+Balancer.py \
+CgiBase.py \
+Cherokee.py \
+Flags.py \
+Graph.py \
+Handler.py \
+Icons.py \
+Mime.py \
+Page.py \
+PageAdvanced.py \
+PageEntry.py \
+PageError.py \
+PageException.py \
+PageGeneral.py \
+PageHelp.py \
+PageIndex.py \
+PageNewConfig.py \
+PageRule.py \
+PageSource.py \
+PageSources.py \
+PageStatus.py \
+PageVServer.py \
+PageVServers.py \
+Rule.py \
+RuleSimple.py \
+SelectionPanel.py \
+Wizard.py \
+XMLServerDigest.py \
+config_version.py \
+consts.py \
+server.py \
+upgrade_config.py \
+util.py \
+validations.py
+
+html_data = \
+exception.html \
+help.html \
+theme.html
+
+endif
+
+adminpy_DATA = $(admin_data) $(html_data)
+
+if INSTALL_ADMIN
+template_data =
+endif
+
+adminhelpdir = "$(datadir)/cherokee/admin"
+adminhelp_DATA = $(template_data)
+
+EXTRA_DIST = \
+$(PY_PRE) \
+$(admin_data) \
+$(admin_scripts) \
+$(template_data)
+
+CLEANFILES = \
+$(generated_DATA)
+
View
162 admin/Mime.py
@@ -0,0 +1,162 @@
+# -*- coding: utf-8 -*-
+#
+# Cherokee-admin
+#
+# Authors:
+# Alvaro Lopez Ortega <alvaro@alobbs.com>
+# Taher Shihadeh <taher@unixwars.com>
+#
+# Copyright (C) 2001-2010 Alvaro Lopez Ortega
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License as published by the Free Software Foundation.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+import CTK
+import Page
+import Cherokee
+import validations
+import util
+
+from consts import *
+from configured import *
+
+URL_APPLY = '/mime/apply'
+
+NOTE_NEW_MIME = N_('New MIME type to be added.')
+NOTE_NEW_EXTENSIONS = N_('Comma separated list of file extensions associated with the MIME type.')
+NOTE_NEW_MAXAGE = N_('Maximum time that this sort of content can be cached (in seconds).')
+
+
+VALIDATIONS = [
+ ('new_mime', validations.is_safe_mime_type),
+ ('new_exts', validations.is_safe_mime_exts),
+]
+
+def commit():
+ # New entry
+ mime = CTK.post.pop('new_mime')
+ exts = CTK.post.pop('new_exts')
+ mage = CTK.post.pop('new_mage')
+
+ if mime:
+ if mage:
+ CTK.cfg['mime!%s!max-age'%(mime)] = mage
+ if exts:
+ CTK.cfg['mime!%s!extensions'%(mime)] = exts
+
+ return CTK.cfg_reply_ajax_ok()
+
+ # Modifications
+ updates = {}
+ for k in CTK.post:
+ if k.endswith('!extensions'):
+ new = CTK.post[k]
+ try:
+ val = validations.is_safe_mime_exts (new, CTK.cfg.get_val(k))
+ if util.lists_differ (val, new):
+ updates[k] = val
+ except ValueError, e:
+ return { "ret": "error", "errors": { k: str(e) }}
+ CTK.cfg[k] = CTK.post[k]
+
+ if updates:
+ return {'ret': 'unsatisfactory', 'updates': updates}
+
+ return CTK.cfg_reply_ajax_ok()
+
+
+class AddMime (CTK.Container):
+ def __init__ (self):
+ CTK.Container.__init__ (self)
+
+ table = CTK.PropsTable()
+ table.Add (_('Mime Type'), CTK.TextField({'name': 'new_mime', 'class': 'noauto'}), _(NOTE_NEW_MIME))
+ table.Add (_('Extensions'), CTK.TextField({'name': 'new_exts', 'class': 'noauto optional'}), _(NOTE_NEW_EXTENSIONS))
+ table.Add (_('Max Age'), CTK.TextField({'name': 'new_mage', 'class': 'noauto optional'}), _(NOTE_NEW_MAXAGE))
+
+ submit = CTK.Submitter(URL_APPLY)
+ submit += table
+ self += submit
+
+
+class AddNew_Button (CTK.Box):
+ def __init__ (self):
+ CTK.Box.__init__ (self, {'class': 'mime-button'})
+
+ # Add New
+ dialog = CTK.Dialog ({'title': _('Add New MIME-Type'), 'width': 480})
+ dialog.AddButton (_('Add'), dialog.JS_to_trigger('submit'))
+ dialog.AddButton (_('Cancel'), "close")
+ dialog += AddMime()
+
+ button = CTK.Button(_('Add New…'))
+ button.bind ('click', dialog.JS_to_show())
+ dialog.bind ('submit_success', dialog.JS_to_close())
+ dialog.bind ('submit_success', self.JS_to_trigger('submit_success'));
+
+ self += button
+ self += dialog
+
+
+class MIME_Table (CTK.Container):
+ def __init__ (self, refreshable, **kwargs):
+ CTK.Container.__init__ (self, **kwargs)
+
+ # List
+ table = CTK.Table ({'id': "mimetable"})
+ table.set_header(1)
+ table += [CTK.RawHTML(x) for x in (_('MIME type'), _('Extensions'), _('MaxAge (<em>secs</em>)'), '')]
+
+ mimes = CTK.cfg.keys('mime')
+ mimes.sort()
+
+ for mime in mimes:
+ pre = "mime!%s"%(mime)
+ e1 = CTK.TextCfg ('%s!extensions'%(pre), False, {'size': 35})
+ e2 = CTK.TextCfg ('%s!max-age'%(pre), True, {'size': 6, 'maxlength': 6})
+ rm = CTK.ImageStock('del')
+ rm.bind('click', CTK.JS.Ajax (URL_APPLY, data = {pre: ''},
+ complete = refreshable.JS_to_refresh()))
+ table += [CTK.RawHTML(mime), e1, e2, rm]
+
+ submit = CTK.Submitter (URL_APPLY)
+ submit += table
+
+ # Add New
+ button = AddNew_Button()
+ button.bind ('submit_success', refreshable.JS_to_refresh ())
+
+ self += CTK.RawHTML ('<h2>%s</h2>' %('MIME Types'))
+ self += submit
+ self += button
+
+
+class MIME_Table_Instancer (CTK.Container):
+ def __init__ (self):
+ CTK.Container.__init__ (self)
+
+ # Refresher
+ refresh = CTK.Refreshable ({'id': 'mime_table'})
+ refresh.register (lambda: MIME_Table(refresh).Render())
+ self += refresh
+
+
+class MIME_Widget (CTK.Container):
+ def __init__ (self, **kwargs):
+ CTK.Container.__init__ (self, **kwargs)
+ self += MIME_Table_Instancer()
+
+
+CTK.publish ('^%s'%(URL_APPLY), commit, validation=VALIDATIONS, method="POST")
View
130 admin/Page.py
@@ -0,0 +1,130 @@
+# -*- coding: utf-8 -*-
+#
+# Cherokee-admin
+#
+# Authors:
+# Alvaro Lopez Ortega <alvaro@alobbs.com>
+#
+# Copyright (C) 2001-2010 Alvaro Lopez Ortega
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License as published by the Free Software Foundation.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+import os
+import copy
+
+import CTK
+import Cherokee
+import configured
+
+SAVED_NOTICE = N_("The Configuration has been Saved")
+SAVED_RESTART = N_("Would you like to apply the changes to the running server now?")
+
+URL_SAVE = r'/save'
+URL_SAVE_GRACEFUL = r'/save/apply/graceful'
+URL_SAVE_HARD = r'/save/apply/hard'
+URL_SAVE_NONE = r'/save/apply/none'
+
+SAVE_BUTTON = """
+$('#save-button').bind ('click', function(){
+ /* Do nothing if it hasn't changed */
+ if ($(this).hasClass('saved')) {
+ return;
+ }
+
+ %s
+})"""
+
+
+def Restart (mode):
+ if mode == 'graceful':
+ Cherokee.server.restart (graceful=True)
+
+ elif mode == 'hard':
+ Cherokee.server.restart (graceful=False)
+
+ return {'ret': 'ok', 'not-modified': '#save-button'}
+
+
+class Save:
+ def __call__ (self, dialog):
+ # Save
+ CTK.cfg.save()
+
+ # Prompt about the reset
+ all = CTK.Box({'id': "buttons"})
+ all += CTK.RawHTML ('<p>%s</p>' %(SAVED_RESTART))
+
+ submit = CTK.Submitter (URL_SAVE_NONE)
+ submit += CTK.Hidden('none')