server-share/linkdrop/controllers/send.py

209 строки
7.7 KiB
Python

# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (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.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Raindrop.
#
# The Initial Developer of the Original Code is
# Mozilla Messaging, Inc..
# Portions created by the Initial Developer are Copyright (C) 2009
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Rob Miller (rmiller@mozilla.com)
#
# ***** END LICENSE BLOCK *****
import logging
import json
import copy
from urlparse import urlparse
from paste.deploy.converters import asbool
import hashlib
from linkoauth.errors import (OAuthKeysException, ServiceUnavailableException,
DomainNotRegisteredError)
from linkdrop.controllers import get_services
from linkdrop.lib.base import BaseController
from linkdrop.lib.helpers import json_exception_response, api_response
from linkdrop.lib.helpers import api_entry, api_arg, get_passthrough_headers
from linkdrop.lib import constants
from linkdrop.lib.metrics import metrics
from linkdrop.lib.shortener import shorten_link
log = logging.getLogger(__name__)
class SendController(BaseController):
"""
Send
====
The 'send' namespace is used to send updates to our supported services.
"""
__api_controller__ = True # for docs
@api_response
@json_exception_response
@api_entry(
doc="""
send
----
Share a link through F1.
""",
queryargs=[
# name, type, required, default, allowed, doc
api_arg('domain', 'string', True, None, None, """
Domain of service to share to (google.com for gmail, facebook.com, twitter.com)
"""),
api_arg('message', 'string', True, None, None, """
Message entered by user
"""),
api_arg('username', 'string', False, None, None, """
Optional username, required if more than one account is configured for """
"""a domain.
"""),
api_arg('userid', 'string', False, None, None, """
Optional userid, required if more than one account is configured for a domain.
"""),
api_arg('link', 'string', False, None, None, """
URL to share
"""),
api_arg('shorturl', 'string', False, None, None, """
Shortened version of URL to share
"""),
api_arg('shorten', 'boolean', False, None, None, """
Force a shortening of the URL provided
"""),
api_arg('to', 'string', False, None, None, """
Individual or group to share with, not supported by all services.
"""),
api_arg('subject', 'string', False, None, None, """
Subject line for emails, not supported by all services.
"""),
api_arg('picture', 'string', False, None, None, """
URL to publicly available thumbnail, not supported by all services.
"""),
api_arg('picture_base64', 'string', False, None, None, """
Base 64 encoded PNG version of the picture used for attaching to emails.
"""),
api_arg('description', 'string', False, None, None, """
Site provided description of the shared item, not supported by all services.
"""),
api_arg('name', 'string', False, None, None, """
"""),
],
response={'type': 'list', 'doc': 'raw data list'})
def send(self, request):
result = {}
error = None
acct = None
domain = request.POST.get('domain')
message = request.POST.get('message', '')
username = request.POST.get('username')
longurl = request.POST.get('link')
shorten = asbool(request.POST.get('shorten', 0))
shorturl = request.POST.get('shorturl')
userid = request.POST.get('userid')
to = request.POST.get('to')
account_data = request.POST.get('account', None)
if not domain:
error = {
'message': "'domain' is not optional",
'code': constants.INVALID_PARAMS,
}
return {'result': result, 'error': error}
if account_data:
acct = json.loads(account_data)
if not acct:
metrics.track(request, 'send-noaccount', domain=domain)
error = {'provider': domain,
'message': ("not logged in or no user "
"account for that domain"),
'status': 401,
}
return {'result': result, 'error': error}
args = copy.copy(request.POST)
if shorten and not shorturl and longurl:
link_timer = metrics.start_timer(request, long_url=longurl)
u = urlparse(longurl)
if not u.scheme:
longurl = 'http://' + longurl
shorturl = shorten_link(request.config, longurl)
link_timer.track('link-shorten', short_url=shorturl)
args['shorturl'] = shorturl
acct_hash = hashlib.sha1(
"%s#%s" % ((username or '').encode('utf-8'),
(userid or '').encode('utf-8'))).hexdigest()
timer = metrics.start_timer(request, domain=domain,
message_len=len(message),
long_url=longurl,
short_url=shorturl,
acct_id=acct_hash)
# send the item
headers = get_passthrough_headers(request)
try:
services = get_services(self.app.config)
result, error = services.sendmessage(domain, acct, message,
args, headers)
except DomainNotRegisteredError:
error = {
'message': "'domain' is invalid",
'code': constants.INVALID_PARAMS,
}
return {'result': result, 'error': error}
except OAuthKeysException, e:
# XXX - I doubt we really want a full exception logged here?
#log.exception('error providing item to %s: %s', domain, e)
# XXX we need to handle this better, but if for some reason the
# oauth values are bad we will get a ValueError raised
error = {'provider': domain,
'message': ("not logged in or no user account "
"for that domain"),
'status': 401,
}
metrics.track(request, 'send-oauth-keys-missing', domain=domain)
timer.track('send-error', error=error)
return {'result': result, 'error': error}
except ServiceUnavailableException, e:
error = {'provider': domain,
'message': ("The service is temporarily unavailable "
"- please try again later."),
'status': 503,
}
if e.debug_message:
error['debug_message'] = e.debug_message
metrics.track(request, 'send-service-unavailable', domain=domain)
timer.track('send-error', error=error)
return {'result': result, 'error': error}
if error:
timer.track('send-error', error=error)
assert not result
#log.error("send failure: %r %r %r", username, userid, error)
else:
# create a new record in the history table.
assert result
result['shorturl'] = shorturl
result['from'] = userid
result['to'] = to
timer.track('send-success')
# no redirects requests, just return the response.
return {'result': result, 'error': error}