Changeset 9822
- Timestamp:
- 22 Dec 2012, 09:16:05 (12 years ago)
- Location:
- main/waeup.kofa/trunk/src/waeup/kofa
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
main/waeup.kofa/trunk/src/waeup/kofa/browser/pages.py
r9806 r9822 194 194 return 195 195 196 def doll_up(view, user=None): 197 """Doll up export jobs for displaying in table. 198 """ 199 job_entries = view.context.get_running_export_jobs(user) 200 job_manager = getUtility(IJobManager) 201 entries = [] 202 for job_id, exporter_name, user_id in job_entries: 203 job = job_manager.get(job_id) 204 exporter = getUtility(ICSVExporter, name=exporter_name) 205 exporter_title = getattr(exporter, 'title', 'Unknown') 206 args = ', '.join([str(x) for x in job.kwargs.values()]) 207 descr = '%s <br> (%s)' % (exporter_title, args) 208 status = job.finished and 'ready' or 'running' 209 status = job.failed and 'FAILED' or status 210 start_time = getattr(job, 'begin_after', None) 211 if start_time: 212 start_time = start_time.astimezone( 213 getUtility( 214 IKofaUtils).tzinfo).strftime("%Y-%m-%d %H:%M:%S %Z") 215 download_url = view.url(view.context, 'download_export', 216 data=dict(job_id=job_id)) 217 new_entry = dict( 218 job=job_id, 219 descr=descr, 220 creator=user_id, 221 status=status, 222 start_time=start_time, 223 download_url=download_url, 224 show_download_button = (job.finished and not job.failed), 225 show_refresh_button = not job.finished, 226 show_discard_button = job.finished,) 227 entries.append(new_entry) 228 return entries 229 196 230 # 197 231 # Login/logout and language switch pages... … … 1505 1539 pnav = 0 1506 1540 export_button = _(u'Create CSV file') 1507 _running_exports = None1508 1541 1509 1542 def getExporters(self): … … 1516 1549 return sorted(title_name_tuples) 1517 1550 1518 def job_finished(self, status): 1519 return status == 'completed' 1520 1521 def getRunningExports(self): 1522 """Returns running exports as list of tuples. 1523 1524 Only exports triggered by the current user (identified by 1525 principal.id) are returned. 1526 1527 Each tuple has the form (<STATUS>, <STATUS_TITLE>, <EXPORTER_NAME>). 1528 1529 ``STATUS``: 1530 the status as machine readable string (something like 1531 ``'completed'``) 1532 1533 ``STATUS_TITLE``: 1534 status of export as translated string. 1535 1536 ``EXPORTER_NAME``: 1537 string representing the exporter title used when triggering 1538 the export job. 1539 """ 1540 if self._running_exports is None: 1541 self._running_exports = self._getRunningExports() 1542 return self._running_exports 1543 1544 def _getRunningExports(self): 1545 result = self.context.get_export_jobs_status(self.user_id) 1546 return result 1547 1548 def update(self, export=None, start_export=None, exporter=None, 1549 discard=None, download=None): 1550 self.user_id = self.request.principal.id 1551 if discard: 1552 myjobs = self.context.get_running_export_jobs(self.user_id) 1553 for entry in myjobs: 1554 self.context.delete_export_entry(entry) 1555 self.flash(_('Discarded export result')) 1556 return 1557 if download: 1558 myjobs = self.context.get_running_export_jobs(self.user_id) 1559 if not len(myjobs): 1560 self.flash(_('This export was already discarded.')) 1561 return 1562 job_id = myjobs[0][0] 1563 self.redirect( 1564 self.url(self.context, 'export.csv') + '?job_id=%s' % job_id) 1565 return 1566 if None in (start_export, exporter): 1567 return 1568 job_id = self.context.start_export_job( 1569 exporter, self.request.principal.id) 1570 self.redirect(self.url(self.context, 'export')) 1551 def update(self, CREATE=None, DISCARD=None, exporter=None, job_id=None): 1552 if CREATE: 1553 job_id = self.context.start_export_job( 1554 exporter, self.request.principal.id) 1555 if DISCARD and job_id: 1556 entry = self.context.entry_from_job_id(job_id) 1557 self.context.delete_export_entry(entry) 1558 self.flash(_('Discarded export') + ' %s' % job_id) 1559 self.entries = doll_up(self, user=None) 1571 1560 return 1572 1561 1573 1562 class ExportCSVView(grok.View): 1574 1563 grok.context(IDataCenter) 1575 grok.name(' export.csv')1564 grok.name('download_export') 1576 1565 grok.require('waeup.manageDataCenter') 1577 1566 1578 1567 def render(self, job_id=None): 1579 1580 1568 manager = getUtility(IJobManager) 1581 1569 job = manager.get(job_id) … … 1597 1585 'Content-Disposition', 'attachment; filename="%s' % filename) 1598 1586 # remove job and running_exports entry from context 1599 self.context.delete_export_entry(1600 self.context.entry_from_job_id(job_id))1587 #self.context.delete_export_entry( 1588 # self.context.entry_from_job_id(job_id)) 1601 1589 ob_class = self.__implemented__.__name__.replace('waeup.kofa.','') 1602 1590 self.context.logger.info('%s - exported: %s' % (ob_class, filename)) -
main/waeup.kofa/trunk/src/waeup/kofa/browser/templates/datacenterexportpage.pt
r9821 r9822 1 <div i18n:domain="waeup.kofa" class="row"> 2 <div class="span8 columns"> 3 <div class="span8 columns"> 4 <p i18n:translate=""> 5 Here you can create CSV files from parts of portal data. 6 </p> 7 <p i18n:translate=""> 8 Please pick the type of objects you want to export from the 9 selection below. 10 </p> 11 <p i18n:translate=""> 12 The file will be generated and then be made available for you 13 to download. You must download or discard any existing export 14 file before creating a new one. 15 </p> 16 </div> 17 <form method="POST"> 18 <fieldset> 19 <label for="running_exports" 20 tal:condition="view/getRunningExports">Running Export: 21 </label> 1 <p i18n:translate=""> 2 Here you can create CSV files from parts of portal data. 3 Please pick the type of objects you want to export from the 4 selection below. The file will be generated and then be 5 made available for you to download in the table below. 6 </p> 22 7 8 <br /> 23 9 24 <div class="input span6"> 25 <div tal:repeat="items view/getRunningExports"> 26 Data type: 27 <span tal:content="python: items[2]">exporter 28 </span><br /> 29 Status: 30 <span tal:content="python: items[1]">status 31 </span> 32 <br /><br /><br /> 33 <span tal:condition="not: python: view.job_finished(items[0])"> 34 <img src="" tal:attributes="src static/ajax-loader.gif" 35 alt="Loading..." class="spinner" /> 36 <input type="submit" name="reload" value="Reload" 37 class="btn primary" /> 38 </span> 39 <div> 40 <span tal:condition="python: view.job_finished(items[0])"> 41 <input type="submit" name="download" value="Download" 42 class="btn primary" /> 43 <input type="submit" name="discard" value="Discard" 44 class="btn secondary" /> 45 </span> 46 </div> 47 </div> 48 <div> 49 <tal:loading_bar content="structure provider:loadingbar" /> 50 </div> 51 </div> 10 <form method="POST"> 11 <label for="exporter"> 12 Exporter (Data Type): 13 </label> 14 <div class="input"> 15 <select name="exporter"> 16 <span tal:repeat="items view/getExporters" tal:omit-tag=""> 17 <option tal:define="name python: items[1]; title python: items[0]" 18 tal:attributes="value name"> 19 <span tal:replace="title">TITLE 20 </span> 21 </option> 22 </span> 23 </select> 24 </div> 25 <br /> 26 <div class="input"> 27 <input i18n:translate="" type="submit" class="btn primary" 28 name="CREATE" tal:attributes="value view/export_button" /> 29 </div> 30 </form> 52 31 32 <br /><br /> 53 33 54 <div class="clearfix" tal:condition="not: view/getRunningExports"> 55 <label for="exporter">Data Type: 56 </label> 57 <div class="input"> 58 <select name="exporter"> 59 <span tal:repeat="items view/getExporters" tal:omit-tag=""> 60 <option tal:define="name python: items[1]; title python: items[0]" 61 tal:attributes="value name"> 62 <span tal:replace="title">TITLE 63 </span> 64 </option> 65 </span> 66 </select> 67 <span class="help-inline" i18n:translate=""> 68 Type of objects to export 69 </span> 70 </div> 71 </div> 72 73 74 <div class="input" tal:condition="not: view/getRunningExports"> 75 <input i18n:translate="" type="submit" class="btn primary" 76 name="start_export" tal:attributes="value view/export_button" /> 77 </div> 78 </fieldset> 79 </form> 80 </div> 81 </div> 34 <table i18n:domain="waeup.kofa"> 35 <thead> 36 <tr> 37 <th i18n:translate="">Export Number</th> 38 <th i18n:translate="">Description</th> 39 <th i18n:translate="">Creator</th> 40 <th i18n:translate="">Creation Date</th> 41 <th i18n:translate="">Status</th> 42 <th> </th> 43 </tr> 44 </thead> 45 <tbody> 46 <tr tal:repeat="job view/entries"> 47 <td> 48 <span tal:replace="job/job">12</span> 49 </td> 50 <td> 51 <span tal:replace="structure job/descr">DESCRIPTION</span> 52 </td> 53 <td> 54 <span tal:replace="job/creator">CREATOR</span> 55 </td> 56 <td nowrap> 57 <span tal:replace="job/start_time">DATETIME</span> 58 </td> 59 <td> 60 <span tal:replace="job/status">STATUS</span> 61 </td> 62 <td nowrap> 63 <a href="" class="btn" i18n:translate="" 64 tal:condition="job/show_refresh_button"> 65 <img tal:attributes="src static/actionicon_reload.png" /> 66 Reload 67 </a> 68 <a href="" class="btn primary" 69 tal:attributes="href job/download_url" 70 tal:condition="job/show_download_button"> 71 Download</a> 72 <form method="POST"> 73 <input type="hidden" name="job_id" 74 tal:attributes="value job/job" /> 75 <input type="submit" class="btn secondary" 76 name="DISCARD" value="Discard" 77 tal:condition="job/show_discard_button" /> 78 </form> 79 </td> 80 </tr> 81 </tbody> 82 </table> -
main/waeup.kofa/trunk/src/waeup/kofa/browser/tests/test_browser.py
r9701 r9822 200 200 # while the export file is created, we get a reload button 201 201 # (or a loading bar if javascript is enabled)... 202 self. browser.getControl("Reload").click()202 self.assertTrue('Reload' in self.browser.contents) 203 203 # ...which is displayed as long as the job is not finished. 204 204 # When the job is finished and we reload the page... 205 205 job_id = self.wait_for_export_job_completed() 206 try: 207 self.browser.getControl("Reload").click() 208 except LookupError: 209 # if the job completed very fast, we will get the download 210 # link immediately 211 pass 206 self.browser.open(self.datacenter_path + '/export') 207 self.assertFalse('Reload' in self.browser.contents) 212 208 # ...we can download the result 213 self.browser.get Control("Download").click()209 self.browser.getLink("Download").click() 214 210 self.assertEqual(self.browser.headers['content-type'], 215 211 'text/csv; charset=UTF-8') … … 221 217 222 218 # after download, the job and the result file are removed 223 manager = getUtility(IJobManager)224 result = manager.get(job_id)225 self.assertEqual(result, None)226 self.assertEqual(self.stored_in_datacenter(job_id), False)219 #manager = getUtility(IJobManager) 220 #result = manager.get(job_id) 221 #self.assertEqual(result, None) 222 #self.assertEqual(self.stored_in_datacenter(job_id), False) 227 223 logfile = os.path.join( 228 224 self.app['datacenter'].storage, 'logs', 'datacenter.log') … … 259 255 self.browser.getControl("Create CSV file").click() 260 256 job_id = self.wait_for_export_job_completed() 261 try: 262 self.browser.getControl("Reload").click() 263 except LookupError: 264 pass 265 self.browser.getControl("Download").click() 257 self.browser.open(self.datacenter_path + '/@@export') 258 self.browser.getLink("Download").click() 266 259 self.assertEqual(self.browser.headers['content-type'], 267 260 'text/csv; charset=UTF-8') … … 291 284 self.browser.open(self.datacenter_path + '/@@export') 292 285 self.browser.getControl("Discard").click() 293 self.assertTrue('Discarded export result' in self.browser.contents)286 self.assertTrue('Discarded export' in self.browser.contents) 294 287 return 295 288 -
main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py
r9819 r9822 37 37 KofaForm, NullValidator) 38 38 from waeup.kofa.browser.breadcrumbs import Breadcrumb 39 from waeup.kofa.browser.pages import ContactAdminForm 39 from waeup.kofa.browser.pages import ContactAdminForm, ExportCSVView, doll_up 40 40 from waeup.kofa.browser.resources import ( 41 41 datepicker, datatable, tabs, warning, toggleall) … … 2661 2661 pnav = 1 2662 2662 2663 def doll_up(self):2664 job_entries = self.context.get_running_export_jobs(2665 self.request.principal.id)2666 job_manager = getUtility(IJobManager)2667 entries = []2668 for job_id, exporter_name, user_id in job_entries:2669 job = job_manager.get(job_id)2670 exporter = getUtility(ICSVExporter, name=exporter_name)2671 exporter_title = getattr(exporter, 'title', 'Unknown')2672 args = ', '.join([str(x) for x in job.kwargs.values()])2673 descr = '%s (%s)' % (exporter_title, args)2674 status = job.finished and 'ready' or 'running'2675 status = job.failed and 'FAILED' or status2676 start_time = getattr(job, 'begin_after', None)2677 if start_time:2678 start_time = start_time.astimezone(2679 getUtility(2680 IKofaUtils).tzinfo).strftime("%Y-%m-%d %H:%M:%S %Z")2681 download_url = self.url(self.context, 'download',2682 data=dict(job_id=job_id))2683 new_entry = dict(2684 job=job_id,2685 descr=descr,2686 creator=user_id,2687 status=status,2688 start_time=start_time,2689 download_url=download_url,2690 show_download_button = (job.finished and not job.failed),2691 show_refresh_button = not job.finished,2692 show_discard_button = job.finished,)2693 entries.append(new_entry)2694 self.entries = entries2695 pass2696 2697 2663 def update(self, CREATE=None, DISCARD=None, job_id=None): 2698 2664 if CREATE: … … 2703 2669 self.context.delete_export_entry(entry) 2704 2670 self.flash(_('Discarded export') + ' %s' % job_id) 2705 self. doll_up()2671 self.entries = doll_up(self, user=self.request.principal.id) 2706 2672 return 2707 2673 … … 2771 2737 return 2772 2738 2773 class ExportJobContainerDownload( grok.View):2739 class ExportJobContainerDownload(ExportCSVView): 2774 2740 """Page that configures a students export job. 2775 2741 """ 2776 2742 grok.context(VirtualExportJobContainer) 2777 2743 grok.require('waeup.showStudents') 2778 grok.name('download')2779 2780 def update(self, job_id=None):2781 self.job_id=job_id2782 return2783 2784 def render(self):2785 job = getUtility(IJobManager).get(self.job_id)2786 self.response.setHeader(2787 'Content-Type', 'text/csv; charset=UTF-8')2788 self.response.setHeader(2789 'Content-Disposition:', 'attachment; filename="%s' % (2790 'students.csv',))2791 return open(job.result, 'rb') -
main/waeup.kofa/trunk/src/waeup/kofa/students/browser_templates/exportjobsindex.pt
r9821 r9822 16 16 </td> 17 17 <td> 18 <span tal:replace=" job/descr">DESCRIPTION</span>18 <span tal:replace="structure job/descr">DESCRIPTION</span> 19 19 </td> 20 20 <td> … … 28 28 </td> 29 29 <td nowrap> 30 <a href="" class="btn" i18n:translate="" 31 tal:condition="job/show_refresh_button"> 32 <img tal:attributes="src static/actionicon_reload.png" /> 33 Reload 34 </a> 35 <a href="" class="btn primary" 36 tal:attributes="href job/download_url" 37 tal:condition="job/show_download_button"> 38 Download</a> 30 39 <form method="POST"> 31 40 <input type="hidden" name="job_id" 32 41 tal:attributes="value job/job" /> 33 <a href="" class="btn primary"34 tal:attributes="href job/download_url"35 tal:condition="job/show_download_button">36 Download</a>37 42 <input type="submit" class="btn secondary" 38 43 name="DISCARD" value="Discard" 39 44 tal:condition="job/show_discard_button" /> 40 <a href="" class="btn" i18n:translate=""41 tal:condition="job/show_refresh_button">42 <img tal:attributes="src static/actionicon_reload.png" />43 Reload44 </a>45 45 </form> 46 46 </td>
Note: See TracChangeset for help on using the changeset viewer.