Changeset 2531
- Timestamp:
- 07/27/07 15:27:44 (1 year ago)
- Files:
-
- downloadsplugin/0.10/tracdownloads/api.py (modified) (15 diffs)
- downloadsplugin/0.10/tracdownloads/core.py (modified) (2 diffs)
- downloadsplugin/0.10/tracdownloads/db/db1.py (modified) (3 diffs)
- downloadsplugin/0.10/tracdownloads/htdocs/css/admin.css (modified) (1 diff)
- downloadsplugin/0.10/tracdownloads/htdocs/css/downloads.css (modified) (1 diff)
- downloadsplugin/0.10/tracdownloads/templates/admin-downloads-list.cs (modified) (4 diffs)
- downloadsplugin/0.10/tracdownloads/templates/downloads-list.cs (moved) (moved from downloadsplugin/0.10/tracdownloads/templates/downloads.cs) (2 diffs)
- downloadsplugin/0.10/tracdownloads/wiki.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
downloadsplugin/0.10/tracdownloads/api.py
r2522 r2531 1 import os, time, re 1 import os, time, re, mimetypes 2 2 3 3 from trac.core import * … … 5 5 from trac.wiki import wiki_to_html, wiki_to_oneliner 6 6 from trac.util import format_datetime, pretty_timedelta, pretty_size 7 from trac.web.chrome import add_stylesheet 7 from trac.web.chrome import add_stylesheet, add_script 8 8 9 9 class IDownloadChangeListener(Interface): … … 26 26 class DownloadsApi(Component): 27 27 28 title = Option('downloads', 'title', 'Downloads', 29 'Main navigation bar button title.') 28 30 path = Option('downloads', 'path', '/var/lib/trac/downloads', 29 31 'Directory to store uploaded downloads.') … … 66 68 67 69 def get_downloads(self, req, cursor, order_by = 'id', desc = False): 68 columns = ('id', 'file', 'description', 'size', 'time', 'author', 69 'tags', 'component', 'version', 'architecture', 'platform', 'type') 70 sql = "SELECT id, file, description, size, time, author, tags," \ 70 columns = ('id', 'file', 'description', 'size', 'time', 'count', 71 'author', 'tags', 'component', 'version', 'architecture', 'platform', 72 'type') 73 sql = "SELECT id, file, description, size, time, count, author, tags," \ 71 74 " component, version, architecture, platform, type FROM download " \ 72 75 "ORDER BY " + order_by + (" ASC", " DESC")[bool(desc)] … … 79 82 row['size'] = pretty_size(row['size']) 80 83 row['time'] = pretty_timedelta(row['time']) 84 row['count'] = row['count'] or 0 81 85 downloads.append(row) 82 86 … … 135 139 136 140 def get_download(self, cursor, id): 137 columns = ('id', 'file', 'description', 'size', 'time', 'author', 138 'tags', 'component', 'version', 'architecture', 'platform', 'type') 139 sql = "SELECT id, file, description, size, time, author, tags," \ 141 columns = ('id', 'file', 'description', 'size', 'time', 'count', 142 'author', 'tags', 'component', 'version', 'architecture', 'platform', 143 'type') 144 sql = "SELECT id, file, description, size, time, count, author, tags," \ 140 145 " component, version, architecture, platform, type FROM download" \ 141 146 " WHERE id = %s" … … 144 149 for row in cursor: 145 150 row = dict(zip(columns, row)) 151 row['count'] = row['count'] or 0 146 152 return row 147 153 148 154 def get_download_by_time(self, cursor, time): 149 columns = ('id', 'file', 'description', 'size', 'time', 'author', 150 'tags', 'component', 'version', 'architecture', 'platform', 'type') 151 sql = "SELECT id, file, description, size, time, author, tags," \ 155 columns = ('id', 'file', 'description', 'size', 'time', 'count', 156 'author', 'tags', 'component', 'version', 'architecture', 'platform', 157 'type') 158 sql = "SELECT id, file, description, size, time, count, author, tags," \ 152 159 " component, version, architecture, platform, type FROM download" \ 153 160 " WHERE time = %s" … … 156 163 for row in cursor: 157 164 row = dict(zip(columns, row)) 165 row['count'] = row['count'] or 0 158 166 return row 159 167 … … 184 192 row = dict(zip(columns, row)) 185 193 return row 194 195 def get_description(self, req, cursor): 196 sql = "SELECT value FROM system WHERE name = 'downloads_description'" 197 self.log.debug(sql) 198 cursor.execute(sql) 199 for row in cursor: 200 return (row[0], wiki_to_html(row[0], self.env, req)) 186 201 187 202 # Add item functions. … … 229 244 self._edit_item(cursor, 'download_type', id, type) 230 245 246 def edit_description(self, cursor, description): 247 sql = "UPDATE system SET value = %s WHERE name = 'downloads_description'" 248 self.log.debug(sql % (description,)) 249 cursor.execute(sql, (description,)) 250 231 251 # Delete item functions. 232 252 … … 271 291 add_stylesheet(req, 'downloads/css/admin.css') 272 292 293 # Add JavaScripts 294 add_script(req, 'common/js/trac.js') 295 add_script(req, 'common/js/wikitoolbar.js') 296 273 297 # Fill up HDF structure and return template 274 298 req.hdf['download.authname'] = req.authname 275 req.hdf['downloads.href'] = req.href.admin('downloads', req.args.get(276 'page'))277 299 req.hdf['download.time'] = format_datetime(time.time()) 278 300 return modes[-1] + '.cs', None … … 285 307 page = req.args.get('page') 286 308 action = req.args.get('action') 287 self.log.debug('co mponent: %s page: %s action: %s' % (context, page,309 self.log.debug('context: %s page: %s action: %s' % (context, page, 288 310 action)) 311 312 if context == 'admin': 313 req.hdf['downloads.href'] = req.href.admin('downloads', page) 314 elif context == 'core': 315 req.hdf['downloads.href'] = req.href.downloads() 289 316 290 317 # Determine mode. … … 326 353 else: 327 354 return ['admin-types-list'] 355 elif context == 'core': 356 if action == 'get-file': 357 return ['get-file'] 358 elif action == 'edit': 359 return ['description-edit', 'downloads-list'] 360 elif action == 'post-edit': 361 return ['description-post-edit', 'downloads-list'] 362 else: 363 return ['downloads-list'] 328 364 else: 329 365 pass … … 331 367 def _do_action(self, req, cursor, modes): 332 368 for mode in modes: 333 if mode == 'downloads-list': 334 req.perm.assert_permission('DOWNLOADS_VIEW') 369 if mode == 'get-file': 370 req.perm.assert_permission('DOWNLOADS_VIEW') 371 372 # Get form values. 373 download_id = req.args.get('id') 374 375 # Get download. 376 download = self.get_download(cursor, download_id) 377 378 if download: 379 path = os.path.join(self.path, unicode(download['id']), 380 download['file']) 381 self.log.debug('path: %s' % (path,)) 382 383 # Increase downloads count. 384 db = self.env.get_db_cnx() 385 cursor = db.cursor() 386 self.edit_download(cursor, download['id'], {'count' : 387 download['count'] + 1}) 388 db.commit() 389 390 # Return uploaded file to request. 391 type = mimetypes.guess_type(path)[0] 392 req.send_file(path, type) 393 else: 394 raise TracError('File not found.') 395 396 elif mode == 'downloads-list': 397 req.perm.assert_permission('DOWNLOADS_VIEW') 398 399 # Get form values. 400 order = req.args.get('order') or 'id' 401 desc = req.args.get('desc') 402 403 req.hdf['downloads.order'] = order 404 req.hdf['downloads.desc'] = desc 405 req.hdf['downloads.has_tags'] = self.env.is_component_enabled( 406 'TagEngine') 407 req.hdf['downloads.title'] = self.title 408 req.hdf['downloads.description'] = self.get_description(req, cursor) 409 req.hdf['downloads.downloads'] = self.get_downloads(req, 410 cursor, order, desc) 335 411 336 412 elif mode == 'admin-downloads-list': … … 359 435 cursor) 360 436 req.hdf['downloads.types'] = self.get_types(req, cursor) 361 return mode + '.cs', None 437 438 elif mode == 'description-edit': 439 req.perm.assert_permission('DOWNLOADS_ADMIN') 440 441 elif mode == 'description-post-edit': 442 req.perm.assert_permission('DOWNLOADS_ADMIN') 443 444 # Get form values. 445 description = req.args.get('description') 446 447 # Set new description. 448 self.edit_description(cursor, description) 362 449 363 450 elif mode == 'downloads-post-add': downloadsplugin/0.10/tracdownloads/core.py
r2522 r2531 23 23 title = Option('downloads', 'title', 'Downloads', 24 24 'Main navigation bar button title.') 25 path = Option('downloads', 'path', '/var/lib/trac/downloads',26 'Directory to store uploaded downloads.')27 25 28 26 # IPermissionRequestor methods. … … 50 48 # IRequestHandler methods. 51 49 def match_request(self, req): 52 if re.match(r'''^/downloads($|/$)''', req.path_info): 50 match = re.match(r'''^/downloads($|/$)''', req.path_info) 51 if match: 53 52 return True 54 if re.match(r'''^/downloads/(\d+)$''', 55 req.path_info): 56 req.args['action'] = 'get_file' 53 match = re.match(r'''^/downloads/(\d+)$''',req.path_info) 54 if match: 55 req.args['action'] = 'get-file' 56 req.args['id'] = match.group(1) 57 57 return True 58 58 return False 59 59 60 60 def process_request(self, req): 61 # Create API object.62 self.api = DownloadsApi(self.env)63 64 61 # Get cursor. 65 62 db = self.env.get_db_cnx() 66 63 cursor = db.cursor() 67 64 68 # CSS styles69 add_stylesheet(req, 'downloads/css/downloads.css')65 # Prepare arguments and HDF structure. 66 req.args['context'] = 'core' 70 67 71 # Prepare HDF structure. 72 req.hdf['downloads.href'] = req.href.downloads() 73 req.hdf['downloads.title'] = self.title 74 75 # Do actions and return content. 76 modes = self._get_modes(req) 77 self.log.debug('modes: %s' % (modes,)) 78 content = self._do_actions(req, cursor, modes) 68 # Return page content. 69 api = DownloadsApi(self.env) 70 content = api.process_downloads(req, cursor) 79 71 db.commit() 80 72 return content 81 82 # Private functions.83 84 def _get_modes(self, req):85 action = req.args.get('action')86 self.log.debug('action: %s' % (action,))87 if action == 'get_file':88 return ['get-file']89 else:90 return ['downloads-list']91 92 def _do_actions(self, req, cursor, modes):93 for mode in modes:94 if mode == 'get-file':95 req.perm.assert_permission('DOWNLOADS_VIEW')96 97 elif mode == 'downloads-list':98 req.perm.assert_permission('DOWNLOADS_VIEW')99 100 # Get form values101 order = req.args.get('order') or 'id'102 desc = req.args.get('desc')103 104 # Fill HDF structure105 req.hdf['downloads.order'] = order106 req.hdf['downloads.desc'] = desc107 req.hdf['downloads.downloads'] = self.api.get_downloads(req,108 cursor)109 110 return 'downloads.cs', None111 #return mode + '.cs', Nonedownloadsplugin/0.10/tracdownloads/db/db1.py
r2522 r2531 10 10 Column('size', type = 'integer'), 11 11 Column('time', type = 'integer'), 12 Column('count', type = 'integer'), 12 13 Column('author'), 13 14 Column('tags'), … … 50 51 "INSERT INTO download_type (name) VALUES ('data')", 51 52 "INSERT INTO download_type (name) VALUES ('other')", 53 "INSERT INTO system (name, value) VALUES ('downloads_description', 'Here is a list of available downloads:')" 52 54 ] 53 55 … … 64 66 cursor.execute(statement) 65 67 66 # Set database schema version 68 # Set database schema version. 67 69 cursor.execute("INSERT INTO system (name, value) VALUES" 68 70 " ('downloads_version', '1')") downloadsplugin/0.10/tracdownloads/htdocs/css/admin.css
r2522 r2531 11 11 } 12 12 13 .listing td.id, .listing td.size, .listing td.time, .listing td.author, 14 .listing td.tags, .listing td.component, .listing td.version, 15 .listing td.architecture, .listing td.platform, .listing td.type 13 .listing td.id, .listing td.size, .listing td.time, .listing td.count, 14 .listing td.author, .listing td.tags, .listing td.component, 15 .listing td.version, .listing td.architecture, .listing td.platform, 16 .listing td.type 16 17 { 17 18 text-align: center; downloadsplugin/0.10/tracdownloads/htdocs/css/downloads.css
r1227 r2531 1 div.downloads-list 2 { 3 margin: 2em; 4 } downloadsplugin/0.10/tracdownloads/templates/admin-downloads-list.cs
r2522 r2531 128 128 <?cs call:sortable_th(downloads.order, downloads.desc, 'size', 'Size', downloads.href) ?> 129 129 <?cs call:sortable_th(downloads.order, downloads.desc, 'time', 'Uploaded', downloads.href) ?> 130 <?cs call:sortable_th(downloads.order, downloads.desc, 'count', 'Downloads', downloads.href) ?> 130 131 <?cs call:sortable_th(downloads.order, downloads.desc, 'author', 'Uploader', downloads.href) ?> 131 132 <?cs if:downloads.has_tags ?> … … 164 165 <td class="description"> 165 166 <div class="description"> 166 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>?order=<?cs var:downloads.order ?>;desc=<?cs var:downloads.desc ?>"> 167 <?cs var:download.description ?> 168 </a> 167 <?cs var:download.description ?> 169 168 </div> 170 169 </td> … … 182 181 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>?order=<?cs var:downloads.order ?>;desc=<?cs var:downloads.desc ?>"> 183 182 <?cs var:download.time ?> 183 </a> 184 </div> 185 </td> 186 187 <td class="count"> 188 <div class="count"> 189 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>?order=<?cs var:downloads.order ?>;desc=<?cs var:downloads.desc ?>"> 190 <?cs var:download.count ?> 184 191 </a> 185 192 </div> … … 243 250 </div> 244 251 </td> 245 252 </tr> 246 253 <?cs /each ?> 247 254 </tbody> downloadsplugin/0.10/tracdownloads/templates/downloads-list.cs
r2522 r2531 1 1 <?cs include "header.cs" ?> 2 <?cs include "macros.cs" ?> 3 <?cs include "my_macros.cs" ?> 2 <?cs include "downloads-macros.cs" ?> 4 3 5 4 <div id="ctxtnav"> … … 10 9 <h1><?cs var:downloads.title ?></h1> 11 10 </div> 11 12 <?cs var:downloads.description.1 ?> 13 14 <?cs if:trac.acl.DOWNLOADS_ADMIN ?> 15 <form method="post" action="<?cs var:downloads.href ?>"> 16 <fieldset> 17 <legend> 18 Edit Description: 19 </legend> 20 21 <?cs if:args.action == 'edit' ?> 22 <div class="field"> 23 <textarea id="description" name="description" class="wikitext" rows="10" cols="78"><?cs var:downloads.description.0 ?></textarea> 24 </div> 25 <?cs /if ?> 26 27 <div class="buttons"> 28 <input type="submit" name="submit" value="Edit"/> 29 <?cs if:args.action == 'edit' ?> 30 <input type="button" name="cancel" value="Cancel" onclick="location.replace('<?cs var:downloads.href ?>?order=<?cs var:downloads.order ?>;desc=<?cs var:downloads.desc ?>')"/> 31 <input type="hidden" name="action" value="post-edit"/> 32 <?cs else ?> 33 <input type="hidden" name="action" value="edit"/> 34 <?cs /if ?> 35 <input type="hidden" name="order" value="<?cs var:downloads.order ?>"/> 36 <input type="hidden" name="desc" value="<?cs var:downloads.desc ?>"/> 37 </div> 38 </fieldset> 39 </form> 40 <?cs /if ?> 41 12 42 <?cs if:downloads.downloads.0.id ?> 13 <table class="listing"> 14 <thead> 15 <tr> 16 <?cs call:my_sortable_th(downloads.order, downloads.desc, 'id', 'ID', downloads.href + '?') ?> 17 </tr> 18 </thead> 19 <tbody> 20 <?cs each:download = downloads.downloads ?> 21 <tr class="<?cs if:download.id % #2 ?>even<?cs else ?>odd<?cs /if ?>"> 22 <td class="id"> 23 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>"> 24 <div class="id"><?cs var:download.id ?></div> 25 </a> 26 </td> 43 <div class="downloads-list"> 44 <table class="listing"> 45 <thead> 46 <tr> 47 <?cs call:sortable_th(downloads.order, downloads.desc, 'id', 'ID', downloads.href) ?> 48 <?cs call:sortable_th(downloads.order, downloads.desc, 'file', 'File', downloads.href) ?> 49 <?cs call:sortable_th(downloads.order, downloads.desc, 'description', 'Description', downloads.href) ?> 50 <?cs call:sortable_th(downloads.order, downloads.desc, 'size', 'Size', downloads.href) ?> 51 <?cs call:sortable_th(downloads.order, downloads.desc, 'time', 'Uploaded', downloads.href) ?> 52 <?cs call:sortable_th(downloads.order, downloads.desc, 'count', 'Downloads', downloads.href) ?> 53 <?cs call:sortable_th(downloads.order, downloads.desc, 'author', 'Uploader', downloads.href) ?> 54 <?cs if:downloads.has_tags ?> 55 <?cs call:sortable_th(downloads.order, downloads.desc, 'tags', 'Tags', downloads.href) ?> 56 <?cs /if ?> 57 <?cs call:sortable_th(downloads.order, downloads.desc, 'component', 'Component', downloads.href) ?> 58 <?cs call:sortable_th(downloads.order, downloads.desc, 'version', 'Version', downloads.href) ?> 59 <?cs call:sortable_th(downloads.order, downloads.desc, 'architecture', 'Architecture', downloads.href) ?> 60 <?cs call:sortable_th(downloads.order, downloads.desc, 'platform', 'Platform', downloads.href) ?> 61 <?cs call:sortable_th(downloads.order, downloads.desc, 'type', 'Type', downloads.href) ?> 27 62 </tr> 28 <?cs /each ?> 29 </tbody> 30 </table> 63 </thead> 64 <tbody> 65 <?cs each:download = downloads.downloads ?> 66 <tr class="<?cs if:download.id % #2 ?>odd<?cs else ?>even<?cs /if ?>"> 67 <td class="id"> 68 <div class="id"> 69 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>"> 70 <?cs var:download.id ?> 71 </a> 72 </div> 73 </td> 74 75 <td class="file"> 76 <div class="file"> 77 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>"> 78 <?cs var:download.file ?> 79 </a> 80 </div> 81 </td> 82 83 <td class="description"> 84 <div class="description"> 85 <?cs var:download.description ?> 86 </div> 87 </td> 88 89 <td class="size"> 90 <div class="size"> 91 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>"> 92 <?cs var:download.size ?> 93 </a> 94 </div> 95 </td> 96 97 <td class="time"> 98 <div class="time"> 99 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>"> 100 <?cs var:download.time ?> 101 </a> 102 </div> 103 </td> 104 105 <td class="count"> 106 <div class="count"> 107 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>"> 108 <?cs var:download.count ?> 109 </a> 110 </div> 111 </td> 112 113 <td class="author"> 114 <div class="author"> 115 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>"> 116 <?cs var:download.author ?> 117 </a> 118 </div> 119 </td> 120 121 <?cs if:downloads.has_tags ?> 122 <td class="tags"> 123 <div class="tags"> 124 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>"> 125 <?cs var:download.tags ?> 126 </a> 127 </div> 128 </td> 129 <?cs /if ?> 130 131 <td class="component"> 132 <div class="component"> 133 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>"> 134 <?cs var:download.component ?> 135 </a> 136 </div> 137 </td> 138 139 <td class="version"> 140 <div class="version"> 141 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>"> 142 <?cs var:download.version ?> 143 </a> 144 </div> 145 </td> 146 147 <td class="architecture"> 148 <div class="architecture"> 149 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>"> 150 <?cs var:download.architecture.name ?> 151 </a> 152 </div> 153 </td> 154 155 <td class="platform"> 156 <div class="platform"> 157 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>"> 158 <?cs var:download.platform.name ?> 159 </a> 160 </div> 161 </td> 162 163 <td class="type"> 164 <div class="type"> 165 <a href="<?cs var:downloads.href ?>/<?cs var:download.id ?>"> 166 <?cs var:download.type.name ?> 167 </a> 168 </div> 169 </td> 170 </tr> 171 <?cs /each ?> 172 </tbody> 173 </table> 174 </div> 31 175 <?cs else ?> 32 176 <p class="help">There are no downloads created.</p> downloadsplugin/0.10/tracdownloads/wiki.py
r1227 r2531 1 2 from trac.core import * 3 from trac.util.html import html 4 5 from trac.wiki import IWikiSyntaxProvider 6 1 7 from tracdownloads.api import * 2 from trac.core import *3 from trac.wiki import IWikiSyntaxProvider4 from trac.util.html import html5 8 6 9 class DownloadsWiki(Component): … … 21 24 def _download_link(self, formatter, ns, params, label): 22 25 if ns == 'download': 23 # Get cursor. 24 db = self.env.get_db_cnx() 25 cursor = db.cursor() 26 if formatter.req.perm.has_permission('DOWNLOADS_VIEW'): 27 # Get cursor. 28 db = self.env.get_db_cnx() 29 cursor = db.cursor() 26 30 27 # Get referenced screenshot.28 api = DownloadsApi(self)31 # Get API component. 32 api = DownloadsApi(self.env) 29 33 30 return html.a(label, href = formatter.href.downloads(), 31 title = params, class_ = 'missing') 34 # Get download. 35 download = api.get_download(cursor, params) 36 37 if download: 38 # Return link to existing file. 39 return html.a(label, href = formatter.href.downloads(params), 40 title = download['file']) 41 else: 42 # Return link to non-existing file. 43 return html.a(label, href = '#', title = 'File not found.', 44 class_ = 'missing') 45 else: 46 # Return link to file to which is no permission. 47 return html.a(label, href = '#', title = 'No permission to file.', 48 class_ = 'missing')
