--- a/doc/book/en/devrepo/testing.rst Fri Jan 14 08:10:41 2011 +0100
+++ b/doc/book/en/devrepo/testing.rst Wed Jan 19 09:31:15 2011 +0100
@@ -196,13 +196,13 @@
blog_entry_2 = req.create_entity('BlogEntry', title=u'yes',
content=u'cubicweb yes')
blog_entry_2.set_relations(entry_of=cubicweb_blog)
- self.assertEquals(len(MAILBOX), 0)
+ self.assertEqual(len(MAILBOX), 0)
self.commit()
- self.assertEquals(len(MAILBOX), 2)
+ self.assertEqual(len(MAILBOX), 2)
mail = MAILBOX[0]
- self.assertEquals(mail.subject, '[data] hop')
+ self.assertEqual(mail.subject, '[data] hop')
mail = MAILBOX[1]
- self.assertEquals(mail.subject, '[data] yes')
+ self.assertEqual(mail.subject, '[data] yes')
Visible actions tests
`````````````````````
@@ -229,7 +229,7 @@
def test_admin(self):
req = self.request()
rset = req.execute('Any C WHERE C is Conference')
- self.assertListEquals(self.pactions(req, rset),
+ self.assertListEqual(self.pactions(req, rset),
[('workflow', workflow.WorkflowActions),
('edit', confactions.ModifyAction),
('managepermission', actions.ManagePermissionsAction),
@@ -238,7 +238,7 @@
('generate_badge_action', badges.GenerateBadgeAction),
('addtalkinconf', confactions.AddTalkInConferenceAction)
])
- self.assertListEquals(self.action_submenu(req, rset, 'addrelated'),
+ self.assertListEqual(self.action_submenu(req, rset, 'addrelated'),
[(u'add Track in_conf Conference object',
u'http://testing.fr/cubicweb/add/Track'
u'?__linkto=in_conf%%3A%(conf)s%%3Asubject&'
--- a/doc/book/en/devweb/request.rst Fri Jan 14 08:10:41 2011 +0100
+++ b/doc/book/en/devweb/request.rst Wed Jan 19 09:31:15 2011 +0100
@@ -1,5 +1,5 @@
-The `Request` class (`cubicweb.web`)
-------------------------------------
+The `Request` class (`cubicweb.web.request`)
+--------------------------------------------
Overview
````````
@@ -7,7 +7,8 @@
A request instance is created when an HTTP request is sent to the web
server. It contains informations such as form parameters,
authenticated user, etc. It is a very prevalent object and is used
-throughout all of the framework and applications.
+throughout all of the framework and applications, as you'll access to
+almost every resources through it.
**A request represents a user query, either through HTTP or not (we
also talk about RQL queries on the server side for example).**
@@ -24,8 +25,8 @@
* `User and identification`:
- * `user`, instance of `cubicweb.common.utils.User` corresponding to
- the authenticated user
+ * `user`, instance of `cubicweb.entities.authobjs.CWUser` corresponding to the
+ authenticated user
* `Session data handling`
--- a/doc/book/en/devweb/views/views.rst Fri Jan 14 08:10:41 2011 +0100
+++ b/doc/book/en/devweb/views/views.rst Wed Jan 19 09:31:15 2011 +0100
@@ -88,7 +88,7 @@
Other basic view classes
````````````````````````
-Here are some of the subclasses of `View` defined in `cubicweb.common.view`
+Here are some of the subclasses of `View` defined in `cubicweb.view`
that are more concrete as they relate to data rendering within the application:
* `EntityView`, view applying to lines or cell containing an entity (e.g. an eid)
Binary file doc/book/en/images/blog-demo-first-page.png has changed
Binary file doc/book/en/images/cbw-add-relation-entryof_en.png has changed
Binary file doc/book/en/images/cbw-create-blog_en.png has changed
Binary file doc/book/en/images/cbw-detail-one-blogentry_en.png has changed
Binary file doc/book/en/images/cbw-list-one-blog_en.png has changed
Binary file doc/book/en/images/cbw-list-two-blog_en.png has changed
Binary file doc/book/en/images/cbw-schema_en.png has changed
Binary file doc/book/en/images/cbw-update-primary-view_en.png has changed
Binary file doc/book/en/images/lax-book_06-header-no-login_en.png has changed
Binary file doc/book/en/images/lax-book_06-main-template-layout_en.png has changed
Binary file doc/book/en/images/lax-book_06-simple-main-template_en.png has changed
Binary file doc/book/en/images/login-form.png has changed
Binary file doc/book/en/images/tutos-base_blog-form_en.png has changed
Binary file doc/book/en/images/tutos-base_blog-primary-after-post-creation_en.png has changed
Binary file doc/book/en/images/tutos-base_blog-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_blogs-list_en.png has changed
Binary file doc/book/en/images/tutos-base_form-generic-relations_en.png has changed
Binary file doc/book/en/images/tutos-base_index_en.png has changed
Binary file doc/book/en/images/tutos-base_login-form_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-blogentry-taggable-commentable-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-community-custom-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-community-default-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-community-taggable-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-custom-footer_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-schema_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-siteinfo_en.png has changed
Binary file doc/book/en/images/tutos-base_schema_en.png has changed
Binary file doc/book/en/images/tutos-base_siteconfig_en.png has changed
Binary file doc/book/en/images/tutos-base_user-menu_en.png has changed
--- a/doc/book/en/tutorials/advanced/index.rst Fri Jan 14 08:10:41 2011 +0100
+++ b/doc/book/en/tutorials/advanced/index.rst Wed Jan 19 09:31:15 2011 +0100
@@ -66,25 +66,35 @@
entities supporting the `tags` relation by linking the to `Tag` entities. This
will allows navigation into a large number of picture.
-Ok, now I'll tell my cube requires all this by editing cubes/sytweb/__pkginfo__.py:
+Ok, now I'll tell my cube requires all this by editing :file:`cubes/sytweb/__pkginfo__.py`:
.. sourcecode:: python
- __depends_cubes__ = {'file': '>= 1.2.0',
- 'folder': '>= 1.1.0',
- 'person': '>= 1.2.0',
- 'comment': '>= 1.2.0',
- 'tag': '>= 1.2.0',
- 'zone': None,
- }
- __depends__ = {'cubicweb': '>= 3.5.10',
- }
- for key,value in __depends_cubes__.items():
- __depends__['cubicweb-'+key] = value
- __use__ = tuple(__depends_cubes__)
+ __depends__ = {'cubicweb': '>= 3.8.0',
+ 'cubicweb-file': '>= 1.2.0',
+ 'cubicweb-folder': '>= 1.1.0',
+ 'cubicweb-person': '>= 1.2.0',
+ 'cubicweb-comment': '>= 1.2.0',
+ 'cubicweb-tag': '>= 1.2.0',
+ 'cubicweb-zone': None}
Notice that you can express minimal version of the cube that should be used,
-`None` meaning whatever version available.
+`None` meaning whatever version available. All packages starting with 'cubicweb-'
+will be recognized as being cube, not bare python packages. You can still specify
+this explicitly using instead the `__depends_cubes__` dictionary which should
+contains cube's name without the prefix. So the example below would be written
+as:
+
+ .. sourcecode:: python
+
+ __depends__ = {'cubicweb': '>= 3.8.0'}
+ __depends_cubes__ = {'file': '>= 1.2.0',
+ 'folder': '>= 1.1.0',
+ 'person': '>= 1.2.0',
+ 'comment': '>= 1.2.0',
+ 'tag': '>= 1.2.0',
+ 'zone': None}
+
Step 3: glue everything together in my cube's schema
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -170,9 +180,11 @@
Here is the ``read`` security model I want:
* folders, files, images and comments should have one of the following visibility:
+
- ``public``, everyone can see it
- ``authenticated``, only authenticated users can see it
- ``restricted``, only a subset of authenticated users can see it
+
* managers (e.g. me) can see everything
* only authenticated users can see people
* everyone can see classifier entities, such as tag and zone
@@ -226,6 +238,12 @@
cardinality = '11' # required
class may_be_read_by(RelationDefinition):
+ __permissions__ = {
+ 'read': ('managers', 'users'),
+ 'add': ('managers',),
+ 'delete': ('managers',),
+ }
+
subject = ('Folder', 'File', 'Image', 'Comment',)
object = 'CWUser'
@@ -241,6 +259,9 @@
* the `parent` possible value will be used for visibility propagation
+* think to secure the `may_be_read_by` permissions, else any user can add/delte it
+ by default, which somewhat breaks our security model...
+
Now, we should be able to define security rules in the schema, based on these new
attribute and relation. Here is the code to add to *schema.py*:
@@ -541,7 +562,7 @@
If you do some changes in your schema, you'll have to force regeneration of that
database. You do that by removing the tmpdb files before running the test: ::
- $ rm tmpdb*
+ $ rm data/tmpdb*
.. Note::
--- a/doc/book/en/tutorials/base/blog-in-five-minutes.rst Fri Jan 14 08:10:41 2011 +0100
+++ b/doc/book/en/tutorials/base/blog-in-five-minutes.rst Wed Jan 19 09:31:15 2011 +0100
@@ -1,42 +1,70 @@
.. -*- coding: utf-8 -*-
-.. _BlogFiveMinutes:
+.. _TutosBaseBlogFiveMinutes:
Get a blog running in five minutes!
-----------------------------------
-For Debian or Ubuntu users, first install the following packages (:ref:`DebianInstallation`)::
+For Debian or Ubuntu users, first install the following packages
+(:ref:`DebianInstallation`)::
cubicweb, cubicweb-dev, cubicweb-blog
-For Windows or Mac OS X users, you must install cubicweb from source (see :ref:`SourceInstallation` and :ref:`WindowsInstallation`).
+Windows or Mac OS X users must install |cubicweb| from source (see
+:ref:`SourceInstallation` and :ref:`WindowsInstallation`).
Then create and initialize your instance::
cubicweb-ctl create blog myblog
-And start it::
+You'll be asked a few questions, and you can keep the default answer for most of
+them. The one question you'll have to think about is the database you'll want to
+use for that instance. For a quick test, if you don't have `postgresql` installed
+and configured (see :ref:`PostgresqlConfiguration`), it's highly recommended to
+choose `sqlite` when asked for which database driver to use, since it has a much
+simple setup (no database server needed).
+
+One the process is completed (including database initialisation), you can start
+your instance by using: ::
cubicweb-ctl start -D myblog
-The -D option is the debugging mode of cubicweb, removing it will lauch the instance in the background.
+The `-D` option activates the debugging mode. Removing it will launch the instance
+as a daemon in the background, and ``cubicweb-ctl stop myblog`` will stop
+it in that case.
+
+
+About file system permissions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Permission
-~~~~~~~~~~
+Unless you installed from sources, the above commands assume that you have root
+access to the :file:`/etc/` directory. In order to initialize your instance as a
+regular user, within your home directory, you can use the :envvar:`CW_MODE`
+environment variable: ::
-This command assumes that you have root access to the /etc/ path. In order to initialize your instance as a `user` (from scratch), please check your current PYTHONPATH then create the ~/etc/cubicweb.d directory.
+ export CW_MODE=user
+
+then create a :file:`~/etc/cubicweb.d` directory that will hold your instances.
+
+More information about how to configure your own environment is
+available in :ref:`ResourceMode`.
+
Instance parameters
~~~~~~~~~~~~~~~~~~~
-If you would like to change some instance parameters, for example, the database host or the user name, edit the `source` file located in the /etc/cubicweb.d/myblog directory.
+If you would like to change database parameters such as the database host or the
+user name used to connect to the database, edit the `sources` file located in the
+:file:`/etc/cubicweb.d/myblog` directory.
Then relaunch the database creation::
cubicweb-ctl db-create myblog
-Other paramaters, like web server or emails parameters, can be modified in the `all-in-one.conf` file.
+Other parameters, like web server or emails parameters, can be modified in the
+:file:`/etc/cubicweb.d/myblog/all-in-one.conf` file.
-This is it. Your blog is running. Visit http://localhost:8080 and enjoy it! This blog is fully functionnal. The next section section will present the way to develop new cubes and customizing the look of your instance.
+You'll have to restart the instance after modification in one of those files.
+This is it. Your blog is functional and running. Visit http://localhost:8080 and enjoy it!
--- a/doc/book/en/tutorials/base/components.rst Fri Jan 14 08:10:41 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _cubes:
-
-Cubes
------
-
-Standard library
-~~~~~~~~~~~~~~~~
-
-A library of standard cubes are available from `CubicWeb Forge`_
-Cubes provide entities and views.
-
-The available application entities in standard cubes are:
-
-* addressbook: PhoneNumber and PostalAddress
-
-* basket: Basket (like a shopping cart)
-
-* blog: Blog (a *very* basic blog)
-
-* classfolder: Folder (to organize things but grouping them in folders)
-
-* classtags: Tag (to tag anything)
-
-* comment: Comment (to attach comment threads to entities)
-
-* file: File (to allow users to upload and store binary or text files)
-
-* link: Link (to collect links to web resources)
-
-* mailinglist: MailingList (to reference a mailing-list and the URLs
- for its archives and its admin interface)
-
-* person: Person (easily mixed with addressbook)
-
-* task: Task (something to be done between start and stop date)
-
-* zone: Zone (to define places within larger places, for example a
- city in a state in a country)
-
-.. _`CubicWeb Forge`: http://www.cubicweb.org/project/
-
-Adding comments to BlogDemo
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To import a cube in your instance just change the line in the
-``__pkginfo__.py`` file and verify that the cube you are planning
-to use is listed by the command ``cubicweb-ctl list``.
-For example::
-
- __use__ = ('comment',)
-
-will make the ``Comment`` entity available in your ``BlogDemo``
-cube.
-
-Change the schema to add a relationship between ``BlogEntry`` and
-``Comment`` and you are done. Since the comment cube defines the
-``comments`` relationship, adding the line::
-
- comments = ObjectRelation('Comment', cardinality='1*', composite='object')
-
-to the definition of a ``BlogEntry`` will be enough.
-
-Synchronize the data model
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Once you modified your data model, you need to synchronize the
-database with your model. For this purpose, *CubicWeb* provides
-a very useful command ``cubicweb-ctl shell blogdemo`` which
-launches an interactive shell where you can enter migration
-commands (see :ref:`cubicweb-ctl` for more details)).
-As you added the cube named `comment`, you need to run:
-
-::
-
- add_cube('comment')
-
-You can now start your instance and comment your blog entries.
--- a/doc/book/en/tutorials/base/conclusion.rst Fri Jan 14 08:10:41 2011 +0100
+++ b/doc/book/en/tutorials/base/conclusion.rst Wed Jan 19 09:31:15 2011 +0100
@@ -3,11 +3,16 @@
What's next?
------------
-In this chapter, we have seen have you can, right after the installation of *CubicWeb*, build a web application in five minutes by defining a data model. Everything is there already: views, templates, permissions, etc.
+In this tutorial, we have seen have you can, right after the installation of
+|cubicweb|, build a web application in a few minutes by defining a data model as
+assembling cubes. You get a working application that you can then customize there
+and there while keeping something that works. This is important in agile
+development practices, you can right from the start of the project show things
+to customer and so take the right decision early in the process.
-The next step is to change the design and learn about the many features available to customize and extend your application: RSS channels (:ref:`XmlAndRss`), events (:ref:`hooks`), support of sources such as
-Google App Engine (:ref:`GoogleAppEngineSource`), etc.
-
-You will find more `tutorials and howtos`_ in the blog published on the CubicWeb.org website.
+The next steps will be to discover hooks, security, data sources, digging deeper
+into view writing and interface customisation... Yet a lot of fun stuff to
+discover! You will find more `tutorials and howtos`_ in the blog published on the
+CubicWeb.org website.
.. _`tutorials and howtos`: http://www.cubicweb.org/view?rql=Any+X+ORDERBY+D+DESC+WHERE+X+is+BlogEntry%2C+T+tags+X%2C+T+name+IN+%28%22tutorial%22%2C+%22howto%22%29%2C+X+creation_date+D
--- a/doc/book/en/tutorials/base/create-cube.rst Fri Jan 14 08:10:41 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,437 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _Steps:
-
-Steps for creating your cube
-----------------------------
-
-The following steps will help you to create and customize a new cube.
-
-1. :ref:`CreateYourCube`
-
-Create the directory to hold the code of your cube. The most important
-files that will be useful to customize your newly created cube are:
-
- * schema.py: contains the data model
- * views.py: contains your custom views
- * entities.py: contains XXX
-
-The detailed structure of the code directory is described in :ref:`cubelayout`.
-
-2. :ref:`DefineDataModel`
-
-Define the data model of your application.
-
-3. :ref:`ExploreYourInstance`
-
-Create, run, and explore an instance of your cube.
-
-4. :ref:`DefineViews`
-
-Customize the views of your data: how and which part of your data are showed.
-
-.. note:: views do not define the look'n'feel and the design of your application. For that, you will use CSS and the files located 'blog/data/'.
-
-
-5. :ref:`DefineEntities`
-
-Define your own entities to add useful functions when you manipulate your data, especially when you write view.
-
-
-.. _CreateYourCube:
-
-Create your cube
-----------------
-
-The packages ``cubicweb`` and ``cubicweb-dev`` install a command line
-tool for *CubicWeb* called ``cubicweb-ctl``. This tool provides a wide
-range of commands described in details in :ref:`cubicweb-ctl`.
-
-Once your *CubicWeb* development environment is set up, you can create
-a new cube::
-
- cubicweb-ctl newcube blog
-
-This will create in the cubes directory (``/path/to/forest/cubes`` for Mercurial
-installation, ``/usr/share/cubicweb/cubes`` for debian packages installation)
-a directory named ``blog`` reflecting the structure described in :ref:`Concepts`.
-
-
-For packages installation, you can still create new cubes in your home directory using the following configuration. Let's say you want to develop your new cubes in `~src/cubes`, then set the following environment variables:
-::
-
- CW_CUBES_PATH=~/src/cubes
- CW_MODE=user
-
-and then create your new cube using:
-::
-
- cubicweb-ctl newcube --directory=~/src/cubes blog
-
-
-.. _DefineDataModel:
-
-Define your data model
-----------------------
-
-The data model or schema is the core of your *CubicWeb* application.
-It defines the type of content your application will handle.
-
-The data model of your cube ``blog`` is defined in the file ``schema.py``:
-
-.. sourcecode:: python
-
- from yams.buildobjs import EntityType, String, SubjectRelation, Date
-
- class Blog(EntityType):
- title = String(maxsize=50, required=True)
- description = String()
-
- class BlogEntry(EntityType):
- title = String(required=True, fulltextindexed=True, maxsize=256)
- publish_date = Date(default='TODAY')
- content = String(required=True, fulltextindexed=True)
- entry_of = SubjectRelation('Blog', cardinality='?*')
-
-The first step is the import of the EntityType (generic class for entity and
-attributes that will be used in both Blog and BlogEntry entities.
-
-A Blog has a title and a description. The title is a string that is
-required and must be less than 50 characters. The
-description is a string that is not constrained.
-
-A BlogEntry has a title, a publish_date and a content. The title is a
-string that is required and must be less than 100 characters. The
-publish_date is a Date with a default value of TODAY, meaning that
-when a BlogEntry is created, its publish_date will be the current day
-unless it is modified. The content is a string that will be indexed in
-the database full-text index and has no constraint.
-
-A BlogEntry also has a relationship ``entry_of`` that links it to a
-Blog. The cardinality ``?*`` means that a BlogEntry can be part of
-zero or one Blog (``?`` means `zero or one`) and that a Blog can
-have any number of BlogEntry (``*`` means `any number including
-zero`). For completeness, remember that ``+`` means `one or more`.
-
-
-.. _ExploreYourInstance:
-
-Create and explore your instance
---------------------------------
-.. _CreateYourInstance:
-
-Create your instance
-~~~~~~~~~~~~~~~~~~~~
-
-To use this cube as an instance and create a new instance named ``blogdemo``, do::
-
- cubicweb-ctl create blog blogdemo
-
-This command will create the corresponding database and initialize it.
-
-
-.. _WelcomeToYourWebInstance:
-
-Welcome to your web instance
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Start your instance in debug mode with the following command: ::
-
- cubicweb-ctl start -D blogdemo
-
-
-You can now access your web instance to create blogs and post messages
-by visiting the URL http://localhost:8080/.
-
-A login form will appear. By default, the instance will not allow anonymous
-users to enter the instance. To login, you need then use the admin account
-you created at the time you initialized the database with ``cubicweb-ctl
-create``.
-
-.. image:: ../../images/login-form.png
-
-
-Once authenticated, you can start playing with your instance
-and create entities.
-
-.. image:: ../../images/blog-demo-first-page.png
-
-Please notice that so far, the *CubicWeb* framework managed all aspects of
-the web application based on the schema provided at the beginning.
-
-.. _AddEntities:
-
-Add entities
-~~~~~~~~~~~~
-
-We will now add entities in our web application.
-
-Add a Blog
-**********
-
-Let us create a few of these entities. Click on the `[+]` at the left of the
-link Blog on the home page. Call this new Blog ``Tech-blog`` and type in
-``everything about technology`` as the description, then validate the form by
-clicking on ``Validate``.
-
-.. image:: ../../images/cbw-create-blog_en.png
- :alt: from to create blog
-
-Click on the logo at top left to get back to the home page, then
-follow the Blog link that will list for you all the existing Blog.
-You should be seeing a list with a single item ``Tech-blog`` you
-just created.
-
-.. image:: ../../images/cbw-list-one-blog_en.png
- :alt: displaying a list of a single blog
-
-Clicking on this item will get you to its detailed description except
-that in this case, there is not much to display besides the name and
-the phrase ``everything about technology``.
-
-Now get back to the home page by clicking on the top-left logo, then
-create a new Blog called ``MyLife`` and get back to the home page
-again to follow the Blog link for the second time. The list now
-has two items.
-
-.. image:: ../../images/cbw-list-two-blog_en.png
- :alt: displaying a list of two blogs
-
-Add a BlogEntry
-***************
-
-Get back to the home page and click on [+] at the left of the link
-BlogEntry. Call this new entry ``Hello World`` and type in some text
-before clicking on ``Validate``. You added a new blog entry without
-saying to what blog it belongs. There is a box on the left entitled
-``actions``, click on the menu item ``modify``. You are back to the form
-to edit the blog entry you just created, except that the form now has
-another section with a combobox titled ``add relation``. Chose
-``entry_of`` in this menu and a second combobox appears where you pick
-``MyLife``.
-
-You could also have, at the time you started to fill the form for a
-new entity BlogEntry, hit ``Apply`` instead of ``Validate`` and the
-combobox titled ``add relation`` would have showed up.
-
-
-.. image:: ../../images/cbw-add-relation-entryof_en.png
- :alt: editing a blog entry to add a relation to a blog
-
-Validate the changes by clicking ``Validate``. The entity BlogEntry
-that is displayed now includes a link to the entity Blog named
-``MyLife``.
-
-.. image:: ../../images/cbw-detail-one-blogentry_en.png
- :alt: displaying the detailed view of a blogentry
-
-Note that all of this was handled by the framework and that the only input
-that was provided so far is the schema. To get a graphical view of the schema,
-point your browser to the URL http://localhost:8080/schema
-
-.. image:: ../../images/cbw-schema_en.png
- :alt: graphical view of the schema (aka data-model)
-
-
-.. _DefineViews:
-
-Define your entity views
-------------------------
-
-Each entity defined in a model is associated with default views
-allowing different renderings of the data. You can redefine each of
-them according to your needs and preferences. So let's see how the
-views are defined.
-
-
-The view selection principle
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A view is defined by a Python class which includes:
-
- - an identifier (all objects in *CubicWeb* are recorded in a
- registry and this identifier will be used as a key)
-
- - a filter to select the result sets it can be applied to
-
-A view has a set of methods complying with the `View` class interface
-(`cubicweb.common.view`).
-
-*CubicWeb* provides a lot of standard views for the type `EntityView`;
-for a complete list, read the code in directory ``cubicweb/web/views/``.
-
-A view is applied on a `result set` which contains a set of entities
-we are trying to display. *CubicWeb* uses a selector mechanism which
-computes for each available view a score: the view with the highest
-score is then used to display the given `result set`. The standard
-library of selectors is in ``cubicweb.selector``.
-
-It is possible to define multiple views for the same identifier
-and to associate selectors and filters to allow the application
-to find the most appropriate way to render the data.
-
-For example, the view named ``primary`` is the one used to display a
-single entity. We will now show you how to create a primary view for
-BlogEntry.
-
-
-Primary view customization
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you wish to modify the way a `BlogEntry` is rendered, you will have
-to subclass the `primary` view, for instance in the module ``views``
-of the cube ``cubes/blog/views.py``.
-
-The standard primary view is the most sophisticated view of all. It
-has more than a call() method. It is a template. Actually the entry
-point calls the following sequence of (redefinable) methods:
-
- * render_entity_title
-
- * render_entity_metadata
-
- * render_entity_attributes
-
- * render_entity_relations
-
- * render_side_boxes
-
-Excepted side boxes, we can see all of them already in action in the
-blog entry view. This is all described in more details in
-:ref:`primary_view`.
-
-We can for example add in front of the publication date a prefix
-specifying that the date we see is the publication date.
-
-To do so, please apply the following changes:
-
-.. sourcecode:: python
-
- from cubicweb.selectors import is_instance
- from cubicweb.web.views import primary
-
- class BlogEntryPrimaryView(primary.PrimaryView):
- __select__ = is_instance('BlogEntry')
-
- def render_entity_attributes(self, entity):
- self.w(u'<p>published on %s</p>' %
- entity.publish_date.strftime('%Y-%m-%d'))
- super(BlogEntryPrimaryView, self).render_entity_attributes(entity)
-
-.. note::
- When a view is modified, it is not required to restart the instance
- server. Save the Python file and reload the page in your web browser
- to view the changes.
-
-You can now see that the publication date has a prefix.
-
-.. image:: ../../images/cbw-update-primary-view_en.png
- :alt: modified primary view
-
-
-The above source code defines a new primary view for ``BlogEntry``.
-
-Since views are applied to result sets and result sets can be tables of
-data, we have to recover the entity from its (row,col)-coordinates.
-The view has a ``self.w()`` method that is used to output data, in our
-example HTML output.
-
-.. note::
- You can find more details about views and selectors in :ref:`Views`.
-
-
-.. _DefineEntities:
-
-Write entities to add logic in your data
-----------------------------------------
-
-By default, CubicWeb provides a default entity for each data type defined in the schema.
-A default entity mainly contains the attributes defined in the data model.
-
-You can redefine each entity to provide additional functions to help you write your views.
-
-.. sourcecode:: python
-
- from cubicweb.entities import AnyEntity
-
- class BlogEntry(AnyEntity):
- """customized class for BlogEntry entities"""
- __regid__ = 'BlogEntry'
-
- def display_cw_logo(self):
- if 'CW' in self.title:
- return True
- else:
- return False
-
-Customizing an entity requires that your entity:
- - inherits from ``cubicweb.entities`` or any subclass
- - defines a ``__regid__`` linked to the corresponding data type of your schema
- - implements the base class by explicitly using ``__implements__``.
-
-We implemented here a function ``display_cw_logo`` which tests if the blog entry title contains 'CW'.
-This function can then be used when you customize your views. For instance, you can modify your previous ``views.py`` as follows:
-
-.. sourcecode:: python
-
- class BlogEntryPrimaryView(primary.PrimaryView):
- __select__ = is_instance('BlogEntry')
-
- ...
-
- def render_entity_title(self, entity):
- if entity.display_cw_logo():
- self.w(u'<image src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>')
- super(BlogEntryPrimaryView, self).render_entity_title(entity)
-
-Then each blog entry whose title contains 'CW' is shown with the CubicWeb logo in front of it.
-
-.. _UpdatingSchemaAndSynchronisingInstance:
-
-Updating the schema and synchronising the instance
---------------------------------------------------
-
-While developping your cube, you may want to update your data model. Let's say you
-want to add a ``category`` attribute in the ``Blog`` data type. This is called a migration.
-
-The required steps are:
-
-1. modify the file ``schema.py``. The ``Blog`` class looks now like this:
-
-.. sourcecode:: python
-
- class Blog(EntityType):
- title = String(maxsize=50, required=True)
- description = String()
- category = String(required=True, vocabulary=(_('Professional'), _('Personal')), default='Personal')
-
-2. stop your ``blogdemo`` instance:
-
-.. sourcecode:: bash
-
- cubicweb-ctl stop blogdemo
-
-3. start the cubicweb shell for your instance by running the following command:
-
-.. sourcecode:: bash
-
- cubicweb-ctl shell blogdemo
-
-4. at the cubicweb shell prompt, execute:
-
-.. sourcecode:: python
-
- add_attribute('Blog', 'category')
-
-5. restart your instance:
-
-.. sourcecode:: bash
-
- cubicweb-ctl start blogdemo
-
-6. modify a blog entity and check that the new attribute
-``category`` has been added.
-
-Of course, you may also want to add relations, entity types, etc. See :ref:`migration`
-for a list of all available migration commands.
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/tutorials/base/customizing-the-application.rst Wed Jan 19 09:31:15 2011 +0100
@@ -0,0 +1,536 @@
+.. -*- coding: utf-8 -*-
+
+.. _TutosBaseCustomizingTheApplication:
+
+Customizing your application
+----------------------------
+
+So far so good. The point is that usually, you won't get enough by assembling
+cubes out-of-the-box. You will want to customize them, have a personal look and
+feel, add your own data model and so on. Or maybe start from scratch?
+
+So let's get a bit deeper and start coding our own cube. In our case, we want
+to customize the blog we created to add more features to it.
+
+
+Create your own cube
+~~~~~~~~~~~~~~~~~~~~
+
+First, notice that if you've installed |cubicweb| using Debian packages, you will
+need the additional ``cubicweb-dev`` package to get the commands necessary to
+|cubicweb| development. All `cubicweb-ctl` commands are described in details in
+:ref:`cubicweb-ctl`.
+
+Once your |cubicweb| development environment is set up, you can create a new
+cube::
+
+ cubicweb-ctl newcube myblog
+
+This will create in the cubes directory (:file:`/path/to/forest/cubes` for source
+installation, :file:`/usr/share/cubicweb/cubes` for Debian packages installation)
+a directory named :file:`blog` reflecting the structure described in
+:ref:`cubelayout`.
+
+For packages installation, you can still create new cubes in your home directory
+using the following configuration. Let's say you want to develop your new cubes
+in `~src/cubes`, then set the following environment variables: ::
+
+ CW_CUBES_PATH=~/src/cubes
+
+and then create your new cube using: ::
+
+ cubicweb-ctl newcube --directory=~/src/cubes myblog
+
+.. Note:
+
+ We previously used `myblog` as the name of our *instance*. We're now creating
+ a *cube* with the same name. Both are different things. We'll now try to
+ specify when we talk about one or another, but keep in mind this difference.
+
+
+Cube metadata
+~~~~~~~~~~~~~
+
+A simple set of metadata about your cube are stored in the :file:`__pkginfo__.py`
+file. In our case, we want to extend the blog cube, so we have to tell that our
+cube depends on this cube, by modifying the ``__depends__`` dictionary in that
+file:
+
+.. sourcecode:: python
+
+ __depends__ = {'cubicweb': '>= 3.10.7',
+ 'cubicweb-blog': None}
+
+where the ``None`` means we do not depends on a particular version of the cube.
+
+
+Extending the data model
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The data model or schema is the core of your |cubicweb| application. It defines
+the type of content your application will handle. It is defined in the file
+:file:`schema.py` of the cube.
+
+
+Defining our model
+******************
+
+For the sake of example, let's say we want a new entity type named `Community`
+with a name, a description. A `Community` will hold several blogs.
+
+.. sourcecode:: python
+
+ from yams.buildobjs import EntityType, RelationDefinition, String, RichString
+
+ class Community(EntityType):
+ name = String(maxsize=50, required=True)
+ description = RichString()
+
+ class community_blog(RelationDefinition):
+ subject = 'Community'
+ object = 'Blog'
+ cardinality = '*?'
+ composite = 'subject'
+
+The first step is the import from the :mod:`yams` package necessary classes to build
+the schema.
+
+This file defines the following:
+
+* a `Community` has a title and a description as attributes
+
+ - the name is a string that is required and can't be longer than 50 characters
+
+ - the description is a string that is not constrained and may contains rich
+ content such as HTML or Restructured text.
+
+* a `Community` may be linked to a `Blog` using the `community_blog` relation
+
+ - ``*`` means a community may be linked to 0 to N blog, ``?`` means a blog may
+ be linked to 0 to 1 community. For completeness, remember that you can also
+ use ``+`` for 1 to N, and ``1`` for single, mandatory relation (e.g. one to one);
+
+ - this is a composite relation where `Community` (e.g. the subject of the
+ relation) is the composite. That means that if you delete a community, its
+ blog will be deleted as well.
+
+Of course, there are a lot of other data types and things such as constraints,
+permissions, etc, that may be defined in the schema, but those won't be covered
+in this tutorial.
+
+Notice that our schema refers to the `Blog` entity type which is not defined
+here. But we know this type is available since we depend on the `blog` cube
+which is defining it.
+
+
+Applying changes to the model into our instance
+***********************************************
+
+Now the problem is that we created an instance using the `blog` cube, not our
+`myblog` cube, so if we don't do anything there is no way that we'll see anything
+changing in the instance.
+
+One easy way, as we've no really valuable data in the instance would be to trash and recreated it::
+
+ cubicweb-ctl stop myblog # or Ctrl-C in the terminal running the server in debug mode
+ cubicweb-ctl delete myblog
+ cubicweb-ctl create myblog
+ cubicweb-ctl start -D myblog
+
+Another way is to add our cube to the instance using the cubicweb-ctl shell
+facility. It's a python shell connected to the instance with some special
+commands available to manipulate it (the same as you'll have in migration
+scripts, which are not covered in this tutorial). In that case, we're interested
+in the `add_cube` command: ::
+
+ $ cubicweb-ctl stop myblog # or Ctrl-C in the terminal running the server in debug mode
+ $ cubicweb-ctl shell myblog
+ entering the migration python shell
+ just type migration commands or arbitrary python code and type ENTER to execute it
+ type "exit" or Ctrl-D to quit the shell and resume operation
+ >>> add_cube('myblog')
+ >>>
+ $ cubicweb-ctl start -D myblog
+
+The `add_cube` command is enough since it automatically updates our
+application to the cube's schema. There are plenty of other migration
+commands of a more finer grain. They are described in :ref:`migration`
+
+As explained, leave the shell by typing Ctrl-D. If you restart the instance and
+take another look at the schema, you'll see that changes to the data model have
+actually been applied (meaning database schema updates and all necessary stuff
+has been done).
+
+.. image:: ../../images/tutos-base_myblog-schema_en.png
+ :alt: the instance schema after adding our cube
+
+If you follow the 'info' link in the user pop-up menu, you'll also see that the
+instance is using blog and myblog cubes.
+
+.. image:: ../../images/tutos-base_myblog-siteinfo_en.png
+ :alt: the instance schema after adding our cube
+
+You can now add some communities, link them to blog, etc... You'll see that the
+framework provides default views for this entity type (we have not yet defined any
+view for it!), and also that the blog primary view will show the community it's
+linked to if any. All this thanks to the model driven interface provided by the
+framework.
+
+You'll then be able to redefine each of them according to your needs
+and preferences. We'll now see how to do such thing.
+
+Defining your views
+~~~~~~~~~~~~~~~~~~~
+
+|cubicweb| provides a lot of standard views in directory
+:file:`cubicweb/web/views/`. We already talked about 'primary' and 'list' views,
+which are views which apply to one ore more entities.
+
+A view is defined by a python class which includes:
+
+ - an identifier: all objects used to build the user interface in |cubicweb| are
+ recorded in a registry and this identifier will be used as a key in that
+ registry. There may be multiple views for the same identifier.
+
+ - a *selector*, which is a kind of filter telling how well a view suit to a
+ particular context. When looking for a particular view (e.g. given an
+ identifier), |cubicweb| computes for each available view with that identifier
+ a score which is returned by the selector. Then the view with the highest
+ score is used. The standard library of selectors is in
+ :mod:`cubicweb.selector`.
+
+A view has a set of methods inherited from the :class:`cubicweb.view.View` class,
+though you usually don't derive directly from this class but from one of its more
+specific child class.
+
+Last but not least, |cubicweb| provides a set of default views accepting any kind
+of entities.
+
+Want a proof? Create a community as you've already done for other entity types
+through the index page, you'll then see something like that:
+
+.. image:: ../../images/tutos-base_myblog-community-default-primary_en.png
+ :alt: the default primary view for our community entity type
+
+
+If you notice the weird messages that appear in the page: those are messages
+generated for the new data model, which have no translation yet. To fix that,
+we'll have to use dedicated `cubicweb-ctl` commands:
+
+.. sourcecode: bash
+
+ cubicweb-ctl i18ncube myblog # build/update cube's message catalogs
+ # then add translation into .po file into the cube's i18n directory
+ cubicweb-ctl i18ninstance myblog # recompile instance's message catalogs
+ cubicweb-ctl restart -D myblog # instance has to be restarted to consider new catalogs
+
+You'll then be able to redefine each of them according to your needs and
+preferences. So let's see how to do such thing.
+
+Changing the layout of the application
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The layout is the general organization of the pages in the site. Views that generate
+the layout are sometimes referred to as 'templates'. They are implemented in the
+framework in the module :mod:`cubicweb.web.views.basetemplates`. By overriding
+classes in this module, you can customize whatever part you wish of the default
+layout.
+
+But notice that |cubicweb| provides many other ways to customize the
+interface, thanks to actions and components (which you can individually
+(de)activate, control their location, customize their look...) as well as
+"simple" CSS customization. You should first try to achieve your goal using such
+fine grained parametrization rather then overriding a whole template, which usually
+embeds customisation access points that you may loose in the process.
+
+But for the sake of example, let's say we want to change the generic page
+footer... We can simply add to the module ``views`` of our cube,
+e.g. :file:`cubes/myblog/views.py`, the code below:
+
+.. sourcecode:: python
+
+ from cubicweb.web.views import basetemplates
+
+ class MyHTMLPageFooter(basetemplates.HTMLPageFooter):
+
+ def footer_content(self):
+ self.w(u'This website has been created with <a href="http://cubicweb.org">CubicWeb</a>.')
+
+ def registration_callback(vreg):
+ vreg.register_all(globals().values(), __name__, (MyHTMLPageFooter,))
+ vreg.register_and_replace(MyHTMLPageFooter, basetemplates.HTMLPageFooter)
+
+
+* Our class inherits from the default page footer to ease getting things right,
+ but this is not mandatory.
+
+* When we want to write something to the output stream, we simply call `self.w`,
+ with *must be passed an unicode string*.
+
+* The latest function is the most exotic stuff. The point is that without it, you
+ would get an error at display time because the framework wouldn't be able to
+ choose which footer to use between :class:`HTMLPageFooter` and
+ :class:`MyHTMLPageFooter`, since both have the same selector, hence the same
+ score... In this case, we want our footer to replace the default one, so we have
+ to define a :func:`registration_callback` function to control object
+ registration: the first instruction tells to register everything in the module
+ but the :class:`MyHTMLPageFooter` class, then the second to register it instead
+ of :class:`HTMLPageFooter`. Without this function, everything in the module is
+ registered blindly.
+
+.. Note::
+
+ When a view is modified while running in debug mode, it is not required to
+ restart the instance server. Save the Python file and reload the page in your
+ web browser to view the changes.
+
+We will now have this simple footer on every page of the site.
+
+
+Primary view customization
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The 'primary' view (i.e. any view with the identifier set to 'primary') is the one used to
+display all the information about a single entity. The standard primary view is one
+of the most sophisticated views of all. It has several customisation points, but
+its power comes with `uicfg`, allowing you to control it without having to
+subclass it.
+
+However this is a bit off-topic for this first tutorial. Let's say we simply want a
+custom primary view for my `Community` entity type, using directly the view
+interface without trying to benefit from the default implementation (you should
+do that though if you're rewriting reusable cubes; everything is described in more
+details in :ref:`primary_view`).
+
+
+So... Some code! That we'll put again in the module ``views`` of our cube.
+
+.. sourcecode:: python
+
+ from cubicweb.selectors import is_instance
+ from cubicweb.web.views import primary
+
+ class CommunityPrimaryView(primary.PrimaryView):
+ __select__ = is_instance('Community')
+
+ def cell_call(self, row, col):
+ entity = self.cw_rset.get_entity(row, col)
+ self.w(u'<h1>Welcome to the "%s" community</h1>' % entity.printable_value('name'))
+ if entity.description:
+ self.w(u'<p>%s</p>' % entity.printable_value('description'))
+
+What's going on here?
+
+* Our class inherits from the default primary view, here mainly to get the correct
+ view identifier, since we don't use any of its features.
+
+* We set on it a selector telling that it only applies when trying to display
+ some entity of the `Community` type. This is enough to get an higher score than
+ the default view for entities of this type.
+
+* View applying to entities usually have to define `cell_call` as entry point,
+ and are given `row` and `col` arguments tell to which entity in the result set
+ the view is applied. We can then get this entity from the result set
+ (`self.cw_rset`) by using the `get_entity` method.
+
+* To ease thing, we access our entity's attribute for display using its
+ printable_value method, which will handle formatting and escaping when
+ necessary. As you can see, you can also access attributes by their name on the
+ entity to get the raw value.
+
+
+You can now reload the page of the community we just created and see the changes.
+
+.. image:: ../../images/tutos-base_myblog-community-custom-primary_en.png
+ :alt: the custom primary view for our community entity type
+
+We've seen here a lot of thing you'll have to deal with to write views in
+|cubicweb|. The good news is that this is almost everything that is used to
+build higher level layers.
+
+.. Note::
+
+ As things get complicated and the volume of code in your cube increases, you can
+ of course still split your views module into a python package with subpackages.
+
+You can find more details about views and selectors in :ref:`Views`.
+
+
+Write entities to add logic in your data
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+|cubicweb| provides an ORM to easily programmaticaly manipulate
+entities (just like the one we have fetched earlier by calling
+`get_entity` on a result set). By default, entity
+types are instances of the :class:`AnyEntity` class, which holds a set of
+predefined methods as well as property automatically generated for
+attributes/relations of the type it represents.
+
+You can redefine each entity to provide additional methods or whatever you want
+to help you write your application. Customizing an entity requires that your
+entity:
+
+- inherits from :class:`cubicweb.entities.AnyEntity` or any subclass
+
+- defines a :attr:`__regid__` linked to the corresponding data type of your schema
+
+You may then want to add your own methods, override default implementation of some
+method, etc...
+
+.. sourcecode:: python
+
+ from cubicweb.entities import AnyEntity, fetch_config
+
+
+ class Community(AnyEntity):
+ """customized class for Community entities"""
+ __regid__ = 'Community'
+
+ fetch_attrs, fetch_order = fetch_config(['name'])
+
+ def dc_title(self):
+ return self.name
+
+ def display_cw_logo(self):
+ return 'CubicWeb' in self.description
+
+In this example:
+
+* we used convenience :func:`fetch_config` function to tell which attributes
+ should be prefetched by the ORM when looking for some related entities of this
+ type, and how they should be ordered
+
+* we overrode the standard `dc_title` method, used in various place in the interface
+ to display the entity (though in this case the default implementation would
+ have had the same result)
+
+* we implemented here a method :meth:`display_cw_logo` which tests if the blog
+ entry title contains 'CW'. It can then be used when you're writing code
+ involving 'Community' entities in your views, hooks, etc. For instance, you can
+ modify your previous views as follows:
+
+.. sourcecode:: python
+
+
+ class CommunityPrimaryView(primary.PrimaryView):
+ __select__ = is_instance('Community')
+
+ def cell_call(self, row, col):
+ entity = self.cw_rset.get_entity(row, col)
+ self.w(u'<h1>Welcome to the "%s" community</h1>' % entity.printable_value('name'))
+ if entity.display_cw_logo():
+ self.w(u'<img src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>')
+ if entity.description:
+ self.w(u'<p>%s</p>' % entity.printable_value('description'))
+
+Then each community whose description contains 'CW' is shown with the |cubicweb|
+logo in front of it.
+
+.. Note::
+
+ As for view, you don't have to restart your instance when modifying some entity
+ classes while your server is running in debug mode, the code will be
+ automatically reloaded.
+
+
+Extending the application by using more cubes!
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+One of the goal of the |cubicweb| framework was to have truly reusable
+components. To do so, they must both behave nicely when plugged into the
+application and be easily customisable, from the data model to the user
+interface. And I think the result is pretty successful, thanks to system such as
+the selection mechanism and the choice to write views as python code which allows
+to build our page using true object oriented programming techniques, that no
+template language provides.
+
+
+A library of standard cubes is available from `CubicWeb Forge`_, to address a
+lot of common concerns such has manipulating people, files, things to do, etc. In
+our community blog case, we could be interested for instance in functionalities
+provided by the `comment` and `tag` cubes. The former provides threaded
+discussion functionalities, the latter a simple tag mechanism to classify content.
+Let's say we want to try those. We will first modify our cube's :file:`__pkginfo__.py`
+file:
+
+.. sourcecode:: python
+
+ __depends__ = {'cubicweb': '>= 3.10.7',
+ 'cubicweb-blog': None,
+ 'cubicweb-comment': None,
+ 'cubicweb-tag': None}
+
+Now, we'll simply tell on which entity types we want to activate the 'comment'
+and 'tag' facilities by adding respectively the 'comments' and 'tags' relations on
+them in our schema (:file:`schema.py`).
+
+.. sourcecode:: python
+
+ class comments(RelationDefinition):
+ subject = 'Comment'
+ object = 'BlogEntry'
+ cardinality = '1*'
+ composite = 'object'
+
+ class tags(RelationDefinition):
+ subject = 'Tag'
+ object = ('Community', 'BlogEntry')
+
+
+So in the case above we activated comments on `BlogEntry` entities and tags on
+both `Community` and `BlogEntry`. Various views from both `comment` and `tag`
+cubes will then be automatically displayed when one of those relations is
+supported.
+
+Let's synchronize the data model as we've done earlier: ::
+
+
+ $ cubicweb-ctl stop myblog
+ $ cubicweb-ctl shell myblog
+ entering the migration python shell
+ just type migration commands or arbitrary python code and type ENTER to execute it
+ type "exit" or Ctrl-D to quit the shell and resume operation
+ >>> add_cubes('comment', 'tag')
+ >>>
+
+Then restart the instance. Let's look at a blog entry:
+
+.. image:: ../../images/tutos-base_myblog-blogentry-taggable-commentable-primary_en.png
+ :alt: the primary view for a blog entry with comments and tags activated
+
+As you can see, we now have a box displaying tags and a section proposing to add
+a comment and displaying existing one below the post. All this without changing
+anything in our views, thanks to the design of generic views provided by the
+framework. Though if we take a look at a community, we won't see the tags box!
+That's because by default this box try to locate itself in the left column within
+the white frame, and this column is handled by the primary view we
+hijacked. Let's change our view to make it more extensible, by keeping both our
+custom rendering but also extension points provided by the default
+implementation.
+
+
+.. sourcecode:: python
+
+ class CommunityPrimaryView(primary.PrimaryView):
+ __select__ = is_instance('Community')
+
+ def render_entity_title(self, entity):
+ self.w(u'<h1>Welcome to the "%s" community</h1>' % entity.printable_value('name'))
+
+ def render_entity_attributes(self, entity):
+ if entity.display_cw_logo():
+ self.w(u'<img src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>')
+ if entity.description:
+ self.w(u'<p>%s</p>' % entity.printable_value('description'))
+
+It appears now properly:
+
+.. image:: ../../images/tutos-base_myblog-community-taggable-primary_en.png
+ :alt: the custom primary view for a community entry with tags activated
+
+You can control part of the interface independently from each others, piece by
+piece. Really.
+
+
+
+.. _`CubicWeb Forge`: http://www.cubicweb.org/project
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/tutorials/base/discovering-the-ui.rst Wed Jan 19 09:31:15 2011 +0100
@@ -0,0 +1,161 @@
+
+.. _TutosBaseDiscoveringTheUI:
+
+Discovering the web interface
+-----------------------------
+
+You can now access your web instance to create blogs and post messages
+by visiting the URL http://localhost:8080/.
+
+By default, anonymous access is disabled, so a login form will appear. If you
+asked to allow anonymous access when initializing the instance, click on the
+'login' link in the top right hand corner. To login, you need then use the admin
+account you specified at the time you initialized the database with
+``cubicweb-ctl create``.
+
+.. image:: ../../images/tutos-base_login-form_en.png
+ :alt: the login form
+
+
+Once authenticated, you can start playing with your instance. The default index
+page looks like the following:
+
+.. image:: ../../images/tutos-base_index_en.png
+ :alt: the index page
+
+
+Minimal configuration
+~~~~~~~~~~~~~~~~~~~~~
+
+Before creating entities, let's change that 'unset title' thing that appears
+here and there. This comes from a |cubicweb| system properties. To set it,
+click on the 'site configuration link' in the pop-up menu behind your login name
+in the upper left-hand corner
+
+.. image:: ../../images/tutos-base_user-menu_en.png
+ :alt: the user pop-up menu
+
+The site title is in the 'Ui' section. Simply set it to the desired value and
+click the 'validate' button.
+
+.. image:: ../../images/tutos-base_siteconfig_en.png
+ :alt: the site configuration form
+
+You should see a 'changes applied' message. You can now go back to the
+index page by clicking on the |cubicweb| logo in the upper left-hand corner.
+
+You will much likely still see 'unset title' at this point. This is because by
+default the index page is cached. Force a refresh of the page (by typing Ctrl-R
+in Firefox for instance) and you should now see the title you entered.
+
+
+Adding entities
+~~~~~~~~~~~~~~~
+
+The ``blog`` cube defines several entity types, among them ``Blog`` which is a
+container for ``BlogEntry`` (i.e. posts) on a particular topic. We can get a
+graphical view of the schema by clicking on the 'site schema' link in the user
+pop-up menu we've already seen:
+
+.. image:: ../../images/tutos-base_schema_en.png
+ :alt: graphical view of the schema (aka data-model)
+
+Nice isn't it? Notice that this, as most other stuff we'll see in this tutorial,
+is generated by the framework according to the model of the application. In our
+case, the model defined by the ``blog`` cube.
+
+Now let us create a few of these entities.
+
+
+Add a blog
+**********
+
+Clicking on the `[+]` at the left of the 'Blog' link on the index page will lead
+you to an HTML form to create a blog.
+
+.. image:: ../../images/tutos-base_blog-form_en.png
+ :alt: the blog creation form
+
+For instance, call this new blog 'Tech-blog' and type in 'everything about
+technology' as the description , then validate the form by clicking on
+'Validate'. You will be redirected to the `primary` view of the newly created blog.
+
+.. image:: ../../images/tutos-base_blog-primary_en.png
+ :alt: the blog primary view
+
+
+Add a blog post
+***************
+
+There are several ways to add a blog entry. The simplest is to click on the 'add
+blog entry' link in the actions box on viewing the blog you have just created.
+You will then see a form to create a post, with a 'blog entry of' field preset
+to the blog we're coming from. Enter a title, some content, click the 'validate'
+button and you're done. You will be redirected to the blog primary view, though you
+now see that it contains the blog post you've just created.
+
+.. image:: ../../images/tutos-base_blog-primary-after-post-creation_en.png
+ :alt: the blog primary view after creation of a post
+
+Notice there are some new boxes that appears in the left column.
+
+You can achieve the same thing by following the same path as we did for the blog
+creation, e.g. by clicking on the `[+]` at the left of the 'Blog entry' link on
+the index page. The diffidence being that since there is no context information,
+the 'blog entry of' selector won't be preset to the blog.
+
+
+If you click on the 'modify' link of the action box, you are back to
+the form to edit the entity you just created, except that the form now
+has another section with a combo-box entitled 'add relation'. It
+provisos a generic way to edit relations which don't appears in the
+above form. Choose the relation you want to add and a second combo box
+appears where you can pick existing entities. If there are too many
+of them, you will be offered to navigate to the target entity, that is
+go away from the form and go back to it later, once you've selected
+the entity you want to link with.
+
+.. image:: ../../images/tutos-base_form-generic-relations_en.png
+ :alt: the generic relations combo box
+
+This combo box can't appear until the entity is actually created. That's why you
+haven't seen it at creation time. You could also have hit 'Apply' instead of
+'validate' and it would have showed up.
+
+
+About ui auto-adaptation
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+One of the things that make |cubicweb| different of other frameworks is
+its automatic user interface that adapts itself according to the data being
+displayed. Let's see an example.
+
+If you go back to the home page an click on the 'Blog' link, you will be redirected
+to the primary view of the blog, the same we've seen earlier. Now, add another
+blog, go back to the index page, and click again on this link. You will see
+a very different view (namely the 'list' view).
+
+.. image:: ../../images/tutos-base_blogs-list_en.png
+ :alt: the list view when there are more than one blog to display
+
+This is because in the first case, the framework chose to use the 'primary'
+view since there was only one entity in the data to be displayed. Now that there
+are two entities, the 'list' view is more appropriate and hence is being used.
+
+There are various other places where |cubicweb| adapts to display data in the best
+way, the main being provided by the view *selection* mechanism that will be detailed
+later.
+
+
+Digging deeper
+~~~~~~~~~~~~~~
+
+By following principles explained below, you should now be able to
+create new users for your application, to configure with a finer
+grain, etc... You will notice that the index page lists a lot of types
+you don't know about. Most are built-in types provided by the framework
+to make the whole system work. You may ignore them in a first time and
+discover them as time goes.
+
+One thing that is worth playing with is the search box. It may be used in various
+way, from simple full text search to advanced queries using the :ref:`RQL` .
--- a/doc/book/en/tutorials/base/index.rst Fri Jan 14 08:10:41 2011 +0100
+++ b/doc/book/en/tutorials/base/index.rst Wed Jan 19 09:31:15 2011 +0100
@@ -1,30 +1,48 @@
.. -*- coding: utf-8 -*-
-.. _Tutorial:
-
-.. _tuto_blog:
+.. _TutosBase:
-Building a simple blog
-======================
+Building a simple blog with |cubicweb|
+======================================
-*CubicWeb* is a semantic web application framework that favors reuse and
+|cubicweb| is a semantic web application framework that favors reuse and
object-oriented design.
-A `cube` is a component that includes a model defining the data types and a set of
-views to display the data. A cube can be built by assembling other cubes.
+
+This tutorial is designed to help in your very first steps to start with
+|cubicweb|. We will tour through basic concepts such as:
-An `instance` is a specific installation of a cube and includes configuration
-files.
+* getting an application running by using existing components
+* discovering the default user interface
+* basic extending and customizing the look and feel of that application
+
+More advanced concepts are covered in :ref:`advanced_tutorial`.
-This tutorial will show how to create a `cube` and how to use it as an
-application to run an `instance`.
+.. _TutosBaseVocab:
+
+Some vocabulary
+---------------
+
+|cubicweb| comes with a few words of vocabulary that you should know to
+understand what we're talking about. To follow this tutorial, you should at least
+know that:
+
+* a `cube` is a component that usually includes a model defining some data types
+ and a set of views to display them. A cube can be built by assembling other
+ cubes;
+
+* an `instance` is a specific installation of one or more cubes and includes
+ configuration files, a web server and a database.
+
+Reading :ref:`Concepts` for more vocabulary will be required at some point.
+
+Now, let's start the hot stuff!
.. toctree::
:maxdepth: 2
blog-in-five-minutes
- create-cube
- components
- maintemplate
+ discovering-the-ui
+ customizing-the-application
conclusion
--- a/doc/book/en/tutorials/base/maintemplate.rst Fri Jan 14 08:10:41 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Templates
----------
-
-Look at ``cubicweb/web/views/basetemplates.py`` and you will
-find the base templates used to generate HTML for your application.
-
-A page is composed as indicated on the schema below:
-
-.. image:: ../../images/lax-book_06-main-template-layout_en.png
-
-In this section we will demonstrate a change in one of the main
-interesting template from the three you will look for,
-that is to say, the HTMLPageHeader, the HTMLPageFooter
-and the TheMainTemplate.
-
-
-Customize a template
-~~~~~~~~~~~~~~~~~~~~
-
-Based on the diagram below, each template can be overriden
-by your customized template. To do so, we recommand you create
-a Python module ``blog.views.templates`` to keep it organized.
-In this module you will have to import the parent class you are
-interested as follows: ::
-
- from cubicweb.web.views.basetemplates import HTMLPageHeader, \
- HTMLPageFooter, TheMainTemplate
-
-and then create your sub-class::
-
- class MyBlogHTMLPageHeader(HTMLPageHeader):
- ...
-
-Customize header
-`````````````````
-
-Let's now move the search box in the header and remove the login form from the
-header. We'll show how to move it to the left column of the user interface.
-
-Let's say we do not want anymore the login menu to be in the header
-
-First, to remove the login menu, we just need to comment out the display of the
-login graphic component such as follows:
-
-.. sourcecode:: python
-
- class MyBlogHTMLPageHeader(HTMLPageHeader):
-
- def main_header(self, view):
- """build the top menu with authentification info and the rql box"""
- self.w(u'<table id="header"><tr>\n')
- self.w(u'<td id="firstcolumn">')
- self._cw.vreg.select_component('logo', self._cw, self.cw_rset).dispatch(w=self.w)
- self.w(u'</td>\n')
- # appliname and breadcrumbs
- self.w(u'<td id="headtext">')
- comp = self._cw.vreg.select_component('appliname', self._cw, self.cw_rset)
- if comp and comp.propval('visible'):
- comp.dispatch(w=self.w)
- comp = self._cw.vreg.select_component('breadcrumbs', self._cw, self.cw_rset, view=view)
- if comp and comp.propval('visible'):
- comp.dispatch(w=self.w, view=view)
- self.w(u'</td>')
- # logged user and help
- #self.w(u'<td>\n')
- #comp = self._cw.vreg.select_component('loggeduserlink', self._cw, self.cw_rset)
- #comp.dispatch(w=self.w)
- #self.w(u'</td><td>')
-
- self.w(u'<td>')
- helpcomp = self._cw.vreg.select_component('help', self._cw, self.cw_rset)
- if helpcomp: # may not be available if Card is not defined in the schema
- helpcomp.dispatch(w=self.w)
- self.w(u'</td>')
- # lastcolumn
- self.w(u'<td id="lastcolumn">')
- self.w(u'</td>\n')
- self.w(u'</tr></table>\n')
- self.template('logform', rset=self.cw_rset, id='popupLoginBox', klass='hidden',
- title=False, message=False)
-
-
-
-.. image:: ../../images/lax-book_06-header-no-login_en.png
-
-Customize footer
-````````````````
-
-If you want to change the footer for example, look
-for HTMLPageFooter and override it in your views file as in:
-
-.. sourcecode:: python
-
- from cubicweb.web.views.basetemplates import HTMLPageFooter
-
- class MyHTMLPageFooter(HTMLPageFooter):
-
- def call(self, **kwargs):
- self.w(u'<div class="footer">')
- self.w(u'This website has been created with <a href="http://cubicweb.org">CubicWeb</a>.')
- self.w(u'</div>')
-
-Updating a view does not require any restart of the server. By reloading
-the page you can see your new page footer.
-
-
-TheMainTemplate
-```````````````
-
-.. _TheMainTemplate:
-
-The MainTemplate is a bit complex as it tries to accomodate many
-different cases. We are now about to go through it and cutomize entirely
-our application.
-
-TheMainTemplate is responsible for the general layout of the entire application.
-It defines the template of ``__regid__ = main`` that is used by the application. Is
-also defined in ``cubicweb/web/views/basetemplates.py`` another template that can
-be used based on TheMainTemplate called SimpleMainTemplate which does not have
-a top section.
-
-.. image:: ../../images/lax-book_06-simple-main-template_en.png
-
-.. XXX
-.. [WRITE ME]
-
-* customize MainTemplate and show that everything in the user
- interface can be changed
-
--- a/etwist/twconfig.py Fri Jan 14 08:10:41 2011 +0100
+++ b/etwist/twconfig.py Wed Jan 19 09:31:15 2011 +0100
@@ -49,7 +49,7 @@
{'type' : 'string',
'default': "",
'help': 'http server address on which to listen (default to everywhere)',
- 'group': 'web', 'level': 0,
+ 'group': 'web', 'level': 1,
}),
('max-post-length',
{'type' : 'bytes',
--- a/hooks/integrity.py Fri Jan 14 08:10:41 2011 +0100
+++ b/hooks/integrity.py Wed Jan 19 09:31:15 2011 +0100
@@ -79,8 +79,6 @@
session = self.session
pendingeids = session.transaction_data.get('pendingeids', ())
pendingrtypes = session.transaction_data.get('pendingrtypes', ())
- # poping key is not optional: if further operation trigger new deletion
- # of relation, we'll need a new operation
for eid, rtype in self.get_data():
# recheck pending eids / relation types
if eid in pendingeids:
@@ -301,8 +299,6 @@
session = self.session
pendingeids = session.transaction_data.get('pendingeids', ())
neweids = session.transaction_data.get('neweids', ())
- # poping key is not optional: if further operation trigger new deletion
- # of composite relation, we'll need a new operation
for eid, rtype in self.get_data():
# don't do anything if the entity is being created or deleted
if not (eid in pendingeids or eid in neweids):
--- a/i18n/en.po Fri Jan 14 08:10:41 2011 +0100
+++ b/i18n/en.po Wed Jan 19 09:31:15 2011 +0100
@@ -328,22 +328,22 @@
msgstr "Relations"
msgid "CWSource"
-msgstr ""
+msgstr "Data source"
msgid "CWSourceHostConfig"
-msgstr ""
+msgstr "Host configuration"
msgid "CWSourceHostConfig_plural"
-msgstr ""
+msgstr "Host configurations"
msgid "CWSource_plural"
-msgstr ""
+msgstr "Data sources"
msgid "CWUniqueTogetherConstraint"
-msgstr ""
+msgstr "Unicity constraint"
msgid "CWUniqueTogetherConstraint_plural"
-msgstr ""
+msgstr "Unicity constraints"
msgid "CWUser"
msgstr "User"
@@ -525,13 +525,13 @@
msgstr "New relation"
msgid "New CWSource"
-msgstr ""
+msgstr "New source"
msgid "New CWSourceHostConfig"
-msgstr ""
+msgstr "New host configuration"
msgid "New CWUniqueTogetherConstraint"
-msgstr ""
+msgstr "New unicity constraint"
msgid "New CWUser"
msgstr "New user"
@@ -733,13 +733,13 @@
msgstr "This relation"
msgid "This CWSource"
-msgstr ""
+msgstr "This data source"
msgid "This CWSourceHostConfig"
-msgstr ""
+msgstr "This host configuration"
msgid "This CWUniqueTogetherConstraint"
-msgstr ""
+msgstr "This unicity constraint"
msgid "This CWUser"
msgstr "This user"
@@ -933,10 +933,10 @@
msgstr "relation definition"
msgid "add CWSourceHostConfig cw_host_config_of CWSource object"
-msgstr ""
+msgstr "host configuration"
msgid "add CWUniqueTogetherConstraint constraint_of CWEType object"
-msgstr ""
+msgstr "unicity constraint"
msgid "add CWUser in_group CWGroup object"
msgstr "user"
@@ -1433,18 +1433,18 @@
msgstr ""
msgid "constraint_of"
-msgstr ""
+msgstr "constraint of"
msgctxt "CWUniqueTogetherConstraint"
msgid "constraint_of"
-msgstr ""
+msgstr "constraint of"
msgctxt "CWEType"
msgid "constraint_of_object"
-msgstr ""
+msgstr "constrained by"
msgid "constraint_of_object"
-msgstr ""
+msgstr "constrained by"
msgid "constraints"
msgstr ""
@@ -1540,7 +1540,7 @@
msgid ""
"creating CWUniqueTogetherConstraint (CWUniqueTogetherConstraint "
"constraint_of CWEType %(linkto)s)"
-msgstr "creating unique together constrain for entity type %(linkto)s"
+msgstr "creating unique together constraint for entity type %(linkto)s"
msgid "creating CWUser (CWUser in_group CWGroup %(linkto)s)"
msgstr "creating a new user in group %(linkto)s"
@@ -3315,14 +3315,14 @@
msgctxt "CWAttribute"
msgid "relations_object"
-msgstr ""
-
-msgctxt "CWRelation"
+msgstr "constrained by"
+
+msgctxt "CWRType"
msgid "relations_object"
-msgstr ""
+msgstr "constrained by"
msgid "relations_object"
-msgstr ""
+msgstr "constrained by"
msgid "relative url of the bookmarked page"
msgstr ""
--- a/i18n/fr.po Fri Jan 14 08:10:41 2011 +0100
+++ b/i18n/fr.po Wed Jan 19 09:31:15 2011 +0100
@@ -347,10 +347,10 @@
msgstr "Source de données"
msgid "CWUniqueTogetherConstraint"
-msgstr "Contrainte unique_together"
+msgstr "Contrainte d'unicité"
msgid "CWUniqueTogetherConstraint_plural"
-msgstr "Contraintes unique_together"
+msgstr "Contraintes d'unicité"
msgid "CWUser"
msgstr "Utilisateur"
--- a/schema.py Fri Jan 14 08:10:41 2011 +0100
+++ b/schema.py Wed Jan 19 09:31:15 2011 +0100
@@ -83,7 +83,7 @@
'SubWorkflowExitPoint'))
INTERNAL_TYPES = set(('CWProperty', 'CWPermission', 'CWCache', 'ExternalUri',
- 'CWSource', 'CWSourceAlias',
+ 'CWSource', 'CWSourceHostConfig',
))
--- a/server/hook.py Fri Jan 14 08:10:41 2011 +0100
+++ b/server/hook.py Wed Jan 19 09:31:15 2011 +0100
@@ -225,8 +225,9 @@
Nothing precludes one to invent new categories and use the
-:class:`~cubicweb.server.session.hooks_control` context manager to filter them
-in or out.
+:class:`~cubicweb.server.session.hooks_control` context manager to
+filter them in or out. Note that ending the transaction with commit()
+or rollback() will restore the hooks.
Hooks specific selector
@@ -299,6 +300,7 @@
key=lambda x: x.order)
with security_enabled(session, write=False):
for hook in hooks:
+ #print hook.category, hook.__regid__
hook()
class HooksManager(object):
@@ -371,8 +373,23 @@
class match_rtype_sets(ExpectedValueSelector):
- """accept if parameters specified as initializer arguments are specified
- in named arguments given to the selector
+ """accept if the relation type is in one of the sets given as initializer
+ argument. The goal of this selector is that it keeps reference to original sets,
+ so modification to thoses sets are considered by the selector. For instance
+
+ MYSET = set()
+
+ class Hook1(Hook):
+ __regid__ = 'hook1'
+ __select__ = Hook.__select__ & match_rtype_sets(MYSET)
+ ...
+
+ class Hook2(Hook):
+ __regid__ = 'hook2'
+ __select__ = Hook.__select__ & match_rtype_sets(MYSET)
+
+ Client code can now change `MYSET`, this will changes the selection criteria
+ of :class:`Hook1` and :class:`Hook1`.
"""
def __init__(self, *expected):
--- a/setup.py Fri Jan 14 08:10:41 2011 +0100
+++ b/setup.py Wed Jan 19 09:31:15 2011 +0100
@@ -194,9 +194,10 @@
old_ok = DS._ok
def _ok(self, path):
"""Return True if ``path`` can be written during installation."""
- out = old_ok(self, path)
+ out = old_ok(self, path) # here for side effect from setuptools
realpath = os.path.normcase(os.path.realpath(path))
- if realpath.startswith(sys.prefix):
+ allowed_path = os.path.normcase(sys.prefix)
+ if realpath.startswith(allowed_path):
out = True
return out
DS._ok = _ok
--- a/skeleton/__pkginfo__.py.tmpl Fri Jan 14 08:10:41 2011 +0100
+++ b/skeleton/__pkginfo__.py.tmpl Wed Jan 19 09:31:15 2011 +0100
@@ -8,13 +8,13 @@
version = '.'.join(str(num) for num in numversion)
license = '%(license)s'
-
author = '%(author)s'
author_email = '%(author-email)s'
+description = '%(shortdesc)s'
+web = 'http://www.cubicweb.org/project/%%s' %% distname
-description = '%(shortdesc)s'
-
-web = 'http://www.cubicweb.org/project/%%s' %% distname
+__depends__ = %(dependencies)s
+__recommends__ = {}
from os import listdir as _listdir
@@ -40,6 +40,3 @@
# Note: here, you'll need to add subdirectories if you want
# them to be included in the debian package
-__depends__ = %(dependencies)s
-__recommends__ = {}
-
--- a/skeleton/setup.py Fri Jan 14 08:10:41 2011 +0100
+++ b/skeleton/setup.py Wed Jan 19 09:31:15 2011 +0100
@@ -1,8 +1,25 @@
#!/usr/bin/env python
-# pylint: disable=W0404,W0622,W0704,W0613
+# pylint: disable=W0142,W0403,W0404,W0613,W0622,W0622,W0704,R0904,C0103,E0611
+#
# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
-
+#
+# This file is part of CubicWeb tag cube.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+"""Generic Setup script, takes package info from __pkginfo__.py file
+"""
__docformat__ = "restructuredtext en"
import os
@@ -12,49 +29,50 @@
try:
if os.environ.get('NO_SETUPTOOLS'):
- raise ImportError()
+ raise ImportError() # do as there is no setuptools
from setuptools import setup
from setuptools.command import install_lib
- USE_SETUPTOOLS = 1
+ USE_SETUPTOOLS = True
except ImportError:
from distutils.core import setup
from distutils.command import install_lib
- USE_SETUPTOOLS = 0
+ USE_SETUPTOOLS = False
+from distutils.command import install_data
-
-sys.modules.pop('__pkginfo__', None)
# import required features
-from __pkginfo__ import modname, version, license, description, \
- web, author, author_email
-# import optional features
-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', '~')
+from __pkginfo__ import modname, version, license, description, web, \
+ author, author_email
if exists('README'):
long_description = file('README').read()
else:
long_description = ''
+
+# import optional features
+import __pkginfo__
if USE_SETUPTOOLS:
- requires = {}
- for entry in ("__depends__", "__recommends__"):
- requires.update(getattr(__pkginfo__, entry, {}))
- install_requires = [("%s %s" % (d, v and v or "")).strip()
+ 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 = []
+ install_requires = []
+
+distname = getattr(__pkginfo__, 'distname', modname)
+scripts = getattr(__pkginfo__, 'scripts', ())
+include_dirs = getattr(__pkginfo__, 'include_dirs', ())
+data_files = getattr(__pkginfo__, 'data_files', None)
+ext_modules = getattr(__pkginfo__, 'ext_modules', None)
+dependency_links = getattr(__pkginfo__, 'dependency_links', ())
+
+BASE_BLACKLIST = ('CVS', '.svn', '.hg', 'debian', 'dist', 'build')
+IGNORED_EXTENSIONS = ('.pyc', '.pyo', '.elc', '~')
def ensure_scripts(linux_scripts):
- """Creates the proper script names required for each platform
+ """
+ Creates the proper script names required for each platform
(taken from 4Suite)
"""
from distutils import util
@@ -64,23 +82,8 @@
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,
+ blacklist=BASE_BLACKLIST,
ignore_ext=IGNORED_EXTENSIONS,
verbose=True):
"""make a mirror of from_dir in to_dir, omitting directories and files
@@ -134,6 +137,35 @@
dest = join(self.install_dir, base, directory)
export(directory, dest, verbose=False)
+# re-enable copying data files in sys.prefix
+old_install_data = install_data.install_data
+if USE_SETUPTOOLS:
+ # overwrite InstallData to use sys.prefix instead of the egg directory
+ class MyInstallData(old_install_data):
+ """A class that manages data files installation"""
+ def run(self):
+ _old_install_dir = self.install_dir
+ if self.install_dir.endswith('egg'):
+ self.install_dir = sys.prefix
+ old_install_data.run(self)
+ self.install_dir = _old_install_dir
+ try:
+ import setuptools.command.easy_install # only if easy_install avaible
+ # monkey patch: Crack SandboxViolation verification
+ from setuptools.sandbox import DirectorySandbox as DS
+ old_ok = DS._ok
+ def _ok(self, path):
+ """Return True if ``path`` can be written during installation."""
+ out = old_ok(self, path) # here for side effect from setuptools
+ realpath = os.path.normcase(os.path.realpath(path))
+ allowed_path = os.path.normcase(sys.prefix)
+ if realpath.startswith(allowed_path):
+ out = True
+ return out
+ DS._ok = _ok
+ except ImportError:
+ pass
+
def install(**kwargs):
"""setup entry point"""
if USE_SETUPTOOLS:
@@ -142,9 +174,13 @@
# 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')
- if USE_SETUPTOOLS and install_requires:
+ cmdclass = {'install_lib': MyInstallLib}
+ if USE_SETUPTOOLS:
kwargs['install_requires'] = install_requires
kwargs['dependency_links'] = dependency_links
+ kwargs['zip_safe'] = False
+ cmdclass['install_data'] = MyInstallData
+
return setup(name = distname,
version = version,
license = license,
@@ -156,7 +192,7 @@
scripts = ensure_scripts(scripts),
data_files = data_files,
ext_modules = ext_modules,
- cmdclass = {'install_lib': MyInstallLib},
+ cmdclass = cmdclass,
**kwargs
)
--- a/web/uicfg.py Fri Jan 14 08:10:41 2011 +0100
+++ b/web/uicfg.py Wed Jan 19 09:31:15 2011 +0100
@@ -128,6 +128,7 @@
indexview_etype_section = InitializableDict(
EmailAddress='subobject',
# entity types in the 'system' table by default (managers only)
+ CWSource='system',
CWUser='system', CWGroup='system',
CWPermission='system',
CWCache='system',
--- a/web/views/schema.py Fri Jan 14 08:10:41 2011 +0100
+++ b/web/views/schema.py Wed Jan 19 09:31:15 2011 +0100
@@ -45,7 +45,7 @@
ALWAYS_SKIP_TYPES = BASE_TYPES | SCHEMA_TYPES
SKIP_TYPES = (ALWAYS_SKIP_TYPES | META_RTYPES | SYSTEM_RTYPES | WORKFLOW_TYPES
| INTERNAL_TYPES)
-SKIP_TYPES.update(set(('CWUser', 'CWGroup')))
+SKIP_TYPES.update(set(('CWUser', 'CWGroup', 'EmailAddress', 'Bookmark')))
def skip_types(req):
if int(req.form.get('skipmeta', True)):
--- a/web/views/sparql.py Fri Jan 14 08:10:41 2011 +0100
+++ b/web/views/sparql.py Wed Jan 19 09:31:15 2011 +0100
@@ -52,7 +52,7 @@
__regid__ = 'sparql'
def call(self):
form = self._cw.vreg['forms'].select('sparql', self._cw)
- self.w(form.render())
+ form.render(w=self.w)
sparql = self._cw.form.get('sparql')
vid = self._cw.form.get('resultvid', 'table')
if sparql:
@@ -67,7 +67,7 @@
else:
rql, args = qinfo.finalize()
if vid == 'sparqlxml':
- url = self._cw.build_url('view', rql=(rql,args), vid=vid)
+ url = self._cw.build_url('view', rql=rql % args, vid=vid)
raise Redirect(url)
rset = self._cw.execute(rql, args)
self.wview(vid, rset, 'null')