diff --git a/mitterlib/network/networkbase.py b/mitterlib/network/networkbase.py
index 091f479..db2f1fd 100644
--- a/mitterlib/network/networkbase.py
+++ b/mitterlib/network/networkbase.py
@@ -105,12 +105,9 @@ class MessageTooLongWarning(NetworkWarning):
# The classes
#--------------------------------------------------------------------
-class NetworkData(object):
- """Provides an uniform way to access information about posts. The
- following fields should appear [*]_ [*]_:
-
- **id**
- The message identification. *Optional*
+class NetworkUser(object):
+ """Provides an uniform way to access information about users. The
+ following fields should appear:
**name**
The name to be displayed as author of the message. *Required*
@@ -120,6 +117,22 @@ class NetworkData(object):
**avatar**
URL to the author avatar. *Optional*
+ """
+ def __init__(self):
+ self.name = ''
+ self.username = ''
+ self.avatar = ''
+
+
+class NetworkData(object):
+ """Provides an uniform way to access information about posts. The
+ following fields should appear [*]_ [*]_:
+
+ **id**
+ The message identification. *Optional*
+
+ **author**
+ Author of the message. A :class:`NetworkUser` object.
**message**
The message. *Required*
@@ -135,16 +148,17 @@ class NetworkData(object):
The parent of this message, in case of a reply. *Optional*
**parent_owner**
- Username of the owner of the parent message (in other words, "in reply
- to".) *Optional*
+ Owner of the parent message (in other words, "in reply to".) It will be
+ a :class:`NetworkUser` object. *Optional*
**reposted_by**
- Username friend of the current user that reposted that message. Some
- networks will return the original user in a separate table (Twitter,
- in this case, returns the original message with the original user
- in a "retweeted_status" structure.) In this case, the network layer
- will must return the original user in *name*, *username* and *avatar*,
- while the friend username will be moved to *reposted_by*. *Optional*
+ Author of the reposted message. A :class:`NetworkUser` object.
+
+ Some networks will return the original
+ user in a separate table (Twitter, in this case, returns the original
+ message with the original user in a "retweeted_status" structure.) In
+ this case, the network layer must return the original user in *author*
+ while the friend will be in *reposted_by*. *Optional*
**network**
The network id source of the message. Network classes don't need to
@@ -162,15 +176,13 @@ class NetworkData(object):
def __init__(self):
self.id = ''
- self.name = ''
- self.username = ''
- self.avatar = ''
+ self.author = None
self.message = ''
self.message_time = None
self.favourite = False
- self.parent = ''
- self.parent_owner = ''
- self.reposted_by = ''
+ self.parent = None
+ self.parent_owner = None
+ self.reposted_by = None
self.network = ''
self.protected = False
diff --git a/mitterlib/network/twitter.py b/mitterlib/network/twitter.py
index 8c9fe95..f0536a5 100644
--- a/mitterlib/network/twitter.py
+++ b/mitterlib/network/twitter.py
@@ -30,7 +30,7 @@ import gettext
from httplib import BadStatusLine
from socket import error as socketError
-from networkbase import NetworkBase, NetworkData, auth_options, \
+from networkbase import NetworkBase, NetworkData, NetworkUser, auth_options, \
NetworkDNSError, NetworkBadStatusLineError, NetworkLowLevelError, \
NetworkInvalidResponseError, NetworkPermissionDeniedError, \
MessageTooLongWarning
@@ -113,6 +113,15 @@ def _make_datetime(response):
return result
+class TwitterNetworkUser(NetworkUser):
+ """A simple wrapper around :class:`NetwokrUser`, to make things easier to
+ convert twitter user information into a NetworkUser object."""
+
+ def __init__(self, data):
+ self.name = data['user']['name']
+ self.username = data['user']['screen_name']
+ self.avatar = data['user']['profile_image_url']
+
class TwitterNetworkData(NetworkData):
"""A simple wrapper around NetworkData, to make things easier to convert
@@ -123,9 +132,7 @@ class TwitterNetworkData(NetworkData):
NetworkData.__init__(self)
self.id = data['id']
- self.name = data['user']['name']
- self.username = data['user']['screen_name']
- self.avatar = data['user']['profile_image_url']
+ self.author = TwitterNetworkUser(data)
self.message_time = _to_datetime(data['created_at'])
if 'protected' in data['user']:
@@ -136,16 +143,14 @@ class TwitterNetworkData(NetworkData):
self.favourited = data['favorited']
if 'in_reply_to_status_id' in data and data['in_reply_to_status_id']:
+ owner = NetworkUser()
+ owner.username = data['in_reply_to_screen_name']
+ # TODO: Check if we have the other data.
self.parent = int(data['in_reply_to_status_id'])
- self.parent_owner = data['in_reply_to_screen_name']
if 'retweeted_status' in data:
- self.reposted_by = self.username
-
- retweet_user = data['retweeted_status']['user']
- self.name = retweet_user['name']
- self.username = retweet_user['screen_name']
- self.avatar = retweet_user['profile_image_url']
+ self.reposted_by = self.author
+ self.author = TwitterNetworkUser(data['retweeted_status'])
self.id = data['retweeted_status']['id']
# also switch the text for the original text.
@@ -393,13 +398,13 @@ class Connection(NetworkBase):
def link(self, message):
"""Return a link directly to the message."""
assert(isinstance(message, NetworkData))
- return 'http://twitter.com/%s/status/%s' % (message.username,
+ return 'http://twitter.com/%s/status/%s' % (message.author.username,
message.id)
def reply_prefix(self, message):
"""Returns the prefix needed for a reply."""
assert(isinstance(message, NetworkData))
- return '@' + message.username + ' '
+ return '@' + message.author.username + ' '
def replies(self):
"""Return a list of NetworkData objects for the replies for the user
@@ -434,8 +439,8 @@ class Connection(NetworkBase):
# start with the username of the original user, we add it
# for the user.
- if not status.startswith('@' + reply_to.username):
- body['status'] = '@' + reply_to.username + ' ' + \
+ if not status.startswith('@' + reply_to.author.username):
+ body['status'] = '@' + reply_to.author.username + ' ' + \
status
else:
body['in_reply_to_status_id'] = reply_to
@@ -486,7 +491,8 @@ class Connection(NetworkBase):
"""Check if the message belongs to the user. If so, returns True;
False otherwise."""
assert(isinstance(message, NetworkData))
- return (message.username == self._options[self.NAMESPACE]['username'])
+ return (message.author.username ==
+ self._options[self.NAMESPACE]['username'])
def can_reply(self, message):
"""Always return True; Twitter allows replying to any messages,
@@ -496,7 +502,7 @@ class Connection(NetworkBase):
def can_repost(self, message):
"""Twitter ignores retweets from the user."""
assert(isinstance(message, NetworkData))
- return not (message.username ==
+ return not (message.author.username ==
self._options[self.NAMESPACE]['username'])
def can_favourite(self, message):
diff --git a/mitterlib/ui/ui_pygtk.py b/mitterlib/ui/ui_pygtk.py
index d6856fc..b53675e 100644
--- a/mitterlib/ui/ui_pygtk.py
+++ b/mitterlib/ui/ui_pygtk.py
@@ -608,7 +608,7 @@ class Interface(object):
userpic."""
data = store.get_value(position, 0)
- pic = data.avatar
+ pic = data.author.avatar
cell.set_property('pixbuf', self._avatars[pic])
return
@@ -625,8 +625,8 @@ class Interface(object):
# unescape escaped entities that pango is not okay with
message_values['message'] = html_escape(data.message)
- message_values['username'] = html_escape(data.username)
- message_values['full_name'] = html_escape(data.name)
+ message_values['username'] = html_escape(data.author.username)
+ message_values['full_name'] = html_escape(data.author.name)
message_values['message_age'] = time
# highlight URLs
@@ -657,11 +657,11 @@ class Interface(object):
info = []
if data.reposted_by:
info.append(_(' — reposted by %s') %
- (data.reposted_by))
+ (data.reposted_by.username))
if data.parent_owner:
info.append(_(' — in reply to %s') %
- (data.parent_owner))
+ (data.parent_owner.username))
if data.protected:
message_values['protected_status'] = (
@@ -781,7 +781,7 @@ class Interface(object):
"""Using the results from the request, fill a gtk.Store."""
for message in data:
message.read = False
- pic = message.avatar
+ pic = message.author.avatar
if not pic in self._avatars:
# set the user avatar to the default image, so it won't get
# queued again. Once downloaded, the _post_download_pic will
@@ -817,7 +817,8 @@ class Interface(object):
count = len(text)
if self._reply_message_id:
- suffix = _('(replying to %s)') % (self._reply_message_id.username)
+ suffix = _('(replying to %s)') % (
+ self._reply_message_id.author.username)
else:
suffix = ''
@@ -1030,7 +1031,7 @@ class Interface(object):
(model, iter) = grid.get_selection().get_selected()
message = model.get_value(iter, 0)
self._update_statusbar(_('Reposting %s message...') %
- (message.username))
+ (message.author.username))
self._threads.add_work(self._post_repost_message,
self._exception_repost_message,
self._connection.repost,
@@ -1049,7 +1050,7 @@ class Interface(object):
display = _('Removing message from %s from favorites...')
else:
display = _('Marking message from %s as favorite...')
- self._update_statusbar(display % (message.username))
+ self._update_statusbar(display % (message.author.username))
self._threads.add_work(self._post_favourite_message,
self._exception_favourite_message,
self._connection.favourite,
@@ -1623,4 +1624,4 @@ class Interface(object):
'protected/private.',
metavar='CHAR',
default=_('(protected)'),
- is_cmd_option=False)
\ No newline at end of file
+ is_cmd_option=False)