--- a/web/views/editcontroller.py Mon Dec 21 20:27:14 2009 +0100
+++ b/web/views/editcontroller.py Mon Dec 21 20:28:01 2009 +0100
@@ -72,7 +72,7 @@
req.set_shared_data('__maineid', form['__maineid'], querydata=True)
# no specific action, generic edition
self._to_create = req.data['eidmap'] = {}
- self._pending_relations = []
+ self._pending_fields = req.data['pendingfields'] = []
todelete = self._cw.get_pending_deletes()
toinsert = self._cw.get_pending_inserts()
try:
@@ -85,19 +85,18 @@
method = getattr(entity, methodname)
method(formparams)
eid = self.edit_entity(formparams)
- except (RequestError, NothingToEdit):
+ except (RequestError, NothingToEdit), ex:
if '__linkto' in req.form and 'eid' in req.form:
self.execute_linkto()
elif not ('__delete' in req.form or '__insert' in req.form or todelete or toinsert):
- raise ValidationError(None, {None: req._('nothing to edit')})
+ raise ValidationError(None, {None: unicode(ex)})
+ # handle relations in newly created entities
+ if self._pending_fields:
+ for form, field in self._pending_fields:
+ self.handle_formfield(form, field)
+ # execute rql to set all relations
for querydef in self.relations_rql:
self._cw.execute(*querydef)
- # handle relations in newly created entities
- # XXX find a way to merge _pending_relations and relations_rql
- if self._pending_relations:
- for form, field, entity in self._pending_relations:
- for querydef in self.handle_relation(form, field, entity, True):
- self._cw.execute(*querydef)
# XXX this processes *all* pending operations of *all* entities
if req.form.has_key('__delete'):
todelete += req.list_form_param('__delete', req.form, pop=True)
@@ -108,6 +107,9 @@
if toinsert:
self.insert_relations(parse_relations_descr(toinsert))
self._cw.remove_pending_operations()
+ if self.errors:
+ errors = dict((f.name, unicode(ex)) for f, ex in self.errors)
+ raise ValidationError(form.get('__maineid'), errors)
def _insert_entity(self, etype, eid, rqlquery):
rql = rqlquery.insert_query(etype)
@@ -125,17 +127,15 @@
return neweid
def _update_entity(self, eid, rqlquery):
- rql = rqlquery.update_query(eid)
- self._cw.execute(rql, rqlquery.kwargs)
+ self._cw.execute(rqlquery.update_query(eid), rqlquery.kwargs)
def edit_entity(self, formparams, multiple=False):
"""edit / create / copy an entity and return its eid"""
etype = formparams['__type']
entity = self._cw.vreg['etypes'].etype_class(etype)(self._cw)
entity.eid = formparams['eid']
- eid = self._get_eid(entity.eid)
is_main_entity = self._cw.form.get('__maineid') == formparams['eid']
- # let a chance to do some entity specific stuff.tn
+ # let a chance to do some entity specific stuff
entity.pre_web_edit()
# create a rql query from parameters
rqlquery = RqlQuery()
@@ -144,9 +144,26 @@
# a few dark corners
formid = self._cw.form.get('__form_id', 'edition')
form = self._cw.vreg['forms'].select(formid, self._cw, entity=entity)
- for field in form.fields:
- if form.form_field_modified(field):
- self.handle_formfield(form, field, entity, rqlquery)
+ eid = form.actual_eid(entity.eid)
+ try:
+ editedfields = formparams['_cw_edited_fields']
+ except KeyError:
+ raise RequestError(self._cw._('no edited fields specified for entity %s' % entity.eid))
+ for editedfield in splitstrip(editedfields):
+ try:
+ name, role = editedfield.split('-')
+ except:
+ name = editedfield
+ role = None
+ if form.field_by_name.im_func.func_code.co_argcount == 4:
+ field = form.field_by_name(name, role, eschema=entity.e_schema)
+ else:
+ field = form.field_by_name(name, role)
+ if field.has_been_modified(form):
+ self.handle_formfield(form, field, rqlquery)
+ if self.errors:
+ errors = dict((f.name, unicode(ex)) for f, ex in self.errors)
+ raise ValidationError(entity.eid, errors)
if eid is None: # creation or copy
entity.eid = self._insert_entity(etype, formparams['eid'], rqlquery)
elif rqlquery.edited: # edition of an existant entity
@@ -165,10 +182,10 @@
self.execute_linkto(entity.eid)
return eid
- def handle_formfield(self, form, field, entity, rqlquery):
- eschema = entity.e_schema
+ def handle_formfield(self, form, field, rqlquery=None):
+ eschema = form.edited_entity.e_schema
try:
- for attr, value in field.process_posted(form):
+ for field, value in field.process_posted(form):
if not (
(field.role == 'subject' and field.name in eschema.subjrels)
or
@@ -176,16 +193,64 @@
continue
rschema = self._cw.vreg.schema.rschema(field.name)
if rschema.final:
- rqlquery.kwargs[attr] = value
- rqlquery.edited.append('X %s %%(%s)s' % (attr, attr))
- elif rschema.inlined:
- self.handle_inlined_relation(form, field, entity, rqlquery)
+ rqlquery.kwargs[field.name] = value
+ rqlquery.edited.append('X %s %%(%s)s' % (rschema, rschema))
else:
- self.relations_rql += self.handle_relation(
- form, field, entity)
+ if form.edited_entity.has_eid():
+ origvalues = set(entity.eid for entity in form.edited_entity.related(field.name, field.role, entities=True))
+ else:
+ origvalues = set()
+ if value is None or value == origvalues:
+ continue # not edited / not modified / to do later
+ if rschema.inlined and rqlquery is not None:
+ self.handle_inlined_relation(form, field, value, origvalues, rqlquery)
+ elif form.edited_entity.has_eid():
+ self.handle_relation(form, field, value, origvalues)
+ else:
+ self._pending_fields.append( (form, field) )
+
except ProcessFormError, exc:
self.errors.append((field, exc))
+ def handle_inlined_relation(self, form, field, values, origvalues, rqlquery):
+ """handle edition for the (rschema, x) relation of the given entity
+ """
+ attr = field.name
+ if values:
+ rqlquery.kwargs[attr] = iter(values).next()
+ rqlquery.edited.append('X %s %s' % (attr, attr.upper()))
+ rqlquery.restrictions.append('%s eid %%(%s)s' % (attr.upper(), attr))
+ elif form.edited_entity.has_eid():
+ self.handle_relation(form, field, values, origvalues)
+
+ def handle_relation(self, form, field, values, origvalues):
+ """handle edition for the (rschema, x) relation of the given entity
+ """
+ etype = form.edited_entity.e_schema
+ rschema = self._cw.vreg.schema.rschema(field.name)
+ if field.role == 'subject':
+ desttype = rschema.objects(etype)[0]
+ card = rschema.rdef(etype, desttype).cardinality[0]
+ subjvar, objvar = 'X', 'Y'
+ else:
+ desttype = rschema.subjects(etype)[0]
+ card = rschema.rdef(desttype, etype).cardinality[1]
+ subjvar, objvar = 'Y', 'X'
+ eid = form.edited_entity.eid
+ if field.role == 'object' or not rschema.inlined or not values:
+ # this is not an inlined relation or no values specified,
+ # explicty remove relations
+ rql = 'DELETE %s %s %s WHERE X eid %%(x)s, Y eid %%(y)s' % (
+ subjvar, rschema, objvar)
+ for reid in origvalues.difference(values):
+ self.relations_rql.append((rql, {'x': eid, 'y': reid}, ('x', 'y')))
+ seteids = values.difference(origvalues)
+ if seteids:
+ rql = 'SET %s %s %s WHERE X eid %%(x)s, Y eid %%(y)s' % (
+ subjvar, rschema, objvar)
+ for reid in seteids:
+ self.relations_rql.append((rql, {'x': eid, 'y': reid}, ('x', 'y')))
+
def _action_apply(self):
self._default_publish()
self.reset()
@@ -201,92 +266,4 @@
self.delete_entities(self._cw.edited_eids(withtype=True))
return self.reset()
- def _relation_values(self, form, field, entity, late=False):
- """handle edition for the (rschema, x) relation of the given entity
- """
- values = set()
- for eid in field.process_form_value(form):
- if not eid: # AutoCompletionWidget
- continue
- typed_eid = self._get_eid(eid)
- if typed_eid is None:
- if late:
- # eid is still None while it's already a late call
- # this mean that the associated entity has not been created
- raise Exception("eid %s is still not created" % eid)
- self._pending_relations.append( (form, field, entity) )
- return None
- values.add(typed_eid)
- return values
- def handle_inlined_relation(self, form, field, entity, rqlquery):
- """handle edition for the (rschema, x) relation of the given entity
- """
- if entity.has_eid():
- origvalues = set(row[0] for row in entity.related(field.name, field.role))
- else:
- origvalues = set()
- values = self._relation_values(form, field, entity)
- if values is None or values == origvalues:
- return # not edited / not modified / to do later
- attr = field.name
- if values:
- rqlquery.kwargs[attr] = iter(values).next()
- rqlquery.edited.append('X %s %s' % (attr, attr.upper()))
- rqlquery.restrictions.append('%s eid %%(%s)s' % (attr.upper(), attr))
- elif entity.has_eid():
- self.relations_rql += self.handle_relation(form, field, entity)
-
- def handle_relation(self, form, field, entity, late=False):
- """handle edition for the (rschema, x) relation of the given entity
- """
- if entity.has_eid():
- origvalues = set(row[0] for row in entity.related(field.name, field.role))
- else:
- origvalues = set()
- values = self._relation_values(form, field, entity, late)
- if values is None or values == origvalues:
- return # not edited / not modified / to do later
- etype = entity.e_schema
- rschema = self._cw.vreg.schema.rschema(field.name)
- if field.role == 'subject':
- desttype = rschema.objects(etype)[0]
- card = rschema.rproperty(etype, desttype, 'cardinality')[0]
- subjvar, objvar = 'X', 'Y'
- else:
- desttype = rschema.subjects(etype)[0]
- card = rschema.rproperty(desttype, etype, 'cardinality')[1]
- subjvar, objvar = 'Y', 'X'
- eid = entity.eid
- if field.role == 'object' or not rschema.inlined or not values:
- # this is not an inlined relation or no values specified,
- # explicty remove relations
- rql = 'DELETE %s %s %s WHERE X eid %%(x)s, Y eid %%(y)s' % (
- subjvar, rschema, objvar)
- for reid in origvalues.difference(values):
- yield (rql, {'x': eid, 'y': reid}, ('x', 'y'))
- seteids = values.difference(origvalues)
- if seteids:
- rql = 'SET %s %s %s WHERE X eid %%(x)s, Y eid %%(y)s' % (
- subjvar, rschema, objvar)
- for reid in seteids:
- yield (rql, {'x': eid, 'y': reid}, ('x', 'y'))
-
- def _get_eid(self, eid):
- # should be either an int (existant entity) or a variable (to be
- # created entity)
- assert eid or eid == 0, repr(eid) # 0 is a valid eid
- try:
- return typed_eid(eid)
- except ValueError:
- try:
- return self._to_create[eid]
- except KeyError:
- self._to_create[eid] = None
- return None
-
- def _linked_eids(self, eids, late=False):
- """return a list of eids if they are all known, else raise ToDoLater
- """
-
-