Revision: 7716
Author:   siebrand
Date:     2009-11-30 11:44:07 +0000 (Mon, 30 Nov 2009)

Log Message:
-----------
[ #2895284 ] Port of the User() class. Contributed by stanlekub. Superfluous 
whitespace removed by siebrand. Untested.

Comments from patch submit:
[..] this creates a class User(), which is a subclass of Page, with additional 
methods.

The patch adds:
* the class User() in page.py
* 2 new exceptions in exceptions.py
* an import statement for User() in __init__.py
* a minimal usrlib.py file is also provided for backwards-compatibility, in the 
same manner it was done for catlib.

This implementation should be fully compatible with the "old" one... with all 
of its defaults included. There is for example a strange discrepancy between 
the format of timestamps as returned by .contributions() and .loadedImages().

The methods .block() and .unblock() aren't implemented yet, and the 'autoblock' 
thingy should probably be tweeked a little more.

Comments on this are really welcomed [..]

Modified Paths:
--------------
    branches/rewrite/pywikibot/__init__.py
    branches/rewrite/pywikibot/exceptions.py
    branches/rewrite/pywikibot/page.py

Added Paths:
-----------
    branches/rewrite/pywikibot/userlib.py

Modified: branches/rewrite/pywikibot/__init__.py
===================================================================
--- branches/rewrite/pywikibot/__init__.py      2009-11-30 11:36:45 UTC (rev 
7715)
+++ branches/rewrite/pywikibot/__init__.py      2009-11-30 11:44:07 UTC (rev 
7716)
@@ -140,7 +140,7 @@
 
     """
     logger = logging.getLogger("pywiki.wiki")
-    
+
     if code is None:
         code = config.mylang
     if fam is None:
@@ -172,7 +172,7 @@
 getSite = Site # alias for backwards-compability
 
 
-from page import Page, ImagePage, Category, Link
+from page import Page, ImagePage, Category, Link, User
 
 
 link_regex = re.compile(r'\[\[(?P<title>[^\]|[#<>{}]*)(\|.*?)?\]\]')
@@ -209,7 +209,7 @@
     Output a string showing the differences between oldtext and newtext.
     The differences are highlighted (only on compatible systems) to show which
     changes were made.
-    
+
     """
     # This is probably not portable to non-terminal interfaces....
     # For information on difflib, see http://pydoc.org/2.3/difflib.html

Modified: branches/rewrite/pywikibot/exceptions.py
===================================================================
--- branches/rewrite/pywikibot/exceptions.py    2009-11-30 11:36:45 UTC (rev 
7715)
+++ branches/rewrite/pywikibot/exceptions.py    2009-11-30 11:44:07 UTC (rev 
7716)
@@ -29,7 +29,7 @@
         return self.unicode
 
 class PageRelatedError(Error):
-    """Abstract Exception, used when the Exception concerns a particular 
+    """Abstract Exception, used when the Exception concerns a particular
     Page, and when a generic message can be written once for all"""
     # Preformated UNICODE message where the page title will be inserted
     # Override this in subclasses.
@@ -68,7 +68,7 @@
 
 class CircularRedirect(Error):
     """Page is a circular redirect
- 
+
     Exception argument is the redirect target; this may be the same title
     as this page or a different title (in which case the target page directly
     or indirectly redirects back to this one)
@@ -119,3 +119,11 @@
 class UploadWarning(Error):
     """Upload failed with a warning message (passed as the argument)."""
 
+class AutoblockUser(Error):
+    """
+    The class AutoblockUserError is an exception that is raised whenever
+    an action is requested on a virtual autoblock user that's not available
+    for him (i.e. roughly everything except unblock).
+    """
+class UserActionRefuse(Error):
+    pass

Modified: branches/rewrite/pywikibot/page.py
===================================================================
--- branches/rewrite/pywikibot/page.py  2009-11-30 11:36:45 UTC (rev 7715)
+++ branches/rewrite/pywikibot/page.py  2009-11-30 11:44:07 UTC (rev 7716)
@@ -1753,6 +1753,243 @@
         return sorted(list(set(self.categories())))
 
 
+class User(Page):
+    """A class that represents a Wiki user.
+    """
+
+    @deprecate_arg("insite", None)
+    def __init__(self, source, title=u''):
+        """All parameters are the same as for Page() constructor.
+        """
+        if len(title) > 1 and title[0] == u'#':
+            self.is_autoblock = True
+            title = title[1:]
+        else:
+            self.is_autoblock = False
+        Page.__init__(self, source, title, ns=2)
+        if self.namespace() != 2:
+            raise ValueError(u"'%s' is not in the user namespace!"
+                             % title)
+        if self.is_autoblock:
+            # This user is probably being queried for purpose of lifting
+            # an autoblock.
+            pywikibot.output("This is an autoblock ID, "
+                            "you can only use to unblock it.")
+
+    @property
+    def username(self):
+        """ Convenience method that returns the title of the page with
+        namespace prefix omitted, aka the username, as a Unicode string.
+        """
+        if self.is_autoblock:
+            return u'#' + self.title(withNamespace=False)
+        else:
+            return self.title(withNamespace=False)
+
+    def getprops(self, force=False):
+        """ Return a Dictionnary that contains user's properties. Use cached
+        values if already called before, otherwise fetch data from the API.
+
+        @param force: if True, forces reloading the data from API
+        @type force: bool
+        """
+        if force:
+            del self._userprops
+        if not hasattr(self, '_userprops'):
+            usrequest = pywikibot.data.api.Request(
+                            site=self.site(),
+                            action='query',
+                            list='users',
+                            
usprop='blockinfo|groups|editcount|registration|emailable',
+                            ususers=self.username,
+                            )
+            usdata = usrequest.submit()
+            assert 'query' in usdata, \
+                   "API users response lacks 'query' key"
+            assert 'users' in usdata['query'], \
+                   "API users response lacks 'users' key"
+            if u'missing' in usdata['query']['users'][0] or \
+                                    u'invalid' in usdata['query']['users'][0]:
+                raise pywikibot.Error(u'No such user or invaild username (%s)'\
+                                                            % self.username)
+            self._userprops = usdata['query']['users'][0]
+        return self._userprops
+
+    def registrationTime(self, force=False):
+        """ Return registration time for this user, as a Unicode string in
+        ISO8601 format, or None if the date is unknown.
+
+        @param force: if True, forces reloading the data from API
+        @type force: bool
+        """
+        if 'registration' in self.getprops(force):
+            return self.getprops()['registration']
+
+    def editCount(self, force=False):
+        """ Return edit count for this user as int.
+
+        @param force: if True, forces reloading the data from API
+        @type force: bool
+        """
+        if 'editcount' in self.getprops(force):
+            return self.getprops()['editcount']
+        else:
+            return 0
+
+    def isBlocked(self, force=False):
+        """ Return True if this user is currently blocked, False otherwise.
+
+        @param force: if True, forces reloading the data from API
+        @type force: bool
+        """
+        return 'blockedby' in self.getprops(force)
+
+    def isEmailable(self, force=False):
+        """ Return True if emails can be send to this user through mediawiki,
+        False otherwise.
+
+        @param force: if True, forces reloading the data from API
+        @type force: bool
+        """
+        return 'emailable' in self.getprops(force)
+
+    def groups(self, force=False):
+        """ Return a list of groups to wich this user belongs. The return value
+        is guaranteed to be a list object, possibly empty.
+
+        @param force: if True, forces reloading the data from API
+        @type force: bool
+        """
+        if 'groups' in self.getprops(force):
+            return self.getprops()['groups']
+        else:
+            return []
+
+    def getUserPage(self, subpage=u''):
+        """ Return a pywikibot.Page object corresponding to this user's main
+        page, or a subpage of it if subpage is set.
+
+        @param subpage: subpage part to be appended to the main
+                            page title (optional)
+        @type subpage: unicode
+        """
+        if self.is_autoblock:
+            #This user is probably being queried for purpose of lifting
+            #an autoblock, so has no user pages per se.
+            raise AutoblockUser("This is an autoblock ID, you can only use to 
unblock it.")
+        if subpage:
+            subpage = u'/' + subpage
+        return Page(Link(self.title() + subpage, self.site()))
+
+    def getUserTalkPage(self, subpage=u''):
+        """ Return a pywikibot.Page object corresponding to this user's main
+        talk page, or a subpage of it if subpage is set.
+
+        @param subpage: subpage part to be appended to the main
+                            talk page title (optional)
+        @type subpage: unicode
+        """
+        if self.is_autoblock:
+            #This user is probably being queried for purpose of lifting
+            #an autoblock, so has no user talk pages per se.
+            raise AutoblockUser("This is an autoblock ID, you can only use to 
unblock it.")
+        if subpage:
+            subpage = u'/' + subpage
+        return Page(Link(self.title(withNamespace=False) + subpage,
+                                            self.site(), defaultNamespace=3))
+
+    def sendMail(self, subject, text, ccme = False):
+        """ Send an email to this user via mediawiki's email interface.
+        Return True on success, False otherwise.
+        This method can raise an UserActionRefuse exception in case this user
+        doesn't allow sending email to him or the currently logged in bot
+        doesn't have the right to send emails.
+
+        @param subject: the subject header of the mail
+        @type subject: unicode
+        @param text: mail body
+        @type text: unicode
+        @param ccme: if True, sends a copy of this email to the bot
+        @type ccme: bool
+        """
+        if not self.isEmailable():
+            raise UserActionRefuse('This user is not mailable')
+
+        if not self.site().has_right('sendemail'):
+            raise UserActionRefuse('You don\'t have permission to send mail')
+
+        params = {
+            'action': 'emailuser',
+            'target': self.username,
+            'token': self.site().token(self, 'email'),
+            'subject': subject,
+            'text': text,
+        }
+        if ccme:
+            params['ccme'] = 1
+        mailrequest = pywikibot.data.api.Request(**params)
+        maildata = mailrequest.submit()
+
+        if 'error' in maildata:
+            code = maildata['error']['code']
+            if code == u'usermaildisabled ':
+                pywikibot.output(u'User mail has been disabled')
+        elif 'emailuser' in maildata:
+            if maildata['emailuser']['result'] == u'Success':
+                pywikibot.output(u'Email sent.')
+                return True
+        return False
+
+    @deprecated("contributions")
+    @deprecate_arg("limit", "total") # To be consistent with rest of framework
+    def editedPages(self, total=500):
+        """ Deprecated function that wraps 'contributions' for backwards
+        compatibility. Yields pywikibot.Page objects that this user has
+        edited, with an upper bound of 'total'. Pages returned are not
+        guaranteed to be unique.
+
+        @param total: limit result to this number of pages.
+        @type total: int.
+        """
+        for item in self.contributions(total=total):
+            yield item[0]
+
+    @deprecate_arg("limit", "total") # To be consistent with rest of framework
+    @deprecate_arg("namespace", "namespaces")
+    def contributions(self, total=500, namespaces=[]):
+        """ Yield tuples describing this user edits.
+        Each tuple is composed of a pywikibot.Page object,
+        the revision id (int), the edit timestamp (as int in mediawiki's
+        internal format), and the comment (unicode).
+        Pages returned are not guaranteed to be unique.
+
+        @param total: limit result to this number of pages
+        @type total: int
+        @param namespaces: only iterate links in these namespaces
+        @type namespaces: list
+        """
+        for contrib in self.site().usercontribs(user=self.username,
+                                        namespaces=namespaces, total=total):
+            ts = pywikibot.Timestamp.fromISOformat(contrib['timestamp'])
+            ts = int(ts.strftime("%Y%m%d%H%M%S"))
+            yield Page(Link(contrib['title'], self.site(),
+                            defaultNamespace=contrib['ns'])), \
+                  contrib['revid'], ts, contrib['comment']
+
+    @deprecate_arg("number", "total")
+    def uploadedImages(self, total=10):
+        """ Yield tuples describing files uploaded by this user.
+        Each tuple is composed of a pywikibot.Page, the timestamp (str in
+        ISO8601 format), comment (unicode) and a bool (always False...).
+        Pages returned are not guaranteed to be unique.
+
+        @param total: limit result to this number of pages
+        @type total: int
+        """
+        for item in self.site().logevents(logtype='upload', user=self.username,
+                                                                total=total):
+            yield item.title(), str(item.timestamp()), item.comment(), False
+
 class Revision(object):
     """A structure holding information about a single revision of a Page."""
     def __init__(self, revid, timestamp, user, anon=False, comment=u"",
@@ -2261,4 +2498,3 @@
             pass
     # Couldn't convert, raise the original exception
     raise firstException
-

Added: branches/rewrite/pywikibot/userlib.py
===================================================================
--- branches/rewrite/pywikibot/userlib.py                               (rev 0)
+++ branches/rewrite/pywikibot/userlib.py       2009-11-30 11:44:07 UTC (rev 
7716)
@@ -0,0 +1,17 @@
+# -*- coding: utf-8  -*-
+"""
+WARNING: THIS MODULE EXISTS SOLELY TO PROVIDE BACKWARDS-COMPATIBILITY.
+
+Do not use in new scripts; use the source to find the appropriate
+function/method instead.
+
+"""
+#
+# (C) Pywikipedia bot team, 2008
+#
+# Distributed under the terms of the MIT license.
+#
+__version__ = '$Id$'
+
+
+from pywikibot import User


Property changes on: branches/rewrite/pywikibot/userlib.py
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:eol-style
   + native



_______________________________________________
Pywikipedia-svn mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/pywikipedia-svn

Reply via email to