diff options
Diffstat (limited to 'chimere_rss')
| -rw-r--r-- | chimere_rss/__init__.py | 1 | ||||
| -rw-r--r-- | chimere_rss/feeds.py | 230 | ||||
| -rw-r--r-- | chimere_rss/templates/rss.html | 73 | ||||
| -rw-r--r-- | chimere_rss/templates/rss_descr.html | 8 | ||||
| -rw-r--r-- | chimere_rss/templates/rss_title.html | 2 | ||||
| -rw-r--r-- | chimere_rss/urls.py | 42 | ||||
| -rw-r--r-- | chimere_rss/views.py | 140 |
7 files changed, 496 insertions, 0 deletions
diff --git a/chimere_rss/__init__.py b/chimere_rss/__init__.py new file mode 100644 index 0000000..792d600 --- /dev/null +++ b/chimere_rss/__init__.py @@ -0,0 +1 @@ +# diff --git a/chimere_rss/feeds.py b/chimere_rss/feeds.py new file mode 100644 index 0000000..18a4259 --- /dev/null +++ b/chimere_rss/feeds.py @@ -0,0 +1,230 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010 Pierre Clarenc <pierre.crc_AT_gmailDOTcom>, +# Samuel Renard <renard.samuel_AT_gmailDOTcom>, +# Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> + +# 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 <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +from django.utils.translation import ugettext as _ +from django.contrib.syndication.feeds import Feed +from django.contrib.syndication.feeds import FeedDoesNotExist +from chimere.main.models import Category, SubCategory, Marker, Area +from django.core.exceptions import ObjectDoesNotExist +from django.contrib.gis.geos import * + +from chimere import settings + +class BaseFeed(Feed): + """ + Base feed for Chimere objects + """ + def item_link(self, item): + ''' Return POI permalink ''' + coord = item.point + cat = 0 + if item.categories.all() and item.categories.all()[0]: + cat = item.categories.all()[0].pk + return settings.BASE_URL + '?zoom=16&lat=%d&lon=%d¤t_feature=%d&\ +checked_categories=%d' % (coord.y, coord.x, item.id, cat) + + def item_pubdate(self, item): + """ + Date of the Marker when it has been available + """ + return item.available_date + + def description(self, obj): + return "" + +class LatestPOIsByCategory(BaseFeed): + ''' + Last Points of interests by category in Feeds + ''' + title_template = "rss_title.html" + description_template = "rss_descr.html" + + def get_object(self, bits): + """ + Get extra url, after rss/category/ id of category + """ + if len(bits) != 1: + raise ObjectDoesNotExist + return Category.objects.get(id__exact=bits[0]) + + def title(self, obj): + """ + Define the title of the feed + """ + return u"%s - %s" % (settings.PROJECT_NAME, obj.name) + + def link(self, obj): + """ + Define the link of the feed. + """ + if not obj: + raise FeedDoesNotExist + return settings.BASE_URL + 'rss/category/' + str(obj.id) + + def items(self, obj): + """ + Requests to marker where its category match the category is requested + and its status is available + This returns a list of the 15 last markers/POIs ordering by date + """ + q = Marker.objects.filter(status__exact='A', + categories__category__id__exact=obj.id, + available_date__isnull=False).order_by('-available_date')[:15] + return q + +class LatestPOIsBySubCategory(BaseFeed): + ''' + Last Points of interests by SubCategory in Feeds + ''' + title_template = "rss_title.html" + description_template = "rss_descr.html" + + def get_object(self, bits): + if len(bits) != 1: + raise ObjectDoesNotExist + return SubCategory.objects.get(id__exact=bits[0]) + + def title(self, obj): + return u"%s - %s - %s" % (settings.PROJECT_NAME, obj.category.name, + obj.name) + + def link(self, obj): + if not obj: + raise FeedDoesNotExist + return settings.BASE_URL + 'rss/subcategory/' + str(obj.id) + + def items(self, obj): + q = Marker.objects.filter(categories__id__exact=obj.id, + available_date__isnull=False, status__exact='A').order_by( + '-available_date')[:15] + return q + +class LatestPOIs(BaseFeed): + ''' + Last Points of interests + ''' + title_template = "rss_title.html" + description_template = "rss_descr.html" + + def title(self): + return settings.PROJECT_NAME + u" - " + _(u"Last points of interest") + + def link(self): + return settings.BASE_URL + 'rss/categories/' + + def description(self): + return _("Latest points of interest from ") + settings.PROJECT_NAME + + def items(self): + q = Marker.objects.filter(status__exact='A', + available_date__isnull=False).order_by('-available_date')[:15] + return q + +class LatestPOIsByZone(BaseFeed): + ''' + Last Points of interests by zone by coordinates + ''' + title_template = "rss_title.html" + description_template = "rss_descr.html" + upper_left_lat = 0 + upper_left_lon = 0 + lower_right_lat = 0 + lower_right_lon = 0 + + def get_object(self, bits): + """ + Get the extra url. Parameters are the coordinates of the zone (the + upper left and lower right points) + """ + if len(bits) != 1: + raise ObjectDoesNotExist + # Then define the upper right and lower left points + coordinates = str(bits[0]).split('_') + upper_left_lat = float(coordinates[0]) + upper_left_lon = float(coordinates[1]) + lower_right_lat = float(coordinates[2]) + lower_right_lon = float(coordinates[3]) + upper_right_lat = upper_left_lat + upper_right_lon = lower_right_lon + lower_left_lat = lower_right_lat + lower_left_lon = upper_left_lon + # Define a Polygon with the 4 points of the zone. + areaBox = Polygon(((upper_left_lon, upper_left_lat), + (upper_right_lon, upper_right_lat), + (lower_right_lon, lower_right_lat), + (lower_left_lon, lower_left_lat), + (upper_left_lon, upper_left_lat)), + srid=settings.EPSG_DISPLAY_PROJECTION) + return areaBox + + def title(self, obj): + return settings.PROJECT_NAME + u" - " +\ + _(u"Last points of interest by area") + + def link(self, obj): + """ + Define the link of the feed. It's the same url as we get in the method + get_object + """ + if not obj: + raise FeedDoesNotExist + return settings.BASE_URL + 'rss/area/' \ + + str(self.upper_left_lat) + '_' + str(self.upper_left_lon) + \ + '_' + str(self.lower_right_lat) + '_' + str(self.lower_right_lon) + + def items(self, obj): + """ + Request to return Markers WHERE there points are containes in the zone + which is requested. + This returns a list of the 15 last markers/POIs ordering by date + """ + q = Marker.objects.filter(point__contained=obj, status__exact='A', + available_date__isnull=False).order_by('-available_date')[:15] + return q + +class LatestPOIsByZoneID(BaseFeed): + ''' + Last Points of interests by zone by id + ''' + title_template = "rss_title.html" + description_template = "rss_descr.html" + + def get_object(self, bits): + if len(bits) != 1: + raise ObjectDoesNotExist + return Area.objects.get(id__exact=bits[0]) + + def title(self, obj): + return settings.PROJECT_NAME + u" - " + \ + _(u"Last points of interest") + u" - " + obj.name + + def link(self, obj): + if not obj: + raise FeedDoesNotExist + return settings.BASE_URL + 'rss/areaid/' + str(obj.id) + + def items(self, obj): + sql = 'select * from "main_marker" where ' + obj.getIncludeSql() + sql += ' and "main_marker".available_date is not null' + sql += ' and "main_marker".status=\'A\'' + sql += ' order by "main_marker".available_date desc limit 15' + q = Marker.objects.raw(sql) + return q diff --git a/chimere_rss/templates/rss.html b/chimere_rss/templates/rss.html new file mode 100644 index 0000000..0c895ed --- /dev/null +++ b/chimere_rss/templates/rss.html @@ -0,0 +1,73 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block sidebar %} +{% endblock %} + +{% block content %} +<div id='content'> +<fieldset class='edit'> +<legend>{% trans "Subscribe to RSS feed" %}</legend> + +<p><font color='red'> {{ error_message }} </font></p> + +<form method='post' id='rss_form' name='rss_form' action=''> +{%if not category_rss_feed %} +<div class="fieldWrapper"> + <label for="rss_category">{% trans "Type of RSS feed" %}</label> + <select name='rss_category' id='rss_category' onchange='document.forms["rss_form"].submit();'> + <option value=""> ---- </option> + <option value="global">{% trans "All new points of interest" %}</option> + <option value="poi">{% trans "New points of interest by category" %}</option> + <option value="area">{% trans "New points of interest by area" %}</option> + </select> +</div> +{% endif %} + +{%ifequal category_rss_feed "category" %} +<h3>{% trans "New points of interest by category" %}</h3> +<div class="fieldWrapper"> + <label for="id_subcategory">{% trans "Choose a category" %}</label> + <select name='subcategory' id='subcategory' onchange='document.forms["rss_form"].submit();'> + {% for cat_subcat in sub_categories %} + <option value ="cat_{{cat_subcat.0.id}}"> ---- {{cat_subcat.0.name}} ---- + {% for sub_category in cat_subcat.1 %} + <option value='{{sub_category.id}}'{% ifequal sub_category.id current_category %} selected='selected'{% endifequal %}> + {% trans sub_category.name %} + </option>{% endfor %} + </option>{% endfor %} + </select> +</div> +{% endifequal %} + +{%ifequal category_rss_feed "area" %} +<h3>{% trans "New points of interest by area" %}</h3> +{% if area_id %} +<div class="fieldWrapper"> + <label for="id_area">{% trans "Choose a pre-defined areas" %}</label> + <select name='id_area' id='id_area' onchange='document.forms["rss_form"].submit();'> + <option value="" selected="selected"> ---- </option> + {% for areaID in area_id %} + <option value ={{areaID.id}}>{{areaID.name}}</option> + {% endfor %} + </select> +</div> + +</form> + +<form method='post' action=''> +{% endif %} +<div class='fieldWrapper'> +<label>{% trans "Or select the area by zooming and panning this map" %}</label> +<div class="map"> + {{form.area}} +</div> +</div> +<p><input type="submit" value="{% trans "Validate" %}" /></p> +{% endifequal %} + +</form> + +</fieldset> +</div> +{% endblock %} diff --git a/chimere_rss/templates/rss_descr.html b/chimere_rss/templates/rss_descr.html new file mode 100644 index 0000000..4f75ac6 --- /dev/null +++ b/chimere_rss/templates/rss_descr.html @@ -0,0 +1,8 @@ +{% load i18n %} +{% load sanitize %} +<div id='detail_content'> +{% if obj.picture %}<img src='{{obj.picture.url}}' alt="{{obj.name}}"/>{%endif%} +<div>{% for property in obj.getProperties %} +<p id='{{property.propertymodel.getNamedId}}'>{{ property.value|sanitize:"p b i br hr strong em span:style a:href:target ul li ol h1 h2 h3 h4"|safe }}</p> +{% endfor %}</div> +</div> diff --git a/chimere_rss/templates/rss_title.html b/chimere_rss/templates/rss_title.html new file mode 100644 index 0000000..5b379e7 --- /dev/null +++ b/chimere_rss/templates/rss_title.html @@ -0,0 +1,2 @@ +{% load i18n %} +{{ obj.name }} diff --git a/chimere_rss/urls.py b/chimere_rss/urls.py new file mode 100644 index 0000000..e5e9a24 --- /dev/null +++ b/chimere_rss/urls.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010 Pierre Clarenc <pierre.crc_AT_gmailDOTcom>, +# Samuel Renard <renard.samuel_AT_gmailDOTcom>, +# Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> + +# 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 <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + + +from django.conf.urls.defaults import * + +from chimere.rss.feeds import LatestPOIsByCategory, LatestPOIsBySubCategory, \ + LatestPOIs, LatestPOIsByZone, LatestPOIsByZoneID +from chimere.urls import EXTRA_NO_AREA as EXTRA + +feeds = { + 'category': LatestPOIsByCategory, + 'subcategory': LatestPOIsBySubCategory, + 'global': LatestPOIs, + 'area': LatestPOIsByZone, + 'areaid': LatestPOIsByZoneID +} + +urlpatterns = patterns('', + (EXTRA + r'rss/$', 'chimere.rss.views.rss'), + (EXTRA + r'rss/(?P<url>.*)/$', + 'django.contrib.syndication.views.feed', {'feed_dict': feeds}), +) + diff --git a/chimere_rss/views.py b/chimere_rss/views.py new file mode 100644 index 0000000..1d6381d --- /dev/null +++ b/chimere_rss/views.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010 Pierre Clarenc <pierre.crc_AT_gmailDOTcom>, +# Samuel Renard <renard.samuel_AT_gmailDOTcom>, +# Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> + +# 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 <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Views of the project +""" + +from django.shortcuts import render_to_response +from django.http import HttpResponseRedirect +from django.utils.translation import ugettext as _ + +from chimere import settings +from chimere.main.views import get_base_response +from chimere.main.actions import actions +from chimere.main.models import SubCategory,Area +from chimere.main.forms import AreaForm +from chimere.main.widgets import AreaWidget + +def rss(request, area_name=''): + ''' + Redirect to RSS subscription page + ''' + response_dct = get_base_response() + response_dct.update({'actions':actions, 'action_selected':('rss',), + 'category_rss_feed':'',}) + # If the form has been submited + if request.method == "POST": + # User has defined the kind of POI he is interested in : POI in a area + # (GET method is used for the link with RSS icon in the browser) + if 'rss_category' in request.POST: + #User wants to follow all the new POI + if request.POST['rss_category'] == 'global': + feeds_link = '/' + settings.EXTRA_URL + 'rss/global/' + return HttpResponseRedirect(feeds_link) + # User wants to follow all the new POI by category or subcategory + elif request.POST['rss_category'] == 'poi': + response_dct['category_rss_feed'] = 'category' + response_dct['sub_categories'] = SubCategory.getAvailable() + return render_to_response('rss.html', response_dct) + # User wants to follow all the new POI situated in a defined area + elif request.POST['rss_category'] == 'area': + # An unbound form + form = AreaForm() + area_widget = AreaWidget().render('area', None) + response_dct.update({'map_layer':settings.MAP_LAYER, + 'extra_head':form.media, + 'form':form, + 'category_rss_feed':'area', + 'area_id':Area.getAvailable(), + 'area_widget':area_widget + }) + return render_to_response('rss.html', response_dct) + # Error when submitting the form + else: + error = _("Incorrect choice in the list") + response_dct.update({'error_message':error, + 'category_rss_feed':'', + 'sub_categories':SubCategory.getAvailable()}) + return render_to_response('rss.html', response_dct) + + # User has specified the category or subcategory he wants to follow => + # we redirect him towards the related rss feed + if 'subcategory' in request.POST and request.POST['subcategory'] != '': + idCat = request.POST['subcategory'] + if idCat.find("cat_") != -1 : + list_Cat = idCat.split('_') + feeds_link = '/' + settings.EXTRA_URL + 'rss/category/' + feeds_link += list_Cat[1] + return HttpResponseRedirect(feeds_link) + + else: + feeds_link = '/' + settings.EXTRA_URL + 'rss/subcategory/' + \ + idCat + return HttpResponseRedirect(feeds_link) + + # User has specified the ID of the area he wants to follow + if 'id_area' in request.POST and request.POST['id_area'] != '': + feeds_link = '/' + settings.EXTRA_URL + 'rss/areaid/' \ + + request.POST['id_area'] + return HttpResponseRedirect(feeds_link) + + # User has specified the area he wants to follow => we redirect him + # towards the related rss feed (using upper left and lower right + # coordinates) + elif 'upper_left_lat' in request.POST and \ + request.POST['upper_left_lat'] != '' and \ + 'upper_left_lon' in request.POST and \ + request.POST['upper_left_lon'] != '' and \ + 'lower_right_lon' in request.POST and \ + request.POST['lower_right_lon'] != '' and \ + 'lower_right_lat' in request.POST and \ + request.POST['lower_right_lat'] != '' : + feeds_link = '/' + settings.EXTRA_URL + 'rss/area/' + \ +request.POST['upper_left_lat'] + '_' + request.POST['upper_left_lon'] + '_' + \ +request.POST['lower_right_lat'] + '_' + request.POST['lower_right_lon'] + return HttpResponseRedirect(feeds_link) + + + # GET method is used for linking with the RSS icon in the browser when user + # wants to choose a category to follow + elif request.method == "GET" and 'rss_category' in request.GET: + if request.GET['rss_category'] == 'global': + feeds_link = '/' + settings.EXTRA_URL + 'rss/global/' + return HttpResponseRedirect(feeds_link) + if request.GET['rss_category'] == 'poi': + response_dct['category_rss_feed'] = 'category' + response_dct['sub_categories'] = SubCategory.getAvailable(['M','B']) + return render_to_response('rss.html', response_dct) + if request.GET['rss_category'] == 'area': + # An unbound form + form = AreaForm() + response_dct.update({'map_layer':settings.MAP_LAYER, + 'extra_head':form.media, + 'form':form, + 'category_rss_feed':'area', + 'area_id':Area.getAvailable(), + 'area_widget':AreaWidget().render('area', None)}) + return render_to_response('rss.html', response_dct) + + # User access to the RSS tab + else: + return render_to_response('rss.html', response_dct) |
