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
15 except NameError:
16 from sets import Set as set
17
18 from __init__ import __version__
19 from room import Room
20
22 "Creates a connection to the Campfire account with the given subdomain."
24
25 self.subdomain = subdomain
26
27 self.logged_in = False
28
29 self.cookie = None
30
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
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
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
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:
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:
84 return None
85
86 room_id = self._room_id_from_uri(room_uri)
87 return Room(self, room_id, name)
88
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:
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
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
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
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
169 return datetime.date.fromtimestamp(time.mktime(
170 time.strptime(date, '%Y/%m/%d')))
171
173 return tag.name == 'div' and tag.has_key('id') and tag['id'].startswith('room_')
174
176 body = self._get().body
177 soup = BeautifulSoup(body)
178 return soup.findAll(self._filter_rooms_markup)
179
181 return "%s/%s" % (urlparse.urlunparse(self.uri), path)
182
184 try:
185 return self._room_re.split(uri)[1]
186 except IndexError:
187 pass
188
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
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
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