Package pinder :: Module campfire

Source Code for Module pinder.campfire

  1  """ 
  2  Handles Campfire online chat. 
  3  """ 
  4  import datetime 
  5  import re 
  6  import time 
  7  import urllib 
  8  import urlparse 
  9   
 10  from BeautifulSoup import BeautifulSoup 
 11  import httplib2 
 12   
 13  try: 
 14      set # python 2.3 does not have the set data type 
 15  except NameError: 
 16      from sets import Set as set 
 17   
 18  from __init__ import __version__ 
 19  from room import Room 
 20   
21 -class Campfire(object):
22 "Creates a connection to the Campfire account with the given subdomain."
23 - def __init__(self, subdomain):
24 #: The Campfire's subdomain. 25 self.subdomain = subdomain 26 #: True if the user is logged in Campfire, False otherwise. 27 self.logged_in = False 28 #: Contains the connection cookie. 29 self.cookie = None 30 #: The U{urlparsed<http://docs.python.org/lib/module-urlparse.html#l2h-4268>} URI of the Campfire account. 31 self.uri = urlparse.urlparse("http://%s.campfirenow.com" % self.subdomain) 32 self._location = None 33 self._room_re = re.compile(r'room\/(\d*)') 34 self._http_client = httplib2.Http(timeout=5) 35 self._http_client.force_exception_to_status_code = False
36
37 - def login(self, email, password):
38 """Logs into Campfire with the given email and password. 39 40 Returns True if logged in, False otherwise.""" 41 response = self._post("login", 42 dict(email_address=email, password=password)) 43 self.logged_in = self._verify_response(response, 44 redirect_to=self._uri_for()) 45 return self.logged_in
46
47 - def logout(self):
48 """Logs out from Campfire. 49 50 Returns True if logged out, False otherwise.""" 51 retval = self._verify_response(self._get("logout"), redirect=True) 52 self.logged_in = not retval 53 return retval
54
55 - def create_room(self, name, topic=''):
56 """Creates a Campfire room with the given name and an optional topic. 57 58 Returns None if the room has not been created.""" 59 room_data = { 60 'room[name]': name, 61 'room[topic]': topic 62 } 63 response = self._post('account/create/room?from=lobby', room_data, 64 ajax=True) 65 if self._verify_response(response, success=True): 66 return self.find_room_by_name(name)
67
68 - def find_room_by_name(self, name):
69 """Finds a Campfire room with the given name. 70 71 Returns a Room instance if found, None otherwise.""" 72 rooms = self._get_rooms_markup() 73 74 for room in rooms: 75 try: 76 room_name = room.h2.a.string 77 except AttributeError: # the chat is full 78 room_name = room.h2.string.strip() 79 80 if room_name.lower() == name.lower(): 81 try: 82 room_uri = room.h2.a['href'] 83 except AttributeError: # no uri available (!?) 84 return None 85 86 room_id = self._room_id_from_uri(room_uri) 87 return Room(self, room_id, name)
88
89 - def find_or_create_room_by_name(self, name):
90 """Finds a Campfire room with the given name. 91 If the room is not present it will be created. 92 93 Returns a Room instance.""" 94 return self.find_room_by_name(name) or self.create_room(name)
95
96 - def users(self, *room_names):
97 """Lists the users chatting in any room or in the given room(s). 98 99 Returns a set of the users.""" 100 rooms = self._get_rooms_markup() 101 102 all_users = [] 103 for room in rooms: 104 try: 105 room_name = room.h2.a.string 106 except AttributeError: # the chat is full 107 room_name = room.h2.string.strip() 108 if not room_names or room_name in room_names: 109 room_users = room.findAll('li', attrs={'class': 'user'}) 110 for user in room_users: 111 all_users.append(user.string) 112 return set(all_users)
113
114 - def rooms_names(self):
115 """Lists the names of the rooms available in the Campfire subdomain. 116 117 Returns a list of the names of the rooms.""" 118 rooms = self._get_rooms_markup() 119 120 rooms_names_list = [] 121 for room in rooms: 122 try: 123 rooms_names_list.append(room.h2.a.string) 124 except AttributeError: 125 rooms_names_list.append(room.h2.string.strip()) 126 rooms_names_list.sort() 127 return rooms_names_list
128
129 - def rooms(self):
130 """Lists the available rooms. 131 132 Returns a list of Room objects.""" 133 names = self.rooms_names() 134 return [self.find_room_by_name(name) for name in names]
135
136 - def transcripts(self, room_id=None):
137 """Gets the dates of the transcripts by room filtered by the given id 138 if any. 139 140 Returns a dictionary of all the dates by room. 141 """ 142 uri = 'files%2Btranscripts' 143 if room_id: 144 uri = '%s?room_id=%s' % (uri, str(room_id)) 145 146 soup = BeautifulSoup(self._get(uri).body) 147 148 def _filter_transcripts(tag): 149 return tag.has_key('class') and 'transcript' in tag['class'].split()
150 transcripts_markup = soup.findAll(_filter_transcripts) 151 152 result = {} 153 for tag in transcripts_markup: 154 link = tag.a['href'] 155 found_room_id = self._room_id_from_uri(link) 156 date = re.search( 157 r'/transcript/(\d{4}/\d{2}/\d{2})', link).groups()[0] 158 try: 159 result[found_room_id] 160 except KeyError: 161 result[found_room_id] = [] 162 result[found_room_id].append(self._parse_transcript_date(date)) 163 164 if room_id: 165 return result[str(room_id)] 166 return result
167
168 - def _parse_transcript_date(self, date):
169 return datetime.date.fromtimestamp(time.mktime( 170 time.strptime(date, '%Y/%m/%d')))
171
172 - def _filter_rooms_markup(self, tag):
173 return tag.name == 'div' and tag.has_key('id') and tag['id'].startswith('room_')
174
175 - def _get_rooms_markup(self):
176 body = self._get().body 177 soup = BeautifulSoup(body) 178 return soup.findAll(self._filter_rooms_markup)
179
180 - def _uri_for(self, path=''):
181 return "%s/%s" % (urlparse.urlunparse(self.uri), path)
182
183 - def _room_id_from_uri(self, uri):
184 try: 185 return self._room_re.split(uri)[1] 186 except IndexError: 187 pass
188
189 - def _prepare_request(self, **options):
190 headers = {} 191 192 headers['User-Agent'] = 'Pinder/%s' % __version__ 193 194 if self.cookie: 195 headers['cookie'] = self.cookie 196 if 'ajax' in options: 197 headers['X-Requested-With'] = 'XMLHttpRequest' 198 headers['X-Prototype-Version'] = '1.5.1.1' 199 return headers
200
201 - def _perform_request(self, method, path, data={}, **options):
202 headers = self._prepare_request(**options) 203 if method == 'POST': 204 headers.update({"Content-type": "application/x-www-form-urlencoded"}) 205 location = self._uri_for(path) 206 elif method == 'GET': 207 if self._location: 208 location = self._location 209 else: 210 location = self._uri_for(path) 211 self._location = None 212 else: 213 raise Exception, 'Unsupported HTTP method' 214 215 response, content = self._http_client.request(location, method, 216 urllib.urlencode(data), headers) 217 response.body = content 218 self.cookie = response.get('set-cookie') 219 return response
220
221 - def _post(self, path, data={}, **options):
222 return self._perform_request('POST', path, data, **options)
223
224 - def _get(self, path=''):
225 return self._perform_request('GET', path)
226
227 - def _verify_response(self, response, **options):
228 if 'success' in options: 229 return response.status == 200 230 elif 'redirect' in options: 231 return response.status in xrange(300, 400) 232 elif 'redirect_to' in options: 233 location = response.get('location') 234 return self._verify_response( 235 response, redirect=True) and location == options['redirect_to'] 236 else: 237 return False
238 239 240 __all__ = ['Campfire'] 241