diff --git a/.gitignore b/.gitignore
index 5538d3f..b92df6c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,6 @@
-*.egg-info
*.pyc
*.pyo
-.DS_Store
-.epio-app
-dist
-docs/_build
-env
-production.cfg
+*.swp
+*.un~
+*.db
+static_root/
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index aadd9e3..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,14 +0,0 @@
-Copyright (c) 2011, Ori Livneh
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
diff --git a/README.md b/README.md
deleted file mode 100644
index 922ffcb..0000000
--- a/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# Marcel
-
-Marcel is a free and simple web application for co-ordinating mutual aid. It is
-built on top of the Flask web framework and Redis.
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/epio.ini b/epio.ini
index 0dc07d3..68c3266 100644
--- a/epio.ini
+++ b/epio.ini
@@ -1,18 +1,22 @@
# epio.ini for permabank
+[django]
+append_settings = false
+base = .
+
[wsgi]
requirements = requirements.txt
-entrypoint = permabank:app
-
-[static]
-/static = permabank/static
[services]
+postgres = true
redis = true
[redis]
memory = 16
+[static]
+/static = static_root
+/media = ../data
+
[env]
EPIO = true
-PERMABANK_SETTINGS = ../production.cfg
diff --git a/epio_commands/__init__.py b/epio_commands/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/epio_commands/management/__init__.py b/epio_commands/management/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/epio_commands/management/commands/__init__.py b/epio_commands/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/epio_commands/management/commands/epio_flush_cache.py b/epio_commands/management/commands/epio_flush_cache.py
new file mode 100644
index 0000000..0936e5a
--- /dev/null
+++ b/epio_commands/management/commands/epio_flush_cache.py
@@ -0,0 +1,10 @@
+from django.core.cache import cache
+
+from django.core.management.base import NoArgsCommand
+
+class Command(NoArgsCommand):
+ help = 'Flushes the cache.'
+
+ def handle_noargs(self, **options):
+ cache.clear()
+ print "Cache flushed."
diff --git a/epio_commands/management/commands/epio_flush_redis.py b/epio_commands/management/commands/epio_flush_redis.py
new file mode 100644
index 0000000..fc2e789
--- /dev/null
+++ b/epio_commands/management/commands/epio_flush_redis.py
@@ -0,0 +1,12 @@
+import redis
+from bundle_config import config
+
+from django.core.management.base import NoArgsCommand
+
+class Command(NoArgsCommand):
+ help = 'Flushes all keys in redis.'
+
+ def handle_noargs(self, **options):
+ r = redis.Redis(host=config['redis']['host'], port=int(config['redis']['port']), password=config['redis']['password'])
+ r.flushall()
+ print "All redis keys flushed."
diff --git a/epio_commands/models.py b/epio_commands/models.py
new file mode 100644
index 0000000..e69de29
diff --git a/fabfile.py b/fabfile.py
new file mode 100644
index 0000000..e0a3301
--- /dev/null
+++ b/fabfile.py
@@ -0,0 +1,21 @@
+from fabric.api import local, env
+
+def production():
+ env['epioapp'] = # production epio instance name
+
+def staging():
+ env['epioapp'] = # staging epio instance
+
+def epio(commandstring):
+ local("epio {0} -a {1}".format(
+ commandstring,
+ env['epioapp']))
+
+def deploy():
+ """ An example deploy workflow """
+ local("./manage.py collectstatic")
+ epio('upload')
+ epio('django syncdb')
+ epio('django migrate')
+ epio('django epio_flush_cache')
+
diff --git a/install_deps b/install_deps
new file mode 100644
index 0000000..e483da0
--- /dev/null
+++ b/install_deps
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+pip install -r requirements.txt
diff --git a/manage.py b/manage.py
new file mode 100644
index 0000000..3e4eedc
--- /dev/null
+++ b/manage.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+from django.core.management import execute_manager
+import imp
+try:
+ imp.find_module('settings') # Assumed to be in the same directory.
+except ImportError:
+ import sys
+ sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__)
+ sys.exit(1)
+
+import settings
+
+if __name__ == "__main__":
+ execute_manager(settings)
diff --git a/permabank.db b/permabank.db
new file mode 100644
index 0000000..3c8fed9
Binary files /dev/null and b/permabank.db differ
diff --git a/permabank.sh b/permabank.sh
index 379cffd..5f29f64 100644
--- a/permabank.sh
+++ b/permabank.sh
@@ -1,11 +1,6 @@
#!/bin/env bash
# functions and aliases
-# resets the app
-function resetapp () {
- python -c "import permabank;print permabank.reset() is None"
-}
-
# starts a redis-cli session on epio-hosted instance
function epio-redis () {
epio run_command python -a permabank -- -c "\"from bundle_config import config;from subprocess import call;r=config['redis'];call(['redis-cli','-h',r['host'],'-p',r['port'],'-a',r['password']])\""
diff --git a/permabank/__init__.py b/permabank/__init__.py
deleted file mode 100644
index 0a549f3..0000000
--- a/permabank/__init__.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- Permabank
- ---------
-
- :copyright: (c) 2011 By Ori Livneh
- :license: GPLv3, see LICENSE for more details.
-"""
-from flask import Flask
-from flaskext.babel import Babel, format_datetime
-from flaskext.openid import OpenID
-from openidredis import RedisStore
-from redis import Redis, RedisError
-
-from permabank.timesince import timesince
-
-
-# settings
-CSRF_ENABLED = True
-DEBUG = True
-SECRET_KEY = 'development key'
-REDIS = {
- 'host': 'localhost',
- 'port': 6379,
- 'password': None,
- 'db': 0
-}
-
-# Initialize app. Defaults are loaded from the namespace of this module. If the
-# PERMABANK_SETTINGS environment variable is set, import settings from whatever
-# file it points to.
-app = Flask(__name__)
-app.config.from_object(__name__)
-app.config.from_envvar('PERMABANK_SETTINGS', silent=True)
-
-# Configure a Redis connection instance
-redis = Redis(**app.config['REDIS'])
-redis.error = RedisError # for convenience's sake; use in try/except
-
-# Set up flask-openid to use Redis as its datastore
-redis_store_factory = lambda: RedisStore(key_prefix='permabank:oid', conn=redis)
-oid = OpenID(app, store_factory=redis_store_factory)
-
-app.config['OPENID_PROVIDERS'] = {
- 'google': 'https://www.google.com/accounts/o8/id',
- 'yahoo': 'https://yahoo.com/',
-}
-
-# Set up flask-babel and register dependent template filters
-babel = Babel(app)
-app.jinja_env.filters['format_datetime'] = format_datetime
-app.jinja_env.filters['timesince'] = timesince
-
-
-def reset_app():
- """ Reset Permabank by deleting all associated keys """
- keys = redis.keys('permabank:*')
- if keys:
- redis.delete(*keys)
-
-# Views must be loaded after the application object is created:
-# See http://flask.pocoo.org/docs/patterns/packages/
-import permabank.views
diff --git a/permabank/forms.py b/permabank/forms.py
deleted file mode 100644
index 2fbbba5..0000000
--- a/permabank/forms.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- HTML form definitions for Marcel
-
- :copyright: (c) 2011 By Ori Livneh
- :license: GPLv3, see LICENSE for more details.
-"""
-from flaskext.wtf import (
- Form,
- SelectField,
- TextAreaField,
- TextField,
- validators
-)
-
-
-class EntryForm(Form):
- """ Represents an HTML form for a Marcel entry """
- entry_type = SelectField(
- label='Type of Entry',
- choices=[('request', 'I have a request'),
- ('offer', 'I have something to offer')]
- )
-
- summary = TextField(
- label='Summary',
- validators=[validators.Length(max=140), validators.Required()],
- description="Headline for your entry, in 140 characters or fewer"
- )
-
- details = TextAreaField(
- label='Details',
- validators=[validators.Length(max=1000), validators.Required()],
- description="1000 characters max."
- )
-
- contact_info = TextField(
- label='Contact Information',
- validators=[validators.Length(max=140), validators.Required()],
- description="A phone number, email address, location, etc."
- )
diff --git a/permabank/gravatars.py b/permabank/gravatars.py
deleted file mode 100644
index f5b6272..0000000
--- a/permabank/gravatars.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from urllib import urlencode
-from hashlib import md5
-
-from marcel import app
-
-def get_gravatar_url(email, default=None, size=40):
- """ Generates a gravatar URL for a given email address """
- if default is None:
- default = app.config['DEFAULT_GRAVATAR_URL']
- email = email.lower()
- digest = md5(email).hexdigest()
- q = urlencode({'d': default, 's': size})
- return "http://www.gravatar.com/avatar/%s?%s" % (digest, q)
diff --git a/permabank/models.py b/permabank/models.py
deleted file mode 100644
index 35bd631..0000000
--- a/permabank/models.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- Mapping of Python objects to Redis datatypes for Permabank
-
- :copyright: (c) 2011 By Ori Livneh
- :license: GPLv3, see LICENSE for more details.
-"""
-from datetime import datetime
-from uuid import uuid5, NAMESPACE_URL
-
-import dateutil.parser
-from flask import session
-
-from permabank import redis
-
-
-class User(object):
- """ Represents a Permabank user / author """
- def __init__(self, uuid=None, openid=None):
- """ Creates a User instance; one of `uuid` or `openid` is required """
- if uuid:
- self.uuid = uuid
- elif openid:
- self.uuid = uuid5(NAMESPACE_URL, openid)
- else:
- raise TypeError("Either a uuid or an openid is required")
- self.key = "permabank:user:%s" % self.uuid
-
- def from_session(self):
- """ Gets the current user based on the value of `openid` in the session
- context """
- return User(openid=session['openid'])
-
- def exists(self):
- """ Check whether or not User exists in Redis """
- return redis.exists(self.key)
-
- def get(self):
- """ Retrieve a User from Redis """
- return redis.hgetall(self.key)
-
- def set(self, **kwargs):
- """ Store User attributes in Redis """
- redis.hmset(self.key, {key: val for key, val in kwargs.items() if val})
-
-
-class EntryManager(object):
- """
- The EntryManager class manages both requests and offers.
- """
- def __init__(self, type):
- """ Instantiates a manager for `type` entry type """
- self.type = type
-
- def get(self, uid):
- """ Retrieves record `uid` from Redis """
- item = redis.hgetall("permabank:%s:%s" % (self.type, uid))
- item['type'] = self.type
- item['pubdate'] = dateutil.parser.parse(item['pubdate'])
- return item
-
- def all(self):
- """ Gets all records of type self.type """
- keys = redis.lrange(name="permabank:%s" % self.type, start=0, end=-1)
- items = [self.get(uid) for uid in keys]
- return items
-
- def add(self, user, summary, details, contact_info, pubdate=None):
- """ Adds a new entry """
- if pubdate is None:
- pubdate = datetime.now().isoformat()
- # TODO(Ori): Should we batch these into a single transaction?
- uid = redis.incr("permabank:%s:next_uid" % self.type)
- redis.rpush("permabank:%s" % self.type, uid)
- redis.hmset("permabank:%s:%s" % (self.type, uid), {
- 'user': user.uuid,
- 'summary': summary,
- 'details': details,
- 'contact_info': contact_info,
- 'pubdate': pubdate
- })
- return uid
-
-# Initialize managers for the two types of entries we have:
-requests = EntryManager("request")
-offers = EntryManager("offer")
diff --git a/permabank/static/openid.png b/permabank/static/openid.png
deleted file mode 100644
index b57e66d..0000000
Binary files a/permabank/static/openid.png and /dev/null differ
diff --git a/permabank/static/permabank.js b/permabank/static/permabank.js
deleted file mode 100644
index 8359ed7..0000000
--- a/permabank/static/permabank.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Javascript code for Marcel. Requires jQuery >= 1.4.3
-//
-// :copyright: (c) 2011 by Ori Livneh
-// :license: GPLv3, see LICENSE for more details.
-(function ($) {
- $(document).ready(function() {
- // Fade out any alerts after a delay
- $('.flash-message').delay(1000).fadeOut('slow');
-
- // Expand/contract entries by clicking on the headline
- $('article header').click(function() {
- $('article header').not(this).next().slideUp();
- $(this).next().slideToggle();
- });
- });
-}(jQuery));
diff --git a/permabank/static/style.css b/permabank/static/style.css
deleted file mode 100644
index 5a201d8..0000000
--- a/permabank/static/style.css
+++ /dev/null
@@ -1,116 +0,0 @@
-/* vim: set ts=2 sw=2: */
-
-h1 {
- font-family: 'Ubuntu', sans-serif;
- font-weight: 400;
-}
-
-div#container > header > h1 {
- font-size: 72px;
- line-height: 52px;
- color: #f38630;
-}
-
-body {
- font-family: "Lucida Grande", "Lucida Sans Unicode", "Trebuchet MS", Helvetica, Arial, Verdana, sans-serif;
- font-size: 13px;
- margin: 0;
- padding: 0;
-}
-
-div.entry_body {
- display: none;
-}
-
-div#container {
- margin: 48px auto;
- padding: 0;
- width: 740px;
-}
-
-section h1 {
- font-size: 48px;
-}
-
-article.entry {
- padding: 8px;
- margin: 16px 0;
- font-size: 24px;
- font-weight: nro
-}
-
-article header {
- cursor: pointer;
-}
-
-article.entry h1 {
- margin: 0;
- color: #4c4a52;
- font-weight: 800;
- font-size: 24px;
- line-height: 24px;
-}
-
-article.request {
- background: #0e2f59;
- color: #cec7d1;
-}
-
-article.request h1 {
- color: #fff;
-}
-
-article.offer div.entry_body p {
- color: #293137;
-}
-
-article.request div.entry_body p {
- color: #f2c288;
-}
-
-article.offer {
- background: #eaecec;
- color: #86a0b7;
-}
-article header h1 {
- font-size: 16px;
-}
-
-p[class^="flash"] {
- background: none repeat scroll 0 0 #fffccf;
- border: 1px solid #fffccf;
- border-radius: 0 0 5px 5px;
- color: #000000;
- left: 50%;
- margin: 0 0 0 -200px;
- padding: 5px;
- position: fixed;
- text-align: center;
- top: 0;
- width: 400px;
- z-index: 1000;
- font-size: 17px;
-}
-
-label small {
- display: block;
-}
-
-input.openid {
- background: url(openid.png) no-repeat 4px center;
- padding-left: 26px;
-}
-
-input, textarea, select {
- border: 1px solid black;
- padding: 2px;
- background: white;
- font-family: 'Georgia', serif;
- font-size: 17px;
- color: #004b6b;
-}
-
-textarea {
- width: 99%;
-}
-
diff --git a/permabank/stopwords.py b/permabank/stopwords.py
deleted file mode 100644
index 425a238..0000000
--- a/permabank/stopwords.py
+++ /dev/null
@@ -1,15 +0,0 @@
-stopwords = ['a', 'about', 'above', 'after', 'again', 'against', 'all',
- 'am', 'an', 'and', 'any', 'are', 'as', 'at', 'be', 'because', 'been',
- 'before', 'being', 'below', 'between', 'both', 'but', 'by', 'can',
- 'did', 'do', 'does', 'doing', 'don', 'down', 'during', 'each', 'few',
- 'for', 'from', 'further', 'had', 'has', 'have', 'having', 'he', 'her',
- 'here', 'hers', 'herself', 'him', 'himself', 'his', 'how', 'i', 'if',
- 'in', 'into', 'is', 'it', 'its', 'itself', 'just', 'me', 'more',
- 'most', 'my', 'myself', 'no', 'nor', 'not', 'now', 'of', 'off', 'on',
- 'once', 'only', 'or', 'other', 'our', 'ours', 'ourselves', 'out',
- 'over', 'own', 's', 'same', 'she', 'should', 'so', 'some', 'such',
- 't', 'than', 'that', 'the', 'their', 'theirs', 'them', 'themselves',
- 'then', 'there', 'these', 'they', 'this', 'those', 'through', 'to',
- 'too', 'under', 'until', 'up', 'very', 'was', 'we', 'were', 'what',
- 'when', 'where', 'which', 'while', 'who', 'whom', 'why', 'will',
- 'with', 'you', 'your', 'yours', 'yourself', 'yourselves']
diff --git a/permabank/templates/_formhelpers.html b/permabank/templates/_formhelpers.html
deleted file mode 100644
index ef3cddf..0000000
--- a/permabank/templates/_formhelpers.html
+++ /dev/null
@@ -1,12 +0,0 @@
-{# Via http://flask.pocoo.org/docs/patterns/wtforms/ #}
-{# By Armin Ronacher #}
-{% macro render_field(field) %}
-
{{ field.label }}
- {{ field(**kwargs)|safe }}
- {% if field.errors %}
-
- {% for error in field.errors %}- {{ error }}{% endfor %}
-
- {% endif %}
-
-{% endmacro %}
diff --git a/permabank/templates/entry.html b/permabank/templates/entry.html
deleted file mode 100644
index c69d2af..0000000
--- a/permabank/templates/entry.html
+++ /dev/null
@@ -1,13 +0,0 @@
-{# vim: set ts=2 sw=2 filetype=htmljinja: #}
-
-
- {{ entry.summary|lower }}
-
-
-
-
{{ entry.details }}
-
-
-
diff --git a/permabank/templates/layout.html b/permabank/templates/layout.html
deleted file mode 100644
index 2a4f92c..0000000
--- a/permabank/templates/layout.html
+++ /dev/null
@@ -1,27 +0,0 @@
-{# vim: set ts=2 sw=2 filetype=htmljinja: #}
-{# Basic skeleton for all pages on Permabank #}
-
-
-
-
Permabank
-
-
-
-
-
-
- {% block body %}{% endblock %}
-
-
-
-
-
-