# HG changeset patch # User Peter Sanchez # Date 1368477887 25200 # Mon May 13 13:44:47 2013 -0700 # Node ID ae31f4022020042658ef862fa4358db2570aef09 # Parent 0000000000000000000000000000000000000000 initial import.... diff --git a/.hgignore b/.hgignore new file mode 100644 --- /dev/null +++ b/.hgignore @@ -0,0 +1,12 @@ +syntax:glob +.coverage +.tox +settings_local.py +.*.swp +**.pyc +MANIFEST + + +syntax:regexp +^htmlcov$ +^env$ diff --git a/README.rst b/README.rst new file mode 100644 diff --git a/awesomebox/__init__.py b/awesomebox/__init__.py new file mode 100644 --- /dev/null +++ b/awesomebox/__init__.py @@ -0,0 +1,3 @@ +__version__ = '0.1' + + diff --git a/awesomebox/base.py b/awesomebox/base.py new file mode 100644 --- /dev/null +++ b/awesomebox/base.py @@ -0,0 +1,57 @@ +from collections import namedtuple +from django.conf import settings +from django.utils.importlib import import_module +from django.core.urlresolvers import reverse_lazy + + +Result = namedtuple('Result', ['success', 'message']) + + +class BaseAwesomebox(object): + init_str = '!' + cmd_sep = ' ' + success_url = reverse_lazy('awesomebox_main') + template_name = 'awesomebox/awesomebox.html' + + def __init__(self, cmd): + self.cmd = cmd + + def run_command(self): + cmd = self.cmd + if self.init_str is not None and not cmd.startswith(self.init_str): + return Result(False, 'Invalid command initialization.') + + real_cmd, _, data = cmd[len(self.init_str):].partition(self.cmd_sep) + func = getattr(self, 'cmd_{}'.format(real_cmd, None) + if func is None or not callable(func): + return Result(False, 'Invalid command.') + + result = func(data) + if not isinstance(result, Result): + return Result( + False, + ('Invalid result type given. Expected ' + 'awesomebox.base.Result instance.'), + ) + return result + + def cmd_echo(self, data): + ''' Example function. Returns back the data passed in. + ''' + return Result(True, data) + + +def get_awesomebox_class(): + ''' Return the class to use for Awesomebox dispatching. + ''' + class NullAwesomeBox(BaseAwesomebox): + pass + + cls_path = getattr(settings, 'AWESOMEBOX_CLASS', None) + cls = NullAwesomeBox if cls_path is None else import_module(cls_path) + if not issubclass(cls, BaseAwesomebox): + raise TypeError( + 'Invalid Awesomebox Class. Must subclass ' + 'awesomebox.base.BaseAwesomebox' + ) + return cls diff --git a/awesomebox/forms.py b/awesomebox/forms.py new file mode 100644 --- /dev/null +++ b/awesomebox/forms.py @@ -0,0 +1,5 @@ +from django import forms + + +class AwesomeboxForm(forms.Form): + cmd = forms.CharField(widget=forms.Textarea()) diff --git a/awesomebox/models.py b/awesomebox/models.py new file mode 100644 --- /dev/null +++ b/awesomebox/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/awesomebox/tests.py b/awesomebox/tests.py new file mode 100644 --- /dev/null +++ b/awesomebox/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.assertEqual(1 + 1, 2) diff --git a/awesomebox/urls.py b/awesomebox/urls.py new file mode 100644 --- /dev/null +++ b/awesomebox/urls.py @@ -0,0 +1,9 @@ +from django.conf.urls import patterns, url +from .views import AwesomeboxView + + +urlpatterns = patterns('awesomebox.views', + url(r'^/?$', + AwesomeboxView.as_view(), + name='awesomebox_main'), +) diff --git a/awesomebox/views.py b/awesomebox/views.py new file mode 100644 --- /dev/null +++ b/awesomebox/views.py @@ -0,0 +1,39 @@ +import json +from django.conf import settings +from django.views.base import View +from django.http import HttpResponse +from django.shortcuts import render, redirect +from .forms import AwesomeboxForm +from .base import get_awesomebox_class + +AwesomeboxCls = get_awesomebox_class() + + +class AwesomeboxView(View): + template_name = AwesomeboxCls.template_name + form_class = AwesomeboxForm + success_url = AwesomeboxCls.success_url + + def get(self, request, *args, **kwargs): + form = self.form_class() + return render(request, self.template_name, {'form': form}) + + def post(self, request, *args, **kwargs): + form = self.form_class(request.POST) + if form.is_valid(): + cmd = form.cleaned_data.get('cmd') + abox = AwesomeboxCls(cmd) + result = abox.run_command() + if request.is_ajax(): + result = { + 'success': result.success, + 'message': result.message, + } + return HttpResponse( + json.dumps(result), + mimetype='application/json', + ) + # TODO Add message here for user session + return redirect(self.success_url) + + return render(request, self.template_name, {'form': form}) diff --git a/setup.py b/setup.py new file mode 100644 --- /dev/null +++ b/setup.py @@ -0,0 +1,51 @@ +import os +from distutils.core import setup + +project_name = 'awesomebox' +long_description = open('README.rst').read() + +# Idea from django-registration setup.py +packages, data_files = [], [] +root_dir = os.path.dirname(__file__) +if root_dir: + os.chdir(root_dir) + +for dirpath, dirnames, filenames in os.walk(project_name): + # Ignore dirnames that start with '.' + for i, dirname in enumerate(dirnames): + if dirname.startswith('.'): + del dirnames[i] + if '__init__.py' in filenames: + pkg = dirpath.replace(os.path.sep, '.') + if os.path.altsep: + pkg = pkg.replace(os.path.altsep, '.') + packages.append(pkg) + elif filenames: + prefix = dirpath[(len(project_name) + 1):] + for f in filenames: + data_files.append(os.path.join(prefix, f)) + +setup( + name='django-awesomebox', + version=__import__(project_name).__version__, + package_dir={project_name: project_name}, + packages=packages, + package_data={project_name: data_files}, + description=('Django "awesomebox" to easily dispatch ' + 'commands from an admin dashboard.'), + author='Peter Sanchez', + author_email='petersanchez@gmail.com', + license='BSD License', + url='http://bitbucket.org/petersanchez/django-awesomebox/', + long_description=long_description, + platforms=['any'], + classifiers=[ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Environment :: Web Environment', + ], +) diff --git a/tox.ini b/tox.ini new file mode 100644 --- /dev/null +++ b/tox.ini @@ -0,0 +1,26 @@ +[tox] +downloadcache = {toxworkdir}/cache/ +envlist = py3.3-django1.5,py2.7-django1.5,py2.6-django1.5,py2.7-django1.4,py2.6-django1.4 + +[testenv] +commands = {envpython} runtests.py + +[testenv:py3.3-django1.5] +basepython = python3.3 +deps = django==1.5.1 + +[testenv:py2.7-django1.5] +basepython = python2.7 +deps = django==1.5.1 + +[testenv:py2.7-django1.4] +basepython = python2.7 +deps = django==1.4.5 + +[testenv:py2.6-django1.5] +basepython = python2.6 +deps = django==1.5.1 + +[testenv:py2.6-django1.4] +basepython = python2.6 +deps = django==1.4.5