Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
cubicweb
cubicweb
Commits
6350e0a482d5
Commit
b1a20441
authored
Jan 12, 2018
by
Denis Laxalde
Browse files
Merge with 3.25
parents
cd760c411242
4a619b42263d
Changes
17
Hide whitespace changes
Inline
Side-by-side
.hgtags
View file @
6350e0a4
...
...
@@ -608,3 +608,9 @@ dacc5b168e29b33515cee5940de1e392dc9d522a centos/3.25.0-1
5010381099f1227724261665f0843a60447991b2 3.25.2
5010381099f1227724261665f0843a60447991b2 debian/3.25.2-1
5010381099f1227724261665f0843a60447991b2 centos/3.25.2-1
d238badfc268ad4440b3238a24690858bad3fbdd 3.25.3
d238badfc268ad4440b3238a24690858bad3fbdd centos/3.25.3-1
d238badfc268ad4440b3238a24690858bad3fbdd debian/3.25.3-1
b8567725c473b701fe9352e578ad6e05c523c1f2 3.25.4
b8567725c473b701fe9352e578ad6e05c523c1f2 centos/3.25.4-1
b8567725c473b701fe9352e578ad6e05c523c1f2 debian/3.25.4-1
cubicweb.spec
View file @
6350e0a4
...
...
@@ -8,7 +8,7 @@
%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
Name: cubicweb
Version: 3.25.
2
Version: 3.25.
4
Release: logilab.1%{?dist}
Summary: CubicWeb is a semantic web application framework
Source0: https://pypi.python.org/packages/source/c/cubicweb/cubicweb-%{version}.tar.gz
...
...
@@ -29,6 +29,7 @@ Requires: %{python}-yams >= 0.45.0
Requires: %{python}-logilab-database >= 1.15.0
Requires: %{python}-passlib
Requires: %{python}-lxml
Requires: %{python}-unittest2 >= 0.7.0
Requires: %{python}-twisted-web < 16.0.0
Requires: %{python}-markdown
Requires: pytz
...
...
cubicweb/entities/__init__.py
View file @
6350e0a4
...
...
@@ -98,15 +98,29 @@ class AnyEntity(Entity):
# meta data api ###########################################################
def
__getattr__
(
self
,
name
):
prefix
=
'dc_'
if
name
.
startswith
(
prefix
):
# Proxy to IDublinCore adapter for bw compat.
adapted
=
self
.
cw_adapt_to
(
'IDublinCore'
)
method
=
name
[
len
(
prefix
):]
if
hasattr
(
adapted
,
method
):
return
getattr
(
adapted
,
method
)
raise
AttributeError
(
name
)
def
dc_title
(
self
):
return
self
.
cw_adapt_to
(
'IDublinCore'
).
title
()
def
dc_long_title
(
self
):
return
self
.
cw_adapt_to
(
'IDublinCore'
).
long_title
()
def
dc_description
(
self
,
*
args
,
**
kwargs
):
return
self
.
cw_adapt_to
(
'IDublinCore'
).
description
(
*
args
,
**
kwargs
)
def
dc_authors
(
self
):
return
self
.
cw_adapt_to
(
'IDublinCore'
).
authors
()
def
dc_creator
(
self
):
return
self
.
cw_adapt_to
(
'IDublinCore'
).
creator
()
def
dc_date
(
self
,
*
args
,
**
kwargs
):
return
self
.
cw_adapt_to
(
'IDublinCore'
).
date
(
*
args
,
**
kwargs
)
def
dc_type
(
self
,
*
args
,
**
kwargs
):
return
self
.
cw_adapt_to
(
'IDublinCore'
).
type
(
*
args
,
**
kwargs
)
def
dc_language
(
self
):
return
self
.
cw_adapt_to
(
'IDublinCore'
).
language
()
@
property
def
creator
(
self
):
...
...
cubicweb/pyramid/pyramidctl.py
View file @
6350e0a4
...
...
@@ -350,13 +350,15 @@ class PyramidStartHandler(InstanceCommand):
host
=
cwconfig
[
'interface'
]
port
=
cwconfig
[
'port'
]
or
8080
url_scheme
=
(
'https'
if
cwconfig
[
'base-url'
].
startswith
(
'https'
)
else
'http'
)
repo
=
app
.
application
.
registry
[
'cubicweb.repository'
]
warnings
.
warn
(
'the "pyramid" command does not start repository "looping tasks" '
'anymore; use the standalone "scheduler" command if needed'
)
try
:
waitress
.
serve
(
app
,
host
=
host
,
port
=
port
)
waitress
.
serve
(
app
,
host
=
host
,
port
=
port
,
url_scheme
=
url_scheme
)
finally
:
repo
.
shutdown
()
if
self
.
_needreload
:
...
...
cubicweb/rtags.py
View file @
6350e0a4
...
...
@@ -88,7 +88,14 @@ class RelationTags(RegistrableRtags):
def
__repr__
(
self
):
# find a way to have more infos but keep it readable
# (in error messages in case of an ambiguity for instance)
return
'%s (%s): %s'
%
(
id
(
self
),
self
.
__regid__
,
self
.
__class__
)
return
'<%s %s>'
%
(
self
.
__regid__
,
self
.
_short_repr
())
def
_short_repr
(
self
):
# find a way to have more infos but keep it readable
# (in error messages in case of an ambiguity for instance)
return
'%s@0x%x%s'
%
(
self
.
__module__
,
id
(
self
),
' derived from %s'
%
self
.
_parent
.
_short_repr
()
if
self
.
_parent
else
''
)
# dict compat
def
__getitem__
(
self
,
key
):
...
...
cubicweb/schema.py
View file @
6350e0a4
# copyright 2003
-2016
LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# copyright 2003 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
...
...
@@ -19,9 +19,8 @@
from
__future__
import
print_function
import
pkgutil
import
re
from
os.path
import
join
,
basename
from
os.path
import
join
from
hashlib
import
md5
from
logging
import
getLogger
from
warnings
import
warn
...
...
@@ -29,7 +28,6 @@ from warnings import warn
from
six
import
PY2
,
text_type
,
string_types
,
add_metaclass
from
six.moves
import
range
from
logilab.common
import
tempattr
from
logilab.common.decorators
import
cached
,
clear_cache
,
monkeypatch
,
cachedproperty
from
logilab.common.logging_ext
import
set_log_methods
from
logilab.common.deprecation
import
deprecated
...
...
@@ -44,14 +42,15 @@ from yams.constraints import (BaseConstraint, FormatConstraint,
cstr_json_dumps
,
cstr_json_loads
)
from
yams.reader
import
(
CONSTRAINTS
,
PyFileReader
,
SchemaLoader
,
cleanup_sys_modules
,
fill_schema_from_namespace
)
from
yams.buildobjs
import
_add_relation
as
yams_add_relation
from
rql
import
parse
,
nodes
,
RQLSyntaxError
,
TypeResolverException
from
rql
import
parse
,
nodes
,
stmts
,
RQLSyntaxError
,
TypeResolverException
from
rql.analyze
import
ETypeResolver
import
cubicweb
from
cubicweb
import
server
from
cubicweb
import
ETYPE_NAME_MAP
,
ValidationError
,
Unauthorized
,
_
from
cubicweb
import
server
PURE_VIRTUAL_RTYPES
=
set
((
'identity'
,
'has_text'
,))
VIRTUAL_RTYPES
=
set
((
'eid'
,
'identity'
,
'has_text'
,))
...
...
@@ -602,6 +601,8 @@ def ERSchema_display_name(self, req, form='', context=None):
a given form
"""
return
display_name
(
req
,
self
.
type
,
form
,
context
)
ERSchema
.
display_name
=
ERSchema_display_name
...
...
@@ -621,6 +622,8 @@ def get_groups(self, action):
return
frozenset
(
g
for
g
in
self
.
permissions
[
action
]
if
isinstance
(
g
,
string_types
))
except
KeyError
:
return
()
PermissionMixIn
.
get_groups
=
get_groups
...
...
@@ -640,6 +643,8 @@ def get_rqlexprs(self, action):
return
tuple
(
g
for
g
in
self
.
permissions
[
action
]
if
not
isinstance
(
g
,
string_types
))
except
KeyError
:
return
()
PermissionMixIn
.
get_rqlexprs
=
get_rqlexprs
...
...
@@ -656,6 +661,8 @@ def set_action_permissions(self, action, permissions):
orig_set_action_permissions
(
self
,
action
,
tuple
(
permissions
))
clear_cache
(
self
,
'get_rqlexprs'
)
clear_cache
(
self
,
'get_groups'
)
orig_set_action_permissions
=
PermissionMixIn
.
set_action_permissions
PermissionMixIn
.
set_action_permissions
=
set_action_permissions
...
...
@@ -673,6 +680,8 @@ def has_local_role(self, action):
if
action
in
(
'update'
,
'delete'
):
return
'owners'
in
self
.
get_groups
(
action
)
return
False
PermissionMixIn
.
has_local_role
=
has_local_role
...
...
@@ -681,6 +690,8 @@ def may_have_permission(self, action, req):
self
.
has_perm
(
req
,
'read'
)):
return
False
return
self
.
has_local_role
(
action
)
or
self
.
has_perm
(
req
,
action
)
PermissionMixIn
.
may_have_permission
=
may_have_permission
...
...
@@ -691,6 +702,8 @@ def has_perm(self, _cw, action, **kwargs):
return
True
except
Unauthorized
:
return
False
PermissionMixIn
.
has_perm
=
has_perm
...
...
@@ -734,6 +747,8 @@ def check_perm(self, _cw, action, **kwargs):
for
rqlexpr
in
self
.
get_rqlexprs
(
action
)):
return
raise
Unauthorized
(
action
,
str
(
self
))
PermissionMixIn
.
check_perm
=
check_perm
...
...
@@ -818,7 +833,7 @@ class CubicWebEntitySchema(EntitySchema):
"""convenience method that returns the *main* (i.e. the first non meta)
attribute defined in the entity schema
"""
for
rschema
,
_
in
self
.
attribute_definitions
():
for
rschema
,
_
_
in
self
.
attribute_definitions
():
if
not
(
rschema
in
META_RTYPES
or
self
.
is_metadata
(
rschema
)):
return
rschema
...
...
@@ -1262,7 +1277,7 @@ class RepoEnforcedRQLConstraintMixIn(object):
#
# possible enhancement: check entity being created, it's probably
# the main eid unless this is a composite relation
if
eidto
is
None
or
'S'
in
self
.
mainvars
or
not
'O'
in
self
.
mainvars
:
if
eidto
is
None
or
'S'
in
self
.
mainvars
or
'O'
not
in
self
.
mainvars
:
maineid
=
eidfrom
qname
=
role_name
(
rtype
,
'subject'
)
else
:
...
...
@@ -1272,7 +1287,7 @@ class RepoEnforcedRQLConstraintMixIn(object):
msg
=
session
.
_
(
self
.
msg
)
else
:
msg
=
'%(constraint)s %(expression)s failed'
%
{
'constraint'
:
session
.
_
(
self
.
type
()),
'constraint'
:
session
.
_
(
self
.
type
()),
'expression'
:
self
.
expression
}
raise
ValidationError
(
maineid
,
{
qname
:
msg
})
...
...
@@ -1320,9 +1335,6 @@ class RQLUniqueConstraint(RepoEnforcedRQLConstraintMixIn, BaseRQLConstraint):
# workflow extensions #########################################################
from
yams.buildobjs
import
_add_relation
as
yams_add_relation
class
workflowable_definition
(
ybo
.
metadefinition
):
"""extends default EntityType's metaclass to add workflow relations
(i.e. in_state, wf_info_for and custom_workflow). This is the default
...
...
@@ -1409,7 +1421,8 @@ class CubicWebSchemaLoader(BootstrapSchemaLoader):
"""
self
.
info
(
'loading %s schemas'
,
', '
.
join
(
config
.
cubes
()))
try
:
return
super
(
CubicWebSchemaLoader
,
self
).
load
(
config
,
config
.
schema_modnames
(),
**
kwargs
)
return
super
(
CubicWebSchemaLoader
,
self
).
load
(
config
,
config
.
schema_modnames
(),
**
kwargs
)
finally
:
# we've to cleanup modules imported from cubicweb.schemas as well
cleanup_sys_modules
([
join
(
cubicweb
.
CW_SOFTWARE_ROOT
,
'schemas'
)])
...
...
@@ -1448,29 +1461,36 @@ def vocabulary(self, entity=None, form=None):
return
self
.
regular_formats
+
tuple
(
NEED_PERM_FORMATS
)
return
self
.
regular_formats
# XXX itou for some Statement methods
from
rql
import
stmts
# XXX itou for some Statement methods
def
bw_get_etype
(
self
,
name
):
return
orig_get_etype
(
self
,
bw_normalize_etype
(
name
))
orig_get_etype
=
stmts
.
ScopeNode
.
get_etype
stmts
.
ScopeNode
.
get_etype
=
bw_get_etype
def
bw_add_main_variable_delete
(
self
,
etype
,
vref
):
return
orig_add_main_variable_delete
(
self
,
bw_normalize_etype
(
etype
),
vref
)
orig_add_main_variable_delete
=
stmts
.
Delete
.
add_main_variable
stmts
.
Delete
.
add_main_variable
=
bw_add_main_variable_delete
def
bw_add_main_variable_insert
(
self
,
etype
,
vref
):
return
orig_add_main_variable_insert
(
self
,
bw_normalize_etype
(
etype
),
vref
)
orig_add_main_variable_insert
=
stmts
.
Insert
.
add_main_variable
stmts
.
Insert
.
add_main_variable
=
bw_add_main_variable_insert
def
bw_set_statement_type
(
self
,
etype
):
return
orig_set_statement_type
(
self
,
bw_normalize_etype
(
etype
))
orig_set_statement_type
=
stmts
.
Select
.
set_statement_type
stmts
.
Select
.
set_statement_type
=
bw_set_statement_type
cubicweb/server/ssplanner.py
View file @
6350e0a4
...
...
@@ -24,7 +24,7 @@ from rql.nodes import Constant, Relation
from
cubicweb
import
QueryError
from
cubicweb.schema
import
VIRTUAL_RTYPES
from
cubicweb.rqlrewrite
import
add_types_restriction
from
cubicweb.rqlrewrite
import
add_types_restriction
,
RQLRelationRewriter
from
cubicweb.server.edition
import
EditedEntity
READ_ONLY_RTYPES
=
set
((
'eid'
,
'has_text'
,
'is'
,
'is_instance_of'
,
'identity'
))
...
...
@@ -302,6 +302,9 @@ class SSPlanner(object):
union
.
append
(
select
)
select
.
clean_solutions
(
solutions
)
add_types_restriction
(
self
.
schema
,
select
)
# Rewrite computed relations
rewriter
=
RQLRelationRewriter
(
plan
.
cnx
)
rewriter
.
rewrite
(
union
,
plan
.
args
)
self
.
rqlhelper
.
annotate
(
union
)
return
self
.
build_select_plan
(
plan
,
union
)
...
...
cubicweb/server/test/unittest_querier.py
View file @
6350e0a4
...
...
@@ -1404,6 +1404,16 @@ Any P1,B,E WHERE P1 identity P2 WITH
self
.
assertEqual
(
len
(
rset
.
rows
),
1
)
self
.
assertEqual
(
rset
.
description
,
[(
'CWUser'
,)])
# computed relation tests ##################################################
def
test_computed_relation_write_queries
(
self
):
"""Ensure we can use computed relation in WHERE clause of write queries"""
with
self
.
admin_access
.
cnx
()
as
cnx
:
cnx
.
execute
(
'INSERT Personne P: P nom "user", P login_user U WHERE NOT U user_login P'
)
cnx
.
execute
(
'DELETE P login_user U WHERE U user_login P'
)
cnx
.
execute
(
'DELETE Personne P WHERE U user_login P'
)
cnx
.
execute
(
'SET U login "people" WHERE U user_login P'
)
# ZT datetime tests ########################################################
def
test_tz_datetime
(
self
):
...
...
cubicweb/web/application.py
View file @
6350e0a4
...
...
@@ -79,11 +79,11 @@ def anonymized_request(req):
from
cubicweb.web.views.authentication
import
Session
orig_cnx
=
req
.
cnx
anon_cnx
=
anonymous_cnx
(
orig_cnx
.
session
.
repo
)
anon_cnx
=
anonymous_cnx
(
orig_cnx
.
repo
)
try
:
with
anon_cnx
:
# web request expect a session attribute on cnx referencing the web session
anon_cnx
.
session
=
Session
(
orig_cnx
.
session
.
repo
,
anon_cnx
.
user
)
anon_cnx
.
session
=
Session
(
orig_cnx
.
repo
,
anon_cnx
.
user
)
req
.
set_cnx
(
anon_cnx
)
yield
req
finally
:
...
...
cubicweb/web/test/unittest_uicfg.py
View file @
6350e0a4
# copyright 2003
-2010
LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# copyright 2003 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
...
...
@@ -15,23 +15,26 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
import
copy
import
warnings
from
logilab.common.testlib
import
tag
from
cubicweb.devtools.testlib
import
CubicWebTC
from
yams.buildobjs
import
RelationDefinition
,
EntityType
from
cubicweb.devtools.testlib
import
CubicWebTC
,
BaseTestCase
from
cubicweb.schema
import
build_schema_from_namespace
from
cubicweb.web
import
uihelper
,
formwidgets
as
fwdgs
from
cubicweb.web.views
import
uicfg
abaa
=
uicfg
.
actionbox_appearsin_addmenu
class
UICFGTC
(
CubicWebTC
):
def
test_default_actionbox_appearsin_addmenu_config
(
self
):
self
.
assertFalse
(
abaa
.
etype_get
(
'TrInfo'
,
'wf_info_for'
,
'object'
,
'CWUser'
))
class
DefinitionOrderTC
(
CubicWebTC
):
"""This test check that when multiple definition could match a key, only
the more accurate apply"""
...
...
@@ -41,19 +44,19 @@ class DefinitionOrderTC(CubicWebTC):
for
rtag
in
(
uicfg
.
autoform_section
,
uicfg
.
autoform_field_kwargs
):
rtag
.
_old_tagdefs
=
copy
.
deepcopy
(
rtag
.
_tagdefs
)
new_def
=
(
((
'*'
,
'login'
,
'*'
),
{
'formtype'
:
'main'
,
'section'
:
'hidden'
}),
((
'*'
,
'login'
,
'*'
),
{
'formtype'
:
'muledit'
,
'section'
:
'hidden'
}),
((
'CWUser'
,
'login'
,
'*'
),
{
'formtype'
:
'main'
,
'section'
:
'attributes'
}),
((
'CWUser'
,
'login'
,
'*'
),
{
'formtype'
:
'muledit'
,
'section'
:
'attributes'
}),
((
'CWUser'
,
'login'
,
'String'
),
{
'formtype'
:
'main'
,
'section'
:
'inlined'
}),
((
'CWUser'
,
'login'
,
'String'
),
{
'formtype'
:
'inlined'
,
'section'
:
'attributes'
}),
)
((
'*'
,
'login'
,
'*'
),
{
'formtype'
:
'main'
,
'section'
:
'hidden'
}),
((
'*'
,
'login'
,
'*'
),
{
'formtype'
:
'muledit'
,
'section'
:
'hidden'
}),
((
'CWUser'
,
'login'
,
'*'
),
{
'formtype'
:
'main'
,
'section'
:
'attributes'
}),
((
'CWUser'
,
'login'
,
'*'
),
{
'formtype'
:
'muledit'
,
'section'
:
'attributes'
}),
((
'CWUser'
,
'login'
,
'String'
),
{
'formtype'
:
'main'
,
'section'
:
'inlined'
}),
((
'CWUser'
,
'login'
,
'String'
),
{
'formtype'
:
'inlined'
,
'section'
:
'attributes'
}),
)
for
key
,
kwargs
in
new_def
:
uicfg
.
autoform_section
.
tag_subject_of
(
key
,
**
kwargs
)
...
...
@@ -62,13 +65,11 @@ class DefinitionOrderTC(CubicWebTC):
for
rtag
in
(
uicfg
.
autoform_section
,
uicfg
.
autoform_field_kwargs
):
rtag
.
_tagdefs
=
rtag
.
_old_tagdefs
@
tag
(
'uicfg'
)
def
test_definition_order_hidden
(
self
):
result
=
uicfg
.
autoform_section
.
get
(
'CWUser'
,
'login'
,
'String'
,
'subject'
)
expected
=
set
([
'main_inlined'
,
'muledit_attributes'
,
'inlined_attributes'
])
self
.
assertSetEqual
(
result
,
expected
)
@
tag
(
'uihelper'
,
'order'
,
'func'
)
def
test_uihelper_set_fields_order
(
self
):
afk_get
=
uicfg
.
autoform_field_kwargs
.
get
self
.
assertEqual
(
afk_get
(
'CWUser'
,
'firstname'
,
'String'
,
'subject'
),
{})
...
...
@@ -78,7 +79,6 @@ class DefinitionOrderTC(CubicWebTC):
self
.
assertTrue
(
issubclass
(
w
[
-
1
].
category
,
DeprecationWarning
))
self
.
assertEqual
(
afk_get
(
'CWUser'
,
'firstname'
,
'String'
,
'subject'
),
{
'order'
:
1
})
@
tag
(
'uicfg'
,
'order'
,
'func'
)
def
test_uicfg_primaryview_set_fields_order
(
self
):
pvdc
=
uicfg
.
primaryview_display_ctrl
pvdc
.
set_fields_order
(
'CWUser'
,
(
'login'
,
'firstname'
,
'surname'
))
...
...
@@ -86,7 +86,6 @@ class DefinitionOrderTC(CubicWebTC):
self
.
assertEqual
(
pvdc
.
get
(
'CWUser'
,
'firstname'
,
'String'
,
'subject'
),
{
'order'
:
1
})
self
.
assertEqual
(
pvdc
.
get
(
'CWUser'
,
'surname'
,
'String'
,
'subject'
),
{
'order'
:
2
})
@
tag
(
'uihelper'
,
'kwargs'
,
'func'
)
def
test_uihelper_set_field_kwargs
(
self
):
afk_get
=
uicfg
.
autoform_field_kwargs
.
get
self
.
assertEqual
(
afk_get
(
'CWUser'
,
'firstname'
,
'String'
,
'subject'
),
{})
...
...
@@ -97,7 +96,6 @@ class DefinitionOrderTC(CubicWebTC):
self
.
assertTrue
(
issubclass
(
w
[
-
1
].
category
,
DeprecationWarning
))
self
.
assertEqual
(
afk_get
(
'CWUser'
,
'firstname'
,
'String'
,
'subject'
),
{
'widget'
:
wdg
})
@
tag
(
'uihelper'
,
'hidden'
,
'func'
)
def
test_uihelper_hide_fields
(
self
):
# original conf : in_group is edited in 'attributes' section everywhere
section_conf
=
uicfg
.
autoform_section
.
get
(
'CWUser'
,
'in_group'
,
'*'
,
'subject'
)
...
...
@@ -117,13 +115,14 @@ class DefinitionOrderTC(CubicWebTC):
section_conf
=
uicfg
.
autoform_section
.
get
(
'CWUser'
,
'in_group'
,
'*'
,
'subject'
)
self
.
assertCountEqual
(
section_conf
,
[
'main_hidden'
,
'muledit_hidden'
])
@
tag
(
'uihelper'
,
'hidden'
,
'formconfig'
)
def
test_uihelper_formconfig
(
self
):
afk_get
=
uicfg
.
autoform_field_kwargs
.
get
class
CWUserFormConfig
(
uihelper
.
FormConfig
):
etype
=
'CWUser'
hidden
=
(
'in_group'
,)
fields_order
=
(
'login'
,
'firstname'
)
section_conf
=
uicfg
.
autoform_section
.
get
(
'CWUser'
,
'in_group'
,
'*'
,
'subject'
)
self
.
assertCountEqual
(
section_conf
,
[
'main_hidden'
,
'muledit_attributes'
])
self
.
assertEqual
(
afk_get
(
'CWUser'
,
'firstname'
,
'String'
,
'subject'
),
{
'order'
:
1
})
...
...
@@ -148,6 +147,55 @@ class UicfgRegistryTC(CubicWebTC):
self
.
assertTrue
(
obj
is
custom_afs
)
def
_schema
():
class
Personne
(
EntityType
):
pass
class
Societe
(
EntityType
):
pass
class
Tag
(
EntityType
):
pass
class
travaille
(
RelationDefinition
):
subject
=
'Personne'
object
=
'Societe'
class
tags
(
RelationDefinition
):
subject
=
'Tag'
object
=
(
'Personne'
,
'Societe'
,
'Tag'
)
return
build_schema_from_namespace
(
locals
().
items
())
class
AutoformSectionTC
(
BaseTestCase
):
def
test_derivation
(
self
):
schema
=
_schema
()
afs
=
uicfg
.
AutoformSectionRelationTags
()
afs
.
tag_subject_of
((
'Personne'
,
'travaille'
,
'*'
),
'main'
,
'relations'
)
afs
.
tag_object_of
((
'*'
,
'travaille'
,
'Societe'
),
'main'
,
'relations'
)
afs
.
tag_subject_of
((
'Tag'
,
'tags'
,
'*'
),
'main'
,
'relations'
)
afs2
=
afs
.
derive
(
__name__
,
afs
.
__select__
)
afs2
.
tag_subject_of
((
'Personne'
,
'travaille'
,
'*'
),
'main'
,
'attributes'
)
afs2
.
tag_object_of
((
'*'
,
'travaille'
,
'Societe'
),
'main'
,
'attributes'
)
afs2
.
tag_subject_of
((
'Tag'
,
'tags'
,
'Societe'
),
'main'
,
'attributes'
)
afs
.
init
(
schema
)
afs2
.
init
(
schema
)
self
.
assertEqual
(
afs2
.
etype_get
(
'Tag'
,
'tags'
,
'subject'
,
'Personne'
),
set
((
'main_relations'
,
'muledit_hidden'
,
'inlined_relations'
)))
self
.
assertEqual
(
afs2
.
etype_get
(
'Tag'
,
'tags'
,
'subject'
,
'Societe'
),
set
((
'main_attributes'
,
'muledit_hidden'
,
'inlined_attributes'
)))
self
.
assertEqual
(
afs2
.
etype_get
(
'Personne'
,
'travaille'
,
'subject'
,
'Societe'
),
set
((
'main_attributes'
,
'muledit_hidden'
,
'inlined_attributes'
)))
self
.
assertEqual
(
afs2
.
etype_get
(
'Societe'
,
'travaille'
,
'object'
,
'Personne'
),
set
((
'main_attributes'
,
'muledit_hidden'
,
'inlined_attributes'
)))
if
__name__
==
'__main__'
:
from
logilab.common.testlib
import
unittest
_main
unittest
_
main
()
import
unittest
unittest
.
main
()
cubicweb/web/views/autoform.py
View file @
6350e0a4
# copyright 2003
-2013
LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# copyright 2003 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
...
...
@@ -118,16 +118,10 @@ checking for dark-corner case where it can't be verified properly.
.. Controlling the generic relation fields
"""
from
cubicweb
import
_
from
warnings
import
warn
from
six.moves
import
range
from
logilab.mtconverter
import
xml_escape
from
logilab.common.decorators
import
iclassmethod
,
cached
from
logilab.common.deprecation
import
deprecated
from
logilab.common.registry
import
NoSelectableObject
from
cubicweb
import
neg_role
,
uilib
...
...
@@ -185,7 +179,7 @@ class InlinedFormField(ff.Field):
return
False
def
process_posted
(
self
,
form
):
pass
# handled by the subform
pass
# handled by the subform
class
InlineEntityEditionFormView
(
f
.
FormViewMixIn
,
EntityView
):
...
...
@@ -237,7 +231,7 @@ class InlineEntityEditionFormView(f.FormViewMixIn, EntityView):
**
self
.
cw_extra_kwargs
)
if
self
.
pform
is
None
:
form
.
restore_previous_post
(
form
.
session_key
())
#assert form.parent_form
#
assert form.parent_form
self
.
add_hiddens
(
form
,
entity
)
return
form
...
...
@@ -261,7 +255,7 @@ class InlineEntityEditionFormView(f.FormViewMixIn, EntityView):
entity
=
self
.
_entity
()
rdef
=
entity
.
e_schema
.
rdef
(
self
.
rtype
,
neg_role
(
self
.
role
),
self
.
petype
)
card
=
rdef
.
role_cardinality
(
self
.
role
)
if
card
==
'1'
:
# don't display remove link
if
card
==
'1'
:
# don't display remove link
return
None
# if cardinality is 1..n (+), dont display link to remove an inlined form for the first form
# allowing to edit the relation. To detect so:
...
...
@@ -294,7 +288,7 @@ class InlineEntityEditionFormView(f.FormViewMixIn, EntityView):
except
KeyError
:
self
.
_cw
.
data
[
countkey
]
=
1
self
.
form
.
render
(
w
=
self
.
w
,
divid
=
divid
,
title
=
title
,
removejs
=
removejs
,
i18nctx
=
i18nctx
,
counter
=
self
.
_cw
.
data
[
countkey
]
,
i18nctx
=
i18nctx
,
counter
=
self
.
_cw
.
data
[
countkey
],
**
kwargs
)
def
form_title
(
self
,
entity
,
i18nctx
):
...
...
@@ -374,21 +368,21 @@ class InlineAddNewLinkView(InlineEntityCreationFormView):
&
specified_etype_implements
(
'Any'
))
_select_attrs
=
InlineEntityCreationFormView
.
_select_attrs
+
(
'card'
,)
card
=
None
# make pylint happy
form
=
None
# no actual form wrapped
card
=
None
# make pylint happy
form
=
None
# no actual form wrapped
def
call
(
self
,
i18nctx
,
**
kwargs
):
self
.
_cw
.
set_varmaker
()
divid
=
"addNew%s%s%s:%s"
%
(
self
.
etype
,
self
.
rtype
,
self
.
role
,
self
.
peid
)
self
.
w
(
u
'<div class="inlinedform" id="%s" cubicweb:limit="true">'
%
divid
)
%
divid
)
js
=
"addInlineCreationForm('%s', '%s', '%s', '%s', '%s', '%s')"
%
(
self
.
peid
,
self
.
petype
,
self
.
etype
,
self
.
rtype
,
self
.
role
,
i18nctx
)
if
self
.
pform
.
should_hide_add_new_relation_link
(
self
.
rtype
,
self
.
card
):
js
=
"toggleVisibility('%s'); %s"
%
(
divid
,
js
)
__
=
self
.
_cw
.
pgettext
self
.
w
(
u
'<a class="addEntity" id="add%s:%slink" href="javascript: %s" >+ %s.</a>'
%
(
self
.
rtype
,
self
.
peid
,
js
,
__
(
i18nctx
,
'add a %s'
%
self
.
etype
)))
%
(
self
.
rtype
,
self
.
peid
,
js
,
__
(
i18nctx
,
'add a %s'
%
self
.
etype
)))
self
.
w
(
u
'</div>'
)
...
...
@@ -400,6 +394,7 @@ def relation_id(eid, rtype, role, reid):
return
u
'%s:%s:%s'
%
(
eid
,
rtype
,
reid
)
return
u
'%s:%s:%s'
%
(
reid
,
rtype
,
eid
)
def
toggleable_relation_link
(
eid
,
nodeid
,
label
=
'x'
):
"""return javascript snippet to delete/undelete a relation between two