source: geosplat/trunk/geosplat_source/for_cgi_bin/splatui.py @ 276

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/geosplat/trunk/geosplat_source/for_cgi_bin/splatui.py@276
Revision 276, 11.5 KB checked in by astephen, 16 years ago (diff)

* empty log message *

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/usr/local/cdat/bin/python
2 
3"""
4splatui.py
5==========
6
7Main module for the geosplat (GeoSpatial Plotting and
8Animation Tool) package.
9 
10This module holds the ControlVisualisation class used
11to control a user options and visualisation.
12
13""" 
14 
15# Import required modules
16import string 
17import sys
18import os 
19import time 
20import cgi 
21import commands 
22import urllib
23
24# Add your location path for the geosplat package
25BASEDIR="/usr/local/geosplat_demo"
26sys.path.append(os.path.split(BASEDIR)[0])
27 
28# Set home directory for use by CDAT
29USER_HOMEDIR="/home/badc"
30os.environ["HOME"]=USER_HOMEDIR 
31
32# Bring DataExtractor package into local scope
33from geosplat_demo import * 
34 
35# Add any other locally required directories in which you have modules.
36for path in LOCAL_PYTHONPATH:
37   sys.path.insert(0, path) 
38   
39# Set up cgi error reporting to screen if DEBUG is on
40if DEBUG==1:
41    import cgitb 
42    cgitb.enable() 
43 
44# Add the CDAT bin path to the PATH environment variable
45os.environ["PATH"]=os.environ["PATH"]+":"+CDAT_BIN_PATH
46           
47class ControlVisualisation:
48    """
49    Class to control the flow of the visualisation process in
50    geosplat.
51    """
52   
53    def __init__(self, args, callMethod):
54        """
55        Method to control the workflow of geosplat calling the relevant
56        methods and classes as required.
57        """ 
58        self.callMethod=callMethod
59        self.user=None 
60        self.allowed_groups=""
61        self.response=None 
62       
63        # Parse the arguments
64        try:
65            self._parseArgs(args)
66        except:
67            if DEBUG==1:
68                raise
69            else:
70                ErrorHandler("Error parsing arguments: "+str(sys.exc_value), noheader=0)
71
72        # If switched on check security       
73        if RESTRICTED_DATA==1:
74            try:
75                self._checkSecurity()
76            except:
77                if DEBUG==1:
78                    raise
79                else:
80                    ErrorHandler("Security error: "+str(sys.exc_value), noheader=0)
81        else:
82            self.user="anon"
83       
84        # Create the interface
85        try:
86            self._createInterface()   
87        except:
88            if DEBUG==1:
89                raise
90            else:
91                ErrorHandler("Error creating interface: "+str(sys.exc_value), noheader=0)
92               
93
94    def _parseArgs(self, args):
95        """
96        _parseArgs method - parses the argument dictionary that are sent.
97        """ 
98        if args==None: 
99            self.callMethod="CGI"
100            self.args={} 
101            form=cgi.FieldStorage() 
102
103            # Populate the argument dictionary
104            for key in form.keys(): 
105                self.args[key]=form.getvalue(key)     
106   
107    def _checkSecurity(self):
108        """
109        _checkSecurity method - checks security by getting username and
110        allowed groups from whatever implementation you have put in place.
111        """
112        sec=Security() 
113        if self.args.has_key("logout"): 
114            # logout
115            self.args={} 
116            sec.logout() 
117            allowed_groups=None 
118     
119        response=sec.getLoginStatus() 
120        if response: 
121            self.username=response[0] 
122            allowed_group_codes=response[1] 
123            self.allowed_groups=[]
124            for i in allowed_group_codes:
125                try:
126                    import grp
127                    group=grp.getgrgid(int(i))[0]
128                except:
129                    group=i
130                self.allowed_groups.append(group)
131
132                # Sort multiple group issue for ECMWFOP
133                if group[:7]=="ecmwfop": 
134                    for g in ("ecmwfop", "ecmwfop1", "ecmwfop2"): 
135                        if g not in self.allowed_groups:  self.allowed_groups.append(g)
136
137                # Sort the ERA40 and ERA15 merger groups
138                if group in ("era", "era4t", "ecmwfera"):
139                    for g in ("era", "era4t", "ecmwfera"):
140                        if g not in self.allowed_groups:  self.allowed_groups.append(g)
141                               
142                if type(self.allowed_groups)==str: 
143                    self.allowed_string=self.allowed_groups.replace(" ","") 
144                    allowed_as_list=allowed_string[1:-1].split(",") 
145                    cleaned_list=map(lambda x: x.replace("'", ""), allowed_as_list) 
146                    self.allowed_groups=cleaned_list
147                       
148                # local rule follows   
149                for key in ("_gohome",):   
150                    if self.args.has_key(key): del self.args[key]
151
152        else: 
153            raise "No response from Security class!"   
154           
155        if self.args.has_key("fileURI"):
156            try: 
157                (groupPermissions, userPermissions)=accountUtils.getFilePermission(args["fileURI"]) 
158            except: 
159                raise
160 
161            if not overlap(groupPermissions, allowed_groups) and username not in userPermissions: 
162                ErrorHandler("You are not authorised to view this data: %s" % args["fileURI"]) 
163        else: 
164            username="anon"
165        self.user=username     
166   
167    def _createInterface(self):
168        """
169        Method to generate a web page or visualisation as output.
170        """ 
171   
172        # Set up canvas as None for check later.
173        canvas=None
174
175        if self.args.has_key("fileURI") and self.args["fileURI"]!="": 
176            # Check if it is a file and it exists
177            if os.path.isdir(self.args["fileURI"]): 
178                ErrorHandler("You have provided a Directory path where a File path is required: %s" % self.args["fileURI"]) 
179            elif not os.path.isfile(self.args["fileURI"]): 
180                ErrorHandler("File not found: %s" % self.args["fileURI"]) 
181
182            # Prepare the output directory
183            outputDir=checkSubDirectory(self.user)
184 
185        # Begin writing page
186        print HTTP_HEADER
187        header=" ".join(open(os.path.join(BASEDIR, "html", "header.html")).readlines())
188        header=header.replace("PACKAGE_NAME", PACKAGE_NAME)
189        header=header.replace("LEFT_LOGO", os.path.join(LOGO_DIR, LEFT_LOGO))
190        header=header.replace("RIGHT_LOGO", os.path.join(LOGO_DIR, RIGHT_LOGO))
191        print header
192        print '<form action="%s" method="POST" onSubmit="update(\'type\');">' % CGI_NAME
193       
194        print '<A HREF="%s">Return to Start</A>&nbsp;|&nbsp;' % CGI_NAME
195 
196        self.showDataLink="no"
197        if self.args.has_key("fileURI"): 
198            print "<B>Data file:</B>   %s" % self.args["fileURI"]
199            httpFilePath=os.path.join(HTTP_OUTPUT_DIR, self.args["fileURI"].split(OUTPUT_DIR_DELIMITER)[-1])
200            testFileGetter=urllib.urlopen(httpFilePath)
201            if testFileGetter.read(10000).find("error")<0 and httpFilePath[0]!="/":
202                print """&nbsp;&nbsp;&nbsp;
203        <B>[ <A HREF="%s">Download</A> ]</B>""" % httpFilePath
204                self.showDataLink=httpFilePath
205        else: 
206            print '<B>Data file:</B>  <input type="text" name="fileURI" size="80">' 
207 
208        if self.args.has_key("fileURI") and self.args.has_key("fill_type"): 
209            fill_type=None 
210            if self.args.has_key("fill_type"): 
211                if self.args["fill_type"]=="Boxfill": 
212                    fill_type="Boxfill" 
213                elif self.args["fill_type"]=="Contour": 
214                    fill_type="Isofill" 
215 
216            if self.args.has_key("type"): 
217                print '<table width="100%" height="39"><tbody><tr class="tablerow"><td>' 
218                keymap={"Type":"Type", "Format":"Format", "fill_type":"Fill type", "Projection":"Projection", "size":"Dimensions"} 
219                for key in ("Type", "Format", "fill_type", "Projection", "size"):
220                    print "<BR>%s:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%s" % (keymap[key], self.args[key.lower()])
221                print '</td></tr></tbody></table>' 
222           
223                # Then do plot
224                print '<FONT FACE="Arial, Helvetica, sans-serif" SIZE="-1"><P><B>Plotting your data...</B><P>'
225                sys.stdout.flush()
226               
227                file=self.args["fileURI"] 
228               
229                # Open the data file
230                import cdms 
231                f=cdms.open(file) 
232                vars=f.variables.keys() 
233               
234                for var in vars: 
235                    if var[:7]!="bounds_" and var not in ("latitude", "longitude", "level", "time"): 
236                        varname=var
237                        break 
238                data=f(varname) 
239               
240                # Set up the VCS canvas
241                import vcs 
242                canvas=vcs.init() 
243 
244                # Work out output filename
245                (path, file)=os.path.split(self.args["fileURI"]) 
246                if file[:7]=="output_": 
247                    imageFile=file.split(".")[0] 
248                else: 
249                    pid=os.getpid() 
250                    imageFile="output_%s" % pid
251                   
252                outfile=os.path.join(outputDir, imageFile+"."+EXTMAP[self.args["format"]]) 
253                if os.path.isfile(outfile): os.unlink(outfile) 
254                wwwoutfile=os.path.join(HTTP_OUTPUT_DIR, self.user, "geosplat_output", os.path.split(outfile)[-1]) 
255       
256                # Redirect standard out to avoid splurging to screen
257                stdout=sys.stdout
258                sys.stdout=RedirectStdout()
259       
260                # It is a plot type so work out which
261                if self.args.has_key("projection"):
262                    projection=self.args["projection"]
263                else:
264                    projection="Standard"
265
266                PlotType=decidePlot(fill_type, projection)
267                # PlotType is now a class so create an instance with appropriate arguments
268                plotter=PlotType(canvas, data)     
269               
270                # Deal with animations appropriately...
271                if self.args["type"]=="Animation":
272                    animator=Animator(data, plotter, self.args["size"], outfile)
273                    animator.createAnimation() 
274                else: 
275                    plotter.createPlot()
276                    # Plot appropriate output format
277                    if self.args["format"]=="GIF": 
278                        canvas.gif(outfile, geometry=self.args["size"]) 
279                        # Brand output if GIF
280                        print "<P>Branding switched off for now...<P>"
281                        #stampPlot(outfile, args["size"])
282                    elif self.args["format"]=="Postscript": 
283                        canvas.postscript(outfile) 
284                    elif self.args["format"]=="CGM": 
285                        canvas.cgm(outfile) 
286 
287                # Get standard out back
288                sys.stdout=stdout
289                print "<P><B>Request processed...</B><P>" 
290 
291                if self.args["format"]=="GIF":   
292                    print """<IMG SRC="%s" BORDER="1">""" % wwwoutfile
293                    print '<P><FONT COLOR="GREEN">Note: the above %s may take some moments to appear in your browser.</FONT><P>' % self.args["type"].lower()
294 
295                print """<P><A HREF="%s">Click here to download %s in %s format</A>""" % (wwwoutfile, self.args["type"].lower(), self.args["format"]) 
296                # Work out if we can serve the data file to the user and if so, link to it.
297                #wwwdatafile=os.path.join(HTTP_OUTPUT_DIR,self.args["fileURI"].split(OUTPUT_DIR_DELIMITER)[-1])
298                if self.showDataLink!="no":
299                    print """<P><B><A HREF="%s">Click here to download data file.</A></B><P>""" % self.showDataLink
300 
301        else: 
302            print " ".join(open(os.path.join(BASEDIR, "html", "options.html")).readlines())
303            if self.args.has_key("fileURI"):  print '<input type="hidden" name="fileURI" value="%s">' % self.args["fileURI"] 
304            print """<p><input type="submit" value="Submit"><input type="reset" value="Reset"></p>
305   </form>
306</table>
307""" 
308            if canvas:
309                canvas.close()
310                del canvas
311               
312        print " ".join(open(os.path.join(BASEDIR, "html", "footer.html")).readlines())
313        # This line stops a vcs message appending to the web page.
314        sys.stdout=RedirectStdout()
315        return 
316   
317
318if __name__=="__main__": 
319    args={} 
320     
321    if len(sys.argv)>1:   # use command line args to test
322        for arg in sys.argv[1:]: 
323            (key, value)=arg.split("=") 
324            args[key]=value
325        callMethod="CommandLine"
326    else: 
327        args=None
328        callMethod="CGI"
329       
330    ControlVisualisation(args, callMethod) 
Note: See TracBrowser for help on using the repository browser.