Changeset 102
- Timestamp:
- 04/09/08 00:17:10 (8 months ago)
- Files:
-
- trunk/tracforums/model.py (modified) (1 diff)
- trunk/tracforums/models/avatar.py (modified) (2 diffs)
- trunk/tracforums/models/forum.py (modified) (7 diffs)
- trunk/tracforums/models/main.py (modified) (6 diffs)
- trunk/tracforums/models/message.py (modified) (4 diffs)
- trunk/tracforums/models/profile.py (modified) (6 diffs)
- trunk/tracforums/models/topic.py (modified) (6 diffs)
- trunk/tracforums/orm.py (modified) (5 diffs)
- trunk/tracforums/web_ui.py (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/tracforums/model.py
r99 r102 246 246 UIContext.__init__(self,req,env,db) 247 247 248 # build up the handlers 249 memberMap = self.__class__.__dict__ 250 self.handlerMap = {} 251 for name in memberMap: 252 member = memberMap[name] 253 if isinstance(member,IPageHandler): 254 for name in member.getPageNames(): 255 self.handlerMap[name] = member 256 248 257 def __getitem__(self,name): 249 def handle(*args): 250 return self.templates[name](self,*args) 251 return handle 258 if name in self.handlerMap: 259 return self.handlerMap[name] 260 else: 261 raise TracError("Unknown handler '" + name + "'") 252 262 253 263 def assertAction(self,test,message): 254 264 if not test: 255 265 raise TracError(message) 266 267 def supports(self,view,mimetype): 268 return view in self.handlerMap and self.handlerMap[view].supports(mimetype) 269 270 def invoke(self,view,mimetype): 271 if view in self.handlerMap: 272 return self.handlerMap[view][mimetype](self) 273 else: 274 raise TracError("Unknown handler '" + view + "'") 275 276 277 class IPageHandler: 278 def getPageNames(self): pass 279 def __call__(self,*args,**kwargs): pass 280 def __getitem__(self,format): pass 281 def getInner(self,format): pass 282 def supports(self,format): pass 283 284 def PageHandler(pageNames,mimetypeTemplateMap): 285 """ 286 Decorator for Controller methods. Supply a list of page names and a 287 mimetype:template map to bind a method for page handling. 288 289 Access a specific type handler via the array index operator: handler["html"]. 290 291 Call directly (__call__) to default to the 'html' type. 292 293 Returns a (templateName,assetMap) tuple 294 """ 295 class PageHandlerImpl(IPageHandler): 296 def getPageNames(self): return self.pageNames 297 298 def __init__(self,func): 299 self.func = func 300 self.mimetypeTemplateMap = mimetypeTemplateMap 301 302 if isinstance(pageNames,list): 303 self.pageNames = pageNames 304 else: 305 self.pageNames = [pageNames,] 306 307 def __call__(self,*args,**kwargs): 308 return self.getInner('text/html')(*args,**kwargs) 309 310 def __getitem__(self,mimetype): 311 return self.getInner(mimetype) 312 313 def getInner(self,mimetype): 314 if mimetype in self.mimetypeTemplateMap: 315 def innerFunc(*args,**kwargs): 316 return (self.mimetypeTemplateMap[mimetype],self.func(*args,**kwargs),mimetype) 317 return innerFunc 318 else: 319 raise TracError("Unknown or unsupported mimetype '" + mimetype + "'") 320 321 def supports(self,mimetype): 322 return mimetype in self.mimetypeTemplateMap 323 324 return PageHandlerImpl 325 326 327 def ContentHandler(pageNames): 328 """ 329 Decorator for Controller methods. Supply a list of page names to handle. 330 The decorated handle is responsible for returning the (template,assets,type) tuple 331 332 Returns a (templateName,assetMap,mimetype) tuple 333 """ 334 class PageHandlerImpl(IPageHandler): 335 def getPageNames(self): return self.pageNames 336 337 def __init__(self,func): 338 self.func = func 339 340 if isinstance(pageNames,list): 341 self.pageNames = pageNames 342 else: 343 self.pageNames = [pageNames,] 344 345 def __call__(self,*args,**kwargs): 346 return self.getInner(None)(*args,**kwargs) 347 348 def __getitem__(self,mimetype): 349 return self.getInner(mimetype) 350 351 def getInner(self,mimetype): 352 def innerFunc(*args,**kwargs): 353 return self.func(*args,**kwargs) 354 return innerFunc 355 356 def supports(self,format): 357 return True 358 359 return PageHandlerImpl trunk/tracforums/models/avatar.py
r100 r102 184 184 Controller.__init__(self,req,env,db) 185 185 186 @ContentHandler(["img","default"]) 186 187 def doView(self): 187 188 args = self.getArgs() … … 189 190 190 191 self.renderAsFile(avatar.getTargetPath(),avatar.mimetype) 191 return "", None 192 193 templates = { 194 "img": doView, 195 "default": doView 196 } 192 return ("", None, avatar.mimetype) trunk/tracforums/models/forum.py
r101 r102 195 195 def __init__(self,req,env,db): 196 196 Controller.__init__(self,req,env,db) 197 197 198 @PageHandler(["view","default"],{ 199 "text/html": "forum/view.cs" 200 }) 198 201 def doView(self): 199 202 args = self.getArgs() … … 234 237 validateErrors = e.reasons 235 238 236 return ("forum/view.cs",{239 return { 237 240 "returnto": self.req.abs_href.forums() + "/forum/view/" + str(forum.id), 238 241 "forum": forum, … … 240 243 "topics": TopicModelWithLeadMessage(self.db,self).getMany({"forumid": forum.id}), 241 244 "watching": ForumWatchModelWithProfile(self.db,self).getMany({"forumid": forum.id}), 242 }) 243 245 } 246 247 @PageHandler("edit",{ 248 "text/html": "forum/edit.cs" 249 }) 244 250 def doEdit(self): 245 251 args = self.getArgs() … … 282 288 print "\nforum:",forum 283 289 284 return ("forum/edit.cs",{290 return { 285 291 "returnto": args.get("returnto",None), 286 292 "forum": forum, … … 289 295 "forum_description_rows": self.getSessionVar("forum_description_rows",8), 290 296 "validateErrors": validateErrors 291 }) 292 297 } 298 299 @PageHandler("manage",{ 300 "text/html": "forum/manage.cs" 301 }) 293 302 def doManage(self): 294 303 args = self.getArgs() … … 346 355 validateErrors = e.reasons 347 356 348 return ("forum/manage.cs",{357 return { 349 358 "returnto": self.req.abs_href.forums() + "/forum/manage/" + str(forum.id), 350 359 "forum": forum, … … 353 362 "canMoveForums": self.isForumAdmin(), 354 363 "forums": ForumModel(self.db,self).getMany({"projectid": self.getProjectId()}), 355 }) 356 357 templates = { 358 "view": doView, 359 "edit": doEdit, 360 "manage": doManage, 361 "default": doView 362 } 364 } trunk/tracforums/models/main.py
r101 r102 6 6 def __init__(self,req,env,db): 7 7 Controller.__init__(self,req,env,db) 8 8 9 @PageHandler(["index","default"],{ 10 "text/html": "main/index.cs", 11 "application/rss+xml": "main/rss.cs" 12 }) 9 13 def doIndex(self): 10 14 self.assertAction( … … 55 59 if forum.canView: plainForums.append(forum) 56 60 57 return ("main/index.cs",{61 return { 58 62 "returnto": self.req.abs_href.forums() + "main/index", 59 63 "validateErrors": validateErrors, … … 63 67 "canWatch": self.isForumUser(), 64 68 "watching": ProjectWatchModelWithProfile(self.db,self).getMany({"projectid": self.getProjectId()}), 65 }) 66 69 } 70 71 @PageHandler("manage",{ 72 "text/html": "main/manage.cs" 73 }) 67 74 def doManage(self): 68 75 self.assertAction( … … 180 187 from tracforums.models.category import CategoryModelWithForums 181 188 from tracforums.models.forum import ForumModel 182 183 return ("main/manage.cs",{ 189 from tracforums.models.project import ProjectModel 190 191 return { 184 192 "returnto": self.req.abs_href.forums() + "/main/manage/", 185 193 "validateErrors": validateErrors, 186 194 "canMoveProjects": self.isTracAdmin(), 187 "projects": [{"id":"foobar","name":"Foobar Project"}], #TODO: project listing195 "projects": ProjectModel(self.db,self).getMany(), 188 196 "categories": CategoryModelWithForums(self.db,self).getMany({"projectid": self.getProjectId()}), 189 197 "forums": ForumModel(self.db,self).getMany({"projectid": self.getProjectId(),"categoryid":0}) 190 }) 191 198 } 199 200 @PageHandler("recent",{ 201 "text/html": "main/recent.cs", 202 "rss": "main/rss.cs" 203 }) 192 204 def doRecent(self): 193 205 from tracforums.models.topic import TouchedTopic … … 197 209 for topic in TouchedTopic(self.db,self).getMany(query={"touched":False},params={"username":self.getAuthname()}): 198 210 if topic.forum.canView: 199 topics.append(topic) 211 topics.append(topic) 200 212 print topic.touched 201 213 202 return ("main/recent.cs",{214 return { 203 215 "topics": topics 204 }) 205 216 } 217 218 @PageHandler("profiles",{ 219 "text/html": "main/profiles.cs" 220 }) 206 221 def doProfiles(self): 207 222 self.assertAction( … … 212 227 from tracforums.models.profile import ProfileModelWithAvatar 213 228 214 return ("main/profiles.cs",{229 return { 215 230 "profiles": ProfileModelWithAvatar(self.db,self).getMany() #get all 216 }) 217 218 def doRss(self): 219 #TODO: should probably do recent for site, rather than current user 220 (template,assets) = self.doRecent() 221 return ("rss.cs",assets,'text/xml')#'application/rss+xml') 222 223 templates = { 224 "index": doIndex, 225 "recent": doRecent, 226 "manage": doManage, 227 "profiles": doProfiles, 228 "rss": doRss, 229 "default": doIndex 230 } 231 } trunk/tracforums/models/message.py
r101 r102 46 46 )): 47 47 def format(self): 48 "MESSAGE FORMAT"49 print ("MESSAGE FORMAT")50 48 #TODO: replace with a smarter, wiki 'null formatter' 51 49 self.synopsis = self.body … … 121 119 Controller.__init__(self,req,env,db) 122 120 121 @PageHandler(["edit","default"],{ 122 "text/html": "message/edit.cs" 123 }) 123 124 def doEdit(self): 124 125 args = self.getArgs() … … 182 183 canSetAvatar = self.isForumAdmin or self.getAuthname() == message.username or message.id == 0 183 184 184 return ("message/edit.cs",{185 return { 185 186 "returnto": args.get("returnto",None), 186 187 "message": message, … … 192 193 "validateErrors": validateErrors, 193 194 "canSetAvatar": canSetAvatar 194 }) 195 196 templates = { 197 "edit": doEdit, 198 "default": doEdit 199 } 195 } trunk/tracforums/models/profile.py
r98 r102 131 131 else: 132 132 return False 133 133 134 @PageHandler(["view","default"],{ 135 "text/html": "profile/view.cs" 136 }) 134 137 def doView(self): 135 138 args = self.getArgs() … … 161 164 moderatedForums = ModeratorModelWithForum(self.db,self).getMany({"username":profile.username}) 162 165 163 return ("profile/view.cs",{166 return { 164 167 "profile": profile, 165 168 "title": title, 166 169 "project": project.name, 167 170 "moderatedForums": moderatedForums 168 }) 169 171 } 172 173 @PageHandler("edit",{ 174 "text/html": "profile/edit.cs" 175 }) 170 176 def doEdit(self): 171 177 args = self.getArgs() … … 189 195 profile = ProfileModelWithAssets(self.db,self).load({"profileid": args["viewid"]}) 190 196 191 return ("profile/edit.cs",{197 return { 192 198 "returnto": args.get("returnto",None), 193 199 "profile_bio_rows": self.getSessionVar('profile_bio_rows',8), 194 200 "profile": profile, 195 201 "validateErrors": validateErrors 196 } )202 } 197 203 204 @PageHandler("watches",{ 205 "text/html": "profile/watches.cs" 206 }) 198 207 def doWatchLists(self): 199 208 args = self.getArgs() … … 254 263 255 264 from tracforums.models.watch import CrossProjectWatchDetails,ForumWatchModelWithForum,TopicWatchModelWithTopic 256 return ("profile/watches.cs",{265 return { 257 266 "profile": profile, 258 267 "watchedForums": ForumWatchModelWithForum(self.db,self).getMany({"watchusername": profile.username,"projectid":self.getProjectId()}), … … 264 273 )), 265 274 "validateErrors": validateErrors 266 }) 267 275 } 276 277 @PageHandler("avatars",{ 278 "text/html": "profile/avatars.cs" 279 }) 268 280 def doManageAvatars(self): 269 281 args = self.getArgs() … … 331 343 332 344 from tracforums.models.avatar import AvatarModelWithDetails 333 return ("profile/avatars.cs",{345 return { 334 346 "profile": profile, 335 347 "avatars": AvatarModelWithDetails(self.db,self).getMany({"username":profile.username}), 336 348 "validateErrors": validateErrors 337 } )349 } 338 350 339 351 trunk/tracforums/models/topic.py
r101 r102 188 188 def canViewAll(self): 189 189 return self.isForumUser() 190 190 191 @PageHandler(["view","default"],{ 192 "text/html": "topic/view.cs" 193 }) 191 194 def doView(self): 192 195 args = self.getArgs() … … 233 236 from tracforums.models.forum import ForumModel 234 237 235 return ("topic/view.cs",{238 return { 236 239 "returnto": self.req.abs_href.forums() + "/topic/view/" + str(topic.id), 237 240 "validateErrors": validateErrors, … … 243 246 }), 244 247 "watching": TopicWatchModelWithProfile(self.db,self).getMany({"topicid": topic.id}) 245 }) 246 248 } 249 250 @PageHandler("edit",{ 251 "text/html": "topic/edit.cs" 252 }) 247 253 def doEdit(self): 248 254 args = self.getArgs() … … 312 318 validateErrors = e.reasons 313 319 314 return ("topic/edit.cs",{320 return { 315 321 "returnto": args.get("returnto",None), 316 322 "topic": topic, … … 319 325 "message_body_rows": self.getSessionVar("message_body_rows",8), 320 326 "validateErrors": validateErrors 321 }) 322 327 } 328 329 @PageHandler("manage",{ 330 "text/html": "topic/manage.cs" 331 }) 323 332 def doManage(self): 324 333 args = self.getArgs() … … 365 374 "canMoveMessages": self.isForumAdmin() 366 375 }) 367 368 templates = {369 "view": doView,370 "edit": doEdit,371 "manage": doManage,372 "default": doView373 }trunk/tracforums/orm.py
r101 r102 347 347 348 348 def doFormat(self,row,obj): 349 print "\nORMJoin doFormat row: ",row349 #print "\nORMJoin doFormat row: ",row 350 350 isNull = True 351 351 for val in row: … … 353 353 isNull = False 354 354 value = self.getModel()(obj.db,obj.formatContext).mapRowToModel(row) 355 print "MAPPED\n"355 #print "MAPPED\n" 356 356 value.format() 357 357 break … … 469 469 return "" 470 470 else: 471 #TODO: fix me - this is broken across the whole ORM 472 print "orderby: ",orderby 471 #print "orderby: ",orderby 473 472 return " order by " + ",".join(map(lambda x: x[0] + " " + x[1],orderby)) 474 473 … … 698 697 self.must(self.validateSave()) 699 698 700 print "\n",self.schema.updateSQL,self._getQueryValues(),"\n",self.__dict__699 #print "\n",self.schema.updateSQL,self._getQueryValues(),"\n",self.__dict__ 701 700 cursor.execute(self.schema.updateSQL,self._getQueryValues()) 702 701 self.db.commit() … … 704 703 self.must(self.validateCreate()) 705 704 706 print "\n",self.schema.insertSQL,self._getQueryValues()705 #print "\n",self.schema.insertSQL,self._getQueryValues() 707 706 cursor.execute(self.schema.insertSQL,self._getQueryValues()) 708 707 self.db.commit() trunk/tracforums/web_ui.py
r98 r102 1 1 from trac.core import * 2 from trac.web.chrome import INavigationContributor, ITemplateProvider, add_stylesheet, add_script 2 from trac.web.chrome import INavigationContributor, ITemplateProvider, add_stylesheet, add_script, add_link 3 3 from trac.web.main import IRequestHandler 4 4 from trac.wiki import wiki_to_html, wiki_to_oneliner … … 212 212 "message": MessageController, 213 213 } 214 215 alternateFormats = { 216 "application/rss+xml": ('alternate', '?format=rss', 'RSS Feed', 'application/rss+xml', 'rss') 217 } 218 219 mimetypeMap = { 220 "html": "text/html", 221 "rss": "application/rss+xml" 222 } 214 223 215 224 """ The process_request handle in this class behaves like a state machine for … … 218 227 def process_request(self,req): 219 228 req.args['authname'] = req.authname # grab authname here 220 229 221 230 db = get_forumDB(self.env) 222 viewName = req.args['view'] 231 232 viewName = req.args['view'] 223 233 if viewName in self.controllers: 224 234 controller = self.controllers[viewName](req,self.env,db) 225 235 else: 226 236 raise TracError("No such forum view: '" + viewName + "'") 227 228 # process the current mode 229 results = controller[req.args["mode"]]() 230 if len(results) == 3: 231 (templateName,assets,mimetype) = results 232 else: 233 (templateName,assets) = results 234 mimetype = 'text/html' 237 238 # process the current mode 239 format = req.args.get('format','html') # get the format of the request 240 mode = req.args["mode"] 241 242 # generate links for all the supported formats 243 for alternate in self.alternateFormats: 244 if controller.supports(mode,alternate): 245 args = (req,) + self.alternateFormats[alternate] 246 add_link(*args) 247 248 # generate the content by requesting a given mimetype 249 #NOTE: we call even though it may report as supporting nothing 250 mimetype = self.mimetypeMap[format] 251 (templateName,assets,mimetype) = controller.invoke(mode,mimetype) 235 252 236 253 # set styles and links … … 241 258 add_script(req, "forums/js/forums.js") 242 259 243 print assets244 260 req.hdf["forums"] = assets 245 261
