Attachment 'subscriber_cache.py'

Download

   1 #!/usr/bin/env python
   2 # -*- coding: utf-8 -*-
   3 
   4 """
   5 This is not a real plugin, but a hack to patch up MoinMoin's page subscriber
   6 list to be cached.
   7 
   8 This is based on http://moinmo.in/MoinMoinBugs/GetSubscribersSlow
   9 """
  10 
  11 
  12 import re
  13 
  14 from MoinMoin import caching, user, Page
  15 
  16 
  17 def getSubscribersCached(self, request, **kw):
  18     """Get all subscribers of this page. Cached version.
  19 
  20     @param request: the request object
  21     @keyword include_self: if 1, include current user (default: 0)
  22     @keyword return_users: if 1, return user instances (default: 0)
  23     @rtype: dict
  24     @return: lists of subscribed email addresses in a dict by language key
  25     """
  26     include_self = kw.get('include_self', self.include_self)
  27     return_users = kw.get('return_users', 0)
  28 
  29     request.clock.start('getSubscribersCached')
  30     # extract categories of this page
  31     pageList = self.getCategories(request)
  32 
  33     # add current page name for list matching
  34     pageList.append(self.page_name)
  35 
  36     arena = 'user'
  37     key = 'page_sub'
  38 
  39     # get or create cache file
  40     page_sub = {}
  41     cache = caching.CacheEntry(request, arena, key, scope='wiki',
  42                                use_pickle=True)
  43     if cache.exists():
  44         page_sub = cache.content()
  45     else:
  46         #build a cache if it doesn't exist
  47         cache = caching.CacheEntry(request, arena, key, scope='wiki',
  48                                    use_pickle=True, do_locking=False)
  49         # lock to stop anybody else interfering with the data while we're
  50         # working
  51         cache.lock('w')
  52         userlist = user.getUserList(request)
  53         for uid in userlist:
  54             subscriber = user.User(request, uid)
  55             # we don't care about storing entries for users without any page
  56             # subscriptions
  57             if subscriber.subscribed_pages:
  58                 page_sub[subscriber.id] = {
  59                     'name': subscriber.name,
  60                     'email': subscriber.email,
  61                     'subscribed_pages': subscriber.subscribed_pages
  62                 }
  63         cache.update(page_sub)
  64         cache.unlock()
  65         # to go back to the same mode as if it had existed all along
  66         cache.lock('r')
  67 
  68     if self.cfg.SecurityPolicy:
  69         UserPerms = self.cfg.SecurityPolicy
  70     else:
  71         from MoinMoin.security import Default as UserPerms
  72 
  73     # get email addresses of the all wiki user which have a profile stored;
  74     # add the address only if the user has subscribed to the page and
  75     # the user is not the current editor
  76     userlist = page_sub
  77     subscriber_list = {}
  78 
  79     pages = pageList[:]
  80     if request.cfg.interwikiname:
  81         pages += ["%s:%s" % (request.cfg.interwikiname, pagename) for pagename in pageList]
  82     # Create text for regular expression search
  83     text = '\n'.join(pages)
  84 
  85     for uid in userlist.keys():
  86         if uid == request.user.id and not include_self:
  87             continue # no self notification
  88 
  89         isSubscribed = False
  90 
  91         # This is a bit wrong if return_users=1 (which implies that the caller
  92         # will process
  93         # user attributes and may, for example choose to send an SMS)
  94         # So it _should_ be "not (subscriber.email and return_users)" but that
  95         # breaks at the moment.
  96         if not userlist[uid]['email']:
  97             continue # skip empty email addresses
  98 
  99         # now check patters for actual match
 100         for pattern in userlist[uid]['subscribed_pages']:
 101             if pattern in pages:
 102                 isSubscribed = True
 103             try:
 104                 pattern = re.compile(r'^%s$' % pattern, re.M)
 105             except re.error:
 106                 continue
 107             if pattern.search(text):
 108                 isSubscribed = True
 109 
 110         # only if subscribed, then read user info from file
 111         if isSubscribed:
 112             subscriber = user.User(request, uid)
 113 
 114             if not UserPerms(subscriber).read(self.page_name):
 115                 continue
 116 
 117             lang = subscriber.language or request.cfg.language_default
 118             if not lang in subscriber_list:
 119                 subscriber_list[lang] = []
 120             if return_users:
 121                 subscriber_list[lang].append(subscriber)
 122             else:
 123                 subscriber_list[lang].append(subscriber.email)
 124 
 125     request.clock.stop('getSubscribersCached')
 126     return subscriber_list
 127 
 128 
 129 def updatePageSubCache(self):
 130     """
 131     When a user changes his preferences, we update the page subscriber's cache
 132     """
 133 
 134     arena = 'user'
 135     key = 'page_sub'
 136 
 137     page_sub = {}
 138     cache = caching.CacheEntry(self._request, arena, key, scope='wiki',
 139                                use_pickle=True, do_locking=False)
 140     if not cache.exists():
 141         return  # if no cache file, just don't do anything
 142 
 143     cache.lock('w')
 144     page_sub = cache.content()
 145 
 146     # we don't care about storing entries for users without any page
 147     # subscriptions
 148     if self.subscribed_pages:
 149         page_sub[self.id] = {
 150             'name': self.name,
 151             'email': self.email,
 152             'subscribed_pages': self.subscribed_pages
 153         }
 154     elif page_sub.get(self.id):
 155         del page_sub[self.id]
 156 
 157     cache.update(page_sub)
 158     cache.unlock()
 159 
 160 
 161 def do_patch():
 162     """Install our uncanny patches."""
 163 
 164     if getattr(user.User, 'updatePageSubCache', None) is not None:
 165         # The patch is applied already, do nothing
 166         return
 167 
 168     Page.Page.getSubscribers = getSubscribersCached
 169     oldUserSave = user.User.save
 170     def userSave(self, *args, **kwargs):
 171         ret = oldUserSave(self, *args, **kwargs)
 172         self.updatePageSubCache()
 173         return ret
 174     user.User.updatePageSubCache = updatePageSubCache
 175     user.User.save = userSave

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2012-08-08 20:37:50, 5.6 KB) [[attachment:subscriber_cache.py]]
  • [get | view] (2012-04-29 18:24:33, 7.1 KB) [[attachment:subscribercache.patch]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.