Virtual Pages

A virtual page is a wiki page which gets its content from a script instead of reading it from a file

diff <Page.py from MoinMoin 1.3.2> <Page.py with virtual pages>

--- /home/nick/moin-1.3.2/MoinMoin/Page.py      2005-01-22 08:37:23.000000000 -0600
+++ Page.py     2005-02-18 15:57:10.000000000 -0600
@@ -65,6 +65,14 @@

         self.reset()

+        if self.__class__ == Page:
+            result = virtualPageLookup(request, self.page_name)
+            if result:
+                self.__class__ = VirtualPage
+                self.generator = result[0]
+                self.match_object = result[1]
+                self.data = None
+
     def reset(self):
         """ Reset page state """
         page_name = self.page_name
@@ -1575,3 +1583,127 @@
         return text


+class VirtualPage(Page):
+    def get_current_from_pagedir(self, pagedir):
+        return 0
+
+    def get_rev_dir(self, pagedir, rev=0):
+        if rev == 0:
+            exists = True
+        else:
+            exists = False
+        return "", rev, exists
+
+    def get_rev(self, use_underlay=-1, rev=0):
+        if rev == 0:
+            exists = True
+        else:
+            exists = False
+
+        return "", rev, exists
+
+    def current_rev(self):
+        return 0
+
+    def get_real_rev(self):
+        return 0
+
+    def getPageBasePath(self, use_underlay):
+        return ""
+
+    def getPageStatus(self, *args, **kw):
+        return "",""
+
+    def getPagePath(self, *args, **kw):
+        return ""
+
+    def _text_filename(self, **kw):
+        return ""
+
+    def _tmp_filename(self):
+        return ""
+
+    def _last_edited(self, request):
+        return None
+
+    def last_edit(self, request):
+        return {'timestamp' : 0, 'editor' : '?'}
+
+    def lastEditInfo(self, request=None):
+        return {'editor' : None, 'time' : 0}
+
+    def isUnderlayPage(self, includeDeleted=True):
+        return False
+
+    def isStandardPage(self, includeDeleted=True):
+        return False
+
+    def exists(self, rev=0, domain=None, includeDeleted=False):
+        return True
+
+    def size(self):
+        if not self.data:
+            self.get_raw_body()
+        return len(self.data)
+
+    def mtime_usecs(self):
+        return 0
+
+    def mtime_printable(self):
+        return "Beginning of time"
+
+    def getPageList(self, user=None, rootpagename=None):
+        return []
+
+    def getPageDict(self, user=None, rootpagename=None):
+        return {}
+
+    def get_raw_body(self):
+        if not self.data:
+            self.data = self.generator(self.page_name, self.match_object)
+        return self.data
+
+    def set_raw_body(self, body, modified=0):
+        self.data = body
+
+    def getSubscribers(self, request, **kw):
+        return []
+
+    def getRevList(self):
+        return [0]
+
+    def olderrevision(self, rev=0):
+        return 0
+
+    def isWritable(self):
+        return False
+
+
+
+
+
+virtual_pages = []
+
+def findVirtualPagePlugins(cfg):
+    from wikiutil import getPlugins, importPlugin
+    plugins = getPlugins("virtual", cfg)
+
+    for vp in plugins:
+        regex = importPlugin(cfg, "virtual", vp, function="regex")
+        filter = importPlugin(cfg, "virtual", vp, function="filter")
+        generator = importPlugin(cfg, "virtual", vp)
+        if regex != None and filter != None and generator != None:
+            virtual_pages.append((re.compile(regex), filter, generator))
+
+def virtualPageLookup(request, page_name):
+    if  virtual_pages == []:
+        findVirtualPagePlugins(request.cfg)
+
+    for (regex, filter, generator) in virtual_pages:
+        mo = regex.match(page_name)
+        if mo:
+            if filter(page_name, mo):
+                return (generator, mo)
+
+    return None
+

I guess that not all functions of VirtualPage are needed. Furthermore I'm not sure if all of them are defined correctly.

To have virtual pages you need a directory plugin/virtual. A plugin in this directory must have three things

The page's name is matched against the regex. If it matches the plugin is considered to be responsible for this page. So regex defines a namespace for wiki pages. To be able to exclude specific pages from this namespace without having to define a complex regex, the function filter is called if the regex matches. The function filter gets the pagename and returns a bool. If filter returns false the next virtual page plugin is checked for responsibility. If none matches the page is considered to be a normal wiki page. As soon as the VirtualPage is supposed to read its contents from the disk the execute fuction is called instead.

-- AlexanderBernauer alex at copton net

Couple of other things that are important to know: In your plugins/virtual directory, you need an __init__.py with a couple lines of code -- just steal the __init__.py from the macros or actions directories. Your execute function needs to take two arguments: the page's name, and a regex match object (I believe this is the result of matching your regex string). execute should return a string with the contents of the page. Also, this patch doesn't pass the request to your execute(), which kind of sucks. A quick fix is to change this line in Page.py:

 self.data = self.generator(self.page_name, self.match_object)

to:

 self.data = self.generator(self.request, self, self.match_object)

And make your execute function now take the arguments: (request, page, match). You can still access page_name through page.page_name. Another issue: although virtual pages are immutable and don't have an edit link, you can still tack on ?action=edit to the URL and be allowed to edit them (it'll just save it as a normal page). Basically VirtualPage and PageEditor are ignorant of each other and PageEditor doesn't know when a page is a virtual page, so it still lets you edit/rename/delete them. -- NickWelch

See also:

MoinMoin: MoinMoinPatch/VirtualPages (last edited 2007-10-29 19:08:12 by localhost)