root/galaxy-central/lib/galaxy/webapps/reports/controllers/jobs.py

リビジョン 2, 21.0 KB (コミッタ: hatakeyama, 14 年 前)

import galaxy-central

行番号 
1import calendar, operator, os, socket
2from datetime import *
3from time import mktime, strftime, localtime
4from galaxy.web.base.controller import *
5from galaxy import model, util
6from galaxy.web.framework.helpers import time_ago, iff, grids
7from galaxy.model.orm import *
8import pkg_resources
9pkg_resources.require( "SQLAlchemy >= 0.4" )
10import sqlalchemy as sa
11import logging
12log = logging.getLogger( __name__ )
13
14class SpecifiedDateListGrid( grids.Grid ):
15    class JobIdColumn( grids.IntegerColumn ):
16        def get_value( self, trans, grid, job ):
17            return job.id
18    class StateColumn( grids.TextColumn ):
19        def get_value( self, trans, grid, job ):
20            return '<div class="count-box state-color-%s">%s</div>' % ( job.state, job.state )
21        def filter( self, trans, user, query, column_filter ):
22            if column_filter == 'Unfinished':
23                return query.filter( not_( or_( model.Job.table.c.state == model.Job.states.OK,
24                                                model.Job.table.c.state == model.Job.states.ERROR,
25                                                model.Job.table.c.state == model.Job.states.DELETED ) ) )
26            return query
27    class ToolColumn( grids.TextColumn ):
28        def get_value( self, trans, grid, job ):
29            return job.tool_id
30    class CreateTimeColumn( grids.DateTimeColumn ):
31        def get_value( self, trans, grid, job ):
32            return job.create_time
33    class UserColumn( grids.GridColumn ):
34        def get_value( self, trans, grid, job ):
35            if job.user:
36                return job.user.email
37            return 'anonymous'
38    class EmailColumn( grids.GridColumn ):
39        def filter( self, trans, user, query, column_filter ):
40            if column_filter == 'All':
41                return query
42            return query.filter( and_( model.Job.table.c.user_id == model.User.table.c.id,
43                                       model.User.table.c.email == column_filter ) )
44    class SpecifiedDateColumn( grids.GridColumn ):
45        def filter( self, trans, user, query, column_filter ):
46            if column_filter == 'All':
47                return query
48            # We are either filtering on a date like YYYY-MM-DD or on a month like YYYY-MM,
49            # so we need to figure out which type of date we have
50            if column_filter.count( '-' ) == 2:
51                # We are filtering on a date like YYYY-MM-DD
52                year, month, day = map( int, column_filter.split( "-" ) )
53                start_date = date( year, month, day )
54                end_date = start_date + timedelta( days=1 )
55                return query.filter( and_( self.model_class.table.c.create_time >= start_date,
56                                           self.model_class.table.c.create_time < end_date ) )
57            if column_filter.count( '-' ) == 1:
58                # We are filtering on a month like YYYY-MM
59                year, month = map( int, column_filter.split( "-" ) )
60                start_date = date( year, month, 1 )
61                end_date = start_date + timedelta( days=calendar.monthrange( year, month )[1] )
62                return query.filter( and_( self.model_class.table.c.create_time >= start_date,
63                                           self.model_class.table.c.create_time < end_date ) )
64
65    # Grid definition
66    use_async = False
67    model_class = model.Job
68    title = "Jobs"
69    template='/webapps/reports/grid.mako'
70    default_sort_key = "id"
71    columns = [
72        JobIdColumn( "Id",
73                     key="id",
74                     link=( lambda item: dict( operation="job_info", id=item.id, webapp="reports" ) ),
75                     attach_popup=False,
76                     filterable="advanced" ),
77        StateColumn( "State",
78                      key="state",
79                      attach_popup=False ),
80        ToolColumn( "Tool Id",
81                    key="tool_id",
82                    link=( lambda item: dict( operation="tool_per_month", id=item.id, webapp="reports" ) ),
83                    attach_popup=False ),
84        CreateTimeColumn( "Creation Time",
85                          key="create_time",
86                          attach_popup=False ),
87        UserColumn( "User",
88                    key="email",
89                    model_class=model.User,
90                    link=( lambda item: dict( operation="user_per_month", id=item.id, webapp="reports" ) ),
91                    attach_popup=False ),
92        # Columns that are valid for filtering but are not visible.
93        SpecifiedDateColumn( "Specified Date",
94                             key="specified_date",
95                             visible=False ),
96        EmailColumn( "Email",
97                     key="email",
98                     model_class=model.User,
99                     visible=False ),
100        grids.StateColumn( "State",
101                           key="state",
102                           visible=False,
103                           filterable="advanced" )
104    ]
105    columns.append( grids.MulticolFilterColumn( "Search",
106                                                cols_to_filter=[ columns[1], columns[2] ],
107                                                key="free-text-search",
108                                                visible=False,
109                                                filterable="standard" ) )
110    standard_filters = []
111    default_filter = { 'specified_date' : 'All' }
112    num_rows_per_page = 50
113    preserve_state = False
114    use_paging = True
115    def build_initial_query( self, trans, **kwd ):
116        return trans.sa_session.query( self.model_class ) \
117                               .join( model.User ) \
118                               .enable_eagerloads( False )
119
120class Jobs( BaseController ):
121
122    specified_date_list_grid = SpecifiedDateListGrid()
123
124    @web.expose
125    def specified_date_handler( self, trans, **kwd ):
126        # We add params to the keyword dict in this method in order to rename the param
127        # with an "f-" prefix, simulating filtering by clicking a search link.  We have
128        # to take this approach because the "-" character is illegal in HTTP requests.
129        if 'f-specified_date' in kwd and 'specified_date' not in kwd:
130            # The user clicked a State link in the Advanced Search box, so 'specified_date'
131            # will have been eliminated.
132            pass
133        elif 'specified_date' not in kwd:
134            kwd[ 'f-specified_date' ] = 'All'
135        else:
136            kwd[ 'f-specified_date' ] = kwd[ 'specified_date' ]
137        if 'operation' in kwd:
138            operation = kwd['operation'].lower()
139            if operation == "job_info":
140                return trans.response.send_redirect( web.url_for( controller='jobs',
141                                                                  action='job_info',
142                                                                  **kwd ) )
143            elif operation == "tool_for_month":
144                kwd[ 'f-tool_id' ] = kwd[ 'tool_id' ]
145            elif operation == "tool_per_month":
146                # The received id is the job id, so we need to get the job's tool_id.
147                job_id = kwd.get( 'id', None )
148                job = get_job( trans, job_id )
149                kwd[ 'tool_id' ] = job.tool_id
150                return trans.response.send_redirect( web.url_for( controller='jobs',
151                                                                  action='tool_per_month',
152                                                                  **kwd ) )
153            elif operation == "user_for_month":
154                kwd[ 'f-email' ] = util.restore_text( kwd[ 'email' ] )
155            elif operation == "user_per_month":
156                # The received id is the job id, so we need to get the id of the user
157                # that submitted the job.
158                job_id = kwd.get( 'id', None )
159                job = get_job( trans, job_id )
160                if job.user:
161                    kwd[ 'email' ] = job.user.email
162                else:
163                    kwd[ 'email' ] = None # For anonymous users
164                return trans.response.send_redirect( web.url_for( controller='jobs',
165                                                                  action='user_per_month',
166                                                                  **kwd ) )
167            elif operation == "specified_date_in_error":
168                kwd[ 'f-state' ] = 'error'
169            elif operation == "unfinished":
170                kwd[ 'f-state' ] = 'Unfinished'
171        return self.specified_date_list_grid( trans, **kwd )
172    @web.expose
173    def specified_month_all( self, trans, **kwd ):
174        params = util.Params( kwd )
175        message = ''
176        monitor_email = params.get( 'monitor_email', 'monitor@bx.psu.edu' )
177        # If specified_date is not received, we'll default to the current month
178        specified_date = kwd.get( 'specified_date', datetime.utcnow().strftime( "%Y-%m-%d" ) )
179        specified_month = specified_date[ :7 ]
180        year, month = map( int, specified_month.split( "-" ) )
181        start_date = date( year, month, 1 )
182        end_date = start_date + timedelta( days=calendar.monthrange( year, month )[1] )
183        month_label = start_date.strftime( "%B" )
184        year_label = start_date.strftime( "%Y" )
185        q = sa.select( ( sa.func.date( model.Job.table.c.create_time ).label( 'date' ),
186                         sa.func.sum( sa.case( [ ( model.User.table.c.email == monitor_email, 1 ) ], else_=0 ) ).label( 'monitor_jobs' ),
187                         sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
188                       whereclause = sa.and_( model.Job.table.c.create_time >= start_date,
189                                              model.Job.table.c.create_time < end_date ),
190                       from_obj = [ sa.outerjoin( model.Job.table, model.User.table ) ],
191                       group_by = [ 'date' ],
192                       order_by = [ sa.desc( 'date' ) ] )
193        jobs = []
194        for row in q.execute():
195            jobs.append( ( row.date.strftime( "%A" ),
196                           row.date,
197                           row.total_jobs - row.monitor_jobs,
198                           row.monitor_jobs,
199                           row.total_jobs,
200                           row.date.strftime( "%d" ) ) )
201        return trans.fill_template( '/webapps/reports/jobs_specified_month_all.mako',
202                                    month_label=month_label,
203                                    year_label=year_label,
204                                    month=month,
205                                    jobs=jobs,
206                                    message=message )
207    @web.expose
208    def specified_month_in_error( self, trans, **kwd ):
209        params = util.Params( kwd )
210        message = ''
211        # If specified_date is not received, we'll default to the current month
212        specified_date = kwd.get( 'specified_date', datetime.utcnow().strftime( "%Y-%m-%d" ) )
213        specified_month = specified_date[ :7 ]
214        year, month = map( int, specified_month.split( "-" ) )
215        start_date = date( year, month, 1 )
216        end_date = start_date + timedelta( days=calendar.monthrange( year, month )[1] )
217        month_label = start_date.strftime( "%B" )
218        year_label = start_date.strftime( "%Y" )
219        q = sa.select( ( sa.func.date( model.Job.table.c.create_time ).label( 'date' ),
220                         sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
221                       whereclause = sa.and_( model.Job.table.c.state == 'error',
222                                              model.Job.table.c.create_time >= start_date,
223                                              model.Job.table.c.create_time < end_date ),
224                       from_obj = [ sa.outerjoin( model.Job.table, model.User.table ) ],
225                       group_by = [ 'date' ],
226                       order_by = [ sa.desc( 'date' ) ] )
227        jobs = []
228        for row in q.execute():
229            jobs.append( ( row.date.strftime( "%A" ),
230                           row.date,
231                           row.total_jobs,
232                           row.date.strftime( "%d" ) ) )
233        return trans.fill_template( '/webapps/reports/jobs_specified_month_in_error.mako',
234                                    month_label=month_label,
235                                    year_label=year_label,
236                                    month=month,
237                                    jobs=jobs,
238                                    message=message )
239    @web.expose
240    def per_month_all( self, trans, **kwd ):
241        params = util.Params( kwd )
242        message = ''
243        monitor_email = params.get( 'monitor_email', 'monitor@bx.psu.edu' )
244        q = sa.select( ( sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ).label( 'date' ),
245                         sa.func.sum( sa.case( [( model.User.table.c.email == monitor_email, 1 )], else_=0 ) ).label( 'monitor_jobs' ),
246                         sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
247                       from_obj = [ sa.outerjoin( model.Job.table, model.User.table ) ],
248                       group_by = [ sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ) ],
249                       order_by = [ sa.desc( 'date' ) ] )
250        jobs = []
251        for row in q.execute():
252            jobs.append( ( row.date.strftime( "%Y-%m" ),
253                           row.total_jobs - row.monitor_jobs,
254                           row.monitor_jobs,
255                           row.total_jobs,
256                           row.date.strftime( "%B" ),
257                           row.date.strftime( "%Y" ) ) )
258        return trans.fill_template( '/webapps/reports/jobs_per_month_all.mako',
259                                    jobs=jobs,
260                                    message=message )
261    @web.expose
262    def per_month_in_error( self, trans, **kwd ):
263        params = util.Params( kwd )
264        message = ''
265        q = sa.select( ( sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ).label( 'date' ),
266                         sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
267                       whereclause = model.Job.table.c.state == 'error',
268                       from_obj = [ model.Job.table ],
269                       group_by = [ sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ) ],
270                       order_by = [ sa.desc( 'date' ) ] )
271        jobs = []
272        for row in q.execute():
273            jobs.append( ( row.date.strftime( "%Y-%m" ),
274                           row.total_jobs,
275                           row.date.strftime( "%B" ),
276                           row.date.strftime( "%Y" ) ) )
277        return trans.fill_template( '/webapps/reports/jobs_per_month_in_error.mako',
278                                    jobs=jobs,
279                                    message=message )
280    @web.expose
281    def per_user( self, trans, **kwd ):
282        params = util.Params( kwd )
283        message = ''
284        jobs = []
285        q = sa.select( ( model.User.table.c.email.label( 'user_email' ),
286                         sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
287                       from_obj = [ sa.outerjoin( model.Job.table, model.User.table ) ],
288                       group_by = [ 'user_email' ],
289                       order_by = [ sa.desc( 'total_jobs' ), 'user_email' ] )
290        for row in q.execute():
291            jobs.append( ( row.user_email,
292                           row.total_jobs ) )
293        return trans.fill_template( '/webapps/reports/jobs_per_user.mako', jobs=jobs, message=message )
294    @web.expose
295    def user_per_month( self, trans, **kwd ):
296        params = util.Params( kwd )
297        message = ''
298        email = util.restore_text( params.get( 'email', '' ) )
299        q = sa.select( ( sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ).label( 'date' ),
300                         sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
301                       whereclause = sa.and_( model.Job.table.c.session_id == model.GalaxySession.table.c.id,
302                                              model.GalaxySession.table.c.user_id == model.User.table.c.id,
303                                              model.User.table.c.email == email
304                                            ),
305                       from_obj = [ sa.join( model.Job.table, model.User.table ) ],
306                       group_by = [ sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ) ],
307                       order_by = [ sa.desc( 'date' ) ] )
308        jobs = []
309        for row in q.execute():
310            jobs.append( ( row.date.strftime( "%Y-%m" ),
311                           row.total_jobs,
312                           row.date.strftime( "%B" ),
313                           row.date.strftime( "%Y" ) ) )
314        return trans.fill_template( '/webapps/reports/jobs_user_per_month.mako',
315                                    email=util.sanitize_text( email ),
316                                    jobs=jobs, message=message )
317    @web.expose
318    def per_tool( self, trans, **kwd ):
319        params = util.Params( kwd )
320        message = ''
321        jobs = []
322        q = sa.select( ( model.Job.table.c.tool_id.label( 'tool_id' ),
323                         sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
324                       from_obj = [ model.Job.table ],
325                       group_by = [ 'tool_id' ],
326                       order_by = [ 'tool_id' ] )
327        for row in q.execute():
328            jobs.append( ( row.tool_id,
329                           row.total_jobs ) )
330        return trans.fill_template( '/webapps/reports/jobs_per_tool.mako',
331                                    jobs=jobs,
332                                    message=message )
333    @web.expose
334    def tool_per_month( self, trans, **kwd ):
335        params = util.Params( kwd )
336        message = ''
337        tool_id = params.get( 'tool_id', 'Add a column1' )
338        specified_date = params.get( 'specified_date', datetime.utcnow().strftime( "%Y-%m-%d" ) )
339        q = sa.select( ( sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ).label( 'date' ),
340                         sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
341                       whereclause = model.Job.table.c.tool_id == tool_id,
342                       from_obj = [ model.Job.table ],
343                       group_by = [ sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ) ],
344                       order_by = [ sa.desc( 'date' ) ] )
345        jobs = []
346        for row in q.execute():
347            jobs.append( ( row.date.strftime( "%Y-%m" ),
348                           row.total_jobs,
349                           row.date.strftime( "%B" ),
350                           row.date.strftime( "%Y" ) ) )
351        return trans.fill_template( '/webapps/reports/jobs_tool_per_month.mako',
352                                    specified_date=specified_date,
353                                    tool_id=tool_id,
354                                    jobs=jobs,
355                                    message=message )
356    @web.expose
357    def job_info( self, trans, **kwd ):
358        params = util.Params( kwd )
359        message = ''
360        job = trans.sa_session.query( model.Job ) \
361                              .get( trans.security.decode_id( kwd.get( 'id', '' ) ) )
362        return trans.fill_template( '/webapps/reports/job_info.mako',
363                                    job=job,
364                                    message=message )
365    @web.expose
366    def per_domain( self, trans, **kwd ):
367        # TODO: rewrite using alchemy
368        params = util.Params( kwd )
369        message = ''
370        engine = model.mapping.metadata.engine
371        jobs = []
372        s = """
373        SELECT
374            substr(bar.first_pass_domain, bar.dot_position, 4) AS domain,
375            count(job_id) AS total_jobs
376        FROM
377            (SELECT
378                user_email AS user_email,
379                first_pass_domain,
380                position('.' in first_pass_domain) AS dot_position,
381                job_id AS job_id
382            FROM
383                (SELECT
384                    email AS user_email,
385                    substr(email, char_length(email)-3, char_length(email)) AS first_pass_domain,
386                    job.id AS job_id
387                FROM
388                    job
389                LEFT OUTER JOIN galaxy_session ON galaxy_session.id = job.session_id
390                LEFT OUTER JOIN galaxy_user ON galaxy_session.user_id = galaxy_user.id
391                WHERE
392                    job.session_id = galaxy_session.id
393                AND
394                    galaxy_session.user_id = galaxy_user.id
395                ) AS foo
396            ) AS bar
397        GROUP BY
398            domain
399        ORDER BY
400            total_jobs DESC
401        """
402        job_rows = engine.text( s ).execute().fetchall()
403        for job in job_rows:
404            jobs.append( ( job.domain, job.total_jobs ) )
405        return trans.fill_template( '/webapps/reports/jobs_per_domain.mako', jobs=jobs, message=message )
406
407## ---- Utility methods -------------------------------------------------------
408
409def get_job( trans, id ):
410    return trans.sa_session.query( trans.model.Job ).get( trans.security.decode_id( id ) )
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。