9434b97d21518fb3bf43b329c0d277be37d8e1cb
[restcoda.git] / objet.py
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 #
5 # Un "Objet" dispose de tout ce qui est nécessaire pour extraire
6 # les données (accès au MS-SQL) et pour en faire le rendu final
7 # (accès au système de template)
8 #
9 # Il analyse également l'environnement WSGI afin d'en extraire
10 # les données de filtrage (extrait des arguments de l'URL, après le ?)
11 # et de les transformer en critères SQL (where, limit, order)
12
13 # l'accès à MS-SQL
14 from pymssql import connect
15
16 # le système de template
17 from jinja import Environment, FileSystemLoader
18 ejinja = Environment(loader=FileSystemLoader('/home/thomas/public_html/modeles/'))
19
20 # le système d'analyse des variables HTTP
21 from paste.request import parse_formvars
22
23 # accès à la configuration (données pour la connexion MS-SQL)
24 import sys
25 sys.path.append('/home/thomas/public_html/')
26 import rest_config
27
28 # dates bien affichées dans jinja : filtre date
29 import locale
30 from datetime import datetime
31 def do_joliedate():
32 def wrapped(env, context, value):
33 if isinstance(value, datetime):
34 locale.setlocale(locale.LC_ALL,'fr_FR.UTF-8')
35 if (value.hour + value.minute + value.second) > 0:
36 return value.strftime('%A %d %B %Y, %Hh%Mmin')
37 else:
38 return value.strftime('%A %d %B %Y')
39 else:
40 return value
41 return wrapped
42 ejinja.filters['joliedate'] = do_joliedate
43
44 class Objet(object):
45 """Objet de base : dispose d'un accès à MS-SQL (lire les données) et d'un accès à jinja (rendu des données)"""
46
47 def __init__(self, environ):
48 """Conserve l'environnement WSGI et traduction des variables HTTP (filtres) en SQL"""
49 self.environ = environ
50 parse_formvars(environ) # extraction des variables de query_string et POST
51 self.filters = environ['paste.parsed_formvars'][0].dict_of_lists() # puis traduction en dictionnaire {var1:[val1,val2], ...}
52 # filtrage : on extrait la liste des filtres "acceptes" pour en faire des where
53 sqlwhere = []
54 if hasattr(self,'accept_like_filters'):
55 for filter in self.accept_like_filters:
56 if filter in self.filters:
57 or_list = []
58 for v in self.filters[filter]:
59 or_list.append("%s like '%s'" % (filter,v.replace('*','%')))
60 sqlwhere.append('(' + ' or '.join(or_list) + ')')
61 # TODO : ajouter ici filtres min_*/max_*, avant/apres
62 self.sqlwhere = ' and '.join(sqlwhere)
63 # filtrage : valeur en cas de limite ("top n" en ODBC), 200 maxi
64 if 'limite' in self.filters:
65 self.sqllimit = min( int(self.filters['limite'][0]), 200 )
66 else:
67 self.sqllimit = 30
68 # TODO : ajouter filtres tri_asc/tri_desc
69 self.sqlorder = ''
70
71 def template(self,template):
72 """Retourne un environnement de rendu"""
73 self.outputformat = self.environ['wsgiorg.routing_args'][1].get('format','xml')
74 if not self.outputformat == 'debug':
75 modele = '%s.%s' % (template,self.outputformat)
76 else:
77 modele = 'debug'
78 return ejinja.get_template( modele )
79
80 def cursor(self):
81 """Retourne un curseur vers la base de données"""
82 if not hasattr(self,'db_connect'):
83 self.db_connect = connect(host=rest_config.host,user=rest_config.user,password=rest_config.password,database=rest_config.database)
84 if not hasattr(self,'db_cursor'):
85 self.db_cursor = self.db_connect.cursor()
86 return self.db_cursor
87
88 def __del__(self):
89 """Destructeur : coupe la connexion à MSSQL à la mort de l'objet"""
90 # (normalement ça se fait tout seul mais j'en suis pas sûr sûr)
91 if hasattr(self,'db_connect'):
92 db_connect.close()
93
94 # exception levée quand une requete SQL ne revoit rien
95 class ObjetInconnu(Exception):
96 def __init__(self, type):
97 self.type = type
98 def __str__(self):
99 return self.type
100