mirror of
https://github.com/hellosteadman/bambu-buffer.git
synced 2025-05-04 08:29:50 +00:00
Initial commit
This commit is contained in:
commit
5deab02e61
23 changed files with 995 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
*.pyc
|
4
README
Normal file
4
README
Normal file
|
@ -0,0 +1,4 @@
|
|||
Bambu Buffer
|
||||
============
|
||||
|
||||
Post to Buffer and manage profile settings through a Django-powered site.
|
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Bambu Buffer
|
||||
|
||||
Post to Buffer and manage profile settings through a Django-powered site.
|
109
bambu_buffer/__init__.py
Normal file
109
bambu_buffer/__init__.py
Normal file
|
@ -0,0 +1,109 @@
|
|||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.sites.models import Site
|
||||
from django.db.models import Model
|
||||
from bambu_buffer.exceptions import *
|
||||
from bambu_buffer.models import BufferToken, BufferProfile, BufferedItem
|
||||
from bambu_buffer.settings import POST_URL, TIMEOUT, AUTOPOST_MODELS
|
||||
from bambu_buffer.sites import BufferSite
|
||||
from datetime import datetime, date
|
||||
from threading import Thread
|
||||
import requests
|
||||
|
||||
__version__ = '2.0'
|
||||
site = BufferSite()
|
||||
|
||||
class BufferThread(Thread):
|
||||
def __init__(self, token, data, *args, **kwargs):
|
||||
self.data = data
|
||||
self.token = token
|
||||
super(BufferThread, self).__init__(*args, **kwargs)
|
||||
|
||||
def run(self):
|
||||
from bambu_buffer import log
|
||||
|
||||
response = requests.post(
|
||||
'%s?access_token=%s' % (POST_URL, self.token),
|
||||
self.data,
|
||||
timeout = TIMEOUT
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
log.error(response.json())
|
||||
|
||||
def post(item, author, **kwargs):
|
||||
try:
|
||||
token = author.buffer_tokens.get()
|
||||
except BufferToken.DoesNotExist:
|
||||
return
|
||||
|
||||
if 'url' in kwargs:
|
||||
url = kwargs.get('url')
|
||||
elif isinstance(item, Model):
|
||||
url = u'http://%s%s' % (
|
||||
Site.objects.get_current().domain, item.get_absolute_url()
|
||||
)
|
||||
|
||||
content_type = ContentType.objects.get_for_model(item)
|
||||
if BufferedItem.objects.filter(
|
||||
object_id = item.pk,
|
||||
content_type = content_type
|
||||
).exists():
|
||||
print '%s %d has already been sent to Buffer' % (
|
||||
unicode(item._meta.verbose_name).capitalize(),
|
||||
item.pk
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
BufferedItem.objects.create(
|
||||
content_type = content_type,
|
||||
object_id = item.pk
|
||||
)
|
||||
else:
|
||||
url = None
|
||||
|
||||
data = {
|
||||
'text': u'%s%s' % (
|
||||
unicode(kwargs.get('text') or item),
|
||||
url and (u' %s' % url) or u''
|
||||
),
|
||||
'profile_ids[]': kwargs.get('profile_ids') or BufferProfile.objects.filter(
|
||||
service__token = token,
|
||||
selected = True
|
||||
).values_list('remote_id', flat = True),
|
||||
'media[description]': kwargs.get('description')
|
||||
}
|
||||
|
||||
if 'picture' in kwargs:
|
||||
data['media[picture]'] = kwargs['picture']
|
||||
if not 'thumbnail' in kwargs:
|
||||
raise TypeError(
|
||||
'For image-based updates, the thumbnail parameter is required.'
|
||||
)
|
||||
|
||||
if 'thumbnail' in kwargs:
|
||||
data['media[thumbnail]'] = kwargs['thumbnail']
|
||||
|
||||
if 'shorten' in kwargs:
|
||||
data['shorten'] = kwargs['shorten'] and 'true' or 'false'
|
||||
|
||||
if 'now' in kwargs:
|
||||
data['now'] = kwargs['now'] and 'true' or 'false'
|
||||
|
||||
if 'top' in kwargs:
|
||||
data['top'] = kwargs['top'] and 'true' or 'false'
|
||||
|
||||
if 'scheduled_at' in kwargs:
|
||||
if isinstance(kwargs['scheduled_at'], (datetime, date)):
|
||||
data['scheduled_at'] = kwargs['scheduled_at'].isoformat()
|
||||
else:
|
||||
try:
|
||||
data['scheduled_at'] = int(kwargs['scheduled_at'])
|
||||
except:
|
||||
raise TypeError(
|
||||
'scheduled_at must be an integer or DateTime'
|
||||
)
|
||||
|
||||
BufferThread(token.token, data).start()
|
||||
|
||||
site.hookup_signals(AUTOPOST_MODELS)
|
5
bambu_buffer/exceptions.py
Normal file
5
bambu_buffer/exceptions.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
class BufferException(Exception):
|
||||
pass
|
||||
|
||||
class NoBufferTokenException(Exception):
|
||||
pass
|
39
bambu_buffer/log.py
Normal file
39
bambu_buffer/log.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
from django.contrib import messages
|
||||
from django.utils.translation import ugettext as _
|
||||
from bambu_buffer.settings import SUCCESS_MESSAGE, ERROR_MESSAGE
|
||||
from bambu_buffer.exceptions import BufferException
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger('bambu_buffer')
|
||||
def error(data, request = None, raise_error = False):
|
||||
error = data.get('error_description',
|
||||
data.get('message',
|
||||
'error' in data and data.get('error').capitalize().replace('_', ' ') or ''
|
||||
)
|
||||
) or u'Unknown error'
|
||||
|
||||
if 'message' in data:
|
||||
data['error_message'] = data.pop('message')
|
||||
|
||||
logger.error(error, extra = data)
|
||||
|
||||
if request and ERROR_MESSAGE:
|
||||
messages.error(request,
|
||||
_(ERROR_MESSAGE) % error
|
||||
)
|
||||
|
||||
if raise_error:
|
||||
raise BufferException(error)
|
||||
|
||||
def success(data, request = None):
|
||||
message = None
|
||||
if 'access_token' in data:
|
||||
message = u'Buffer access token created'
|
||||
|
||||
if message:
|
||||
logger.info(message)
|
||||
|
||||
if request and SUCCESS_MESSAGE:
|
||||
messages.success(request,
|
||||
_(SUCCESS_MESSAGE)
|
||||
)
|
0
bambu_buffer/management/__init__.py
Normal file
0
bambu_buffer/management/__init__.py
Normal file
0
bambu_buffer/management/commands/__init__.py
Normal file
0
bambu_buffer/management/commands/__init__.py
Normal file
40
bambu_buffer/management/commands/fakebuffer.py
Normal file
40
bambu_buffer/management/commands/fakebuffer.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
from django.db import transaction
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from optparse import make_option
|
||||
from os import sys
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Fake Buffer records for items in settings.BUFFER_AUTOPOST_MODELS'
|
||||
|
||||
@transaction.commit_on_success
|
||||
def handle(self, *args, **options):
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from bambu_buffer import site
|
||||
from bambu_buffer.models import BufferedItem
|
||||
|
||||
for model, info in site._registry.items():
|
||||
query = dict(
|
||||
[
|
||||
(key, callable(value) and value() or value)
|
||||
for (key, value) in info['conditions'].items()
|
||||
]
|
||||
)
|
||||
|
||||
count = 0
|
||||
for pk in model.objects.filter(**query).values_list('pk', flat = True):
|
||||
item, created = BufferedItem.objects.get_or_create(
|
||||
content_type = ContentType.objects.get_for_model(model),
|
||||
object_id = pk
|
||||
)
|
||||
|
||||
if not created:
|
||||
count += 1
|
||||
|
||||
sys.stdout.write(
|
||||
'Added fake Buffer item for %d %s\n' % (
|
||||
count,
|
||||
unicode(
|
||||
count == 1 and model._meta.verbose_name or model._meta.verbose_name_plural
|
||||
)
|
||||
)
|
||||
)
|
118
bambu_buffer/migrations/0001_initial.py
Normal file
118
bambu_buffer/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,118 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding model 'BufferToken'
|
||||
db.create_table('buffer_token', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='buffer_tokens', unique=True, to=orm['auth.User'])),
|
||||
('token', self.gf('django.db.models.fields.CharField')(max_length=36)),
|
||||
))
|
||||
db.send_create_signal(u'buffer', ['BufferToken'])
|
||||
|
||||
# Adding model 'BufferService'
|
||||
db.create_table('buffer_service', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('token', self.gf('django.db.models.fields.related.ForeignKey')(related_name='services', to=orm['buffer.BufferToken'])),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=30)),
|
||||
('remote_id', self.gf('django.db.models.fields.CharField')(max_length=36)),
|
||||
('username', self.gf('django.db.models.fields.CharField')(max_length=30)),
|
||||
))
|
||||
db.send_create_signal(u'buffer', ['BufferService'])
|
||||
|
||||
# Adding model 'BufferProfile'
|
||||
db.create_table('buffer_profile', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('service', self.gf('django.db.models.fields.related.ForeignKey')(related_name='profiles', to=orm['buffer.BufferService'])),
|
||||
('avatar', self.gf('django.db.models.fields.URLField')(max_length=255)),
|
||||
('created_at', self.gf('django.db.models.fields.DateTimeField')()),
|
||||
('default', self.gf('django.db.models.fields.BooleanField')(default=True)),
|
||||
('formatted_username', self.gf('django.db.models.fields.CharField')(max_length=100)),
|
||||
('remote_id', self.gf('django.db.models.fields.CharField')(unique=True, max_length=36)),
|
||||
('schedules', self.gf('django.db.models.fields.TextField')()),
|
||||
))
|
||||
db.send_create_signal(u'buffer', ['BufferProfile'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting model 'BufferToken'
|
||||
db.delete_table('buffer_token')
|
||||
|
||||
# Deleting model 'BufferService'
|
||||
db.delete_table('buffer_service')
|
||||
|
||||
# Deleting model 'BufferProfile'
|
||||
db.delete_table('buffer_profile')
|
||||
|
||||
|
||||
models = {
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
u'buffer.bufferprofile': {
|
||||
'Meta': {'object_name': 'BufferProfile', 'db_table': "'buffer_profile'"},
|
||||
'avatar': ('django.db.models.fields.URLField', [], {'max_length': '255'}),
|
||||
'created_at': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'default': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'formatted_username': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'remote_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'}),
|
||||
'schedules': ('django.db.models.fields.TextField', [], {}),
|
||||
'service': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'profiles'", 'to': u"orm['buffer.BufferService']"})
|
||||
},
|
||||
u'buffer.bufferservice': {
|
||||
'Meta': {'object_name': 'BufferService', 'db_table': "'buffer_service'"},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
|
||||
'remote_id': ('django.db.models.fields.CharField', [], {'max_length': '36'}),
|
||||
'token': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'services'", 'to': u"orm['buffer.BufferToken']"}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'max_length': '30'})
|
||||
},
|
||||
u'buffer.buffertoken': {
|
||||
'Meta': {'object_name': 'BufferToken', 'db_table': "'buffer_token'"},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'token': ('django.db.models.fields.CharField', [], {'max_length': '36'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'buffer_tokens'", 'unique': 'True', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['buffer']
|
|
@ -0,0 +1,87 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding field 'BufferProfile.selected'
|
||||
db.add_column('buffer_profile', 'selected',
|
||||
self.gf('django.db.models.fields.BooleanField')(default=1),
|
||||
keep_default=False)
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting field 'BufferProfile.selected'
|
||||
db.delete_column('buffer_profile', 'selected')
|
||||
|
||||
|
||||
models = {
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
u'buffer.bufferprofile': {
|
||||
'Meta': {'object_name': 'BufferProfile', 'db_table': "'buffer_profile'"},
|
||||
'avatar': ('django.db.models.fields.URLField', [], {'max_length': '255'}),
|
||||
'created_at': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'default': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'formatted_username': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'remote_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'}),
|
||||
'schedules': ('django.db.models.fields.TextField', [], {}),
|
||||
'selected': ('django.db.models.fields.BooleanField', [], {}),
|
||||
'service': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'profiles'", 'to': u"orm['buffer.BufferService']"})
|
||||
},
|
||||
u'buffer.bufferservice': {
|
||||
'Meta': {'object_name': 'BufferService', 'db_table': "'buffer_service'"},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
|
||||
'remote_id': ('django.db.models.fields.CharField', [], {'max_length': '36'}),
|
||||
'token': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'services'", 'to': u"orm['buffer.BufferToken']"}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'max_length': '30'})
|
||||
},
|
||||
u'buffer.buffertoken': {
|
||||
'Meta': {'object_name': 'BufferToken', 'db_table': "'buffer_token'"},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'token': ('django.db.models.fields.CharField', [], {'max_length': '36'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'buffer_tokens'", 'unique': 'True', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['buffer']
|
|
@ -0,0 +1,102 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding model 'BufferedItem'
|
||||
db.create_table(u'buffer_buffereditem', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
|
||||
('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
|
||||
))
|
||||
db.send_create_signal(u'buffer', ['BufferedItem'])
|
||||
|
||||
# Adding unique constraint on 'BufferedItem', fields ['content_type', 'object_id']
|
||||
db.create_unique(u'buffer_buffereditem', ['content_type_id', 'object_id'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Removing unique constraint on 'BufferedItem', fields ['content_type', 'object_id']
|
||||
db.delete_unique(u'buffer_buffereditem', ['content_type_id', 'object_id'])
|
||||
|
||||
# Deleting model 'BufferedItem'
|
||||
db.delete_table(u'buffer_buffereditem')
|
||||
|
||||
|
||||
models = {
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
u'buffer.buffereditem': {
|
||||
'Meta': {'unique_together': "(('content_type', 'object_id'),)", 'object_name': 'BufferedItem'},
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
|
||||
},
|
||||
u'buffer.bufferprofile': {
|
||||
'Meta': {'object_name': 'BufferProfile', 'db_table': "'buffer_profile'"},
|
||||
'avatar': ('django.db.models.fields.URLField', [], {'max_length': '255'}),
|
||||
'created_at': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'default': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'formatted_username': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'remote_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '36'}),
|
||||
'schedules': ('django.db.models.fields.TextField', [], {}),
|
||||
'selected': ('django.db.models.fields.BooleanField', [], {}),
|
||||
'service': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'profiles'", 'to': u"orm['buffer.BufferService']"})
|
||||
},
|
||||
u'buffer.bufferservice': {
|
||||
'Meta': {'object_name': 'BufferService', 'db_table': "'buffer_service'"},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
|
||||
'remote_id': ('django.db.models.fields.CharField', [], {'max_length': '36'}),
|
||||
'token': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'services'", 'to': u"orm['buffer.BufferToken']"}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'max_length': '30'})
|
||||
},
|
||||
u'buffer.buffertoken': {
|
||||
'Meta': {'object_name': 'BufferToken', 'db_table': "'buffer_token'"},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'token': ('django.db.models.fields.CharField', [], {'max_length': '36'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'buffer_tokens'", 'unique': 'True', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['buffer']
|
0
bambu_buffer/migrations/__init__.py
Normal file
0
bambu_buffer/migrations/__init__.py
Normal file
116
bambu_buffer/models.py
Normal file
116
bambu_buffer/models.py
Normal file
|
@ -0,0 +1,116 @@
|
|||
from django.db import models
|
||||
from django.utils.timezone import pytz
|
||||
from bambu_buffer.settings import PROFILES_URL, TIMEOUT
|
||||
from bambu_buffer import log, helpers
|
||||
from datetime import datetime, timedelta
|
||||
import requests, json
|
||||
|
||||
class BufferToken(models.Model):
|
||||
user = models.ForeignKey('auth.User', related_name = 'buffer_tokens', unique = True)
|
||||
token = models.CharField(max_length = 36)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.token
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
new = not self.pk
|
||||
super(BufferToken, self).save(*args, **kwargs)
|
||||
|
||||
if new:
|
||||
self.refresh_services()
|
||||
|
||||
def refresh_services(self):
|
||||
response = requests.get(
|
||||
'%s?access_token=%s' % (
|
||||
PROFILES_URL,
|
||||
self.token
|
||||
),
|
||||
timeout = TIMEOUT
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
self.services.all().delete()
|
||||
services = {}
|
||||
for profile in response.json():
|
||||
remote_id = profile['formatted_service']
|
||||
if remote_id in services:
|
||||
service = services[remote_id]
|
||||
else:
|
||||
service = self.services.create(
|
||||
remote_id = profile[u'service_id'],
|
||||
name = remote_id,
|
||||
username = profile['service_username']
|
||||
)
|
||||
|
||||
services[service.remote_id] = service
|
||||
|
||||
epoch = datetime(1970, 1, 1, 0, 0, 0,
|
||||
tzinfo = pytz.timezone(
|
||||
profile['timezone']
|
||||
)
|
||||
)
|
||||
|
||||
service.profiles.create(
|
||||
avatar = profile.get('avatar_https',
|
||||
profile.get('avatar')
|
||||
),
|
||||
created_at = epoch + timedelta(
|
||||
seconds = profile['created_at']
|
||||
),
|
||||
default = profile['default'],
|
||||
selected = profile['default'],
|
||||
formatted_username = profile['formatted_username'],
|
||||
remote_id = profile['id'],
|
||||
schedules = json.dumps(
|
||||
profile['schedules']
|
||||
)
|
||||
)
|
||||
else:
|
||||
log.error(response.json(), request)
|
||||
|
||||
class Meta:
|
||||
db_table = 'buffer_token'
|
||||
|
||||
class BufferService(models.Model):
|
||||
token = models.ForeignKey(BufferToken, related_name = 'services')
|
||||
name = models.CharField(max_length = 30)
|
||||
remote_id = models.CharField(max_length = 36)
|
||||
username = models.CharField(max_length = 30)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
return self.name.lower().split(' ')[0].replace('+', '-plus')
|
||||
|
||||
class Meta:
|
||||
db_table = 'buffer_service'
|
||||
|
||||
class BufferProfile(models.Model):
|
||||
service = models.ForeignKey(BufferService, related_name = 'profiles')
|
||||
avatar = models.URLField(max_length = 255)
|
||||
created_at = models.DateTimeField()
|
||||
default = models.BooleanField(default = True)
|
||||
formatted_username = models.CharField(max_length = 100)
|
||||
remote_id = models.CharField(max_length = 36, unique = True)
|
||||
schedules = models.TextField()
|
||||
selected = models.BooleanField()
|
||||
|
||||
def __unicode__(self):
|
||||
return self.formatted_username
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
return self.service.icon
|
||||
|
||||
class Meta:
|
||||
db_table = 'buffer_profile'
|
||||
|
||||
class BufferedItem(models.Model):
|
||||
content_type = models.ForeignKey('contenttypes.ContentType')
|
||||
object_id = models.PositiveIntegerField()
|
||||
|
||||
class Meta:
|
||||
unique_together = ('content_type', 'object_id')
|
||||
db_table = 'buffer_buffereditem'
|
44
bambu_buffer/settings.py
Normal file
44
bambu_buffer/settings.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
from django.conf import settings as s
|
||||
from django.utils.timezone import now
|
||||
|
||||
CLIENT_ID = s.BUFFER_CLIENT_ID
|
||||
CLIENT_SECRET = s.BUFFER_CLIENT_SECRET
|
||||
AUTH_REDIRECT = getattr(s, 'BUFFER_AUTH_REDIRECT', '/')
|
||||
SUCCESS_MESSAGE = getattr(s, 'BUFFER_SUCCESS_MESSAGE',
|
||||
u'Your Buffer account is now conntected.'
|
||||
)
|
||||
|
||||
ERROR_MESSAGE = getattr(s, 'BUFFER_ERROR_MESSAGE',
|
||||
u'Sorry, your account could not be connected to Buffer: %s.'
|
||||
)
|
||||
|
||||
UPDATED_MESSAGE = getattr(s, 'BUFFER_UPDATED_MESSAGE',
|
||||
u'Your Buffer settings have been updated.'
|
||||
)
|
||||
|
||||
REFRESHED_MESSAGES = getattr(s, 'BUFFER_REFRESHED_MESSAGES',
|
||||
u'Your Buffer profiles have been refreshed.'
|
||||
)
|
||||
|
||||
AUTOPOST_MODELS = getattr(s, 'BUFFER_AUTOPOST_MODELS',
|
||||
(
|
||||
(
|
||||
'blog.Post',
|
||||
'author', {
|
||||
'published': True,
|
||||
'date__lte': now
|
||||
},
|
||||
{
|
||||
'top': True
|
||||
}
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
TIMEOUT = getattr(s, 'BUFFER_TIMEOUT', 5)
|
||||
AUTHORISE_URL = 'https://bufferapp.com/oauth2/authorize'
|
||||
TOKEN_URL = 'https://api.bufferapp.com/1/oauth2/token.json'
|
||||
PROFILES_URL = 'https://api.bufferapp.com/1/profiles.json'
|
||||
POST_URL = 'https://api.bufferapp.com/1/updates/create.json'
|
||||
RESPONSE_TYPE = 'code'
|
||||
AUTHORISATION_CODE = 'authorization_code'
|
101
bambu_buffer/sites.py
Normal file
101
bambu_buffer/sites.py
Normal file
|
@ -0,0 +1,101 @@
|
|||
from logging import getLogger
|
||||
from django.db.models.loading import get_model
|
||||
from django.db.models.signals import post_save
|
||||
|
||||
def post_save_receiver(sender, instance, **kwargs):
|
||||
from bambu_buffer import post, site
|
||||
|
||||
model = site.get_info(type(instance))
|
||||
if not model or not any(model):
|
||||
print '%s not registered' % (
|
||||
unicode(instance._meta.verbose_name).capitalize()
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
if any(model['conditions']):
|
||||
query = dict(
|
||||
[
|
||||
(key, callable(value) and value() or value)
|
||||
for (key, value) in model['conditions'].items()
|
||||
]
|
||||
)
|
||||
|
||||
if not type(instance).objects.filter(
|
||||
pk = instance.pk,
|
||||
**query
|
||||
).exists():
|
||||
print '%s does not match Buffer criteria' % unicode(
|
||||
unicode(instance._meta.verbose_name).capitalize()
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
post(
|
||||
instance,
|
||||
getattr(instance,
|
||||
model['author_field']
|
||||
),
|
||||
**dict(
|
||||
[
|
||||
(key, callable(value) and value() or value)
|
||||
for (key, value) in model['post_kwargs'].items()
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
class BufferSite(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._registry = {}
|
||||
|
||||
def register(self, model, author_field, conditions = {}, post_kwargs = {}):
|
||||
self._registry[model] = {
|
||||
'author_field': author_field,
|
||||
'conditions': conditions,
|
||||
'post_kwargs': post_kwargs
|
||||
}
|
||||
|
||||
def get_info(self, model):
|
||||
return self._registry.get(model)
|
||||
|
||||
def hookup_signals(self, models):
|
||||
logger = getLogger('bambu_buffer')
|
||||
for m in [list(m) for m in models]:
|
||||
if not any(m):
|
||||
continue
|
||||
|
||||
name = m.pop(0)
|
||||
if any(m):
|
||||
author_field = m.pop(0)
|
||||
else:
|
||||
author_field = 'author'
|
||||
|
||||
if any(m):
|
||||
conditions = m.pop(0)
|
||||
else:
|
||||
conditions = {}
|
||||
|
||||
if any(m):
|
||||
post_kwargs = m.pop(0)
|
||||
else:
|
||||
post_kwargs = {}
|
||||
|
||||
try:
|
||||
model = get_model(*name.split('.'))
|
||||
except:
|
||||
logger.warn('Model %s not found' % name)
|
||||
continue
|
||||
|
||||
field = model._meta.get_field_by_name(author_field)
|
||||
if not any(field) or field[0] is None:
|
||||
raise Exception(
|
||||
'Field %s not found in model %s' % (author_field, name)
|
||||
)
|
||||
|
||||
self.register(model,
|
||||
author_field = author_field,
|
||||
conditions = conditions,
|
||||
post_kwargs = post_kwargs
|
||||
)
|
||||
|
||||
post_save.connect(post_save_receiver, sender = model)
|
1
bambu_buffer/templates/buffer/base.html
Normal file
1
bambu_buffer/templates/buffer/base.html
Normal file
|
@ -0,0 +1 @@
|
|||
{% extends 'base.html' %}
|
35
bambu_buffer/templates/buffer/profiles.html
Normal file
35
bambu_buffer/templates/buffer/profiles.html
Normal file
|
@ -0,0 +1,35 @@
|
|||
{% extends 'buffer/base.html' %}
|
||||
{% load i18n icons %}
|
||||
|
||||
{% block page_header %}
|
||||
<h1>{% trans 'Your Buffer profiles' %}</h1>
|
||||
<p>{% trans 'Select the Buffer profiles you want to automatically post to.' %}</p>
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block form_content %}
|
||||
<form method="post">
|
||||
<ul class="media-list">
|
||||
{% for profile in profiles %}
|
||||
<li class="media">
|
||||
<div class="pull-left">
|
||||
<img class="media-object" src="{{ profile.avatar }}" alt="{{ profile }}" width="50" height="50" />
|
||||
</div>
|
||||
|
||||
<div class="media-body">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input name="profiles" type="checkbox" value="{{ profile.pk }}"{% if profile.selected %} checked{% endif %} />
|
||||
<span class="h4">{{ profile }}</span><br />
|
||||
{% icon profile.icon %} <span class="p">{{ profile.service }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% csrf_token %}
|
||||
<button class="btn btn-primary">{% trans 'Save settings' %}</button>
|
||||
<a class="btn btn-default" href="{% url 'buffer_refresh' %}">{% icon 'refresh' %} {% trans 'Reload my Buffer profiles' %}</a>
|
||||
</form>
|
||||
{% endblock form_content %}
|
12
bambu_buffer/tests.py
Normal file
12
bambu_buffer/tests.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
from bambu_buffer.views import auth
|
||||
|
||||
class AuthorisationTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.client = RequestFactory()
|
||||
|
||||
def test_authorisation(self):
|
||||
request = self.client.get('/buffer/auth/')
|
||||
response = auth(request)
|
||||
response
|
8
bambu_buffer/urls.py
Normal file
8
bambu_buffer/urls.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from django.conf.urls import patterns, url
|
||||
|
||||
urlpatterns = patterns('bambu_buffer.views',
|
||||
url('^$', 'profiles', name = 'buffer_profiles'),
|
||||
url('^refresh/$', 'refresh', name = 'buffer_refresh'),
|
||||
url('^auth/$', 'auth', name = 'buffer_auth'),
|
||||
url('^callback/$', 'callback', name = 'buffer_callback')
|
||||
)
|
135
bambu_buffer/views.py
Normal file
135
bambu_buffer/views.py
Normal file
|
@ -0,0 +1,135 @@
|
|||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.contrib import messages
|
||||
from django.db import transaction
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.template.response import TemplateResponse
|
||||
from django.utils.http import urlencode
|
||||
from bambu_buffer import settings, log
|
||||
from bambu_buffer.models import BufferToken, BufferProfile
|
||||
import requests
|
||||
|
||||
@login_required
|
||||
def auth(request):
|
||||
next = request.GET.get('next', settings.AUTH_REDIRECT)
|
||||
request.session['bambu_buffer.next'] = next
|
||||
|
||||
return HttpResponseRedirect(
|
||||
'%s?%s' % (
|
||||
settings.AUTHORISE_URL,
|
||||
urlencode(
|
||||
{
|
||||
'client_id': settings.CLIENT_ID,
|
||||
'redirect_uri': 'http%s://%s%s' % (
|
||||
request.is_secure() and 's' or '',
|
||||
Site.objects.get_current(),
|
||||
reverse('buffer_callback')
|
||||
),
|
||||
'response_type': settings.RESPONSE_TYPE
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@login_required
|
||||
def callback(request):
|
||||
response = requests.post(
|
||||
settings.TOKEN_URL,
|
||||
data = {
|
||||
'client_id': settings.CLIENT_ID,
|
||||
'client_secret': settings.CLIENT_SECRET,
|
||||
'redirect_uri': 'http%s://%s%s' % (
|
||||
request.is_secure() and 's' or '',
|
||||
Site.objects.get_current(),
|
||||
reverse('buffer_callback')
|
||||
),
|
||||
'code': request.GET.get('code'),
|
||||
'grant_type': settings.AUTHORISATION_CODE
|
||||
},
|
||||
timeout = settings.TIMEOUT
|
||||
)
|
||||
|
||||
next = request.session.get('bambu_buffer.next',
|
||||
settings.AUTH_REDIRECT
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
token = data.get('access_token')
|
||||
|
||||
with transaction.commit_on_success():
|
||||
request.user.buffer_tokens.all().delete()
|
||||
request.user.buffer_tokens.create(
|
||||
token = token
|
||||
)
|
||||
|
||||
log.success(data, request)
|
||||
return HttpResponseRedirect(
|
||||
reverse('buffer_profiles')
|
||||
)
|
||||
else:
|
||||
log.error(response.json(), request)
|
||||
|
||||
return HttpResponseRedirect(next)
|
||||
|
||||
@login_required
|
||||
def profiles(request):
|
||||
try:
|
||||
token = request.user.buffer_tokens.get()
|
||||
except BufferToken.DoesNotExist:
|
||||
return HttpResponseRedirect(
|
||||
reverse('buffer_auth')
|
||||
)
|
||||
|
||||
if request.method == 'POST':
|
||||
selected = request.POST.getlist('profiles')
|
||||
for pk in selected:
|
||||
BufferProfile.objects.filter(
|
||||
service__token = token,
|
||||
pk = pk
|
||||
).update(
|
||||
selected = True
|
||||
)
|
||||
|
||||
BufferProfile.objects.filter(
|
||||
service__token = token
|
||||
).exclude(
|
||||
pk__in = selected
|
||||
).update(
|
||||
selected = False
|
||||
)
|
||||
|
||||
if settings.UPDATED_MESSAGE:
|
||||
messages.success(request, settings.UPDATED_MESSAGE)
|
||||
|
||||
return HttpResponseRedirect(
|
||||
reverse('buffer_profiles')
|
||||
)
|
||||
|
||||
return TemplateResponse(
|
||||
request,
|
||||
'buffer/profiles.html',
|
||||
{
|
||||
'profiles': BufferProfile.objects.filter(
|
||||
service__token = token
|
||||
).select_related()
|
||||
}
|
||||
)
|
||||
|
||||
@login_required
|
||||
def refresh(request):
|
||||
try:
|
||||
token = request.user.buffer_tokens.get()
|
||||
except BufferToken.DoesNotExist:
|
||||
return HttpResponseRedirect(
|
||||
reverse('buffer_auth')
|
||||
)
|
||||
|
||||
token.refresh_services()
|
||||
if settings.REFRESHED_MESSAGES:
|
||||
messages.success(request, settings.REFRESHED_MESSAGES)
|
||||
|
||||
return HttpResponseRedirect(
|
||||
reverse('buffer_profiles')
|
||||
)
|
2
requirements.txt
Normal file
2
requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
Django>=1.6
|
||||
requests>=2.0
|
33
setup.py
Normal file
33
setup.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/env python
|
||||
from setuptools import setup
|
||||
from os import path
|
||||
|
||||
setup(
|
||||
name = 'bambu-buffer',
|
||||
version = '2.0',
|
||||
description = 'Post to Buffer and manage profile settings through a Django-powered site',
|
||||
author = 'Steadman',
|
||||
author_email = 'mark@steadman.io',
|
||||
url = 'https://github.com/iamsteadman/bambu-buffer',
|
||||
long_description = open(path.join(path.dirname(__file__), 'README')).read(),
|
||||
packages = [
|
||||
'bambu_buffer',
|
||||
'bambu_buffer.migrations',
|
||||
'bambu_buffer.management',
|
||||
'bambu_buffer.management.commands'
|
||||
],
|
||||
package_data = {
|
||||
'bambu_buffer': [
|
||||
'templates/buffer/*.html'
|
||||
]
|
||||
},
|
||||
install_requires = [
|
||||
'Django>=1.6',
|
||||
'requests>=2.0'
|
||||
],
|
||||
classifiers = [
|
||||
'Development Status :: 4 - Beta',
|
||||
'Environment :: Web Environment',
|
||||
'Framework :: Django'
|
||||
]
|
||||
)
|
Loading…
Reference in a new issue