1 | import grok |
---|
2 | from zc.async.interfaces import COMPLETED, NEW |
---|
3 | from zope.interface import Interface |
---|
4 | from waeup.ikoba.async import IJob, IJobManager |
---|
5 | from waeup.ikoba.browser.layout import IkobaPage |
---|
6 | from waeup.ikoba.interfaces import IIkobaObject, IDataCenter |
---|
7 | from waeup.ikoba.interfaces import MessageFactory as _ |
---|
8 | |
---|
9 | grok.templatedir('templates') |
---|
10 | grok.context(IIkobaObject) |
---|
11 | |
---|
12 | loadingbar_template = ''' |
---|
13 | <input id="status_url" type="hidden" name="status_url" value="%s" /> |
---|
14 | <div id="loadbar">%%s</div> |
---|
15 | ''' |
---|
16 | |
---|
17 | class LoadingBar(grok.ViewletManager): |
---|
18 | grok.name('loadingbar') |
---|
19 | |
---|
20 | class LoadingBarViewlet(grok.Viewlet): |
---|
21 | grok.context(Interface) |
---|
22 | grok.viewletmanager(LoadingBar) |
---|
23 | |
---|
24 | _running_exports = None |
---|
25 | |
---|
26 | def getRunningExports(self): |
---|
27 | """Returns running exports as list of tuples. |
---|
28 | |
---|
29 | Only exports triggered by the current user (identified by |
---|
30 | principal.id) are returned. |
---|
31 | |
---|
32 | Each tuple has the form (<STATUS>, <STATUS_TITLE>, <EXPORTER_NAME>). |
---|
33 | |
---|
34 | ``STATUS``: |
---|
35 | the status as machine readable string (something like |
---|
36 | ``'completed'``) |
---|
37 | |
---|
38 | ``STATUS_TITLE``: |
---|
39 | status of export as translated string. |
---|
40 | |
---|
41 | ``EXPORTER_NAME``: |
---|
42 | string representing the exporter title used when triggering |
---|
43 | the export job. |
---|
44 | """ |
---|
45 | result = self.context.get_export_jobs_status(self.user_id) |
---|
46 | return result |
---|
47 | |
---|
48 | def update(self): |
---|
49 | self.user_id = self.request.principal.id |
---|
50 | self.exports = self.getRunningExports() |
---|
51 | self.uncompleted = [x for x in self.exports if x[0] != 'completed'] |
---|
52 | |
---|
53 | def render(self): |
---|
54 | status_url = self.view.url('status') |
---|
55 | template = loadingbar_template % (status_url,) |
---|
56 | content = '' |
---|
57 | return template % content |
---|
58 | |
---|
59 | class DataCenterJSON(grok.JSON): |
---|
60 | grok.context(IDataCenter) |
---|
61 | |
---|
62 | def status(self): |
---|
63 | """Get status of currently handled export jobs for users. |
---|
64 | |
---|
65 | The result is a set of valus useful for JavaScript handlers to |
---|
66 | update some page handling data center exports. |
---|
67 | |
---|
68 | Returns a mapping:: |
---|
69 | |
---|
70 | {html=<string>, interval=<int>, reload=<bool>} |
---|
71 | |
---|
72 | where `html` is some HTML code that might be shown in a |
---|
73 | loading bar section. |
---|
74 | |
---|
75 | `interval` is the time in microseconds after which the loading |
---|
76 | bar should be reloaded (by a new JSON call). If the value is |
---|
77 | zero, then the loading bar should not be renewed and further |
---|
78 | JSON calls be canceled. |
---|
79 | |
---|
80 | `reload` is a hint to tell, whether the complete page should |
---|
81 | be reloaded or not. Reloading is neccessary, if the export |
---|
82 | file creation finished and download buttons or similar should |
---|
83 | appear. |
---|
84 | """ |
---|
85 | user_id = self.request.principal.id |
---|
86 | jobs = self.context.get_export_jobs_status(user_id) |
---|
87 | uncompleted = [x for x in jobs if x[0] != 'completed'] |
---|
88 | result = dict( |
---|
89 | html='', interval=0, reload=False) |
---|
90 | if len(uncompleted): |
---|
91 | html = '<em>%s</em>' % (_("Please wait..."),) |
---|
92 | result.update(interval=500, html=html) |
---|
93 | else: |
---|
94 | if len(jobs): |
---|
95 | result.update(reload=True) |
---|
96 | return result |
---|
97 | |
---|
98 | |
---|
99 | class JobManagerView(IkobaPage): |
---|
100 | """The main view for the job container. |
---|
101 | """ |
---|
102 | grok.name('index.html') |
---|
103 | grok.context(IJobManager) |
---|
104 | grok.template('virtjobscontainerindex') |
---|
105 | grok.require('waeup.manageJobs') |
---|
106 | |
---|
107 | def jobs(self): |
---|
108 | for job_id, job in sorted(self.context.jobs(), |
---|
109 | cmp=lambda x, y: cmp(int(x[0]), int(y[0]))): |
---|
110 | link = self.url(self.context, job_id) |
---|
111 | removable = job.status in (COMPLETED, NEW) |
---|
112 | yield dict( |
---|
113 | job_id = job_id, |
---|
114 | job = job, |
---|
115 | link = link, |
---|
116 | status = job.status, |
---|
117 | begin_after = job.begin_after, |
---|
118 | begin_by = job.begin_by, |
---|
119 | annotations = '%r' % [ |
---|
120 | (x, y) for x, y in job.annotations.items()], |
---|
121 | removable = removable, |
---|
122 | failure = '%r' % getattr(job, 'traceback', None), |
---|
123 | ) |
---|
124 | |
---|
125 | def update(self, START_NEW=None, REMOVE=None, job_id=None): |
---|
126 | if REMOVE and job_id: |
---|
127 | self.context.remove(job_id) |
---|
128 | self.flash('Removed job "%s"' % job_id) |
---|
129 | if START_NEW: |
---|
130 | self.context.start_test_job() #pragma NO COVER |
---|
131 | self.flash('Started new test job "%s"' % job_id) #pragma NO COVER |
---|
132 | return |
---|
133 | |
---|
134 | class JobView(grok.View): |
---|
135 | grok.name('index.html') |
---|
136 | grok.context(IJob) |
---|
137 | grok.template('jobindex') |
---|
138 | grok.require('waeup.manageJobs') |
---|
139 | |
---|
140 | def percent(self): |
---|
141 | value = self.context.annotations.get('percent', None) |
---|
142 | if not value: |
---|
143 | return |
---|
144 | value = int(value+0.5) |
---|
145 | return min(value, 100) |
---|
146 | |
---|
147 | def update(self): |
---|
148 | pass |
---|