[MIG] website_twitter: migration to new api
This commit is contained in:
committed by
David Monjoie
parent
12bd44fd96
commit
c3ff15b147
@@ -1,2 +1,5 @@
|
||||
import models
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import controllers
|
||||
import models
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
'name': 'Twitter Roller',
|
||||
'category': 'Website',
|
||||
@@ -16,7 +19,5 @@ Display best tweets
|
||||
'views/website_twitter_settings_views.xml',
|
||||
'views/website_twitter_snippet_templates.xml'
|
||||
],
|
||||
'demo': [],
|
||||
'qweb': [],
|
||||
'installable': True,
|
||||
}
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import main
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.tools.translate import _
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import json
|
||||
from odoo import _
|
||||
from odoo.addons.web import http
|
||||
from odoo.addons.web.http import request
|
||||
|
||||
|
||||
class Twitter(http.Controller):
|
||||
@http.route(['/twitter_reload'], type='json', auth="user", website=True)
|
||||
@@ -14,8 +17,7 @@ class Twitter(http.Controller):
|
||||
key = request.website.twitter_api_key
|
||||
secret = request.website.twitter_api_secret
|
||||
screen_name = request.website.twitter_screen_name
|
||||
cr, uid = request.cr, request.uid
|
||||
debug = request.registry['res.users'].has_group(cr, uid, 'base.group_website_publisher')
|
||||
debug = request.env['res.users'].has_group('base.group_website_publisher')
|
||||
if not key or not secret:
|
||||
if debug:
|
||||
return {"error": _("Please set the Twitter API Key and Secret in the Website Settings.")}
|
||||
@@ -25,12 +27,11 @@ class Twitter(http.Controller):
|
||||
return {"error": _("Please set a Twitter screen name to load favorites from, "
|
||||
"in the Website Settings (it does not have to be yours)")}
|
||||
return []
|
||||
twitter_tweets = request.registry['website.twitter.tweet']
|
||||
tweets = twitter_tweets.search_read(
|
||||
cr, uid,
|
||||
[('website_id','=', request.website.id),
|
||||
('screen_name','=', screen_name)],
|
||||
['tweet'], limit=int(limit), order="tweet_id desc", context=request.context)
|
||||
TwitterTweets = request.env['website.twitter.tweet']
|
||||
tweets = TwitterTweets.search(
|
||||
[('website_id', '=', request.website.id),
|
||||
('screen_name', '=', screen_name)],
|
||||
limit=int(limit), order="tweet_id desc")
|
||||
if len(tweets) < 12:
|
||||
if debug:
|
||||
return {"error": _("Twitter user @%(username)s has less than 12 favorite tweets. "
|
||||
@@ -38,4 +39,4 @@ class Twitter(http.Controller):
|
||||
{'username': screen_name}}
|
||||
else:
|
||||
return []
|
||||
return [json.loads(tweet['tweet']) for tweet in tweets]
|
||||
return tweets.mapped(lambda t: json.loads(t.tweet))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<odoo>
|
||||
|
||||
<record id="ir_cron_twitter_actions" model="ir.cron">
|
||||
<field name="name">Fetch new Twitter favorites</field>
|
||||
<field name="interval_number">2</field>
|
||||
@@ -11,6 +11,6 @@
|
||||
<field name="function">_refresh_favorite_tweets</field>
|
||||
<field name="args">()</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
</odoo>
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import website_twitter
|
||||
import website_twitter_config
|
||||
import website_twitter_tweet
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from urllib2 import urlopen, Request, HTTPError
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import base64
|
||||
import json
|
||||
import logging
|
||||
import werkzeug
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from urllib2 import urlopen, Request, HTTPError
|
||||
from odoo import api, fields, models
|
||||
|
||||
API_ENDPOINT = 'https://api.twitter.com'
|
||||
API_VERSION = '1.1'
|
||||
@@ -17,15 +16,15 @@ URLOPEN_TIMEOUT = 10
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class TwitterClient(osv.osv):
|
||||
_inherit = "website"
|
||||
|
||||
_columns = {
|
||||
'twitter_api_key': fields.char('Twitter API key', help="Twitter API Key"),
|
||||
'twitter_api_secret': fields.char('Twitter API secret', help="Twitter API Secret"),
|
||||
'twitter_screen_name': fields.char('Get favorites from this screen name'),
|
||||
}
|
||||
class WebsiteTwitter(models.Model):
|
||||
_inherit = 'website'
|
||||
|
||||
twitter_api_key = fields.Char(string='Twitter API key', help='Twitter API Key')
|
||||
twitter_api_secret = fields.Char(string='Twitter API secret', help='Twitter API Secret')
|
||||
twitter_screen_name = fields.Char(string='Get favorites from this screen name')
|
||||
|
||||
@api.model
|
||||
def _request(self, website, url, params=None):
|
||||
"""Send an authenticated request to the Twitter API."""
|
||||
access_token = self._get_access_token(website)
|
||||
@@ -41,50 +40,44 @@ class TwitterClient(osv.osv):
|
||||
e.code, e.msg, e.fp.read())
|
||||
raise
|
||||
|
||||
def _refresh_favorite_tweets(self, cr, uid, context=None):
|
||||
@api.model
|
||||
def _refresh_favorite_tweets(self):
|
||||
''' called by cron job '''
|
||||
website = self.pool['website']
|
||||
ids = self.pool['website'].search(cr, uid, [('twitter_api_key', '!=', False),
|
||||
('twitter_api_secret', '!=', False),
|
||||
('twitter_screen_name', '!=', False)],
|
||||
context=context)
|
||||
_logger.debug("Refreshing tweets for website IDs: %r", ids)
|
||||
website.fetch_favorite_tweets(cr, uid, ids, context=context)
|
||||
website = self.env['website'].search([('twitter_api_key', '!=', False),
|
||||
('twitter_api_secret', '!=', False),
|
||||
('twitter_screen_name', '!=', False)])
|
||||
_logger.debug("Refreshing tweets for website IDs: %r", website.ids)
|
||||
website.fetch_favorite_tweets()
|
||||
|
||||
def fetch_favorite_tweets(self, cr, uid, ids, context=None):
|
||||
website_tweets = self.pool['website.twitter.tweet']
|
||||
@api.multi
|
||||
def fetch_favorite_tweets(self):
|
||||
WebsiteTweets = self.env['website.twitter.tweet']
|
||||
tweet_ids = []
|
||||
for website in self.browse(cr, uid, ids, context=context):
|
||||
if not all((website.twitter_api_key, website.twitter_api_secret,
|
||||
website.twitter_screen_name)):
|
||||
_logger.debug("Skip fetching favorite tweets for unconfigured website %s",
|
||||
website)
|
||||
for website in self:
|
||||
if not all((website.twitter_api_key, website.twitter_api_secret, website.twitter_screen_name)):
|
||||
_logger.debug("Skip fetching favorite tweets for unconfigured website %s", website)
|
||||
continue
|
||||
params = {'screen_name': website.twitter_screen_name}
|
||||
last_tweet = website_tweets.search_read(
|
||||
cr, uid, [('website_id', '=', website.id),
|
||||
('screen_name', '=', website.twitter_screen_name)],
|
||||
['tweet_id'],
|
||||
limit=1, order='tweet_id desc', context=context)
|
||||
last_tweet = WebsiteTweets.search([('website_id', '=', website.id),
|
||||
('screen_name', '=', website.twitter_screen_name)],
|
||||
limit=1, order='tweet_id desc')
|
||||
if last_tweet:
|
||||
params['since_id'] = int(last_tweet[0]['tweet_id'])
|
||||
params['since_id'] = int(last_tweet.tweet_id)
|
||||
_logger.debug("Fetching favorite tweets using params %r", params)
|
||||
response = self._request(website, REQUEST_FAVORITE_LIST_URL, params=params)
|
||||
for tweet_dict in response:
|
||||
tweet_id = tweet_dict['id'] # unsigned 64-bit snowflake ID
|
||||
tweet_ids = website_tweets.search(cr, uid, [('tweet_id', '=', tweet_id)])
|
||||
tweet_id = tweet_dict['id'] # unsigned 64-bit snowflake ID
|
||||
tweet_ids = WebsiteTweets.search([('tweet_id', '=', tweet_id)]).ids
|
||||
if not tweet_ids:
|
||||
new_tweet = website_tweets.create(
|
||||
cr, uid,
|
||||
new_tweet = WebsiteTweets.create(
|
||||
{
|
||||
'website_id': website.id,
|
||||
'tweet': json.dumps(tweet_dict),
|
||||
'tweet_id': tweet_id, # stored in NUMERIC PG field
|
||||
'tweet_id': tweet_id, # stored in NUMERIC PG field
|
||||
'screen_name': website.twitter_screen_name,
|
||||
},
|
||||
context=context)
|
||||
})
|
||||
_logger.debug("Found new favorite: %r, %r", tweet_id, tweet_dict)
|
||||
tweet_ids.append(new_tweet)
|
||||
tweet_ids.append(new_tweet.id)
|
||||
return tweet_ids
|
||||
|
||||
def _get_access_token(self, website):
|
||||
|
||||
@@ -1,62 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import logging
|
||||
from urllib2 import URLError, HTTPError
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
from openerp.exceptions import UserError
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
TWITTER_EXCEPTION = {
|
||||
304: _('There was no new data to return.'),
|
||||
400: _('The request was invalid or cannot be otherwise served. Requests without authentication are considered invalid and will yield this response.'),
|
||||
401: _('Authentication credentials were missing or incorrect. Maybe screen name tweets are protected.'),
|
||||
403: _('The request is understood, but it has been refused or access is not allowed. Please check your Twitter API Key and Secret.'),
|
||||
429: _('Request cannot be served due to the applications rate limit having been exhausted for the resource.'),
|
||||
500: _('Twitter seems broken. Please retry later. You may consider posting an issue on Twitter forums to get help.'),
|
||||
502: _('Twitter is down or being upgraded.'),
|
||||
503: _('The Twitter servers are up, but overloaded with requests. Try again later.'),
|
||||
504: _('The Twitter servers are up, but the request could not be serviced due to some failure within our stack. Try again later.')
|
||||
}
|
||||
|
||||
class twitter_config_settings(osv.TransientModel):
|
||||
|
||||
class WebsiteTwitterConfig(models.TransientModel):
|
||||
_inherit = 'website.config.settings'
|
||||
|
||||
_columns = {
|
||||
'twitter_api_key': fields.related(
|
||||
'website_id', 'twitter_api_key', type="char",
|
||||
string='Twitter API Key',
|
||||
help="Twitter API key you can get it from https://apps.twitter.com/app/new"),
|
||||
'twitter_api_secret': fields.related(
|
||||
'website_id', 'twitter_api_secret', type="char",
|
||||
string='Twitter API secret',
|
||||
help="Twitter API secret you can get it from https://apps.twitter.com/app/new"),
|
||||
'twitter_tutorial': fields.dummy(
|
||||
type="boolean", string="Show me how to obtain the Twitter API Key and Secret"),
|
||||
'twitter_screen_name': fields.related(
|
||||
'website_id', 'twitter_screen_name',
|
||||
type="char", string='Get favorites from this screen name',
|
||||
help="Screen Name of the Twitter Account from which you want to load favorites."
|
||||
"It does not have to match the API Key/Secret."),
|
||||
}
|
||||
twitter_api_key = fields.Char(
|
||||
related='website_id.twitter_api_key',
|
||||
string='Twitter API Key',
|
||||
help='Twitter API key you can get it from https://apps.twitter.com/app/new')
|
||||
twitter_api_secret = fields.Char(
|
||||
related='website_id.twitter_api_secret',
|
||||
string='Twitter API secret',
|
||||
help='Twitter API secret you can get it from https://apps.twitter.com/app/new')
|
||||
twitter_tutorial = fields.Boolean(string='Show me how to obtain the Twitter API Key and Secret')
|
||||
twitter_screen_name = fields.Char(
|
||||
related='website_id.twitter_screen_name',
|
||||
string='Get favorites from this screen name',
|
||||
help='Screen Name of the Twitter Account from which you want to load favorites.'
|
||||
'It does not have to match the API Key/Secret.')
|
||||
|
||||
def _get_twitter_exception_message(self, error_code, context=None):
|
||||
TWITTER_EXCEPTION = {
|
||||
304: _('There was no new data to return.'),
|
||||
400: _('The request was invalid or cannot be otherwise served. Requests without authentication are considered invalid and will yield this response.'),
|
||||
401: _('Authentication credentials were missing or incorrect. Maybe screen name tweets are protected.'),
|
||||
403: _('The request is understood, but it has been refused or access is not allowed. Please check your Twitter API Key and Secret.'),
|
||||
429: _('Request cannot be served due to the applications rate limit having been exhausted for the resource.'),
|
||||
500: _('Twitter seems broken. Please retry later. You may consider posting an issue on Twitter forums to get help.'),
|
||||
502: _('Twitter is down or being upgraded.'),
|
||||
503: _('The Twitter servers are up, but overloaded with requests. Try again later.'),
|
||||
504: _('The Twitter servers are up, but the request could not be serviced due to some failure within our stack. Try again later.')
|
||||
}
|
||||
def _get_twitter_exception_message(self, error_code):
|
||||
if error_code in TWITTER_EXCEPTION:
|
||||
return TWITTER_EXCEPTION[error_code]
|
||||
else:
|
||||
return _('HTTP Error: Something is misconfigured')
|
||||
|
||||
def _check_twitter_authorization(self, cr, uid, config_id, context=None):
|
||||
website_obj = self.pool['website']
|
||||
website_config = self.browse(cr, uid, config_id, context=context)
|
||||
def _check_twitter_authorization(self):
|
||||
try:
|
||||
website_obj.fetch_favorite_tweets(cr, uid, [website_config.website_id.id], context=context)
|
||||
self.website_id.fetch_favorite_tweets()
|
||||
|
||||
except HTTPError, e:
|
||||
_logger.info("%s - %s" % (e.code, e.reason), exc_info=True)
|
||||
raise UserError("%s - %s" % (e.code, e.reason) + ':' + self._get_twitter_exception_message(e.code, context))
|
||||
raise UserError("%s - %s" % (e.code, e.reason) + ':' + self._get_twitter_exception_message(e.code))
|
||||
except URLError, e:
|
||||
_logger.info(_('We failed to reach a twitter server.'), exc_info=True)
|
||||
raise UserError(_('Internet connection refused') + ' ' + _('We failed to reach a twitter server.'))
|
||||
@@ -64,14 +59,16 @@ class twitter_config_settings(osv.TransientModel):
|
||||
_logger.info(_('Please double-check your Twitter API Key and Secret!'), exc_info=True)
|
||||
raise UserError(_('Twitter authorization error!') + ' ' + _('Please double-check your Twitter API Key and Secret!'))
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
res_id = super(twitter_config_settings, self).create(cr, uid, vals, context=context)
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
TwitterConfig = super(WebsiteTwitterConfig, self).create(vals)
|
||||
if vals.get('twitter_api_key') or vals.get('twitter_api_secret') or vals.get('twitter_screen_name'):
|
||||
self._check_twitter_authorization(cr, uid, res_id, context=context)
|
||||
return res_id
|
||||
TwitterConfig._check_twitter_authorization()
|
||||
return TwitterConfig
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
res_id = super(twitter_config_settings, self).write(cr, uid, ids, vals, context=context)
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
TwitterConfig = super(WebsiteTwitterConfig, self).write(vals)
|
||||
if vals.get('twitter_api_key') or vals.get('twitter_api_secret') or vals.get('twitter_screen_name'):
|
||||
self._check_twitter_authorization(cr, uid, ids, context=context)
|
||||
return res_id
|
||||
self._check_twitter_authorization()
|
||||
return TwitterConfig
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class WebsiteTwitterTweet(osv.osv):
|
||||
_name = "website.twitter.tweet"
|
||||
_description = "Twitter Tweets"
|
||||
_columns = {
|
||||
'website_id': fields.many2one('website', string="Website"),
|
||||
'screen_name': fields.char("Screen Name"),
|
||||
'tweet': fields.text('Tweets'),
|
||||
class WebsiteTwitterTweet(models.Model):
|
||||
_name = 'website.twitter.tweet'
|
||||
|
||||
# Twitter IDs are 64-bit unsigned ints, so we need to store them in
|
||||
# unlimited precision NUMERIC columns, which can be done with a
|
||||
# float field. Used digits=(0,0) to indicate unlimited.
|
||||
# Using VARCHAR would work too but would have sorting problems.
|
||||
'tweet_id': fields.float("Tweet ID", digits=(0,0)), # Twitter
|
||||
}
|
||||
website_id = fields.Many2one('website', string='Website')
|
||||
screen_name = fields.Char(string='Screen Name')
|
||||
tweet = fields.Text(string='Tweets')
|
||||
|
||||
# Twitter IDs are 64-bit unsigned ints, so we need to store them in
|
||||
# unlimited precision NUMERIC columns, which can be done with a
|
||||
# float field. Used digits=(0,0) to indicate unlimited.
|
||||
# Using VARCHAR would work too but would have sorting problems.
|
||||
tweet_id = fields.Float(string='Tweet ID', digits=(0, 0)) # Twitter
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<odoo>
|
||||
|
||||
<record id="view_website_config_settings" model="ir.ui.view">
|
||||
<field name="name">Twitter settings</field>
|
||||
<field name="model">website.config.settings</field>
|
||||
@@ -52,5 +52,5 @@
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<template id="website_twitter_snippet" name="Twitter snippet" inherit_id="website.snippets">
|
||||
<odoo>
|
||||
|
||||
<template id="website_twitter_snippet" inherit_id="website.snippets" name="Twitter snippet">
|
||||
<xpath expr="//div[@id='snippet_feature']/div[@class='o_panel_body']" position="inside">
|
||||
<div>
|
||||
<div class="oe_snippet_thumbnail">
|
||||
@@ -14,7 +14,7 @@
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
<template id="website_twitter_options" name="Twitter Options" inherit_id="website.snippet_options">
|
||||
<template id="website_twitter_options" inherit_id="website.snippet_options" name="Twitter Options">
|
||||
<xpath expr="//div" position="after">
|
||||
<div data-js='twitter'
|
||||
data-selector=".twitter"
|
||||
@@ -33,5 +33,5 @@
|
||||
<script type="text/javascript" src="/website_twitter/static/src/js/website.twitter.editor.js"/>
|
||||
</xpath>
|
||||
</template>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
</odoo>
|
||||
|
||||
Reference in New Issue
Block a user