summaryrefslogtreecommitdiff
path: root/plugins/pythondemo
blob: 1edbb819e02615f0022de164a518ddb8d0e28c04 (plain)
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # pythondemo — demo Python ikiwiki plugin
  5. #
  6. # Copyright © martin f. krafft <madduck@madduck.net>
  7. # Released under the terms of the GNU GPL version 2
  8. #
  9. __name__ = 'pythondemo'
  10. __description__ = 'demo Python ikiwiki plugin'
  11. __version__ = '0.1'
  12. __author__ = 'martin f. krafft <madduck@madduck.net>'
  13. __copyright__ = 'Copyright © ' + __author__
  14. __licence__ = 'GPLv2'
  15. from proxy import IkiWikiProcedureProxy
  16. import sys
  17. def debug(s):
  18. sys.stderr.write(__name__ + ':DEBUG:%s\n' % s)
  19. sys.stderr.flush()
  20. proxy = IkiWikiProcedureProxy(__name__, debug_fn=None)
  21. def _arglist_to_dict(args):
  22. if len(args) % 2 != 0:
  23. raise ValueError, 'odd number of arguments, cannot convert to dict'
  24. return dict([args[i:i+2] for i in xrange(0, len(args), 2)])
  25. def getopt_demo(proxy, *args):
  26. # This allows for plugins to perform their own processing of command-line
  27. # options and so add options to the ikiwiki command line. It's called
  28. # during command line processing, with @ARGV full of any options that
  29. # ikiwiki was not able to process on its own. The function should process
  30. # any options it can, removing them from @ARGV, and probably recording the
  31. # configuration settings in %config. It should take care not to abort if
  32. # it sees an option it cannot process, and should just skip over those
  33. # options and leave them in @ARGV.
  34. #
  35. debug("hook `getopt' called with arguments %s" % str(args))
  36. args = proxy.getargv()
  37. if '--demo' in args:
  38. args = [i for i in args if i != '--demo']
  39. proxy.setargv(args)
  40. proxy.hook('getopt', getopt_demo)
  41. def checkconfig_demo(proxy, *args):
  42. # This is useful if the plugin needs to check for or modify ikiwiki's
  43. # configuration. It's called early in the startup process. The function is
  44. # passed no values. It's ok for the function to call error() if something
  45. # isn't configured right.
  46. debug("hook `checkconfig' called with arguments %s" % str(args))
  47. # check that --url has been set
  48. url = proxy.getvar('config', 'url')
  49. if url is None or len(url) == 0:
  50. proxy.error('--url has not been set')
  51. proxy.hook('checkconfig', checkconfig_demo)
  52. def refresh_demo(proxy, *args):
  53. # This hook is called just before ikiwiki scans the wiki for changed
  54. # files. It's useful for plugins that need to create or modify a source
  55. # page. The function is passed no values.
  56. debug("hook `refresh' called with arguments %s" % str(args))
  57. proxy.hook('refresh', refresh_demo)
  58. def needsbuild_demo(proxy, *args):
  59. # This allows a plugin to manipulate the list of files that need to be
  60. # built when the wiki is refreshed. The function is passed a reference to
  61. # an array of pages that will be rebuilt, and can modify the array, either
  62. # adding or removing files from it.
  63. # TODO: how do we modify the array? Joey sees no solution...
  64. # we could just return the array and expect ikiwiki to use that...
  65. debug("hook `needsbuild' called with arguments %s" % str(args))
  66. raise NotImplementedError
  67. #proxy.hook('needsbuild', needsbuild_demo)
  68. def filter_demo(proxy, *args):
  69. # Runs on the raw source of a page, before anything else touches it, and
  70. # can make arbitrary changes. The function is passed named parameters
  71. # "page", "destpage", and "content". It should return the filtered
  72. # content.
  73. kwargs = _arglist_to_dict(args)
  74. debug("hook `filter' called with arguments %s" % kwargs);
  75. return kwargs['content']
  76. proxy.hook('filter', filter_demo)
  77. def preprocess_demo(proxy, *args):
  78. # Each time the directive is processed, the referenced function
  79. # (preprocess in the example above) is called, and is passed named
  80. # parameters. A "page" parameter gives the name of the page that embedded
  81. # the preprocessor directive, while a "destpage" parameter gives the name
  82. # of the page the content is going to (different for inlined pages), and
  83. # a "preview" parameter is set to a true value if the page is being
  84. # previewed. All parameters included in the directive are included as
  85. # named parameters as well. Whatever the function returns goes onto the
  86. # page in place of the directive.
  87. #
  88. # An optional "scan" parameter, if set to a true value, makes the hook be
  89. # called during the preliminary scan that ikiwiki makes of updated pages,
  90. # before begining to render pages. This parameter should be set to true if
  91. # the hook modifies data in %links. Note that doing so will make the hook
  92. # be run twice per page build, so avoid doing it for expensive hooks. (As
  93. # an optimisation, if your preprocessor hook is called in a void contets,
  94. # you can assume it's being run in scan mode.)
  95. #
  96. # Note that if the htmlscrubber is enabled, html in PreProcessorDirective
  97. # output is sanitised, which may limit what your plugin can do. Also, the
  98. # rest of the page content is not in html format at preprocessor time.
  99. # Text output by a preprocessor directive will be linkified and passed
  100. # through markdown (or whatever engine is used to htmlize the page) along
  101. # with the rest of the page.
  102. #
  103. kwargs = _arglist_to_dict(args)
  104. debug("hook `preprocess' called with arguments %s" % kwargs)
  105. del kwargs['preview']
  106. del kwargs['page']
  107. del kwargs['destpage']
  108. ret = 'foobar preprocessor called with arguments:'
  109. for i in kwargs.iteritems():
  110. ret += ' %s=%s' % i
  111. return ret
  112. # put [[!foobar ...]] somewhere to try this
  113. proxy.hook('preprocess', preprocess_demo, id='foobar')
  114. def linkify_demo(proxy, *args):
  115. # This hook is called to convert WikiLinks on the page into html links.
  116. # The function is passed named parameters "page", "destpage", and
  117. # "content". It should return the linkified content.
  118. #
  119. # Plugins that implement linkify must also implement a scan hook, that
  120. # scans for the links on the page and adds them to %links.
  121. kwargs = _arglist_to_dict(args)
  122. debug("hook `linkify' called with arguments %s" % kwargs)
  123. return kwargs['content']
  124. proxy.hook('linkify', linkify_demo)
  125. def scan_demo(proxy, *args):
  126. # This hook is called early in the process of building the wiki, and is
  127. # used as a first pass scan of the page, to collect metadata about the
  128. # page. It's mostly used to scan the page for WikiLinks, and add them to
  129. # %links.
  130. #
  131. # The function is passed named parameters "page" and "content". Its return
  132. # value is ignored.
  133. #
  134. kwargs = _arglist_to_dict(args)
  135. debug("hook `scan' called with arguments %s" % kwargs)
  136. links = proxy.getvar('links', kwargs['page'])
  137. debug("links for page `%s' are: %s" % (kwargs['page'], links))
  138. proxy.setvar('links', kwargs['page'], links)
  139. # TODO: this yields "Can't use string ("1") as an ARRAY ref while "strict
  140. # refs" in use at /home/madduck/code/ikiwiki/IkiWiki/Render.pm line 17,
  141. # <GEN1> line 476."
  142. raise NotImplementedError
  143. proxy.hook('scan', scan_demo)
  144. def htmlize_demo(proxy, *args):
  145. # Runs on the raw source of a page and turns it into html. The id
  146. # parameter specifies the filename extension that a file must have to be
  147. # htmlized using this plugin. This is how you can add support for new and
  148. # exciting markup languages to ikiwiki.
  149. #
  150. # The function is passed named parameters: "page" and "content" and should
  151. # return the htmlized content.
  152. kwargs = _arglist_to_dict(args)
  153. debug("hook `htmlize' called with arguments %s" % kwargs)
  154. return kwargs['content']
  155. proxy.hook('htmlize', htmlize_demo)
  156. def pagetemplate_demo(proxy, *args):
  157. # Templates are filled out for many different things in ikiwiki, like
  158. # generating a page, or part of a blog page, or an rss feed, or a cgi.
  159. # This hook allows modifying the variables available on those templates.
  160. # The function is passed named parameters. The "page" and "destpage"
  161. # parameters are the same as for a preprocess hook. The "template"
  162. # parameter is a HTML::Template object that is the template that will be
  163. # used to generate the page. The function can manipulate that template
  164. # object.
  165. #
  166. # The most common thing to do is probably to call $template->param() to
  167. # add a new custom parameter to the template.
  168. # TODO: how do we call $template->param()?
  169. kwargs = _arglist_to_dict(args)
  170. debug("hook `pagetemplate' called with arguments %s" % kwargs)
  171. raise NotImplementedError
  172. #proxy.hook('pagetemplate', pagetemplate_demo)
  173. def templatefile_demo(proxy, *args):
  174. # This hook allows plugins to change the template that is used for a page
  175. # in the wiki. The hook is passed a "page" parameter, and should return
  176. # the name of the template file to use, or undef if it doesn't want to
  177. # change the default ("page.tmpl"). Template files are looked for in
  178. # /usr/share/ikiwiki/templates by default.
  179. #
  180. kwargs = _arglist_to_dict(args)
  181. debug("hook `templatefile' called with arguments %s" % kwargs)
  182. return None #leave the default
  183. proxy.hook('templatefile', templatefile_demo)
  184. def sanitize_demo(proxy, *args):
  185. # Use this to implement html sanitization or anything else that needs to
  186. # modify the body of a page after it has been fully converted to html.
  187. #
  188. # The function is passed named parameters: "page" and "content", and
  189. # should return the sanitized content.
  190. kwargs = _arglist_to_dict(args)
  191. debug("hook `sanitize' called with arguments %s" % kwargs)
  192. return kwargs['content']
  193. proxy.hook('sanitize', sanitize_demo)
  194. def format_demo(proxy, *args):
  195. # The difference between format and sanitize is that sanitize only acts on
  196. # the page body, while format can modify the entire html page including
  197. # the header and footer inserted by ikiwiki, the html document type, etc.
  198. #
  199. # The function is passed named parameters: "page" and "content", and
  200. # should return the formatted content.
  201. kwargs = _arglist_to_dict(args)
  202. debug("hook `format' called with arguments %s" % kwargs)
  203. return kwargs['content']
  204. proxy.hook('format', format_demo)
  205. def delete_demo(proxy, *args):
  206. # Each time a page or pages is removed from the wiki, the referenced
  207. # function is called, and passed the names of the source files that were
  208. # removed.
  209. debug("hook `delete' called with arguments %s" % str(args))
  210. proxy.hook('delete', delete_demo)
  211. def change_demo(proxy, *args):
  212. # Each time ikiwiki renders a change or addition (but not deletion) to the
  213. # wiki, the referenced function is called, and passed the names of the
  214. # source files that were rendered.
  215. debug("hook `change' called with arguments %s" % str(args))
  216. proxy.hook('change', change_demo)
  217. def cgi_demo(proxy, *args):
  218. # Use this to hook into ikiwiki's cgi script. Each registered cgi hook is
  219. # called in turn, and passed a CGI object. The hook should examine the
  220. # parameters, and if it will handle this CGI request, output a page
  221. # (including the http headers) and terminate the program.
  222. #
  223. # Note that cgi hooks are called as early as possible, before any ikiwiki
  224. # state is loaded, and with no session information.
  225. debug("hook `cgi' called with arguments %s" % str(args))
  226. raise NotImplementedError
  227. #proxy.hook('cgi', cgi_demo)
  228. def auth_demo(proxy, *args):
  229. # This hook can be used to implement a different authentication method
  230. # than the standard web form. When a user needs to be authenticated, each
  231. # registered auth hook is called in turn, and passed a CGI object and
  232. # a session object.
  233. #
  234. # If the hook is able to authenticate the user, it should set the session
  235. # object's "name" parameter to the authenticated user's name. Note that if
  236. # the name is set to the name of a user who is not registered, a basic
  237. # registration of the user will be automatically performed.
  238. #
  239. # TODO: how do we set the session parameter?
  240. debug("hook `auth' called with arguments %s" % str(args))
  241. raise NotImplementedError
  242. #proxy.hook('auth', auth_demo)
  243. def sessioncgi_demo(proxy, *args):
  244. # Unlike the cgi hook, which is run as soon as possible, the sessioncgi
  245. # hook is only run once a session object is available. It is passed both
  246. # a CGI object and a session object. To check if the user is in fact
  247. # signed in, you can check if the session object has a "name" parameter
  248. # set.
  249. debug("hook `sessioncgi' called with arguments %s" % str(args))
  250. raise NotImplementedError
  251. #proxy.hook('sessioncgi', sessioncgi_demo)
  252. def canedit_demo(proxy, *args):
  253. # This hook can be used to implement arbitrary access methods to control
  254. # when a page can be edited using the web interface (commits from revision
  255. # control bypass it). When a page is edited, each registered canedit hook
  256. # is called in turn, and passed the page name, a CGI object, and a session
  257. # object.
  258. #
  259. # If the hook has no opinion about whether the edit can proceed, return
  260. # undef, and the next plugin will be asked to decide. If edit can proceed,
  261. # the hook should return "". If the edit is not allowed by this hook, the
  262. # hook should return an error message for the user to see, or a function
  263. # that can be run to log the user in or perform other action necessary for
  264. # them to be able to edit the page.
  265. #
  266. # This hook should avoid directly redirecting the user to a signin page,
  267. # since it's sometimes used to test to see which pages in a set of pages
  268. # a user can edit.
  269. #
  270. # TODO: how do we return a function?
  271. debug("hook `canedit' called with arguments %s" % str(args))
  272. raise NotImplementedError
  273. #proxy.hook('canedit', canedit_demo)
  274. def editcontent_demo(proxy, *args):
  275. # This hook is called when a page is saved (or previewed) using the web
  276. # interface. It is passed named parameters: content, page, cgi, and
  277. # session. These are, respectively, the new page content as entered by the
  278. # user, the page name, a CGI object, and the user's CGI::Session.
  279. #
  280. # It can modify the content as desired, and should return the content.
  281. kwargs = _arglist_to_dict(args)
  282. debug("hook `editcontent' called with arguments %s" % kwargs)
  283. return kwargs['content']
  284. proxy.hook('editcontent', editcontent_demo)
  285. def formbuilder_setup_demo(proxy, *args):
  286. # These hooks allow tapping into the parts of ikiwiki that use
  287. # CGI::FormBuilder to generate web forms. These hooks are passed named
  288. # parameters: cgi, session, form, and buttons. These are, respectively,
  289. # the CGI object, the user's CGI::Session, a CGI::FormBuilder, and
  290. # a reference to an array of names of buttons to go on the form.
  291. #
  292. # Each time a form is set up, the formbuilder_setup hook is called.
  293. # Typically the formbuilder_setup hook will check the form's title, and if
  294. # it's a form that it needs to modify, will call various methods to
  295. # add/remove/change fields, tweak the validation code for the fields, etc.
  296. # It will not validate or display the form.
  297. #
  298. # Just before a form is displayed to the user, the formbuilder hook is
  299. # called. It can be used to validate the form, but should not display it.
  300. #
  301. # TODO: how do we modify the form?
  302. kwargs = _arglist_to_dict(args)
  303. debug("hook `formbuilder_setup' called with arguments %s" % kwargs)
  304. raise NotImplementedError
  305. return kwargs['content']
  306. #proxy.hook('formbuilder_setup', formbuilder_setup_demo)
  307. def formbuilder_demo(proxy, *args):
  308. # These hooks allow tapping into the parts of ikiwiki that use
  309. # CGI::FormBuilder to generate web forms. These hooks are passed named
  310. # parameters: cgi, session, form, and buttons. These are, respectively,
  311. # the CGI object, the user's CGI::Session, a CGI::FormBuilder, and
  312. # a reference to an array of names of buttons to go on the form.
  313. #
  314. # Each time a form is set up, the formbuilder_setup hook is called.
  315. # Typically the formbuilder_setup hook will check the form's title, and if
  316. # it's a form that it needs to modify, will call various methods to
  317. # add/remove/change fields, tweak the validation code for the fields, etc.
  318. # It will not validate or display the form.
  319. #
  320. # Just before a form is displayed to the user, the formbuilder hook is
  321. # called. It can be used to validate the form, but should not display it.
  322. # TODO: how do we modify the form?
  323. kwargs = _arglist_to_dict(args)
  324. debug("hook `formbuilder' called with arguments %s" % kwargs)
  325. raise NotImplementedError
  326. return kwargs['content']
  327. #proxy.hook('formbuilder', formbuilder_demo)
  328. def savestate_demo(proxy, *args):
  329. # This hook is called wheneven ikiwiki normally saves its state, just
  330. # before the state is saved. The function can save other state, modify
  331. # values before they're saved, etc.
  332. #
  333. # TODO: how?
  334. debug("hook `savestate' called with arguments %s" % str(args))
  335. raise NotImplementedError
  336. #proxy.hook('savestate', savestate_demo)
  337. proxy.run()