statut visible dans les rss
[restcoda.git] / rest.wsgi
CommitLineData
1795efcd
TN
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3
4import sys, traceback
5
a6627284
TN
6# configuration (codes d'accès à la base MS-SQL)
7sys.path.append('/home/thomas/public_html/')
8import rest_config
9
0a4c31d4 10# pour savoir quel objet interroger : Routes
1795efcd 11from routes import Mapper
a6627284 12from routes.middleware import RoutesMiddleware
81b8aba3
TN
13# et analyse des paramètres (POST et query_string) pour filtrage
14from paste.request import parse_formvars
1795efcd 15
a6627284 16# pour chercher les données sur MS-SQL
1795efcd 17from pymssql import connect
a6627284
TN
18
19# pour afficher le résultat : jinja
1795efcd
TN
20from jinja import Environment, FileSystemLoader
21from jinja.filters import stringfilter
0ae81148 22import jinja.exceptions
1795efcd 23
0a4c31d4
TN
24# TODO systeme de cache : beaker
25# from beaker.middleware import CacheMiddleware
1795efcd 26
a6627284 27# formats de sortie autorisés, et content-type correspondant
d588d902
TN
28# formats = { 'xml': 'application/xml', 'html': 'text/html', 'txt': 'text/plain', 'json': 'application/json', 'rss': 'application/rss+xml' }
29formats = { 'xml': 'application/xml', 'html': 'text/html', 'txt': 'text/plain', 'json': 'text/plain', 'rss': 'application/rss+xml' }
1795efcd 30
0a4c31d4 31# les routes RESTful (cf http://routes.groovie.org/manual.html#restful-services)
1795efcd 32mapper = Mapper()
0a4c31d4
TN
33mapper.resource('demlog','demlog')
34mapper.resource('comlog','comlog')
35mapper.resource('demdep','demdep')
36mapper.resource('comdep','comdep')
37mapper.resource('dempub','dempub')
38mapper.resource('compub','compub')
0a4c31d4 39mapper.resource('comare','comare')
db1681c0
TN
40# pour les comarexxx où xxx est un code d'implantation
41mapper.resource('comarei','comare:(impl)',controller='comare')
0a4c31d4 42mapper.resource('comsra','comsre')
db1681c0 43mapper.resource('comsrai','comsre:(impl)',controller='comsre')
f6b772ed
TN
44mapper.resource('dem','dem')
45mapper.resource('com','com')
1795efcd
TN
46
47class objetsql(object):
0a4c31d4 48 """objet de base : dispose d'un accès à MS-SQL (lire les données) et d'un accès à jinja (rendu des données)"""
1795efcd 49 def __init__(self, environ):
1795efcd 50 self.environ = environ
0ae81148
TN
51 def template(self,template):
52 self.jinja = Environment(loader=FileSystemLoader('/home/thomas/public_html/'))
53 self.outputformat = self.environ['wsgiorg.routing_args'][1].get('format','xml')
54 return self.jinja.get_template('%s.%s' % (template,self.outputformat))
55 def cursor(self):
56 if not hasattr(self,'bd'):
57 self.bd = connect(host=rest_config.host,user=rest_config.user,password=rest_config.password,database=rest_config.database)
58 return self.bd.cursor()
a6627284 59
1795efcd 60class document(objetsql):
0a4c31d4 61 """objet document CODA (demlog, comlog, demdep... ils ont tous le même format)"""
1795efcd
TN
62 def __init__(self, environ, code_document='%', basename_template='document'):
63 super(document, self).__init__(environ)
64 self.code_document = code_document
65 self.basename_template = basename_template
66
0ae81148
TN
67 def _get_index(self, code):
68 """renvoie une liste de documents"""
69 # connexion a la base de données
70 cursor = self.cursor()
71 # extraction des données
72 cursor.execute("select top 15 * from auf_v_acces_demcom where code like '%s' order by date_modif desc" % code)
73 index = {}
74 index['code'] = code
75 items = []
1795efcd 76 while 1:
0ae81148
TN
77 item = dict_fetchone( cursor )
78 if item == None: break
79 item['code_rest'] = coda2rest(item['code'])
80 items.append(item)
81 index['documents'] = items
82 return index
83
84 def _get_details(self,code,id):
f2897cb3 85 """renvoie la liste des détails pour un document"""
1795efcd 86 details = []
0ae81148
TN
87 cursor = self.cursor()
88 cursor.execute("select * from auf_v_acces_dtls_demcom where code like '%s' and numero = %d" % (code, id))
1795efcd 89 while 1:
0ae81148 90 detail = dict_fetchone(cursor)
1795efcd
TN
91 if detail == None: break
92 details.append(detail)
0ae81148
TN
93 return details
94
95 def _get_document(self,code,id):
f2897cb3 96 """renvoie un document"""
0ae81148
TN
97 cursor = self.cursor()
98 cursor.execute("select top 1 * from auf_v_acces_demcom where code like '%s' and numero = %d" % (code, id))
99 document = dict_fetchone(cursor)
100 if document == None:
101 raise "document inexistant"
102 document['code_rest'] = coda2rest( document['code'] )
103 document['details'] = self._get_details( code,id )
104 return document
105
106 def index(self):
107 """renvoie une liste de documents formatée"""
62760773
TN
108 template = self.template('%s-index' % self.basename_template) # préparation du modèle
109 index = self._get_index( self.code_document ) # extraction des documents concernés
110 output = template.render( index ) # formattage via le modèle
0ae81148
TN
111 return self.outputformat, output
112
113 def show(self):
114 """renvoie un document formaté"""
115 # return 'txt', '%s' % self.environ # pour debug
116 id = int(self.environ['wsgiorg.routing_args'][1]['id'])
117 template = self.template( self.basename_template )
118 document = self._get_document( self.code_document, id )
119 output = template.render( document )
1795efcd
TN
120 return self.outputformat, output
121
f6b772ed
TN
122class dem(document):
123 def __init__(self, environ):
124 super(dem, self).__init__(environ, code_document = 'DEM-%')
125
126class com(document):
127 def __init__(self, environ):
128 super(com, self).__init__(environ, code_document = 'COM-%')
129
1795efcd
TN
130class demlog(document):
131 def __init__(self, environ):
132 super(demlog, self).__init__(environ, code_document = 'DEM-LOG-AUF')
133
134class comlog(document):
135 def __init__(self, environ):
136 super(comlog, self).__init__(environ, code_document = 'COM-LOG-AUF')
137
0a4c31d4
TN
138class demdep(document):
139 def __init__(self, environ):
140 super(demdep, self).__init__(environ, code_document = 'DEM-DEP-AUF')
141
142class comdep(document):
143 def __init__(self, environ):
144 super(comdep, self).__init__(environ, code_document = 'COM-DEP-AUF')
145
146class dempub(document):
147 def __init__(self, environ):
148 super(dempub, self).__init__(environ, code_document = 'DEM-PUB-AUF')
149
150class compub(document):
151 def __init__(self, environ):
152 super(compub, self).__init__(environ, code_document = 'COM-PUB-AUF')
153
0a4c31d4
TN
154class comsre(document):
155 def __init__(self, environ):
db1681c0
TN
156 # est-ce un appel de comsre ou comsrexxx (avec xxx = implantation)
157 impl = environ['wsgiorg.routing_args'][1].get('impl','%')
158 super(comsre, self).__init__(environ, code_document = 'COM-SRE-%s' % impl)
0a4c31d4
TN
159
160class comare(document):
161 def __init__(self, environ):
db1681c0
TN
162 impl = environ['wsgiorg.routing_args'][1].get('impl','%')
163 super(comare, self).__init__(environ, code_document = 'COM-ARE-%s' % impl)
0a4c31d4 164
0ae81148
TN
165#
166# fin des objets accessibles
167#
168
a6627284 169def dispatcher(environ, start_response):
81b8aba3
TN
170 """dispatch vers la bonne methode du bon objet, et retour WSGI"""
171 parse_formvars(environ)
a6627284 172 results = environ['wsgiorg.routing_args'][1]
1795efcd
TN
173 try:
174 target_class = globals()[results['controller']]
0ae81148
TN
175 method = getattr(target_class,results['action'])
176 except:
177 start_response("404 Not Found", [('Content-type', 'text/html')])
178 return '<html><body><h2>404 objet ou action invalide</h2><pre>%s: %s\n%s</pre></body></html>' % ( sys.exc_info()[0] , sys.exc_info()[1] , traceback.format_exc())
179 try:
1795efcd
TN
180 type, output = method(target_class(environ))
181 start_response("200 OK", [('Content-type', formats[type])])
182 return output.encode('utf-8')
0ae81148
TN
183 except jinja.exceptions.TemplateNotFound, template:
184 start_response("415 Unsupported Media Type", [('Content-type', 'text/html')])
185 return '<html><body><h2>415 format non supporté (%s inexistant)</h2></body></html>' % template
1795efcd 186 except:
0ae81148
TN
187 start_response("500 INTERNAL ERROR", [('Content-type', 'text/html')])
188 return '<html><body><h2>500 erreur lors du traitement</h2><pre>%s: %s\n%s</pre></body></html>' % ( sys.exc_info()[0] , sys.exc_info()[1] , traceback.format_exc())
1795efcd 189
81b8aba3 190# application qui sera lancée par mod_wsgi : on route et on dispatche
a6627284 191application = RoutesMiddleware( dispatcher, mapper)
0ae81148 192# TODO : ajouter un middleware de cache (beaker, basé sur REQUEST_URI quand la methode est GET)
1795efcd 193
0a4c31d4
TN
194
195#
196# petits utilitaires
197#
1795efcd
TN
198def dict_fetchone(cursor):
199 """Renvoie le resultat d'un fetchone dans un dictionnaire"""
200 result = cursor.fetchone()
201 if result == None: return None
202 result_dict = {}
203 for i in range(len(result)):
204 if isinstance( result[i], str ):
205 result_dict[cursor.description[i][0]] = result[i].decode('iso-8859-1')
206 else:
207 result_dict[cursor.description[i][0]] = result[i]
208 return result_dict
209
a6627284 210import re
db1681c0 211p = re.compile('(dem|com)-(...)-(...)',re.IGNORECASE)
a6627284 212def coda2rest(value):
db1681c0
TN
213 """Traduit un nom CODA vers la base REST correspodante,
214 par exemple DEM-LOG-AUF en demlog ou COM-ARE-VN3 en comarevn3"""
a6627284
TN
215 m = p.search(value)
216 if m == None: return value
db1681c0
TN
217 if m.group(3).lower() == 'auf':
218 return m.group(1).lower() + m.group(2).lower()
219 else:
220 return m.group(1).lower() + m.group(2).lower() + m.group(3).lower()
a6627284 221