Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@sugarlabs.org>2014-03-12 11:17:00 (GMT)
committer Aleksey Lim <alsroot@sugarlabs.org>2014-03-12 11:17:00 (GMT)
commitae31651d6ae31215db903530115bf340ae9f98f5 (patch)
tree7d5a5083eee504a74d4b5ca4c249959e83f78392
parent47be127e9955013ddc5563013ded534cc3952ef1 (diff)
More cleanups
* iterate metadata props in the same order all time; * clear separation between original and posted props in db.Resource; * access to assetes directory from blobs iface.
-rw-r--r--sugar_network/assets/__init__.py19
-rw-r--r--sugar_network/assets/activity.svg (renamed from blobs/activity.svg)0
-rw-r--r--sugar_network/assets/book.svg (renamed from blobs/book.svg)0
-rw-r--r--sugar_network/assets/favicon.ico (renamed from blobs/favicon.ico)bin1150 -> 1150 bytes
-rw-r--r--sugar_network/assets/group.svg (renamed from blobs/group.svg)0
-rw-r--r--sugar_network/assets/missing-logo.png (renamed from blobs/missing-logo.png)bin4073 -> 4073 bytes
-rw-r--r--sugar_network/assets/missing.png (renamed from blobs/missing.png)bin1566 -> 1566 bytes
-rw-r--r--sugar_network/assets/missing.svg (renamed from blobs/missing.svg)0
-rw-r--r--sugar_network/assets/package-logo.png (renamed from blobs/package-logo.png)bin2874 -> 2874 bytes
-rw-r--r--sugar_network/assets/package.png (renamed from blobs/package.png)bin1199 -> 1199 bytes
-rw-r--r--sugar_network/assets/package.svg (renamed from blobs/package.svg)0
-rw-r--r--sugar_network/db/blobs.py24
-rw-r--r--sugar_network/db/directory.py16
-rw-r--r--sugar_network/db/metadata.py6
-rw-r--r--sugar_network/db/resource.py44
-rw-r--r--sugar_network/db/routes.py42
-rw-r--r--sugar_network/model/__init__.py28
-rw-r--r--sugar_network/model/context.py41
-rw-r--r--sugar_network/model/post.py2
-rw-r--r--sugar_network/toolkit/__init__.py5
-rwxr-xr-xtests/integration/master_personal.py12
-rwxr-xr-xtests/integration/master_slave.py20
-rwxr-xr-xtests/units/db/resource.py92
-rwxr-xr-xtests/units/db/routes.py30
-rwxr-xr-xtests/units/model/context.py41
-rwxr-xr-xtests/units/model/model.py10
26 files changed, 320 insertions, 112 deletions
diff --git a/sugar_network/assets/__init__.py b/sugar_network/assets/__init__.py
new file mode 100644
index 0000000..7ad1378
--- /dev/null
+++ b/sugar_network/assets/__init__.py
@@ -0,0 +1,19 @@
+# Copyright (C) 2014 Aleksey Lim
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from os.path import dirname
+
+
+PATH = dirname(__file__)
diff --git a/blobs/activity.svg b/sugar_network/assets/activity.svg
index c5302fd..c5302fd 100644
--- a/blobs/activity.svg
+++ b/sugar_network/assets/activity.svg
diff --git a/blobs/book.svg b/sugar_network/assets/book.svg
index 92fb811..92fb811 100644
--- a/blobs/book.svg
+++ b/sugar_network/assets/book.svg
diff --git a/blobs/favicon.ico b/sugar_network/assets/favicon.ico
index 80e42ba..80e42ba 100644
--- a/blobs/favicon.ico
+++ b/sugar_network/assets/favicon.ico
Binary files differ
diff --git a/blobs/group.svg b/sugar_network/assets/group.svg
index c9a6b64..c9a6b64 100644
--- a/blobs/group.svg
+++ b/sugar_network/assets/group.svg
diff --git a/blobs/missing-logo.png b/sugar_network/assets/missing-logo.png
index 98be121..98be121 100644
--- a/blobs/missing-logo.png
+++ b/sugar_network/assets/missing-logo.png
Binary files differ
diff --git a/blobs/missing.png b/sugar_network/assets/missing.png
index 91a65a8..91a65a8 100644
--- a/blobs/missing.png
+++ b/sugar_network/assets/missing.png
Binary files differ
diff --git a/blobs/missing.svg b/sugar_network/assets/missing.svg
index 7e6a568..7e6a568 100644
--- a/blobs/missing.svg
+++ b/sugar_network/assets/missing.svg
diff --git a/blobs/package-logo.png b/sugar_network/assets/package-logo.png
index c6cf086..c6cf086 100644
--- a/blobs/package-logo.png
+++ b/sugar_network/assets/package-logo.png
Binary files differ
diff --git a/blobs/package.png b/sugar_network/assets/package.png
index 24bd5ac..24bd5ac 100644
--- a/blobs/package.png
+++ b/sugar_network/assets/package.png
Binary files differ
diff --git a/blobs/package.svg b/sugar_network/assets/package.svg
index a5fd32d..a5fd32d 100644
--- a/blobs/package.svg
+++ b/sugar_network/assets/package.svg
diff --git a/sugar_network/db/blobs.py b/sugar_network/db/blobs.py
index 084ffde..cfbe517 100644
--- a/sugar_network/db/blobs.py
+++ b/sugar_network/db/blobs.py
@@ -20,7 +20,7 @@ import mimetypes
from contextlib import contextmanager
from os.path import exists, abspath, join, dirname, isdir
-from sugar_network import toolkit
+from sugar_network import toolkit, assets
from sugar_network.toolkit.router import File
from sugar_network.toolkit import http, ranges, enforce
@@ -40,11 +40,16 @@ class Blobs(object):
def root(self):
return self._root
- def path(self, *args):
- if len(args) == 1 and len(args[0]) == 40 and '.' not in args[0]:
- return self._blob_path(args[0])
- else:
- return join(self._root, 'files', *args)
+ def path(self, path=None):
+ if path is None:
+ return join(self._root, 'files')
+ if isinstance(path, basestring):
+ path = path.split(os.sep)
+ if len(path) == 1 and len(path[0]) == 40 and '.' not in path[0]:
+ return self._blob_path(path[0])
+ if path[0] == 'assets':
+ return join(assets.PATH, *path[1:])
+ return join(self._root, 'files', *path)
def post(self, content, mime_type=None, digest_to_assert=None, meta=None):
if meta is None:
@@ -110,9 +115,11 @@ class Blobs(object):
return File(path, digest, _read_meta(path))
elif isdir(path):
return _lsdir(path, digest)
+ elif exists(path):
+ return File(path, digest)
def delete(self, path):
- self._delete(path, None)
+ self._delete(self.path(path), None)
def populate(self, path=None, recursive=True):
for __ in self.diff([[1, None]], path or '', recursive):
@@ -127,7 +134,7 @@ class Blobs(object):
enforce(not [i for i in path if i == '..'],
http.BadRequest, 'Relative paths are not allowed')
is_files = True
- root = self.path(*path)
+ root = self.path(path)
checkin_seqno = None
for root, __, files in os.walk(root):
@@ -203,7 +210,6 @@ class Blobs(object):
os.utime(path, (seqno, seqno))
def _delete(self, path, seqno):
- path = self.path(path)
if exists(path + _META_SUFFIX):
if seqno is None:
seqno = self._seqno.next()
diff --git a/sugar_network/db/directory.py b/sugar_network/db/directory.py
index 3ef4b91..9ebf907 100644
--- a/sugar_network/db/directory.py
+++ b/sugar_network/db/directory.py
@@ -202,7 +202,7 @@ class Directory(object):
if doc.post_seqno is not None and doc.exists:
# No need in after-merge event, further commit event
# is enough to avoid increasing events flow
- self._index.store(guid, doc.props, self._preindex)
+ self._index.store(guid, doc.origs, self._preindex)
return seqno
@@ -227,18 +227,16 @@ class Directory(object):
doc = self.resource(guid, self._storage.get(guid), changes)
for prop in self.metadata:
enforce(doc[prop] is not None, 'Empty %r property', prop)
- return doc.props
+ return doc
def _prestore(self, guid, changes, event):
- doc = self.resource(guid, self._storage.get(guid))
+ doc = self.resource(guid, self._storage.get(guid), posts=changes)
doc.post_seqno = self._seqno.next()
+ for prop in changes.keys():
+ doc.post(prop, changes[prop])
for prop in self.metadata.keys():
- value = changes.get(prop)
- if value is None:
- enforce(doc[prop] is not None, 'Empty %r property', prop)
- else:
- doc.post(prop, value)
- return doc.props
+ enforce(doc[prop] is not None, 'Empty %r property', prop)
+ return doc
def _postdelete(self, guid, event):
self._storage.delete(guid)
diff --git a/sugar_network/db/metadata.py b/sugar_network/db/metadata.py
index ecefdab..31cace1 100644
--- a/sugar_network/db/metadata.py
+++ b/sugar_network/db/metadata.py
@@ -102,11 +102,17 @@ class Metadata(dict):
self[prop.name] = prop
+ self._keys = dict.keys(self)
+ self._keys.sort()
+
@property
def name(self):
"""Resource type name."""
return self._name
+ def keys(self):
+ return self._keys
+
def __getitem__(self, prop_name):
enforce(prop_name in self, http.NotFound,
'There is no %r property in %r', prop_name, self.name)
diff --git a/sugar_network/db/resource.py b/sugar_network/db/resource.py
index 9d94929..d17637d 100644
--- a/sugar_network/db/resource.py
+++ b/sugar_network/db/resource.py
@@ -29,8 +29,9 @@ class Resource(object):
#: Whether these resources should be migrated from slave-to-master only
one_way = False
- def __init__(self, guid, record, cached_props=None):
- self.props = cached_props or {}
+ def __init__(self, guid, record, origs=None, posts=None):
+ self.origs = origs or {}
+ self.posts = posts or {}
self.guid = guid
self.is_new = not bool(guid)
self.record = record
@@ -69,7 +70,7 @@ class Resource(object):
@layer.setter
def layer(self, value):
- orig = self['layer']
+ orig = self.orig('layer')
if 'deleted' in value:
if this.request.method != 'POST' and 'deleted' not in orig:
self.deleted()
@@ -91,7 +92,7 @@ class Resource(object):
def restored(self):
pass
- def get(self, prop):
+ def get(self, prop, default=None):
"""Get document's property value.
:param prop:
@@ -100,15 +101,31 @@ class Resource(object):
`prop` value
"""
+ value = self.posts.get(prop)
+ if value is None:
+ value = self.orig(prop)
+ if value is None:
+ value = default
+ return value
+
+ def orig(self, prop):
+ """Get document's property original value.
+
+ :param prop:
+ property name to get value
+ :returns:
+ `prop` value
+
+ """
prop = self.metadata[prop]
- value = self.props.get(prop.name)
+ value = self.origs.get(prop.name)
if value is None and self.record is not None:
meta = self.record.get(prop.name)
if meta is not None:
value = meta.get('value')
else:
value = prop.default
- self.props[prop.name] = value
+ self.origs[prop.name] = value
return value
def properties(self, props):
@@ -168,18 +185,15 @@ class Resource(object):
for agg in value.values():
agg['seqno'] = self.post_seqno
if isinstance(prop, Composite):
- old_value = self[prop.name]
- if old_value:
- old_value.update(value)
- value = old_value
+ orig_value = self.orig(prop.name)
+ if orig_value:
+ orig_value.update(value)
+ value = orig_value
self.record.set(prop.name, value=value, seqno=self.post_seqno, **meta)
- self.props[prop.name] = value
-
- def _set(self, prop, value):
- self.props[prop] = value
+ self.posts[prop.name] = value
def __contains__(self, prop):
- return prop in self.props
+ return prop in self.origs or prop in self.posts
def __getitem__(self, prop):
return self.get(prop)
diff --git a/sugar_network/db/routes.py b/sugar_network/db/routes.py
index 153e0a7..e1f190c 100644
--- a/sugar_network/db/routes.py
+++ b/sugar_network/db/routes.py
@@ -40,8 +40,8 @@ class Routes(object):
@route('POST', [None], acl=ACL.AUTH, mime_type='application/json')
def create(self, request):
with self._post(request, ACL.CREATE) as doc:
- self.on_create(request, doc.props)
- self.volume[request.resource].create(doc.props)
+ self.on_create(request, doc.posts)
+ self.volume[request.resource].create(doc.posts)
self.after_post(doc)
return doc['guid']
@@ -78,10 +78,10 @@ class Routes(object):
@route('PUT', [None, None], acl=ACL.AUTH | ACL.AUTHOR)
def update(self, request):
with self._post(request, ACL.WRITE) as doc:
- if not doc.props:
+ if not doc.posts:
return
- self.on_update(request, doc.props)
- self.volume[request.resource].update(doc.guid, doc.props)
+ self.on_update(request, doc.posts)
+ self.volume[request.resource].update(doc.guid, doc.posts)
self.after_post(doc)
@route('PUT', [None, None, None], acl=ACL.AUTH | ACL.AUTHOR)
@@ -209,32 +209,28 @@ class Routes(object):
enforce(_GUID_RE.match(guid) is not None,
http.BadRequest, 'Malformed %s GUID', guid)
else:
- doc.props['guid'] = toolkit.uuid()
+ doc.posts['guid'] = toolkit.uuid()
for name, prop in directory.metadata.items():
if name not in content and prop.default is not None:
- doc.props[name] = prop.default
- orig = None
- this.resource = doc
+ doc.posts[name] = prop.default
else:
doc = directory.get(request.guid)
- orig = directory.get(request.guid)
- this.resource = orig
+ this.resource = doc
- def teardown(new):
- if orig is None:
- return
- for name, orig_value in orig.props.items():
- if doc[name] == orig_value:
- continue
- prop = directory.metadata[name]
- prop.teardown(doc[name] if new else orig_value)
+ def teardown(new, old):
+ for name, value in new.items():
+ if old.get(name) != value:
+ directory.metadata[name].teardown(value)
try:
for name, value in content.items():
prop = directory.metadata[name]
- prop.assert_access(access, orig[name] if orig else None)
+ prop.assert_access(access, doc.orig(name))
+ if value is None:
+ doc.posts[name] = prop.default
+ continue
try:
- doc.props[name] = prop.typecast(value)
+ doc.posts[name] = prop.typecast(value)
except Exception, error:
error = 'Value %r for %r property is invalid: %s' % \
(value, prop.name, error)
@@ -242,10 +238,10 @@ class Routes(object):
raise http.BadRequest(error)
yield doc
except Exception:
- teardown(True)
+ teardown(doc.posts, doc.origs)
raise
else:
- teardown(False)
+ teardown(doc.origs, doc.posts)
def _preget(self, request):
reply = request.get('reply')
diff --git a/sugar_network/model/__init__.py b/sugar_network/model/__init__.py
index 5068a63..77a322c 100644
--- a/sugar_network/model/__init__.py
+++ b/sugar_network/model/__init__.py
@@ -58,6 +58,9 @@ RESOURCES = (
'sugar_network.model.user',
)
+ICON_SIZE = 55
+LOGO_SIZE = 140
+
_logger = logging.getLogger('model')
@@ -118,16 +121,6 @@ def generate_node_stats(volume):
volume['post'].update(topic.guid, {'rating': rating})
-def populate_context_images(props, svg):
- if 'guid' in props:
- from sugar_network.toolkit.sugar import color_svg
- svg = color_svg(svg, props['guid'])
- blobs = this.volume.blobs
- props['artifact_icon'] = blobs.post(svg, 'image/svg+xml').digest
- props['icon'] = blobs.post(svg_to_png(svg, 55, 55), 'image/png').digest
- props['logo'] = blobs.post(svg_to_png(svg, 140, 140), 'image/png').digest
-
-
def load_bundle(blob, context=None, initial=False, extra_deps=None):
contexts = this.volume['context']
context_type = None
@@ -215,7 +208,7 @@ def load_bundle(blob, context=None, initial=False, extra_deps=None):
patch = context_doc.format_patch(context_meta)
if patch:
this.call(method='PUT', path=['context', context], content=patch)
- context_doc.props.update(patch)
+ context_doc.posts.update(patch)
# TRANS: Release notes title
title = i18n._('%(name)s %(version)s release')
else:
@@ -250,8 +243,19 @@ def _load_context_metadata(bundle, spec):
result['guid'] = spec['context']
try:
+ from sugar_network.toolkit.sugar import color_svg
+
icon_file = bundle.extractfile(join(bundle.rootdir, spec['icon']))
- populate_context_images(result, icon_file.read())
+ svg = color_svg(icon_file.read(), result['guid'])
+ blobs = this.volume.blobs
+
+ result['artefact_icon'] = \
+ blobs.post(svg, 'image/svg+xml').digest
+ result['icon'] = \
+ blobs.post(svg_to_png(svg, ICON_SIZE), 'image/png').digest
+ result['logo'] = \
+ blobs.post(svg_to_png(svg, LOGO_SIZE), 'image/png').digest
+
icon_file.close()
except Exception:
exception(_logger, 'Failed to load icon')
diff --git a/sugar_network/model/context.py b/sugar_network/model/context.py
index 951aad1..3aceacc 100644
--- a/sugar_network/model/context.py
+++ b/sugar_network/model/context.py
@@ -16,6 +16,7 @@
from sugar_network import db, model
from sugar_network.toolkit.coroutine import this
from sugar_network.toolkit.router import ACL
+from sugar_network.toolkit import svg_to_png
class Context(db.Resource):
@@ -27,8 +28,34 @@ class Context(db.Resource):
@type.setter
def type(self, value):
- if 'package' in value and 'common' not in self['layer']:
- self.post('layer', self['layer'] + ['common'])
+ if 'package' in value:
+ self.post('icon', 'assets/package.png')
+ self.post('logo', 'assets/package-logo.png')
+ self.post('artefact_icon', 'assets/package.svg')
+ return value
+
+ svg = None
+ blobs = this.volume.blobs
+ if not self['artefact_icon']:
+ for type_ in ('activity', 'book', 'group'):
+ if type_ in value:
+ with file(blobs.get('assets/%s.svg' % type_).path) as f:
+ svg = f.read()
+ from sugar_network.toolkit.sugar import color_svg
+ svg = color_svg(svg, self['guid'])
+ self.post('artefact_icon',
+ blobs.post(svg, 'image/svg+xml').digest)
+ break
+ for prop, png, size in (
+ ('icon', 'assets/missing.png', model.ICON_SIZE),
+ ('logo', 'assets/missing-logo.svg', model.LOGO_SIZE),
+ ):
+ if self[prop]:
+ continue
+ if svg is not None:
+ png = blobs.post(svg_to_png(svg, size), 'image/png').digest
+ self.post(prop, png)
+
return value
@db.indexed_property(db.Localized, slot=1, prefix='S', full_text=True)
@@ -51,17 +78,15 @@ class Context(db.Resource):
def mime_types(self, value):
return value
- @db.stored_property(db.Blob, mime_type='image/png', default='missing.png')
+ @db.stored_property(db.Blob, mime_type='image/png')
def icon(self, value):
return value
- @db.stored_property(db.Blob, mime_type='image/svg+xml',
- default='missing.svg')
- def artifact_icon(self, value):
+ @db.stored_property(db.Blob, mime_type='image/svg+xml')
+ def artefact_icon(self, value):
return value
- @db.stored_property(db.Blob, mime_type='image/png',
- default='missing-logo.png')
+ @db.stored_property(db.Blob, mime_type='image/png')
def logo(self, value):
return value
diff --git a/sugar_network/model/post.py b/sugar_network/model/post.py
index 107f354..21046f2 100644
--- a/sugar_network/model/post.py
+++ b/sugar_network/model/post.py
@@ -70,7 +70,7 @@ class Post(db.Resource):
return value
@db.stored_property(db.Blob, mime_type='image/png',
- default='missing-logo.png')
+ default='assets/missing-logo.png')
def preview(self, value):
return value
diff --git a/sugar_network/toolkit/__init__.py b/sugar_network/toolkit/__init__.py
index 89a9d0f..67ee7da 100644
--- a/sugar_network/toolkit/__init__.py
+++ b/sugar_network/toolkit/__init__.py
@@ -432,10 +432,13 @@ class mkdtemp(str):
shutil.rmtree(self)
-def svg_to_png(data, w, h):
+def svg_to_png(data, w, h=None):
import rsvg
import cairo
+ if h is None:
+ h = w
+
svg = rsvg.Handle(data=data)
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
context = cairo.Context(surface)
diff --git a/tests/integration/master_personal.py b/tests/integration/master_personal.py
index 7bfa6aa..7057c0b 100755
--- a/tests/integration/master_personal.py
+++ b/tests/integration/master_personal.py
@@ -77,7 +77,7 @@ class MasterPersonalTest(tests.Test):
'title': 'title_1',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo1',
'layer': 'pilot',
})
@@ -86,7 +86,7 @@ class MasterPersonalTest(tests.Test):
'title': 'title_2',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo2',
'layer': 'pilot',
})
@@ -97,7 +97,7 @@ class MasterPersonalTest(tests.Test):
'title': 'title_3',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo3',
'layer': 'pilot',
})
@@ -106,7 +106,7 @@ class MasterPersonalTest(tests.Test):
'title': 'title_4',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo4',
'layer': 'pilot',
})
@@ -133,7 +133,7 @@ class MasterPersonalTest(tests.Test):
'title': 'title_5',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo5',
'layer': 'pilot',
})
@@ -146,7 +146,7 @@ class MasterPersonalTest(tests.Test):
'title': 'title_6',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo6',
'layer': 'pilot',
})
diff --git a/tests/integration/master_slave.py b/tests/integration/master_slave.py
index c9981df..8be40b0 100755
--- a/tests/integration/master_slave.py
+++ b/tests/integration/master_slave.py
@@ -65,7 +65,7 @@ class MasterSlaveTest(tests.Test):
'title': 'title1',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo1',
'layer': 'pilot',
})
@@ -76,7 +76,7 @@ class MasterSlaveTest(tests.Test):
'title': 'title2',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo2',
'layer': 'pilot',
})
@@ -117,7 +117,7 @@ class MasterSlaveTest(tests.Test):
'title': 'title3',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo3',
'layer': 'pilot',
})
@@ -131,7 +131,7 @@ class MasterSlaveTest(tests.Test):
'title': 'title4',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo4',
'layer': 'pilot',
})
@@ -191,7 +191,7 @@ class MasterSlaveTest(tests.Test):
'title': 'title_1',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo1',
'layer': 'pilot',
})
@@ -200,7 +200,7 @@ class MasterSlaveTest(tests.Test):
'title': 'title_2',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo2',
'layer': 'pilot',
})
@@ -211,7 +211,7 @@ class MasterSlaveTest(tests.Test):
'title': 'title_3',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo3',
'layer': 'pilot',
})
@@ -220,7 +220,7 @@ class MasterSlaveTest(tests.Test):
'title': 'title_4',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo4',
'layer': 'pilot',
})
@@ -245,7 +245,7 @@ class MasterSlaveTest(tests.Test):
'title': 'title_5',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo5',
'layer': 'pilot',
})
@@ -258,7 +258,7 @@ class MasterSlaveTest(tests.Test):
'title': 'title_6',
'summary': 'summary',
'description': 'description',
- 'artifact_icon': 'artifact_icon',
+ 'artefact_icon': 'artefact_icon',
'logo': 'logo6',
'layer': 'pilot',
})
diff --git a/tests/units/db/resource.py b/tests/units/db/resource.py
index 4870418..64187aa 100755
--- a/tests/units/db/resource.py
+++ b/tests/units/db/resource.py
@@ -379,7 +379,10 @@ class ResourceTest(tests.Test):
def test_wipe(self):
class Document(db.Resource):
- pass
+
+ @db.stored_property()
+ def prop(self, value):
+ return value
directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
guid = directory.create({'prop': '1'})
@@ -392,6 +395,93 @@ class ResourceTest(tests.Test):
self.assertEqual([], [i.guid for i in directory.find()[0]])
assert not exists('db/document')
+ def test_ChangePassedPropsInSetters(self):
+
+ class Document(db.Resource):
+
+ @db.stored_property()
+ def prop1(self, value):
+ return value
+
+ @db.stored_property()
+ def prop2(self, value):
+ return value
+
+ @prop2.setter
+ def prop2(self, value):
+ self.post('prop1', value + '!')
+ self.post('prop3', value + '!')
+ return value
+
+ @db.stored_property()
+ def prop3(self, value):
+ return value
+
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ guid = directory.create({'guid': 'guid', 'prop1': 'set1', 'prop2': 'set2', 'prop3': 'set3'})
+
+ doc = directory.get(guid)
+ self.assertEqual('set2!', doc['prop1'])
+ self.assertEqual('set2!', doc['prop3'])
+
+ def test_ChangeDefaultPropsInSetters(self):
+
+ class Document(db.Resource):
+
+ @db.stored_property(default='default')
+ def prop1(self, value):
+ return value
+
+ @db.stored_property()
+ def prop2(self, value):
+ return value
+
+ @prop2.setter
+ def prop2(self, value):
+ self.post('prop1', value + '!')
+ self.post('prop3', value + '!')
+ return value
+
+ @db.stored_property(default='default')
+ def prop3(self, value):
+ return value
+
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ guid = directory.create({'guid': 'guid', 'prop2': 'set2'})
+
+ doc = directory.get(guid)
+ self.assertEqual('set2!', doc['prop1'])
+ self.assertEqual('set2!', doc['prop3'])
+
+ def test_SetMissedMandatoryPropsInSetters(self):
+
+ class Document(db.Resource):
+
+ @db.stored_property()
+ def prop1(self, value):
+ return value
+
+ @db.stored_property()
+ def prop2(self, value):
+ return value
+
+ @prop2.setter
+ def prop2(self, value):
+ self.post('prop1', value + '!')
+ self.post('prop3', value + '!')
+ return value
+
+ @db.stored_property()
+ def prop3(self, value):
+ return value
+
+ directory = Directory(tests.tmpdir, Document, IndexWriter, _SessionSeqno())
+ guid = directory.create({'guid': 'guid', 'prop2': 'set2'})
+
+ doc = directory.get(guid)
+ self.assertEqual('set2!', doc['prop1'])
+ self.assertEqual('set2!', doc['prop3'])
+
class _SessionSeqno(object):
diff --git a/tests/units/db/routes.py b/tests/units/db/routes.py
index 2e1cabb..9f9131e 100755
--- a/tests/units/db/routes.py
+++ b/tests/units/db/routes.py
@@ -964,7 +964,7 @@ class RoutesTest(tests.Test):
@prop.setter
def prop(self, value):
- return value + (self['prop'] or 0)
+ return value + (self.orig('prop') or 0)
volume = db.Volume(tests.tmpdir, [TestDocument])
router = Router(db.Routes(volume))
@@ -1114,6 +1114,10 @@ class RoutesTest(tests.Test):
def name(self, value):
return value
+ @db.stored_property()
+ def pubkey(self, value):
+ return value
+
class Document(db.Resource):
pass
@@ -1146,6 +1150,10 @@ class RoutesTest(tests.Test):
def name(self, value):
return value
+ @db.stored_property()
+ def pubkey(self, value):
+ return value
+
class Document(db.Resource):
pass
@@ -1189,6 +1197,10 @@ class RoutesTest(tests.Test):
def name(self, value):
return value
+ @db.stored_property()
+ def pubkey(self, value):
+ return value
+
class Document(db.Resource):
pass
@@ -1272,6 +1284,10 @@ class RoutesTest(tests.Test):
def name(self, value):
return value
+ @db.stored_property()
+ def pubkey(self, value):
+ return value
+
class Document(db.Resource):
pass
@@ -1341,6 +1357,10 @@ class RoutesTest(tests.Test):
def name(self, value):
return value
+ @db.stored_property()
+ def pubkey(self, value):
+ return value
+
class Document(db.Resource):
pass
@@ -1394,6 +1414,10 @@ class RoutesTest(tests.Test):
def name(self, value):
return value
+ @db.stored_property()
+ def pubkey(self, value):
+ return value
+
class Document(db.Resource):
pass
@@ -1751,11 +1775,11 @@ class RoutesTest(tests.Test):
class Document(db.Resource):
- @db.stored_property(db.Aggregated, prefix='A', full_text=True)
+ @db.indexed_property(db.Aggregated, prefix='A', full_text=True)
def comments(self, value):
return value
- @db.stored_property(prefix='B', full_text=False, default='')
+ @db.indexed_property(prefix='B', full_text=False, default='')
def prop(self, value):
return value
diff --git a/tests/units/model/context.py b/tests/units/model/context.py
index 16faa11..d33cb73 100755
--- a/tests/units/model/context.py
+++ b/tests/units/model/context.py
@@ -13,12 +13,13 @@ from sugar_network.client import IPCConnection, Connection, keyfile
from sugar_network.model.context import Context
from sugar_network.toolkit.coroutine import this
from sugar_network.toolkit.router import Request
-from sugar_network.toolkit import i18n, http, coroutine, enforce
+from sugar_network.toolkit.sugar import color_svg
+from sugar_network.toolkit import svg_to_png, i18n, http, coroutine, enforce
class ContextTest(tests.Test):
- def test_SetCommonLayerForPackages(self):
+ def test_PackageImages(self):
volume = self.start_master()
conn = Connection(auth=http.SugarAuth(keyfile.value))
@@ -28,25 +29,47 @@ class ContextTest(tests.Test):
'summary': 'summary',
'description': 'description',
})
- self.assertEqual(['common'], conn.get(['context', guid, 'layer']))
+
+ assert conn.request('GET', ['context', guid, 'artefact_icon']).content == file(volume.blobs.get('assets/package.svg').path).read()
+ assert conn.request('GET', ['context', guid, 'icon']).content == file(volume.blobs.get('assets/package.png').path).read()
+ assert conn.request('GET', ['context', guid, 'logo']).content == file(volume.blobs.get('assets/package-logo.png').path).read()
+
+ def test_ContextImages(self):
+ volume = self.start_master()
+ conn = Connection(auth=http.SugarAuth(keyfile.value))
guid = conn.post(['context'], {
- 'type': 'package',
+ 'type': 'activity',
'title': 'title',
'summary': 'summary',
'description': 'description',
- 'layer': 'foo',
})
- self.assertEqual(['foo', 'common'], conn.get(['context', guid, 'layer']))
+ svg = color_svg(file(volume.blobs.get('assets/activity.svg').path).read(), guid)
+ assert conn.request('GET', ['context', guid, 'artefact_icon']).content == svg
+ assert conn.request('GET', ['context', guid, 'icon']).content == svg_to_png(svg, 55).getvalue()
+ assert conn.request('GET', ['context', guid, 'logo']).content == svg_to_png(svg, 140).getvalue()
guid = conn.post(['context'], {
- 'type': 'package',
+ 'type': 'book',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ svg = color_svg(file(volume.blobs.get('assets/book.svg').path).read(), guid)
+ assert conn.request('GET', ['context', guid, 'artefact_icon']).content == svg
+ assert conn.request('GET', ['context', guid, 'icon']).content == svg_to_png(svg, 55).getvalue()
+ assert conn.request('GET', ['context', guid, 'logo']).content == svg_to_png(svg, 140).getvalue()
+
+ guid = conn.post(['context'], {
+ 'type': 'group',
'title': 'title',
'summary': 'summary',
'description': 'description',
- 'layer': ['common', 'bar'],
})
- self.assertEqual(['common', 'bar'], conn.get(['context', guid, 'layer']))
+ svg = color_svg(file(volume.blobs.get('assets/group.svg').path).read(), guid)
+ assert conn.request('GET', ['context', guid, 'artefact_icon']).content == svg
+ assert conn.request('GET', ['context', guid, 'icon']).content == svg_to_png(svg, 55).getvalue()
+ assert conn.request('GET', ['context', guid, 'logo']).content == svg_to_png(svg, 140).getvalue()
def test_Releases(self):
volume = self.start_master()
diff --git a/tests/units/model/model.py b/tests/units/model/model.py
index a180f30..49fd1a3 100755
--- a/tests/units/model/model.py
+++ b/tests/units/model/model.py
@@ -74,8 +74,8 @@ class ModelTest(tests.Test):
'content-type': 'application/vnd.olpc-sugar',
'content-disposition': 'attachment; filename="Activity-1%s"' % (mimetypes.guess_extension('application/vnd.olpc-sugar') or ''),
'content-length': str(len(bundle)),
- 'x-seqno': '4',
- }, blobs.get(blob.digest))
+ 'x-seqno': '7',
+ }, dict(blobs.get(blob.digest)))
self.assertEqual('bundle_id', context)
self.assertEqual([[1], 0], release['version'])
self.assertEqual('developer', release['stability'])
@@ -129,8 +129,8 @@ class ModelTest(tests.Test):
'content-type': 'application/pdf',
'content-disposition': 'attachment; filename="NonActivity-2.pdf"',
'content-length': str(len(bundle)),
- 'x-seqno': '4',
- }, blobs.get(blob.digest))
+ 'x-seqno': '7',
+ }, dict(blobs.get(blob.digest)))
self.assertEqual('bundle_id', context)
self.assertEqual([[2], 0], release['version'])
self.assertEqual(['GPL'], release['license'])
@@ -409,7 +409,7 @@ class ModelTest(tests.Test):
'en': 'It has features one would expect of a standard image viewer, like zoom, rotate, etc.',
},
context['description'])
- self.assertEqual(svg, file(blobs.get(context['artifact_icon']).path).read())
+ self.assertEqual(svg, file(blobs.get(context['artefact_icon']).path).read())
assert context['icon'] != 'missing.png'
assert context['logo'] != 'missing-logo.png'
self.assertEqual('http://wiki.sugarlabs.org/go/Activities/Image_Viewer', context['homepage'])