Changeset 1701
- Timestamp:
- 07/21/08 13:53:50 (4 months ago)
- Location:
- trunk/pylucid
- Files:
-
- 2 added
- 6 modified
-
media/PyLucid/internal_page/blog/display_blog.css (modified) (4 diffs)
-
media/PyLucid/internal_page/blog/display_blog.html (modified) (3 diffs)
-
media/PyLucid/internal_page/blog/edit_blog_entry.html (modified) (1 diff)
-
media/PyLucid/internal_page/blog/edit_comment.html (modified) (1 diff)
-
PyLucid/plugins_internal/blog/blog.py (modified) (11 diffs)
-
PyLucid/plugins_internal/blog/blog_cfg.py (modified) (3 diffs)
-
PyLucid/plugins_internal/blog/forms.py (added)
-
PyLucid/plugins_internal/blog/models.py (added)
Legend:
- Unmodified
- Added
- Removed
-
trunk/pylucid/media/PyLucid/internal_page/blog/display_blog.css
r1691 r1701 1 fieldset {1 .blog fieldset { 2 2 padding: 0.2em 0em 0.5em 1em; 3 3 margin: 0px; … … 6 6 border-top: 1px solid #777; 7 7 } 8 legend { 9 font-size: 0.8em; 10 padding: 2px; 11 border: 1px solid #000; 12 background-color: #FFF; 8 .blog legend { 9 font-size: 0.9em; 10 border: 1px solid #333; 11 background-color: #FFF; 12 padding: 0.2em 1em 0.2em 1em; 13 margin: 0px; 14 margin-left: 1em; 13 15 } 14 16 /* -------------------------------------------------------------------------- */ 15 . entry {17 .blog fieldset.entry { 16 18 background-color: #fff; 17 19 margin: 1em 0 1em 0; 18 20 padding: 0; 19 21 } 20 . headline {22 .blog .headline { 21 23 background-color: #f5f5f5; 22 padding: 0.5em;23 margin-left: 1em;24 24 } 25 .entry, .headline { 25 .blog .headline a { 26 text-decoration: none; 27 } 28 .blog fieldset.entry, .blog .headline { 26 29 border: 1px solid #888; 27 30 } 28 .headline { 29 padding: 0 0.5em 0 0.5em; 30 font-size: 1.5em; 31 } 32 .content { 33 margin: 0.1em 0.5em 0.1em 0.5em; 31 .content, .comment_link { 32 padding: 0.1em 0.5em 0.1em 0.5em; 34 33 } 35 34 /* -------------------------------------------------------------------------- */ … … 61 60 } 62 61 /* -------------------------------------------------------------------------- */ 63 . taglist {62 .blog fieldset.taglist { 64 63 background-color: #eee; 65 64 } 66 . taglist legend, .dateinfo {65 .dateinfo { 67 66 color: #666; 68 67 } 69 . taglist a{68 .blog .taglist { 70 69 text-decoration: none; 71 70 font-size: 0.9em; 72 71 } 73 . taglist a:hover {72 .blog .taglist a:hover { 74 73 text-decoration: underline; 75 74 } … … 147 146 } 148 147 /* -------------------------------------------------------------------------- */ 148 .feeds ul, .feeds * { 149 list-style-type:none; 150 padding: 0px; 151 margin: 0px; 152 } 153 .feed_type, .feed_type li { 154 display:inline; 155 } 156 /* -------------------------------------------------------------------------- */ -
trunk/pylucid/media/PyLucid/internal_page/blog/display_blog.html
r1691 r1701 73 73 <fieldset class="comments"><legend>Leave a comment</legend> 74 74 <script type="text/javascript"> 75 document.write('<fo rm method="post" action=".">');75 document.write('<fo'+'rm met'+'hod="po'+'st" act'+'ion=".">'); 76 76 </script> 77 77 <ul id="input_fields"> 78 78 {% for field in add_comment_form %} 79 79 <li title="{{ field.help_text }}" class="{{ field.html_name }}"> 80 <label for="{{ field.auto_id }}">{{ field.label }} :</label>80 <label for="{{ field.auto_id }}">{{ field.label }}:</label> 81 81 {{ field }} 82 82 <span class="field_help_text">{{ field.help_text }}</span> … … 87 87 <noscript><h2 style="color:red;">JavaScript required!</h2></noscript> 88 88 <script type="text/javascript"> 89 document.write('<in put type="submit" value="{% trans 'submit' %}" />');90 document.write('</fo rm>');89 document.write('<in'+'put type="sub'+'mit" value="{% trans 'submit' %}" />'); 90 document.write('</fo'+'rm>'); 91 91 </script> 92 92 </fieldset> … … 96 96 {% endfor %} 97 97 98 <fieldset class="feeds"><legend>{% trans 'available syndication feeds' %}</legend> 99 {% regroup feed_info|dictsort:"feed_type" by feed_type as feeds_grouped %} 100 <ul> 101 {% for feed in feeds_grouped %} 102 <li class="grouper"><strong>{{ feed.grouper }}:</strong> 103 <ul class="feed_type"> 104 {% for item in feed.list %} 105 <li><a href="{{ item.url }}">{{ item.title_info }}</a></li> 106 {% endfor %} 107 </ul> 108 </li> 109 {% endfor %} 110 </ul> 111 </fieldset> 112 98 113 {% if back_url %}<p><a href="{{ back_url }}" class="action_link">Display all blog entries</a></p>{% endif %} 99 114 {% if create_url %}<p><a href="{{ create_url }}" class="action_link">create a new blog entry</a></p>{% endif %} -
trunk/pylucid/media/PyLucid/internal_page/blog/edit_blog_entry.html
r1686 r1701 4 4 {% for field in form %} 5 5 <li title="{{ field.help_text }}" class="{{ field.html_name }}"> 6 <label for="{{ field.auto_id }}">{{ field.label }} :</label>6 <label for="{{ field.auto_id }}">{{ field.label }}:</label> 7 7 {{ field }} 8 8 <span class="field_help_text">{{ field.help_text }}</span> -
trunk/pylucid/media/PyLucid/internal_page/blog/edit_comment.html
r1688 r1701 4 4 {% for field in form %} 5 5 <li title="{{ field.help_text }}" class="{{ field.html_name }}"> 6 <label for="{{ field.auto_id }}">{{ field.label }} :</label>6 <label for="{{ field.auto_id }}">{{ field.label }}:</label> 7 7 {{ field }} 8 8 <span class="field_help_text">{{ field.help_text }}</span> -
trunk/pylucid/PyLucid/plugins_internal/blog/blog.py
r1699 r1701 21 21 __version__= "$Rev:$ Alpha" 22 22 23 import datetime 24 25 from django.db import models 23 # from python core 24 import os, datetime, posixpath 25 26 # from django 26 27 from django.conf import settings 27 from django import newforms as forms28 from django.http import HttpResponse 28 29 from django.utils import feedgenerator 29 30 from django.core.mail import send_mail 30 from django.contrib.auth.models import User31 31 from django.utils.safestring import mark_safe 32 32 from django.utils.encoding import force_unicode 33 33 from django.utils.translation import ugettext as _ 34 35 34 from django.utils import feedgenerator 36 35 from django.contrib.syndication.feeds import Feed, FeedDoesNotExist 37 36 38 37 # from PyLucid 38 from PyLucid.tools.utils import escape 39 39 from PyLucid.system.BasePlugin import PyLucidBasePlugin 40 from PyLucid.tools.content_processors import apply_markup41 from PyLucid.tools.newforms_utils import StripedCharField42 40 from PyLucid.tools.utils import escape_django_tags 43 41 from PyLucid.system.page_msg import PageMessages 44 from PyLucid.models.Page import MARKUPS 45 42 43 # from blog plugin 44 from PyLucid.plugins_internal.blog.forms import BlogCommentForm, \ 45 AdminCommentForm, BlogEntryForm 46 from PyLucid.plugins_internal.blog.models import BlogComment, BlogTag, BlogEntry 46 47 from PyLucid.plugins_internal.blog.blog_cfg import DONT_CHECK, REJECT_SPAM, \ 47 48 MODERATED 49 50 #______________________________________________________________________________ 51 52 PLUGIN_MODELS = (BlogComment, BlogTag, BlogEntry,) 48 53 49 54 # Don't send mails, display them only. … … 51 56 MAIL_DEBUG = False 52 57 53 """54 AVAILABLE_FEEDS = {55 ENTRIES_FEED = "all_blog_entries"56 COMMENTS_FEED = "all_blog_comments"57 }58 59 FEED_FORMATS = (60 {61 "file_ext": "rss",62 "generator": feedgenerator.Rss201rev2Feed,63 },64 {65 "file_ext": "atom",66 "generator": feedgenerator.Atom1Feed,67 },68 )69 """70 71 58 #______________________________________________________________________________ 72 73 class BlogComment(models.Model): 59 # FEEDS 60 61 # Don't response the RSS/Atom feed, display it only 62 #FEED_DEBUG = True 63 FEED_DEBUG = False 64 65 ENTRIES_FEED_NAME = u"entries" 66 COMMENTS_FEED_NAME = u"comments" 67 TAG_FEED_PREFIX = u"tag_" # The tag slug would be appended! 68 69 # All file endings must be lower case and without "." ! 70 RSS = u"rss" 71 ATOM = u"atom" 72 73 #______________________________________________________________________________ 74 75 class FeedInfo(list): 74 76 """ 75 comment from non-registered users 77 A list of feed information. 78 I a normal list with one spectial add method. 79 Contains a dict for every feed info. 76 80 """ 77 blog_entry = models.ForeignKey("BlogEntry") 78 79 ip_address = models.IPAddressField(_('ip address'),) 80 person_name = models.CharField( 81 _("person's name"), max_length=50, 82 help_text=_("Your full name (will be published) (required)"), 83 ) 84 email = models.EmailField( 85 _('e-mail address'), 86 help_text=_("Only for internal use. (will not be published) (required)"), 87 ) 88 homepage = models.URLField( 89 _("homepage"), help_text = _("Your homepage (optional)"), 90 verify_exists = False, max_length = 200, 91 null=True, blank=True 92 ) 93 94 content = models.TextField(_('content'), max_length=3000) 95 96 is_public = models.BooleanField(_('is public')) 97 98 createtime = models.DateTimeField( 99 auto_now_add=True, help_text="Create time", 100 ) 101 lastupdatetime = models.DateTimeField( 102 auto_now=True, help_text="Time of the last change.", 103 ) 104 createby = models.ForeignKey( 105 User, editable=False, 106 help_text="User how create the current comment.", 107 null=True, blank=True 108 ) 109 lastupdateby = models.ForeignKey( 110 User, editable=False, 111 help_text="User as last edit the current comment.", 112 null=True, blank=True 113 ) 114 115 class Admin: 116 pass 117 118 class Meta: 119 app_label = 'PyLucidPlugins' 120 121 122 123 class BlogCommentForm(forms.ModelForm): 124 """ 125 Add a new comment. 126 """ 127 person_name = forms.CharField( 128 min_length=4, max_length=50, 129 help_text=_("Your name."), 130 ) 131 content = StripedCharField( 132 label = _('content'), min_length=5, max_length=3000, 133 help_text=_("Your comment to this blog entry."), 134 widget=forms.Textarea(attrs={'rows': '15'}), 135 ) 136 137 class Meta: 138 model = BlogComment 139 # Using a subset of fields on the form 140 fields = ('person_name', 'email', "homepage") 141 142 143 class AdminCommentForm(BlogCommentForm): 144 """ 145 Form for editing a existing comment. Only for Admins 146 """ 147 class Meta: 148 model = BlogComment 149 fields = ( 150 'ip_address', 'person_name', 'email', "homepage", 151 "content", "is_public", 152 "createtime", "lastupdatetime", "createby", "lastupdateby" 153 ) 81 def add(self, title_info, url_parts): 82 assert(isinstance(url_parts, (list,tuple))) #Needed? 83 url_start = posixpath.join(*url_parts) 84 85 list.append(self, { 86 "feed_type": RSS, 87 "title_info": title_info, 88 "url": "%s.%s" % (url_start, RSS), 89 }) 90 list.append(self, { 91 "feed_type": ATOM, 92 "title_info": title_info, 93 "url": "%s.%s" % (url_start, ATOM), 94 }) 95 154 96 155 97 #______________________________________________________________________________ 156 157 158 class BlogTagManager(models.Manager):159 """160 Manager for BlogTag model.161 """162 def get_or_creates(self, tags_string):163 """164 split the given tags_string and create not existing tags.165 returns a list of all tag model objects and a list of all created tags.166 """167 tag_objects = []168 new_tags = []169 for tag_name in tags_string.split(" "):170 tag_name = tag_name.strip().lower()171 try:172 tag_obj = self.get(name = tag_name)173 except self.model.DoesNotExist:174 new_tags.append(tag_name)175 tag_obj = self.create(name = tag_name, slug = tag_name)176 177 tag_objects.append(tag_obj)178 179 return tag_objects, new_tags180 181 182 class BlogTag(models.Model):183 184 objects = BlogTagManager()185 186 name = models.CharField(max_length=255, core=True, unique=True)187 slug = models.SlugField(188 unique=True, prepopulate_from=('tag',), max_length=120189 )190 191 def __unicode__(self):192 return self.name193 194 class Admin:195 pass196 197 class Meta:198 app_label = 'PyLucidPlugins'199 200 201 #______________________________________________________________________________202 203 class BlogEntry(models.Model):204 """205 A blog entry206 """207 headline = models.CharField(_('Headline'),208 help_text=_("The blog entry headline"), max_length=255209 )210 content = models.TextField(_('Content'))211 markup = models.IntegerField(212 max_length=1, choices=MARKUPS,213 help_text="the used markup language for this entry",214 )215 216 tags = models.ManyToManyField(BlogTag, blank=True)217 218 is_public = models.BooleanField(219 default=True, help_text="Is post public viewable?"220 )221 222 createtime = models.DateTimeField(auto_now_add=True)223 lastupdatetime = models.DateTimeField(auto_now=True)224 createby = models.ForeignKey(User,225 editable = False,226 )227 lastupdateby = models.ForeignKey(228 User,229 editable = False,230 null=True, blank=True231 )232 233 def html_content(self, context):234 """235 returns the generatet html code from the content applyed the markup.236 """237 return apply_markup(238 content = self.content,239 context = context,240 markup_no = self.markup241 )242 243 def get_tag_string(self):244 """245 Returns all tags as a joined string246 """247 tags = self.tags.all()248 tags_names = [i.name for i in tags]249 return " ".join(tags_names)250 251 def __unicode__(self):252 return self.headline253 254 class Admin:255 pass256 257 class Meta:258 app_label = 'PyLucidPlugins'259 ordering = ('-createtime', '-lastupdatetime')260 261 '''262 class RssBlogEntryFeed(Feed):263 """264 TODO!265 http://www.djangoproject.com/documentation/syndication_feeds/266 """267 title = "Blog entry feed"268 link = "/TODO/"269 description = "FIXME"270 271 def items(self):272 return BlogEntry.objects.filter(is_public=True).all()[:count]273 274 class AtomBlogEntryFeed(RssBlogEntryFeed):275 feed_type = Atom1Feed276 subtitle = RssBlogEntryFeed.description277 278 class BlogEntryForm(forms.ModelForm):279 """280 Form for create/edit a blog entry.281 """282 content = forms.CharField(283 widget=forms.Textarea(attrs={'rows': '15'}),284 )285 286 tags = forms.CharField(287 max_length=255, required=False,288 help_text=_("Tags for this entry (separated by spaces.)"),289 widget=forms.TextInput(attrs={'class':'bigger'}),290 )291 class Meta:292 model = BlogEntry293 '''294 295 #______________________________________________________________________________296 297 298 PLUGIN_MODELS = (BlogComment, BlogTag, BlogEntry,)299 300 301 98 302 99 … … 319 116 # Change the page title. 320 117 self.current_page.title = self.preferences["blog_title"] 118 119 # The absolute url to the page witch contains the blog 120 self.index_url = "FIXME" 121 122 self.feed_url_prefix = self.URLs.methodLink("feed") 321 123 322 124 … … 372 174 context["create_url"] = self.URLs.methodLink("add_entry") 373 175 374 self._render_template("display_blog", context)#, debug=2) 176 # Add all available syndication feeds information 177 context["feed_info"] = self._get_feeds_info() 178 179 self._render_template("display_blog", context, debug=0) 375 180 376 181 def _get_max_count(self): … … 405 210 ) 406 211 407 max= self._get_max_count()408 entries = entries.all()[: max]212 limit = self._get_max_count() 213 entries = entries.all()[:limit] 409 214 410 215 self._list_entries(entries) … … 425 230 # in users. 426 231 if self.request.user.is_anonymous(): 427 msg = "Wrong url." 428 if self.request.debug: 429 msg += " Blog entry is not public" 430 self.page_msg.red(msg) 431 return 232 return self.error(_("Wrong URL."), "Blog entry is not public") 432 233 433 234 if self.request.method == 'POST': … … 478 279 entries = entries.filter(is_public = True) 479 280 480 max= self._get_max_count()481 entries = entries.all()[: max]281 limit = self._get_max_count() 282 entries = entries.all()[:limit] 482 283 483 284 context = { … … 561 362 return model.objects.get(id = entry_id) 562 363 except Exception, err: 563 msg = "Wrong url" 564 if self.request.debug: 565 msg += " %s" % err 566 self.page_msg.red(msg) 567 return 364 return self.error(_("Wrong URL."), err) 568 365 569 366 def delete(self, urlargs): … … 893 690 894 691 self._render_template("mod_comments", context)#, debug=2) 895 ''' 896 def get_feeds_info(self): 897 # return the existing feed names 898 return (ENTRIES_FEED, COMMENTS_FEED) 899 900 def feed(self, feed_name, FeedGenerator, count=10): 901 """ 902 Feeds 903 * RSS 2.0 / Atom for all entries 904 * RSS 2.0 / Atom for the comments 905 906 FeedGenerator = django.utils.feedgenerator.Atom1Feed 907 or 908 FeedGenerator = django.utils.feedgenerator.Rss201rev2Feed 909 910 911 RSSfeedGenerator.lucidTag 912 - Generates a list of all available feeds 913 - The links are always /feed/PluginName/FeedName/FeedType.xml 914 915 /_command/1/RSSfeedGenerator/ 916 917 692 693 def _get_feeds_info(self): 694 """ 695 returns information about all available syndication feeds. 696 """ 697 feed_info = FeedInfo() 698 699 # Add "normal" feeds 700 feed_info.add( 701 title_info = ENTRIES_FEED_NAME, 702 url_parts = (self.feed_url_prefix, ENTRIES_FEED_NAME,) 703 ) 704 feed_info.add( 705 title_info = COMMENTS_FEED_NAME, 706 url_parts = (self.feed_url_prefix, COMMENTS_FEED_NAME,) 707 ) 708 709 # Build a list of tag feeds 710 limit = self.preferences.get("max_tag_feed", 10) 711 tags = BlogTag.objects.values_list("slug", "name").all()[:limit] 712 tag_feeds = [TAG_FEED_PREFIX + i[0] for i in tags] 713 #self.page_msg(tag_feeds) 714 715 # Add tag feeds 716 for tag_slug, tag_name in tags: 717 filename = TAG_FEED_PREFIX + tag_slug 718 719 feed_info.add( 720 title_info = tag_name, 721 url_parts = (self.feed_url_prefix, filename,) 722 ) 723 724 return feed_info 725 726 727 def feed(self, raw_feed_name): 728 """ 729 Generate and return a syndication feeds. 730 731 feed_name e.g.: 732 tag_%s.rss 733 tag_%s.atom 734 entries .rss/.atom 735 comments .rss/.atom 918 736 """ 919 737 title = self.preferences["blog_title"] 920 738 921 if feed_name == ENTRIES_FEED: 922 model = BlogEntry 739 try: 740 feed_name, feed_type = os.path.splitext(raw_feed_name) 741 feed_type = feed_type.lstrip(".") 742 except Exception, err: 743 return self.error(_("Wrong URL."), err) 744 745 if feed_type == RSS: 746 FeedGenerator = feedgenerator.Rss201rev2Feed 747 elif feed_type == ATOM: 748 FeedGenerator = feedgenerator.Atom1Feed 749 else: 750 return self.error( 751 _("Wrong URL."), " feed type '%s' unknown." % feed_type 752 ) 753 754 limit = self._get_max_count() 755 756 if feed_name == ENTRIES_FEED_NAME: 757 # Feed with all blog entries 758 entries = BlogEntry.objects 923 759 title += " - all blog entries" 924 760 925 elif feed_name == COMMENTS_FEED: 926 model = BlogComment 761 elif feed_name == COMMENTS_FEED_NAME: 762 # Feed with all comments 763 entries = BlogComment.objects 927 764 title += " - all blog comments" 928 765 766 elif feed_name.startswith(TAG_FEED_PREFIX): 767 # Feed with all blog entries tagged with the given tag 768 tag_slug = feed_name[len(TAG_FEED_PREFIX):] 769 #self.page_msg("Tag slug: '%s'" % tag_slug) 770 tag_obj = BlogTag.objects.get(slug = tag_slug) 771 title += " - all blog entries tagged with '%s'" % tag_obj.name 772 entries = tag_obj.blogentry_set 773 929 774 else: 930 raise AttributeError("Wrong feed_name.") 931 932 items = model.objects.filter(is_public=True).all()[:10] 933 934 link = self.URLs.methodLink("feed", feed_name) 935 936 feed = self._get_feed(FeedGenerator, items, title, link) 937 938 return feed.writeString('utf8') 939 940 941 def _get_feed(self, FeedGenerator, items, title, link): 775 return self.error( 776 _("Wrong URL."), " feed name '%s' unknown." % feed_name 777 ) 778 779 # Get the items 780 items = entries.filter(is_public=True).all()[:limit] 781 782 feed = self._get_feed(FeedGenerator, items, title) 783 feed_content = feed.writeString('utf8') 784 content_type = "%s; charset=utf-8" % feed.mime_type 785 786 if FEED_DEBUG: 787 self.response.write("<h2>Debug:</h2>") 788 self.response.write("content type: %s" % content_type) 789 self.response.write("<pre>") 790 self.response.write(escape(feed_content)) 791 self.response.write("</pre>") 792 return 793 794 # send the feed as a file to the client 795 response = HttpResponse(content_type=content_type)
