diff --git a/.hgtags b/.hgtags index e19a103bf18715ecfe0f8db5e40e75f79e5cf70f_LmhndGFncw==..b201437d2c20b97490153df78669eb17593827f5_LmhndGFncw== 100644 --- a/.hgtags +++ b/.hgtags @@ -14,3 +14,5 @@ 2d7395dcc266985522d49a94786d525d19a6e535 cubicweb-blog-debian-version-1.7.1-1 97d3cac5c4bc0e9b2fd8a09e4b728ef9bb100a2f cubicweb-blog-version-1.7.3 51ec7229996d86fd006712258ffe121b5205478b cubicweb-blog-debian-version-1.7.3-1 +67460215a89e547c9d388c47c50f9f43fae6758f cubicweb-blog-version-1.7.4 +fd1d9f3a0b928870eff77dd521d0e8dc2384bd6d cubicweb-blog-debian-version-1.7.4-1 diff --git a/README b/README new file mode 100644 index 0000000000000000000000000000000000000000..b201437d2c20b97490153df78669eb17593827f5_UkVBRE1F --- /dev/null +++ b/README @@ -0,0 +1,42 @@ +Summary +------- +The `blog` cube provides blogging functionnalities. It creates two entity types, +`Blog` and `BlogEntry`. There are related to each other by the relation +`BlogEntry entry_of Blog`. + +Usage +----- + +When a user submits a blog entry, it goes in a `draft` state until the blog +entry is published by an application managers. The blog entry will not be +visible until it reaches the `published` state. + +When a blog entry is submitted, an email notification is automatically sent +to all the users belonging to the `managers` group of the application. + +Specific boxes provided by this cube: + +- `BlogEntryArchiveBox`, displays a box with the total number of blog entries + submitted by month for the last twelve months. + +- `BlogEntryListBox`, displays a box with the latest five blog entries + published in your application as well as link to subscribe to a RSS feed. + +- `BlogEntrySummary`, displays a box with the list of users who submitted + blog entries and the total number of blog entries they submitted. + +This cube also provides some web services such as: + +- http://xx:xxxx/blogentries/YYYY to retrieve the blog entries submitted + during the year YYYY through a RSS feed + +- http://xx:xxxx/blogentries/YYYY/MM to retrieve the blog entries submitted + during the month MM of the year YYYY through a RSS feed + +- http://xx:xxxx/blog/[eid]/blogentries/YYYY to retrieve the blog entries + submitted in the blog of identifier [eid], during the year YYYY through + a RSS feed + +- http://xx:xxxx/blog/[eid]/blogentries/YYYY/MM to retrieve the blog entries + submitted in the blog of identifier [eid], during the month MM of the + year YYYY through a RSS feed diff --git a/__pkginfo__.py b/__pkginfo__.py index e19a103bf18715ecfe0f8db5e40e75f79e5cf70f_X19wa2dpbmZvX18ucHk=..b201437d2c20b97490153df78669eb17593827f5_X19wa2dpbmZvX18ucHk= 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -4,7 +4,7 @@ modname = 'blog' distname = "cubicweb-%s" % modname -numversion = (1, 7, 3) +numversion = (1, 7, 4) version = '.'.join(str(num) for num in numversion) license = 'LGPL' @@ -13,51 +13,8 @@ author_email = "contact@logilab.fr" web = 'http://www.cubicweb.org/project/%s' % distname -short_desc = "blogging component for the CubicWeb framework" -long_desc = """\ -Summary -------- -The `blog` cube provides blogging functionnalities. It creates two entity types, -`Blog` and `BlogEntry`. There are related to each other by the relation -`BlogEntry entry_of Blog`. - -Usage ------ - -When a user submits a blog entry, it goes in a `draft` state until the blog -entry is published by an application managers. The blog entry will not be -visible until it reaches the `published` state. - -When a blog entry is submitted, an email notification is automatically sent -to all the users belonging to the `managers` group of the application. - -Specific boxes provided by this cube: - -- `BlogEntryArchiveBox`, displays a box with the total number of blog entries - submitted by month for the last twelve months. - -- `BlogEntryListBox`, displays a box with the latest five blog entries - published in your application as well as link to subscribe to a RSS feed. - -- `BlogEntrySummary`, displays a box with the list of users who submitted - blog entries and the total number of blog entries they submitted. - -This cube also provides some web services such as: - -- http://xx:xxxx/blogentries/YYYY to retrieve the blog entries submitted - during the year YYYY through a RSS feed - -- http://xx:xxxx/blogentries/YYYY/MM to retrieve the blog entries submitted - during the month MM of the year YYYY through a RSS feed - -- http://xx:xxxx/blog/[eid]/blogentries/YYYY to retrieve the blog entries - submitted in the blog of identifier [eid], during the year YYYY through - a RSS feed - -- http://xx:xxxx/blog/[eid]/blogentries/YYYY/MM to retrieve the blog entries - submitted in the blog of identifier [eid], during the month MM of the - year YYYY through a RSS feed -""" +description = "blogging component for the CubicWeb framework" +short_desc = description # XXX cw < 3.8 bw compat classifiers = [ 'Environment :: Web Environment' @@ -66,5 +23,4 @@ 'Programming Language :: JavaScript', ] -__depends_cubes__ = {} __depends__ = {'cubicweb': '>= 3.7.3'} @@ -70,5 +26,10 @@ __depends__ = {'cubicweb': '>= 3.7.3'} -__use__ = tuple(__depends_cubes__) +__recommends_cubes__ = {'tag': None, + 'comment': '>= 1.6.3'} +__recommends__ = {} +for cube in __recommends_cubes__: + __recommends__['cubicweb-'+cube] = __recommends_cubes__[cube] + # package ### diff --git a/debian/changelog b/debian/changelog index e19a103bf18715ecfe0f8db5e40e75f79e5cf70f_ZGViaWFuL2NoYW5nZWxvZw==..b201437d2c20b97490153df78669eb17593827f5_ZGViaWFuL2NoYW5nZWxvZw== 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +cubicweb-blog (1.7.4-1) unstable; urgency=low + + * new upstream release + + -- Sylvain Thénault <sylvain.thenault@logilab.fr> Mon, 26 Apr 2010 15:22:14 +0200 + cubicweb-blog (1.7.3-1) unstable; urgency=low * new upstream release diff --git a/debian/control b/debian/control index e19a103bf18715ecfe0f8db5e40e75f79e5cf70f_ZGViaWFuL2NvbnRyb2w=..b201437d2c20b97490153df78669eb17593827f5_ZGViaWFuL2NvbnRyb2w= 100644 --- a/debian/control +++ b/debian/control @@ -10,6 +10,7 @@ Package: cubicweb-blog Architecture: all Depends: cubicweb-common (>= 3.7.3) +Suggests: cubicweb-comment (>= 1.6.3), cubicweb-tag Description: blog component for the CubicWeb framework This CubicWeb component provides blogging functionnalities. . diff --git a/debian/rules b/debian/rules index e19a103bf18715ecfe0f8db5e40e75f79e5cf70f_ZGViaWFuL3J1bGVz..b201437d2c20b97490153df78669eb17593827f5_ZGViaWFuL3J1bGVz 100755 --- a/debian/rules +++ b/debian/rules @@ -7,7 +7,7 @@ build: build-stamp build-stamp: dh_testdir - python setup.py -q build + NO_SETUPTOOLS=1 python setup.py -q build touch build-stamp clean: @@ -24,7 +24,7 @@ dh_testroot dh_clean -k dh_installdirs -i - python setup.py -q install --no-compile --prefix=debian/cubicweb-blog/usr/ + NO_SETUPTOOLS=1 python setup.py -q install --no-compile --prefix=debian/cubicweb-blog/usr/ rm -rf debian/cubicweb-blog/usr/lib/python* diff --git a/i18n/en.po b/i18n/en.po index e19a103bf18715ecfe0f8db5e40e75f79e5cf70f_aTE4bi9lbi5wbw==..b201437d2c20b97490153df78669eb17593827f5_aTE4bi9lbi5wbw== 100644 --- a/i18n/en.po +++ b/i18n/en.po @@ -52,9 +52,6 @@ msgid "blog's rss url (useful for when using external site such as feedburner)" msgstr "" -msgid "blog_latest_box" -msgstr "latest blogs" - msgid "blogged in " msgstr "" @@ -67,7 +64,15 @@ 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" +msgid "boxes_blog_summary_box" +msgstr "posts by author" + +msgid "boxes_blog_summary_box_description" +msgstr "" +"this box contains a list of authors with the number of blog entries they " +"posted" + +msgid "boxes_latest_blogs_box" +msgstr "latest blogs" # add related box generated message @@ -72,13 +77,7 @@ # add related box generated message -msgid "boxes_blog_latest_box_description" -msgstr "this box contains the latest posts" - -msgid "boxes_blog_summary_box" -msgstr "Posts by author" - -msgid "boxes_blog_summary_box_description" -msgstr "this box contains a list of authors with the number of posts" +msgid "boxes_latest_blogs_box_description" +msgstr "this box contains the latest blog entries posted" msgid "by" msgstr "by" @@ -97,6 +96,12 @@ msgctxt "BlogEntry" msgid "content_format" +msgstr "format" + +msgid "contentnavigation_blogsubscribe" +msgstr "blog subscribtion icon" + +msgid "contentnavigation_blogsubscribe_description" msgstr "" msgid "creating BlogEntry (BlogEntry entry_of Blog %(linkto)s)" @@ -111,7 +116,7 @@ msgctxt "Blog" msgid "description_format" -msgstr "" +msgstr "format" msgid "draft" msgstr "" @@ -123,7 +128,7 @@ msgctxt "BlogEntry" msgid "entry_of" -msgstr "" +msgstr "blog entry of" msgctxt "Blog" msgid "entry_of_object" @@ -127,6 +132,6 @@ msgctxt "Blog" msgid "entry_of_object" -msgstr "" +msgstr "posts" msgid "entry_of_object" @@ -131,6 +136,12 @@ msgid "entry_of_object" -msgstr "contains" +msgstr "posts" + +msgid "latest_blogs_blog_box" +msgstr "latest blogs" + +msgid "latest_blogs_box" +msgstr "latest blogs" msgid "next month" msgstr "" @@ -155,8 +166,8 @@ msgctxt "Blog" msgid "rss_url" -msgstr "" +msgstr "rss feed url" msgid "see more" msgstr "see more" @@ -159,7 +170,10 @@ msgid "see more" msgstr "see more" +msgid "see more archives" +msgstr "" + msgid "subscribe" msgstr "subscribe" @@ -163,6 +177,9 @@ msgid "subscribe" msgstr "subscribe" +msgid "subscribe to this blog" +msgstr "" + msgid "tags" msgstr "tags" @@ -173,18 +190,3 @@ msgctxt "BlogEntry" msgid "title" msgstr "" - -#~ msgid "add a Blog" -#~ msgstr "add a blog" - -#~ msgid "add a BlogEntry" -#~ msgstr "add a blog entry" - -#~ msgid "more" -#~ msgstr "more" - -#~ msgid "remove this Blog" -#~ msgstr "remove this blog" - -#~ msgid "remove this BlogEntry" -#~ msgstr "remove this blog entry" diff --git a/i18n/es.po b/i18n/es.po index e19a103bf18715ecfe0f8db5e40e75f79e5cf70f_aTE4bi9lcy5wbw==..b201437d2c20b97490153df78669eb17593827f5_aTE4bi9lcy5wbw== 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -51,9 +51,6 @@ msgid "blog's rss url (useful for when using external site such as feedburner)" msgstr "" -msgid "blog_latest_box" -msgstr "últimos blogs" - msgid "blogged in " msgstr "" @@ -63,15 +60,9 @@ msgid "boxes_blog_archives_box_description" msgstr "espacio hacia los archivos del blog en meses anteriores" -msgid "boxes_blog_latest_box" -msgstr "último" - -msgid "boxes_blog_latest_box_description" -msgstr "espacio que contiene la lista de los últimos blogs" - msgid "boxes_blog_summary_box" msgstr "" msgid "boxes_blog_summary_box_description" msgstr "" @@ -72,9 +63,15 @@ msgid "boxes_blog_summary_box" msgstr "" msgid "boxes_blog_summary_box_description" msgstr "" +msgid "boxes_latest_blogs_box" +msgstr "último" + +msgid "boxes_latest_blogs_box_description" +msgstr "espacio que contiene la lista de los últimos blogs" + msgid "by" msgstr "por" @@ -94,6 +91,12 @@ msgid "content_format" msgstr "" +msgid "contentnavigation_blogsubscribe" +msgstr "" + +msgid "contentnavigation_blogsubscribe_description" +msgstr "" + msgid "creating BlogEntry (BlogEntry entry_of Blog %(linkto)s)" msgstr "creación de una entrada de blog %(linkto)s" @@ -127,6 +130,12 @@ msgid "entry_of_object" msgstr "contiene las entradas" +msgid "latest_blogs_blog_box" +msgstr "" + +msgid "latest_blogs_box" +msgstr "últimos blogs" + msgid "next month" msgstr "" @@ -155,6 +164,9 @@ msgid "see more" msgstr "ver más" +msgid "see more archives" +msgstr "" + msgid "subscribe" msgstr "suscribirse" @@ -158,6 +170,9 @@ msgid "subscribe" msgstr "suscribirse" +msgid "subscribe to this blog" +msgstr "" + msgid "tags" msgstr "palabras clave" diff --git a/i18n/fr.po b/i18n/fr.po index e19a103bf18715ecfe0f8db5e40e75f79e5cf70f_aTE4bi9mci5wbw==..b201437d2c20b97490153df78669eb17593827f5_aTE4bi9mci5wbw== 100644 --- a/i18n/fr.po +++ b/i18n/fr.po @@ -33,7 +33,7 @@ msgstr "Nouveau blog" msgid "New BlogEntry" -msgstr "Nouveau billet" +msgstr "Nouveau billet" msgid "This Blog" msgstr "Ce blog" @@ -47,10 +47,10 @@ #, python-format msgid "blog entries created by %s" -msgstr "" +msgstr "billets créés par %s" msgid "blog's rss url (useful for when using external site such as feedburner)" msgstr "" "url du flux rss du blog (peut être utile lorsque l'on utilise un service tel " "que feedburner)" @@ -51,13 +51,10 @@ msgid "blog's rss url (useful for when using external site such as feedburner)" msgstr "" "url du flux rss du blog (peut être utile lorsque l'on utilise un service tel " "que feedburner)" -msgid "blog_latest_box" -msgstr "derniers blogs" - msgid "blogged in " msgstr "bloggué dans " msgid "boxes_blog_archives_box" @@ -60,8 +57,8 @@ msgid "blogged in " msgstr "bloggué dans " msgid "boxes_blog_archives_box" -msgstr "boîte d'archive des blogs" +msgstr "archive des blogs" # subject and object forms for each relation type # (no object form for final relation types) @@ -69,7 +66,13 @@ 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" +msgid "boxes_blog_summary_box" +msgstr "billets par auteur" + +msgid "boxes_blog_summary_box_description" +msgstr "boîte contenant la liste des auteurs et le nombre de billets" + +msgid "boxes_latest_blogs_box" +msgstr "derniers billets" # add related box generated message @@ -74,13 +77,7 @@ # add related box generated message -msgid "boxes_blog_latest_box_description" -msgstr "boîte contentant la liste des derniers blogs" - -msgid "boxes_blog_summary_box" -msgstr "blogs par auteur" - -msgid "boxes_blog_summary_box_description" -msgstr "boîte contenant la liste des auteurs et le nombre de blogs" +msgid "boxes_latest_blogs_box_description" +msgstr "boîte contentant la liste des derniers billets postés" msgid "by" msgstr "par" @@ -88,7 +85,7 @@ # subject and object forms for each relation type # (no object form for final relation types) msgid "content" -msgstr "" +msgstr "contenu" msgctxt "BlogEntry" msgid "content" @@ -92,6 +89,6 @@ msgctxt "BlogEntry" msgid "content" -msgstr "" +msgstr "contenu" msgid "content_format" @@ -96,6 +93,6 @@ msgid "content_format" -msgstr "" +msgstr "format" msgctxt "BlogEntry" msgid "content_format" @@ -99,9 +96,15 @@ msgctxt "BlogEntry" msgid "content_format" -msgstr "" +msgstr "format" + +msgid "contentnavigation_blogsubscribe" +msgstr "souscrire au blog" + +msgid "contentnavigation_blogsubscribe_description" +msgstr "icône permettant de souscrire à un blog" msgid "creating BlogEntry (BlogEntry entry_of Blog %(linkto)s)" msgstr "création d'un billet dans le blog %(linkto)s" msgid "default BlogEntry workflow" @@ -103,9 +106,9 @@ msgid "creating BlogEntry (BlogEntry entry_of Blog %(linkto)s)" msgstr "création d'un billet dans le blog %(linkto)s" msgid "default BlogEntry workflow" -msgstr "" +msgstr "workflow des billets par défaut" msgctxt "Blog" msgid "description" @@ -109,7 +112,7 @@ msgctxt "Blog" msgid "description" -msgstr "" +msgstr "description" msgctxt "Blog" msgid "description_format" @@ -113,7 +116,7 @@ msgctxt "Blog" msgid "description_format" -msgstr "" +msgstr "format" msgid "draft" msgstr "brouillon" @@ -125,7 +128,7 @@ msgctxt "BlogEntry" msgid "entry_of" -msgstr "" +msgstr "dans le blog" msgctxt "Blog" msgid "entry_of_object" @@ -129,6 +132,6 @@ msgctxt "Blog" msgid "entry_of_object" -msgstr "" +msgstr "billets" msgid "entry_of_object" @@ -133,6 +136,12 @@ msgid "entry_of_object" -msgstr "contient les entrées" +msgstr "billets" + +msgid "latest_blogs_blog_box" +msgstr "derniers billets dans ce blog" + +msgid "latest_blogs_box" +msgstr "derniers billets" msgid "next month" msgstr "mois suivant" @@ -157,8 +166,8 @@ msgctxt "Blog" msgid "rss_url" -msgstr "" +msgstr "url du flux RSS" msgid "see more" msgstr "voir plus" @@ -161,7 +170,10 @@ msgid "see more" msgstr "voir plus" +msgid "see more archives" +msgstr "voir plus d'archives" + msgid "subscribe" msgstr "souscrire" @@ -165,8 +177,11 @@ msgid "subscribe" msgstr "souscrire" +msgid "subscribe to this blog" +msgstr "souscrire à ce blog" + msgid "tags" msgstr "étiquettes" msgctxt "Blog" msgid "title" @@ -168,9 +183,9 @@ msgid "tags" msgstr "étiquettes" msgctxt "Blog" msgid "title" -msgstr "" +msgstr "titre" msgctxt "BlogEntry" msgid "title" @@ -174,19 +189,4 @@ msgctxt "BlogEntry" msgid "title" -msgstr "" - -#~ msgid "add a Blog" -#~ msgstr "ajouter un blog" - -#~ msgid "add a BlogEntry" -#~ msgstr "ajouter un billet" - -#~ msgid "blog entries created by %s %s" -#~ msgstr "billets créés par %s %s" - -#~ msgid "remove this Blog" -#~ msgstr "supprimer ce blog" - -#~ msgid "remove this BlogEntry" -#~ msgstr "supprimer cette entrée de blog" +msgstr "titre" diff --git a/setup.py b/setup.py index e19a103bf18715ecfe0f8db5e40e75f79e5cf70f_c2V0dXAucHk=..b201437d2c20b97490153df78669eb17593827f5_c2V0dXAucHk= 100644 --- a/setup.py +++ b/setup.py @@ -1,19 +1,15 @@ #!/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 """ +"""Generic Setup script, takes package info from __pkginfo__.py file. + +:copyright: 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses +""" +__docformat__ = "restructuredtext en" + +import os +import sys +import shutil +from os.path import isdir, exists, join, walk @@ -19,3 +15,12 @@ -from distutils.core import setup +try: + if os.environ.get('NO_SETUPTOOLS'): + raise ImportError() + from setuptools import setup + from setuptools.command import install_lib + USE_SETUPTOOLS = 1 +except ImportError: + from distutils.core import setup + from distutils.command import install_lib + USE_SETUPTOOLS = 0 @@ -21,2 +26,4 @@ + +sys.modules.pop('__pkginfo__', None) # import required features @@ -22,4 +29,4 @@ # import required features -from __pkginfo__ import distname, version, license, short_desc, long_desc, \ +from __pkginfo__ import modname, version, license, description, \ web, author, author_email # import optional features @@ -24,13 +31,111 @@ web, author, author_email # import optional features -try: - from __pkginfo__ import data_files -except ImportError: - data_files = None -try: - from __pkginfo__ import include_dirs -except ImportError: - include_dirs = [] +import __pkginfo__ +distname = getattr(__pkginfo__, 'distname', modname) +scripts = getattr(__pkginfo__, 'scripts', []) +data_files = getattr(__pkginfo__, 'data_files', None) +include_dirs = getattr(__pkginfo__, 'include_dirs', []) +ext_modules = getattr(__pkginfo__, 'ext_modules', None) +dependency_links = getattr(__pkginfo__, 'dependency_links', []) + +STD_BLACKLIST = ('CVS', '.svn', '.hg', 'debian', 'dist', 'build') + +IGNORED_EXTENSIONS = ('.pyc', '.pyo', '.elc', '~') + +if exists('README'): + long_description = file('README').read() +else: + long_description = '' +if USE_SETUPTOOLS: + requires = {} + for entry in ("__depends__", "__recommends__"): + requires.update(getattr(__pkginfo__, entry, {})) + install_requires = [("%s %s" % (d, v and v or "")).strip() + for d, v in requires.iteritems()] +else: + install_requires = [] + + +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 get_packages(directory, prefix): + """return a list of subpackages for the given directory""" + result = [] + for package in os.listdir(directory): + absfile = join(directory, package) + if isdir(absfile): + if exists(join(absfile, '__init__.py')) or \ + package in ('test', 'tests'): + if prefix: + result.append('%s.%s' % (prefix, package)) + else: + result.append(package) + result += get_packages(absfile, result[-1]) + return result + +def export(from_dir, to_dir, + blacklist=STD_BLACKLIST, + ignore_ext=IGNORED_EXTENSIONS, + verbose=True): + """make a mirror of from_dir in to_dir, omitting directories and files + listed in the black list + """ + def make_mirror(arg, directory, fnames): + """walk handler""" + for norecurs in blacklist: + try: + fnames.remove(norecurs) + except ValueError: + pass + for filename in fnames: + # don't include binary files + if filename[-4:] in ignore_ext: + continue + if filename[-1] == '~': + continue + src = join(directory, filename) + dest = to_dir + src[len(from_dir):] + if verbose: + print >> sys.stderr, src, '->', dest + if os.path.isdir(src): + if not exists(dest): + os.mkdir(dest) + else: + if exists(dest): + os.remove(dest) + shutil.copy2(src, dest) + try: + os.mkdir(to_dir) + except OSError, ex: + # file exists ? + import errno + if ex.errno != errno.EEXIST: + raise + walk(from_dir, make_mirror, None) + + +class MyInstallLib(install_lib.install_lib): + """extend install_lib command to handle package __init__.py and + include_dirs variable if necessary + """ + def run(self): + """overridden from install_lib class""" + install_lib.install_lib.run(self) + # manually install included directories if any + if include_dirs: + base = modname + for directory in include_dirs: + dest = join(self.install_dir, base, directory) + export(directory, dest, verbose=False) def install(**kwargs): """setup entry point""" @@ -34,17 +139,32 @@ 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, - data_files=data_files, - **kwargs) - + if USE_SETUPTOOLS: + if '--force-manifest' in sys.argv: + sys.argv.remove('--force-manifest') + # install-layout option was introduced in 2.5.3-1~exp1 + elif sys.version_info < (2, 5, 4) and '--install-layout=deb' in sys.argv: + sys.argv.remove('--install-layout=deb') + kwargs['package_dir'] = {modname : '.'} + packages = [modname] + get_packages(os.getcwd(), modname) + if USE_SETUPTOOLS and install_requires: + kwargs['install_requires'] = install_requires + kwargs['dependency_links'] = dependency_links + kwargs['packages'] = packages + return setup(name = distname, + version = version, + license = license, + description = description, + long_description = long_description, + author = author, + author_email = author_email, + url = web, + scripts = ensure_scripts(scripts), + data_files = data_files, + ext_modules = ext_modules, + cmdclass = {'install_lib': MyInstallLib}, + **kwargs + ) + if __name__ == '__main__' : install() diff --git a/views/boxes.py b/views/boxes.py new file mode 100644 index 0000000000000000000000000000000000000000..b201437d2c20b97490153df78669eb17593827f5_dmlld3MvYm94ZXMucHk= --- /dev/null +++ b/views/boxes.py @@ -0,0 +1,101 @@ +"""Various blog boxes: archive, per author, etc... + +:organization: Logilab +:copyright: 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +""" +__docformat__ = "restructuredtext en" +_ = unicode + +from logilab.mtconverter import xml_escape + +from cubicweb.selectors import one_line_rset, implements +from cubicweb.web.htmlwidgets import BoxLink, BoxWidget +from cubicweb.web.views import boxes + +class BlogArchivesBox(boxes.BoxTemplate): + """blog side box displaying a Blog Archive""" + __regid__ = 'blog_archives_box' + title = _('boxes_blog_archives_box') + order = 35 + + def call(self, **kwargs): + """display blogs archive""" + # XXX turn into a selector + count_blogentry = self._cw.execute('Any COUNT(B) WHERE B is BlogEntry') + if count_blogentry[0][0] > 0: + box = BoxWidget(self._cw._(self.title), id=self.__regid__, islist=False) + box.append(boxes.BoxHtml(self._cw.view('blog_archive', None, maxentries=12))) + box.render(self.w) + + +class BlogsByAuthorBox(boxes.BoxTemplate): + __regid__ = 'blog_summary_box' + title = _('boxes_blog_summary_box') + order = 36 + + def call(self, view=None, **kwargs): + box = BoxWidget(self._cw._(self.title), self.__regid__, islist=True) + rql = 'Any U, COUNT(B) GROUPBY U WHERE U is CWUser, ' \ + 'B is BlogEntry, B created_by U' + rset = self._cw.execute(rql) + for user in rset: + euser = self._cw.entity_from_eid(user[0]) + box.append(BoxLink(self._cw.build_url('blogentry/%s' % euser.login), + u'%s [%s]' % (euser.name(), + user[1]))) + box.render(self.w) + + +class LatestBlogsBox(boxes.BoxTemplate): + """display a box with latest blogs and rss""" + __regid__ = 'latest_blogs_box' + title = _('latest_blogs_box') + visible = True # enabled by default + order = 34 + display_see_more_link = True + + def latest_blogs_rset(self): + return self._cw.execute( + 'Any X,T,CD ORDERBY CD DESC LIMIT 5 WHERE X is BlogEntry, ' + 'X title T, X creation_date CD') + + def call(self, **kwargs): + # XXX turn into a selector + rset = self.latest_blogs_rset() + if not rset: + return + box = BoxWidget(self._cw._(self.title), self.__regid__, islist=True) + # TODO - get the date between brakets after link + # empty string for title argument to deactivate auto-title + for i in xrange(rset.rowcount): + entity = rset.get_entity(i, 0) + box.append(BoxLink(entity.absolute_url(), xml_escape(entity.dc_title()))) + rqlst = rset.syntax_tree() + rqlst.set_limit(None) + rql = rqlst.as_string(kwargs=rset.args) + if self.display_see_more_link: + url = self._cw.build_url('view', rql=rql, page_size=10) + box.append(BoxLink(url, u'[%s]' % self._cw._(u'see more'))) + rss_icon = self._cw.external_resource('RSS_LOGO_16') + # FIXME - could use rss_url defined as a property if available + rss_label = u'%s <img src="%s" alt="%s"/>' % ( + self._cw._(u'subscribe'), rss_icon, self._cw._('rss icon')) + rss_url = self._cw.build_url('view', vid='rss', rql=rql) + box.append(BoxLink(rss_url, rss_label)) + box.render(self.w) + + +class LatestBlogsBlogBox(LatestBlogsBox): + """display a box with latest blogs and rss, filtered for a particular blog + """ + __select__ = LatestBlogsBox.__select__ & one_line_rset() & implements('Blog') + title = _('latest_blogs_blog_box') + display_see_more_link = False + + def latest_blogs_rset(self): + blog = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) + return self._cw.execute( + 'Any X,T,CD ORDERBY CD DESC LIMIT 5 WHERE X is BlogEntry, ' + 'X title T, X creation_date CD, X entry_of B, B eid %(b)s', + {'b': blog.eid}) diff --git a/views/primary.py b/views/primary.py index e19a103bf18715ecfe0f8db5e40e75f79e5cf70f_dmlld3MvcHJpbWFyeS5weQ==..b201437d2c20b97490153df78669eb17593827f5_dmlld3MvcHJpbWFyeS5weQ== 100644 --- a/views/primary.py +++ b/views/primary.py @@ -6,8 +6,7 @@ """ __docformat__ = "restructuredtext en" - from logilab.mtconverter import xml_escape from cubicweb.utils import UStringIO from cubicweb.selectors import implements @@ -10,7 +9,7 @@ from logilab.mtconverter import xml_escape from cubicweb.utils import UStringIO from cubicweb.selectors import implements -from cubicweb.web import uicfg -from cubicweb.web.views import primary +from cubicweb.web import uicfg, component +from cubicweb.web.views import primary, workflow @@ -16,8 +15,8 @@ -uicfg.primaryview_section.tag_attribute(('Blog', 'title'), 'hidden') -uicfg.primaryview_section.tag_attribute(('Blog', 'rss_url'), 'hidden') -uicfg.primaryview_section.tag_attribute(('BlogEntry', 'title'), 'hidden') -uicfg.primaryview_section.tag_object_of(('*', 'entry_of', 'Blog'), 'hidden') -uicfg.primaryview_section.tag_subject_of(('BlogEntry', 'entry_of', '*'), - 'relations') +_pvs = uicfg.primaryview_section +_pvs.tag_attribute(('Blog', 'title'), 'hidden') +_pvs.tag_attribute(('Blog', 'rss_url'), 'hidden') +_pvs.tag_attribute(('BlogEntry', 'title'), 'hidden') +_pvs.tag_object_of(('*', 'entry_of', 'Blog'), 'hidden') +_pvs.tag_subject_of(('BlogEntry', 'entry_of', '*'), 'relations') @@ -23,7 +22,14 @@ -uicfg.actionbox_appearsin_addmenu.tag_object_of(('*', 'entry_of', 'Blog'), True) +_pvdc = uicfg.primaryview_display_ctrl +_pvdc.tag_attribute(('Blog', 'description'), {'showlabel': False}) + +_abaa = uicfg.actionbox_appearsin_addmenu +_abaa.tag_object_of(('*', 'entry_of', 'Blog'), True) + +_afs = uicfg.autoform_section +_afs.tag_subject_of(('BlogEntry', 'entry_of', 'Blog'), 'main', 'attributes') class BlogPrimaryView(primary.PrimaryView): __select__ = implements('Blog') @@ -25,17 +31,11 @@ class BlogPrimaryView(primary.PrimaryView): __select__ = implements('Blog') - def render_entity_attributes(self, entity): - super(BlogPrimaryView, self).render_entity_attributes(entity) - self.w('<a class="right" href="%s">%s <img src="%s" alt="%s"/></a>' % ( - xml_escape(entity.rss_feed_url()), self._cw._(u'subscribe'), - self._cw.external_resource('RSS_LOGO_16'), self._cw._('rss icon'))) - def render_entity_relations(self, entity): super(BlogPrimaryView, self).render_entity_relations(entity) rset = entity.related('entry_of', 'object') if rset: strio = UStringIO() self.paginate(self._cw, w=strio.write, page_size=10, rset=rset) @@ -36,9 +36,10 @@ def render_entity_relations(self, entity): super(BlogPrimaryView, self).render_entity_relations(entity) rset = entity.related('entry_of', 'object') if rset: strio = UStringIO() self.paginate(self._cw, w=strio.write, page_size=10, rset=rset) - self.wview('sameetypelist', rset) + self.w(strio.getvalue()) + self.wview('sameetypelist', rset, showtitle=False) self.w(strio.getvalue()) @@ -43,10 +44,20 @@ self.w(strio.getvalue()) - def render_entity_title(self, entity): - self.w(u'<h1>%s</h1>' % xml_escape(entity.dc_title())) + +class SubscribeToBlogComponent(component.EntityVComponent): + __regid__ = 'blogsubscribe' + __select__ = component.EntityVComponent.__select__ & implements('Blog') + context = 'ctxtoolbar' + + def cell_call(self, row, col, view): + entity = self.cw_rset.get_entity(row, col) + self.w('<a href="%s"><img src="%s" alt="%s"/></a>' % ( + xml_escape(entity.rss_feed_url()), + self._cw.external_resource('RSS_LOGO_16'), + self._cw._(u'subscribe to this blog'))) class BlogEntryPrimaryView(primary.PrimaryView): __select__ = implements('BlogEntry') show_attr_label = False @@ -47,14 +58,11 @@ class BlogEntryPrimaryView(primary.PrimaryView): __select__ = implements('BlogEntry') show_attr_label = False - def render_entity_title(self, entity): - self.w(u'<h1>%s</h1>' % xml_escape(entity.dc_title())) - def render_entity_relations(self, entity): rset = entity.related('entry_of', 'subject') if rset: self.w(self._cw._('blogged in ')) self.wview('csv', rset, 'null') @@ -56,5 +64,13 @@ def render_entity_relations(self, entity): rset = entity.related('entry_of', 'subject') if rset: self.w(self._cw._('blogged in ')) self.wview('csv', rset, 'null') + + +# don't show workflow history for blog entry +class BlogEntryWFHistoryVComponent(workflow.WFHistoryVComponent): + __select__ = workflow.WFHistoryVComponent.__select__ & implements('BlogEntry') + + def cell_call(self, row, col, view=None): + pass diff --git a/views/secondary.py b/views/secondary.py index e19a103bf18715ecfe0f8db5e40e75f79e5cf70f_dmlld3Mvc2Vjb25kYXJ5LnB5..b201437d2c20b97490153df78669eb17593827f5_dmlld3Mvc2Vjb25kYXJ5LnB5 100644 --- a/views/secondary.py +++ b/views/secondary.py @@ -13,10 +13,8 @@ from cubicweb.schema import display_name from cubicweb.view import EntityView, StartupView -from cubicweb.selectors import paginated_rset, sorted_rset, implements, \ - authenticated_user -from cubicweb.web.htmlwidgets import BoxLink, BoxWidget -from cubicweb.web.views import baseviews, boxes, calendar, navigation, workflow +from cubicweb.selectors import paginated_rset, sorted_rset, implements +from cubicweb.web.views import baseviews, calendar, navigation class BlogEntryArchiveView(StartupView): """control the view of a blog archive""" @@ -36,10 +34,11 @@ label = u'%s %s [%s]' % (self._cw._(calendar.MONTHNAMES[month-1]), year, nmb_entries) vtitle = '%s %s' % (display_name(self._cw, 'BlogEntry', 'plural'), label) - url = xml_escape(self._cw.build_url('view', rql=rql, month=month, year=year, vtitle=vtitle)) + url = xml_escape(self._cw.build_url('view', rql=rql, month=month, + year=year, vtitle=vtitle)) link = u'<a href="%s" title="">%s</a>' % (url, label) items.append( u'<li class="">%s</li>\n' % link ) def call(self, maxentries=None, **kwargs): """display a list of entities by calling their <item_vid> view """ @@ -40,11 +39,11 @@ link = u'<a href="%s" title="">%s</a>' % (url, label) items.append( u'<li class="">%s</li>\n' % link ) def call(self, maxentries=None, **kwargs): """display a list of entities by calling their <item_vid> view """ - rset = self._cw.execute('Any CD ORDERBY CD DESC WHERE B is BlogEntry, B creation_date CD') - + rset = self._cw.execute('Any CD ORDERBY CD DESC WHERE B is BlogEntry, ' + 'B creation_date CD') blogmonths = [] items = [] for (blogdate,) in rset: @@ -61,7 +60,8 @@ self.represent(items, year, month) if needmore: url = self._cw.build_url('view', vid='blog_archive') - link = u'<a href="%s" title="">[%s]</a>' % (url, self._cw._('see more archives')) + link = u'<a href="%s" title="">[%s]</a>' % ( + url, self._cw._('see more archives')) items.append( u'<li class="">%s</li>\n' % link ) self.w(u'<div class="boxFrame">') if items: @@ -72,75 +72,5 @@ self.w(u'</div>') -class BlogEntryArchiveBox(boxes.BoxTemplate): - """blog side box displaying a Blog Archive""" - __regid__ = 'blog_archives_box' - title = _('boxes_blog_archives_box') - order = 35 - - def call(self, **kwargs): - """display blogs archive""" - # XXX turn into a selector - count_blogentry = self._cw.execute('Any COUNT(B) WHERE B is BlogEntry') - if count_blogentry[0][0] > 0: - box = BoxWidget(self._cw._(self.title), id=self.__regid__, islist=False) - box.append(boxes.BoxHtml(self._cw.view('blog_archive', None, maxentries=12))) - box.render(self.w) - - -class BlogEntryListBox(boxes.BoxTemplate): - """display a box with latest blogs and rss""" - __regid__ = 'blog_latest_box' - title = _('blog_latest_box') - visible = True # enabled by default - order = 34 - - def call(self, view=None, **kwargs): - # XXX turn into a selector - rset = self._cw.execute('Any X,T,CD ORDERBY CD DESC LIMIT 5 ' - 'WHERE X is BlogEntry, X title T, ' - 'X creation_date CD') - if not rset: - return - box = BoxWidget(self._cw._(self.title), self.__regid__, islist=True) - # TODO - get the date between brakets after link - # empty string for title argument to deactivate auto-title - for i in xrange(rset.rowcount): - entity = rset.get_entity(i, 0) - box.append(BoxLink(entity.absolute_url(), xml_escape(entity.dc_title()))) - rqlst = rset.syntax_tree() - rqlst.set_limit(None) - rql = rqlst.as_string(kwargs=rset.args) - url = self._cw.build_url('view', rql=rql, page_size=10) - box.append(BoxLink(url, u'[%s]' % self._cw._(u'see more'))) - rss_icon = self._cw.external_resource('RSS_LOGO_16') - # FIXME - could use rss_url defined as a property if available - rss_label = u'%s <img src="%s" alt="%s"/>' % ( - self._cw._(u'subscribe'), rss_icon, self._cw._('rss icon')) - rss_url = self._cw.build_url('view', vid='rss', rql=rql) - box.append(BoxLink(rss_url, rss_label)) - box.render(self.w) - - -class BlogEntrySummary(boxes.BoxTemplate): - __regid__ = 'blog_summary_box' - title = _('boxes_blog_summary_box') - order = 36 - __select__ = boxes.BoxTemplate.__select__ - - def call(self, view=None, **kwargs): - box = BoxWidget(self._cw._(self.title), self.__regid__, islist=True) - rql = 'Any U, COUNT(B) GROUPBY U WHERE U is CWUser, ' \ - 'B is BlogEntry, B created_by U' - rset = self._cw.execute(rql) - for user in rset: - euser = self._cw.entity_from_eid(user[0]) - box.append(BoxLink(self._cw.build_url('blogentry/%s' % euser.login), - u'%s [%s]' % (euser.name(), - user[1]))) - box.render(self.w) - -## list views ################################################################## - class BlogEntrySameETypeListView(baseviews.SameETypeListView): __select__ = baseviews.SameETypeListView.__select__ & implements('BlogEntry') @@ -145,6 +75,7 @@ class BlogEntrySameETypeListView(baseviews.SameETypeListView): __select__ = baseviews.SameETypeListView.__select__ & implements('BlogEntry') - countrql = 'Any COUNT(B) WHERE B is BlogEntry, B creation_date >= %(firstday)s, B creation_date <= %(lastday)s' + countrql = ('Any COUNT(B) WHERE B is BlogEntry, ' + 'B creation_date >= %(firstday)s, B creation_date <= %(lastday)s') item_vid = 'blog' def call(self, **kwargs): @@ -164,7 +95,6 @@ year = year - 1 else: previousmonth = month -1 - self.w(u'<div class="prevnext">') self.w(u'<span class="previousmonth">%s</span>' \ % self.render_link(year, previousmonth, @@ -177,5 +107,9 @@ def render_link(self, year, month, atitle): firstday = datetime(year, month, 1) lastday = datetime(year, month, monthrange(year, month)[1]) + args = {'firstday': firstday, 'lastday': lastday} + nmb_entries = self._cw.execute(self.countrql, args)[0][0] + if not nmb_entries: + return rql = ('Any B, BD ORDERBY BD DESC ' 'WHERE B is BlogEntry, B creation_date BD, ' @@ -180,4 +114,4 @@ rql = ('Any B, BD ORDERBY BD DESC ' 'WHERE B is BlogEntry, B creation_date BD, ' - 'B creation_date >= "%s", B creation_date <= "%s"' % + 'B creation_date >= "%s", B creation_date <= "%s"' % (firstday.strftime('%Y-%m-%d'), lastday.strftime('%Y-%m-%d'))) @@ -183,6 +117,4 @@ (firstday.strftime('%Y-%m-%d'), lastday.strftime('%Y-%m-%d'))) - args = {'firstday':firstday, 'lastday':lastday} - nmb_entries = self._cw.execute(self.countrql, args)[0][0] label = u'%s %s [%s]' % (self._cw._(calendar.MONTHNAMES[month-1]), year, nmb_entries) vtitle = '%s %s' % (display_name(self._cw, 'BlogEntry', 'plural'), label) @@ -186,14 +118,12 @@ label = u'%s %s [%s]' % (self._cw._(calendar.MONTHNAMES[month-1]), year, nmb_entries) vtitle = '%s %s' % (display_name(self._cw, 'BlogEntry', 'plural'), label) - url = xml_escape(self._cw.build_url('view', rql=rql, vtitle=vtitle, - month=month, year=year)) - if self._cw.execute(rql): - return u'<a href="%s" title="">%s</a>' % (url, atitle) - return u'' + url = self._cw.build_url('view', rql=rql, vtitle=vtitle, + month=month, year=year) + return u'<a href="%s">%s</a>' % (xml_escape(url), atitle) class BlogEntryBlogView(EntityView): __regid__ = 'blog' __select__ = implements('BlogEntry') @@ -194,10 +124,10 @@ class BlogEntryBlogView(EntityView): __regid__ = 'blog' __select__ = implements('BlogEntry') - def cell_call(self, row, col): + def cell_call(self, row, col, **kwargs): entity = self.cw_rset.get_entity(row, col) w = self.w _ = self._cw._ @@ -231,9 +161,10 @@ _ = lambda ertype, form='': display_name(self._cw, ertype, form) reldata = [] w = reldata.append - if 'comments' in self._cw.vreg.schema and \ - 'BlogEntry' in self._cw.vreg.schema.rschema('comments').objects(): - count = self._cw.execute('Any COUNT(C) WHERE C comments B, B eid %(x)s', - {'x': entity.eid}, 'x')[0][0] + schema = self._cw.vreg.schema + if 'comments' in schema and \ + 'BlogEntry' in schema.rschema('comments').objects(): + from cubes.comment.entities import subcomments_count + count = subcomments_count(entity) if count: url = xml_escape(entity.absolute_url()) @@ -238,5 +169,9 @@ if count: url = xml_escape(entity.absolute_url()) - w(u'<a href="%s">%s %s</a>' % (url, count, _('Comment', 'plural'))) + if count > 1: + label = _('Comment', 'plural') + else: + label = _('Comment') + w(u'<a href="%s">%s %s</a>' % (url, count, label)) else: w(u'%s %s' % (count, _('Comment'))) @@ -241,7 +176,6 @@ else: w(u'%s %s' % (count, _('Comment'))) - if 'tags' in self._cw.vreg.schema and \ - 'BlogEntry' in self._cw.vreg.schema.rschema('tags').objects(): + if 'tags' in schema and 'BlogEntry' in schema.rschema('tags').objects(): tag_rset = entity.related('tags', 'object') if tag_rset: w(u'%s %s' % (_('tags', 'object'), self._cw.view('csv', tag_rset))) @@ -257,12 +191,3 @@ def index_display(self, start, stop): return u'%s' % (int(start / self.page_size)+1) - - -# WFHistoryView ############################################################### - -class BlogEntryWFHistoryVComponent(workflow.WFHistoryVComponent): - __select__ = workflow.WFHistoryVComponent.__select__ & implements('BlogEntry') - - def cell_call(self, row, col, view=None): - pass