doc/tutorials/advanced/part03_bfss.rst
changeset 10491 c67bcee93248
parent 10376 b566c8081832
child 12209 3a3551fff787
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/advanced/part03_bfss.rst	Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,131 @@
+Storing images on the file-system
+---------------------------------
+
+Step 1: configuring the BytesFileSystem storage
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To avoid cluttering my database, and to ease file manipulation, I don't want them
+to be stored in the database. I want to be able create File entities for some
+files on the server file system, where those file will be accessed to get
+entities data. To do so I've to set a custom :class:`BytesFileSystemStorage`
+storage for the File 'data' attribute, which hold the actual file's content.
+
+Since the function to register a custom storage needs to have a repository
+instance as first argument, we've to call it in a server startup hook. So I added
+in `cubes/sytweb/hooks.py` :
+
+.. sourcecode:: python
+
+    from os import makedirs
+    from os.path import join, exists
+
+    from cubicweb.server import hook
+    from cubicweb.server.sources import storages
+
+    class ServerStartupHook(hook.Hook):
+        __regid__ = 'sytweb.serverstartup'
+        events = ('server_startup', 'server_maintenance')
+
+        def __call__(self):
+            bfssdir = join(self.repo.config.appdatahome, 'bfss')
+            if not exists(bfssdir):
+                makedirs(bfssdir)
+                print 'created', bfssdir
+            storage = storages.BytesFileSystemStorage(bfssdir)
+            storages.set_attribute_storage(self.repo, 'File', 'data', storage)
+
+.. Note::
+
+  * how we built the hook's registry identifier (`__regid__`): you can introduce
+    'namespaces' by using there python module like naming identifiers. This is
+    especially important for hooks where you usually want a new custom hook, not
+    overriding / specializing an existant one, but the concept may be applied to
+    any application objects
+
+  * we catch two events here: "server_startup" and "server_maintenance". The first
+    is called on regular repository startup (eg, as a server), the other for
+    maintenance task such as shell or upgrade. In both cases, we need to have
+    the storage set, else we'll be in trouble...
+
+  * the path given to the storage is the place where file added through the ui
+    (or in the database before migration) will be located
+
+  * beware that by doing this, you can't anymore write queries that will try to
+    restrict on File `data` attribute. Hopefuly we don't do that usually
+    on file's content or more generally on attributes for the Bytes type
+
+Now, if you've already added some photos through the web ui, you'll have to
+migrate existing data so file's content will be stored on the file-system instead
+of the database. There is a migration command to do so, let's run it in the
+cubicweb shell (in real life, you would have to put it in a migration script as we
+have seen last time):
+
+::
+
+   $ cubicweb-ctl shell sytweb_instance
+   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
+   >>> storage_changed('File', 'data')
+   [........................]
+
+
+That's it. Now, files added through the web ui will have their content stored on
+the file-system, and you'll also be able to import files from the file-system as
+explained in the next part.
+
+Step 2: importing some data into the instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Hey, we start to have some nice features, let us give a try to this new web
+site. For instance if I have a 'photos/201005WePyrenees' containing pictures for
+a particular event, I can import it to my web site by typing ::
+
+  $ cubicweb-ctl fsimport -F sytweb_instance photos/201005WePyrenees/
+  ** importing directory /home/syt/photos/201005WePyrenees
+  importing IMG_8314.JPG
+  importing IMG_8274.JPG
+  importing IMG_8286.JPG
+  importing IMG_8308.JPG
+  importing IMG_8304.JPG
+
+.. Note::
+  The -F option means that folders should be mapped, hence my photos will be
+  linked to a Folder entity corresponding to the file-system folder.
+
+Let's take a look at the web ui:
+
+.. image:: ../../images/tutos-photowebsite_ui1.png
+
+Nothing different, I can't see the new folder... But remember our security model!
+By default, files are only accessible to authenticated users, and I'm looking at
+the site as anonymous, e.g. not authenticated. If I login, I can now see:
+
+.. image:: ../../images/tutos-photowebsite_ui2.png
+
+Yeah, it's there! You will notice that I can see some entities as well as
+folders and images the anonymous user can't. It just works **everywhere in the
+ui** since it's handled at the repository level, thanks to our security model.
+
+Now if I click on the recently inserted folder, I can see
+
+.. image:: ../../images/tutos-photowebsite_ui3.png
+
+Great! There is even my pictures in the folder. I can know give to this folder a
+nicer name (provided I don't intend to import from it anymore, else already
+imported photos will be reimported), change permissions, title for some pictures,
+etc... Having a good content is much more difficult than having a good web site
+;)
+
+
+Conclusion
+~~~~~~~~~~
+
+We started to see here an advanced feature of our repository: the ability
+to store some parts of our data-model into a custom storage, outside the
+database. There is currently only the :class:`BytesFileSystemStorage` available,
+but you can expect to see more coming in a near future (or write your own!).
+
+Also, we can know start to feed our web-site with some nice pictures!
+The site isn't perfect (far from it actually) but it's usable, and we can
+now start using it and improve it on the way. The Incremental Cubic Way :)