# HG changeset patch # User Thierry Florac # Date 1434527983 -7200 # Node ID 980ffaa51a75698a4937c4577370c64e8cdc7da3 Version 0.1.0 diff -r 000000000000 -r 980ffaa51a75 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,19 @@ + +syntax: regexp +^develop-eggs$ +syntax: regexp +^parts$ +syntax: regexp +^bin$ +syntax: regexp +^\.installed\.cfg$ +syntax: regexp +^\.settings$ +syntax: regexp +^build$ +syntax: regexp +^dist$ +syntax: regexp +^\.idea$ +syntax: regexp +.*\.pyc$ diff -r 000000000000 -r 980ffaa51a75 LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LICENSE Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,42 @@ +Zope Public License (ZPL) Version 2.1 +===================================== + +A copyright notice accompanies this license document that identifies +the copyright holders. + +This license has been certified as open source. It has also been designated +as GPL compatible by the Free Software Foundation (FSF). + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions in source code must retain the accompanying copyright + notice, this list of conditions, and the following disclaimer. + 2. Redistributions in binary form must reproduce the accompanying copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Names of the copyright holders must not be used to endorse or promote + products derived from this software without prior written permission + from the copyright holders. + 4. The right to distribute this software or to use it for any purpose does + not give you the right to use Servicemarks (sm) or Trademarks (tm) of the + copyright holders. Use of them is covered by separate agreement with the + copyright holders. + 5. If any files are modified, you must cause the modified files to carry + prominent notices stating that you changed the files and the date of any + change. + + +Disclaimer +========== + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff -r 000000000000 -r 980ffaa51a75 MANIFEST.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MANIFEST.in Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,5 @@ +include *.txt +recursive-include docs * +recursive-include src * +global-exclude *.pyc +global-exclude *.*~ diff -r 000000000000 -r 980ffaa51a75 bootstrap.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bootstrap.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,178 @@ +############################################################################## +# +# Copyright (c) 2006 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +"""Bootstrap a buildout-based project + +Simply run this script in a directory containing a buildout.cfg. +The script accepts buildout command-line options, so you can +use the -c option to specify an alternate configuration file. +""" + +import os +import shutil +import sys +import tempfile + +from optparse import OptionParser + +tmpeggs = tempfile.mkdtemp() + +usage = '''\ +[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] + +Bootstraps a buildout-based project. + +Simply run this script in a directory containing a buildout.cfg, using the +Python that you want bin/buildout to use. + +Note that by using --find-links to point to local resources, you can keep +this script from going over the network. +''' + +parser = OptionParser(usage=usage) +parser.add_option("-v", "--version", help="use a specific zc.buildout version") + +parser.add_option("-t", "--accept-buildout-test-releases", + dest='accept_buildout_test_releases', + action="store_true", default=False, + help=("Normally, if you do not specify a --version, the " + "bootstrap script and buildout gets the newest " + "*final* versions of zc.buildout and its recipes and " + "extensions for you. If you use this flag, " + "bootstrap and buildout will get the newest releases " + "even if they are alphas or betas.")) +parser.add_option("-c", "--config-file", + help=("Specify the path to the buildout configuration " + "file to be used.")) +parser.add_option("-f", "--find-links", + help=("Specify a URL to search for buildout releases")) +parser.add_option("--allow-site-packages", + action="store_true", default=False, + help=("Let bootstrap.py use existing site packages")) + + +options, args = parser.parse_args() + +###################################################################### +# load/install setuptools + +try: + if options.allow_site_packages: + import setuptools + import pkg_resources + from urllib.request import urlopen +except ImportError: + from urllib2 import urlopen + +ez = {} +exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez) + +if not options.allow_site_packages: + # ez_setup imports site, which adds site packages + # this will remove them from the path to ensure that incompatible versions + # of setuptools are not in the path + import site + # inside a virtualenv, there is no 'getsitepackages'. + # We can't remove these reliably + if hasattr(site, 'getsitepackages'): + for sitepackage_path in site.getsitepackages(): + sys.path[:] = [x for x in sys.path if sitepackage_path not in x] + +setup_args = dict(to_dir=tmpeggs, download_delay=0) +ez['use_setuptools'](**setup_args) +import setuptools +import pkg_resources + +# This does not (always?) update the default working set. We will +# do it. +for path in sys.path: + if path not in pkg_resources.working_set.entries: + pkg_resources.working_set.add_entry(path) + +###################################################################### +# Install buildout + +ws = pkg_resources.working_set + +cmd = [sys.executable, '-c', + 'from setuptools.command.easy_install import main; main()', + '-mZqNxd', tmpeggs] + +find_links = os.environ.get( + 'bootstrap-testing-find-links', + options.find_links or + ('http://downloads.buildout.org/' + if options.accept_buildout_test_releases else None) + ) +if find_links: + cmd.extend(['-f', find_links]) + +setuptools_path = ws.find( + pkg_resources.Requirement.parse('setuptools')).location + +requirement = 'zc.buildout' +version = options.version +if version is None and not options.accept_buildout_test_releases: + # Figure out the most recent final version of zc.buildout. + import setuptools.package_index + _final_parts = '*final-', '*final' + + def _final_version(parsed_version): + for part in parsed_version: + if (part[:1] == '*') and (part not in _final_parts): + return False + return True + index = setuptools.package_index.PackageIndex( + search_path=[setuptools_path]) + if find_links: + index.add_find_links((find_links,)) + req = pkg_resources.Requirement.parse(requirement) + if index.obtain(req) is not None: + best = [] + bestv = None + for dist in index[req.project_name]: + distv = dist.parsed_version + if _final_version(distv): + if bestv is None or distv > bestv: + best = [dist] + bestv = distv + elif distv == bestv: + best.append(dist) + if best: + best.sort() + version = best[-1].version +if version: + requirement = '=='.join((requirement, version)) +cmd.append(requirement) + +import subprocess +if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=setuptools_path)) != 0: + raise Exception( + "Failed to execute command:\n%s" % repr(cmd)[1:-1]) + +###################################################################### +# Import and run buildout + +ws.add_entry(tmpeggs) +ws.require(requirement) +import zc.buildout.buildout + +if not [a for a in args if '=' not in a]: + args.append('bootstrap') + +# if -c was provided, we push it back into args for buildout' main function +if options.config_file is not None: + args[0:0] = ['-c', options.config_file] + +zc.buildout.buildout.main(args) +shutil.rmtree(tmpeggs) diff -r 000000000000 -r 980ffaa51a75 buildout.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/buildout.cfg Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,70 @@ +[buildout] +eggs-directory = /var/local/env/pyams/eggs + +socket-timeout = 3 +show-picked-versions = true +newest = false + +allow-hosts = + bitbucket.org + *.python.org + *.sourceforge.net + github.com + +#extends = http://download.ztfy.org/webapp/ztfy.webapp.dev.cfg +versions = versions +newest = false +#allow-picked-versions = false + +src = src +develop = + . + ../pyams_base + ../pyams_catalog + ../pyams_file + ../pyams_form + ../pyams_i18n + ../pyams_pagelet + ../pyams_skin + ../pyams_template + ../pyams_utils + ../pyams_viewlet + +parts = + package + i18n + pyflakes + test + +[package] +recipe = zc.recipe.egg +eggs = + pyams_sequence + pyramid + zope.component + zope.interface + +[i18n] +recipe = zc.recipe.egg +eggs = + babel + lingua + +[pyflakes] +recipe = zc.recipe.egg +eggs = pyflakes +scripts = pyflakes +entry-points = pyflakes=pyflakes.scripts.pyflakes:main +initialization = if not sys.argv[1:]: sys.argv[1:] = ["${buildout:src}"] + +[pyflakesrun] +recipe = collective.recipe.cmd +on_install = true +cmds = ${buildout:develop}/bin/${pyflakes:scripts} + +[test] +recipe = zc.recipe.testrunner +eggs = pyams_sequence [test] + +[versions] +pyams_sequence = 0.1.0 diff -r 000000000000 -r 980ffaa51a75 docs/HISTORY.txt diff -r 000000000000 -r 980ffaa51a75 docs/README.txt diff -r 000000000000 -r 980ffaa51a75 setup.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,72 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +""" +This module contains pyams_sequence package +""" +from setuptools import setup, find_packages +import os + +DOCS = os.path.join(os.path.dirname(__file__), + 'docs') + +README = os.path.join(DOCS, 'README.txt') +HISTORY = os.path.join(DOCS, 'HISTORY.txt') + +version = '0.1.0' +long_description = open(README).read() + '\n\n' + open(HISTORY).read() + +tests_require = [] + +setup(name='pyams_sequence', + version=version, + description="PyAMS sequence interfaces and classes", + long_description=long_description, + classifiers=[ + "License :: OSI Approved :: Zope Public License", + "Development Status :: 4 - Beta", + "Programming Language :: Python", + "Framework :: Pyramid", + "Topic :: Software Development :: Libraries :: Python Modules", + ], + keywords='Pyramid PyAMS sequence', + author='Thierry Florac', + author_email='tflorac@ulthar.net', + url='http://hg.ztfy.org/pyams/pyams_sequence', + license='ZPL', + packages=find_packages('src'), + package_dir={'': 'src'}, + namespace_packages=[], + include_package_data=True, + package_data={'': ['*.zcml', '*.txt', '*.pt', '*.pot', '*.po', '*.mo', '*.png', '*.gif', '*.jpeg', '*.jpg', '*.css', '*.js']}, + zip_safe=False, + # uncomment this to be able to run tests with setup.py + test_suite="pyams_sequence.tests.test_utilsdocs.test_suite", + tests_require=tests_require, + extras_require=dict(test=tests_require), + install_requires=[ + 'setuptools', + # -*- Extra requirements: -*- + 'pyams_base', + 'pyams_catalog', + 'pyams_form', + 'pyams_pagelet', + 'pyams_utils', + 'pyramid', + 'zope.component', + 'zope.interface', + 'zope.intid', + ], + entry_points=""" + # -*- Entry points: -*- + """, + ) diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence.egg-info/PKG-INFO --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence.egg-info/PKG-INFO Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,18 @@ +Metadata-Version: 1.1 +Name: pyams-sequence +Version: 0.1.0 +Summary: PyAMS sequence interfaces and classes +Home-page: http://hg.ztfy.org/pyams/pyams_sequence +Author: Thierry Florac +Author-email: tflorac@ulthar.net +License: ZPL +Description: + + +Keywords: Pyramid PyAMS sequence +Platform: UNKNOWN +Classifier: License :: OSI Approved :: Zope Public License +Classifier: Development Status :: 4 - Beta +Classifier: Programming Language :: Python +Classifier: Framework :: Pyramid +Classifier: Topic :: Software Development :: Libraries :: Python Modules diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence.egg-info/SOURCES.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence.egg-info/SOURCES.txt Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,33 @@ +MANIFEST.in +setup.py +docs/HISTORY.txt +docs/README.txt +src/pyams_sequence/__init__.py +src/pyams_sequence/include.py +src/pyams_sequence/schema.py +src/pyams_sequence/sequence.py +src/pyams_sequence/site.py +src/pyams_sequence/utility.py +src/pyams_sequence.egg-info/PKG-INFO +src/pyams_sequence.egg-info/SOURCES.txt +src/pyams_sequence.egg-info/dependency_links.txt +src/pyams_sequence.egg-info/entry_points.txt +src/pyams_sequence.egg-info/namespace_packages.txt +src/pyams_sequence.egg-info/not-zip-safe +src/pyams_sequence.egg-info/requires.txt +src/pyams_sequence.egg-info/top_level.txt +src/pyams_sequence/doctests/README.txt +src/pyams_sequence/interfaces/__init__.py +src/pyams_sequence/locales/pyams_sequence.pot +src/pyams_sequence/locales/fr/LC_MESSAGES/pyams_sequence.mo +src/pyams_sequence/locales/fr/LC_MESSAGES/pyams_sequence.po +src/pyams_sequence/rpc/__init__.py +src/pyams_sequence/rpc/json/__init__.py +src/pyams_sequence/tests/__init__.py +src/pyams_sequence/tests/test_utilsdocs.py +src/pyams_sequence/tests/test_utilsdocstrings.py +src/pyams_sequence/widget/__init__.py +src/pyams_sequence/widget/interfaces.py +src/pyams_sequence/widget/templates/reference-display.pt +src/pyams_sequence/widget/templates/reference-input.pt +src/pyams_sequence/zmi/__init__.py \ No newline at end of file diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence.egg-info/dependency_links.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence.egg-info/dependency_links.txt Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,1 @@ + diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence.egg-info/entry_points.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence.egg-info/entry_points.txt Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,3 @@ + + # -*- Entry points: -*- + \ No newline at end of file diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence.egg-info/namespace_packages.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence.egg-info/namespace_packages.txt Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,1 @@ + diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence.egg-info/not-zip-safe --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence.egg-info/not-zip-safe Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,1 @@ + diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence.egg-info/requires.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence.egg-info/requires.txt Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,12 @@ +setuptools +pyams_base +pyams_catalog +pyams_form +pyams_pagelet +pyams_utils +pyramid +zope.component +zope.interface +zope.intid + +[test] diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence.egg-info/top_level.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence.egg-info/top_level.txt Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,1 @@ +pyams_sequence diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/__init__.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,24 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +from pyramid.i18n import TranslationStringFactory +_ = TranslationStringFactory('pyams_sequence') + + +def includeme(config): + """Pyramid include""" + + from .include import include_package + include_package(config) diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/doctests/README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/doctests/README.txt Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,3 @@ +====================== +pyams_sequence package +====================== diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/include.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/include.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,38 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces + +# import packages + + +def include_package(config): + """Pyramid include""" + + # add translations + config.add_translation_dirs('pyams_sequence:locales') + + # define JSON-RPC endpoint + config.add_jsonrpc_endpoint('sequence', '/api/sequence/json') + + # load registry components + try: + import pyams_zmi + except ImportError: + config.scan(ignore='pyams_sequence.zmi') + else: + config.scan() diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/interfaces/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/interfaces/__init__.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,80 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from zope.annotation.interfaces import IAttributeAnnotatable + +# import packages +from zope.interface import Interface +from zope.schema import TextLine, Int + +from pyams_sequence import _ + + +class ISequentialIntIds(Interface): + """Sequential IntIds utility interface""" + + prefix = TextLine(title=_("Hexadecimal prefix"), + description=_("Prefix used to generate hexadecimal ID"), + required=False, + max_length=10) + + hex_oid_length = Int(title=_("Hexadecimal ID length"), + description=_("Full length of hexadecimal ID, not including prefix"), + min=0, + max=20, + default=10) + + last_oid = Int(title=_("Last OID"), + description=_("Last used sequence"), + required=True, + default=0) + + def query_hex_oid(self, obj): + """Generate an hexadecimal ID for the given sequence""" + + def get_full_oid(self, oid, obj_prefix=None): + """Get full ID based on partial OID""" + + def get_short_oid(self, oid, obj_prefix=None): + """Get short ID based on given numeric object ID""" + + +class ISequentialIdInfo(Interface): + """Sequential ID info interface""" + + oid = Int(title=_("Sequential ID"), + required=False) + + hex_oid = TextLine(title=_("Unique ID"), + required=False) + + def get_short_oid(self): + """Get short ID""" + + +class ISequentialIdTarget(IAttributeAnnotatable): + """Marker interface used to identify contents requiring sequential IDs""" + + sequence_name = TextLine(title=_("Sequence name"), + description=_("Name of registered sequence utility used to get unique IDs"), + required=False) + + sequence_prefix = TextLine(title=_("Hexadecimal prefix"), + description=_("Prefix used to generate hexadecimal ID, placed after utility prefix. " + "Generally defined at class level..."), + required=False) diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/locales/fr/LC_MESSAGES/pyams_sequence.mo Binary file src/pyams_sequence/locales/fr/LC_MESSAGES/pyams_sequence.mo has changed diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/locales/fr/LC_MESSAGES/pyams_sequence.po --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/locales/fr/LC_MESSAGES/pyams_sequence.po Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,83 @@ +# +# French translations for PACKAGE package +# This file is distributed under the same license as the PACKAGE package. +# Thierry Florac , 2015. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE 1.0\n" +"POT-Creation-Date: 2015-06-16 15:29+0200\n" +"PO-Revision-Date: 2015-06-16 15:29+0200\n" +"Last-Translator: Thierry Florac \n" +"Language-Team: French\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Lingua 3.8\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: src/pyams_sequence/utility.py:87 src/pyams_sequence/zmi/__init__.py:61 +msgid "Can't set last OID to value lower than current one!" +msgstr "Impossible de définir le dernier OID à une valeur inférieure à sa valeur actuelle" + +#: src/pyams_sequence/widget/__init__.py:77 +#, python-format +msgid "missing reference: {0}" +msgstr "référence manquante : {0}" + +#: src/pyams_sequence/widget/templates/reference-input.pt:3 +msgid "Clear selected value" +msgstr "Effacer la sélection" + +#: src/pyams_sequence/zmi/__init__.py:44 +msgid "Display sequence properties" +msgstr "Afficher les propriétés de la séquence" + +#: src/pyams_sequence/interfaces/__init__.py:31 +#: src/pyams_sequence/interfaces/__init__.py:77 +msgid "Hexadecimal prefix" +msgstr "Préfixe hexadécimal" + +#: src/pyams_sequence/interfaces/__init__.py:32 +msgid "Prefix used to generate hexadecimal ID" +msgstr "Préfixe utilisé pour générer l'identifiant hexadécimal" + +#: src/pyams_sequence/interfaces/__init__.py:36 +msgid "Hexadecimal ID length" +msgstr "Longueur de l'ID" + +#: src/pyams_sequence/interfaces/__init__.py:37 +msgid "Full length of hexadecimal ID, not including prefix" +msgstr "Longueur de l'identifiant hexadécimal, préfixe non compris" + +#: src/pyams_sequence/interfaces/__init__.py:42 +msgid "Last OID" +msgstr "Dernier OID" + +#: src/pyams_sequence/interfaces/__init__.py:43 +msgid "Last used sequence" +msgstr "Dernier numéro de séquence utilisé" + +#: src/pyams_sequence/interfaces/__init__.py:60 +msgid "Sequential ID" +msgstr "ID séquentiel" + +#: src/pyams_sequence/interfaces/__init__.py:63 +msgid "Unique ID" +msgstr "ID unique" + +#: src/pyams_sequence/interfaces/__init__.py:73 +msgid "Sequence name" +msgstr "Nom de la séquence" + +#: src/pyams_sequence/interfaces/__init__.py:74 +msgid "Name of registered sequence utility used to get unique IDs" +msgstr "Nom de la séquence enregistrée utilisée pour génerer les identifiants uniques" + +#: src/pyams_sequence/interfaces/__init__.py:78 +msgid "" +"Prefix used to generate hexadecimal ID, placed after utility prefix. " +"Generally defined at class level..." +msgstr "" +"Préfixe utilisé pour générer les identifiants hexadécimaux, en plus du préfixe de la séquence. " +"Généralement défini au niveau de la classe." diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/locales/pyams_sequence.pot --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/locales/pyams_sequence.pot Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,81 @@ +# +# SOME DESCRIPTIVE TITLE +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , 2015. +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE 1.0\n" +"POT-Creation-Date: 2015-06-16 15:29+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Lingua 3.8\n" + +#: ./src/pyams_sequence/utility.py:87 ./src/pyams_sequence/zmi/__init__.py:61 +msgid "Can't set last OID to value lower than current one!" +msgstr "" + +#: ./src/pyams_sequence/widget/__init__.py:77 +#, python-format +msgid "missing reference: {0}" +msgstr "" + +#: ./src/pyams_sequence/widget/templates/reference-input.pt:3 +msgid "Clear selected value" +msgstr "" + +#: ./src/pyams_sequence/zmi/__init__.py:44 +msgid "Display sequence properties" +msgstr "" + +#: ./src/pyams_sequence/interfaces/__init__.py:31 +#: ./src/pyams_sequence/interfaces/__init__.py:77 +msgid "Hexadecimal prefix" +msgstr "" + +#: ./src/pyams_sequence/interfaces/__init__.py:32 +msgid "Prefix used to generate hexadecimal ID" +msgstr "" + +#: ./src/pyams_sequence/interfaces/__init__.py:36 +msgid "Hexadecimal ID length" +msgstr "" + +#: ./src/pyams_sequence/interfaces/__init__.py:37 +msgid "Full length of hexadecimal ID, not including prefix" +msgstr "" + +#: ./src/pyams_sequence/interfaces/__init__.py:42 +msgid "Last OID" +msgstr "" + +#: ./src/pyams_sequence/interfaces/__init__.py:43 +msgid "Last used sequence" +msgstr "" + +#: ./src/pyams_sequence/interfaces/__init__.py:60 +msgid "Sequential ID" +msgstr "" + +#: ./src/pyams_sequence/interfaces/__init__.py:63 +msgid "Unique ID" +msgstr "" + +#: ./src/pyams_sequence/interfaces/__init__.py:73 +msgid "Sequence name" +msgstr "" + +#: ./src/pyams_sequence/interfaces/__init__.py:74 +msgid "Name of registered sequence utility used to get unique IDs" +msgstr "" + +#: ./src/pyams_sequence/interfaces/__init__.py:78 +msgid "" +"Prefix used to generate hexadecimal ID, placed after utility prefix. " +"Generally defined at class level..." +msgstr "" diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/rpc/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/rpc/__init__.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,20 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces + +# import packages diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/rpc/json/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/rpc/json/__init__.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,53 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from hypatia.interfaces import ICatalog +from pyams_sequence.interfaces import ISequentialIntIds + +# import packages +from hypatia.catalog import CatalogQuery +from hypatia.query import Eq, Contains +from pyams_catalog.query import CatalogResultSet +from pyams_sequence.utility import get_last_version, get_sequence_dict +from pyams_utils.list import unique +from pyams_utils.registry import get_utility +from pyramid_rpc.jsonrpc import jsonrpc_method + + +@jsonrpc_method(endpoint='sequence') +def findReferences(request, query, content_type): + """Find references matching given query""" + if not query: + return [] + catalog = get_utility(ICatalog) + sequence = get_utility(ISequentialIntIds) + if query.startswith('+'): + params = Eq(catalog['oid'], sequence.get_full_oid(query)) + else: + query_params = Eq(catalog['oid'], sequence.get_full_oid(query)) + index = catalog['title:' + request.registry.settings.get('pyramid.default_locale_name', 'en')] + if index.check_query(query): + query_params |= Contains(index, ' and '.join((w+'*' for w in query.split()))) + params = query_params + if content_type: + params &= Eq(catalog['content_type'], content_type) + return sorted([get_sequence_dict(result) + for result in unique(filter(None, + map(get_last_version, + CatalogResultSet(CatalogQuery(catalog).query(params)))))], + key=lambda x: x['text']) diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/schema.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/schema.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,38 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from zope.schema.interfaces import ITextLine + +# import packages +from zope.interface import implementer, Attribute +from zope.schema import TextLine + + +class IInternalReference(ITextLine): + """Internal reference field interface""" + + content_type = Attribute("Requested content type") + + +@implementer(IInternalReference) +class InternalReference(TextLine): + """Internal reference field""" + + def __init__(self, content_type=None, *args, **kwargs): + super(InternalReference, self).__init__(*args, **kwargs) + self.content_type = content_type diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/sequence.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/sequence.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,47 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_sequence.interfaces import ISequentialIdInfo, ISequentialIdTarget +from zope.annotation.interfaces import IAnnotations + +# import packages +from persistent import Persistent +from pyams_utils.adapter import adapter_config +from zope.interface import implementer +from zope.schema.fieldproperty import FieldProperty + + +@implementer(ISequentialIdInfo) +class SequentialIdInfo(Persistent): + """Sequential ID info""" + + oid = FieldProperty(ISequentialIdInfo['oid']) + hex_oid = FieldProperty(ISequentialIdInfo['hex_oid']) + + +SEQUENCE_INFO_KEY = 'pyams_sequence.info' + + +@adapter_config(context=ISequentialIdTarget, provides=ISequentialIdInfo) +def SequentialIdInfoFactory(context): + """Sequential ID info factory""" + annotations = IAnnotations(context) + info = annotations.get(SEQUENCE_INFO_KEY) + if info is None: + info = annotations[SEQUENCE_INFO_KEY] = SequentialIdInfo() + return info diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/site.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/site.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,56 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_sequence.interfaces import ISequentialIntIds, ISequentialIdInfo +from pyams_utils.interfaces.site import ISiteGenerations +from zope.site.interfaces import INewLocalSite + +# import packages +from pyams_catalog.index import FieldIndexWithInterface +from pyams_catalog.site import check_required_indexes +from pyams_sequence.utility import SequentialIntIds +from pyams_utils.registry import utility_config +from pyams_utils.site import check_required_utilities +from pyramid.events import subscriber + + +REQUIRED_UTILITIES = ((ISequentialIntIds, '', SequentialIntIds, 'Sequential IDs'), ) + + +REQUIRED_INDEXES = (('oid', FieldIndexWithInterface, {'interface': ISequentialIdInfo, + 'discriminator': 'hex_oid'}), ) + + +@subscriber(INewLocalSite) +def handle_new_local_site(event): + """Check for required utilities when a site is created""" + site = event.manager.__parent__ + check_required_utilities(site, REQUIRED_UTILITIES) + check_required_indexes(site, REQUIRED_INDEXES) + + +@utility_config(name='PyAMS sequence', provides=ISiteGenerations) +class SequenceGenerationsChecker(object): + """PyAMS sequence generations checker""" + + generation = 1 + + def evolve(self, site, current=None): + """Check for required utilities""" + check_required_utilities(site, REQUIRED_UTILITIES) + check_required_indexes(site, REQUIRED_INDEXES) diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/tests/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/tests/__init__.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,1 @@ + diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/tests/test_utilsdocs.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/tests/test_utilsdocs.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,59 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +""" +Generic Test case for pyams_sequence doctest +""" +__docformat__ = 'restructuredtext' + +import doctest +import unittest +import sys +import os + + +current_dir = os.path.dirname(__file__) + +def doc_suite(test_dir, setUp=None, tearDown=None, globs=None): + """Returns a test suite, based on doctests found in /doctest.""" + suite = [] + if globs is None: + globs = globals() + + flags = (doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE | + doctest.REPORT_ONLY_FIRST_FAILURE) + + package_dir = os.path.split(test_dir)[0] + if package_dir not in sys.path: + sys.path.append(package_dir) + + doctest_dir = os.path.join(package_dir, 'doctests') + + # filtering files on extension + docs = [os.path.join(doctest_dir, doc) for doc in + os.listdir(doctest_dir) if doc.endswith('.txt')] + + for test in docs: + suite.append(doctest.DocFileSuite(test, optionflags=flags, + globs=globs, setUp=setUp, + tearDown=tearDown, + module_relative=False)) + + return unittest.TestSuite(suite) + +def test_suite(): + """returns the test suite""" + return doc_suite(current_dir) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') + diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/tests/test_utilsdocstrings.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/tests/test_utilsdocstrings.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,62 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +""" +Generic Test case for pyams_sequence doc strings +""" +__docformat__ = 'restructuredtext' + +import doctest +import unittest +import sys +import os + + +current_dir = os.path.abspath(os.path.dirname(__file__)) + +def doc_suite(test_dir, globs=None): + """Returns a test suite, based on doc tests strings found in /*.py""" + suite = [] + if globs is None: + globs = globals() + + flags = (doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE | + doctest.REPORT_ONLY_FIRST_FAILURE) + + package_dir = os.path.split(test_dir)[0] + if package_dir not in sys.path: + sys.path.append(package_dir) + + # filtering files on extension + docs = [doc for doc in + os.listdir(package_dir) if doc.endswith('.py')] + docs = [doc for doc in docs if not doc.startswith('__')] + + for test in docs: + fd = open(os.path.join(package_dir, test)) + content = fd.read() + fd.close() + if '>>> ' not in content: + continue + test = test.replace('.py', '') + location = 'pyams_sequence.%s' % test + suite.append(doctest.DocTestSuite(location, optionflags=flags, + globs=globs)) + + return unittest.TestSuite(suite) + +def test_suite(): + """returns the test suite""" + return doc_suite(current_dir) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/utility.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/utility.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,144 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_i18n.interfaces import II18n +from pyams_sequence.interfaces import ISequentialIntIds, ISequentialIdTarget, ISequentialIdInfo + +try: + from pyams_workflow.interfaces import IWorkflowVersions, IWorkflowVersion, IWorkflowManagedContent +except ImportError: + handle_workflow = False +else: + handle_workflow = True + +from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectRemovedEvent + +# import packages +from pyams_utils.registry import query_utility, get_utility +from pyramid.events import subscriber +from zope.interface import implementer, Invalid +from zope.intid import IntIds +from zope.schema.fieldproperty import FieldProperty + +from pyams_sequence import _ + + +def get_last_version(content): + """Check for last available version""" + if handle_workflow and (IWorkflowVersion.providedBy(content) or IWorkflowManagedContent.providedBy(content)): + content = IWorkflowVersions(content).get_last_versions()[0] + if ISequentialIdInfo(content, None) is not None: + return content + else: + return None + + +def get_version_in_state(content, state): + """Check for versions in given status""" + if handle_workflow and (IWorkflowVersion.providedBy(content) or IWorkflowManagedContent.providedBy(content)): + versions = IWorkflowVersions(content).get_versions(state) + if versions: + content = versions[0] + if ISequentialIdInfo(content, None) is not None: + return content + else: + return None + + +def get_sequence_dict(version, attribute='title', request=None): + """Get OID and label matching given version""" + sequence = get_utility(ISequentialIntIds) + info = ISequentialIdInfo(version) + return {'id': info.hex_oid, + 'text': '{0} ({1})'.format(II18n(version).query_attribute(attribute, request=request), + sequence.get_short_oid(info.oid))} + + +@implementer(ISequentialIntIds) +class SequentialIntIds(IntIds): + """Sequential IntIds utility""" + + prefix = FieldProperty(ISequentialIntIds['prefix']) + hex_oid_length = FieldProperty(ISequentialIntIds['hex_oid_length']) + _last_oid = FieldProperty(ISequentialIntIds['last_oid']) + + @property + def last_oid(self): + return self._last_oid + + @last_oid.setter + def last_oid(self, value): + if value < self._last_oid: + raise Invalid(_("Can't set last OID to value lower than current one!")) + self._last_oid = value + + def _generateId(self): + self._last_oid += 1 + return self._last_oid + + def register(self, ob): + if not ISequentialIdTarget.providedBy(ob): + return None + return super(SequentialIntIds, self).register(ob) + + def query_hex_oid(self, obj): + oid = self.queryId(obj) + if oid is not None: + return '{{prefix}}{{obj_prefix}}{{hex_id:0{length}x}}' \ + .format(length=self.hex_oid_length) \ + .format(prefix=self.prefix or '', + obj_prefix=getattr(obj, 'sequence_prefix', ''), + hex_id=oid) + + def get_full_oid(self, oid, obj_prefix=None): + if self.prefix and oid.startswith(self.prefix or ''): + return oid + if oid.startswith('+'): + oid = oid[1:] + return '{prefix}{obj_prefix}{zeros}{hex_id}'.format(prefix=self.prefix or '', + obj_prefix=obj_prefix or '', + zeros='0' * (self.hex_oid_length - len(oid)), + hex_id=oid) + + def get_short_oid(self, oid, obj_prefix=None): + return '{prefix}{obj_prefix} {hex_id:x}'.format(prefix=self.prefix or '', + obj_prefix=obj_prefix or '', + hex_id=oid) + + +@subscriber(IObjectAddedEvent, context_selector=ISequentialIdTarget) +def handle_added_intid_target(event): + """Handle added sequential ID target""" + target = event.object + sequence = query_utility(ISequentialIntIds, name=getattr(target, 'sequence_name', '')) + if sequence is not None: + info = ISequentialIdInfo(target) + if not info.oid: # Objects cloned inside a workflow may share the same ID... + info.oid = sequence.register(target) + info.hex_oid = sequence.query_hex_oid(target) + + +@subscriber(IObjectRemovedEvent, context_selector=ISequentialIdTarget) +def handle_removed_intid_target(event): + """Handle removed sequential ID target""" + target = event.object + sequence = query_utility(ISequentialIntIds, name=getattr(target, 'sequence_name', '')) + if sequence is not None: + info = ISequentialIdInfo(target) + if info.oid: + sequence.unregister(target) diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/widget/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/widget/__init__.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,83 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library +import json + +# import interfaces +from hypatia.interfaces import ICatalog +from pyams_form.interfaces.form import IFormLayer +from pyams_i18n.interfaces import II18n +from pyams_sequence.interfaces import ISequentialIntIds, ISequentialIdInfo +from pyams_sequence.schema import IInternalReference +from pyams_sequence.widget.interfaces import IInternalReferenceWidget + +try: + from pyams_workflow.interfaces import IWorkflowVersions, IWorkflowVersion, IWorkflowManagedContent +except ImportError: + handle_workflow = False +else: + handle_workflow = True + +from z3c.form.interfaces import IFieldWidget + +# import packages +from hypatia.catalog import CatalogQuery +from hypatia.query import Eq +from pyams_catalog.query import CatalogResultSet +from pyams_form.widget import widgettemplate_config +from pyams_sequence.utility import get_last_version +from pyams_utils.adapter import adapter_config +from pyams_utils.registry import get_utility +from z3c.form.browser.widget import HTMLInputWidget +from z3c.form.widget import Widget, FieldWidget +from zope.interface import implementer_only + +from pyams_sequence import _ + + +# +# Internal reference widget +# + +@widgettemplate_config(mode='input', template='templates/reference-input.pt', layer=IFormLayer) +@widgettemplate_config(mode='display', template='templates/reference-display.pt', layer=IFormLayer) +@implementer_only(IInternalReferenceWidget) +class InternalReferenceWidget(HTMLInputWidget, Widget): + """Internal reference widget""" + + @property + def query_params(self): + return json.dumps({'content_type': self.field.content_type}) + + @property + def values_map(self): + catalog = get_utility(ICatalog) + params = Eq(catalog['oid'], self.value) + results = list(map(get_last_version, CatalogResultSet(CatalogQuery(catalog).query(params)))) + if results: + sequence = get_utility(ISequentialIntIds) + return json.dumps({self.value: '{0} ({1})'.format(II18n(results[0]).query_attribute('title', + request=self.request), + sequence.get_short_oid(ISequentialIdInfo(results[0]).oid))}) + else: + translate = self.request.localizer.translate + return json.dumps({self.value: translate(_("missing reference: {0}")).format(self.value)}) + + +@adapter_config(context=(IInternalReference, IFormLayer), provides=IFieldWidget) +def InternalReferenceFieldWidget(field, request): + """Internal reference field widget factory""" + return FieldWidget(field, InternalReferenceWidget(request)) diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/widget/interfaces.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/widget/interfaces.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,25 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from z3c.form.interfaces import IWidget + +# import packages + + +class IInternalReferenceWidget(IWidget): + """Single term widget""" diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/widget/templates/reference-display.pt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/widget/templates/reference-display.pt Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,25 @@ + diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/widget/templates/reference-input.pt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/widget/templates/reference-input.pt Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,45 @@ + diff -r 000000000000 -r 980ffaa51a75 src/pyams_sequence/zmi/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_sequence/zmi/__init__.py Wed Jun 17 09:59:43 2015 +0200 @@ -0,0 +1,67 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_base.interfaces import IIndexLength +from pyams_sequence.interfaces import ISequentialIntIds +from pyams_skin.layer import IPyAMSLayer +from z3c.form.interfaces import DISPLAY_MODE, IDataExtractedEvent + +# import packages +from pyams_form.form import AJAXEditForm +from pyams_pagelet.pagelet import pagelet_config +from pyams_zmi.form import AdminDialogEditForm +from pyramid.events import subscriber +from pyramid.view import view_config +from z3c.form import field +from zope.interface import Invalid + +from pyams_sequence import _ + + +@pagelet_config(name='properties.html', context=ISequentialIntIds, layer=IPyAMSLayer, permission='system.view') +class SequentialIntIdsPropertiesEditForm(AdminDialogEditForm): + """Sequential IDs properties edit form""" + + @property + def title(self): + return self.context.__name__ + + legend = _("Display sequence properties") + fields = field.Fields(IIndexLength) + field.Fields(ISequentialIntIds) + + ajax_handler = 'properties.json' + edit_permission = 'system.manage' + + def updateWidgets(self, prefix=None): + super(SequentialIntIdsPropertiesEditForm, self).updateWidgets(prefix) + if 'count' in self.widgets: + self.widgets['count'].mode = DISPLAY_MODE + + +@subscriber(IDataExtractedEvent, form_selector=SequentialIntIdsPropertiesEditForm) +def handle_sequence_data_extraction(event): + """Handle sequence properties data extraction""" + last_oid = event.data.get('last_oid') + if last_oid < event.form.context.last_oid: + event.form.widgets.errors += (Invalid(_("Can't set last OID to value lower than current one!")),) + + +@view_config(name='properties.json', context=ISequentialIntIds, request_type=IPyAMSLayer, + permission='system.manage', renderer='json', xhr=True) +class SequentialIntIdsPropertiesAJAXEditForm(AJAXEditForm, SequentialIntIdsPropertiesEditForm): + """Sequential IDs properties edit form, JSON renderer"""