Permalink
Browse files

Flask app initial commit

  • Loading branch information...
jonthornton committed Mar 24, 2014
0 parents commit f9a7e7a7aa1073cd024a887edd0226cd05d335d2
@@ -0,0 +1,4 @@
.DS_Store
venv
.Python
*.cfg

Large diffs are not rendered by default.

Oops, something went wrong.
BIN +23.3 KB pytumblr/__init__.pyc
Binary file not shown.
@@ -0,0 +1,45 @@
def validate_params(valid_options, params):
"""
Helps us validate the parameters for the request
:param valid_options: a list of strings of valid options for the
api request
:param params: a dict, the key-value store which we really only care about
the key which has tells us what the user is using for the
API request
:returns: None or throws an exception if the validation fails
"""
#crazy little if statement hanging by himself :(
if not params:
return
#We only allow one version of the data parameter to be passed
data_filter = ['data', 'source', 'external_url', 'embed']
multiple_data = filter(lambda x: x in data_filter, params.keys())
if len(multiple_data) > 1:
raise Exception("You can't mix and match data parameters")
#No bad fields which are not in valid options can pass
disallowed_fields = filter(lambda x: x not in valid_options, params.keys())
if disallowed_fields:
field_strings = ",".join(disallowed_fields)
raise Exception("%s are not allowed fields" % field_strings)
def validate_blogname(fn):
"""
Decorator to validate the blogname and let you pass in a blogname like:
client.blog_info('codingjester')
or
client.blog_info('codingjester.tumblr.com')
or
client.blog_info('blog.johnbunting.me')
and query all the same blog.
"""
def add_dot_tumblr(*args, **kwargs):
if (len(args) > 1 and ("." not in args[1])):
args = list(args)
args[1] += ".tumblr.com"
return fn(*args, **kwargs)
return add_dot_tumblr
BIN +2.13 KB pytumblr/helpers.pyc
Binary file not shown.
@@ -0,0 +1,155 @@
import urllib
import urllib2
import time
import json
from urlparse import parse_qsl
import oauth2 as oauth
from httplib2 import RedirectLimit
class TumblrRequest(object):
"""
A simple request object that lets us query the Tumblr API
"""
def __init__(self, consumer_key, consumer_secret="", oauth_token="", oauth_secret="", host="http://api.tumblr.com"):
self.host = host
self.consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret)
self.token = oauth.Token(key=oauth_token, secret=oauth_secret)
def get(self, url, params):
"""
Issues a GET request against the API, properly formatting the params
:param url: a string, the url you are requesting
:param params: a dict, the key-value of all the paramaters needed
in the request
:returns: a dict parsed of the JSON response
"""
url = self.host + url
if params:
url = url + "?" + urllib.urlencode(params)
client = oauth.Client(self.consumer, self.token)
try:
client.follow_redirects = False
resp, content = client.request(url, method="GET", redirections=False)
except RedirectLimit, e:
resp, content = e.args
return self.json_parse(content)
def post(self, url, params={}, files=[]):
"""
Issues a POST request against the API, allows for multipart data uploads
:param url: a string, the url you are requesting
:param params: a dict, the key-value of all the parameters needed
in the request
:param files: a list, the list of tuples of files
:returns: a dict parsed of the JSON response
"""
url = self.host + url
try:
if files:
return self.post_multipart(url, params, files)
else:
client = oauth.Client(self.consumer, self.token)
resp, content = client.request(url, method="POST", body=urllib.urlencode(params))
return self.json_parse(content)
except urllib2.HTTPError, e:
return self.json_parse(e.read())
def json_parse(self, content):
"""
Wraps and abstracts content validation and JSON parsing
to make sure the user gets the correct response.
:param content: The content returned from the web request to be parsed as json
:returns: a dict of the json response
"""
try:
data = json.loads(content)
except ValueError, e:
data = {'meta': { 'status': 500, 'msg': 'Server Error'}, 'response': {"error": "Malformed JSON or HTML was returned."}}
#We only really care about the response if we succeed
#and the error if we fail
if data['meta']['status'] in [200, 201, 301]:
return data['response']
else:
return data
def post_multipart(self, url, params, files):
"""
Generates and issues a multipart request for data files
:param url: a string, the url you are requesting
:param params: a dict, a key-value of all the parameters
:param files: a list, the list of tuples for your data
:returns: a dict parsed from the JSON response
"""
#combine the parameters with the generated oauth params
params = dict(params.items() + self.generate_oauth_params().items())
faux_req = oauth.Request(method="POST", url=url, parameters=params)
faux_req.sign_request(oauth.SignatureMethod_HMAC_SHA1(), self.consumer, self.token)
params = dict(parse_qsl(faux_req.to_postdata()))
content_type, body = self.encode_multipart_formdata(params, files)
headers = {'Content-Type': content_type, 'Content-Length': str(len(body))}
#Do a bytearray of the body and everything seems ok
r = urllib2.Request(url, bytearray(body), headers)
content = urllib2.urlopen(r).read()
return self.json_parse(content)
def encode_multipart_formdata(self, fields, files):
"""
Properly encodes the multipart body of the request
:param fields: a dict, the parameters used in the request
:param files: a list of tuples containing information about the files
:returns: the content for the body and the content-type value
"""
import mimetools
import mimetypes
BOUNDARY = mimetools.choose_boundary()
CRLF = '\r\n'
L = []
for (key, value) in fields.items():
L.append('--' + BOUNDARY)
L.append('Content-Disposition: form-data; name="%s"' % key)
L.append('')
L.append(value)
for (key, filename, value) in files:
L.append('--' + BOUNDARY)
L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
L.append('Content-Type: %s' % mimetypes.guess_type(filename)[0] or 'application/octet-stream')
L.append('Content-Transfer-Encoding: binary')
L.append('')
L.append(value)
L.append('--' + BOUNDARY + '--')
L.append('')
body = CRLF.join(L)
content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
return content_type, body
def generate_oauth_params(self):
"""
Generates the oauth parameters needed for multipart/form requests
:returns: a dictionary of the proper headers that can be used
in the request
"""
params = {
'oauth_version': "1.0",
'oauth_nonce': oauth.generate_nonce(),
'oauth_timestamp': int(time.time()),
'oauth_token': self.token.key,
'oauth_consumer_key': self.consumer.key
}
return params
BIN +6.28 KB pytumblr/request.pyc
Binary file not shown.
@@ -0,0 +1,3 @@
Flask==0.10.1
Flask-OAuthlib==0.4.3
oauth2==1.5.211
@@ -0,0 +1,6 @@
# get your consumer keys from http://www.tumblr.com/oauth/apps
TUMBLR_CONSUMER_KEY = 'key goes here'
TUMBLR_CONSUMER_SECRET = 'key goes here'
DEBUG = True
SECRET_KEY = 'development'
@@ -0,0 +1,4 @@
html {
margin: 0;
padding: 0;
}
@@ -0,0 +1,31 @@
# Import a Wordpress Blog into Tumblr: wp2tumblr
wp2tumblr is a simple [Flask](http://flask.pocoo.org/docs/) app that will import a Wordpress XML export into Tumblr with publishing dates intact.
# Alpha Version
This script is under active development and has minimal testing. Use at your own risk.
## Requirements
* [Python](http://www.python.org/getit/)
* [pip](https://pypi.python.org/pypi/pip)
## Usage
1. Clone the wp2tumblr repo.
2. Visit http://www.tumblr.com/oauth/apps and register a new application. Set the default callback url to ```http://127.0.0.1:5000```. The rest of the fields can be filled in however you want.
3. Copy settings.py.sample to settings.py and fill in your client keys.
4. Export the path to the settings file: ```$ export WP2TUMBLR_SETTINGS=/path/to/settings.py```
5. Start the server ```$ python wp2tumblr.py```
6. Open your browser to http://127.0.0.1:5000 and follow the instructions
## Help
Submit a [GitHub Issues request](https://github.com/jonthornton/wp2tumblr/issues/new).
------------------
This software is made available under the open source MIT License. © 2014 [Jon Thornton](http://jonthornton.com).
@@ -0,0 +1,12 @@
{% extends "layout.html" %}
{% block body %}
<h1>wp2tumblr &ndash; Wordpress to Tumblr</h1>
{% if userinfo %}
{% for blog in userinfo['user']['blogs'] %}
<div><a href="/upload?tumblog_name={{ blog['name'] }}">{{ blog['name'] }}</a></div>
{% endfor %}
{% else %}
<div><a href="/login">Sign in to Tumblr</a></div>
{% endif %}
{% endblock %}
@@ -0,0 +1,17 @@
<!doctype html>
<html>
<head>
<title>wp2tumblr &ndash; Wordpress to Tumblr</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<div id="wrapper">
{% for message in get_flashed_messages() %}
<div class=flash>{{ message }}</div>
{% endfor %}
{% block body %}{% endblock %}
</div>
</body>
</html>
@@ -0,0 +1,19 @@
{% extends "layout.html" %}
{% block body %}
<h1>wp2tumblr &ndash; Wordpress to Tumblr</h1>
<div>Blog: {{ bloginfo['blog']['title'] }}</div>
<div>URL: {{ bloginfo['blog']['url'] }}</div>
<form method="post" action="/upload" enctype="multipart/form-data">
<div>
<label for="tumblog_name">Wordpress export XML file</label>
<input type="file" name="wordpress_xml" />
<input type="hidden" name="tumblog_name" value="{{ tumblog_name }}" />
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
{% endblock %}
Oops, something went wrong.

0 comments on commit f9a7e7a

Please sign in to comment.