diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_Q2hhbmdlTG9n --- /dev/null +++ b/ChangeLog @@ -0,0 +1,6 @@ +ChangeLog for component Blog +============================ + +2008-05-12 -- 1.0.2 + + * import and xhtml fixes diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_TUFOSUZFU1QuaW4= --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,4 @@ +include *.py +recursive-include data external_resources *.gif *.jpg *.css +recursive-include i18n *.pot *.po +recursive-include migration *.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_X19pbml0X18ucHk= --- /dev/null +++ b/__init__.py @@ -0,0 +1,1 @@ +"""package __init__""" diff --git a/__pkginfo__.py b/__pkginfo__.py new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_X19wa2dpbmZvX18ucHk= --- /dev/null +++ b/__pkginfo__.py @@ -0,0 +1,49 @@ +# pylint: disable-msg=W0622 +"""cubicweb-blog packaging information""" + +distname = "cubicweb-blog" + +numversion = (1, 3, 0) +version = '.'.join(str(num) for num in numversion) + +license = 'LCL' +copyright = '''Copyright (c) 2003-2007 LOGILAB S.A. (Paris, FRANCE). +http://www.logilab.fr/ -- mailto:contact@logilab.fr''' + +author = "Logilab" +author_email = "contact@logilab.fr" +web = '' + +short_desc = "blog support for the CubicWeb framework" +long_desc = """CubicWeb is a entities / relations bases knowledge management system +developped at Logilab. +. +This package provides schema and views to add bloging functionalities to +cubicweb applications. +. +""" + +from os import listdir +from os.path import join + +TEMPLATES_DIR = join('share', 'cubicweb', 'cubes') +try: + data_files = [ + [join(TEMPLATES_DIR, 'eblog'), + [fname for fname in listdir('.') + if fname.endswith('.py') and fname != 'setup.py']], + [join(TEMPLATES_DIR, 'eblog', 'data'), + [join('data', fname) for fname in listdir('data')]], + [join(TEMPLATES_DIR, 'eblog', 'i18n'), + [join('i18n', fname) for fname in listdir('i18n')]], + [join(TEMPLATES_DIR, 'eblog', 'migration'), + [join('migration', fname) for fname in listdir('migration')]], + ] +except OSError: + # we are in an installed directory + pass + + +template_eid = 20300 +# used packages +__use__ = () diff --git a/data/blog_style.css b/data/blog_style.css new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_ZGF0YS9ibG9nX3N0eWxlLmNzcw== --- /dev/null +++ b/data/blog_style.css @@ -0,0 +1,41 @@ +div.post { + width: 50%; + margin-bottom: 2em; +} + +div.post h1 { + font-size: 1.3em; + position: relative; + border-bottom: none; +} + +div.post p.postmetadata { + background:transparent url(postdatabg.jpg) no-repeat scroll left bottom; + font-size: 0.92em; + padding-bottom: 12px; + padding-left: 10px; + padding-top: 10px; + margin-bottom:1.5em; +} + +div.post div.entry { + margin-left: 10px; + margin-top: 25px; + padding-top: 5px; +} + +div.post div.entry p { + margin-bottom:1.5em; +} + +div.post small { + font-size: 80%; + color:#949494; + display: block; + margin-left: 2em; + margin: 0em 0em 1em 1em; +} + +ul.invisible li { + background: none; +} diff --git a/data/external_resources b/data/external_resources new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_ZGF0YS9leHRlcm5hbF9yZXNvdXJjZXM= --- /dev/null +++ b/data/external_resources @@ -0,0 +1,1 @@ +BLOG_ICON = DATADIR/icon_blog.gif diff --git a/data/icon_blog.gif b/data/icon_blog.gif new file mode 100644 index 0000000000000000000000000000000000000000..504c74b992621321a8b5a39ebb744784f5679e48 GIT binary patch literal 276 zc$@(g0qg!pNk%w1VGsZi0K@<QW|_>x*XxC@*6;NCm%80@q0rgo^RUY0|NsA#x7%i! z%;4+wqQT(r_y5%5@p`7yi?P_}@Atja>2ROVoW0(v#^TQ2@Adfnd#%=uv)SF~^rOPy zbEVeU<?{dk{{R30A^8La6aXFoEC2ui01yBW000G%peK%GX;RPxOaftg)$<(M;4m^n zR>g+=h|6U`m{3NK3J`c1L^2N%<#9m(u2?`sGf8*^mFhC+j3fk}iJ_XsMk0ZUM=Pug z2hN2Bkhb94R|^Xgasmtyc!^~T1{oM02@eYqfB+g66B!~81R5F<f`SGH5K&T@o~a!c a851reQ?3#g5(x#IFBt+V6BwE!ApkoY$b6pw diff --git a/data/postdatabg.jpg b/data/postdatabg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5f4ae169ab66808eaae67fe07cc086b8ea520f38 GIT binary patch literal 868 zc%1ux<NpH&0WUXCHwH!~28I+MWcdGvLC~c%IlGd9k%5JQfgu1W^o~KzF(p4Kl_BK- zP=t}0L6n7=jf<Cofk^;}J%RWZ0|Rr?|Jw{L3`}sq48knTAcB<z1X$Tv!GMj8ot=Z7 zosE-|i;I(!2Nf_fGc&WYuyV4oaq@C=a`W=@0RcZhSPn|@@blmS{|_+;axmyHv@tUZ zGB61;G7B>PKf<t(fe`{2;DC{dg_)HDSp)(EfIehqMHUuRR8lZV5O4@EbYv0)>0?Kh zb#!uIEOb@~P<+UwWRxU?ZeD^g0~1gSE0T$ff{KX(9|9YJh8AvgFm#;wapC`43_Q$? zK=(2W0_Fey;sPs_OIWJu0HoOseMOdPdI4DlQ<n9LT=WW>!oc{sXUa`qk&BC6HN67( zjE^kUTr^A5S7cciBhW06w-{NO9$Zg+wz~YF>q6JfU+<ipq~bAA@wiOYey{>2kb;vC zHZu~NiHXgg$rmDwU@|fSnJ1Qd$eA=wKR3DY_1kjYX{VFfc%@7nS%mo^N|+h#73VwK z-R)GFS8{o4lc&n0%Hl7cDszPVg#49cpY(6EnB-|Oxn=TU$?M5C;-93foVBcKruOme zqM{q4MGr$P2bu9IA7VS4jR+Y50dTm0(j1UvRG9z@e}*Pb1_lm=CJ&Yg3@QSQ3Id$= za0dzeh!xt)>iN|v_UMM_&Y0`cJp!%@vv+LcF4Ug-UHXqux3i$5NRQtmAisCxhu;h@ zg*g<agmWGd@Hp}%2`Jcn-2c&{Rn>WV&!1(9E!rafMEr?Zq}Y08Ti4ZRB2&%=W{b~e Qy%1gucf0_S<3a430M~NM6aWAK diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_ZGViaWFuL2NoYW5nZWxvZw== --- /dev/null +++ b/debian/changelog @@ -0,0 +1,56 @@ +cubicweb-blog (1.3.0-1) unstable; urgency=low + + * new upstream release + + -- Adrien Di Mascio <Adrien.DiMascio@logilab.fr> Thu, 09 Oct 2008 15:02:08 +0200 + +cubicweb-blog (1.2.2-2) unstable; urgency=low + + * new upstream release + + -- Julien Jehannet <julien.jehannet@logilab.fr> Fri, 3 Oct 2008 14:05:01 +0200 + +cubicweb-blog (1.2.2-1) unstable; urgency=low + + * new upstream release + + -- Julien Jehannet <julien.jehannet@logilab.fr> Fri, 3 Oct 2008 11:15:11 +0200 + +cubicweb-blog (1.2.1-1) unstable; urgency=low + + * new upstream release + + -- Sylvain Thénault <sylvain.thenault@logilab.fr> Mon, 11 Aug 2008 13:26:31 +0200 + +cubicweb-blog (1.2.0-1) unstable; urgency=low + + * new upstream release + + -- Nicolas Chauvat <Nicolas.Chauvat@logilab.fr> Thu, 7 Aug 2008 17:41:00 +0200 + +cubicweb-blog (1.1.0-1) unstable; urgency=low + + * new upstream release + + -- Sylvain Thénault <sylvain.thenault@logilab.fr> Thu, 12 Jun 2008 17:23:21 +0200 + +cubicweb-blog (1.0.2-1) unstable; urgency=low + + * new upstream release + + -- Nicolas Chauvat <Nicolas.Chauvat@logilab.fr> Mon, 12 May 2008 21:50:19 +0200 + +cubicweb-blog (1.0.1-1) unstable; urgency=low + + * add debian/compat and debian/pycompat files, remove DH_COMPAT from rules + * update standards version, fixed uploaders/maintainer/section in debian/control + * new upstream release + + -- Sylvain Thénault <Sylvain.Thenault@logilab.fr> Wed, 26 Mar 2008 11:10:15 +0100 + +cubicweb-blog (1.0.0-1) unstable; urgency=low + + * initial upstream release + + -- Sylvain Thénault <Sylvain.Thenault@logilab.fr> Tue, 18 Sep 2007 16:31:38 +0200 + diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_ZGViaWFuL2NvbXBhdA== --- /dev/null +++ b/debian/compat @@ -0,0 +1,1 @@ +5 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_ZGViaWFuL2NvbnRyb2w= --- /dev/null +++ b/debian/control @@ -0,0 +1,16 @@ +Source: cubicweb-blog +Section: web +Priority: optional +Maintainer: Logilab Packaging Team <contact@logilab.fr> +Uploaders: Sylvain Thenault <sylvain.thenault@logilab.fr> +Build-Depends: debhelper (>= 5.0.37.1), python (>=2.4), python-dev (>=2.4) +Standards-Version: 3.8.0 + +Package: cubicweb-blog +Architecture: all +Depends: python2.4, cubicweb-common (>= 3.0.0) +Description: Blog support for the CubicWeb framework + CubicWeb is semantic web application framework. + . + This package provides schema and views to add bloging functionalities + to cubicweb applications. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_ZGViaWFuL2NvcHlyaWdodA== --- /dev/null +++ b/debian/copyright @@ -0,0 +1,15 @@ +This package was debianized by Logilab <contact@logilab.fr>. + + +Upstream Author: + + Logilab <contact@logilab.fr> + +Copyright: + +Copyright (c) 2003-2008 LOGILAB S.A. (Paris, FRANCE). +http://www.logilab.fr/ -- mailto:contact@logilab.fr + +Logilab Closed source License. This code is *NOT* open-source. Usage of this +code is subject to a licence agreement. If you want to use it, you should +contact logilab's sales service at commercial@logilab.fr . diff --git a/debian/cubicweb-blog.dirs b/debian/cubicweb-blog.dirs new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_ZGViaWFuL2N1Ymljd2ViLWJsb2cuZGlycw== --- /dev/null +++ b/debian/cubicweb-blog.dirs @@ -0,0 +1,1 @@ +usr/share/cubicweb/cubes/eblog diff --git a/debian/cubicweb-blog.prerm b/debian/cubicweb-blog.prerm new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_ZGViaWFuL2N1Ymljd2ViLWJsb2cucHJlcm0= --- /dev/null +++ b/debian/cubicweb-blog.prerm @@ -0,0 +1,27 @@ +#!/bin/sh -e + +delete_pyo_pyc () { + find /usr/share/cubicweb/cubes/eblog -name "*.pyc" | xargs rm -f + find /usr/share/cubicweb/cubes/eblog -name "*.pyo" | xargs rm -f +} + + +case "$1" in + failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + upgrade) + delete_pyo_pyc + ;; + remove) + delete_pyo_pyc + ;; + purge) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + +esac + +#DEBHELPER# diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_ZGViaWFuL3J1bGVz --- /dev/null +++ b/debian/rules @@ -0,0 +1,55 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 +build: build-stamp +build-stamp: + dh_testdir + python setup.py -q build + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + rm -rf build + find . -name "*.pyc" | xargs rm -f + rm -f changelog.gz + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs -i + python setup.py -q install --no-compile --prefix=debian/cubicweb-blog-comp/usr/ + + +# Build architecture-independent files here. +binary-indep: build install + dh_testdir + dh_testroot + dh_install -i +# dh_pycentral -i +# dh_python -i +# gzip -9 -c ChangeLog > changelog.gz + dh_installchangelogs -i + dh_installexamples -i + dh_installdocs -i + dh_installman -i + dh_link -i + dh_compress -i -X.py -X.ini -X.xml -Xtest + dh_fixperms -i + dh_installdeb -i + dh_gencontrol -i + dh_md5sums -i + dh_builddeb -i + + +# Build architecture-dependent files here. +binary-arch: + +binary: binary-indep +.PHONY: build clean binary-arch binary-indep binary diff --git a/entities.py b/entities.py new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_ZW50aXRpZXMucHk= --- /dev/null +++ b/entities.py @@ -0,0 +1,51 @@ +"""entity classes for Blog entities + +:organization: Logilab +:copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +:license: General Public License version 2 - http://www.gnu.org/gpl +""" +__docformat__ = "restructuredtext en" + +from cubicweb.entities import AnyEntity, fetch_config +from cubicweb.interfaces import ICalendarViews, ICalendarable + +class BlogEntry(AnyEntity): + """customized class for BlogEntry entities""" + id = 'BlogEntry' + fetch_attrs, fetch_order = fetch_config(['creation_date', 'title'], order='DESC') + __implements__ = (ICalendarViews, ICalendarable) + + def dc_title(self): + return self.title + + def dc_description(self): + return self.printable_value('content') + + ## calendar interfaces #################################################### + @property + def start(self): + return self.creation_date + + @property + def stop(self): + return self.creation_date + + def matching_dates(self, begin, end): + """calendar views interface""" + mydate = self.creation_date + if mydate and begin < mydate < end: + return [mydate] + return [] + + def postinfo_description(self): + _ = self.req._ + descr = u'%s %s' % (_('posted on'), self.format_date(self.creation_date)) + return descr + + +class Blog(AnyEntity): + """customized class for Blog entities""" + + id = 'Blog' + __rtags__ = {'entry_of': 'create'} diff --git a/hooks.py b/hooks.py new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_aG9va3MucHk= --- /dev/null +++ b/hooks.py @@ -0,0 +1,6 @@ +from cubicweb.sobjects.notification import NormalizedTextView + +class BlogEntryAddedView(NormalizedTextView): + """get notified from new blogs""" + accepts = ('BlogEntry',) + content_attr = 'content' diff --git a/i18n/en.po b/i18n/en.po new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_aTE4bi9lbi5wbw== --- /dev/null +++ b/i18n/en.po @@ -0,0 +1,109 @@ +# cubicweb-blog i18n catalog +# Copyright 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# Logilab <contact@logilab.fr> +msgid "" +msgstr "" +"Project-Id-Version: cubicweb-blog 0.1.0\n" +"PO-Revision-Date: 2008-07-15 08:48+0200\n" +"Last-Translator: Logilab Team <contact@logilab.fr>\n" +"Language-Team: en <contact@logilab.fr>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +# schema pot file, generated on 2007-09-28 17:24:46 +# +# singular and plural forms for each entity type +msgid "Blog" +msgstr "Blog" + +msgid "BlogEntry" +msgstr "Blog entry" + +msgid "BlogEntry_plural" +msgstr "Blog entries" + +msgid "Blog_plural" +msgstr "Blogs" + +msgid "Comment" +msgstr "Comment" + +msgid "New Blog" +msgstr "New blog" + +msgid "New BlogEntry" +msgstr "New blog entry" + +msgid "This Blog" +msgstr "This blog" + +msgid "This BlogEntry" +msgstr "This blog entry" + +# add related box generated message +msgid "add BlogEntry entry_of Blog object" +msgstr "" + +msgid "add a Blog" +msgstr "add a blog" + +msgid "add a BlogEntry" +msgstr "add a blog entry" + +msgid "blog_latest_box" +msgstr "latest blogs" + +msgid "boxes_blog_archives_box" +msgstr "blog archives" + +# subject and object forms for each relation type +# (no object form for final relation types) +# add related box generated message +msgid "boxes_blog_archives_box_description" +msgstr "box displaying latest blog entries posted" + +msgid "boxes_blog_latest_box" +msgstr "box displaying latest blog entries posted" + +# add related box generated message +msgid "boxes_blog_latest_box_description" +msgstr "this box contains the latest posts" + +msgid "by" +msgstr "by" + +msgid "creating BlogEntry (BlogEntry entry_of Blog %(linkto)s)" +msgstr "" + +# subject and object forms for each relation type +# (no object form for final relation types) +msgid "entry_of" +msgstr "blog entry of" + +msgid "entry_of_object" +msgstr "contains" + +msgid "more" +msgstr "more" + +msgid "posted on" +msgstr "posted on" + +msgid "remove this Blog" +msgstr "remove this blog" + +msgid "remove this BlogEntry" +msgstr "remove this blog entry" + +msgid "rss icon" +msgstr "" + +msgid "see more" +msgstr "see more" + +msgid "subscribe" +msgstr "subscribe" + +msgid "tags" +msgstr "tags" diff --git a/i18n/fr.po b/i18n/fr.po new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_aTE4bi9mci5wbw== --- /dev/null +++ b/i18n/fr.po @@ -0,0 +1,109 @@ +# cubicweb-blog i18n catalog +# Copyright 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# Logilab <contact@logilab.fr> +msgid "" +msgstr "" +"Project-Id-Version: cubicweb-blog 0.1.0\n" +"PO-Revision-Date: 2008-10-02 17:27+0200\n" +"Last-Translator: Logilab Team <contact@logilab.fr>\n" +"Language-Team: fr <contact@logilab.fr>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +# schema pot file, generated on 2007-09-28 17:24:46 +# +# singular and plural forms for each entity type +msgid "Blog" +msgstr "Blog" + +msgid "BlogEntry" +msgstr "Entrée de blog" + +msgid "BlogEntry_plural" +msgstr "Entrées de blog" + +msgid "Blog_plural" +msgstr "Blogs" + +msgid "Comment" +msgstr "Commentaire" + +msgid "New Blog" +msgstr "Nouveau blog" + +msgid "New BlogEntry" +msgstr "Nouvelle entrée de blog" + +msgid "This Blog" +msgstr "Ce blog" + +msgid "This BlogEntry" +msgstr "Cette entrée de blog" + +# add related box generated message +msgid "add BlogEntry entry_of Blog object" +msgstr "entrée de blog" + +msgid "add a Blog" +msgstr "ajouter un blog" + +msgid "add a BlogEntry" +msgstr "ajouter une entrée de blog" + +msgid "blog_latest_box" +msgstr "derniers blogs" + +msgid "boxes_blog_archives_box" +msgstr "boîte d'archive des blogs" + +# subject and object forms for each relation type +# (no object form for final relation types) +# add related box generated message +msgid "boxes_blog_archives_box_description" +msgstr "boîte permettant d'accéder aux archives des blogs pour les mois passés" + +msgid "boxes_blog_latest_box" +msgstr "dernier" + +# add related box generated message +msgid "boxes_blog_latest_box_description" +msgstr "boîte contentant la liste des derniers blogs" + +msgid "by" +msgstr "par" + +msgid "creating BlogEntry (BlogEntry entry_of Blog %(linkto)s)" +msgstr "création d'une entrée du blog %(linkto)s" + +# subject and object forms for each relation type +# (no object form for final relation types) +msgid "entry_of" +msgstr "entrée du blog" + +msgid "entry_of_object" +msgstr "contient les entrées" + +msgid "more" +msgstr "plus" + +msgid "posted on" +msgstr "posté le" + +msgid "remove this Blog" +msgstr "supprimer ce blog" + +msgid "remove this BlogEntry" +msgstr "supprimer cette entrée de blog" + +msgid "rss icon" +msgstr "" + +msgid "see more" +msgstr "voir plus" + +msgid "subscribe" +msgstr "souscrire" + +msgid "tags" +msgstr "étiquettes" diff --git a/migration/1.2.0_Any.py b/migration/1.2.0_Any.py new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_bWlncmF0aW9uLzEuMi4wX0FueS5weQ== --- /dev/null +++ b/migration/1.2.0_Any.py @@ -0,0 +1,5 @@ +rename_entity_type('Blog', u'BlogEntry') +add_entity_type('Blog') +rql('INSERT Blog B: B title "main blog"') +rql('SET BE entry_of B WHERE BE is BlogEntry, B is Blog') +checkpoint() diff --git a/migration/postcreate.py b/migration/postcreate.py new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_bWlncmF0aW9uL3Bvc3RjcmVhdGUucHk= --- /dev/null +++ b/migration/postcreate.py @@ -0,0 +1,2 @@ +# postcreate script. You could setup a workflow here for example + diff --git a/schema.py b/schema.py new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_c2NoZW1hLnB5 --- /dev/null +++ b/schema.py @@ -0,0 +1,13 @@ + +from cubicweb.common.schema import format_constraint + +class Blog(EntityType): + title = String(maxsize=50, required=True) + description = String() + +class BlogEntry(EntityType): + title = String(required=True, fulltextindexed=True, maxsize=256) + content_format = String(meta=True, internationalizable=True, maxsize=50, + default='text/rest', constraints=[format_constraint]) + content = String(required=True, fulltextindexed=True) + entry_of = SubjectRelation('Blog', cardinality='?*') diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_c2V0dXAucHk= --- /dev/null +++ b/setup.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# pylint: disable-msg=W0404,W0622,W0704,W0613,W0152 +# Copyright (c) 2003-2004 LOGILAB S.A. (Paris, FRANCE). +# http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# 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 2 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, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +""" Generic Setup script, takes package info from __pkginfo__.py file """ + +import os +import sys +import shutil +from distutils.core import setup +from distutils import command +from distutils.command import install_lib +from os.path import isdir, exists, join, walk + +# import required features +from __pkginfo__ import distname, version, license, short_desc, long_desc, \ + web, author, author_email +# import optional features +try: + from __pkginfo__ import distname +except ImportError: + distname = distname +try: + from __pkginfo__ import scripts +except ImportError: + scripts = [] +try: + from __pkginfo__ import data_files +except ImportError: + data_files = None +try: + from __pkginfo__ import include_dirs +except ImportError: + include_dirs = [] + +BASE_BLACKLIST = ('CVS', 'debian', 'dist', 'build', '__buildlog') +IGNORED_EXTENSIONS = ('.pyc', '.pyo', '.elc') + + +def ensure_scripts(linux_scripts): + """creates the proper script names required for each platform + (taken from 4Suite) + """ + from distutils import util + if util.get_platform()[:3] == 'win': + scripts_ = [script + '.bat' for script in linux_scripts] + else: + scripts_ = linux_scripts + return scripts_ + + + +def install(**kwargs): + """setup entry point""" + #kwargs['distname'] = modname + return setup(name=distname, + version=version, + license =license, + description=short_desc, + long_description=long_desc, + author=author, + author_email=author_email, + url=web, + scripts=ensure_scripts(scripts), + data_files=data_files, + **kwargs) + +if __name__ == '__main__' : + install() diff --git a/test/unittest_blog.py b/test/unittest_blog.py new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_dGVzdC91bml0dGVzdF9ibG9nLnB5 --- /dev/null +++ b/test/unittest_blog.py @@ -0,0 +1,10 @@ +from logilab.common.testlib import TestCase, unittest_main + +class EBlogTC(TestCase): + def test_something(self): + self.skip('this component has no test') + +from cubicweb.devtools.testlib import AutomaticWebTest + +if __name__ == '__main__': + unittest_main() diff --git a/views.py b/views.py new file mode 100644 index 0000000000000000000000000000000000000000..1d35f3863578449fcc21ad5a26397150a400beb8_dmlld3MucHk= --- /dev/null +++ b/views.py @@ -0,0 +1,173 @@ +"""Specific views for blogs + +:organization: Logilab +:copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +""" +__docformat__ = "restructuredtext en" + +from mx.DateTime import DateTime +from logilab.mtconverter import html_escape + +from cubicweb.common.uilib import text_cut +from cubicweb.common.view import EntityView +from cubicweb.web.views import baseviews +from cubicweb.web.views.boxes import BoxTemplate, BoxHtml +from cubicweb.web.views.calendar import MONTHNAMES +from cubicweb.web.htmlwidgets import BoxLink, BoxWidget + + +class BlogPrimaryView(baseviews.PrimaryView): + accepts = ('Blog',) + skip_attrs = baseviews.PrimaryView.skip_attrs + ('title',) + + def render_entity_title(self, entity): + self.w(u'<h1>%s</h1>' % html_escape(entity.dc_title())) + + def render_entity_relations(self, entity, siderelations): + rset = entity.related('entry_of', 'object') + self.pagination(self.req, rset, self.w) + self.wview('list', rset, 'null', title='') + + +class BlogEntryPrimaryView(baseviews.PrimaryView): + accepts = ('BlogEntry',) + skip_attrs = baseviews.PrimaryView.skip_attrs + ('title',) + show_attr_label = False + + def render_entity_title(self, entity): + self.w(u'<h1>%s</h1>' % html_escape(entity.dc_title())) + + def content_format(self, entity): + return entity.view('reledit', rtype='content_format') + + +class BlogEntryArchiveBox(BoxTemplate): + """side box usually displaying some related entities in a primary view""" + id = 'blog_archives_box' + title = _('boxes_blog_archives_box') + order = 35 + + def call(self, **kwargs): + """display a list of entities by calling their <item_vid> view + """ + _ = self.req._ + rset = self.req.execute('Any CD ORDERBY CD DESC WHERE B is BlogEntry, B creation_date CD') + blogmonths = [] + for (blogdate,) in rset: + year, month = blogdate.year, blogdate.month + if (year, month) not in blogmonths: + blogmonths.append( (year, month) ) + box = BoxWidget(_(self.title), id=self.id) + for year, month in blogmonths: + firstday = DateTime(year, month, 1) + lastday = DateTime(year, month, firstday.days_in_month) + rql = ('Any B WHERE B is BlogEntry, B creation_date >= "%s", B creation_date <= "%s"' % + (firstday.strftime('%Y-%m-%d'), lastday.strftime('%Y-%m-%d'))) + label = u'%s %s' % (_(MONTHNAMES[month-1]), year) + vtitle = '%s %s' % (_('BlogEntry_plural'), label) + url = self.build_url(rql=rql, vtitle=vtitle) + box.append( BoxLink(url, label) ) + box.render(self.w) + + +class BlogEntryListBox(BoxTemplate): + """display a box with latest blogs and rss""" + id = 'blog_latest_box' + title = _('blog_latest_box') + __selectors__ = BoxTemplate.__selectors__ + visible = True # enabled by default + order = 34 + + def call(self, view=None, **kwargs): + box = BoxWidget(self.req._(self.title), self.id, islist=False) + rset = self.req.execute('Any X,T,CD ORDERBY CD DESC ' + 'WHERE X is BlogEntry, X title T, ' + 'X creation_date CD LIMIT 5') + if not rset: + return + # TODO - get the date between brakets after link + # empty string for title argument to deactivate auto-title + html = self.view('secondary', rset) + rqlst = rset.syntax_tree() + rqlst.set_limit(20) + rql = rqlst.as_string(kwargs=rset.args) # en gros... + url = self.build_url(vid='primary', rql=rql) + html += u'<p>[ <a href="%s">%s</a> ]</p>' % (html_escape(url), + self.req._(u'see more')) + rss_icon = self.req.external_resource('RSS_LOGO_16') + rss_url = self.build_url(vid='rss', rql=rql) + html += u'<p><a href="%s">%s <img src="%s" alt="%s"/></a></p>' % ( + html_escape(rss_url), self.req._(u'subscribe'), rss_icon, + self.req._('rss icon')) + box.append(BoxHtml(html)) + box.render(self.w) + + + +## list views ################################################################# + +class BlogEntryListView(baseviews.ListView): + accepts = ('BlogEntry',) + + def call(self, klass=None, title=None, **kwargs): + """display a list of entities by calling their <item_vid> view + """ + self.req.add_css('eblog_style.css') + if title is None and not 'vtitle' in self.req.form: + self.w(u'<h1>%s</h1>' % display_name(self.req, 'BlogEntry', form='plural')) + super(BlogEntryListView, self).call(klass='invisible', **kwargs) + + +class BlogEntryListItemView(baseviews.ListItemView): + accepts = ('BlogEntry',) + + def cell_call(self, row, col, vid=None): + entity = self.entity(row, col) + w = self.w + _ = self.req._ + w(u'<div class="post">') + w(u'<h1>%s</h1>' % entity.view('incontext')) + + w(u'%s ' % entity.postinfo_description()) + + creator = entity.creator + + if creator: + + _rql = 'Any X WHERE X is BlogEntry, X created_by Y, Y eid %s' % creator.eid + + url = self.build_url('view', rql=_rql) + w(u'%s <a href="%s">%s </a>' % (_('by'), html_escape(url), creator.dc_title())) + + w(u'<div class="entry">') + body = entity.printable_value('content', format='text/plain') + w(html_escape(text_cut(body, 30))) + if len(body) > 200: + self.w(u'<p><a href="%s">%s ...</a></p>' % (html_escape(entity.absolute_url()), + _('more'))) + w(u'</div>') + w(u'<p class="postmetadata">%s</p>' % entity.view('post-reldata')) + w(u'</div>') + + +class BlogEntryPostMetaData(EntityView): + id = 'post-reldata' + accepts = ('BlogEntry',) + + def cell_call(self, row, col): + _ = lambda ertype,form='': display_name(self.req, ertype, form) + w = self.w + entity = self.entity(row, col) + if 'comments' in self.schema and 'BlogEntry' in self.schema.rschema('comments').objects(): + count = self.req.execute('Any COUNT(C) WHERE C comments B, B eid %(x)s', + {'x': entity.eid}, 'x')[0][0] + url = html_escape(entity.absolute_url()) + if count: + w(u'<a href="%s">%s %s</a>' % (url, count, _('Comment', 'plural'))) + else: + w(u'%s %s' % (count, _('Comment'))) + if 'tags' in self.schema and 'BlogEntry' in self.schema.rschema('tags').objects(): + tag_rset = entity.related('tags', 'object') + if tag_rset: + w(u' | %s %s' % (_('tags', 'object'), self.view('csv', tag_rset)))