Commits

Michael Manfre committed 37a42bf Draft

Initial commit

Comments (0)

Files changed (14)

+*.py[co]
+.project
+.pydevproject
+*~
+*.db
+*.orig
+*.DS_Store
+.coverage
+.tox
+*.egg-info/*
+docs/_build/*
+dist/*
+# use glob syntax.
+syntax: glob
+*.py[co]
+.project
+.pydevproject
+*~
+*.db
+*.orig
+*.DS_Store
+.coverage
+.tox/*
+*.egg-info/*
+docs/_build/*
+dist/*
+Michael Manfre
+Copyright (c) 2012, Michael Manfre
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, 
+are permitted provided that the following conditions are met:
+
+    Redistributions of source code must retain the above copyright notice, this 
+    list of conditions and the following disclaimer. Redistributions in binary 
+    form must reproduce the above copyright notice, this list of conditions and 
+    the following disclaimer in the documentation and/or other materials 
+    provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+include AUTHORS
+include LICENSE
+include README.rst
+recursive-include textpattern/static *
+recursive-include textpattern/templates *
+django-textpattern
+==================
+
+This Django application is intended to allow accessing a Textpattern database.
+
+
+Running the Tests
+------------------------------------
+
+You can run the tests with via::
+
+    python setup.py test
+
+or::
+
+    python runtests.py
+#!/usr/bin/env python
+import sys
+
+from django.conf import settings
+
+
+if not settings.configured:
+    settings.configure(
+        DATABASES={
+            'default': {
+                'ENGINE': 'django.db.backends.sqlite3',
+                'NAME': ':memory:',
+            }
+        },
+        INSTALLED_APPS=(
+            'textpattern',
+        ),
+        SITE_ID=1,
+        SECRET_KEY='this-is-just-for-tests-so-not-that-secret',
+    )
+
+
+from django.test.utils import get_runner
+
+
+def runtests():
+    TestRunner = get_runner(settings)
+    test_runner = TestRunner(verbosity=1, interactive=True, failfast=False)
+    failures = test_runner.run_tests(['textpattern', ])
+    sys.exit(failures)
+
+
+if __name__ == '__main__':
+    runtests()
+
+import os
+from setuptools import setup, find_packages
+
+
+def read_file(filename):
+    """Read a file into a string"""
+    path = os.path.abspath(os.path.dirname(__file__))
+    filepath = os.path.join(path, filename)
+    try:
+        return open(filepath).read()
+    except IOError:
+        return ''
+
+
+setup(
+    name='django-textpattern',
+    version=__import__('textpattern').__version__,
+    author='Michael Manfre',
+    author_email='mmanfre@gmail.com',
+    packages=find_packages(),
+    include_package_data=True,
+    url='https://bitbucket.org/Manfre/django-textpattern/',
+    license='BSD',
+    description=u' '.join(__import__('textpattern').__doc__.splitlines()).strip(),
+    classifiers=[
+        'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
+        'Intended Audience :: Developers',
+        'Programming Language :: Python',      
+        'Programming Language :: Python :: 2.6',
+        'Programming Language :: Python :: 2.7',
+        'Framework :: Django',
+        'Development Status :: 4 - Beta',
+        'Operating System :: OS Independent',
+    ],
+    long_description=read_file('README.rst'),
+    test_suite="runtests.runtests",
+    zip_safe=False,
+)

textpattern/__init__.py

+"Django application to provide easy access to a Textpattern database"
+
+__version__ = '0.1a'

textpattern/models.py

+from django.db import models
+
+TEXTPATTERN_STATUS_CHOICES = (
+    (1, 'Draft'),
+    (2, 'Hidden'),
+    (3, 'Pending'),
+    (4, 'Live'),
+    (5, 'Sticky'),
+)
+
+FILE_STATUS_CHOICES = (
+    (2, 'Hidden'),
+    (3, 'Pending'),
+    (4, 'Live'),
+)
+
+
+DISCUSS_VISIBLE_CHOICES = (
+    (-1,  'Spam'),
+    (0,   'Moderate'),
+    (1,   'Visible'),
+    (-99, 'Reload'),
+)
+
+# Create your models here.
+class Textpattern(models.Model):
+    id = models.IntegerField(primary_key=True, db_column='ID') # Field name made lowercase.
+    posted = models.DateTimeField(db_column='Posted') # Field name made lowercase.
+    expires = models.DateTimeField(db_column='Expires') # Field name made lowercase.
+    authorid = models.CharField(max_length=192, db_column='AuthorID') # Field name made lowercase.
+    lastmod = models.DateTimeField(db_column='LastMod') # Field name made lowercase.
+    lastmodid = models.CharField(max_length=192, db_column='LastModID') # Field name made lowercase.
+    title = models.CharField(max_length=765, db_column='Title') # Field name made lowercase.
+    title_html = models.CharField(max_length=765, db_column='Title_html') # Field name made lowercase.
+    body = models.TextField(db_column='Body') # Field name made lowercase.
+    body_html = models.TextField(db_column='Body_html') # Field name made lowercase.
+    excerpt = models.TextField(db_column='Excerpt') # Field name made lowercase.
+    excerpt_html = models.TextField(db_column='Excerpt_html') # Field name made lowercase.
+    image = models.CharField(max_length=765, db_column='Image') # Field name made lowercase.
+    category1 = models.CharField(max_length=384, db_column='Category1') # Field name made lowercase.
+    category2 = models.CharField(max_length=384, db_column='Category2') # Field name made lowercase.
+    annotate = models.IntegerField(db_column='Annotate') # Field name made lowercase.
+    annotateinvite = models.CharField(max_length=765, db_column='AnnotateInvite') # Field name made lowercase.
+    comments_count = models.IntegerField()
+    status = models.IntegerField(db_column='Status', choices=TEXTPATTERN_STATUS_CHOICES) # Field name made lowercase.
+    textile_body = models.IntegerField()
+    textile_excerpt = models.IntegerField()
+    section = models.CharField(max_length=192, db_column='Section') # Field name made lowercase.
+    override_form = models.CharField(max_length=765)
+    keywords = models.CharField(max_length=765, db_column='Keywords') # Field name made lowercase.
+    url_title = models.CharField(max_length=765)
+    custom_1 = models.CharField(max_length=765)
+    custom_2 = models.CharField(max_length=765)
+    custom_3 = models.CharField(max_length=765)
+    custom_4 = models.CharField(max_length=765)
+    custom_5 = models.CharField(max_length=765)
+    custom_6 = models.CharField(max_length=765)
+    custom_7 = models.CharField(max_length=765)
+    custom_8 = models.CharField(max_length=765)
+    custom_9 = models.CharField(max_length=765)
+    custom_10 = models.CharField(max_length=765)
+    uid = models.CharField(max_length=96)
+    feed_time = models.DateField()
+
+    class Meta:
+        db_table = u'textpattern'
+
+    def get_absolute_url(self):
+        """
+        Get aboslute URL based upon the Textpattern `permlink_mode`
+        """
+        return self.get_permlink()
+        
+    def get_permlink(self, permlink_mode=None):
+        if not permlink_mode:
+            permlink_mode = TxpPrefs.get_for_name('permlink_mode')
+            if not permlink_mode:
+                permlink_mode = 'section_id_title'
+
+        year = self.posted.year
+        month = self.posted.month
+        day = self.posted.day
+        
+        exclude_parts = ['only', 'url']
+        parts = [x for x in permlink_mode.split('_') if x not in exclude_parts]
+
+        # convert `permlink_mode` pref to format string
+        fmt = u'/' + u'/'.join(map(lambda x: u'{' + x + u'}', parts))
+        
+        return fmt.format(
+            id=self.pk,
+            title=self.url_title,
+            section=self.section,
+            year=year,
+            month=month,
+            day=day,
+        )
+
+class TxpCategory(models.Model):
+    id = models.IntegerField(primary_key=True)
+    name = models.CharField(max_length=192)
+    type = models.CharField(max_length=192)
+    parent = models.CharField(max_length=192)
+    lft = models.IntegerField()
+    rgt = models.IntegerField()
+    title = models.CharField(max_length=765)
+
+    class Meta:
+        db_table = u'txp_category'
+
+class TxpCss(models.Model):
+    name = models.CharField(primary_key=True, max_length=765, unique=True)
+    css = models.TextField()
+
+    class Meta:
+        db_table = u'txp_css'
+
+class TxpDiscuss(models.Model):
+    discussid = models.IntegerField(primary_key=True)
+    parentid = models.IntegerField()
+    name = models.CharField(max_length=765)
+    email = models.CharField(max_length=150)
+    web = models.CharField(max_length=765)
+    ip = models.CharField(max_length=300)
+    posted = models.DateTimeField()
+    message = models.TextField()
+    visible = models.IntegerField(choices=DISCUSS_VISIBLE_CHOICES)
+
+    class Meta:
+        db_table = u'txp_discuss'
+
+class TxpDiscussIpban(models.Model):
+    ip = models.CharField(max_length=765, primary_key=True)
+    name_used = models.CharField(max_length=765)
+    date_banned = models.DateTimeField()
+    banned_on_message = models.IntegerField()
+
+    class Meta:
+        db_table = u'txp_discuss_ipban'
+
+class TxpDiscussNonce(models.Model):
+    issue_time = models.DateTimeField()
+    nonce = models.CharField(max_length=765, primary_key=True)
+    used = models.IntegerField()
+    secret = models.CharField(max_length=765)
+
+    class Meta:
+        db_table = u'txp_discuss_nonce'
+
+class TxpFile(models.Model):
+    id = models.IntegerField(primary_key=True)
+    filename = models.CharField(max_length=765, unique=True)
+    title = models.CharField(max_length=765, blank=True)
+    category = models.CharField(max_length=765)
+    permissions = models.CharField(max_length=96)
+    description = models.TextField()
+    downloads = models.IntegerField()
+    status = models.IntegerField(choices=FILE_STATUS_CHOICES)
+    modified = models.DateTimeField()
+    created = models.DateTimeField()
+    size = models.BigIntegerField(null=True, blank=True)
+    author = models.CharField(max_length=765)
+
+    class Meta:
+        db_table = u'txp_file'
+
+class TxpForm(models.Model):
+    name = models.CharField(max_length=192, primary_key=True)
+    type = models.CharField(max_length=84)
+    form = models.TextField(db_column='Form') # Field name made lowercase.
+
+    class Meta:
+        db_table = u'txp_form'
+
+class TxpImage(models.Model):
+    id = models.IntegerField(primary_key=True)
+    name = models.CharField(max_length=765)
+    category = models.CharField(max_length=765)
+    ext = models.CharField(max_length=60)
+    w = models.IntegerField()
+    h = models.IntegerField()
+    alt = models.CharField(max_length=765)
+    caption = models.TextField()
+    date = models.DateTimeField()
+    author = models.CharField(max_length=765)
+    thumbnail = models.IntegerField()
+    thumb_w = models.IntegerField()
+    thumb_h = models.IntegerField()
+
+    class Meta:
+        db_table = u'txp_image'
+
+class TxpLang(models.Model):
+    id = models.IntegerField(primary_key=True)
+    lang = models.CharField(max_length=48)
+    name = models.CharField(max_length=192, unique=True)
+    event = models.CharField(max_length=192)
+    data = models.TextField(blank=True)
+    lastmod = models.DateTimeField()
+
+    class Meta:
+        db_table = u'txp_lang'
+
+class TxpLink(models.Model):
+    id = models.IntegerField(primary_key=True)
+    date = models.DateTimeField()
+    category = models.CharField(max_length=192)
+    url = models.TextField()
+    linkname = models.CharField(max_length=765)
+    linksort = models.CharField(max_length=384)
+    description = models.TextField()
+    author = models.CharField(max_length=765)
+
+    class Meta:
+        db_table = u'txp_link'
+
+class TxpLog(models.Model):
+    id = models.IntegerField(primary_key=True)
+    time = models.DateTimeField()
+    host = models.CharField(max_length=765)
+    page = models.CharField(max_length=765)
+    refer = models.TextField()
+    status = models.IntegerField()
+    method = models.CharField(max_length=48)
+    ip = models.CharField(max_length=48)
+
+    class Meta:
+        db_table = u'txp_log'
+
+class TxpPage(models.Model):
+    name = models.CharField(max_length=384, primary_key=True)
+    user_html = models.TextField()
+
+    class Meta:
+        db_table = u'txp_page'
+
+class TxpPlugin(models.Model):
+    name = models.CharField(max_length=192, unique=True, primary_key=True)
+    status = models.IntegerField()
+    author = models.CharField(max_length=384)
+    author_uri = models.CharField(max_length=384)
+    version = models.CharField(max_length=30)
+    description = models.TextField()
+    help = models.TextField()
+    code = models.TextField()
+    code_restore = models.TextField()
+    code_md5 = models.CharField(max_length=96)
+    type = models.IntegerField()
+    load_order = models.IntegerField()
+    flags = models.IntegerField()
+
+    class Meta:
+        db_table = u'txp_plugin'
+
+class TxpPrefs(models.Model):
+    prefs_id = models.IntegerField(unique=True)
+    name = models.CharField(max_length=765)
+    val = models.TextField()
+    type = models.IntegerField()
+    event = models.CharField(max_length=36)
+    html = models.CharField(max_length=192)
+    position = models.IntegerField()
+    user_name = models.CharField(max_length=192)
+
+    class Meta:
+        db_table = u'txp_prefs'
+
+    @staticmethod
+    def get_for_name(self, name, prefs_id=1):
+        """
+        Get the pref for the given name.
+        """
+        key = 'txp_prefs;id={0}'.format(prefs_id)
+        prefs = cache.get(key)
+        
+        if prefs is None:
+            prefs = {}
+            for p in TxpPrefs.objects.filter(prefs_id=prefs_id):
+                prefs[p.name] = p.val
+            cache.set(key, prefs)
+        return prefs.get(name, None)
+
+class TxpSection(models.Model):
+    name = models.CharField(max_length=384, primary_key=True)
+    page = models.CharField(max_length=384)
+    css = models.CharField(max_length=384)
+    in_rss = models.IntegerField()
+    on_frontpage = models.IntegerField()
+    searchable = models.IntegerField()
+    title = models.CharField(max_length=765)
+
+    class Meta:
+        db_table = u'txp_section'
+
+class TxpUsers(models.Model):
+    user_id = models.IntegerField(primary_key=True)
+    name = models.CharField(max_length=192, unique=True)
+    pass_field = models.CharField(max_length=384, db_column='pass') # Field renamed because it was a Python reserved word.
+    realname = models.CharField(max_length=765, db_column='RealName') # Field name made lowercase.
+    email = models.CharField(max_length=762)
+    privs = models.IntegerField()
+    last_access = models.DateTimeField()
+    nonce = models.CharField(max_length=192)
+
+    class Meta:
+        db_table = u'txp_users'
+

textpattern/tests/__init__.py

+from test_permlink import *

textpattern/tests/test_permlink.py

+import datetime
+from django.test import TestCase
+
+from textpattern import models as txp
+
+class PermlinkModeTestCase(TestCase):
+    """
+    Test the ability to construct an absolute URL based upon the permlink_mode.
+    """
+    def setUp(self):
+        self.article = txp.Textpattern(
+            id=1,
+            section='section',
+            url_title='some-title',
+            posted=datetime.datetime.now(),
+        )
+
+    def test_title_only(self):
+        expected = '/{0}'.format(self.article.url_title)
+        self.assertEqual(expected, self.article.get_permlink('title_only'))
+        
+    def test_section_id_title(self):
+        expected = '/{0}/{1}/{2}'.format(self.article.section, self.article.id, self.article.url_title)
+        self.assertEqual(expected, self.article.get_permlink('section_id_title'))
+
+    def test_dates(self):
+        expected = '/{0}/{1}/{2}/{3}'.format(
+            self.article.posted.year, 
+            self.article.posted.month, 
+            self.article.posted.day,
+            self.article.id)
+        self.assertEqual(expected, self.article.get_permlink('year_month_day_id'))
+
+    def test_filtered_words(self):
+        expected = '/{0}'.format(self.article.id)
+        self.assertEqual(expected, self.article.get_permlink('url_id_only'))

textpattern/views.py

+# Create your views here.
+[tox]
+downloadcache = {toxworkdir}/_download/
+envlist = py27-trunk,py27-1.4.X
+
+[testenv]
+commands = {envpython} runtests.py
+
+[testenv:py27-trunk]
+basepython = python2.7
+deps = https://github.com/django/django/zipball/master
+
+[testenv:py27-1.4.X]
+basepython = python2.7
+deps = django>=1.4,<1.5