Changeset 105

Show
Ignore:
Timestamp:
04/20/08 23:59:38 (7 months ago)
Author:
pragma
Message:

Massive Update - just about ready for Beta testing.

  • NOTE: deletions still do not cascade.
  • Cleaned up templates and argument handling for all macros
  • Fixed a nasty ORM bug regarding ORMJoin columns
  • Fixed avatar display handling - default now displays where appropriate
  • Various other behaviors improved or bugfixed
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/tracforums/__init__.py

    r60 r105  
    22from tracforums.web_ui import * 
    33from tracforums.macros import * 
     4from tracforums.search import * 
     5from tracforums.timeline import * 
  • trunk/tracforums/htdocs/css/forums.css

    r104 r105  
    176176} 
    177177 
     178.signature{ 
     179    border-top: 1px solid #D7D7D7; 
     180} 
     181 
    178182label{ 
    179183    width: 10em; 
     
    269273    white-space: nowrap; 
    270274} 
     275 
     276/** Macro Styles **/ 
     277.embedded-reply{ 
     278    border: 1px solid rgb(0, 0, 0);  
     279    padding: 4px;  
     280    background: rgb(238, 238, 238) none repeat scroll 0%;  
     281    text-align: right; 
     282} 
     283 
     284.embedded-reply-date{ 
     285    float: left; 
     286    margin-top: 8px; 
     287    margin-left: 8px; 
     288} 
     289 
     290.embedded-reply img, 
     291.reply-portrait{ 
     292    height: 32px; 
     293    float: right; 
     294    margin-left: 4px;    
     295} 
     296 
     297.embedded-reply-content{ 
     298    padding: 4px 4px 8px; 
     299    background: rgb(250, 250, 250) none repeat scroll 0%;  
     300} 
     301 
     302.recent-topics{ 
     303    margin-bottom: 5px; 
     304} 
     305 
     306.recent-topics .title{ 
     307    white-space: nowrap; 
     308} 
     309 
     310.recent-topics .synopsis{ 
     311    font-size: smaller; 
     312    font-style: italic; 
     313} 
  • trunk/tracforums/macros.py

    r104 r105  
    104104        
    105105    def __str__(self):        
    106        result = "TOKENS (" + str(len(self.tokens)) + "):\n" 
    107106       for tok in self.tokens: 
    108107           result = result + str(tok) + "\n" 
     
    129128   
    130129    tokens = Tokenizer(content) 
    131      
    132     print tokens 
    133      
     130         
    134131    def parseErr(tok,msg): 
    135132       raise TracError("Macro Arguments " + str(tok.loc) + " at '" + str(tok.val) + "': " + msg) 
     
    228225        Displays topics from a given forum. 
    229226         
    230         RecentTopics(forum,maxposts=10
     227        RecentTopics(forum,maxposts=10,viewMoreText='View Older Topics...'
    231228         
    232229        Example: 
    233230        {{{ 
    234231        [[RecentTopics('Test Forum')]] 
    235         }}}         
     232        }}} 
    236233    """ 
    237234             
     
    240237        args = parseMacroArgs( 
    241238            content, 
    242             ["forum","maxPosts"], 
    243             [None   ,10
     239            ["forum", "maxPosts","viewMoreText"], 
     240            [None   , 10        ,'View Older Topics'
    244241        ) 
    245242 
     
    254251        try: 
    255252            from tracforums.models.forum import ForumModel 
    256             forum = ForumModel(db,context).load({"name":args.forum},debug=True
     253            forum = ForumModel(db,context).load({"name":args.forum}
    257254        except: 
    258255           raise TracError("cannot find forum: '" + args.forum + "'") 
     
    274271        req.hdf["forums"] = { 
    275272            "forum": forum, 
    276             "topics": topics 
     273            "topics": topics, 
     274            "viewMoreText": args.viewMoreText, 
    277275        } 
    278276        req.hdf['trac.href.forums'] = self.env.href.forums() 
     
    292290        Displays topics from a given forum 
    293291         
    294         RecentTopicsSummary(forum,maxposts=10
     292        RecentTopicsSummary(forum,maxposts=10,viewMoreText='View Older Topics...'
    295293         
    296294        Example: 
     
    304302        args = parseMacroArgs( 
    305303            content, 
    306             ["forum","maxPosts"], 
    307             [None   ,10
     304            ["forum", "maxPosts","viewMoreText"], 
     305            [None   , 10        ,'View Older Topics'
    308306        ) 
    309307 
     
    338336        req.hdf["forums"] = { 
    339337            "forum": forum, 
    340             "topics": topics 
     338            "topics": topics, 
     339            "viewMoreText": args.viewMoreText, 
    341340        } 
    342341        req.hdf['trac.href.forums'] = self.env.href.forums() 
  • trunk/tracforums/models/avatar.py

    r102 r105  
    1515    columns   = { 
    1616        "id": ORMKey(type='int', auto_increment = True), 
    17         "username":  ORMColumn(), 
    18         "mimetype":  ORMColumn(), 
    19         "name":      ORMColumn(), 
    20         "avatarid":  ORMAlias(sql="id"), 
     17        "username":  ORMColumn(type="str"), 
     18        "mimetype":  ORMColumn(type="str"), 
     19        "name":      ORMColumn(type="str"), 
     20        "avatarid":  ORMAlias(type="int",sql="id"), 
    2121    } 
    2222)): 
     
    9494        # check if the file has been uploaded                 
    9595        if "filedata" in self.__dict__: 
    96             print "FILE:",self.filedata 
    9796            metrics = self.formatContext.getAvatarMetrics() 
    9897             
  • trunk/tracforums/models/category.py

    r97 r105  
    5353        "forums": ORMRelation( 
    5454            model        = ORMImportModel("tracforums.models.forum","ForumModelWithRecentPost"), 
    55             relationship = {"categoryid":"categoryid"} 
     55            relationship = {"categoryid":"categoryid"}, 
     56            debug = True 
    5657        ), 
    5758    } 
  • trunk/tracforums/models/forum.py

    r104 r105  
    146146         
    147147    def saveModerators(self): 
    148         print "\nMODERATORS:",map(lambda x: x.username,self.moderators) 
    149148        if self.moderators and len(self.moderators) > 0: 
    150149            from tracforums.models.moderator import ModeratorModel 
     
    166165        # increase rank value to lower it's priority in the list 
    167166        ranks = self.getColumnValues("rank",{"projectid":self.projectid,"categoryid":self.categoryid}) 
    168         print "\nRanks:",ranks 
    169167        idx = ranks.index(self.rank) 
    170168         
     
    177175        # decrease rank value to raise it's priority in the list 
    178176        ranks = self.getColumnValues("rank",{"projectid":self.projectid,"categoryid":self.categoryid}) 
    179         print "\nRanks:",ranks 
    180177        idx = ranks.index(self.rank) 
    181178         
     
    208205    def doView(self): 
    209206        args = self.getArgs() 
    210         forum = ForumModel(self.db,self).load({"id": args["viewid"]},debug=True
     207        forum = ForumModel(self.db,self).load({"id": args["viewid"]}
    211208         
    212209        self.assertAction( 
     
    286283                    forum.attemptSave() 
    287284                elif action == "save": 
    288                     #print "SAVING..." 
    289285                    forum.save() 
    290286                    self.db.commit() 
     
    292288            except ModelValidateException,e: 
    293289               validateErrors = e.reasons 
    294             
    295         print "\nforum:",forum 
    296          
     290                    
    297291        return { 
    298292            "returnto": args.get("returnto",None), 
  • trunk/tracforums/models/main.py

    r104 r105  
    4242        from tracforums.models.category import CategoryModelWithForums    
    4343        from tracforums.models.watch    import ProjectWatchModelWithProfile 
    44          
     44                         
    4545        #filter visibiltiy for security 
    4646        categoriesWithForums = [] 
     
    5252                category.forums = categoryForums 
    5353                categoriesWithForums.append(category)        
    54          
    55         #filter visibiltiy for security 
    56                          
     54                 
    5755        return { 
    5856            "returnto": self.req.abs_href.forums() + "main/index", 
     
    8987                 
    9088                forum = ForumModel(self.db,self).load({"id":forumid}) 
    91                 print "loaded forum:",forum 
    9289                if action == "category": 
    9390                    categoryid = int(categoryid) 
     
    228225        "text/html": "main/profiles.cs" 
    229226    }) 
    230     def doProfiles(self): 
    231         self.assertAction( 
    232             self.isForumUser(), 
    233             "You do not have permission to view this item." 
    234         ) 
    235          
     227    def doProfiles(self):         
    236228        from tracforums.models.profile import ProfileModelWithAvatar 
    237229 
  • trunk/tracforums/models/message.py

    r102 r105  
    4343                type="datetime" 
    4444            ), 
     45             
     46                     
     47            "modifieddatehtml": ORMAlias( 
     48                name="modified", 
     49                type="date" 
     50            ), 
     51                          
     52            "canEdit": ORMAlias(type="bool",sql=""" 
     53                %%(isadmin)s 
     54                or %(message)s.author = %%(authname)s 
     55                or ( 
     56                    %%(isuser)s 
     57                    and coalesce(( 
     58                        select true from %(moderator)s m  
     59                        join %(forum)s f on m.forumid = f.id 
     60                        join %(topic)s t on f.id = t.forumid 
     61                        where t.id = %(message)s.topicid and m.username=%%(authname)s 
     62                    ),false) 
     63                ) 
     64            """ % Tablenames), 
    4565        } 
    4666    )): 
     
    5979         
    6080    def setTopic(self,topicModel): 
    61         self.topic = topicModel 
    62         self.topicid = topicModel.id 
    63         self.canModify = toBool(self._canModify()) 
    64         self.canView = toBool(self._canView()) 
     81        if topicModel != None: 
     82            self.topic = topicModel 
     83            self.topicid = topicModel.id 
     84            self.canModify = toBool(self._canModify()) 
     85            self.canView = toBool(self._canView()) 
    6586         
    6687    def setAuthor(self,profileModel): 
     
    90111    base = MessageModel, 
    91112    columns={ 
    92         "profile": ORMJoin( 
    93             model       = ORMImportModel("tracforums.models.profile","ProfileModelWithAvatar"), 
    94             relationship = {"author":"profileid"} 
    95         ), 
     113        "profile": ORMJoin( 
     114            model       = ORMImportModel("tracforums.models.profile","ProfileModelWithAvatar"), 
     115            relationship = {"author":"profileid"} 
     116        ), 
    96117        "avatar": ORMJoin( 
    97118            model       = ORMImportModel("tracforums.models.avatar","AvatarModel"), 
     
    104125class MessageModelWithProfileAndTopic(ORMSchema( 
    105126    base = MessageModelWithProfile, 
    106     columns={   
     127    columns={ 
    107128        "topic": ORMRelation( 
    108129            model        = ORMImportModel("tracforums.models.topic","TopicModelWithForum"), 
     
    114135        self.setTopic(self.topic) 
    115136        MessageModelWithProfile.format(self) 
     137         
    116138 
    117139class MessageController(Controller): 
     
    123145    }) 
    124146    def doEdit(self): 
     147        return self.doEditImpl() 
     148         
     149    @PageHandler(["wiki"],{ 
     150        "text/html": "message/wiki.cs" 
     151    }) 
     152    def doWikiEdit(self): 
     153        return self.doEditImpl() 
     154     
     155    def doEditImpl(self): 
    125156        args = self.getArgs() 
    126157        message = MessageModel(self.db,self) 
    127158         
    128         if args.get("messageid",0) != 0: 
     159        from tracforums.models.topic import TopicModelWithForum    
     160        from tracforums.models.profile import ProfileModelWithAssets   
     161        from tracforums.models.avatar import AvatarModel   
     162         
     163        if args.get("viewid",0) != 0: 
     164            #edit/modify the current message 
    129165            message.load({"messageid": args["viewid"]}) 
     166 
     167            self.assertAction( 
     168                message.canEdit, 
     169                "You do not have permission to edit this item." 
     170            ) 
     171            message.modcount = message.modcount + 1 
     172            message.modifiedby = self.getAuthname() 
     173            message.modified = self.epochNow()               
     174            message.setTopic(TopicModelWithForum(self.db,self).load({"topicid":message.topicid})) 
    130175        else: 
    131             from tracforums.models.topic import TopicModelWithForum 
    132              
    133         message.setTopic(TopicModelWithForum(self.db,self).load({"topicid":args["topicid"]})) 
    134              
    135         from tracforums.models.profile import ProfileModelWithAssets 
    136         authorProfile = ProfileModelWithAssets(self.db,self).load({"profileid":self.getAuthname()}) 
    137         authorProfile.posts = authorProfile.posts + 1 
    138         message.setAuthor(authorProfile) 
    139                  
    140         validateErrors = [] 
    141          
    142         print "Profile: ",authorProfile,"\n" 
    143                      
     176            # prep the model for a first time edit       
     177            message.setTopic(TopicModelWithForum(self.db,self).load({"topicid":args["topicid"]})) 
     178             
     179        # generic setup   
     180        message.profile = ProfileModelWithAssets(self.db,self).load({"profileid":message.author})           
     181        message.profile.posts = message.profile.posts + 1                               
     182             
    144183        self.assertAction( 
    145             message != None, 
    146             "Topic does not exist" 
    147         ) 
    148          
    149         self.assertAction( 
    150             message.canModify, 
     184            message.topic.canAppend, 
    151185            "You do not have permission to edit this item." 
    152186        ) 
    153          
     187                         
     188        validateErrors = []                                           
    154189        preview = False 
    155190                         
     
    161196                message.set(args) 
    162197                message.doFormat() 
    163                 if action == "preview": 
    164                     #match avatar with message 
    165                     for x in authorProfile.avatars: 
    166                         if x.id == message.avatarid: 
    167                             message.avatar = x 
    168                             message.avatarid = x.id                             
     198                if action == "preview":                       
    169199                    preview = True 
    170200                elif action == "save": 
    171                     message.modcount = message.modcount + 1 
    172                     authorProfile.save() 
     201                    message.profile.save() 
    173202                    message.save() 
    174203                    self.db.commit() 
     
    177206               validateErrors = e.reasons 
    178207                       
    179         from tracforums.models.avatar import AvatarModel 
    180         from tracforums.models.message import MessageModelWithProfile 
     208        # set the avatar after the post input has been accounted for         
     209        message.avatar = AvatarModel(self.db,self).load({"avatarid":message.avatarid}) 
    181210 
    182211        #Admins, original authors or new authors can change avatar 
  • trunk/tracforums/models/profile.py

    r102 r105  
    4545        if uiContext.isForumAdmin(): 
    4646            self.canModify = True 
    47         elif uiContext.isForumUser() and uiContext.getAuthname() == instance['username']
     47        elif uiContext.isForumUser() and uiContext.getAuthname() == self.username
    4848            self.canModify = True 
    4949        else: 
     
    9090    orderby = [("profileid","asc")], 
    9191    columns = { 
     92        "sightml": ORMAlias( 
     93            sql="sig", 
     94            type="wiki" 
     95        ), 
    9296        "defaultAvatar": ORMJoin( 
    9397            model        = ORMImportModel("tracforums.models.avatar","AvatarModel"), 
    9498            relationship = {"defaultavatarid":"id"}      
    95         ),     
     99        ), 
    96100    }     
    97101) 
     
    109113            type="wiki" 
    110114        ),  
    111         "sightml": ORMAlias( 
     115    } 
     116
     117 
     118SearchableProfileModel = ORMSchema( 
     119    base    = ProfileModel, 
     120    orderby = [("lastvisit","desc")], 
     121    columns = { 
     122        "biosynopsis": ORMAlias( 
     123            name="bio", 
     124            type="shortwiki" 
     125        ), 
     126        "sigsynopsis": ORMAlias( 
    112127            name="sig", 
    113             type="wiki" 
     128            type="shortwiki" 
    114129        ), 
    115130    } 
    116 )         
     131) 
    117132 
    118133 
     
    144159         
    145160        profile = ProfileModelWithAssets(self.db,self).load({"profileid": args["viewid"]}) 
    146         print profile 
    147161         
    148162        from tracforums.models.project import ProjectModel 
  • trunk/tracforums/models/topic.py

    r104 r105  
    6565         
    6666        "canModify": ORMAlias(type="bool",sql=""" 
    67             %%(isadmin)s or 
    68             not (select locked from %(forum)s f where f.id = %(topic)s.forumid)  
     67            %%(isadmin)s 
    6968            or ( 
    7069                %%(isuser)s 
    7170                and coalesce((select true from %(moderator)s m where m.forumid = %(topic)s.forumid and m.username=%%(authname)s),false) 
     71            ) 
     72        """ % Tablenames), 
     73         
     74        "canAppend": ORMAlias(type="bool",sql=""" 
     75            %%(isadmin)s or 
     76            ( 
     77                %%(isuser)s 
     78                and ( 
     79                    coalesce((select true from %(moderator)s m where m.forumid = %(topic)s.forumid and m.username=%%(authname)s),false) 
     80                    or not (select locked from %(forum)s f where f.id = %(topic)s.forumid)  
     81                ) 
    7282            ) 
    7383        """ % Tablenames), 
     
    103113    def validateCreate(self): 
    104114        return self.validate() 
    105              
     115         
    106116    def validateSave(self): 
    107117        return self.validate() 
    108118         
     119    def touch(self): 
     120        if self.views == None: 
     121            self.views = 1 
     122        else: 
     123            self.views = self.views + 1 
     124        self.getBase().save(self) 
     125         
    109126    def save(self,data={}): 
     127        TouchedTopicModel(self.db,self.formatContext).deleteMany({"topicid":self.id}) 
    110128        self.getBase().save(self,data) 
    111129         
    112     def saveAndNotify(self,data={}): 
    113         self.save(data) 
     130    def saveAndNotify(self,data={}):         
    114131        from tracforums.models.watch import notifyTopicChanged 
    115132        notifyTopicChanged(self.db,self.formatContext,self) 
     133        self.save(data) 
    116134     
    117135         
     
    139157     
    140158    def format(self): 
    141         self.canAppend = toBool(self._canAppend()) 
    142          
     159        pass 
     160             
    143161    def setForum(self,forumModel): 
    144162        self.forum = forumModel 
    145163        self.format() 
    146          
    147     def _canAppend(self): 
    148         if not self.formatContext.isForumUser(): return False 
    149         elif self.formatContext.isForumAdmin(): return True 
    150         elif self.forum.locked: return False 
    151         elif self.formatContext.getAuthname() == self.leadMessageAuthor: return True 
    152         else: self.formatContext.getAuthname() in self.forum.moderators 
    153164        
    154165class TopicModelWithRecentPost(ORMSchema( 
     
    227238                    watchModel.save(criteria) 
    228239            else: 
    229                 if topic.views == None: 
    230                     topic.views = 1 
    231                 else: 
    232                     topic.views = topic.views + 1 
    233                 topic.save() 
     240                topic.touch() 
    234241                             
    235242            #force changes through before display 
     
    252259                "messageid": ("<>",topic.leadmessageid) 
    253260            }), 
     261            "isForumUser": self.isForumUser(), 
    254262            "watching": TopicWatchModelWithProfile(self.db,self).getMany({"topicid": topic.id}) 
    255263        } 
     
    265273        from tracforums.models.avatar import AvatarModel 
    266274        from tracforums.models.forum import ForumModel 
    267         from tracforums.models.profile import ProfileModel 
    268          
     275        from tracforums.models.profile import ProfileModel, ProfileModelWithAssets 
     276              
     277        # edit existing model    
    269278        if args.get("viewid",0) != 0: 
    270279            topic.load({"topicid": args["viewid"]}) 
    271             topic.leadmessage = MessageModel(self.db,self).load({"id":topic.leadmessageid},debug=True) 
    272             messageAuthor = topic.leadmessage.author 
     280            topic.leadmessage = MessageModel(self.db,self).load({"messageid":topic.leadmessageid}) 
     281      
     282            self.assertAction( 
     283                topic.canModify, 
     284                "You do not have permission to view this item." 
     285            ) 
     286             
     287        # edit new model 
    273288        else: 
    274289            topic.doFormat() 
    275290            #HACK: work around ORM limitations by loading up a dummy message model and forum 
    276291            topic.leadmessage = MessageModel(self.db,self) 
     292            topic.leadmessage.author = self.getAuthname() 
     293             
    277294            topic.setForum(ForumModel(self.db,self).load({"forumid":args["forumid"]})) 
    278             messageAuthor = self.getAuthname() 
     295             
     296            self.assertAction( 
     297                topic.forum.canAppend, 
     298                "You do not have permission to perform this action." 
     299            ) 
     300             
     301        topic.leadmessage.profile = ProfileModelWithAssets(self.db,self).load({"profileid":self.getAuthname()})           
     302        topic.leadmessage.avatar = AvatarModel(self.db,self).load({"avatarid":topic.leadmessage.avatarid})           
     303         
    279304        validateErrors = [] 
    280                      
    281         self.assertAction( 
    282             topic != None, 
    283             "Topic does not exist" 
    284         ) 
    285          
    286         self.assertAction( 
    287             topic.canModify, 
    288             "You do not have permission to view this item." 
    289         ) 
    290          
    291         preview = None         
    292          
     305        preview = None 
     306                 
    293307        if "action" in args: 
    294308            action = args["action"] 
     
    298312                topic.set(args) 
    299313                topic.doFormat() 
    300                 #hack: further work around ORM limitations by setting message parts directly 
    301                 #topic.leadmessage.body = args.get("body","") 
    302                 #topic.leadmessage.avatarid = args.get("avatarid",0) 
    303314                topic.leadmessage.set(args) 
    304315                topic.leadmessage.created = self.epochNow() 
    305316                topic.leadmessage.modified = self.epochNow() 
    306                 topic.leadmessage.author = messageAuthor 
    307                 topic.leadmessage.profile = ProfileModel(self.db,self).load({"username":messageAuthor}) 
    308317                topic.leadmessage.doFormat() 
    309318                if action == "preview": 
    310319                    topic.attemptSave() 
     320                    if topic.avatarid != 0: 
     321                        topic.leadmessage.avatar = AvatarModel(self.db,self).load({"id":topic.avatarid}) 
    311322                    preview = [topic] 
    312323                elif action == "save": 
     
    329340            "topic": topic, 
    330341            "preview": preview, 
    331             "avatars": AvatarModel(self.db,self).getMany({"username":messageAuthor})
     342            "canSetAvatar": True
    332343            "message_body_rows": self.getSessionVar("message_body_rows",8), 
    333344            "validateErrors": validateErrors 
     
    359370                    "username":  self.getAuthname(), 
    360371                    "topicid": topic.id 
    361                 })       
     372                }) 
    362373            #force changes through before display 
    363374            self.db.commit() 
     
    369380        from tracforums.models.forum   import ForumModel             
    370381                  
    371         return ("topic/manage.cs",
     382        return
    372383            "returnto": self.req.abs_href.forums() + "/topic/view/" + str(topic.id), 
    373384            "validateErrors": validateErrors, 
     
    380391            "topics": TopicModelWithForum(self.db,self).getMany(), #TODO: restrict to this project 
    381392            "canMoveMessages": self.isForumAdmin() 
    382         }) 
     393        } 
  • trunk/tracforums/orm.py

    r104 r105  
    1212 
    1313### SQL Builder #### 
    14  
    15 def resolveOperator(op): 
    16     if not op in ["=","<",">","<=",">=","<>","like"]: return "=" 
    17     elif op == "like": 
    18         val = db.like_escape(val) 
    19         return db.like() 
     14         
     15class AND: 
     16    def __init__(self,*terms): 
     17       self.terms = terms 
     18     
     19class OR: 
     20    def __init__(self,*terms): 
     21       self.terms = terms 
     22             
     23def getSqlTerm(db,part,prefix="",parentKey="",suffix=""): 
     24    termSQL = "" 
     25    termValues = {} 
     26             
     27    def getSqlSequence(terms,joinValue): 
     28        codeParts = [] 
     29        termValues = {} 
     30        i = 0 
     31        for x in terms: 
     32            (code,values) = getSqlTerm(db,x,prefix,parentKey,str(i)) 
     33            codeParts.append(code) 
     34            termValues.update(values) 
     35            i = i + 1 
     36        return(joinValue.join(codeParts),termValues) 
     37     
     38    if isinstance(part,AND): 
     39        (termSQL,termValues) = getSqlSequence(part.terms," and ") 
     40             
     41    elif isinstance(part,OR): 
     42        (termSQL,termValues) = getSqlSequence(part.terms," or ") 
     43                     
     44    elif isinstance(part,tuple): 
     45        if len(part) == 1: 
     46            name = parentKey 
     47            op = "=" 
     48            (val) = part 
     49        if len(part) == 2: 
     50            name = parentKey 
     51            (op,val) = part 
     52        else: 
     53            (name,op,val) = part 
     54        lookup = prefix+name+suffix 
     55        if not op in ["=","<",">","<=",">=","<>","like"]: op = "=" 
     56 
     57        if isinstance(val,list): 
     58            listterms = [] 
     59            for i in range(0,len(val)): 
     60                keyname = lookup + str(i) 
     61                if op == "like": 
     62                    thisOp = db.like() % ("%(" + keyname + ")s") 
     63                    termValues[keyname] ="%" + str(val[i]) + "%" 
     64                else: 
     65                    thisOp = op + " %(" + keyname + ")s"                  
     66                    termValues[keyname] = val[i] 
     67                listterms.append(name + " " + thisOp) 
     68            termSQL += "(" + " or ".join(listterms) + ")" 
     69        else: 
     70            if op == "like": 
     71                op = db.like() % ("%(" + lookup + ")s") 
     72                val = "%" + str(val) + "%" 
     73            else: 
     74                op = op + " %(" + lookup + ")s" 
     75            (termSQL,termValues) = (name + " " + op,{lookup:val}) 
     76             
     77    elif isinstance(part,list): 
     78        listterms = [] 
     79        for i in range(0,len(part)): 
     80            keyname = prefix + parentKey +  str(i) 
     81            termValues[keyname] = val[i] 
     82            listterms.append(parentKey + " = %(" + keyname + ")s") 
     83        termSQL += "(" + " or ".join(listterms) + ")" 
     84         
     85    elif isinstance(part,dict): 
     86        codeParts = [] 
     87        for key in part: 
     88            (code,values) = getSqlTerm(db,part[key],prefix,key) 
     89            codeParts.append(code) 
     90            termValues.update(values) 
     91        termSQL = " and ".join(codeParts) 
     92         
    2093    else: 
    21         return op 
    22          
    23 def getSqlTerm(term,prefix=""): 
    24     """ 
    25         getSqlTerm - composes SQL where expressions based on input 
    26          
    27         term = tuple or array: the term is composed as a tuple containing an (name,operator,value) 
    28             sequence, or an (sql,value) sequence. 
    29         term = string: the term is inserted into the where clause literally 
    30         term = dict: the key/value pairs are composed into an "and" delimited sequence of equality 
    31             (=) operations. 
    32              
    33         returns a tuple containing sql code and a map of values 
    34     """ 
    35     if type(term) == dict: 
    36         termSQL = [] 
    37         termVal = {} 
    38         for key in term: 
    39             val = term[key] 
    40             if type(val) == tuple: 
    41                 (op,val) = val 
    42                 termSQL.append(key + " " + resolveOperator(op) + " %(" + prefix+key + ")s") 
    43                 termVal[prefix+key] = val 
    44             elif type(val) == list: 
    45                 # populate a list 
    46                 listterms = [] 
    47                 for x in val: 
    48                     keyname = prefix + key + str(len(listterms)) 
    49                     termVal[keyname] = x 
    50                     listterms.append(key + " = %(" + keyname + ")s") 
    51                 termSQL.append("(" + " or ".join(listterms) + ")") 
    52             else: 
    53                 termSQL.append(key + " = %(" + prefix+key + ")s") 
    54                 termVal[prefix+key] = val 
    55         return (" and ".join(termSQL),termVal) 
    56                  
    57     if type(term) == str or len(term) == 1: 
    58         return (term,{}) 
    59     elif len(term) == 2: 
    60         return term 
    61     else: 
    62         (name,op,val) = term 
    63         return (name + " " + resolveOperator(op) + " %(" + prefix+name + ")s",{prefix+name:val})         
    64          
    65 def getSqlSequence(separator,terms): 
    66     sqlParts = [] 
    67     data = {} 
    68     for term in terms: 
    69         (termSQL,valueDict) = getSqlTerm(term) 
    70         sqlParts.append("(" + termSQL + ")") 
    71         data.update(valueDict) 
    72     return (separator.join(sqlParts),data) 
    73          
    74 def AND(*terms): 
    75     return getSqlSequence(" and ",terms) 
    76      
    77 def OR(*terms): 
    78     return getSqlSequence(" or ",terms) 
    79          
    80 defaultQuery = ("",{}) 
     94        lookup = prefix+parentKey+suffix 
     95        (termSQL,termValues) = (parentKey + " = %(" + lookup + ")s",{lookup:part}) 
     96                 
     97    return (termSQL,termValues) 
     98        
     99defaultQuery = {} 
    81100 
    82101### HDF #### 
     
    94113            return self.__dict__[name] 
    95114        return None 
    96  
     115         
    97116    #NOTE: needed for HDF support to work 
    98117    def keys(self): 
     
    131150    def wiki(formatContext,value): 
    132151        return formatContext.wikiToHTML(value) 
    133          
     152       
     153    @staticmethod 
     154    def shortwiki(formatContext,value): 
     155        synopsisLength = formatContext.getSynopsisLength() 
     156        if value and len(value) > synopsisLength: 
     157            value = value[:synopsisLength] + "..." 
     158        return formatContext.wikiToOneLiner(value) 
     159           
    134160    @staticmethod 
    135161    def oneliner(formatContext,value): 
     
    156182    @staticmethod 
    157183    def int(formatContext,value): 
    158         #####print "CONVERTING: ",value,type(value) 
    159184        return int(value) 
    160185         
     
    258283             
    259284    def doFormat(self,value,obj): 
    260         ####print "ORMColumn loadaction: ",fieldname,col.formatter,type(col.formatter),obj.__dict__[fieldname] 
    261285        if value != None: 
    262286             return self.formatter(obj.formatContext,value) 
     
    291315        Represents one or more model instances that get attached to the model at load time. 
    292316    """ 
    293     def __init__(self,model,relationship=None,columnname=None,limit=0,*args,**kwargs): 
     317    def __init__(self,model,relationship=None,columnname=None,limit=0,debug=False,*args,**kwargs): 
    294318        ORMColumn.__init__(self,*args,**kwargs) 
    295319        self.model = model 
     
    297321        self.columnname = columnname 
    298322        self.limit = lim