[web/test] drop dependency on third party cubes
authorPhilippe Pepiot <philippe.pepiot@logilab.fr>
Tue, 19 Mar 2019 13:17:47 +0100
changeset 12519 aff5d3498f68
parent 12518 12e8b65146d9
child 12520 c53f66bcc641
[web/test] drop dependency on third party cubes Drop dependency on cubicweb-file, cubicweb-blog and cubicweb-tag for cubicweb/web/test Copy required parts of cubes (schema, entities, views and hooks) into cubicweb/web/test/data/cubicweb-<cube> that make tests pass.
MANIFEST.in
cubicweb/web/test/data/cubicweb_blog/__init__.py
cubicweb/web/test/data/cubicweb_blog/__pkginfo__.py
cubicweb/web/test/data/cubicweb_blog/entities.py
cubicweb/web/test/data/cubicweb_blog/schema.py
cubicweb/web/test/data/cubicweb_file/__init__.py
cubicweb/web/test/data/cubicweb_file/__pkginfo__.py
cubicweb/web/test/data/cubicweb_file/data/file.png
cubicweb/web/test/data/cubicweb_file/entities.py
cubicweb/web/test/data/cubicweb_file/hooks.py
cubicweb/web/test/data/cubicweb_file/schema.py
cubicweb/web/test/data/cubicweb_file/uiprops.py
cubicweb/web/test/data/cubicweb_file/views.py
cubicweb/web/test/data/cubicweb_file/wdoc/toc.xml
cubicweb/web/test/data/cubicweb_tag/__init__.py
cubicweb/web/test/data/cubicweb_tag/__pkginfo__.py
cubicweb/web/test/data/cubicweb_tag/schema.py
cubicweb/web/test/data/cubicweb_tag/views.py
requirements/test-web.txt
--- a/MANIFEST.in	Fri Mar 15 18:07:18 2019 +0100
+++ b/MANIFEST.in	Tue Mar 19 13:17:47 2019 +0100
@@ -68,6 +68,8 @@
 recursive-include cubicweb/server/test/data-schemaserial *.py
 include cubicweb/web/test/testutils.js
 recursive-include cubicweb/web/test *.py
+include cubicweb/web/test/data/cubicweb_file/data/file.png
+include cubicweb/web/test/data/cubicweb_file/wdoc/toc.xml
 recursive-include cubicweb/web/test/data bootstrap_cubes pouet.css *.py
 recursive-include cubicweb/web/test/data/static/jstests *.js *.html *.json
 recursive-include cubicweb/wsgi/test *.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/test/data/cubicweb_blog/__pkginfo__.py	Tue Mar 19 13:17:47 2019 +0100
@@ -0,0 +1,2 @@
+numversion = (1, 2, 3)
+version = "1.2.3"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/test/data/cubicweb_blog/entities.py	Tue Mar 19 13:17:47 2019 +0100
@@ -0,0 +1,7 @@
+from cubicweb.entities import AnyEntity, fetch_config
+
+
+class BlogEntry(AnyEntity):
+    __regid__ = 'BlogEntry'
+    fetch_attrs, cw_fetch_order = fetch_config(
+        ['creation_date', 'title'], order='DESC')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/test/data/cubicweb_blog/schema.py	Tue Mar 19 13:17:47 2019 +0100
@@ -0,0 +1,22 @@
+from yams.buildobjs import EntityType, String, RichString, SubjectRelation
+from cubicweb.schema import WorkflowableEntityType, ERQLExpression
+
+
+class Blog(EntityType):
+    title = String(maxsize=50, required=True)
+    description = RichString()
+    rss_url = String(maxsize=128, description=(
+        'blog\'s rss url (useful for when using external site such as feedburner)'))
+
+
+class BlogEntry(WorkflowableEntityType):
+    __permissions__ = {
+        'read': ('managers', 'users', ERQLExpression('X in_state S, S name "published"'),),
+        'add': ('managers', 'users'),
+        'update': ('managers', 'owners'),
+        'delete': ('managers', 'owners')
+    }
+    title = String(required=True, fulltextindexed=True, maxsize=256)
+    content = RichString(required=True, fulltextindexed=True)
+    entry_of = SubjectRelation('Blog')
+    same_as = SubjectRelation('ExternalUri')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/test/data/cubicweb_file/__pkginfo__.py	Tue Mar 19 13:17:47 2019 +0100
@@ -0,0 +1,2 @@
+numversion = (1, 2, 3)
+version = "1.2.3"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/test/data/cubicweb_file/entities.py	Tue Mar 19 13:17:47 2019 +0100
@@ -0,0 +1,51 @@
+from six import text_type
+from logilab.mtconverter import guess_mimetype_and_encoding
+from cubicweb.entities import AnyEntity, fetch_config
+
+
+class File(AnyEntity):
+    """customized class for File entities"""
+    __regid__ = 'File'
+    fetch_attrs, cw_fetch_order = fetch_config(['data_name', 'title'])
+
+    def set_format_and_encoding(self):
+        """try to set format and encoding according to known values (filename,
+        file content, format, encoding).
+
+        This method must be called in a before_[add|update]_entity hook else it
+        won't have any effect.
+        """
+        assert 'data' in self.cw_edited, "missing mandatory attribute data"
+        if self.cw_edited.get('data'):
+            if (hasattr(self.data, 'filename')
+                    and not self.cw_edited.get('data_name')):
+                self.cw_edited['data_name'] = self.data.filename
+        else:
+            self.cw_edited['data_format'] = None
+            self.cw_edited['data_encoding'] = None
+            self.cw_edited['data_name'] = None
+            return
+        if 'data_format' in self.cw_edited:
+            format = self.cw_edited.get('data_format')
+        else:
+            format = None
+        if 'data_encoding' in self.cw_edited:
+            encoding = self.cw_edited.get('data_encoding')
+        else:
+            encoding = None
+        if not (format and encoding):
+            format, encoding = guess_mimetype_and_encoding(
+                data=self.cw_edited.get('data'),
+                # use get and not get_value since data has changed, we only
+                # want to consider explicitly specified values, not old ones
+                filename=self.cw_edited.get('data_name'),
+                format=format, encoding=encoding,
+                fallbackencoding=self._cw.encoding)
+            if format:
+                self.cw_edited['data_format'] = text_type(format)
+            if encoding:
+                self.cw_edited['data_encoding'] = text_type(encoding)
+
+
+class UnResizeable(Exception):
+    pass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/test/data/cubicweb_file/hooks.py	Tue Mar 19 13:17:47 2019 +0100
@@ -0,0 +1,69 @@
+import os
+
+from cubicweb.server import hook
+from cubicweb.predicates import is_instance
+from cubicweb.entities import adapters
+
+from cubicweb_file.entities import UnResizeable
+
+
+class UpdateFileHook(hook.Hook):
+    """a file has been updated, check data_format/data_encoding consistency
+    """
+    __regid__ = 'updatefilehook'
+    __select__ = hook.Hook.__select__ & is_instance('File')
+    events = ('before_add_entity', 'before_update_entity',)
+    order = -1  # should be run before other hooks
+    category = 'hash'
+
+    def __call__(self):
+        edited = self.entity.cw_edited
+        if 'data' in edited:
+            self.entity.set_format_and_encoding()
+            maxsize = None
+            if maxsize and self.entity.data_format.startswith('image/'):
+                iimage = self.entity.cw_adapt_to('IImage')
+                try:
+                    edited['data'] = iimage.resize(maxsize)
+                except UnResizeable:
+                    # if the resize fails for some reason, do nothing
+                    # (original image will be stored)
+                    pass
+
+            # thumbnail cache invalidation
+            if 'update' in self.event and 'data' in edited:
+                thumb = self.entity.cw_adapt_to('IThumbnail')
+                if not thumb:
+                    return
+                thumbpath = thumb.thumbnail_path()
+                if thumbpath:
+                    try:
+                        os.unlink(thumbpath)
+                    except Exception as exc:
+                        self.warning(
+                            'could not invalidate thumbnail file `%s` '
+                            '(cause: %s)',
+                            thumbpath, exc)
+
+
+class FileIDownloadableAdapter(adapters.IDownloadableAdapter):
+    __select__ = is_instance('File')
+
+    # IDownloadable
+    def download_url(self, **kwargs):
+        # include filename in download url for nicer url
+        name = self._cw.url_quote(self.download_file_name())
+        path = '%s/raw/%s' % (self.entity.rest_path(), name)
+        return self._cw.build_url(path, **kwargs)
+
+    def download_content_type(self):
+        return self.entity.data_format
+
+    def download_encoding(self):
+        return self.entity.data_encoding
+
+    def download_file_name(self):
+        return self.entity.data_name
+
+    def download_data(self):
+        return self.entity.data.getvalue()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/test/data/cubicweb_file/schema.py	Tue Mar 19 13:17:47 2019 +0100
@@ -0,0 +1,27 @@
+from yams.buildobjs import EntityType, String, Bytes, RichString
+
+
+class File(EntityType):
+    """a downloadable file which may contains binary data"""
+    title = String(fulltextindexed=True, maxsize=256)
+    data = Bytes(required=True, description='file to upload')
+    data_format = String(
+        required=True, maxsize=128,
+        description=('MIME type of the file. Should be dynamically set '
+                     'at upload time.'))
+    data_encoding = String(
+        maxsize=32,
+        description=('encoding of the file when it applies (e.g. text). '
+                     'Should be dynamically set at upload time.'))
+    data_name = String(
+        required=True, fulltextindexed=True,
+        description=('name of the file. Should be dynamically set '
+                     'at upload time.'))
+    data_hash = String(
+        maxsize=256,  # max len of currently available hash alg + prefix is 140
+        description=('hash of the file. May be set at upload time.'),
+        __permissions__={'read': ('managers', 'users', 'guests'),
+                         'add': (),
+                         'update': ()})
+    description = RichString(fulltextindexed=True, internationalizable=True,
+                             default_format='text/rest')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/test/data/cubicweb_file/uiprops.py	Tue Mar 19 13:17:47 2019 +0100
@@ -0,0 +1,1 @@
+FILE_ICON = data('file.png')  # noqa: F821
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/test/data/cubicweb_file/views.py	Tue Mar 19 13:17:47 2019 +0100
@@ -0,0 +1,9 @@
+from cubicweb.web import formwidgets as wdgs
+from cubicweb.web.views import uicfg
+
+# fields required in the schema but automatically set by hooks. Tell about that
+# to the ui
+_pvdc = uicfg.autoform_field_kwargs
+_pvdc.tag_attribute(('File', 'data_name'), {
+    'required': False, 'widget': wdgs.TextInput({'size': 45})})
+_pvdc.tag_attribute(('File', 'data_format'), {'required': False})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/test/data/cubicweb_file/wdoc/toc.xml	Tue Mar 19 13:17:47 2019 +0100
@@ -0,0 +1,6 @@
+<toc>
+  <section resource="add_file" appendto="add_content">
+    <title xml:lang="en">Add an attachement</title>
+    <title xml:lang="fr">Ajouter un fichier</title>
+  </section>
+</toc>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/test/data/cubicweb_tag/__pkginfo__.py	Tue Mar 19 13:17:47 2019 +0100
@@ -0,0 +1,2 @@
+numversion = (1, 2, 3)
+version = "1.2.3"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/test/data/cubicweb_tag/schema.py	Tue Mar 19 13:17:47 2019 +0100
@@ -0,0 +1,17 @@
+from yams.buildobjs import EntityType, String, SubjectRelation, RelationType
+
+
+class Tag(EntityType):
+    """tags are used by users to mark entities.
+    When you include the Tag entity, all application specific entities
+    may then be tagged using the "tags" relation.
+    """
+    name = String(required=True, fulltextindexed=True, unique=True,
+                  maxsize=128)
+    # when using this component, add the Tag tag X relation for each type that
+    # should be taggeable
+    tags = SubjectRelation('Tag', description="tagged objects")
+
+
+class tags(RelationType):
+    """indicates that an entity is classified by a given tag"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/web/test/data/cubicweb_tag/views.py	Tue Mar 19 13:17:47 2019 +0100
@@ -0,0 +1,28 @@
+from cubicweb.web import component
+from cubicweb.web.views import ajaxcontroller
+
+
+@ajaxcontroller.ajaxfunc
+def tag_entity(self, eid, taglist):
+    execute = self._cw.execute
+    # get list of tag for this entity
+    tagged_by = set(tagname for (tagname,) in
+                    execute('Any N WHERE T name N, T tags X, X eid %(x)s',
+                            {'x': eid}))
+    for tagname in taglist:
+        tagname = tagname.strip()
+        if not tagname or tagname in tagged_by:
+            continue
+        tagrset = execute('Tag T WHERE T name %(name)s', {'name': tagname})
+        if tagrset:
+            rql = 'SET T tags X WHERE T eid %(t)s, X eid %(x)s'
+            execute(rql, {'t': tagrset[0][0], 'x': eid})
+        else:
+            rql = 'INSERT Tag T: T name %(name)s, T tags X WHERE X eid %(x)s'
+            execute(rql, {'name': tagname, 'x': eid})
+
+
+class TagsBox(component.AjaxEditRelationCtxComponent):
+    __regid__ = 'tags_box'
+    rtype = 'tags'
+    role = 'object'
--- a/requirements/test-web.txt	Fri Mar 15 18:07:18 2019 +0100
+++ b/requirements/test-web.txt	Tue Mar 19 13:17:47 2019 +0100
@@ -2,6 +2,3 @@
 Twisted < 16.0.0
 requests
 webtest
-cubicweb-blog
-cubicweb-file >= 2.0.0
-cubicweb-tag