[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.
--- 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