Logo Search packages:      
Sourcecode: zope-emarket version File versions



Simple EMarket product implementation.

An EMarket is a collection of classes, folders and documents that
implement a simple online shopping area. There are two main managers
that keep things organized. 1) A shopper manager, for all the online
shoppers and 2) a marketItems manager to keep the items to be
sold. Now that we're using ZPatterns, we've also exposed a
'transactionManager', a 'basketManager', and a 'basketItemManager'.
These allow the developer to implement each of these in a variety of
ways using the extreme flexibility of ZPatterns. The default
implementation works, that's about all we can say for it. ;-)

Steve Spicklemire
Silicon Prairie Ventures Inc.


__version__='$Revision: 1.83 $'[11:-2]

from Globals import HTMLFile, MessageDialog, Persistent, DateTime
from Persistence import PersistentMapping
import OFS.SimpleItem, Acquisition, AccessControl.Role
import OFS.Folder, OFS.Document
import Products.MailHost.MailHost
from Products import ZPatterns
import ShopperManager
import MarketItemManager
import BasketManager
import traceback
import StringIO
import string
from socket import gethostname
import time
import random

Specialists = ZPatterns.Specialists

Folder = OFS.Folder.Folder
Document = OFS.Document.Document

EMarketError = 'Emarket Error'

# these are kinda random

randWords = ['foo','bar','shoo','fork','spoon','table','car','stairs',
randSymbs = ['%','$','#','*']

# Prepare a bunch of sources to include as default initial
# docs for the folders.....

def GetHTML(name):
    return HTMLFile(name, globals())

# --- Main EMarket Folder DTML Sources... -----
# some of these really should be torn out... they relate to
# 'functionality' that is no longer supported, and therefore
# it's bogus to keep them here.... but no time right now to
# sort it all out...

mainMarketDTML = {'index_html':(GetHTML('eMarketMain'), "Main EMarket Page"),
                  'newUserFormFields':(GetHTML('newUserFields'), "Input fields for new user"),
                  'setUserCookie':(GetHTML('setUserCookie'), "Prepare to set the cookie...."),
                  'register':(GetHTML('register'), "Register as a past user...."),
                  'sendPassword':(GetHTML('sendPassword'), "Send a forgotten password"),
                  'redirectToShoppingCart':(GetHTML('redirectToShoppingCart'), "Redirect to Shopping Cart Area"),
                  #'redirectToSalesItems':(GetHTML('redirectToSalesItems'), "Redirect to Sales Items Area"),
                  'redirectToEMarket':(GetHTML('redirectToEMarket'), "Redirect to Main Market"),
                  #'redirectToEditInfo':(GetHTML('redirectToEditInfo'), "Redirect to Edit Page"),
                  #'redirectToPastTransactions':(GetHTML('redirectToPastTransactions'), "Redirect to Past Transactions"),
                  'addToShoppingCart':(GetHTML('addToShoppingCart'), "Add arbitrary item to shopping cart."),
                  'standard_html_footer':(GetHTML('footer'),"Footer dtml"),
                  'logOut':(GetHTML('logOut'),"log out of server..."),
                  'addShopperWrapper':(GetHTML('addShopperWrapper'),"Add New Shopper"),
                  'checkForValues':(GetHTML('checkForValues'),"Check for missing values"),
                  #'productListing':(GetHTML('productListing'),"Generate a nice category list."),
                  'searchresults':(GetHTML('searchresults'),"Catalog Search Results"),

# --- Market Item folder DTML -----

marketItemDTML = {'index_html':(GetHTML('eMarketItemMain'), 'MarketItem Template Page'),
                  'addToCart': (GetHTML('addToCart'), 'Form To add MarketItems to a cart.'),
                  #'shopperMarketItemAddForm': (GetHTML('shopperMarketItemAdd'), 'Form To add MarketItems to sell.'),
                  #'shopperMarketItemEditForm': (GetHTML('shopperMarketItemEditForm'), 'Form To add MarketItems to sell.'),
                  #'listActiveOffers': (GetHTML('listActiveOffers'), 'Active offers for sales item.'),
                  #'acceptOffer': (GetHTML('acceptOffer'), 'Accept offer from a buyer.'),
                  #'displayBids': (GetHTML('displayBids'), 'Display current bids on an item.'),
                  'getItemIds':(GetHTML('getItemIds'),"Get All the Item Ids from this Manager"),
                  'getIdsInCategory':(GetHTML('getIdsInCategory'),"Get the Item Ids from this Manager that are in a category"),
                  'addMarketItem':(GetHTML('addMarketItem'),"Add a new MarketItem"),
                  'addMarketItemForm':(GetHTML('addMarketItemForm'),"Form to Add a new MarketItem"),
                  'manageMarketItems':(GetHTML('manageMarketItems'),"Manage Market Items"),

# --- Shopper Folder DTML ----

shopperDTML = {'addNewItem':(GetHTML('shopperAddItem'),'Response template for adding item'),
               'index_html':(GetHTML('shopperIndex'),'Shopper Template'),
               'showMyBasket':(GetHTML('showMyBasket'),'Shopping basket template'),
               #'showMySales':(GetHTML('showMySales'),'Shopping basket template'),
               #'processOrder':(GetHTML('processOrder'),"Process a shopper's order."),
               'shoppingCart':(GetHTML('shoppingCart'), "Shopping cart area"),
               #'shopperSalesItems':(GetHTML('salesItems'), "Display Sales Items area"),
               'updateCart':(GetHTML('updateCart'), "Update the cart area"),
               #'updateSales':(GetHTML('updateSales'), "Update the sales booth area"),
               #'editSelfShopper':(GetHTML('editSelfShopper'),"Edit a Shopper's Personal Info"),
               'submitOrder':(GetHTML('submitOrder'),"Submit an order for processing"),
               #                             "list of validated transactions"),
               #'acceptableOffer':(GetHTML('acceptableOffer'), "You have made an acceptable offer..."),
               #'confirmOffer':(GetHTML('confirmOffer'),"Confirm Your Offer..."),
               #'confirmOfferForm':(GetHTML('confirmOfferForm'),"Confirm Your Offer..."),
               #'pendingCart':(GetHTML('pendingCart'),"Confirm Your Offer..."),
               'getItemIds':(GetHTML('getItemIds'),"Get All the Item Ids from this Manager"),

wampumboxDTML = {'index_html':(GetHTML('wampum_submitCCTrans'),"Form to submit CC purchase through Wampum"),
                 'processCCTrans':(GetHTML('wampum_processCCTrans'),"Submit CC purchase through Wampum"),

def cmpFolders(folder1, folder2):
    if folder1.title < folder2.title:
        return -1
    elif folder1.title > folder2.title:
        return 1
        return 0

def buildDefaultRack(self, aSpecialist):
    aSpecialist = aSpecialist.__of__(self)
    aSpecialist.RacksGroup._constructPlugIn('Rack', id='defaultRack')
def delDocsFromFolder( theFolder, theDocs ):
    """ Delete the listed docs from the given folder. """
    errs = StringIO.StringIO()
    for key in theDocs.keys():

    return errs.read()
def addDocsToFolder( theFolder, theDocs):
    """ add the listed docs to the given folder """
    errs = StringIO.StringIO()

    for key in theDocs.keys():
        id = key
        dtml,title = theDocs[key]
            thedtml = open(dtml.raw).read()
            raise RuntimeError, "Can't find " + dtml.raw

            theFolder.manage_addDocument(id, title=title, file=thedtml)

    return errs.read()

def updateDocsInFolder( theFolder, theDocs, REQUEST=None ):
    """ update the documents in a folder from theDocs collection """

    processing = []
    errs = StringIO.StringIO()
    for key in theDocs.keys():
        dtml, title = theDocs[key]
        theDTML = open(dtml.raw).read()
        if hasattr(theFolder, key):
            theDoc = getattr(theFolder, key)
            theDoc.manage_edit(data = theDTML, title=title, REQUEST=REQUEST)
            processing.append('Updated document ' + key )
            theFolder.manage_addDTMLMethod(key, title=title, file=theDTML, REQUEST=REQUEST)
            processing.append('Added document ' + key )

    return '<pre>' + string.join(processing,'<br>\n') + '</pre>'

    defaulthost = gethostname()
    defaulthost = 'localhost'

def addMarketItemsManager(self, id, title='', REQUEST=None):
    """ method to add market items folders to a folder. """
    newMarketF = MarketItemManager.MarketItemManager()
    newMarketF.id = id
    newMarketF.title = title

    self._setObject(id, newMarketF)

    buildDefaultRack(self, newMarketF)  # build a rack for MarketItems...

    if REQUEST is None:
        result = newMarketF
        result = MessageDialog(
            title = "OK",
            message='<strong>%s</strong> Has beed added as a MarketItems Folder.' % id,
            action ='./manage_main',

    return result

addEMarketForm=HTMLFile('eMarketAdd', globals(), defaulthost = defaulthost)
def addEMarket(self, id, title='', smtp_host = defaulthost, localhost = defaulthost, processURL='',
               localSecret='', contactInfo='', EMarketURL='', default_html = '', requireLogin = 1,
               addToCartText = 'Add To Cart', install_wampumbox = 0, REQUEST=None):

    Add an EMarket to a folder

    The argument 'self' will be bound to a folder.

    newMainF = EMarket()
    newMainF = newMainF.__of__(self)
    newMainF.id = id
    newMainF.title = title
    newMainF.smtp_host = smtp_host
    newMainF.localhost = localhost
    if processURL=='' and install_wampumbox:
      processURL = 'https' + self.absolute_url()[4:] + '/' + id + \
    newMainF.processURL = processURL
    newMainF.localSecret = localSecret
    newMainF.contactInfo = contactInfo
    newMainF.EMarketURL = EMarketURL
    newMainF.default_html = default_html
    newMainF.requireLogin = requireLogin
    newMainF.addToCartText = addToCartText
    newMainF.biddingAllowed = 0  # default to no...
    newMainF.defaultToAuction = 0 # have new market items default to auction sales
    newMainF.randWords = randWords

    self._setObject(id, newMainF)

    if id in ['shoppers','marketItems','trasactions','basketManager','basketItemManager']:
        raise EMarketError, "The id %s is illegal." % id

    newMarketF = addMarketItemsManager(newMainF, 'marketItems', "Market Items Manager")
    newShopperF = ShopperManager.ShopperManager()
    newShopperF.id = 'shoppers'
    newShopperF.title = "Market Shoppers Manager"
    newMainF._setObject(newShopperF.id, newShopperF)
    buildDefaultRack( newMainF, newShopperF)

    newBasketF = BasketManager.BasketManager()
    newBasketF.id = 'basketManager'
    newBasketF.title = "Basket Manager"
    newMainF._setObject(newBasketF.id, newBasketF)
    buildDefaultRack( newMainF, newBasketF)

    newBasketItemF = BasketManager.BasketItemManager()
    newBasketItemF.id = 'basketItemManager'
    newBasketItemF.title = "Basket Item Manager"
    newMainF._setObject(newBasketItemF.id, newBasketItemF)
    buildDefaultRack( newMainF, newBasketItemF)

    newTransF = Specialists.Specialist()
    newTransF.id = 'transactions'
    newTransF.title = "Transaction Manager"
    newMainF._setObject(newTransF.id, newTransF)
    buildDefaultRack( newMainF, newTransF)

    if install_wampumbox:
        newWampumboxF = Folder()
        newWampumboxF.id = 'wampumbox'
        newWampumboxF.title = 'Wampum Transaction Processor'
        newWampumboxF.meta_types = ()
        newWampumboxF.icon = 'misc_/EMarket/wampumbox'
        Products.Wampum.WampumGenerator.addWampum(newWampumboxF,'Wampum','Wampum Generator',ccps_host='',cybercash_id='',merchant_key='')

        newMainF._setObject(newWampumboxF.id, newWampumboxF)

    addDocsToFolder(newMainF, mainMarketDTML)
    addDocsToFolder(newMarketF, marketItemDTML)
    addDocsToFolder(newShopperF, shopperDTML)

    if install_wampumbox:
        addDocsToFolder(newWampumboxF, wampumboxDTML)
#        x=newWampumboxF.processCCTrans
#        x._proxy_roles=('Manager',)
#        newWampumboxF.processCCTrans=x

    newMainF.shopperFolder = newShopperF
    newMainF.marketFolder = newMarketF
    newMainF.basketManager = newBasketF
    newMainF.basketItemManager = newBasketItemF
    newMainF.transactionFolder = newTransF

    if install_wampumbox:
        newMainF.wampumbox = newWampumboxF
        newMainF.wampumbox = None
    Products.MailHost.MailHost.add(newMainF, 'eMarketMailhost',
                                   smtp_host = smtp_host,
                                   localhost = localhost)

                                                  'Market Items Catalog')


                                                                    'Set Object Attributes.. ',

    if REQUEST is not None:
        return self.manage_main(self, REQUEST, update_menu=1)

class Dummy:

    def __init__(self, title=None):
        self.title = title
    isDummy = 1

    def objectIds(self, foo):
        return [self.title]

    def __repr__(self):
        return `self.title`

dummy = Dummy()

00360 class EMarket(OFS.Folder.Folder):

    """An EMarket class.

    Provide the functions needed to contain an online shopping area.

    # Specify a name for the item type:
    id       ='emarket'
    title    ='EMarket Object'
    icon     ='misc_/EMarket/emarket'
    RegistrationSubject = 'Registration Information'
    RegistrationFrom = 'manager@' + defaulthost              
    EMarketURL = ''                                          # where is 'home'?
    default_html = ''                                        # if we don't want index_html as the default doc.
    administratorEmail = RegistrationFrom                    
    requireLogin = 0
    addToCartText = 'Add Item To My Shopping Cart'
    shoppingCartTitle = 'My Shopping Cart'    
    allowShoppersToSell = 0
    biddingAllowed = 0
    refreshEnabled = 1
    defaultToAuction = 0
    processURL = ''

    _properties=({'id':'title', 'type': 'string', 'mode':'w'},

    manage_options = OFS.Folder.Folder.manage_options + (
        {'label':'DefaultDTML', 'action':'refresh_warning'},)

    # Specify how individual operations add up to "permissions":
      ('View management screens', ('manage_tabs','manage_main')),
      ('Change permissions',      ('manage_access',)           ),
      ('Change EMarkets',         ('refresh_warning', 'refresh_dtml')),
      ('View',                    ('','index_html')),

    refresh_warning = HTMLFile('refresh_warning', globals())

00444     def do_break(self, REQUEST=None, RESPONSE=None, PARENTS=None):
        """ do a break.. """
        import pdb
00449     def refresh_dtml(self, REQUEST=None, ignoreDropErrors = 1):
        """ Refresh all the default DTML documents. """

        if not self.refreshEnabled:
            raise "Bad Request", "<html><br><br><center><b>Sorry.... no refresh allowed.</b></center></html>"
        errText = []
        errText.append(updateDocsInFolder(self, mainMarketDTML, REQUEST=REQUEST))
        errText.append(updateDocsInFolder(self.marketFolder, marketItemDTML, REQUEST=REQUEST))
        errText.append(updateDocsInFolder(self.shopperFolder, shopperDTML, REQUEST=REQUEST))
        if self.wampumbox:
            errText.append(updateDocsInFolder(self.wampumbox, wampumboxDTML, REQUEST=REQUEST))

        errs = string.join(errText)

        result = "<pre>We've Got Results...:\n" + errs + "</pre>"

        if REQUEST is not None:
            return MessageDialog(
                message=result + '<strong>%s</strong> Has default DTML docs now.' % self.id,
                action ='./manage_main',

        return result

00476     def set_cookie(self, RESPONSE = None,
                   REQUEST = None, path = None, parents = None,
                   clientCookie = None, oldCookie = None):
        Check the browser cookie...
        if RESPONSE is not None:
            if (path is not None) and (parents is not None):
                cookiePath = self.constructCookieURL(REQUEST, parents, path)
                cookiePath = '/'
            RESPONSE.setCookie('clientCookie', clientCookie, path = cookiePath)

        if oldCookie is not None:
            # we need to copy the temp shopper here and then delete the
            # temporary shopper info....
            # replace the old basket with the new...

            oldShopper = getattr(self.shopperFolder, oldCookie)
            newShopper = getattr(self.shopperFolder, clientCookie)
            newShopper.basket.items = oldShopper.basket.items

        return "clientCookie = '%s', path = '%s'" % (clientCookie, cookiePath)

00504     def checkEMail(self, email):
        check to see if there is an email address among the shoppers.....
        found = 0

        for shopperID in self.shopperFolder.getItemIds():
            shopper = self.shopperFolder.getItem(shopperID)
            if shopper.email == email:
                found = 1

        return found

00519     def findEMail(self, email):
        Find an email address among the shoppers.....
        foundInfo = ''

        for shopperID in self.shopperFolder.getItemIds():
            shopper = self.shopperFolder.getItem(shopperID)
            if shopper.email == email:
                foundInfo = foundInfo + "Shopper-ID : %s, password : %s " % (shopperID, shopper.passwd)

        return foundInfo

00534     def findShopper(self, shopperID):
        """ Find information about a shopper based on 'id'. """

        theShopper = self.shopperFolder.getItem(shopperID)
        if theShopper is not None:
            foundInfo = "Shopper-ID : %s, password : %s " % (shopperID, theShopper.passwd)
            foundInfo = "Can't find shopper: %s." % shopperID            

        return foundInfo

00545     def assignNewCookie(self, REQUEST=None, RESPONSE=None, PATH_INFO=None, PARENTS=None):
        This method allows for assignment of 'random' cookies....
        so folks don't have to fill in forms just to shop around...
        errs = StringIO.StringIO()

        if REQUEST.cookies.has_key('clientCookie'):
            id = REQUEST.cookies['clientCookie']
            id = 'temp' + `time.time()`

            if RESPONSE is not None:
                newShopper = self.shopperFolder.newShopper(id,passwd='',email='')
                result = self.set_cookie( REQUEST=REQUEST, RESPONSE=RESPONSE, path=PATH_INFO, parents=PARENTS, clientCookie=id)
                return 0,"Successfully created user and set cookie...." + result
                raise RuntimeError, "Hello? This needs a RESPONSE!"
            return 1, "failed to create new shopper. \n" + errs.read()
00570     def addShopper(self, id, passwd, passwd2, email, REQUEST=None ):
        """  addShopper creates a new shopper using the given cookie.... """

        ShopperError = ShopperManager.ShopperError

        result = "Shopper %s added." % id
        if passwd != passwd2:
            raise "Bad Request","Sorry.. passwords must match."
        newShopper = self.shopperFolder.newShopper( id, passwd, email )
        return result

00584     def addNewShopper(self, REQUEST = None, RESPONSE = None, PATH_INFO = None, PARENTS = None):
        addNewShopper handles a special situation. We have a temporary user with
        no passwd, name etc. etc. etc.... We need to extract the name etc from
        the REQUEST, but *not* aqcuire the bogus values from the temporary user.
        This means we need to explicity get the from the REQUEST object.

        ShopperError = ShopperManager.ShopperError

        checkList = ['id','email']

        missingList = []

        for item in checkList:
            if not REQUEST.has_key(item): 

        if len(missingList) > 0:
            raise "Bad Request", "Missing Data..."

        clientCookie = REQUEST.cookies.get('clientCookie',None)
        origURL = REQUEST.get('origURL',None)
        validateUser = REQUEST.get('validateUser',0)
        id = REQUEST['id']
        email = REQUEST['email']

        if not hasattr(self,'randWords'):
            self.randWords = randWords

        randPass = random.choice(self.randWords) + random.choice(randSymbs) + random.choice(self.randWords)

        passwd = REQUEST.get('passwd',randPass)
        passwd2 = REQUEST.get('passwd2',randPass)

        if passwd == '':
            passwd = passwd2 = randPass
            msg = self.addShopper(id, passwd, passwd2, email, REQUEST)

            if (clientCookie is not None) and (clientCookie != id) and clientCookie[:4] == 'temp':

                # we need to copy the temp shopper here and then delete the
                # temporary shopper info....

                oldShopper = self.shopperFolder.getItem( clientCookie )
                newShopper = self.shopperFolder.getItem(id)
                if oldShopper is not None:
                    theOldBasket = self.basketManager.getItem(clientCookie)
                    if theOldBasket:
                        oldBasketItemIds = getattr(theOldBasket,'basketItemIds',[])
                        theNewBasket = self.basketManager.newShoppingBasket(id)
                        theNewBasket.basketItemIds = oldBasketItemIds

                        if origURL is not None:
                            origURL = string.replace(origURL, clientCookie, id)

            if RESPONSE is not None:
                if not self.requireLogin:
                    self.set_cookie(REQUEST = REQUEST, RESPONSE = RESPONSE, path=PATH_INFO, parents=PARENTS, clientCookie=id)
                result = "OK! Successfully added new Shopper."

        except ShopperError, msg:
            result = "ERR Sorry... %s" % msg

        return result

00659     def constructAbsURL(self, meta_type, parents, path, base, rel):

            Construct an Absolute URL based on:

            meta_type: the metatype of the object, higher in the object tree
               relative to which 'rel' is based

            parents: the PARENTS of the current object

            path: the PATH_INFO of the current object

            base: the BASE0 from Zope

            rel: the path, relative to the object with the given meta_type.
        # put a comment here to make python-mode happy.....
        foundIndex = -1  # nothing found yet...
        for index in range(len(parents)):
            item = parents[index]

            if item.meta_type == meta_type:
                foundIndex = index
        while path[:1]=='/': path=path[1:]
        while path[-1:]=='/': path=path[:-1]

        if foundIndex == 0:
            newPath = path
        elif foundIndex == -1:
            raise EMarketError  # there was no object with the given meta_type.

        if base:
            return base+'/'+string.join(newPath,'/') + '/' + rel
            return string.join(newPath,'/') + '/' + rel

00703     def constructCookieURL(self, REQUEST, parents, path):
        """ construct cookie-root URL """
        foundIndex = -1  # nothing found yet...
        for index in range(len(parents)):
            item = parents[index]

            if item.meta_type == 'EMarket':
                foundIndex = index
        if REQUEST.has_key('SCRIPT_NAME'):
            path = REQUEST['SCRIPT_NAME'] + path

        while path[0]=='/': path=path[1:]
        while path[-1]=='/': path=path[:-1]

        if foundIndex == 0:
            newPath = path
        elif foundIndex == -1:
            raise EMarketError  # there was no object with the given meta_type.

        return '/' + string.join(newPath,'/') 

00731     def getShopper(self, shopperID):
        """ retrieve a shopper object.. """
        return self.shopperFolder.getItem(shopperID)
00735     def getMarketItem(self, marketItemID):
        """ find the market item for a certain id. """

        return self.marketFolder.getItem( marketItemID)

00740     def removeMarketItem(self, marketItemID):
        """ find the market item for a certain id. """

        return self.marketFolder.getItem( marketItemID).manage_delete()

00745     def debugPrint(self, whatever=None, mesg="No Message" ):
            this is the debugPrint method, useful for
            sending text to the console while debugging...
        print mesg, whatever
00753     def getValidItemIdsInCategory(self, client=None, ns=None, category=None):
        """ return the set of 'valid' (available) items from the set passed in...."""

        result = []

        for itemID in self.marketFolder.getIdsInCategory(client, ns, category=category ):
            theItem = self.marketFolder.getItem(itemID)
            if theItem and getattr(theItem, 'available', 0):

        return result

    def getCategories(self, theObjects):

        nonEmptyList = []

        for folder in theObjects:
            if len(self.getValidItems(folder.objectValues(['MarketItem']))) > 0:


        return nonEmptyList

    def doProductLayout(self, theObjects, maxCols):

        # we need to layout as many rows as needed
        # in order to show all the non-empty categories
        # using no more than maxCols columns....

        theObjects = self.getCategories(theObjects)

        numObjs = len(theObjects)

        numRows = (numObjs + maxCols - 1)/maxCols

        if numRows == 1:
            numCols = numObjs
            numCols = maxCols

        rows = []

        for i in range(numRows):
            cols = []
            for j in range(numCols):
                theIndex = i*numCols + j

        return rows

Generated by  Doxygen 1.6.0   Back to index