├── test ├── __init__.py ├── fixtures │ ├── default.html │ ├── no_rooms.html │ ├── no_transcripts.html │ ├── transcripts.html │ ├── rooms_names.html │ ├── chat_rooms_empty.html │ ├── chat_rooms_one_empty.html │ ├── chat_rooms_not_empty.html │ ├── room_info.html │ ├── room_info_nospaces.html │ ├── no_guest_url.html │ └── guest_url.html ├── runtests.py ├── utils.py ├── test_room.py └── test_campfire.py ├── .gitignore ├── doc ├── api │ ├── crarr.png │ ├── redirect.html │ ├── api-objects.txt │ ├── module-tree.html │ ├── class-tree.html │ ├── pinder.room-module.html │ ├── pinder.campfire-module.html │ ├── index.html │ ├── pinder-module.html │ ├── pinder-pysrc.html │ ├── epydoc.js │ ├── help.html │ ├── identifier-index.html │ ├── epydoc.css │ ├── pinder.campfire.Campfire-class.html │ └── pinder.room.Room-class.html ├── faq.txt └── usage.txt ├── pinder ├── __init__.py ├── campfire.py └── room.py ├── PKG-INFO ├── README.txt ├── NEWS.txt ├── setup.py ├── CHANGELOG.txt └── LICENSE.txt /test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.swp 3 | build 4 | -------------------------------------------------------------------------------- /test/fixtures/default.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/fixtures/no_rooms.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/fixtures/no_transcripts.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /doc/api/crarr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defunkt/pinder/master/doc/api/crarr.png -------------------------------------------------------------------------------- /pinder/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Campfire Python API. 3 | """ 4 | 5 | __author__ = "Lawrence Oluyede (oluyede.org)" 6 | __version__ = '0.6.5' 7 | __copyright__ = "Copyright (c) 2007, 2008 Lawrence Oluyede" 8 | __license__ = "BSD" 9 | 10 | from campfire import * 11 | from room import * 12 | -------------------------------------------------------------------------------- /test/fixtures/transcripts.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | Foo 4 |

5 |
6 | 7 |
8 |

9 | Foo 10 |

11 |
12 | -------------------------------------------------------------------------------- /test/fixtures/rooms_names.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | Room A 4 |

5 |
6 |
7 |

8 | Room B 9 |

10 |
11 | -------------------------------------------------------------------------------- /doc/faq.txt: -------------------------------------------------------------------------------- 1 | FAQ 2 | === 3 | 4 | * First and foremost: why did you take the burden to translate the already mighty Tinder? 5 | 6 | We needed a way to integrate Campfire chats into our web application so instead of monkey patching some crappy code in a hurry I ported the whole thing to Python in a couple of hours. I think that's the right call. I could have write some glue code to make Django and Tinder communicate but the idea sucked to me. 7 | 8 | That's it. 9 | -------------------------------------------------------------------------------- /test/fixtures/chat_rooms_empty.html: -------------------------------------------------------------------------------- 1 |
2 |

Room A 3 |

4 |
5 | Unoccupied 6 |
7 |

test test test

8 |
9 |
10 |

Room B

11 |
Unoccupied
12 |

13 |
14 | -------------------------------------------------------------------------------- /test/fixtures/chat_rooms_one_empty.html: -------------------------------------------------------------------------------- 1 |
2 |

Room A

3 |
4 |
5 |

6 | 9 |
10 |
11 |

Room B

12 |
Unoccupied
13 |

14 |
15 | -------------------------------------------------------------------------------- /test/fixtures/chat_rooms_not_empty.html: -------------------------------------------------------------------------------- 1 |
2 |

Room A

3 |
4 |

5 | 6 |
7 |
8 |

Room B

9 |
10 |

11 | 12 |
13 | -------------------------------------------------------------------------------- /test/fixtures/room_info.html: -------------------------------------------------------------------------------- 1 | /* \n Alan S.\n
#{body}
\n\n", messageHistory: 100, speakURL: "http://sample.campfirenow.com/room/12345/speak", soundsEnabled: true, pollURL: "/poll.fcgi", transcriptElement: "chat", scrollToBottom: true, "membershipKey": "ea243569b02d3129"}); 3 | /* ]]> */ 4 | -------------------------------------------------------------------------------- /test/fixtures/room_info_nospaces.html: -------------------------------------------------------------------------------- 1 | /* look for membershipKey */ 2 | 3 | /* \n Alan S.\n
#{body}
\n\n", messageHistory: 100, speakURL: "http://sample.campfirenow.com/room/12345/speak", soundsEnabled: true, pollURL: "/poll.fcgi", transcriptElement: "chat", scrollToBottom: true, "membershipKey":"ea243569b02d3129"}); 5 | /* ]]> */ 6 | -------------------------------------------------------------------------------- /test/fixtures/no_guest_url.html: -------------------------------------------------------------------------------- 1 |
2 |

Guest access is off

3 |
4 | 5 | /* \n Alan S.\n
#{body}
\n\n", messageHistory: 100, speakURL: "http://sample.campfirenow.com/room/12345/speak", soundsEnabled: true, pollURL: "/poll.fcgi", transcriptElement: "chat", scrollToBottom: true, "membershipKey": "ea243569b02d3129"}); 7 | /* ]]> */ 8 | -------------------------------------------------------------------------------- /test/fixtures/guest_url.html: -------------------------------------------------------------------------------- 1 |
2 |

Guest access is on

3 |

http://sample.campfirenow.com/99d14

4 |
5 | 6 | /* \n Alan S.\n
#{body}
\n\n", messageHistory: 100, speakURL: "http://sample.campfirenow.com/room/12345/speak", soundsEnabled: true, pollURL: "/poll.fcgi", transcriptElement: "chat", scrollToBottom: true, "membershipKey": "ea243569b02d3129"}); 8 | /* ]]> */ 9 | -------------------------------------------------------------------------------- /test/runtests.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | import os 3 | import sys 4 | import unittest 5 | 6 | if __name__ == "__main__": 7 | __file__ = sys.argv[0] 8 | 9 | TESTDIR = os.path.dirname(os.path.abspath(__file__)) 10 | TOPDIR = os.path.dirname(TESTDIR) 11 | 12 | def load_test_files(): 13 | test_files = [] 14 | for f in os.listdir(TESTDIR): 15 | if f.startswith('test_') and f.endswith('.py'): 16 | test_files.append(os.path.splitext(f)[0]) 17 | return test_files 18 | 19 | if __name__ == "__main__": 20 | if TOPDIR not in sys.path: 21 | sys.path.insert(0, TOPDIR) 22 | sys.path.insert(0, TESTDIR) 23 | suite = unittest.defaultTestLoader.loadTestsFromNames(load_test_files()) 24 | try: 25 | v = sys.argv[1] 26 | except: 27 | v = 1 28 | runner = unittest.TextTestRunner(verbosity=int(v)) 29 | runner.run(suite) 30 | -------------------------------------------------------------------------------- /PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.0 2 | Name: pinder 3 | Version: 0.6.5 4 | Summary: Python API for Campfire. 5 | Home-page: http://dev.oluyede.org/pinder/ 6 | Author: Lawrence Oluyede 7 | Author-email: l.oluyede@gmail.com 8 | License: BSD 9 | Download-URL: http://dev.oluyede.org/download/pinder/0.6.5/ 10 | Description: UNKNOWN 11 | Platform: UNKNOWN 12 | Classifier: Development Status :: 4 - Beta 13 | Classifier: Environment :: Console 14 | Classifier: Environment :: Web Environment 15 | Classifier: Intended Audience :: Developers 16 | Classifier: License :: OSI Approved :: BSD License 17 | Classifier: Natural Language :: English 18 | Classifier: Operating System :: MacOS :: MacOS X 19 | Classifier: Operating System :: Microsoft :: Windows 20 | Classifier: Operating System :: POSIX 21 | Classifier: Programming Language :: Python 22 | Classifier: Topic :: Communications :: Chat 23 | Classifier: Topic :: Internet :: WWW/HTTP 24 | Classifier: Topic :: Software Development :: Libraries 25 | Classifier: Topic :: Software Development :: Libraries :: Python Modules 26 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | Pinder 0.6.5 2 | ============ 3 | 4 | Pinder is a client library for Campfire, the chat application from 37Signals. 5 | 6 | You can find Campfire here: 7 | 8 | Requirements 9 | ------------ 10 | 11 | * Python 2.3+ 12 | * BeautifulSoup >= 3.0.4 13 | * httplib2 >= 0.3.0 14 | 15 | Installation 16 | ------------ 17 | 18 | 19 | $ easy_install -U BeautifulSoup 20 | $ easy_install -U httplib2 21 | 22 | Then: 23 | 24 | $ easy_install -U pinder 25 | 26 | - OR - 27 | 28 | Get the latest version from , unpack it, go inside the new directory and type the following in the shell: 29 | 30 | $ python setup.py install 31 | 32 | 33 | Documentation 34 | ------------- 35 | 36 | See doc/usage.txt for usage documentation and doc/api/pinder.html for the API doc. There's also a faq in doc/faq.txt. 37 | 38 | 39 | Many thanks to Brandon Keepers for Tinder. 40 | 41 | Subversion access 42 | ----------------- 43 | 44 | See 45 | -------------------------------------------------------------------------------- /NEWS.txt: -------------------------------------------------------------------------------- 1 | Pinder 0.6.5 [May 18 2007]: 2 | - BACKWARDS INCOMPATIBLE CHANGE: BeautifulSoup and httplib2 are no longer 3 | distributed with Pinder. You have to install them separately. 4 | 5 | - Fixed a bug in Room.leave() 6 | 7 | - Fixed a couple of bugs in the tests 8 | 9 | - Room objects now have ping() to ping the server and topic() to retrieve 10 | the topic of the room 11 | 12 | Pinder 0.6.0 [Apr 08 2007]: 13 | - Campfire objects now have rooms() and rooms_names() methods to get the 14 | list of the associated room objects and the names of all the rooms 15 | 16 | - Campfire objects also have find_or_create_room_by_name(), an helper 17 | method which combine find_room_by_name() and create_room() 18 | 19 | - The whole library has been updated to httlibp2 0.3.0 20 | 21 | - A proper user agent is sent during the requests 22 | 23 | - Room objects now have guest_access_enabled() to know if the guests can 24 | enter that room 25 | 26 | - The support for transcripts has been added throughout the library. See 27 | the changelog for details. 28 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from distutils.core import setup 4 | 5 | from pinder import __version__ 6 | 7 | setup( 8 | name='pinder', 9 | version=__version__, 10 | description='Python API for Campfire.', 11 | license='BSD', 12 | author='Lawrence Oluyede', 13 | author_email='l.oluyede@gmail.com', 14 | url='http://dev.oluyede.org/pinder/', 15 | download_url='http://dev.oluyede.org/download/pinder/0.6.5/', 16 | packages=['pinder'], 17 | classifiers=[ 18 | 'Development Status :: 4 - Beta', 19 | 'Environment :: Console', 20 | 'Environment :: Web Environment', 21 | 'Intended Audience :: Developers', 22 | 'License :: OSI Approved :: BSD License', 23 | 'Natural Language :: English', 24 | 'Operating System :: MacOS :: MacOS X', 25 | 'Operating System :: Microsoft :: Windows', 26 | 'Operating System :: POSIX', 27 | 'Programming Language :: Python', 28 | 'Topic :: Communications :: Chat', 29 | 'Topic :: Internet :: WWW/HTTP', 30 | 'Topic :: Software Development :: Libraries', 31 | 'Topic :: Software Development :: Libraries :: Python Modules', 32 | ] 33 | ) 34 | -------------------------------------------------------------------------------- /doc/api/redirect.html: -------------------------------------------------------------------------------- 1 | Epydoc Redirect Page 2 | 3 | 4 | 5 | 6 | 7 | 8 | 18 | 19 |

Epydoc Auto-redirect page

20 | 21 |

When javascript is enabled, this page will redirect URLs of 22 | the form redirect.html#dotted.name to the 23 | documentation for the object with the given fully-qualified 24 | dotted name.

25 |

 

26 | 27 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | from runtests import TESTDIR 3 | 4 | FIXTURE = 'default' 5 | 6 | class MockResponse(object): 7 | def __init__(self): 8 | self.status = 200 9 | self.headers = { 10 | 'location': '/foobar', 11 | 'set-cookie': 'cookie', 12 | } 13 | self.fixture = '' 14 | 15 | def getheader(self, header_name, default=None): 16 | return self.headers.get(header_name) 17 | get = getheader 18 | 19 | def read(self): 20 | path = os.path.join(TESTDIR, "fixtures/%s.html" % FIXTURE) 21 | return open(path).read() 22 | 23 | class MockHttplib2Response(MockResponse): 24 | def __init__(self, info): 25 | self.status = info.status 26 | self.headers = info.headers 27 | self.fixture = '' 28 | 29 | def has_key(self, key): 30 | return self.__contains__(key) 31 | 32 | def __iter__(self): 33 | return iter(self.headers.keys()) 34 | 35 | def __contains__(self, item): 36 | return item in self.headers 37 | 38 | def __getitem__(self, item): 39 | item = self.headers.get(item) 40 | if not item: 41 | raise KeyError(item) 42 | 43 | def __setitem__(self, key, value): 44 | self.headers[key] = value 45 | -------------------------------------------------------------------------------- /CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | * May 18 2008: Pinder 0.6.5: third public release. 2 | 3 | * May 18 2008: trunk: Removed BeautifulSoup and httplib2 from internal packaging, now they are required dependencies 4 | 5 | * Feb 16 2008: trunk: Added a method to retrieve the topic of the room 6 | 7 | * Jan 27 2008: trunk: The interval to ping the server should be less than 60 8 | 9 | * Dec 26 2007: trunk: 10 | - Updated prototype.js version 11 | - Added room.ping() to ping the server 12 | 13 | * Sep 01 2007: trunk: 14 | - Fixed a problem in the fake response object 15 | - Added a proper mapping implementation in the fake object 16 | 17 | * Apr 14 2007: trunk: fixed a bug in room.leave() (thanks to Pinder codebase) 18 | 19 | * Apr 10 2007: trunk: Updated BeautifulSoup to 3.0.4 20 | 21 | * Apr 08 2007: Pinder 0.6.0: second public release. 22 | 23 | * Apr 08 2007: trunk: 24 | - Fixed room regexp 25 | - Added support for transcripts: 26 | - Campfire.transcripts() 27 | - Room.transcripts() 28 | - Room.transcript() 29 | 30 | * Apr 03 2007: trunk: 31 | - pinder now sends a proper user agent. 32 | - Added guest_access_enabled() to the public API. 33 | - Little fix in toggle_guest_access(). 34 | 35 | * Mar 10 2007: trunk: Updated pinder to httplib2 0.3.0. 36 | 37 | * Mar 09 2007: trunk: Added find_or_create_room_by_name() to the public API. 38 | 39 | * Mar 07 2007: trunk: Added rooms_names() and rooms() to the public API. 40 | 41 | * Mar 07 2007: Pinder 0.5.0: first public release. 42 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007, Lawrence Oluyede 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /test/test_room.py: -------------------------------------------------------------------------------- 1 | from httplib import HTTPConnection 2 | import unittest 3 | 4 | from pinder import Campfire, Room 5 | import utils 6 | 7 | 8 | class RoomTest(unittest.TestCase): 9 | def setUp(self): 10 | self.response = utils.MockResponse() 11 | self.campfire = Campfire('foobar') 12 | self.room = Room(self.campfire, 12345, 'Room 1') 13 | self.campfire = Campfire('foobar') 14 | response = self.response 15 | HTTPConnection.request = lambda self, m, l, b, h: None 16 | HTTPConnection.getresponse = lambda self: response 17 | 18 | def test_join(self): 19 | utils.FIXTURE = 'room_info' 20 | self.assertEqual(True, self.room.join()) 21 | self.assertEqual(True, self.room.join(force=True)) 22 | 23 | def test_join_nospaces(self): 24 | utils.FIXTURE = 'room_info_nospaces' 25 | self.assertEqual(True, self.room.join()) 26 | self.assertEqual(True, self.room.join(force=True)) 27 | 28 | def test_guest_url_no_guest_url(self): 29 | utils.FIXTURE = 'no_guest_url' 30 | self.assert_(self.room.guest_url() is None) 31 | 32 | def test_guest_url(self): 33 | utils.FIXTURE = 'guest_url' 34 | self.assertEqual('http://sample.campfirenow.com/99d14', 35 | self.room.guest_url()) 36 | 37 | def test_guest_invite_code_no_guest_url(self): 38 | utils.FIXTURE = 'no_guest_url' 39 | self.assert_(self.room.guest_invite_code() is None) 40 | 41 | def test_guest_invite_code(self): 42 | utils.FIXTURE = 'guest_url' 43 | self.assertEqual('99d14', self.room.guest_invite_code()) 44 | 45 | def test_transcripts(self): 46 | utils.FIXTURE = 'transcripts' 47 | transcripts = self.room.transcripts() 48 | self.assertEqual(1, len(transcripts)) 49 | 50 | 51 | if __name__ == '__main__': 52 | unittest.main() 53 | -------------------------------------------------------------------------------- /doc/usage.txt: -------------------------------------------------------------------------------- 1 | ============ 2 | User's guide 3 | ============ 4 | 5 | Pinder is a straightforward Python API to *script* Campfire_, the web 2.0 chat application kindly brought to us by the 37signals_ team. 6 | 7 | Usage is all but rocket science so I'm gonna show you its full power in its simplicity. Thanks to `Brandon Keepers`_ for Tinder_. 8 | 9 | Connect and login to the server 10 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 11 | 12 | :: 13 | 14 | >>> c = Campfire('subdomain') 15 | >>> c.login('john@doe.com', 'secret') 16 | 17 | Any need to explain? I don't think so. We shall move on. 18 | 19 | Find the proper room 20 | ~~~~~~~~~~~~~~~~~~~~ 21 | 22 | :: 23 | 24 | >>> room = c.find_room_by_name('Jonz Room') 25 | 26 | Only remember that *None* will be returned if you accidentally type in the wrong name. Ouch! 27 | 28 | Poke with the room itself! 29 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 30 | 31 | :: 32 | 33 | >>> print room.users() 34 | set([u'Alice']) 35 | 36 | As you can see you get back a **set** of the people talking about wild stuff in *Jonz Room*. You can also, while you are at it know the name of all the chatters in your Campfire subdomain:: 37 | 38 | >>> print c.users() 39 | set([u'Alice', u'Bob']) 40 | 41 | Seems Alice and Bob don't enjoy each other company any more! We don't like ladies to feel so alone so let's tell Alice she isn't:: 42 | 43 | >>> room.speak("I'm working hard to get you out of there. Keep strong!") 44 | I'm working hard to get you out of there. Keep strong! 45 | 46 | Then you can leave the room:: 47 | 48 | >>> room.leave() 49 | 50 | or destroy Alice hopes:: 51 | 52 | >>> room.destroy() 53 | 54 | and create your own love's nest:: 55 | 56 | >>> c.create_room("Love's Nest", topic='No pun intended') 57 | 58 | Room eavesdropping! 59 | ~~~~~~~~~~~~~~~~~~~ 60 | 61 | You can peek inside the room reading the transcripts this way:: 62 | 63 | >>> dates_of_transcripts = room.transcripts() 64 | >>> print room.transcript(dates_of_transcripts[0]) # last transcript 65 | [{'person': u'Bob B.', 'message': u'Are you spying on me?', 'user_id': u'1234567', 'id': u'19343281'}] 66 | 67 | Logout 68 | ~~~~~~ 69 | 70 | When you are done playing you can simply logout:: 71 | 72 | >>> c.logout() 73 | 74 | and say farewell to Alice. 75 | 76 | ps. I think we forgot about Bob, but who cares? 77 | 78 | Extra 79 | ~~~~~ 80 | 81 | You can lock yourself in the room if you really want to but it's sad so I won't mention how to that. If you're absolutely certain about it go read the boring `API doc`_ where you can find other secret combos :-) 82 | 83 | .. _Campfire: http://wwww.campfirenow.com/ 84 | .. _37signals: http://www.37signals.com/ 85 | .. _`Brandon Keepers`: http://opensoul.org/ 86 | .. _Tinder: http://rubyforge.org/projects/tinder 87 | .. _`API doc`: http://dev.oluyede.org/pinder/api_doc/ 88 | -------------------------------------------------------------------------------- /doc/api/api-objects.txt: -------------------------------------------------------------------------------- 1 | pinder pinder-module.html 2 | pinder.campfire pinder.campfire-module.html 3 | pinder.room pinder.room-module.html 4 | pinder.campfire.Campfire pinder.campfire.Campfire-class.html 5 | pinder.campfire.Campfire._get_rooms_markup pinder.campfire.Campfire-class.html#_get_rooms_markup 6 | pinder.campfire.Campfire._verify_response pinder.campfire.Campfire-class.html#_verify_response 7 | pinder.campfire.Campfire._perform_request pinder.campfire.Campfire-class.html#_perform_request 8 | pinder.campfire.Campfire.create_room pinder.campfire.Campfire-class.html#create_room 9 | pinder.campfire.Campfire.rooms pinder.campfire.Campfire-class.html#rooms 10 | pinder.campfire.Campfire.rooms_names pinder.campfire.Campfire-class.html#rooms_names 11 | pinder.campfire.Campfire.__init__ pinder.campfire.Campfire-class.html#__init__ 12 | pinder.campfire.Campfire.logged_in pinder.campfire.Campfire-class.html#logged_in 13 | pinder.campfire.Campfire._parse_transcript_date pinder.campfire.Campfire-class.html#_parse_transcript_date 14 | pinder.campfire.Campfire.subdomain pinder.campfire.Campfire-class.html#subdomain 15 | pinder.campfire.Campfire.users pinder.campfire.Campfire-class.html#users 16 | pinder.campfire.Campfire._get pinder.campfire.Campfire-class.html#_get 17 | pinder.campfire.Campfire.logout pinder.campfire.Campfire-class.html#logout 18 | pinder.campfire.Campfire._room_id_from_uri pinder.campfire.Campfire-class.html#_room_id_from_uri 19 | pinder.campfire.Campfire.login pinder.campfire.Campfire-class.html#login 20 | pinder.campfire.Campfire._uri_for pinder.campfire.Campfire-class.html#_uri_for 21 | pinder.campfire.Campfire._post pinder.campfire.Campfire-class.html#_post 22 | pinder.campfire.Campfire._prepare_request pinder.campfire.Campfire-class.html#_prepare_request 23 | pinder.campfire.Campfire.find_or_create_room_by_name pinder.campfire.Campfire-class.html#find_or_create_room_by_name 24 | pinder.campfire.Campfire.uri pinder.campfire.Campfire-class.html#uri 25 | pinder.campfire.Campfire.find_room_by_name pinder.campfire.Campfire-class.html#find_room_by_name 26 | pinder.campfire.Campfire._filter_rooms_markup pinder.campfire.Campfire-class.html#_filter_rooms_markup 27 | pinder.campfire.Campfire.cookie pinder.campfire.Campfire-class.html#cookie 28 | pinder.campfire.Campfire.transcripts pinder.campfire.Campfire-class.html#transcripts 29 | pinder.room.Room pinder.room.Room-class.html 30 | pinder.room.Room.rename pinder.room.Room-class.html#rename 31 | pinder.room.Room._send pinder.room.Room-class.html#_send 32 | pinder.room.Room.lock pinder.room.Room-class.html#lock 33 | pinder.room.Room.topic pinder.room.Room-class.html#topic 34 | pinder.room.Room.unlock pinder.room.Room-class.html#unlock 35 | pinder.room.Room.id pinder.room.Room-class.html#id 36 | pinder.room.Room.__init__ pinder.room.Room-class.html#__init__ 37 | pinder.room.Room.speak pinder.room.Room-class.html#speak 38 | pinder.room.Room.__eq__ pinder.room.Room-class.html#__eq__ 39 | pinder.room.Room.ping pinder.room.Room-class.html#ping 40 | pinder.room.Room.toggle_guest_access pinder.room.Room-class.html#toggle_guest_access 41 | pinder.room.Room.change_name pinder.room.Room-class.html#change_name 42 | pinder.room.Room.destroy pinder.room.Room-class.html#destroy 43 | pinder.room.Room.guest_invite_code pinder.room.Room-class.html#guest_invite_code 44 | pinder.room.Room.change_topic pinder.room.Room-class.html#change_topic 45 | pinder.room.Room.paste pinder.room.Room-class.html#paste 46 | pinder.room.Room.users pinder.room.Room-class.html#users 47 | pinder.room.Room._get_room_data pinder.room.Room-class.html#_get_room_data 48 | pinder.room.Room.guest_url pinder.room.Room-class.html#guest_url 49 | pinder.room.Room.transcript pinder.room.Room-class.html#transcript 50 | pinder.room.Room.guest_access_enabled pinder.room.Room-class.html#guest_access_enabled 51 | pinder.room.Room.join pinder.room.Room-class.html#join 52 | pinder.room.Room.name pinder.room.Room-class.html#name 53 | pinder.room.Room.uri pinder.room.Room-class.html#uri 54 | pinder.room.Room.leave pinder.room.Room-class.html#leave 55 | pinder.room.Room.__repr__ pinder.room.Room-class.html#__repr__ 56 | pinder.room.Room.transcripts pinder.room.Room-class.html#transcripts 57 | -------------------------------------------------------------------------------- /doc/api/module-tree.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Module Hierarchy 7 | 8 | 9 | 10 | 11 | 13 | 14 | 16 | 17 | 18 | 20 | 21 | 22 | 24 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 49 | 50 |
  45 | 46 | 47 |
48 |
51 |
52 | [ Module Hierarchy 53 | | Class Hierarchy ] 54 |

55 |

Module Hierarchy

56 | 64 | 65 | 67 | 68 | 69 | 71 | 72 | 73 | 75 | 76 | 77 | 79 | 80 | 81 | 83 | 84 | 85 | 90 | 91 | 92 | 93 | 94 | 97 | 101 | 102 |
103 | 104 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /doc/api/class-tree.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Class Hierarchy 7 | 8 | 9 | 10 | 11 | 13 | 14 | 16 | 17 | 18 | 20 | 21 | 22 | 24 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 49 | 50 |
  45 | 46 | 47 |
48 |
51 |
52 | [ Module Hierarchy 53 | | Class Hierarchy ] 54 |

55 |

Class Hierarchy

56 |
    57 |
  • object: 58 | The most base type 59 | 68 |
  • 69 |
70 | 71 | 73 | 74 | 75 | 77 | 78 | 79 | 81 | 82 | 83 | 85 | 86 | 87 | 89 | 90 | 91 | 96 | 97 | 98 | 99 | 100 | 103 | 107 | 108 |
109 | 110 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /doc/api/pinder.room-module.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | pinder.room 7 | 8 | 9 | 10 | 11 | 13 | 14 | 16 | 17 | 18 | 20 | 21 | 22 | 24 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 49 | 54 | 55 |
44 | 45 | Package pinder :: 46 | Module room 47 | 48 | 50 | 51 | 52 |
53 |
56 | 57 |

Module room

source code

58 |

Handles the Campfire room.

59 | 60 | 61 | 62 | 64 | 65 | 67 | 68 | 69 | 75 | 76 |
66 | Classes
70 |   71 | 72 | Room
73 | A Campfire room. 74 |
77 | 78 | 80 | 81 | 82 | 84 | 85 | 86 | 88 | 89 | 90 | 92 | 93 | 94 | 96 | 97 | 98 | 103 | 104 | 105 | 106 | 107 | 110 | 114 | 115 |
116 | 117 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /doc/api/pinder.campfire-module.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | pinder.campfire 7 | 8 | 9 | 10 | 11 | 13 | 14 | 16 | 17 | 18 | 20 | 21 | 22 | 24 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 49 | 54 | 55 |
44 | 45 | Package pinder :: 46 | Module campfire 47 | 48 | 50 | 51 | 52 |
53 |
56 | 57 |

Module campfire

source code

58 |

Handles Campfire online chat.

59 | 60 |
61 |

Version: 62 | 0.6.5 63 |

64 |
65 | 66 | 68 | 69 | 71 | 72 | 73 | 80 | 81 |
70 | Classes
74 |   75 | 76 | Campfire
77 | Creates a connection to the Campfire account with the given 78 | subdomain. 79 |
82 | 83 | 85 | 86 | 87 | 89 | 90 | 91 | 93 | 94 | 95 | 97 | 98 | 99 | 101 | 102 | 103 | 108 | 109 | 110 | 111 | 112 | 115 | 119 | 120 |
121 | 122 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /doc/api/index.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | pinder 7 | 8 | 9 | 10 | 11 | 13 | 14 | 16 | 17 | 18 | 20 | 21 | 22 | 24 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 48 | 53 | 54 |
44 | 45 | Package pinder 46 | 47 | 49 | 50 | 51 |
52 |
55 | 56 |

Package pinder

source code

57 |

Campfire Python API.

58 | 59 |
60 |

Version: 61 | 0.6.5 62 |

63 |

Author: 64 | Lawrence Oluyede (oluyede.org) 65 |

66 |

Copyright: 67 | Copyright (c) 2007, 2008 Lawrence Oluyede 68 |

69 |

License: 70 | BSD 71 |

72 |
73 | 74 | 76 | 77 | 79 | 80 | 85 |
78 | Submodules
81 |
86 | 87 |
88 | 89 | 91 | 92 | 93 | 95 | 96 | 97 | 99 | 100 | 101 | 103 | 104 | 105 | 107 | 108 | 109 | 114 | 115 | 116 | 117 | 118 | 121 | 125 | 126 |
127 | 128 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /doc/api/pinder-module.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | pinder 7 | 8 | 9 | 10 | 11 | 13 | 14 | 16 | 17 | 18 | 20 | 21 | 22 | 24 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 48 | 53 | 54 |
44 | 45 | Package pinder 46 | 47 | 49 | 50 | 51 |
52 |
55 | 56 |

Package pinder

source code

57 |

Campfire Python API.

58 | 59 |
60 |

Version: 61 | 0.6.5 62 |

63 |

Author: 64 | Lawrence Oluyede (oluyede.org) 65 |

66 |

Copyright: 67 | Copyright (c) 2007, 2008 Lawrence Oluyede 68 |

69 |

License: 70 | BSD 71 |

72 |
73 | 74 | 76 | 77 | 79 | 80 | 85 |
78 | Submodules
81 |
86 | 87 |
88 | 89 | 91 | 92 | 93 | 95 | 96 | 97 | 99 | 100 | 101 | 103 | 104 | 105 | 107 | 108 | 109 | 114 | 115 | 116 | 117 | 118 | 121 | 125 | 126 |
127 | 128 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /doc/api/pinder-pysrc.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | pinder 7 | 8 | 9 | 10 | 11 | 13 | 14 | 16 | 17 | 18 | 20 | 21 | 22 | 24 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 48 | 53 | 54 |
44 | 45 | Package pinder 46 | 47 | 49 | 50 | 51 |
52 |
55 |

Source Code for Package pinder

56 |
 57 |  1  """ 
 58 |  2  Campfire Python API. 
 59 |  3  """ 
 60 |  4   
 61 |  5  __author__ = "Lawrence Oluyede (oluyede.org)" 
 62 |  6  __version__ = '0.6.5' 
 63 |  7  __copyright__ = "Copyright (c) 2007, 2008 Lawrence Oluyede" 
 64 |  8  __license__ = "BSD" 
 65 |  9   
 66 | 10  from campfire import * 
 67 | 11  from room import * 
 68 | 12   
 73 | 
74 |
75 | 76 | 78 | 79 | 80 | 82 | 83 | 84 | 86 | 87 | 88 | 90 | 91 | 92 | 94 | 95 | 96 | 101 | 102 | 103 | 104 | 105 | 108 | 112 | 113 |
114 | 115 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /test/test_campfire.py: -------------------------------------------------------------------------------- 1 | from httplib import HTTPConnection 2 | import unittest 3 | from urlparse import urlparse 4 | 5 | import httplib2 6 | 7 | from pinder import Campfire 8 | import utils 9 | 10 | class CampfireTest(unittest.TestCase): 11 | def setUp(self): 12 | self.response = utils.MockResponse() 13 | self.campfire = Campfire('foobar') 14 | response = self.response 15 | HTTPConnection.request = lambda self, m, l, b, h: None 16 | HTTPConnection.getresponse = lambda self: response 17 | httplib2.Response = utils.MockHttplib2Response 18 | 19 | def test_creation(self): 20 | self.assertEqual('foobar', self.campfire.subdomain) 21 | self.assertEqual(False, self.campfire.logged_in) 22 | self.assertEqual(None, self.campfire.cookie) 23 | uri = 'http://foobar.campfirenow.com' 24 | self.assertEqual(urlparse(uri), self.campfire.uri) 25 | self.assertEqual(self.campfire._uri_for(), '%s/' % uri) 26 | 27 | def test_ssl(self): 28 | campfire = Campfire('foobar', True) 29 | uri = 'https://foobar.campfirenow.com' 30 | self.assertEqual(urlparse(uri), campfire.uri) 31 | 32 | def test_verify_response_success(self): 33 | self.response.status = 200 34 | self.assertEqual(True, self.campfire._verify_response(self.response, 35 | success=True)) 36 | 37 | def test_verify_response_redirect_true(self): 38 | self.response.status = 302 39 | self.assertEqual(True, self.campfire._verify_response(self.response, 40 | redirect=True)) 41 | 42 | def test_verify_response_redirect_false(self): 43 | self.response.status = 200 44 | self.assertEqual(False, self.campfire._verify_response(self.response, 45 | redirect=True)) 46 | 47 | def test_verify_response_redirect_to(self): 48 | self.response.status = 304 49 | self.assertEqual(True, self.campfire._verify_response(self.response, 50 | redirect_to='/foobar')) 51 | 52 | def test_verify_response_redirect_to_without_redirect(self): 53 | self.response.status = 200 54 | self.assertEqual(False, self.campfire._verify_response(self.response, 55 | redirect_to='/foobar')) 56 | 57 | def test_verify_response_redirect_to_wrong_path(self): 58 | response = utils.MockResponse() 59 | response.headers['location'] = '/baz' 60 | response.status = 304 61 | self.assertEqual(False, self.campfire._verify_response(response, 62 | redirect_to='/foobar')) 63 | 64 | def test_prepare_request(self): 65 | headers = self.campfire._prepare_request() 66 | self.assert_('User-Agent' in headers) 67 | self.assert_(headers['User-Agent'].startswith('Pinder/')) 68 | headers = self.campfire._prepare_request(ajax=True) 69 | self.assert_('X-Requested-With' in headers) 70 | self.campfire.cookie = 'cookie' 71 | headers = self.campfire._prepare_request() 72 | self.assertEqual(headers['cookie'], self.campfire.cookie) 73 | 74 | def test_perform_request(self): 75 | response = self.campfire._perform_request('GET', '') 76 | self.assertEqual(self.campfire.cookie, response.getheader('set-cookie')) 77 | 78 | def test_login(self): 79 | utils.FIXTURE = 'default' 80 | self.response.headers['location'] = self.campfire._uri_for() 81 | self.response.status = 302 82 | self.assertEqual(True, self.campfire.login('foo', 'foopass')) 83 | 84 | def test_find_room_by_name(self): 85 | utils.FIXTURE = 'rooms_names' 86 | room = self.campfire.find_room_by_name('Room A') 87 | self.assert_(room is not None) 88 | self.assert_(self.campfire.find_room_by_name('No Room') is None) 89 | 90 | def test_find_room_by_name_no_rooms(self): 91 | utils.FIXTURE = 'no_rooms' 92 | self.assert_(self.campfire.find_room_by_name('Room A') is None) 93 | 94 | def test_create_room(self): 95 | utils.FIXTURE = 'rooms_names' 96 | name = 'New Room' 97 | self.assert_(self.campfire.find_room_by_name(name) is None) 98 | new_room_markup = self.response.read().splitlines() 99 | new_room_markup.append(""" 100 |

101 | %s 102 |

103 |
""" % name) 104 | self.response.read = lambda: '\n'.join(new_room_markup) 105 | self.assert_(self.campfire.find_room_by_name(name) is not None) 106 | 107 | def test_users_rooms_empty(self): 108 | utils.FIXTURE = 'chat_rooms_empty' 109 | self.assert_(not self.campfire.users()) 110 | 111 | def test_users_rooms_one_empty(self): 112 | utils.FIXTURE = 'chat_rooms_one_empty' 113 | self.assert_('Tom Jones' in self.campfire.users('Room A')) 114 | self.assert_(not self.campfire.users('Room B')) 115 | 116 | def test_users_rooms_not_empty(self): 117 | utils.FIXTURE = 'chat_rooms_not_empty' 118 | users = self.campfire.users() 119 | self.assertEqual(['Tom Jones', 'Gloria Estefan'], list(users)) 120 | 121 | def test_rooms_names(self): 122 | utils.FIXTURE = 'rooms_names' 123 | self.assertEqual(['Room A', 'Room B'], self.campfire.rooms_names()) 124 | 125 | def test_rooms(self): 126 | utils.FIXTURE = 'rooms_names' 127 | from pinder import Room 128 | self.assert_(isinstance(self.campfire.rooms()[0], Room)) 129 | 130 | def test_find_or_create_room_by_name(self): 131 | utils.FIXTURE = 'chat_rooms_empty' 132 | room = self.campfire.find_room_by_name('Room A') 133 | self.assertEqual(room, self.campfire.find_or_create_room_by_name( 134 | 'Room A')) 135 | 136 | def test_room_id_from_url(self): 137 | self.assertEqual(None, self.campfire._room_id_from_uri( 138 | 'http://www.google.com')) 139 | self.assertEqual('1234', self.campfire._room_id_from_uri( 140 | 'http://foo.campfirenow.com/room/1234/foo/bar')) 141 | 142 | def test_transcripts(self): 143 | utils.FIXTURE = 'transcripts' 144 | transcripts = self.campfire.transcripts() 145 | self.assertEqual(2, len(transcripts.keys())) 146 | self.assert_('12345' in transcripts.keys()) 147 | self.assertEqual(2001, transcripts['12345'][0].year) 148 | 149 | def test_transcripts_empty(self): 150 | utils.FIXTURE = 'no_transcripts' 151 | transcripts = self.campfire.transcripts() 152 | self.assertEqual({}, transcripts) 153 | 154 | 155 | if __name__ == '__main__': 156 | unittest.main() 157 | -------------------------------------------------------------------------------- /pinder/campfire.py: -------------------------------------------------------------------------------- 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 | Also accepts a boolean indicating whether the connection should be made with 24 | SSL or not (default: False).""" 25 | def __init__(self, subdomain, ssl=False): 26 | #: The Campfire's subdomain. 27 | self.subdomain = subdomain 28 | #: True if the user is logged in Campfire, False otherwise. 29 | self.logged_in = False 30 | #: Contains the connection cookie. 31 | self.cookie = None 32 | 33 | # Schema for the Campfire URI 34 | schema = 'http' 35 | if ssl: schema += 's' 36 | 37 | #: The U{urlparsed} URI of the Campfire account. 38 | self.uri = urlparse.urlparse("%s://%s.campfirenow.com" % (schema, self.subdomain)) 39 | self._location = None 40 | self._room_re = re.compile(r'room\/(\d*)') 41 | self._http_client = httplib2.Http(timeout=5) 42 | self._http_client.force_exception_to_status_code = False 43 | 44 | def login(self, email, password): 45 | """Logs into Campfire with the given email and password. 46 | 47 | Returns True if logged in, False otherwise.""" 48 | response = self._post("login", 49 | dict(email_address=email, password=password)) 50 | self.logged_in = self._verify_response(response, 51 | redirect_to=self._uri_for()) 52 | return self.logged_in 53 | 54 | def logout(self): 55 | """Logs out from Campfire. 56 | 57 | Returns True if logged out, False otherwise.""" 58 | retval = self._verify_response(self._get("logout"), redirect=True) 59 | self.logged_in = not retval 60 | return retval 61 | 62 | def create_room(self, name, topic=''): 63 | """Creates a Campfire room with the given name and an optional topic. 64 | 65 | Returns None if the room has not been created.""" 66 | room_data = { 67 | 'room[name]': name, 68 | 'room[topic]': topic 69 | } 70 | response = self._post('account/create/room?from=lobby', room_data, 71 | ajax=True) 72 | if self._verify_response(response, success=True): 73 | return self.find_room_by_name(name) 74 | 75 | def find_room_by_name(self, name): 76 | """Finds a Campfire room with the given name. 77 | 78 | Returns a Room instance if found, None otherwise.""" 79 | rooms = self._get_rooms_markup() 80 | 81 | for room in rooms: 82 | try: 83 | room_name = room.h2.a.string 84 | except AttributeError: # the chat is full 85 | room_name = room.h2.string.strip() 86 | 87 | if room_name.lower() == name.lower(): 88 | try: 89 | room_uri = room.h2.a['href'] 90 | except AttributeError: # no uri available (!?) 91 | return None 92 | 93 | room_id = self._room_id_from_uri(room_uri) 94 | return Room(self, room_id, name) 95 | 96 | def find_or_create_room_by_name(self, name): 97 | """Finds a Campfire room with the given name. 98 | If the room is not present it will be created. 99 | 100 | Returns a Room instance.""" 101 | return self.find_room_by_name(name) or self.create_room(name) 102 | 103 | def users(self, *room_names): 104 | """Lists the users chatting in any room or in the given room(s). 105 | 106 | Returns a set of the users.""" 107 | rooms = self._get_rooms_markup() 108 | 109 | all_users = [] 110 | for room in rooms: 111 | try: 112 | room_name = room.h2.a.string 113 | except AttributeError: # the chat is full 114 | room_name = room.h2.string.strip() 115 | if not room_names or room_name in room_names: 116 | room_users_list = room.find('ul') 117 | if not room_users_list: 118 | break 119 | room_users = room_users_list.findAll('span') 120 | for user in room_users: 121 | all_users.append(user.string) 122 | return set(all_users) 123 | 124 | def rooms_names(self): 125 | """Lists the names of the rooms available in the Campfire subdomain. 126 | 127 | Returns a list of the names of the rooms.""" 128 | rooms = self._get_rooms_markup() 129 | 130 | rooms_names_list = [] 131 | for room in rooms: 132 | try: 133 | rooms_names_list.append(room.h2.a.string) 134 | except AttributeError: 135 | rooms_names_list.append(room.h2.string.strip()) 136 | rooms_names_list.sort() 137 | return rooms_names_list 138 | 139 | def rooms(self): 140 | """Lists the available rooms. 141 | 142 | Returns a list of Room objects.""" 143 | names = self.rooms_names() 144 | return [self.find_room_by_name(name) for name in names] 145 | 146 | def transcripts(self, room_id=None): 147 | """Gets the dates of the transcripts by room filtered by the given id 148 | if any. 149 | 150 | Returns a dictionary of all the dates by room. 151 | """ 152 | uri = 'files%2Btranscripts' 153 | if room_id: 154 | uri = '%s?room_id=%s' % (uri, str(room_id)) 155 | 156 | soup = BeautifulSoup(self._get(uri).body) 157 | 158 | def _filter_transcripts(tag): 159 | return tag.has_key('class') and 'transcript' in tag['class'].split() 160 | transcripts_markup = soup.findAll(_filter_transcripts) 161 | 162 | result = {} 163 | for tag in transcripts_markup: 164 | link = tag.a['href'] 165 | found_room_id = self._room_id_from_uri(link) 166 | date = re.search( 167 | r'/transcript/(\d{4}/\d{2}/\d{2})', link).groups()[0] 168 | try: 169 | result[found_room_id] 170 | except KeyError: 171 | result[found_room_id] = [] 172 | result[found_room_id].append(self._parse_transcript_date(date)) 173 | 174 | if room_id: 175 | return result[str(room_id)] 176 | return result 177 | 178 | def _parse_transcript_date(self, date): 179 | return datetime.date.fromtimestamp(time.mktime( 180 | time.strptime(date, '%Y/%m/%d'))) 181 | 182 | def _filter_rooms_markup(self, tag): 183 | return tag.name == 'div' and tag.has_key('id') and tag['id'].startswith('room_') 184 | 185 | def _get_rooms_markup(self): 186 | body = self._get().body 187 | soup = BeautifulSoup(body) 188 | return soup.findAll(self._filter_rooms_markup) 189 | 190 | def _uri_for(self, path=''): 191 | return "%s/%s" % (urlparse.urlunparse(self.uri), path) 192 | 193 | def _room_id_from_uri(self, uri): 194 | try: 195 | return self._room_re.split(uri)[1] 196 | except IndexError: 197 | pass 198 | 199 | def _prepare_request(self, **options): 200 | headers = {} 201 | 202 | headers['User-Agent'] = 'Pinder/%s' % __version__ 203 | 204 | if self.cookie: 205 | headers['cookie'] = self.cookie 206 | if 'ajax' in options: 207 | headers['X-Requested-With'] = 'XMLHttpRequest' 208 | headers['X-Prototype-Version'] = '1.5.1.1' 209 | return headers 210 | 211 | def _perform_request(self, method, path, data={}, **options): 212 | headers = self._prepare_request(**options) 213 | if method == 'POST': 214 | headers.update({"Content-type": "application/x-www-form-urlencoded"}) 215 | location = self._uri_for(path) 216 | elif method == 'GET': 217 | if self._location: 218 | location = self._location 219 | else: 220 | location = self._uri_for(path) 221 | self._location = None 222 | else: 223 | raise Exception, 'Unsupported HTTP method' 224 | 225 | response, content = self._http_client.request(location, method, 226 | urllib.urlencode(data), headers) 227 | response.body = content 228 | 229 | if response.get('set-cookie'): 230 | self.cookie = response.get('set-cookie') 231 | 232 | return response 233 | 234 | def _post(self, path, data={}, **options): 235 | return self._perform_request('POST', path, data, **options) 236 | 237 | def _get(self, path=''): 238 | return self._perform_request('GET', path) 239 | 240 | def _verify_response(self, response, **options): 241 | if 'success' in options: 242 | return response.status == 200 243 | elif 'redirect' in options: 244 | return response.status in xrange(300, 400) 245 | elif 'redirect_to' in options: 246 | location = response.get('location') 247 | return self._verify_response( 248 | response, redirect=True) and location == options['redirect_to'] 249 | else: 250 | return False 251 | 252 | 253 | __all__ = ['Campfire'] 254 | -------------------------------------------------------------------------------- /pinder/room.py: -------------------------------------------------------------------------------- 1 | """ 2 | Handles the Campfire room. 3 | """ 4 | from datetime import datetime 5 | import re 6 | import time 7 | import urlparse 8 | 9 | from BeautifulSoup import BeautifulSoup 10 | 11 | class Room(object): 12 | "A Campfire room." 13 | def __init__(self, campfire, id, name=None): 14 | self._campfire = campfire 15 | self._verify_response = campfire._verify_response 16 | self._post = campfire._post 17 | self._get = campfire._get 18 | self._room = None 19 | 20 | self.membership_key = self.user_id = None 21 | self.last_cache_id = self.timestamp = None 22 | self.idle_since = datetime.now() 23 | 24 | #: The room id. 25 | self.id = id 26 | #: The name of the room. 27 | self.name = name 28 | #: The U{urlparsed} URI of the room. 29 | self.uri = urlparse.urlparse("%s/room/%s" % (urlparse.urlunparse(self._campfire.uri), self.id)) 30 | 31 | def __repr__(self): 32 | return "" % self.name 33 | 34 | def __eq__(self, other): 35 | return self.id == other.id 36 | 37 | def join(self, force=False): 38 | """Joins the room; if 'force' is True join even if already joined. 39 | 40 | Returns True if successfully joined, False otherwise. """ 41 | if not self._room or force: 42 | self._room = self._get("room/%s" % self.id) 43 | if not self._verify_response(self._room, success=True): 44 | self._room = None 45 | return False 46 | self._get_room_data() 47 | self.ping() 48 | return True 49 | 50 | def leave(self): 51 | """Leaves the room. 52 | 53 | Returns True if successfully left, False otherwise.""" 54 | has_left = self._verify_response( 55 | self._post('room/%s/leave' % self.id), redirect=True) 56 | self._room = self.membership_key = self.user_id = None 57 | self.last_cache_id = self.timestamp = self.idle_since = None 58 | return has_left 59 | 60 | def toggle_guest_access(self): 61 | """Toggles guest access on and off. 62 | 63 | Returns True if successfully toggled, False otherwise.""" 64 | response_result = self._verify_response( 65 | self._post( 66 | 'room/%s/toggle_guest_access' % self.id), success=True) 67 | 68 | # go back inside to toggle the guest access 69 | return response_result and self.join(True) 70 | 71 | def guest_access_enabled(self): 72 | """Checks if the guest access is enabled. 73 | 74 | Returns True if the guest access is enabled, False otherwise.""" 75 | return self.guest_url() is not None 76 | 77 | def guest_url(self): 78 | """Gets the URL for guest access. 79 | 80 | Returns None if the guest access is not enabled.""" 81 | self.join() 82 | soup = BeautifulSoup(self._room.body) 83 | try: 84 | return soup.find('div', {'id': 'guest_access_control'}).h4.string 85 | except AttributeError: 86 | return None 87 | 88 | def guest_invite_code(self): 89 | """Gets the invite code for guest access. 90 | 91 | Returns None if the guest access is not enabled.""" 92 | url = self.guest_url() 93 | if url: 94 | return re.search(r'\/(\w*)$', url).groups(0)[0] 95 | 96 | def change_name(self, name): 97 | """Changes the name of the room. 98 | 99 | Returns the new name if successfully changed, None otherwise.""" 100 | response = self._post('account/edit/room/%s' % self.id, 101 | {'room[name]': name}, ajax=True) 102 | if self._verify_response(response, success=True): 103 | self.name = name 104 | return self.name 105 | rename = change_name 106 | 107 | def change_topic(self, topic): 108 | """Changes the topic of the room. 109 | 110 | Returns the new topic if successfully changed, None otherwise.""" 111 | response = self._post('room/%s/change_topic' % self.id, 112 | {'room[topic]': topic}, ajax=True) 113 | if self._verify_response(response, success=True): 114 | return topic 115 | 116 | def topic(self): 117 | """Gets the current topic, if any.""" 118 | self.join() 119 | soup = BeautifulSoup(self._room.body) 120 | h = soup.find(attrs={'id': 'topic'}) 121 | if h: 122 | def _is_navigable_string(tag): 123 | return not hasattr(tag, 'attrs') 124 | topic = filter(_is_navigable_string, h.contents) 125 | return repr("".join(topic).strip()) 126 | 127 | def lock(self): 128 | """Locks the room to prevent new users from entering. 129 | 130 | Returns True if successfully locked, False otherwise.""" 131 | return self._verify_response(self._post( 132 | 'room/%s/lock' % self.id, {}, ajax=True), success=True) 133 | 134 | def unlock(self): 135 | """Unlocks the room. 136 | 137 | Returns True if successfully unlocked, False otherwise.""" 138 | return self._verify_response(self._post( 139 | 'room/%s/unlock' % self.id, {}, ajax=True), success=True) 140 | 141 | def ping(self, force=False): 142 | """Pings the server updating the last time we have been seen there. 143 | 144 | Returns True if successfully pinged, False otherwise.""" 145 | now = datetime.now() 146 | delta = now - self.idle_since 147 | if delta.seconds < 60 or force: 148 | self.idle_since = datetime.now() 149 | return self._verify_response(self._post( 150 | 'room/%s/tabs' % self.id, {}, ajax=True), success=True) 151 | return False 152 | 153 | def destroy(self): 154 | """Destroys the room. 155 | 156 | Returns True if successfully destroyed, False otherwise.""" 157 | return self._verify_response(self._post( 158 | 'account/delete/room/%s' % self.id), success=True) 159 | 160 | def users(self): 161 | """Lists the users chatting in the room. 162 | 163 | Returns a set of the users.""" 164 | return self._campfire.users(self.name) 165 | 166 | def speak(self, message): 167 | """Send a message to the room. 168 | 169 | Returns the message if successfully sent it, None otherwise.""" 170 | self.join() 171 | return self._send(message) 172 | 173 | def paste(self, message): 174 | """Paste a message to the room. 175 | 176 | Returns the message if successfully pasted it, None otherwise.""" 177 | self.join() 178 | return self._send(message, {'paste': True}) 179 | 180 | def messages(self): 181 | """Gets new messages. 182 | 183 | Returns a list of message data: 184 | * id: the id of the message 185 | * person: the name of the person who wrote the message if any 186 | * user_id: the user id of the person if any 187 | * message: the message itself if any""" 188 | data = dict(l=self.last_cache_id, m=self.membership_key, 189 | s=self.timestamp, t=int(time.time())) 190 | response = self._post("poll.fcgi", data, ajax=True) 191 | 192 | cache_match = re.search(r'lastCacheID = (\d+)', response.body) 193 | if cache_match: 194 | self.last_cache_id = cache_match.groups(0)[0] 195 | 196 | messages = [] 197 | 198 | for line in response.body.split("\r\n"): 199 | if 'timestamp_message' in line: 200 | continue 201 | 202 | id_match = re.search(r'message_(\d+)', line) 203 | if not id_match: 204 | continue 205 | 206 | try: 207 | messages.append(dict( 208 | id = id_match.groups(0)[0], 209 | user_id = re.search(r'user_(\d+)', line).groups(0)[0], 210 | person = re.search(r'\\u003Ctd class=\\"person\\"\\u003E(?:\\u003Cspan\\u003E)?(.+?)(?:\\u003C\/span\\u003E)?\\u003C\/td\\u003E', line).groups(0)[0], 211 | message = re.search(r'\\u003Ctd class=\\"body\\"\\u003E\\u003Cdiv\\u003E(.+?)\\u003C\/div\\u003E\\u003C\/td\\u003E', line).groups(0)[0] 212 | )) 213 | except AttributeError: 214 | continue 215 | 216 | return messages 217 | 218 | def transcripts(self): 219 | """Gets the dates of transcripts of the room. 220 | 221 | Returns a list of dates.""" 222 | return self._campfire.transcripts(self.id) 223 | 224 | def transcript(self, date): 225 | """Get the transcript for the given date (a datetime.date instance). 226 | 227 | Returns a list of message data: 228 | * id: the id of the message 229 | * person: the name of the person who wrote the message if any 230 | * user_id: the user id of the person if any 231 | * message: the message itself if any""" 232 | uri = 'room/%s/transcript/%s' % (self.id, date.strftime('%Y/%m/%d')) 233 | 234 | soup = BeautifulSoup(self._get(uri).body) 235 | 236 | def _filter_messages(tag): 237 | return tag.has_key('class') and 'message' in tag['class'].split() 238 | messages = soup.findAll(_filter_messages) 239 | 240 | all_transcript = [] 241 | for message in messages: 242 | t = {} 243 | 244 | person = message.find(True, attrs={'class': 'person'}) 245 | try: 246 | t['person'] = person.span.string 247 | except AttributeError: 248 | try: 249 | t['person'] = person.string 250 | except AttributeError: 251 | t['person'] = None 252 | 253 | body = message.find('td', attrs={'class': 'body'}) 254 | try: 255 | t['message'] = body.div.string 256 | except AttributeError: 257 | t['message'] = None 258 | 259 | t['id'] = re.search(r'message_(\d+)', message['id']).groups()[0] 260 | match = re.search(r'user_(\d+)', message['class']) 261 | if match: 262 | t['user_id'] = match.groups()[0] 263 | else: 264 | t['user_id'] = None 265 | 266 | all_transcript.append(t) 267 | 268 | return all_transcript 269 | 270 | def _send(self, message, options={}): 271 | data = {'message': message, 't': int(time.time())} 272 | data.update(options) 273 | response = self._post('room/%s/speak' % self.id, data, ajax=True) 274 | if self._verify_response(response, success=True): 275 | return message 276 | 277 | def _get_room_data(self): 278 | self.membership_key = re.search(r'\"membershipKey\":\s?\"([a-z0-9]+)\"', 279 | self._room.body).groups(0)[0] 280 | self.user_id = re.search(r'\"userID\":\s?(\d+)', 281 | self._room.body).groups(0)[0] 282 | self.last_cache_id = re.search(r'\"lastCacheID\":\s?(\d+)', 283 | self._room.body).groups(0)[0] 284 | self.timestamp = re.search(r'\"timestamp\":\s?(\d+)', 285 | self._room.body).groups(0)[0] 286 | 287 | 288 | 289 | __all__ = ['Room'] 290 | -------------------------------------------------------------------------------- /doc/api/epydoc.js: -------------------------------------------------------------------------------- 1 | function toggle_private() { 2 | // Search for any private/public links on this page. Store 3 | // their old text in "cmd," so we will know what action to 4 | // take; and change their text to the opposite action. 5 | var cmd = "?"; 6 | var elts = document.getElementsByTagName("a"); 7 | for(var i=0; i...
"; 127 | elt.innerHTML = s; 128 | } 129 | } 130 | 131 | function toggle(id) { 132 | elt = document.getElementById(id+"-toggle"); 133 | if (elt.innerHTML == "-") 134 | collapse(id); 135 | else 136 | expand(id); 137 | return false; 138 | } 139 | 140 | function highlight(id) { 141 | var elt = document.getElementById(id+"-def"); 142 | if (elt) elt.className = "py-highlight-hdr"; 143 | var elt = document.getElementById(id+"-expanded"); 144 | if (elt) elt.className = "py-highlight"; 145 | var elt = document.getElementById(id+"-collapsed"); 146 | if (elt) elt.className = "py-highlight"; 147 | } 148 | 149 | function num_lines(s) { 150 | var n = 1; 151 | var pos = s.indexOf("\n"); 152 | while ( pos > 0) { 153 | n += 1; 154 | pos = s.indexOf("\n", pos+1); 155 | } 156 | return n; 157 | } 158 | 159 | // Collapse all blocks that mave more than `min_lines` lines. 160 | function collapse_all(min_lines) { 161 | var elts = document.getElementsByTagName("div"); 162 | for (var i=0; i 0) 166 | if (elt.id.substring(split, elt.id.length) == "-expanded") 167 | if (num_lines(elt.innerHTML) > min_lines) 168 | collapse(elt.id.substring(0, split)); 169 | } 170 | } 171 | 172 | function expandto(href) { 173 | var start = href.indexOf("#")+1; 174 | if (start != 0 && start != href.length) { 175 | if (href.substring(start, href.length) != "-") { 176 | collapse_all(4); 177 | pos = href.indexOf(".", start); 178 | while (pos != -1) { 179 | var id = href.substring(start, pos); 180 | expand(id); 181 | pos = href.indexOf(".", pos+1); 182 | } 183 | var id = href.substring(start, href.length); 184 | expand(id); 185 | highlight(id); 186 | } 187 | } 188 | } 189 | 190 | function kill_doclink(id) { 191 | var parent = document.getElementById(id); 192 | parent.removeChild(parent.childNodes.item(0)); 193 | } 194 | function auto_kill_doclink(ev) { 195 | if (!ev) var ev = window.event; 196 | if (!this.contains(ev.toElement)) { 197 | var parent = document.getElementById(this.parentID); 198 | parent.removeChild(parent.childNodes.item(0)); 199 | } 200 | } 201 | 202 | function doclink(id, name, targets_id) { 203 | var elt = document.getElementById(id); 204 | 205 | // If we already opened the box, then destroy it. 206 | // (This case should never occur, but leave it in just in case.) 207 | if (elt.childNodes.length > 1) { 208 | elt.removeChild(elt.childNodes.item(0)); 209 | } 210 | else { 211 | // The outer box: relative + inline positioning. 212 | var box1 = document.createElement("div"); 213 | box1.style.position = "relative"; 214 | box1.style.display = "inline"; 215 | box1.style.top = 0; 216 | box1.style.left = 0; 217 | 218 | // A shadow for fun 219 | var shadow = document.createElement("div"); 220 | shadow.style.position = "absolute"; 221 | shadow.style.left = "-1.3em"; 222 | shadow.style.top = "-1.3em"; 223 | shadow.style.background = "#404040"; 224 | 225 | // The inner box: absolute positioning. 226 | var box2 = document.createElement("div"); 227 | box2.style.position = "relative"; 228 | box2.style.border = "1px solid #a0a0a0"; 229 | box2.style.left = "-.2em"; 230 | box2.style.top = "-.2em"; 231 | box2.style.background = "white"; 232 | box2.style.padding = ".3em .4em .3em .4em"; 233 | box2.style.fontStyle = "normal"; 234 | box2.onmouseout=auto_kill_doclink; 235 | box2.parentID = id; 236 | 237 | // Get the targets 238 | var targets_elt = document.getElementById(targets_id); 239 | var targets = targets_elt.getAttribute("targets"); 240 | var links = ""; 241 | target_list = targets.split(","); 242 | for (var i=0; i" + 246 | target[0] + ""; 247 | } 248 | 249 | // Put it all together. 250 | elt.insertBefore(box1, elt.childNodes.item(0)); 251 | //box1.appendChild(box2); 252 | box1.appendChild(shadow); 253 | shadow.appendChild(box2); 254 | box2.innerHTML = 255 | "Which "+name+" do you want to see documentation for?" + 256 | ""; 261 | } 262 | return false; 263 | } 264 | 265 | function get_anchor() { 266 | var href = location.href; 267 | var start = href.indexOf("#")+1; 268 | if ((start != 0) && (start != href.length)) 269 | return href.substring(start, href.length); 270 | } 271 | function redirect_url(dottedName) { 272 | // Scan through each element of the "pages" list, and check 273 | // if "name" matches with any of them. 274 | for (var i=0; i-m" or "-c"; 277 | // extract the portion & compare it to dottedName. 278 | var pagename = pages[i].substring(0, pages[i].length-2); 279 | if (pagename == dottedName.substring(0,pagename.length)) { 280 | 281 | // We've found a page that matches `dottedName`; 282 | // construct its URL, using leftover `dottedName` 283 | // content to form an anchor. 284 | var pagetype = pages[i].charAt(pages[i].length-1); 285 | var url = pagename + ((pagetype=="m")?"-module.html": 286 | "-class.html"); 287 | if (dottedName.length > pagename.length) 288 | url += "#" + dottedName.substring(pagename.length+1, 289 | dottedName.length); 290 | return url; 291 | } 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /doc/api/help.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Help 7 | 8 | 9 | 10 | 11 | 13 | 14 | 16 | 17 | 18 | 20 | 21 | 22 | 24 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 49 | 50 |
  45 | 46 | 47 |
48 |
51 | 52 |

API Documentation

53 | 54 |

This document contains the API (Application Programming Interface) 55 | documentation for Pinder. Documentation for the Python 56 | objects defined by the project is divided into separate pages for each 57 | package, module, and class. The API documentation also includes two 58 | pages containing information about the project as a whole: a trees 59 | page, and an index page.

60 | 61 |

Object Documentation

62 | 63 |

Each Package Documentation page contains:

64 |
    65 |
  • A description of the package.
  • 66 |
  • A list of the modules and sub-packages contained by the 67 | package.
  • 68 |
  • A summary of the classes defined by the package.
  • 69 |
  • A summary of the functions defined by the package.
  • 70 |
  • A summary of the variables defined by the package.
  • 71 |
  • A detailed description of each function defined by the 72 | package.
  • 73 |
  • A detailed description of each variable defined by the 74 | package.
  • 75 |
76 | 77 |

Each Module Documentation page contains:

78 |
    79 |
  • A description of the module.
  • 80 |
  • A summary of the classes defined by the module.
  • 81 |
  • A summary of the functions defined by the module.
  • 82 |
  • A summary of the variables defined by the module.
  • 83 |
  • A detailed description of each function defined by the 84 | module.
  • 85 |
  • A detailed description of each variable defined by the 86 | module.
  • 87 |
88 | 89 |

Each Class Documentation page contains:

90 |
    91 |
  • A class inheritance diagram.
  • 92 |
  • A list of known subclasses.
  • 93 |
  • A description of the class.
  • 94 |
  • A summary of the methods defined by the class.
  • 95 |
  • A summary of the instance variables defined by the class.
  • 96 |
  • A summary of the class (static) variables defined by the 97 | class.
  • 98 |
  • A detailed description of each method defined by the 99 | class.
  • 100 |
  • A detailed description of each instance variable defined by the 101 | class.
  • 102 |
  • A detailed description of each class (static) variable defined 103 | by the class.
  • 104 |
105 | 106 |

Project Documentation

107 | 108 |

The Trees page contains the module and class hierarchies:

109 |
    110 |
  • The module hierarchy lists every package and module, with 111 | modules grouped into packages. At the top level, and within each 112 | package, modules and sub-packages are listed alphabetically.
  • 113 |
  • The class hierarchy lists every class, grouped by base 114 | class. If a class has more than one base class, then it will be 115 | listed under each base class. At the top level, and under each base 116 | class, classes are listed alphabetically.
  • 117 |
118 | 119 |

The Index page contains indices of terms and 120 | identifiers:

121 |
    122 |
  • The term index lists every term indexed by any object's 123 | documentation. For each term, the index provides links to each 124 | place where the term is indexed.
  • 125 |
  • The identifier index lists the (short) name of every package, 126 | module, class, method, function, variable, and parameter. For each 127 | identifier, the index provides a short description, and a link to 128 | its documentation.
  • 129 |
130 | 131 |

The Table of Contents

132 | 133 |

The table of contents occupies the two frames on the left side of 134 | the window. The upper-left frame displays the project 135 | contents, and the lower-left frame displays the module 136 | contents:

137 | 138 | 139 | 140 | 142 | 145 | 146 | 147 | 150 | 151 |
141 | Project
Contents
...
143 | API
Documentation
Frame


144 |
148 | Module
Contents
 
...
  149 |

152 | 153 |

The project contents frame contains a list of all packages 154 | and modules that are defined by the project. Clicking on an entry 155 | will display its contents in the module contents frame. Clicking on a 156 | special entry, labeled "Everything," will display the contents of 157 | the entire project.

158 | 159 |

The module contents frame contains a list of every 160 | submodule, class, type, exception, function, and variable defined by a 161 | module or package. Clicking on an entry will display its 162 | documentation in the API documentation frame. Clicking on the name of 163 | the module, at the top of the frame, will display the documentation 164 | for the module itself.

165 | 166 |

The "frames" and "no frames" buttons below the top 167 | navigation bar can be used to control whether the table of contents is 168 | displayed or not.

169 | 170 |

The Navigation Bar

171 | 172 |

A navigation bar is located at the top and bottom of every page. 173 | It indicates what type of page you are currently viewing, and allows 174 | you to go to related pages. The following table describes the labels 175 | on the navigation bar. Note that not some labels (such as 176 | [Parent]) are not displayed on all pages.

177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 191 | 192 | 193 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 |
LabelHighlighted when...Links to...
[Parent](never highlighted) the parent of the current package
[Package]viewing a packagethe package containing the current object 190 |
[Module]viewing a modulethe module containing the current object 194 |
[Class]viewing a class the class containing the current object
[Trees]viewing the trees page the trees page
[Index]viewing the index page the index page
[Help]viewing the help page the help page
208 | 209 |

The "show private" and "hide private" buttons below 210 | the top navigation bar can be used to control whether documentation 211 | for private objects is displayed. Private objects are usually defined 212 | as objects whose (short) names begin with a single underscore, but do 213 | not end with an underscore. For example, "_x", 214 | "__pprint", and "epydoc.epytext._tokenize" 215 | are private objects; but "re.sub", 216 | "__init__", and "type_" are not. However, 217 | if a module defines the "__all__" variable, then its 218 | contents are used to decide which objects are private.

219 | 220 |

A timestamp below the bottom navigation bar indicates when each 221 | page was last updated.

222 | 223 | 225 | 226 | 227 | 229 | 230 | 231 | 233 | 234 | 235 | 237 | 238 | 239 | 241 | 242 | 243 | 248 | 249 | 250 | 251 | 252 | 255 | 259 | 260 |
261 | 262 | 271 | 272 | 273 | -------------------------------------------------------------------------------- /doc/api/identifier-index.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Identifier Index 7 | 8 | 9 | 10 | 11 | 13 | 14 | 16 | 17 | 18 | 20 | 21 | 22 | 24 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 49 | 50 |
  45 | 46 | 47 |
48 |
51 | 52 |
53 |

Identifier Index

54 |
55 | [ 56 | A 57 | B 58 | C 59 | D 60 | E 61 | F 62 | G 63 | H 64 | I 65 | J 66 | K 67 | L 68 | M 69 | N 70 | O 71 | P 72 | Q 73 | R 74 | S 75 | T 76 | U 77 | V 78 | W 79 | X 80 | Y 81 | Z 82 | _ 83 | ] 84 |
85 | 86 | 87 | 106 | 107 | 118 | 119 | 131 | 132 | 145 | 146 | 157 | 158 | 176 | 177 | 189 | 190 | 208 | 209 | 220 | 221 | 240 | 241 | 254 | 255 | 273 |

C

88 | 89 | 90 | 92 | 94 | 96 | 97 | 98 | 100 | 102 | 103 | 104 | 105 |

D

108 | 109 | 110 | 112 | 113 | 114 | 115 | 116 | 117 |

F

120 | 121 | 122 | 124 | 126 | 127 | 128 | 129 | 130 |

G

133 | 134 | 135 | 137 | 139 | 141 | 142 | 143 | 144 |

J

147 | 148 | 149 | 151 | 152 | 153 | 154 | 155 | 156 |

L

159 | 160 | 161 | 163 | 165 | 166 | 167 | 168 | 170 | 172 | 173 | 174 | 175 |

P

178 | 179 | 180 | 182 | 183 | 185 | 186 | 187 | 188 |

R

191 | 192 | 193 | 195 | 197 | 198 | 199 | 200 | 202 | 204 | 205 | 206 | 207 |

S

210 | 211 | 212 | 214 | 215 | 216 | 217 | 218 | 219 |

T

222 | 223 | 224 | 226 | 228 | 230 | 231 | 232 | 234 | 236 | 237 | 238 | 239 |

U

242 | 243 | 244 | 246 | 248 | 250 | 251 | 252 | 253 |

_

256 | 257 | 258 | 260 | 262 | 263 | 264 | 265 | 267 | 269 | 270 | 271 | 272 |
274 |

275 | 277 | 278 | 279 | 281 | 282 | 283 | 285 | 286 | 287 | 289 | 290 | 291 | 293 | 294 | 295 | 300 | 301 | 302 | 303 | 304 | 307 | 311 | 312 |
313 | 314 | 323 | 324 | 325 | -------------------------------------------------------------------------------- /doc/api/epydoc.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* Epydoc CSS Stylesheet 4 | * 5 | * This stylesheet can be used to customize the appearance of epydoc's 6 | * HTML output. 7 | * 8 | */ 9 | 10 | /* Default Colors & Styles 11 | * - Set the default foreground & background color with 'body'; and 12 | * link colors with 'a:link' and 'a:visited'. 13 | * - Use bold for decision list terms. 14 | * - The heading styles defined here are used for headings *within* 15 | * docstring descriptions. All headings used by epydoc itself use 16 | * either class='epydoc' or class='toc' (CSS styles for both 17 | * defined below). 18 | */ 19 | body { background: #ffffff; color: #000000; } 20 | p { margin-top: 0.5em; margin-bottom: 0.5em; } 21 | a:link { color: #0000ff; } 22 | a:visited { color: #204080; } 23 | dt { font-weight: bold; } 24 | h1 { font-size: +140%; font-style: italic; 25 | font-weight: bold; } 26 | h2 { font-size: +125%; font-style: italic; 27 | font-weight: bold; } 28 | h3 { font-size: +110%; font-style: italic; 29 | font-weight: normal; } 30 | code { font-size: 100%; } 31 | /* N.B.: class, not pseudoclass */ 32 | a.link { font-family: monospace; } 33 | 34 | /* Page Header & Footer 35 | * - The standard page header consists of a navigation bar (with 36 | * pointers to standard pages such as 'home' and 'trees'); a 37 | * breadcrumbs list, which can be used to navigate to containing 38 | * classes or modules; options links, to show/hide private 39 | * variables and to show/hide frames; and a page title (using 40 | *

). The page title may be followed by a link to the 41 | * corresponding source code (using 'span.codelink'). 42 | * - The footer consists of a navigation bar, a timestamp, and a 43 | * pointer to epydoc's homepage. 44 | */ 45 | h1.epydoc { margin: 0; font-size: +140%; font-weight: bold; } 46 | h2.epydoc { font-size: +130%; font-weight: bold; } 47 | h3.epydoc { font-size: +115%; font-weight: bold; 48 | margin-top: 0.2em; } 49 | td h3.epydoc { font-size: +115%; font-weight: bold; 50 | margin-bottom: 0; } 51 | table.navbar { background: #a0c0ff; color: #000000; 52 | border: 2px groove #c0d0d0; } 53 | table.navbar table { color: #000000; } 54 | th.navbar-select { background: #70b0ff; 55 | color: #000000; } 56 | table.navbar a { text-decoration: none; } 57 | table.navbar a:link { color: #0000ff; } 58 | table.navbar a:visited { color: #204080; } 59 | span.breadcrumbs { font-size: 85%; font-weight: bold; } 60 | span.options { font-size: 70%; } 61 | span.codelink { font-size: 85%; } 62 | td.footer { font-size: 85%; } 63 | 64 | /* Table Headers 65 | * - Each summary table and details section begins with a 'header' 66 | * row. This row contains a section title (marked by 67 | * 'span.table-header') as well as a show/hide private link 68 | * (marked by 'span.options', defined above). 69 | * - Summary tables that contain user-defined groups mark those 70 | * groups using 'group header' rows. 71 | */ 72 | td.table-header { background: #70b0ff; color: #000000; 73 | border: 1px solid #608090; } 74 | td.table-header table { color: #000000; } 75 | td.table-header table a:link { color: #0000ff; } 76 | td.table-header table a:visited { color: #204080; } 77 | span.table-header { font-size: 120%; font-weight: bold; } 78 | th.group-header { background: #c0e0f8; color: #000000; 79 | text-align: left; font-style: italic; 80 | font-size: 115%; 81 | border: 1px solid #608090; } 82 | 83 | /* Summary Tables (functions, variables, etc) 84 | * - Each object is described by a single row of the table with 85 | * two cells. The left cell gives the object's type, and is 86 | * marked with 'code.summary-type'. The right cell gives the 87 | * object's name and a summary description. 88 | * - CSS styles for the table's header and group headers are 89 | * defined above, under 'Table Headers' 90 | */ 91 | table.summary { border-collapse: collapse; 92 | background: #e8f0f8; color: #000000; 93 | border: 1px solid #608090; 94 | margin-bottom: 0.5em; } 95 | td.summary { border: 1px solid #608090; } 96 | code.summary-type { font-size: 85%; } 97 | table.summary a:link { color: #0000ff; } 98 | table.summary a:visited { color: #204080; } 99 | 100 | 101 | /* Details Tables (functions, variables, etc) 102 | * - Each object is described in its own div. 103 | * - A single-row summary table w/ table-header is used as 104 | * a header for each details section (CSS style for table-header 105 | * is defined above, under 'Table Headers'). 106 | */ 107 | table.details { border-collapse: collapse; 108 | background: #e8f0f8; color: #000000; 109 | border: 1px solid #608090; 110 | margin: .2em 0 0 0; } 111 | table.details table { color: #000000; } 112 | table.details a:link { color: #0000ff; } 113 | table.details a:visited { color: #204080; } 114 | 115 | /* Fields */ 116 | dl.fields { margin-left: 2em; margin-top: 1em; 117 | margin-bottom: 1em; } 118 | dl.fields dd ul { margin-left: 0em; padding-left: 0em; } 119 | dl.fields dd ul li ul { margin-left: 2em; padding-left: 0em; } 120 | div.fields { margin-left: 2em; } 121 | div.fields p { margin-bottom: 0.5em; } 122 | 123 | /* Index tables (identifier index, term index, etc) 124 | * - link-index is used for indices containing lists of links 125 | * (namely, the identifier index & term index). 126 | * - index-where is used in link indices for the text indicating 127 | * the container/source for each link. 128 | * - metadata-index is used for indices containing metadata 129 | * extracted from fields (namely, the bug index & todo index). 130 | */ 131 | table.link-index { border-collapse: collapse; 132 | background: #e8f0f8; color: #000000; 133 | border: 1px solid #608090; } 134 | td.link-index { border-width: 0px; } 135 | table.link-index a:link { color: #0000ff; } 136 | table.link-index a:visited { color: #204080; } 137 | span.index-where { font-size: 70%; } 138 | table.metadata-index { border-collapse: collapse; 139 | background: #e8f0f8; color: #000000; 140 | border: 1px solid #608090; 141 | margin: .2em 0 0 0; } 142 | td.metadata-index { border-width: 1px; border-style: solid; } 143 | table.metadata-index a:link { color: #0000ff; } 144 | table.metadata-index a:visited { color: #204080; } 145 | 146 | /* Function signatures 147 | * - sig* is used for the signature in the details section. 148 | * - .summary-sig* is used for the signature in the summary 149 | * table, and when listing property accessor functions. 150 | * */ 151 | .sig-name { color: #006080; } 152 | .sig-arg { color: #008060; } 153 | .sig-default { color: #602000; } 154 | .summary-sig { font-family: monospace; } 155 | .summary-sig-name { color: #006080; font-weight: bold; } 156 | table.summary a.summary-sig-name:link 157 | { color: #006080; font-weight: bold; } 158 | table.summary a.summary-sig-name:visited 159 | { color: #006080; font-weight: bold; } 160 | .summary-sig-arg { color: #006040; } 161 | .summary-sig-default { color: #501800; } 162 | 163 | /* Subclass list 164 | */ 165 | ul.subclass-list { display: inline; } 166 | ul.subclass-list li { display: inline; } 167 | 168 | /* To render variables, classes etc. like functions */ 169 | table.summary .summary-name { color: #006080; font-weight: bold; 170 | font-family: monospace; } 171 | table.summary 172 | a.summary-name:link { color: #006080; font-weight: bold; 173 | font-family: monospace; } 174 | table.summary 175 | a.summary-name:visited { color: #006080; font-weight: bold; 176 | font-family: monospace; } 177 | 178 | /* Variable values 179 | * - In the 'variable details' sections, each varaible's value is 180 | * listed in a 'pre.variable' box. The width of this box is 181 | * restricted to 80 chars; if the value's repr is longer than 182 | * this it will be wrapped, using a backslash marked with 183 | * class 'variable-linewrap'. If the value's repr is longer 184 | * than 3 lines, the rest will be ellided; and an ellipsis 185 | * marker ('...' marked with 'variable-ellipsis') will be used. 186 | * - If the value is a string, its quote marks will be marked 187 | * with 'variable-quote'. 188 | * - If the variable is a regexp, it is syntax-highlighted using 189 | * the re* CSS classes. 190 | */ 191 | pre.variable { padding: .5em; margin: 0; 192 | background: #dce4ec; color: #000000; 193 | border: 1px solid #708890; } 194 | .variable-linewrap { color: #604000; font-weight: bold; } 195 | .variable-ellipsis { color: #604000; font-weight: bold; } 196 | .variable-quote { color: #604000; font-weight: bold; } 197 | .variable-group { color: #008000; font-weight: bold; } 198 | .variable-op { color: #604000; font-weight: bold; } 199 | .variable-string { color: #006030; } 200 | .variable-unknown { color: #a00000; font-weight: bold; } 201 | .re { color: #000000; } 202 | .re-char { color: #006030; } 203 | .re-op { color: #600000; } 204 | .re-group { color: #003060; } 205 | .re-ref { color: #404040; } 206 | 207 | /* Base tree 208 | * - Used by class pages to display the base class hierarchy. 209 | */ 210 | pre.base-tree { font-size: 80%; margin: 0; } 211 | 212 | /* Frames-based table of contents headers 213 | * - Consists of two frames: one for selecting modules; and 214 | * the other listing the contents of the selected module. 215 | * - h1.toc is used for each frame's heading 216 | * - h2.toc is used for subheadings within each frame. 217 | */ 218 | h1.toc { text-align: center; font-size: 105%; 219 | margin: 0; font-weight: bold; 220 | padding: 0; } 221 | h2.toc { font-size: 100%; font-weight: bold; 222 | margin: 0.5em 0 0 -0.3em; } 223 | 224 | /* Syntax Highlighting for Source Code 225 | * - doctest examples are displayed in a 'pre.py-doctest' block. 226 | * If the example is in a details table entry, then it will use 227 | * the colors specified by the 'table pre.py-doctest' line. 228 | * - Source code listings are displayed in a 'pre.py-src' block. 229 | * Each line is marked with 'span.py-line' (used to draw a line 230 | * down the left margin, separating the code from the line 231 | * numbers). Line numbers are displayed with 'span.py-lineno'. 232 | * The expand/collapse block toggle button is displayed with 233 | * 'a.py-toggle' (Note: the CSS style for 'a.py-toggle' should not 234 | * modify the font size of the text.) 235 | * - If a source code page is opened with an anchor, then the 236 | * corresponding code block will be highlighted. The code 237 | * block's header is highlighted with 'py-highlight-hdr'; and 238 | * the code block's body is highlighted with 'py-highlight'. 239 | * - The remaining py-* classes are used to perform syntax 240 | * highlighting (py-string for string literals, py-name for names, 241 | * etc.) 242 | */ 243 | pre.py-doctest { padding: .5em; margin: 1em; 244 | background: #e8f0f8; color: #000000; 245 | border: 1px solid #708890; } 246 | table pre.py-doctest { background: #dce4ec; 247 | color: #000000; } 248 | pre.py-src { border: 2px solid #000000; 249 | background: #f0f0f0; color: #000000; } 250 | .py-line { border-left: 2px solid #000000; 251 | margin-left: .2em; padding-left: .4em; } 252 | .py-lineno { font-style: italic; font-size: 90%; 253 | padding-left: .5em; } 254 | a.py-toggle { text-decoration: none; } 255 | div.py-highlight-hdr { border-top: 2px solid #000000; 256 | border-bottom: 2px solid #000000; 257 | background: #d8e8e8; } 258 | div.py-highlight { border-bottom: 2px solid #000000; 259 | background: #d0e0e0; } 260 | .py-prompt { color: #005050; font-weight: bold;} 261 | .py-more { color: #005050; font-weight: bold;} 262 | .py-string { color: #006030; } 263 | .py-comment { color: #003060; } 264 | .py-keyword { color: #600000; } 265 | .py-output { color: #404040; } 266 | .py-name { color: #000050; } 267 | .py-name:link { color: #000050 !important; } 268 | .py-name:visited { color: #000050 !important; } 269 | .py-number { color: #005000; } 270 | .py-defname { color: #000060; font-weight: bold; } 271 | .py-def-name { color: #000060; font-weight: bold; } 272 | .py-base-class { color: #000060; } 273 | .py-param { color: #000060; } 274 | .py-docstring { color: #006030; } 275 | .py-decorator { color: #804020; } 276 | /* Use this if you don't want links to names underlined: */ 277 | /*a.py-name { text-decoration: none; }*/ 278 | 279 | /* Graphs & Diagrams 280 | * - These CSS styles are used for graphs & diagrams generated using 281 | * Graphviz dot. 'img.graph-without-title' is used for bare 282 | * diagrams (to remove the border created by making the image 283 | * clickable). 284 | */ 285 | img.graph-without-title { border: none; } 286 | img.graph-with-title { border: 1px solid #000000; } 287 | span.graph-title { font-weight: bold; } 288 | span.graph-caption { } 289 | 290 | /* General-purpose classes 291 | * - 'p.indent-wrapped-lines' defines a paragraph whose first line 292 | * is not indented, but whose subsequent lines are. 293 | * - The 'nomargin-top' class is used to remove the top margin (e.g. 294 | * from lists). The 'nomargin' class is used to remove both the 295 | * top and bottom margin (but not the left or right margin -- 296 | * for lists, that would cause the bullets to disappear.) 297 | */ 298 | p.indent-wrapped-lines { padding: 0 0 0 7em; text-indent: -7em; 299 | margin: 0; } 300 | .nomargin-top { margin-top: 0; } 301 | .nomargin { margin-top: 0; margin-bottom: 0; } 302 | 303 | /* HTML Log */ 304 | div.log-block { padding: 0; margin: .5em 0 .5em 0; 305 | background: #e8f0f8; color: #000000; 306 | border: 1px solid #000000; } 307 | div.log-error { padding: .1em .3em .1em .3em; margin: 4px; 308 | background: #ffb0b0; color: #000000; 309 | border: 1px solid #000000; } 310 | div.log-warning { padding: .1em .3em .1em .3em; margin: 4px; 311 | background: #ffffb0; color: #000000; 312 | border: 1px solid #000000; } 313 | div.log-info { padding: .1em .3em .1em .3em; margin: 4px; 314 | background: #b0ffb0; color: #000000; 315 | border: 1px solid #000000; } 316 | h2.log-hdr { background: #70b0ff; color: #000000; 317 | margin: 0; padding: 0em 0.5em 0em 0.5em; 318 | border-bottom: 1px solid #000000; font-size: 110%; } 319 | p.log { font-weight: bold; margin: .5em 0 .5em 0; } 320 | tr.opt-changed { color: #000000; font-weight: bold; } 321 | tr.opt-default { color: #606060; } 322 | pre.log { margin: 0; padding: 0; padding-left: 1em; } 323 | -------------------------------------------------------------------------------- /doc/api/pinder.campfire.Campfire-class.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | pinder.campfire.Campfire 7 | 8 | 9 | 10 | 11 | 13 | 14 | 16 | 17 | 18 | 20 | 21 | 22 | 24 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 50 | 55 | 56 |
44 | 45 | Package pinder :: 46 | Module campfire :: 47 | Class Campfire 48 | 49 | 51 | 52 | 53 |
54 |
57 | 58 |

Class Campfire

source code

59 |
 60 | object --+
 61 |          |
 62 |         Campfire
 63 | 
64 | 65 |
66 |

Creates a connection to the Campfire account with the given 67 | subdomain.

68 | 69 | 70 | 71 | 73 | 74 | 76 | 77 | 78 | 94 | 95 | 96 | 113 | 114 | 115 | 130 | 131 | 132 | 149 | 150 | 151 | 167 | 168 | 169 | 185 | 186 | 187 | 203 | 204 | 205 | 220 | 221 | 222 | 237 | 238 | 239 | 256 | 257 | 258 | 271 | 272 |
75 | Instance Methods
79 |   80 | 81 | 82 | 83 | 86 | 90 | 91 |
__init__(self, 84 | subdomain)
85 | x.__init__(...) initializes x; see x.__class__.__doc__ for signature
87 | source code 88 | 89 |
92 | 93 |
97 |   98 | 99 | 100 | 101 | 105 | 109 | 110 |
login(self, 102 | email, 103 | password)
104 | Logs into Campfire with the given email and password.
106 | source code 107 | 108 |
111 | 112 |
116 |   117 | 118 | 119 | 120 | 122 | 126 | 127 |
logout(self)
121 | Logs out from Campfire.
123 | source code 124 | 125 |
128 | 129 |
133 |   134 | 135 | 136 | 137 | 141 | 145 | 146 |
create_room(self, 138 | name, 139 | topic='')
140 | Creates a Campfire room with the given name and an optional topic.
142 | source code 143 | 144 |
147 | 148 |
152 |   153 | 154 | 155 | 156 | 159 | 163 | 164 |
find_room_by_name(self, 157 | name)
158 | Finds a Campfire room with the given name.
160 | source code 161 | 162 |
165 | 166 |
170 |   171 | 172 | 173 | 174 | 177 | 181 | 182 |
find_or_create_room_by_name(self, 175 | name)
176 | Finds a Campfire room with the given name.
178 | source code 179 | 180 |
183 | 184 |
188 |   189 | 190 | 191 | 192 | 195 | 199 | 200 |
users(self, 193 | *room_names)
194 | Lists the users chatting in any room or in the given room(s).
196 | source code 197 | 198 |
201 | 202 |
206 |   207 | 208 | 209 | 210 | 212 | 216 | 217 |
rooms_names(self)
211 | Lists the names of the rooms available in the Campfire subdomain.
213 | source code 214 | 215 |
218 | 219 |
223 |   224 | 225 | 226 | 227 | 229 | 233 | 234 |
rooms(self)
228 | Lists the available rooms.
230 | source code 231 | 232 |
235 | 236 |
240 |   241 | 242 | 243 | 244 | 248 | 252 | 253 |
transcripts(self, 245 | room_id=None)
246 | Gets the dates of the transcripts by room filtered by the given id if 247 | any.
249 | source code 250 | 251 |
254 | 255 |
259 |

Inherited from object: 260 | __delattr__, 261 | __getattribute__, 262 | __hash__, 263 | __new__, 264 | __reduce__, 265 | __reduce_ex__, 266 | __repr__, 267 | __setattr__, 268 | __str__ 269 |

270 |
273 | 274 | 275 | 277 | 278 | 280 | 281 | 282 | 288 | 289 | 290 | 296 | 297 | 298 | 304 | 305 | 306 | 314 | 315 |
279 | Instance Variables
283 |   284 | 285 | subdomain
286 | The Campfire's subdomain. 287 |
291 |   292 | 293 | logged_in
294 | True if the user is logged in Campfire, False otherwise. 295 |
299 |   300 | 301 | cookie
302 | Contains the connection cookie. 303 |
307 |   308 | 309 | uri
310 | The urlparsed URI of the Campfire account. 313 |
316 | 317 | 318 | 320 | 321 | 323 | 324 | 325 | 330 | 331 |
322 | Properties
326 |

Inherited from object: 327 | __class__ 328 |

329 |
332 | 333 | 334 | 336 | 337 | 339 | 340 |
338 | Method Details
341 | 342 |
343 | 345 |
346 | 347 | 355 |
348 |

__init__(self, 349 | subdomain) 350 |
(Constructor) 351 |

352 |
source code  354 |
356 | 357 |

x.__init__(...) initializes x; see x.__class__.__doc__ for 358 | signature

359 |
360 |
Overrides: 361 | object.__init__ 362 |
(inherited documentation)
363 | 364 |
365 |
366 |
367 | 368 |
369 | 371 |
372 | 373 | 381 |
374 |

login(self, 375 | email, 376 | password) 377 |

378 |
source code  380 |
382 | 383 |

Logs into Campfire with the given email and password.

384 |

Returns True if logged in, False otherwise.

385 |
386 |
387 |
388 |
389 | 390 |
391 | 393 |
394 | 395 | 401 |
396 |

logout(self) 397 |

398 |
source code  400 |
402 | 403 |

Logs out from Campfire.

404 |

Returns True if logged out, False otherwise.

405 |
406 |
407 |
408 |
409 | 410 |
411 | 413 |
414 | 415 | 423 |
416 |

create_room(self, 417 | name, 418 | topic='') 419 |

420 |
source code  422 |
424 | 425 |

Creates a Campfire room with the given name and an optional topic.

426 |

Returns None if the room has not been created.

427 |
428 |
429 |
430 |
431 | 432 |
433 | 435 |
436 | 437 | 444 |
438 |

find_room_by_name(self, 439 | name) 440 |

441 |
source code  443 |
445 | 446 |

Finds a Campfire room with the given name.

447 |

Returns a Room instance if found, None otherwise.

448 |
449 |
450 |
451 |
452 | 453 |
454 | 456 |
457 | 458 | 465 |
459 |

find_or_create_room_by_name(self, 460 | name) 461 |

462 |
source code  464 |
466 | 467 |

Finds a Campfire room with the given name. If the room is not present 468 | it will be created.

469 |

Returns a Room instance.

470 |
471 |
472 |
473 |
474 | 475 |
476 | 478 |
479 | 480 | 487 |
481 |

users(self, 482 | *room_names) 483 |

484 |
source code  486 |
488 | 489 |

Lists the users chatting in any room or in the given room(s).

490 |

Returns a set of the users.

491 |
492 |
493 |
494 |
495 | 496 |
497 | 499 |
500 | 501 | 507 |
502 |

rooms_names(self) 503 |

504 |
source code  506 |
508 | 509 |

Lists the names of the rooms available in the Campfire subdomain.

510 |

Returns a list of the names of the rooms.

511 |
512 |
513 |
514 |
515 | 516 |
517 | 519 |
520 | 521 | 527 |
522 |

rooms(self) 523 |

524 |
source code  526 |
528 | 529 |

Lists the available rooms.

530 |

Returns a list of Room objects.

531 |
532 |
533 |
534 |
535 | 536 |
537 | 539 |
540 | 541 | 548 |
542 |

transcripts(self, 543 | room_id=None) 544 |

545 |
source code  547 |
549 | 550 |

Gets the dates of the transcripts by room filtered by the given id if 551 | any.

552 |

Returns a dictionary of all the dates by room.

553 |
554 |
555 |
556 |
557 |
558 | 559 | 561 | 562 | 563 | 565 | 566 | 567 | 569 | 570 | 571 | 573 | 574 | 575 | 577 | 578 | 579 | 584 | 585 | 586 | 587 | 588 | 591 | 595 | 596 |
597 | 598 | 607 | 608 | 609 | -------------------------------------------------------------------------------- /doc/api/pinder.room.Room-class.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | pinder.room.Room 7 | 8 | 9 | 10 | 11 | 13 | 14 | 16 | 17 | 18 | 20 | 21 | 22 | 24 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 50 | 55 | 56 |
44 | 45 | Package pinder :: 46 | Module room :: 47 | Class Room 48 | 49 | 51 | 52 | 53 |
54 |
57 | 58 |

Class Room

source code

59 |
  60 | object --+
  61 |          |
  62 |         Room
  63 | 
64 | 65 |
66 |

A Campfire room.

67 | 68 | 69 | 70 | 72 | 73 | 75 | 76 | 77 | 95 | 96 | 97 | 112 | 113 | 114 | 129 | 130 | 131 | 147 | 148 | 149 | 164 | 165 | 166 | 181 | 182 | 183 | 198 | 199 | 200 | 215 | 216 | 217 | 232 | 233 | 234 | 250 | 251 | 252 | 268 | 269 | 270 | 286 | 287 | 288 | 303 | 304 | 305 | 320 | 321 | 322 | 337 | 338 | 339 | 355 | 356 | 357 | 372 | 373 | 374 | 389 | 390 | 391 | 407 | 408 | 409 | 425 | 426 | 427 | 442 | 443 | 444 | 460 | 461 | 462 | 474 | 475 |
74 | Instance Methods
78 |   79 | 80 | 81 | 82 | 87 | 91 | 92 |
__init__(self, 83 | campfire, 84 | id, 85 | name=None)
86 | x.__init__(...) initializes x; see x.__class__.__doc__ for signature
88 | source code 89 | 90 |
93 | 94 |
98 |   99 | 100 | 101 | 102 | 104 | 108 | 109 |
__repr__(self)
103 | repr(x)
105 | source code 106 | 107 |
110 | 111 |
115 |   116 | 117 | 118 | 119 | 121 | 125 | 126 |
__eq__(self, 120 | other) 122 | source code 123 | 124 |
127 | 128 |
132 |   133 | 134 | 135 | 136 | 139 | 143 | 144 |
join(self, 137 | force=False)
138 | Joins the room; if 'force' is True join even if already joined.
140 | source code 141 | 142 |
145 | 146 |
150 |   151 | 152 | 153 | 154 | 156 | 160 | 161 |
leave(self)
155 | Leaves the room.
157 | source code 158 | 159 |
162 | 163 |
167 |   168 | 169 | 170 | 171 | 173 | 177 | 178 |
toggle_guest_access(self)
172 | Toggles guest access on and off.
174 | source code 175 | 176 |
179 | 180 |
184 |   185 | 186 | 187 | 188 | 190 | 194 | 195 |
guest_access_enabled(self)
189 | Checks if the guest access is enabled.
191 | source code 192 | 193 |
196 | 197 |
201 |   202 | 203 | 204 | 205 | 207 | 211 | 212 |
guest_url(self)
206 | Gets the URL for guest access.
208 | source code 209 | 210 |
213 | 214 |
218 |   219 | 220 | 221 | 222 | 224 | 228 | 229 |
guest_invite_code(self)
223 | Gets the invite code for guest access.
225 | source code 226 | 227 |
230 | 231 |
235 |   236 | 237 | 238 | 239 | 242 | 246 | 247 |
change_name(self, 240 | name)
241 | Changes the name of the room.
243 | source code 244 | 245 |
248 | 249 |
253 |   254 | 255 | 256 | 257 | 260 | 264 | 265 |
rename(self, 258 | name)
259 | Changes the name of the room.
261 | source code 262 | 263 |
266 | 267 |
271 |   272 | 273 | 274 | 275 | 278 | 282 | 283 |
change_topic(self, 276 | topic)
277 | Changes the topic of the room.
279 | source code 280 | 281 |
284 | 285 |
289 |   290 | 291 | 292 | 293 | 295 | 299 | 300 |
topic(self)
294 | Gets the current topic, if any.
296 | source code 297 | 298 |
301 | 302 |
306 |   307 | 308 | 309 | 310 | 312 | 316 | 317 |
lock(self)
311 | Locks the room to prevent new users from entering.
313 | source code 314 | 315 |
318 | 319 |
323 |   324 | 325 | 326 | 327 | 329 | 333 | 334 |
unlock(self)
328 | Unlocks the room.
330 | source code 331 | 332 |
335 | 336 |
340 |   341 | 342 | 343 | 344 | 347 | 351 | 352 |
ping(self, 345 | force=False)
346 | Pings the server updating the last time we have been seen there.
348 | source code 349 | 350 |
353 | 354 |
358 |   359 | 360 | 361 | 362 | 364 | 368 | 369 |
destroy(self)
363 | Destroys the room.
365 | source code 366 | 367 |
370 | 371 |
375 |   376 | 377 | 378 | 379 | 381 | 385 | 386 |
users(self)
380 | Lists the users chatting in the room.
382 | source code 383 | 384 |
387 | 388 |
392 |   393 | 394 | 395 | 396 | 399 | 403 | 404 |
speak(self, 397 | message)
398 | Send a message to the room.
400 | source code 401 | 402 |
405 | 406 |
410 |   411 | 412 | 413 | 414 | 417 | 421 | 422 |
paste(self, 415 | message)
416 | Paste a message to the room.
418 | source code 419 | 420 |
423 | 424 |
428 |   429 | 430 | 431 | 432 | 434 | 438 | 439 |
transcripts(self)
433 | Gets the dates of transcripts of the room.
435 | source code 436 | 437 |
440 | 441 |
445 |   446 | 447 | 448 | 449 | 452 | 456 | 457 |
transcript(self, 450 | date)
451 | Get the transcript for the given date (a datetime.date instance).
453 | source code 454 | 455 |
458 | 459 |
463 |

Inherited from object: 464 | __delattr__, 465 | __getattribute__, 466 | __hash__, 467 | __new__, 468 | __reduce__, 469 | __reduce_ex__, 470 | __setattr__, 471 | __str__ 472 |

473 |
476 | 477 | 478 | 480 | 481 | 483 | 484 | 485 | 491 | 492 | 493 | 499 | 500 | 501 | 509 | 510 |
482 | Instance Variables
486 |   487 | 488 | id
489 | The room id. 490 |
494 |   495 | 496 | name
497 | The name of the room. 498 |
502 |   503 | 504 | uri
505 | The urlparsed URI of the room. 508 |
511 | 512 | 513 | 515 | 516 | 518 | 519 | 520 | 525 | 526 |
517 | Properties
521 |

Inherited from object: 522 | __class__ 523 |

524 |
527 | 528 | 529 | 531 | 532 | 534 | 535 |
533 | Method Details
536 | 537 |
538 | 540 |
541 | 542 | 552 |
543 |

__init__(self, 544 | campfire, 545 | id, 546 | name=None) 547 |
(Constructor) 548 |

549 |
source code  551 |
553 | 554 |

x.__init__(...) initializes x; see x.__class__.__doc__ for 555 | signature

556 |
557 |
Overrides: 558 | object.__init__ 559 |
(inherited documentation)
560 | 561 |
562 |
563 |
564 | 565 |
566 | 568 |
569 | 570 | 577 |
571 |

__repr__(self) 572 |
(Representation operator) 573 |

574 |
source code  576 |
578 | 579 |

repr(x)

580 |
581 |
Overrides: 582 | object.__repr__ 583 |
(inherited documentation)
584 | 585 |
586 |
587 |
588 | 589 |
590 | 592 |
593 | 594 | 601 |
595 |

join(self, 596 | force=False) 597 |

598 |
source code  600 |
602 | 603 |

Joins the room; if 'force' is True join even if already joined.

604 |

Returns True if successfully joined, False otherwise.

605 |
606 |
607 |
608 |
609 | 610 |
611 | 613 |
614 | 615 | 621 |
616 |

leave(self) 617 |

618 |
source code  620 |
622 | 623 |

Leaves the room.

624 |

Returns True if successfully left, False otherwise.

625 |
626 |
627 |
628 |
629 | 630 |
631 | 633 |
634 | 635 | 641 |
636 |

toggle_guest_access(self) 637 |

638 |
source code  640 |
642 | 643 |

Toggles guest access on and off.

644 |

Returns True if successfully toggled, False otherwise.

645 |
646 |
647 |
648 |
649 | 650 |
651 | 653 |
654 | 655 | 661 |
656 |

guest_access_enabled(self) 657 |

658 |
source code  660 |
662 | 663 |

Checks if the guest access is enabled.

664 |

Returns True if the guest access is enabled, False otherwise.

665 |
666 |
667 |
668 |
669 | 670 |
671 | 673 |
674 | 675 | 681 |
676 |

guest_url(self) 677 |

678 |
source code  680 |
682 | 683 |

Gets the URL for guest access.

684 |

Returns None if the guest access is not enabled.

685 |
686 |
687 |
688 |
689 | 690 |
691 | 693 |
694 | 695 | 701 |
696 |

guest_invite_code(self) 697 |

698 |
source code  700 |
702 | 703 |

Gets the invite code for guest access.

704 |

Returns None if the guest access is not enabled.

705 |
706 |
707 |
708 |
709 | 710 |
711 | 713 |
714 | 715 | 722 |
716 |

change_name(self, 717 | name) 718 |

719 |
source code  721 |
723 | 724 |

Changes the name of the room.

725 |

Returns the new name if successfully changed, None otherwise.

726 |
727 |
728 |
729 |
730 | 731 |
732 | 734 |
735 | 736 | 743 |
737 |

rename(self, 738 | name) 739 |

740 |
source code  742 |
744 | 745 |

Changes the name of the room.

746 |

Returns the new name if successfully changed, None otherwise.

747 |
748 |
749 |
750 |
751 | 752 |
753 | 755 |
756 | 757 | 764 |
758 |

change_topic(self, 759 | topic) 760 |

761 |
source code  763 |
765 | 766 |

Changes the topic of the room.

767 |

Returns the new topic if successfully changed, None otherwise.

768 |
769 |
770 |
771 |
772 | 773 |
774 | 776 |
777 | 778 | 784 |
779 |

lock(self) 780 |

781 |
source code  783 |
785 | 786 |

Locks the room to prevent new users from entering.

787 |

Returns True if successfully locked, False otherwise.

788 |
789 |
790 |
791 |
792 | 793 |
794 | 796 |
797 | 798 | 804 |
799 |

unlock(self) 800 |

801 |
source code  803 |
805 | 806 |

Unlocks the room.

807 |

Returns True if successfully unlocked, False otherwise.

808 |
809 |
810 |
811 |
812 | 813 |
814 | 816 |
817 | 818 | 825 |
819 |

ping(self, 820 | force=False) 821 |

822 |
source code  824 |
826 | 827 |

Pings the server updating the last time we have been seen there.

828 |

Returns True if successfully pinged, False otherwise.

829 |
830 |
831 |
832 |
833 | 834 |
835 | 837 |
838 | 839 | 845 |
840 |

destroy(self) 841 |

842 |
source code  844 |
846 | 847 |

Destroys the room.

848 |

Returns True if successfully destroyed, False otherwise.

849 |
850 |
851 |
852 |
853 | 854 |
855 | 857 |
858 | 859 | 865 |
860 |

users(self) 861 |

862 |
source code  864 |
866 | 867 |

Lists the users chatting in the room.

868 |

Returns a set of the users.

869 |
870 |
871 |
872 |
873 | 874 |
875 | 877 |
878 | 879 | 886 |
880 |

speak(self, 881 | message) 882 |

883 |
source code  885 |
887 | 888 |

Send a message to the room.

889 |

Returns the message if successfully sent it, None otherwise.

890 |
891 |
892 |
893 |
894 | 895 |
896 | 898 |
899 | 900 | 907 |
901 |

paste(self, 902 | message) 903 |

904 |
source code  906 |
908 | 909 |

Paste a message to the room.

910 |

Returns the message if successfully pasted it, None otherwise.

911 |
912 |
913 |
914 |
915 | 916 |
917 | 919 |
920 | 921 | 927 |
922 |

transcripts(self) 923 |

924 |
source code  926 |
928 | 929 |

Gets the dates of transcripts of the room.

930 |

Returns a list of dates.

931 |
932 |
933 |
934 |
935 | 936 |
937 | 939 |
940 | 941 | 948 |
942 |

transcript(self, 943 | date) 944 |

945 |
source code  947 |
949 | 950 |
 951 | Get the transcript for the given date (a datetime.date instance).
 952 | 
 953 | Returns a list of message data:
 954 |  * id: the id of the message
 955 |  * person: the name of the person who wrote the message if any
 956 |  * user_id: the user id of the person if any
 957 |  * message: the message itself if any
 958 | 
 959 | 
960 |
961 |
962 |
963 |
964 |
965 | 966 | 968 | 969 | 970 | 972 | 973 | 974 | 976 | 977 | 978 | 980 | 981 | 982 | 984 | 985 | 986 | 991 | 992 | 993 | 994 | 995 | 998 | 1002 | 1003 |
1004 | 1005 | 1014 | 1015 | 1016 | --------------------------------------------------------------------------------