Commits

Gregory Petukhov  committed 3e10085

Many changes

  • Participants
  • Parent commits 78331d4

Comments (0)

Files changed (34)

+Grigoriy Petukhov: http://lorien.name
+============
+Installation
+============
+
+ 1. pip or easy_install feedzilla
+ 2. Make sure you have install all dependencies
+ 3. Add feedzilla to INSTALLED_APPS
+ 4. Run `manage.py syncdb`
+ 5. Add `url('', include('feedzilla.urls'))` into root urls.py
+ 6. Setup Site instance via Django admin interface
+ 7. Setup feedzilla settings via settings.py.
+    See README for the list of available settings.
+
+
+Dependencies
+============
+
+ * django-common
+ * django-tagging
+ * feedparser
+Copyright (c) 2009, Grigoriy Petukhov
+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.
+    * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+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 OWNER 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.
+============================
+Feedzilla Django Application
+============================
+
+This is django application that add to your site ability to aggregate
+ATOM/RSS feeds and display the in single stream.
+
+Project page: http://bitbucket.org/lorien/feedzilla
+
+
+Installation
+============
+For installation instructions look into INSTALL document.
+
+
+Settings 
+========
+
+ * FEEDZILLA_PAGE_SIZE
+ * FEEDZILLA_SUMMARY_SIZE
+ * FEEDZILLA_SITE_TITLE
+ * FEEDZILLA_SITE_DESCRIPTION
+
+For actual list look into feedzilla/settings.py

File feedzilla/admin.py

 # -*- coding: utf-8
 
 from django.contrib import admin
-from feed.models import Feed, Post, FilterTag, FilterWord
+from feedzilla.models import Feed, Post, FilterTag, FilterWord
 
 class FeedAdmin(admin.ModelAdmin):
     list_display = ['title', 'feed_url', 'active', 'last_checked']

File feedzilla/context_processor.py

-from django.conf import settings
-
-def feed(request):
-    return {'SITE_TITLE': settings.FEEDZILLA_SITE_TITLE,
-            'SITE_DESCRIPTION': settings.FEEDZILLA_SITE_DESCRIPTION,
-            }

File feedzilla/context_processors.py

+from django.conf import settings
+
+from feedzilla import settings as app_settings
+
+def feed(request):
+    return {'SITE_TITLE': app_settings.SITE_TITLE,
+            'SITE_DESCRIPTION': app_settings.SITE_DESCRIPTION,
+            }

File feedzilla/filter.py

 
 from tagging.models import Tag
 
-filter = {}
+CACHE = {}
 
 def load_filters():
-    from feed.models import FilterTag, FilterWord
+    from feedzilla.models import FilterTag, FilterWord
 
-    if not filter:
+    if not CACHE:
         tags = [x.value.upper() for x in FilterTag.objects.all()]
         words = [re.compile(ur'\b%s\b' % x.value, re.U | re.I)\
             for x in FilterWord.objects.all()]
-        filter['tags'] = tags
-        filter['words'] = words
+        CACHE['tags'] = tags
+        CACHE['words'] = words
 
 
 def check_post(post):
     load_filters()
 
     for tag in Tag.objects.get_for_object(post):
-        if tag.name.upper() in filter['tags']:
+        if tag.name.upper() in CACHE['tags']:
             return True
 
     title = strip_tags(post.title)
     text = strip_tags(post.content)
 
-    return any(x.search(text) or x.search(title) for x in filter['words'])
+    return any(x.search(text) or x.search(title) for x in CACHE['words'])

File feedzilla/management/commands/feedzilla_refilter.py

 
 from django.core.management.base import BaseCommand
 
-from feed.models import Post
+from feedzilla.models import Post
 
 class Command(BaseCommand):
     help = u'Refilter posts'

File feedzilla/management/commands/feedzilla_update.py

 from django.core.management.base import BaseCommand
 from django.conf import settings
 
-from feed.util.parse import parse_feed
-from feed.models import Feed, Post
+from feedzilla.util.parse import parse_feed
+from feedzilla.models import Feed, Post
 
 class Command(BaseCommand):
     help = u'Update feeds'

File feedzilla/models.py

         return self.title
 
     def get_absolute_url(self):
-        return reverse('feed.views.feed', args=[self.id])
+        return reverse('feedzilla_feed', args=[self.id])
 
     class Meta:
         verbose_name = u'Фид'
         return self.value
 
 
-from feed import signals
+from feedzilla import signals
 signals.setup()

File feedzilla/settings.py

+from django.conf import settings
+
+def define(key, default):
+    return getattr(settings, key, default)
+
+PAGE_SIZE = define('FEEDZILLA_PAGE_SIZE', 25)
+SUMMARY_SIZE = define('FEEDZILLA_SUMMARY_SIZE', 2000)
+SITE_TITLE = define('FEEDZILLA_SITE_TITLE', 'Yet another feedzilla site')
+SITE_DESCRIPTION = define('FEEDZILLA_SITE_DESCRIPTION', 'Edit your settings to change that line')

File feedzilla/signals.py

 from django.db.models.signals import post_save
 
-from feed.models import Post
-import feed.filter
+from feedzilla.models import Post
+import feedzilla.filter
 
 def post_saved(instance, **kwargs):
     if not hasattr(instance, '_processed'):
-        instance.active = feed.filter.check_post(instance)
+        instance.active = feedzilla.filter.check_post(instance)
         instance._processed = True
         instance.save()
 

File feedzilla/syndication.py

 from django.utils.feedgenerator import Atom1Feed
 from django.conf import settings
 
-from feed.models import Post
+from feedzilla.models import Post
+from feedzilla import settings as app_settings
+
 
 class PostFeed(Feed):
     feed_type = Atom1Feed
     link = '/'
-    title = settings.FEEDZILLA_SITE_TITLE
+    title = app_settings.SITE_TITLE
 
     #def item_link(self, obj):
         #return obj.get_imdb_link()
         return str(obj.guid)
 
     def items(self, obj):
-        return Post.active_objects.all().order_by('-created')[:settings.FEEDZILLA_PAGE_SIZE]
+        return Post.active_objects.all()\
+                   .order_by('-created')[:app_settings.PAGE_SIZE]
 
     def item_pubdate(self, obj):
         return obj.created

File feedzilla/templates/404.html

+{% extends 'base.html' %}
+
+{% block content %}
 Извинте, запрашиваемая страница не найдена. Попробуйте посмотреть <a href="/">главную страницу</a> сайта.
+{% endblock %}

File feedzilla/templates/500.html

+Произошла ошибка. Администратор уведомлён. Попробуйте продолжить работу с <a href="/">главной страницы сайта</a>.

File feedzilla/templates/base.html

-{% load common_extras %}
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <!--
 
 		<!-- HINT: Set the class of any menu link below to "active" to make it appear active -->
 		<ul>
 			<li><a href="/">Лента новостей</a></li>
-            <li><a href="{% url feed.views.sources %}">Источники агрегации</a></li>
+            <li><a href="{% url feedzilla_sources %}">Источники агрегации</a></li>
 			<!--<li><a href="/about/">О сайте</a></li>-->
             <li><a class="external" href="http://webofdata.ru">Сайт сообщества</a></li>
             <li><a class="external" href="http://groups.google.com/group/webofdata-russian">Обсудить</a></li>

File feedzilla/templates/feedzilla/donor_list.html

-{% load common_extras %}
-
 <ul>
     {% for donor in donors %}
     <li><a href="{{ donor.site_url }}">{{ donor.title }}</a></li>

File feedzilla/templates/feedzilla/feed_head.html

-{% load common_extras %}
 <ul>
     {% for post in posts %}
     <li>{{ post.summary }}</li>

File feedzilla/templates/feedzilla/post_list.html

-{% load common_extras %}
-
 {% for post in posts %}
-{% include 'feed/post_template.html' %}
+{% include 'feedzilla/post_template.html' %}
 {% endfor %}

File feedzilla/templates/feedzilla/post_template.html

-{% load common_extras %}
 {% load tagging_tags %}
 
 <div class="post">

File feedzilla/templates/feedzilla/search.html

 {% extends 'base.html' %}
-{% load common_extras %}
 
 {% block head_extra %}
 <script type="text/javascript" src="{{ MEDIA_URL }}/js/jquery.highlight-2.js"></script>
 <div class="divider2"></div>
 {% if page.object_list %}
     {% for post in page.object_list %}
-    {% include 'feed/post_template.html' %}
+    {% include 'feedzilla/post_template.html' %}
     {% endfor %}
     {% include "common/pagination.html" %}
 {% else %}

File feedzilla/templates/feedzilla/sources.html

 {% extends 'base.html' %}
-{% load common_extras %}
 
 {% block content %}
 <h4>Источники информации для этого сайта</h4>

File feedzilla/templates/feedzilla/tag.html

 {% extends 'base.html' %}
-{% load common_extras %}
 
 {% block content %}
 <h4>Записи с меткой &laquo;{{ tag }}&raquo;</h4>
 <div class="contentarea">
 {% if page.object_list %}
     {% for post in page.object_list %}
-    {% include 'feed/post_template.html' %}
+    {% include 'feedzilla/post_template.html' %}
     {% endfor %}
     {% include "common/pagination.html" %}
 {% else %}

File feedzilla/templates/feedzilla/tag_cloud.html

-{% load common_extras %}
-
 <div class="tag-cloud">
 {% for tag in tags %}
 <font size="{{ tag.font_size }}">
-    <a class="tag" href="{% url feed.views.tag tag %}" size="{{ tag.font_size }}">{{ tag|escape|strong_spaces }}</a>
+    <a class="tag" href="{% url feedzilla_tag tag %}" size="{{ tag.font_size }}">{{ tag|escape|strong_spaces }}</a>
 </font>
 {% endfor %}
 </div>

File feedzilla/templates/footer.html

 <div class="left">
-    {% now "Y" %} &copy; webofdata.ru<br/>
+    {% now "Y" %} &copy; {{ request.get_host }} <br/>
     Design by <a href="http://www.nodethirtythree.com/">NodeThirtyThree Design</a>
 </div>
 <div class="right">

File feedzilla/templates/index.html

 {% extends 'base.html' %}
 {% load common_extras %}
-{% load feed_extras %}
+{% load feedzilla_tags %}
 
 {% block content %}
 {% for post in page.object_list %}

File feedzilla/templates/robots.txt

-User-Agent: *
-Disallow: /admin

File feedzilla/templates/sidebar.html

-{% load feed_extras %}
+{% load feedzilla_tags %}
 
 <div class="box">
     <h4>Метки</h4>
     <div class="contentarea tags">
-    {% tag_cloud %}
+    {% feedzilla_tag_cloud %}
     </div>
 </div>

File feedzilla/templatetags/feed_extras.py

-import random
-
-from django import template
-
-from feed.models import Feed, Post
-from tagging.models import Tag
-
-register = template.Library()
-
-
-@register.inclusion_tag('feed/tag_cloud.html', takes_context=True)
-def tag_cloud(context):
-    """
-    Show tag cloud for specified site.
-    """
-
-    tags = Tag.objects.cloud_for_model(Post, filters={'active': True})
-    return {'tags': tags,
-            }
-
-
-@register.inclusion_tag('feed/donor_list.html')
-def donor_list():
-    """
-    Show aggregated feed.
-    """
-
-    donors = Feed.objects.all()
-    return {'donors': donors,
-            }
-
-
-@register.inclusion_tag('feed/feed_head.html')
-def feed_head(feed_id, number=3):
-    """
-    Show last 'number' messages from feed.
-    """
-
-    try:
-        feed = Feed.objects.get(pk=feed_id)
-        messages = feed.posts.all().filter(active=True)[:number]
-    except Feed.DoesNotExist:
-        feed = None
-        messages =  []
-
-    return {'feed': feed,
-            'messages': messages,
-            }

File feedzilla/templatetags/feedzilla_tags.py

+import random
+
+from django import template
+
+from tagging.models import Tag
+
+from feedzilla.models import Feed, Post
+
+
+register = template.Library()
+
+@register.inclusion_tag('feedzilla/tag_cloud.html', takes_context=True)
+def feedzilla_tag_cloud(context):
+    """
+    Show tag cloud for specified site.
+    """
+
+    tags = Tag.objects.cloud_for_model(Post, filters={'active': True})
+
+    return {'tags': tags,
+            }
+
+
+@register.inclusion_tag('feedzilla/donor_list.html')
+def feedzilla_donor_list():
+    """
+    Show aggregated feed.
+    """
+
+    donors = Feed.objects.all()
+
+    return {'donors': donors,
+            }
+
+
+@register.inclusion_tag('feedzilla/feed_head.html')
+def feedzilla_feed_head(feed_id, number=3):
+    """
+    Show last 'number' messages from feed.
+    """
+
+    try:
+        feed = Feed.objects.get(pk=feed_id)
+        messages = feed.posts.all().filter(active=True)[:number]
+    except Feed.DoesNotExist:
+        feed = None
+        messages =  []
+
+    return {'feed': feed,
+            'messages': messages,
+            }

File feedzilla/urls.py

 from django.conf.urls.defaults import *
-from feed.syndication import PostFeed
+
+from feedzilla.syndication import PostFeed
 
 feed_dict = {
     'posts': PostFeed,
 }
 
-urlpatterns = patterns('feed.views',
-    url(r'^$', 'index', name='index'),
+urlpatterns = patterns('feedzilla.views',
+    url(r'^$', 'index', name='feedzilla_index'),
     url('^tag/(?P<tag_value>.+)/$', 'tag', name='feedzilla_tag'),
-    url('^sources/$', 'sources'),
-    url('^search/$', 'search', name='search'),
+    url('^sources/$', 'sources', name='feedzilla_sources'),
+    url('^search/$', 'search', name='feedzilla_search'),
 )
 
 urlpatterns += patterns('django.contrib.syndication.views',

File feedzilla/views.py

 from django.shortcuts import get_object_or_404
 
 from common.decorators import render_to, paged
+from common.util import paginate
 from tagging.models import Tag, TaggedItem
-from feed.models import Post, Feed
-from common.util import paginate
+
+from feedzilla.models import Post, Feed
+from feedzilla import settings as app_settings
 
 
 @render_to('index.html')
 def index(request):
     qs = Post.active_objects.all().select_related('feed')
-    page, paginator = paginate(qs, request, settings.FEEDZILLA_PAGE_SIZE)
+    page, paginator = paginate(qs, request, app_settings.PAGE_SIZE)
 
     return {'page': page,
             'paginator': paginator,
             }
 
 
-@render_to('feed/tag.html')
+@render_to('feedzilla/tag.html')
 def tag(request, tag_value):
     tag = get_object_or_404(Tag, name=tag_value)
     qs = TaggedItem.objects.get_by_model(Post, tag).filter(active=True).order_by('-created')
-    page, paginator = paginate(qs, request, settings.FEEDZILLA_PAGE_SIZE)
+    page, paginator = paginate(qs, request, app_settings.PAGE_SIZE)
 
     return {'tag': tag,
             'page': page,
             }
 
 
-@render_to('feed/sources.html')
+@render_to('feedzilla/sources.html')
 def sources(request):
+
     return {'feed': Feed.objects.all(),
             }
 
 
-@render_to('feed/search.html')
+@render_to('feedzilla/search.html')
 def search(request):
     query = request.GET.get('query', '') 
     min_limit = 2
         posts = Post.active_objects.filter(content__icontains=query)
         message = ''
 
-    page, paginator = paginate(posts, request, settings.FEEDZILLA_PAGE_SIZE)
+    page, paginator = paginate(posts, request, app_settings.PAGE_SIZE)
+
     return {'page': page,
             'paginator': paginator,
             'message': message,
+import os
+from setuptools import setup
+
+# Compile the list of packages available, because distutils doesn't have
+# an easy way to do this.
+
+packages, data_files = [], []
+root_dir = os.path.dirname(__file__)
+if root_dir:
+    os.chdir(root_dir)
+
+PACKAGE = 'feedzilla'
+
+for dirpath, dirnames, filenames in os.walk(PACKAGE):
+    for i, dirname in enumerate(dirnames):
+        if dirname in ['.', '..']:
+            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(PACKAGE) + 1:] # Strip package directory + path separator
+        for f in filenames:
+            data_files.append(os.path.join(prefix, f))
+
+setup(
+    version = '0.1.0',
+    description = 'Django application for atom/rss feeds aggregation'
+    author = 'Grigoriy Petukhov',
+    author_email = 'lorien@lorien.name',
+    url = 'http://bitbucket.org/lorien/feedzilla',
+    name = 'feedzilla',
+
+    packages = packages,
+    package_data = {'feedzilla': data_files},
+
+    license = "BSD",
+    keywords = "django application feeds syndication aggregation atom rss",
+    classifiers=[
+        'Development Status :: 4 - Beta',
+        'Environment :: Web Environment',
+        'Framework :: Django',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: BSD License',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+        'Topic :: Utilities'
+    ],
+)