Changeset 7095


Ignore:
Timestamp:
25/06/10 14:29:20 (9 years ago)
Author:
astephen
Message:

fixing up jobs page and moving renderer code into renderer package

Location:
cows_wps/trunk/cows_wps
Files:
1 added
7 edited

Legend:

Unmodified
Added
Removed
  • cows_wps/trunk/cows_wps/controllers/jobs.py

    r5968 r7095  
    1010from cows_wps.model.managers import requestManager 
    1111from cows_wps.process_handler.context.process_status import STATUS 
     12from cows_wps.process_handler.validate_arguments import parseDateTime 
    1213 
    1314log = logging.getLogger(__name__) 
    1415 
     16 
     17def checkValidJobStatus(status): 
     18    allowed_status_codes = [code for code in STATUS.__dict__.keys() if code[0] != "_"] 
     19    status = status.split("|") 
     20 
     21    for st in status: 
     22        if st not in allowed_status_codes: 
     23            return False 
     24 
     25    return status 
     26     
     27     
     28def checkValidJobType(jtype): 
     29    allowed_job_types = ["1", "2"] 
     30    job_types = jtype.split("|") 
     31 
     32    for jtype in job_types: 
     33        if jtype not in allowed_job_types: 
     34            return False 
     35 
     36    return job_types 
     37 
     38 
     39def checkValidOrderBy(order_by): 
     40    allowed = ["job_id", "user_id", "job_status", "job_type", "sub_time"] 
     41    new_allowed = [] 
     42 
     43    for i in allowed: 
     44        new_allowed.append("%s_rev" % i) 
     45 
     46    allowed.extend(new_allowed) 
     47 
     48    if order_by not in allowed: 
     49        return False 
     50 
     51    return order_by 
     52 
     53     
     54def toDateTime(tm): 
     55    try: 
     56        return parseDateTime(tm) 
     57    except: 
     58        return False 
     59    
     60 
    1561class JobsController(BaseController): 
    1662 
    17     def cancel(self): 
    18         """ 
    19         Cancel a job 
    20         """ 
    21         job_id = request.params.get("job_id", None) 
    22         if job_id == None: 
    23             return "Please provide an argument job_id=<Something>" 
    24  
    25         resp = "Nothing yet..." 
     63    job_item_order = {"job_id_match": 0, "user_id": 1, "job_status": 2, 
     64                      "job_type": 3, "sub_before": 4, "sub_after": 4, 
     65                      "job_id": 0, "sub_time": 4} 
     66 
     67    filter_types = {"job_id_match": "regex",  
     68                    "job_desc_match": "regex", 
     69            "job_type": "contains", 
     70            "job_status": "contains",             
     71            "sub_after": "time:after", 
     72            "sub_before": "time:before", 
     73            } 
     74    default_args = {"start": 0, 
     75                    "n_records": 20, 
     76            "job_desc_match": None, 
     77            "job_id_match": None, 
     78            "job_type": None, 
     79            "job_status": None, 
     80            "sub_before": None, 
     81            "sub_after": None, 
     82            "order_by": "sub_time"} 
     83    arg_processers = {"start": int, 
     84                    "n_records": int, 
     85            "job_desc_match": str, 
     86            "job_id_match": str, 
     87            "job_type": checkValidJobType, 
     88            "job_status": checkValidJobStatus, 
     89            "sub_before": toDateTime, 
     90            "sub_after": toDateTime, 
     91            "order_by": checkValidOrderBy} 
     92 
     93    def index(self): 
     94        (args, bad_args) = self._parseArgs() 
     95#        return str(args) 
     96        (filtered_jobs, total_matches) = apply(self._filterJobs, [], args) 
     97 
    2698        renderer = UIPageRenderer() 
    27         resp = renderer.render("Job cancellation page", 
    28                                [("Cancelling: %s" % job_id, resp)]) 
    29         return resp 
    30  
    31  
    32     def index(self): 
    33         """ 
    34         Reads jobs list and shows. 
    35         """ 
    36         requestManager.updateRunningRequests() 
    37  
    38         resp = '<table border="2"><tr><td>Job id</td><td>type</td><td>user</td><td>status</td></tr>\n' 
    39         for r in requestManager.getAllRequest(): 
    40             status = r.job.status 
    41             type = r.job.type 
    42             job_id = r.job.job_id 
    43             user = r.user_id 
    44             row = "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n" % (job_id, type, user, status) 
    45             resp += row 
    46  
    47         resp += "</table>"  
    48         renderer = UIPageRenderer() 
    49         resp = renderer.render("Job list page", 
    50                                [("All jobs", resp)]) 
    51         return resp 
     99        return renderer.renderJobsPage(filtered_jobs, total_matches, args, bad_args) 
     100     
     101     
     102    def _parseArgs(self): 
     103        args = {} 
     104        bad_args = {} 
     105     
     106        for (key, default) in self.default_args.items(): 
     107            value = None 
     108            if request.params.has_key(key): 
     109                value = str(request.params.getone(key)) 
     110             
     111                # If arg_check is False then bad input 
     112                arg_check = apply(self.arg_processers[key], [value]) 
     113                if arg_check == False: 
     114                    bad_args[key] = value 
     115                    value = default 
     116                else: 
     117                    value = arg_check 
     118            else: 
     119                value = default 
     120             
     121            args[key] = value 
     122             
     123        return (args, bad_args) 
     124     
     125 
     126    def _orderJobs(self, jobs, order_by): 
     127        reverse = False 
     128 
     129        if order_by.find("_rev") > -1: 
     130            order_by = order_by.replace("_rev", "") 
     131            reverse = True 
     132 
     133        indx = self.job_item_order[order_by]  
     134        tmp_jobs = [(job[indx], job[:]) for job in jobs] 
     135        tmp_jobs.sort() 
     136 
     137        if reverse: 
     138            tmp_jobs.reverse() 
     139          
     140        ordered_jobs = [i[1] for i in tmp_jobs] 
     141        return ordered_jobs 
     142     
     143     
     144    def _filterJobs(self, start, n_records, job_desc_match, job_id_match, 
     145                    job_type, job_status, sub_before, sub_after, order_by): 
     146        # Get all jobs at start 
     147        requests = requestManager.getAllRequest() 
     148        
     149        # Define jobs as tuple of (job_id, user, status, job_type, created)  
     150        # And convert all unicodes 
     151        jobs = [[str(i) for i in (r.job_id, r.user_id, r.job.status, r.job.type, r.job.created)] for r in requests] 
     152          
     153        for filtr in ("job_id_match", "job_type", "job_status", "sub_before", "sub_after"): 
     154            jobs = self._filterBy(jobs, filtr, filter_value = vars()[filtr]) 
     155        
     156        total_matches = len(jobs)         
     157        ordered_jobs = self._orderJobs(jobs, order_by)[start:(start + n_records)] 
     158        return (ordered_jobs, total_matches) 
     159     
     160     
     161    def _filterBy(self, jobs, filtr, filter_value): 
     162        # Represent jobs as lists of properties 
     163        if filter_value == None: 
     164            return jobs 
     165         
     166        indx = self.job_item_order[filtr] 
     167        test_param = None 
     168        filter_type = self.filter_types[filtr] 
     169        filtered_jobs = [] 
     170 
     171        for job in jobs: 
     172         
     173            item = job[indx] 
     174         
     175            if filter_type == "regex": 
     176                if not test_param: 
     177                    test_param = re.compile(filter_value) 
     178         
     179                if test_param.search(item): 
     180                    filtered_jobs.append(job) 
     181             
     182            elif filter_type.find("time:") == 0: 
     183                if not test_param: 
     184                    test_param = filter_value 
     185         
     186                when = filter_type.split(":")[1].strip() 
     187         
     188                if when == "after": 
     189                    if item > test_param: 
     190                        filtered_jobs.append(job) 
     191             
     192                elif when == "before": 
     193                    if item < test_param: 
     194                        filtered_jobs.append(job) 
     195             
     196            elif filter_type == "equality": 
     197                if filter_value == item: 
     198                    filtered_jobs.append(job) 
     199             
     200            elif filter_type == "contains": 
     201#                raise str(str(item) + str(filter_value)) 
     202                if item in filter_value: 
     203                    filtered_jobs.append(job) 
     204 
     205        return filtered_jobs 
     206 
  • cows_wps/trunk/cows_wps/controllers/submit.py

    r6976 r7095  
    77 
    88from cows_wps.renderer.ui_renderer import * 
     9from cows_wps.renderer.proc_config_renderer import * 
    910from cows_wps.controllers import * 
    1011from cows_wps.lib.ui.proc_config import * 
     
    104105            args[str(k)] = str(v)  
    105106 
    106         pc = ProcConfig() 
    107         proc_submission_form_html = pc.renderProcSubmissionForm(proc, args) 
    108         bbox_required = pc.bbox_arg_found 
     107#        pc = ProcConfig() 
     108        pcr = ProcConfigRenderer() 
     109        proc_submission_form_html = pcr.renderProcSubmissionForm(proc, args) 
     110        bbox_required = pcr.bbox_arg_found 
    109111        resp = proc_submission_form_html 
    110112 
  • cows_wps/trunk/cows_wps/controllers/view.py

    r6955 r7095  
    55 
    66from cows_wps.renderer.ui_renderer import * 
     7from cows_wps.renderer.proc_config_renderer import * 
    78from cows_wps.controllers import * 
    89from cows_wps.lib.ui.proc_config import * 
     
    1718        Shows a table of all procs. 
    1819        """ 
    19         pc = ProcConfig() 
    20         procs = pc.renderProcsViewTable() 
     20#        pc = ProcConfig() 
     21        pcr = ProcConfigRenderer() 
     22        resp = pcr.renderProcsViewTable() 
    2123 
    22         resp = "%s" % procs 
    2324        renderer = UIPageRenderer() 
    24         c.tester = "tester" 
     25#        c.tester = "tester" 
    2526        resp = renderer.render("View available processes", 
    2627                               [("Select your process", resp)]) 
     
    5960            return "Please provide an argument proc=&lt;Something&gt;" 
    6061 
    61         pc = ProcConfig()  
    62         proc_view_html = pc.renderProcConfig(proc) 
     62#        pc = ProcConfig()  
     63#        proc_view_html = pc.renderProcConfig(proc) 
     64        pcr = ProcConfigRenderer() 
     65        proc_view_html = pcr.renderProcConfig(proc) 
     66 
    6367        resp = "\n".join(proc_view_html) 
    6468 
  • cows_wps/trunk/cows_wps/lib/request.py

    r6949 r7095  
    136136        # need to run another query on the database for each request returned. 
    137137         
    138         #!TODO:There must be a better way of achiving this using sqlalchemy 
    139         s = sqlalchemy.sql.text("""SELECT r.id, r.user_id, r.job_id, j.process, j.process_dir, j.status, j.type, sj.sge_id, sj.sge_queue, sj.last_polled 
     138        s = sqlalchemy.sql.text("""SELECT r.id, r.user_id, r.job_id, j.process, j.process_dir, j.status, j.type, j.created, sj.sge_id, sj.sge_queue, sj.last_polled  
    140139                    FROM request as r 
    141140                    JOIN job as j ON r.job_id = j.job_id 
    142141                    LEFT JOIN sge_job as sj ON r.job_id = sj.job_id""") 
    143142         
    144         columns = ["id", "user_id", "job_id", "process", "process_dir", "status", "type", "sge_id", "sge_queue", "last_polled"] 
     143        columns = ["id", "user_id", "job_id", "process", "process_dir", "status", "type", "created", "sge_id", "sge_queue", "last_polled"] 
    145144         
    146145        conn = self.engine.connect() 
     
    170169            job.type = r['type'] 
    171170            job.job_id = r['job_id'] 
     171            job.created = r['created'] 
    172172             
    173173            req = Request(r['id'], r['user_id']) 
  • cows_wps/trunk/cows_wps/lib/ui/proc_config.py

    r7008 r7095  
    22import copy 
    33 
    4 from cows_wps.utils.create_process_config import createProcessConfig 
     4#from cows_wps.utils.create_process_config import createProcessConfig 
    55 
    66from cows_wps.lib.ui.proc_config_convertor import ProcConfigConvertor  
    77from cows_wps.utils.parse_capabilities_config import caps_config_dict 
    88 
    9 from cows_wps.renderer.form_renderer import FormRenderer 
     9#from cows_wps.renderer.form_renderer import FormRenderer 
    1010 
    1111log = logging.getLogger(__name__) 
     
    2424    def getProcList(self): 
    2525        proc_dict = {} 
    26         log.warn("%s"%caps_config_dict.keys()) 
     26        log.warn("%s" % caps_config_dict.keys()) 
    2727 
    2828        for proc_id in caps_config_dict["Identifiers"]: 
     
    3232        return proc_dict 
    3333 
    34     def renderProcConfig(self, proc): 
    35         pcc = ProcConfigConvertor() 
    36         proc_config = pcc.convertConfig(proc) 
    37         return self.renderProcessPage(proc_config) 
    38  
    39     def renderProcessPage(self, pc): 
    40         """ 
    41         Takes a dictionary representing the process config. 
    42         Returns a list of HTML components. 
    43         """ 
    44         resp = ["<div>"] 
    45  
    46         resp.extend( self.renderBlock("Process Information", pc["Process Information"]) ) 
    47  
    48         resp.extend( self.renderInputs(pc["Inputs"]) ) 
    49  
    50         resp.extend( self.renderBlock("Process Outputs", pc["Outputs"]) )  
    51         resp.append( "</div>\n" ) 
    52         return resp 
    53  
    54     def renderBlock(self, id, items): 
    55  
    56         resp = ["<div>"] 
    57         resp.append( "<H3>%s</H3>\n" % id ) 
    58  
    59         for k, v in items: 
    60                  
    61             resp.append( '<div style="width:200px;"><b>%s:</b></div><div style="position: relative; left:210px; top: -20px;">%s</div>\n' % (k, v) ) 
    62  
    63         resp.append("</div>\n") 
    64         return resp  
    65  
    66     def renderInputs(self, items): 
    67         resp = ["<div>\n<H3>Process Inputs</H3>"] 
    68         resp.append( '<table border="1" style="position: relative; left: 30px;">\n' ) 
    69  
    70         keys = ["Parameter name", "type", "item_type", "allowed_length", "possible_values"] 
    71         skeys = ["Parameter name", "Data type", "Is array?", "Permitted lengths", "Allowed values"] 
    72  
    73         resp.append("<tr>\n") 
    74         for (i, key) in enumerate(keys): 
    75             resp.append( '<td style="background:#FF9900"><b>%s</b></td>\n' % skeys[i] )  
    76  
    77         for (param_name, dct) in items:  
    78  
    79             resp.append( '<tr>\n<td style="background:#FFFFFF">%s</td>\n' % param_name ) 
    80  
    81             for key in keys[1:]: 
    82                  
    83                 value = dct[key] 
    84                 if key == "possible_values" and value != None: 
    85                     value = ", ".join(value) 
    86  
    87                 if value != None:  
    88                     resp.append( '<td style="background:#00FF00;">%s</td>\n' % value )  
    89                 else: 
    90                     resp.append( '<td style="background:red;">-</td>\n' ) 
    91  
    92             resp.append("</tr>\n") 
    93  
    94         resp.append("</table>\n") 
    95         resp.append("</div>\n") 
    96         return resp 
    97  
    98     def renderProcsViewTable(self): 
    99         """ 
    100         Renders the table of all procs on the view page. 
    101         """ 
    102         resp = """<table border="1">\n<tr>""" 
    103         headings = ("Process name", "Short description", "Full description", "Comments",  
    104                     "Options") 
    105         for heading in headings: 
    106             resp += """<td width="17%%" style="background:#FF9900"><b>%s</b></td>\n""" % heading   
    107         resp += "</tr>\n" 
    108  
    109         procs = self.getProcList() 
    110         for (proc, long_name) in procs.items(): 
    111             # Get config dict for this proc 
    112             proc_dict = createProcessConfig(proc)["Capabilities"]["globals"] 
    113  
    114             required_items = ("Title", "Abstract", "ProcessDescription")      
    115             resp += """<tr>\n<td style="background: #FFFFFF;">%s</td>\n""" % proc  
    116  
    117             for req_item in required_items: 
    118                 resp += """<td style="background: #FFFFFF;">%s</td>\n""" % proc_dict[req_item] 
    119  
    120             # Now add link to details and submit pages 
    121             resp += """<td style="background: #FFFFFF;"><a href="/submit/form?proc_id=%s">Submit job</a><br /> 
    122                            <a href="/view/proc?proc_id=%s">View full details</a></td>\n""" % (proc, proc) 
    123  
    124             resp += "</tr>\n" 
    125  
    126         resp += "</table>\n"  
    127         return resp 
    128  
    129     def renderProcSubmissionForm(self, proc, args): 
    130         """         
    131         Renders a submission form for a proc. 
    132         Populates items with args dictionary if they exist. 
    133         """ 
    134         pcc = ProcConfigConvertor() 
    135         proc_config = pcc.convertConfig(proc) 
    136         inputs = proc_config["Inputs"] 
    137  
    138         # Get form renderer 
    139         fm = FormRenderer() 
    140  
    141         resp = """Please complete the form below to submit a request to the CEDA Web Processing Service. 
    142                 Note that some processes are restricted to registered users only. 
    143                 Click the 'Submit' button to submit your request.<br><br>""" 
    144  
    145         resp += """\n\n <form action="/submit" onSubmit="return validateInputs();"> 
    146                 <input type="hidden" name="proc_id" id="proc_id" value="%s" /> 
    147                 <input type="hidden" id="_textarea_ids" name="_textarea_ids" value="" /> 
    148                 <table border="0">\n""" % proc 
    149  
    150         # Now render the inputs dict as a form 
    151         count = 0  
    152         for (name, input) in inputs: 
    153  
    154             # Set colour style for row 
    155             count += 1 
    156             row_style = ("even_row", "odd_row")[count % 2] 
    157  
    158             # Start HTML for row 
    159             resp += """<tr class="%s"><td width="25%%"><b>%s</b></td><td width="30%%">\n""" % (row_style, name) 
    160  
    161             # Parse arguments from config 
    162             al = input["allowed_length"] 
    163             pv = input["possible_values"] 
    164             default = input.get("default", None) 
    165             opt = input.get("optional", False) 
    166             array_or_item = input["item_type"] 
    167  
    168             multiple = False 
    169             if array_or_item == "list": 
    170                 multiple = True 
    171  
    172             tp = input["type"] 
    173  
    174             # Add a default instruction for this input type 
    175             instruction = "" 
    176             if opt == True: 
    177                 instruction = "This input is optional." 
    178             if multiple == True: 
    179                 instruction += " Multiple inputs are allowed." 
    180  
    181             # Now render them according to data type etc 
    182             if pv != None: 
    183                 resp += fm.renderSelectList(name, values=pv, optional=opt, multiple=multiple) 
    184                 n_items = "an item" 
    185                 if multiple == True: n_items = "one or more items" 
    186                 instruction += " Please select %s from the list." % n_items 
    187  
    188             elif tp == "bool": 
    189                 resp += fm.renderRadioButton(name, is_boolean=True) 
    190                 instruction += " Please select either true or false." 
    191              
    192             elif tp in ("float", "int", "string", "datetime"): 
    193                 if tp == "datetime": 
    194                     if args.has_key(name): 
    195                         # Use input arg sent in to form if received 
    196                         default = args[name] 
    197                     elif default: 
    198                         # Ensure time formatted correctly 
    199                         default = str(default).replace(" ", "T") 
    200          
    201                     instruction += " Please insert a date/time field in the format <kbd><B>YYYY-MM-DDThh:mm:ss</B></kbd> such as <kbd>2009-01-01T00:00:00</kbd>." 
    202                 else: 
    203                     # Use CGI arg if received 
    204                     if args.has_key(name): 
    205                         default = args[name] 
    206  
    207                     instruction += " Please insert a value of type: %s." % tp 
    208  
    209                 resp += fm.renderTextInput(name, dtype = tp, optional = opt, default = default, multiple = multiple) 
    210             
    211             elif tp == "filepath": 
    212                 base_dir = input["basedir"]  
    213                 resp += fm.renderTypeAheadDirList(name, base_dir) 
    214                 instruction += " Please type a file path on the CEDA file system. Click down to auto-fill with one of the options on the drop-down list." 
    215  
    216             elif tp == "bbox": 
    217                 self.bbox_arg_found = True 
    218                 extent = input.get("extent", False) 
    219                 resp += fm.renderBBox(name, extent) 
    220                 csv_extent = extent.replace("|", ", ") 
    221                 instruction += " Please select a valid bounding box with the following geographical extent: %s" % csv_extent  
    222  
    223             resp += "</td><td>%s</td></tr>\n" % instruction 
    224       
    225         count += 1 
    226         row_style = ("even_row", "odd_row")[count % 2]  
    227         resp += '<tr class="%s"><td></td><td colspan="2"><input type="submit" value="Submit" /> Click this button when you are happy with your selections.</td></table>\n</form>\n' % row_style 
    228         return  fm.htmlify(resp) 
  • cows_wps/trunk/cows_wps/process_handler/context/process_status.py

    r5615 r7095  
    33""" 
    44 
    5 # We could use Arif's Enum class here. 
    65class STATUS: 
    76    ACCEPTED = 'ACCEPTED' 
  • cows_wps/trunk/cows_wps/renderer/ui_renderer.py

    r6955 r7095  
    4545        return stream.render('xhtml') 
    4646 
     47 
     48    def renderJobsPage(self, jobs, total_matches, args, bad_args): 
     49        """ 
     50        Renders jobs page. 
     51        """ 
     52        rjobs = '<table border="2"><tr><td>Job id</td><td>Job type</td><td>User</td><td>Submission time</td><td>Job status</td></tr>\n' 
     53        for  (job_id, user, status, job_type, created) in jobs: 
     54            created = created.split(".")[0] 
     55            row = "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n" % (job_id, job_type, user, created, status) 
     56            rjobs += row 
     57 
     58        rjobs += "</table>" 
     59  
     60        items = [("Jobs Page", "This is where you can view jobs."), 
     61                 ("Warning bad args", str(bad_args)), 
     62                 ("Filtering Area", str(args)), 
     63                 ("Total Matches", str(total_matches)), 
     64                 ("Jobs", rjobs)]  #["<br>%s = %s" % (job[0], str(job)) for job in jobs])]  
     65 
     66        return self.render("Jobs Page", items) 
     67 
Note: See TracChangeset for help on using the changeset viewer.