Twitter: First commit (can authenticate and get friendslist)
parent
c7c04b2c57
commit
0f6a385921
|
@ -0,0 +1 @@
|
|||
Insert a description of your plugin here, with any notes, etc. about using it.
|
|
@ -0,0 +1,69 @@
|
|||
###
|
||||
# Copyright (c) 2011, Valentin Lorentz
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer.
|
||||
# * 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.
|
||||
# * Neither the name of the author of this software nor the name of
|
||||
# contributors to this software may be used to endorse or promote products
|
||||
# derived from this software without specific prior written consent.
|
||||
#
|
||||
# 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.
|
||||
|
||||
###
|
||||
|
||||
"""
|
||||
Add a description of the plugin (to be presented to the user inside the wizard)
|
||||
here. This should describe *what* the plugin does.
|
||||
"""
|
||||
|
||||
import supybot
|
||||
import supybot.world as world
|
||||
|
||||
# Use this for the version of this plugin. You may wish to put a CVS keyword
|
||||
# in here if you're keeping the plugin in CVS or some similar system.
|
||||
__version__ = ""
|
||||
|
||||
# XXX Replace this with an appropriate author or supybot.Author instance.
|
||||
if not hasattr(supybot.authors, 'progval'):
|
||||
supybot.authors.progval =supybot.Author('Valentin Lorentz', 'ProgVal',
|
||||
'progval@gmail.com')
|
||||
__author__ = supybot.authors.progval
|
||||
|
||||
# This is a dictionary mapping supybot.Author instances to lists of
|
||||
# contributions.
|
||||
__contributors__ = {}
|
||||
|
||||
# This is a url where the most recent plugin package can be downloaded.
|
||||
__url__ = '' # 'http://supybot.com/Members/yourname/Twitter/download'
|
||||
|
||||
import config
|
||||
import plugin
|
||||
reload(plugin) # In case we're being reloaded.
|
||||
# Add more reloads here if you add third-party modules and want them to be
|
||||
# reloaded when this plugin is reloaded. Don't forget to import them as well!
|
||||
|
||||
if world.testing:
|
||||
import test
|
||||
|
||||
Class = plugin.Class
|
||||
configure = config.configure
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
|
@ -0,0 +1,71 @@
|
|||
###
|
||||
# Copyright (c) 2011, Valentin Lorentz
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer.
|
||||
# * 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.
|
||||
# * Neither the name of the author of this software nor the name of
|
||||
# contributors to this software may be used to endorse or promote products
|
||||
# derived from this software without specific prior written consent.
|
||||
#
|
||||
# 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.
|
||||
|
||||
###
|
||||
|
||||
import supybot.conf as conf
|
||||
import supybot.registry as registry
|
||||
from supybot.i18n import PluginInternationalization, internationalizeDocstring
|
||||
|
||||
_ = PluginInternationalization('Twitter')
|
||||
|
||||
def configure(advanced):
|
||||
# This will be called by supybot to configure this module. advanced is
|
||||
# a bool that specifies whether the user identified himself as an advanced
|
||||
# user or not. You should effect your configuration by manipulating the
|
||||
# registry as appropriate.
|
||||
from supybot.questions import expect, anything, something, yn
|
||||
conf.registerPlugin('Twitter', True)
|
||||
|
||||
|
||||
Twitter = conf.registerPlugin('Twitter')
|
||||
# This is where your configuration variables (if any) should go. For example:
|
||||
# conf.registerGlobalValue(Twitter, 'someConfigVariableName',
|
||||
# registry.Boolean(False, _("""Help for someConfigVariableName.""")))
|
||||
conf.registerGroup(Twitter, 'accounts')
|
||||
|
||||
helpGetToken = _('running get_access_token.py is a way to get it')
|
||||
|
||||
conf.registerGroup(Twitter.accounts, 'bot')
|
||||
conf.registerGlobalValue(Twitter.accounts.bot, 'key',
|
||||
registry.String('', _("""The Twitter Access Token key for the bot's
|
||||
account (%s)""") % helpGetToken))
|
||||
conf.registerGlobalValue(Twitter.accounts.bot, 'secret',
|
||||
registry.String('', _("""The Twitter Access Token secret for the bot's
|
||||
account (%s)""") % helpGetToken, private=True))
|
||||
|
||||
conf.registerGroup(Twitter.accounts, 'channel')
|
||||
conf.registerChannelValue(Twitter.accounts.channel, 'key',
|
||||
registry.String('', _("""The Twitter Access Token key for this
|
||||
channel's account (%s)""") % helpGetToken))
|
||||
conf.registerChannelValue(Twitter.accounts.channel, 'secret',
|
||||
registry.String('', _("""The Twitter Access Token secret for this
|
||||
channel's account (%s)""") % helpGetToken, private=True))
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
|
@ -0,0 +1,90 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright 2007 The Python-Twitter Developers
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# parse_qsl moved to urlparse module in v2.6
|
||||
try:
|
||||
from urlparse import parse_qsl
|
||||
except:
|
||||
from cgi import parse_qsl
|
||||
|
||||
import oauth2 as oauth
|
||||
|
||||
REQUEST_TOKEN_URL = 'https://api.twitter.com/oauth/request_token'
|
||||
ACCESS_TOKEN_URL = 'https://api.twitter.com/oauth/access_token'
|
||||
AUTHORIZATION_URL = 'https://api.twitter.com/oauth/authorize'
|
||||
SIGNIN_URL = 'https://api.twitter.com/oauth/authenticate'
|
||||
|
||||
consumer_key = 'bItq1HZhBGyx5Y8ardIeQ'
|
||||
consumer_secret = 'qjC6Ye6xSMM3XPLR3LLeMqOP4ri0rgoYFT2si1RpY'
|
||||
|
||||
if consumer_key is None or consumer_secret is None:
|
||||
print 'You need to edit this script and provide values for the'
|
||||
print 'consumer_key and also consumer_secret.'
|
||||
print ''
|
||||
print 'The values you need come from Twitter - you need to register'
|
||||
print 'as a developer your "application". This is needed only until'
|
||||
print 'Twitter finishes the idea they have of a way to allow open-source'
|
||||
print 'based libraries to have a token that can be used to generate a'
|
||||
print 'one-time use key that will allow the library to make the request'
|
||||
print 'on your behalf.'
|
||||
print ''
|
||||
sys.exit(1)
|
||||
|
||||
signature_method_hmac_sha1 = oauth.SignatureMethod_HMAC_SHA1()
|
||||
oauth_consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret)
|
||||
oauth_client = oauth.Client(oauth_consumer)
|
||||
|
||||
print 'Requesting temp token from Twitter'
|
||||
|
||||
resp, content = oauth_client.request(REQUEST_TOKEN_URL, 'GET')
|
||||
|
||||
if resp['status'] != '200':
|
||||
print 'Invalid respond from Twitter requesting temp token: %s' % resp['status']
|
||||
else:
|
||||
request_token = dict(parse_qsl(content))
|
||||
|
||||
print ''
|
||||
print 'Please visit this Twitter page and retrieve the pincode to be used'
|
||||
print 'in the next step to obtaining an Authentication Token:'
|
||||
print ''
|
||||
print '%s?oauth_token=%s' % (AUTHORIZATION_URL, request_token['oauth_token'])
|
||||
print ''
|
||||
|
||||
pincode = raw_input('Pincode? ')
|
||||
|
||||
token = oauth.Token(request_token['oauth_token'], request_token['oauth_token_secret'])
|
||||
token.set_verifier(pincode)
|
||||
|
||||
print ''
|
||||
print 'Generating and signing request for an access token'
|
||||
print ''
|
||||
|
||||
oauth_client = oauth.Client(oauth_consumer, token)
|
||||
resp, content = oauth_client.request(ACCESS_TOKEN_URL, method='POST', body='oauth_verifier=%s' % pincode)
|
||||
access_token = dict(parse_qsl(content))
|
||||
|
||||
if resp['status'] != '200':
|
||||
print 'The request for a Token did not succeed: %s' % resp['status']
|
||||
print access_token
|
||||
else:
|
||||
print 'Your Twitter Access Token key: %s' % access_token['oauth_token']
|
||||
print ' Access Token secret: %s' % access_token['oauth_token_secret']
|
||||
print ''
|
||||
|
|
@ -0,0 +1 @@
|
|||
# Stub so local is a module, used for third-party modules
|
|
@ -0,0 +1,110 @@
|
|||
###
|
||||
# Copyright (c) 2011, Valentin Lorentz
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer.
|
||||
# * 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.
|
||||
# * Neither the name of the author of this software nor the name of
|
||||
# contributors to this software may be used to endorse or promote products
|
||||
# derived from this software without specific prior written consent.
|
||||
#
|
||||
# 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.
|
||||
|
||||
###
|
||||
|
||||
import twitter
|
||||
import supybot.utils as utils
|
||||
from supybot.commands import *
|
||||
import supybot.plugins as plugins
|
||||
import supybot.ircutils as ircutils
|
||||
import supybot.callbacks as callbacks
|
||||
from supybot.i18n import PluginInternationalization, internationalizeDocstring
|
||||
|
||||
_ = PluginInternationalization('Twitter')
|
||||
|
||||
reload(twitter)
|
||||
if twitter.__version__.split('.') < ['0', '8', '0']:
|
||||
raise ImportError('You current version of python-twitter is to old, '
|
||||
'you need at least version 0.8.0, because older '
|
||||
'versions do not support OAuth authentication.')
|
||||
|
||||
@internationalizeDocstring
|
||||
class Twitter(callbacks.Plugin):
|
||||
"""Add the help for "@plugin help Twitter" here
|
||||
This should describe *how* to use this plugin."""
|
||||
threaded = True
|
||||
|
||||
def __init__(self, irc):
|
||||
self.__parent = super(Twitter, self)
|
||||
callbacks.Plugin.__init__(self, irc)
|
||||
self._apis = {}
|
||||
|
||||
def _getApi(self, channel):
|
||||
if channel in self._apis:
|
||||
return self._apis[channel]
|
||||
if channel is None:
|
||||
key = self.registryValue('accounts.bot.key')
|
||||
secret = self.registryValue('accounts.bot.secret')
|
||||
else:
|
||||
key = self.registryValue('accounts.channel.key', channel)
|
||||
secret = self.registryValue('accounts.channel.secret', channel)
|
||||
if key == '' or secret == '':
|
||||
return twitter.Api()
|
||||
api = twitter.Api(consumer_key='bItq1HZhBGyx5Y8ardIeQ',
|
||||
consumer_secret='qjC6Ye6xSMM3XPLR3LLeMqOP4ri0rgoYFT2si1RpY',
|
||||
access_token_key=key,
|
||||
access_token_secret=secret)
|
||||
self._apis[channel] = api
|
||||
return api
|
||||
|
||||
|
||||
@internationalizeDocstring
|
||||
def friendslist(self, irc, msg, args, channel, user):
|
||||
"""[<channel>] [<user>]
|
||||
|
||||
Replies with the friends (i.e. people who one subscribes to) of the
|
||||
<user>, as the <channel> associated account. <channel> is only
|
||||
needed if you don't run the command in the channel itself. If <user>
|
||||
is not given, it defaults to the channel's account."""
|
||||
api = self._getApi(channel)
|
||||
if not api._oauth_consumer and user is None:
|
||||
irc.error(_('No account is associated with this channel. Ask '
|
||||
'an op, try with another channel, or provide '
|
||||
'a user name.'))
|
||||
return
|
||||
friends = api.GetFriends(user) # If user is not given, it defaults
|
||||
# to None, and giving None to
|
||||
# GetFriends() has the expected
|
||||
# behaviour.
|
||||
reply = utils.str.format("%L", ['%s(%s)' % (x.name, x.screen_name)
|
||||
for x in friends])
|
||||
reply = reply.encode('utf8')
|
||||
irc.reply(reply)
|
||||
friendslist = wrap(friendslist, ['channel',
|
||||
optional('somethingWithoutSpaces')])
|
||||
|
||||
|
||||
|
||||
def die(self):
|
||||
self.__parent.die()
|
||||
|
||||
Class = Twitter
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
|
@ -0,0 +1,37 @@
|
|||
###
|
||||
# Copyright (c) 2011, Valentin Lorentz
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer.
|
||||
# * 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.
|
||||
# * Neither the name of the author of this software nor the name of
|
||||
# contributors to this software may be used to endorse or promote products
|
||||
# derived from this software without specific prior written consent.
|
||||
#
|
||||
# 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.
|
||||
|
||||
###
|
||||
|
||||
from supybot.test import *
|
||||
|
||||
class TwitterTestCase(ChannelPluginTestCase):
|
||||
plugins = ('Twitter',)
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
Loading…
Reference in New Issue