plugin CS: friends parsing

This commit is contained in:
Goffi 2010-06-26 15:33:16 +08:00
commit 6eddbcf368
5 changed files with 135 additions and 40 deletions

View file

@ -62,6 +62,7 @@ class XMLUI(wx.Frame):
error(message)
raise Exception(message)
_proportion = 0
id = elem.getAttribute("id")
name = elem.getAttribute("name")
type = elem.getAttribute("type")
value = elem.getAttribute("value") if elem.hasAttribute('value') else u''
@ -88,7 +89,10 @@ class XMLUI(wx.Frame):
self.ctl_list.append({'name':name, 'type':type, 'control':ctrl})
_proportion = 1
elif type=="button":
pass
callback_id = elem.getAttribute("callback_id")
ctrl = wx.Button(parent, -1, value)
ctrl.param_id = callback_id
parent.Bind(wx.EVT_BUTTON, self.onButtonClicked, ctrl)
else:
error(_("FIXME FIXME FIXME: type [%s] is not implemented") % type) #FIXME !
raise NotImplementedError
@ -174,6 +178,16 @@ class XMLUI(wx.Frame):
self.sizer.Add(panel, 1, flag=wx.EXPAND)
cat_dom.unlink()
###events
def onButtonClicked(self, event):
"""Called when a button is pushed"""
callback_id = event.GetEventObject().param_id
data = {"callback_id":callback_id}
id = self.host.bridge.launchAction("button", data)
self.host.current_action_ids.add(id)
event.Skip()
def onFormSubmitted(self, event):
"""Called when submit button is clicked"""
debug(_("Submitting form"))

View file

@ -33,11 +33,11 @@ import random
from zope.interface import implements
from wokkel import disco, iwokkel, data_form
from tools.xml_tools import dataForm2xml
from tools.xml_tools import XMLUI
import urllib
from BeautifulSoup import BeautifulSoup
import re
PLUGIN_INFO = {
@ -73,14 +73,13 @@ class CS_Plugin():
host.memory.importParams(CS_Plugin.params)
#menu
host.importMenu(_("Plugin"), "CouchSurfing", self.menuSelected, help_string = _("Launch CoushSurfing mangement interface"))
self.data={} #TODO: delete cookies/data after a while
self.data=self.host.memory.getPrivate('plugin_cs_data') or {} #TODO: delete cookies/data after a while
def erroCB(self, e, id):
"""Called when something is going wrong when contacting CS website"""
message_data={"reason": "connection error", "message":_(u"Impossible to contact CS website, please check your login/password, connection or try again later")}
self.host.bridge.actionResult("ERROR", id, message_data)
def menuSelected(self, id, profile):
"""Called when the couchsurfing menu item is selected"""
login = self.host.memory.getParamA("Login", "CouchSurfing", profile_key=profile)
@ -92,36 +91,113 @@ class CS_Plugin():
post_data = urllib.urlencode({'auth_login[un]':login,'auth_login[pw]':password,'auth_login[action]':'Login...'})
self.data[profile] = {'cookies':{}}
def connectionCB(html):
print 'Response received'
soup = self.data[profile]['soup'] = BeautifulSoup(html)
user_nick = soup.find('a','item_link',href='/home.html').contents[0]
user_name = soup.html.head.title.string.split(' - ')[1]
unread_messages = int(soup.find('div','item_bubble').a.string)
form_xml = """
<form>
<elem type='text' value='Welcome %(name)s, you have %(nb_message)i unread messages'/>
</form>
""" % {'name':user_name, 'nb_message':unread_messages}
self.host.bridge.actionResult("XMLUI", id, {"type":"window", "xml":form_xml})
if not self.data.has_key(profile):
self.data[profile] = {'cookies':{}}
else:
self.data[profile]['cookies'] = {}
#d = getPage('http://www.couchsurfing.org/messages.html?message_status=inbox', agent=AGENT, cookies=self.session_cookies[profile])
#tmp
f = open('/home/goffi/tmp/CS_principale.html','r')
html = f.read()
connectionCB(html)
self.__connectionCB(html, id, profile)
"""d = getPage('http://www.couchsurfing.org/login.html', method='POST', postdata=post_data, headers={'Content-Type':'application/x-www-form-urlencoded'} , agent=AGENT, cookies=self.data[profile]['cookies'])
d.addCallback(connectionCB)
d.addCallback(self.__connectionCB, id, profile)
d.addErrback(self.erroCB, id)"""
#self.host.bridge.actionResult("SUPPRESS", id, {})
#self.host.bridge.actionResult("SUPPRESS", id, {})
#pages parsing callbacks
def savePage(self, name, html):
f = open ('/home/goffi/tmp/CS_'+name+'.html','w')
f.write(html)
f.close()
print "page [%s] sauvee" % name
#pdb.set_trace()
def __connectionCB(self, html, id, profile):
print 'Response received'
self.savePage('principale',html)
soup = BeautifulSoup(html)
self.data[profile]['user_nick'] = soup.find('a','item_link',href='/home.html').contents[0]
self.data[profile]['user_name'] = soup.html.head.title.string.split(' - ')[1]
#unread messages
try:
self.data[profile]['unread_messages'] = int(soup.find(lambda tag: tag.name=='div' and ('class','item_bubble') in tag.attrs and tag.find('a', href="/messages.html?message_status=inbox")).find(text=True))
except:
self.data[profile]['unread_messages'] = 0
#unread couchrequest messages
try:
self.data[profile]['unread_CR_messages'] = int(soup.find(lambda tag: tag.name=='div' and ('class','item_bubble') in tag.attrs and tag.find('a', href="/couchmanager")).find(text=True))
except:
self.data[profile]['unread_CR_messages'] = 0
#if we have already the list of friend, no need to make new requests
if not self.data[profile].has_key('friends'):
self.data[profile]['friends'] = {}
"""f = open('/home/goffi/tmp/CS_friends.html','r')
html = f.read()
self.__friendsPageCB(html, id, profile)"""
d = getPage('http://www.couchsurfing.org/connections.html?type=myfriends&show=10000', agent=AGENT, cookies=self.data[profile]['cookies'])
d.addCallback(self.__friendsPageCB, id=id, profile=profile)
d.addErrback(self.erroCB, id)
else:
self.host.bridge.actionResult("XMLUI", id, {"type":"window", "xml":self.__buildUI(self.data[profile])})
def __buildUI(self, data):
"""Build the XML UI of the plugin
@param data: data store for the profile"""
user_nick = data['user_nick']
user_name = data['user_name']
unread_mess = data['unread_messages']
unread_CR_mess = data['unread_CR_messages']
friends_list = data['friends'].keys()
friends_list.sort()
interface = XMLUI('window','tabs')
interface.addCategory(_("Messages"), "vertical")
interface.addText(_("G'day %(name)s, you have %(nb_message)i unread message%(plural_mess)s and %(unread_CR_mess)s unread couch request message%(plural_CR)s") % {'name':user_name, 'nb_message':unread_mess, 'plural_mess':'s' if unread_mess>1 else '', 'unread_CR_mess': unread_CR_mess, 'plural_CR':'s' if unread_CR_mess>1 else ''})
interface.addList(friends_list, 'friends')
interface.addCategory(_("Events"), "vertical")
interface.addCategory(_("Couch search"), "vertical")
return interface.toXml()
def __meetingPageCB(self, html):
"""Called when the meeting page has been received"""
def __friendsPageCB(self, html, id, profile):
"""Called when the friends list page has been received"""
self.savePage('friends',html)
soup = BeautifulSoup(html.replace('"formtable width="400','"formtable" width="400"'))
friends = self.data[profile]['friends']
for _tr in soup.findAll('tr', {'class':re.compile("^msgRow*")}): #we parse the row with friends infos
_nobr = _tr.find('nobr') #contain the friend name
friend_name = unicode(_nobr.string)
friend_link = u'http://www.couchsurfing.org'+_nobr.parent['href']
regex_href = re.compile(r'/connections\.html\?id=([^&]+)')
a_tag = _tr.find('a',href=regex_href)
friend_id = regex_href.search(unicode(a_tag)).groups()[0]
debug(_("CS friend found: %(friend_name)s (id: %(friend_id)s, link: %(friend_link)s)") % {'friend_name':friend_name, 'friend_id':friend_id, 'friend_link':friend_link})
friends[friend_name] = {'link':friend_link,'id':friend_id}
a = soup.find('td','barmiddle next').a #is there several pages ?
if a:
#yes, we parse the next page
d = getPage('http://www.couchsurfing.org/'+str(a['href']), agent=AGENT, cookies=self.data[profile]['cookies'])
d.addCallback(self.__friendsPageCB, id=id, profile=profile)
d.addErrback(self.erroCB, id)
else:
#no, we show the result
self.host.bridge.actionResult("XMLUI", id, {"type":"window", "xml":self.__buildUI(self.data[profile])})
#and save the data
self.host.memory.setPrivate('plugin_cs_data', self.data)

View file

@ -25,6 +25,8 @@ CONST = {
'local_dir' : '~/.sat'
}
import gettext
gettext.install('sat', "i18n", unicode=True)
from twisted.application import internet, service
from twisted.internet import glib2reactor, protocol, task
@ -50,9 +52,6 @@ from tools.memory import Memory
from tools.xml_tools import tupleList2dataForm
from glob import glob
import gettext
gettext.install('sat', "i18n", unicode=True)
try:
from twisted.words.protocols.xmlstream import XMPPHandler
except ImportError:
@ -568,7 +567,7 @@ class SAT(service.Service):
"""
if type=="button":
try:
cb_name = self.memory.getParamA(data["name"], data["category"], "callback")
cb_name = data['callback_id']
except KeyError:
error (_("Incomplete data"))
return ""

View file

@ -23,7 +23,7 @@ from __future__ import with_statement
import os.path
import time
import pickle
import cPickle as pickle
from xml.dom import minidom
from logging import debug, info, error
import pdb
@ -46,13 +46,13 @@ class Param():
<general>
</general>
<individual>
<category name="Connection">
<category name='"""+_("Connection")+"""'>
<param name="JabberID" value="goffi@necton2.int/TestScript" type="string" />
<param name="Password" value="toto" type="password" />
<param name="Server" value="necton2.int" type="string" />
<param name="NewAccount" value="Register new account" type="button" callback="registerNewAccount"/>
<param name="NewAccount" value='"""+_("Register new account")+"""' type="button" callback_id="registerNewAccount"/>
</category>
<category name="Misc">
<category name='"""+_("Misc")+"""'>
<param name="Watched" value="test@Jabber.goffi.int" type="string" />
</category>
</individual>

View file

@ -88,9 +88,12 @@ def paramsXml2xmlUI(xml):
assert(False)
type = param.getAttribute('type')
value = param.getAttribute('value') or None
callback = param.getAttribute('callback') or None
param_ui.addLabel(name)
param_ui.addElement(name=name, type=type, value=value, callback=callback)
callback_id = param.getAttribute('callback_id') or None
if type == "button":
param_ui.addEmpty()
else:
param_ui.addLabel(name)
param_ui.addElement(name=name, type=type, value=value, callback_id=callback_id)
return param_ui.toXml()
@ -200,15 +203,18 @@ class XMLUI:
if value:
elem.setAttribute('value', value)
def addButton(self, callback, name):
def addButton(self, callback_id, name, value):
"""Add a button
@param callback: callback which will be called if button is pressed
@param name: name shown on the button"""
@param name: name
@param value: label of the button"""
elem = self.__createElem('button', name, self.currentLayout)
elem.setAttribute('callback', callback)
elem.setAttribute('callback_id', callback_id)
if value:
elem.setAttribute('value', value)
def addElement(self, type, name = None, content = None, value = None, options = None, callback = None):
def addElement(self, type, name = None, content = None, value = None, options = None, callback_id = None):
"""Convenience method to add element, the params correspond to the ones in addSomething methods"""
if type == 'empty':
self.addEmpty(name)
@ -224,8 +230,8 @@ class XMLUI:
elif type == 'list':
self.addList(options, name, value)
elif type == 'button':
assert(callback and name)
self.addButton(callback, name)
assert(callback_id and value)
self.addButton(callback_id, name, value)
def addOptions(self, options, parent):
"""Add options to a multi-values element (e.g. list)