apply original patches from MoinMoinBugs/GetSubscribersSlow (as is)
authorThomas Waldmann <tw AT waldmann-edv DOT de>
Tue, 11 Feb 2014 14:08:06 +0100
changeset 602154dc774ff49b
parent 6020 b59cef3f6e09
child 6022 fa5f81a0dfa9
apply original patches from MoinMoinBugs/GetSubscribersSlow (as is)

thanks to everybody who contributed to it!
MoinMoin/Page.py
MoinMoin/user.py
     1.1 --- a/MoinMoin/Page.py	Mon Feb 03 17:14:05 2014 +0100
     1.2 +++ b/MoinMoin/Page.py	Tue Feb 11 14:08:06 2014 +0100
     1.3 @@ -811,7 +811,7 @@
     1.4  
     1.5          return link
     1.6  
     1.7 -    def getSubscribers(self, request, **kw):
     1.8 +    def getSubscribersUncached(self, request, **kw):  # original function renamed
     1.9          """ Get all subscribers of this page.
    1.10  
    1.11          @param request: the request object
    1.12 @@ -834,6 +834,8 @@
    1.13          else:
    1.14              from MoinMoin.security import Default as UserPerms
    1.15  
    1.16 +        request.clock.start("getSubscribersUncached")
    1.17 +
    1.18          # get email addresses of the all wiki user which have a profile stored;
    1.19          # add the address only if the user has subscribed to the page and
    1.20          # the user is not the current editor
    1.21 @@ -872,6 +874,113 @@
    1.22              else:
    1.23                  subscriber_list[lang].append(subscriber.email)
    1.24  
    1.25 +        request.clock.stop("getSubscribersUncached")
    1.26 +
    1.27 +        return subscriber_list
    1.28 +
    1.29 +    # cached version of getSubscribers
    1.30 +    def getSubscribers(self, request, **kw):
    1.31 +        """ Get all subscribers of this page.
    1.32 +
    1.33 +        @param request: the request object
    1.34 +        @keyword include_self: if 1, include current user (default: 0)
    1.35 +        @keyword return_users: if 1, return user instances (default: 0)
    1.36 +        @rtype: dict
    1.37 +        @return: lists of subscribed email addresses in a dict by language key
    1.38 +        """
    1.39 +        include_self = kw.get('include_self', self.include_self)
    1.40 +        return_users = kw.get('return_users', 0)
    1.41 +
    1.42 +        request.clock.start('getSubscribersCached')
    1.43 +        # extract categories of this page
    1.44 +        pageList = self.getCategories(request)
    1.45 +
    1.46 +        # add current page name for list matching
    1.47 +        pageList.append(self.page_name)
    1.48 +
    1.49 +        arena = 'user'
    1.50 +        key = 'page_sub'
    1.51 +
    1.52 +        # get or create cache file
    1.53 +        page_sub = {}
    1.54 +        cache = caching.CacheEntry(request, arena, key, scope='wiki', use_pickle=True)
    1.55 +        if cache.exists():
    1.56 +            page_sub = cache.content()
    1.57 +        else:
    1.58 +            #build a cache if it doesn't exist
    1.59 +            cache = caching.CacheEntry(request, arena, key, scope='wiki', use_pickle=True, do_locking=False)
    1.60 +            # lock to stop anybody else interfering with the data while we're working
    1.61 +            cache.lock('w')
    1.62 +            userlist = user.getUserList(request)
    1.63 +            for uid in userlist:
    1.64 +                subscriber = user.User(request, uid)
    1.65 +                # we don't care about storing entries for users without any page subscriptions
    1.66 +                if subscriber.subscribed_pages:
    1.67 +                    page_sub[subscriber.id] = {
    1.68 +                        'name': subscriber.name,
    1.69 +                        'email': subscriber.email,
    1.70 +                        'subscribed_pages': subscriber.subscribed_pages
    1.71 +                    }
    1.72 +            cache.update(page_sub)
    1.73 +            cache.unlock()
    1.74 +            cache.lock('r') # to go back to the same mode as if it had existed all along
    1.75 +
    1.76 +        if self.cfg.SecurityPolicy:
    1.77 +            UserPerms = self.cfg.SecurityPolicy
    1.78 +        else:
    1.79 +            from MoinMoin.security import Default as UserPerms
    1.80 +
    1.81 +        # get email addresses of the all wiki user which have a profile stored;
    1.82 +        # add the address only if the user has subscribed to the page and
    1.83 +        # the user is not the current editor
    1.84 +        userlist = page_sub
    1.85 +        subscriber_list = {}
    1.86 +
    1.87 +        pages = pageList[:]
    1.88 +        if request.cfg.interwikiname:
    1.89 +            pages += ["%s:%s" % (request.cfg.interwikiname, pagename) for pagename in pageList]
    1.90 +        # Create text for regular expression search
    1.91 +        text = '\n'.join(pages)
    1.92 +
    1.93 +        for uid in userlist.keys():
    1.94 +            if uid == request.user.id and not include_self:
    1.95 +                continue # no self notification
    1.96 +
    1.97 +            isSubscribed = False
    1.98 +
    1.99 +            # This is a bit wrong if return_users=1 (which implies that the caller will process
   1.100 +            # user attributes and may, for example choose to send an SMS)
   1.101 +            # So it _should_ be "not (subscriber.email and return_users)" but that breaks at the moment.
   1.102 +            if not userlist[uid]['email']:
   1.103 +                continue # skip empty email addresses
   1.104 +
   1.105 +            # now check patters for actual match
   1.106 +            for pattern in userlist[uid]['subscribed_pages']:
   1.107 +                if pattern in pages:
   1.108 +                    isSubscribed = True
   1.109 +                try:
   1.110 +                    pattern = re.compile(r'^%s$' % pattern, re.M)
   1.111 +                except re.error:
   1.112 +                    continue
   1.113 +                if pattern.search(text):
   1.114 +                    isSubscribed = True
   1.115 +
   1.116 +            # only if subscribed, then read user info from file
   1.117 +            if isSubscribed:
   1.118 +                subscriber = user.User(request, uid)
   1.119 +
   1.120 +                if not UserPerms(subscriber).read(self.page_name):
   1.121 +                    continue
   1.122 +
   1.123 +                lang = subscriber.language or request.cfg.language_default
   1.124 +                if not lang in subscriber_list:
   1.125 +                    subscriber_list[lang] = []
   1.126 +                if return_users:
   1.127 +                    subscriber_list[lang].append(subscriber)
   1.128 +                else:
   1.129 +                    subscriber_list[lang].append(subscriber.email)
   1.130 +
   1.131 +        request.clock.stop('getSubscribersCached')
   1.132          return subscriber_list
   1.133  
   1.134      def parse_processing_instructions(self):
     2.1 --- a/MoinMoin/user.py	Mon Feb 03 17:14:05 2014 +0100
     2.2 +++ b/MoinMoin/user.py	Tue Feb 11 14:08:06 2014 +0100
     2.3 @@ -708,6 +708,9 @@
     2.4              event = events.UserCreatedEvent(self._request, self)
     2.5              events.send_event(event)
     2.6  
     2.7 +        # update page subscriber's cache after saving user preferences
     2.8 +        self.updatePageSubCache()
     2.9 +
    2.10      # -----------------------------------------------------------------
    2.11      # Time and date formatting
    2.12  
    2.13 @@ -895,6 +898,36 @@
    2.14              self.save()
    2.15          return not self.isSubscribedTo([pagename])
    2.16  
    2.17 +    # update page subscribers cache
    2.18 +    def updatePageSubCache(self):
    2.19 +        """ When a user changes his preferences, we update the
    2.20 +        page subscriber's cache
    2.21 +        """
    2.22 +
    2.23 +        arena = 'user'
    2.24 +        key = 'page_sub'
    2.25 +
    2.26 +        page_sub = {}
    2.27 +        cache = caching.CacheEntry(self._request, arena, key, scope='wiki', use_pickle=True, do_locking=False)
    2.28 +        if not cache.exists():
    2.29 +            return  # if no cache file, just don't do anything
    2.30 +
    2.31 +        cache.lock('w')
    2.32 +        page_sub = cache.content()
    2.33 +
    2.34 +        # we don't care about storing entries for users without any page subscriptions
    2.35 +        if self.subscribed_pages:
    2.36 +            page_sub[self.id] = {
    2.37 +                'name': self.name,
    2.38 +                'email': self.email,
    2.39 +                'subscribed_pages': self.subscribed_pages
    2.40 +            }
    2.41 +        elif page_sub.get(self.id):
    2.42 +            del page_sub[self.id]
    2.43 +
    2.44 +        cache.update(page_sub)
    2.45 +        cache.unlock()
    2.46 +
    2.47      # -----------------------------------------------------------------
    2.48      # Quicklinks
    2.49