I'm writing Zope product supposed to give shopping cart functionality. Order can be specified and completed by anonymous user; user should be prompted for password in latest possible moment, i.e. when throwing order to the cart. Order is remembered in session variable. When user decides that order is complete I call (from unrestricted code) something like: self.Cart().ThrowIn(self.REQUEST) Cart() returns instance of `current' shopping cart (one that user is currently using); when there is no current cart, one is created; when user isn't logged in, Unauthorized is raised. Cart is not calling object's own method but independent callable object acquired by calling object. Now when user isn't logged in, Cart() raises Unauthorized, user gets asked for login and password, and boom! We have no order data in REQUEST.SESSION after authentication. I read in one of recent posts on this list that it's because exception aborts ZODB transaction, so I tried to work around the problem by committing transaction before calling Cart(), so now our fragment looks like this: get_transaction().commit() self.Cart().ThrowIn(self.REQUEST) It seems to work for now but I'm not really sure if such messing with something usually done automagically by Zope won't have some obscure and nasty side effects. Am I doing something dangerous now or is this the Right Way to deal with my problem and if it's not then what is? --japh -- __ Maciek Pasternacki <maciekp@japhy.fnord.org> [ http://japhy.fnord.org/ ] `| _ |_\ / { Any road followed to its end leads precisely nowhere. Climb ,|{-}|}| }\/ the mountain just a little to test it's a mountain. From the top \/ |____/ of the mountain you cannot see the mountain. } ( F.Herbert ) -><-
* Maciek Pasternacki <maciekp@japhy.fnord.org> [2004-08-08 05:57]:
I'm writing Zope product supposed to give shopping cart functionality. Order can be specified and completed by anonymous user; user should be prompted for password in latest possible moment, i.e. when throwing order to the cart. Order is remembered in session variable. When user decides that order is complete I call (from unrestricted code) something like:
self.Cart().ThrowIn(self.REQUEST)
Cart() returns instance of `current' shopping cart (one that user is currently using); when there is no current cart, one is created; when user isn't logged in, Unauthorized is raised. Cart is not calling object's own method but independent callable object acquired by calling object.
Now when user isn't logged in, Cart() raises Unauthorized, user gets asked for login and password, and boom! We have no order data in REQUEST.SESSION after authentication. I read in one of recent posts on this list that it's because exception aborts ZODB transaction, so I tried to work around the problem by committing transaction before calling Cart(), so now our fragment looks like this:
get_transaction().commit() self.Cart().ThrowIn(self.REQUEST)
It seems to work for now but I'm not really sure if such messing with something usually done automagically by Zope won't have some obscure and nasty side effects. Am I doing something dangerous now or is this the Right Way to deal with my problem and if it's not then what is?
There's nothing wrong with committing a transaction by hand - it can be very useful at times. Just make sure that you are not committing state that you actually don't want persisted in cases where exceptions other than Unauthorized are raised. Or put differently, only commit when the user is anonymous. -- Roché Compaan Upfront Systems http://www.upfrontsystems.co.za
Maciek Pasternacki wrote at 2004-8-8 05:18 +0200:
... get_transaction().commit() self.Cart().ThrowIn(self.REQUEST)
It seems to work for now but I'm not really sure if such messing with something usually done automagically by Zope won't have some obscure and nasty side effects. Am I doing something dangerous now or is this the Right Way to deal with my problem and if it's not then what is?
In general, it is not a good idea to explicitly commit a transaction: If after the "commit" a "ConflictError" occurs (which is not that unlikely when you modify the ZODB), then the publisher will retry the requests. This means that the transaction you already committed is performed again. In your case, this may not make a problem, though. -- Dieter
On Sweetmorn, Bureaucracy 2, 3170 YOLD, Dieter Maurer wrote:
... get_transaction().commit() self.Cart().ThrowIn(self.REQUEST)
It seems to work for now but I'm not really sure if such messing with something usually done automagically by Zope won't have some obscure and nasty side effects. Am I doing something dangerous now or is this the Right Way to deal with my problem and if it's not then what is?
In general, it is not a good idea to explicitly commit a transaction:
If after the "commit" a "ConflictError" occurs (which is not that unlikely when you modify the ZODB), then the publisher will retry the requests. This means that the transaction you already committed is performed again.
In my case, if request is replayed exactly as if from the Web, it shouldn't do any harm. Before committing I leave `completion mark' in session variables so that on next hit on the same URL application goes directly to self.Cart().ThrowIn() (ThrowIn() gets all data from SESSION and nothing directly from REQUEST), so either my data was saved to SESSION, Cart() raises Unauthorized (or not) and CookieCrumbler takes control (or not), or my data was not saved and it gets created again from the same request, completion mark is saved, this time successfully, code goes on to Cart(), and Unauthorized is raised (or not). In either case, data is either completed in SESSION, marked as such and not touched again regardless of REQUEST, or it's not there and REQUEST is processed once again beginning from state identical to request start. Please correct me if I'm wrong at some point or if there's some other way to save data and let it survive an exception. -- __ Maciek Pasternacki <maciekp@japhy.fnord.org> [ http://japhy.fnord.org/ ] `| _ |_\ / { ...For I was born with a habit, from a sign, ,|{-}|}| }\/ the habit of a windswept thumb, \/ |____/ and a sign of the rain... } ( Fish ) -><-
participants (3)
-
Dieter Maurer -
Maciek Pasternacki -
Roché Compaan