· 6 years ago · Oct 02, 2019, 07:38 PM
1# -*- coding: utf-8 -*-
2import datetime
3import json
4import logging
5
6import pytz
7from django.utils.translation import ugettext
8from jinja2 import Template as TemplateJinja, TemplateSyntaxError
9
10from core.models import ApiVersionMethod, Template
11from core.rest.renderers import UTF8JSONRenderer
12from settings import DEFAULT_ERROR_TEMPLATE
13
14logger = logging.getLogger(__name__)
15
16
17class Row(object):
18 def __init__(self, cells, aliases):
19 self.cells = cells
20 self.aliases = aliases
21 print 'self.cells ', self.cells
22
23 def __getattribute__(self, key):
24 try:
25 intKey = int(key)
26 value = object.__getattribute__(self, "cells")[intKey]
27 except:
28 index = object.__getattribute__(self, "aliases").get(key)
29 if index is None:
30 value = None
31 else:
32 value = object.__getattribute__(self, "cells")[index]
33 return value
34
35 def __setattr__(self, key, value):
36 object.__setattr__(self, key, value)
37 print 'entro!\n'
38
39 # def __str__(self):
40 # return self.__cells__
41
42 def __unicode__(self):
43 print 'unicode\n'
44 print 'cells ', self.cells
45 return self.cells
46
47 # def __iter__(self):
48 # self.iterator = iter(self._cells_)
49 # def _next_(self):
50 # return next(self.iterator)
51
52
53class MethodRenderer(UTF8JSONRenderer):
54 """
55 Class to renderize methods with jinja templates.
56 Output can be generated in any format defined in Template.
57 """
58
59 def render(self, data, media_type=None, renderer_context=None):
60 """
61 Renderiza response segun el template definido para el método.
62 """
63 response = renderer_context['response']
64 if response.exception:
65 return super(MethodRenderer, self).render(data, media_type, renderer_context)
66
67 # el template puede estar inyectado en la request (ej: en get_object de apim)
68 template_body = getattr(renderer_context['request'], 'template', None)
69
70 # el api method puede estar inyectado en la request (ej: en get_object de developers)
71 apimethod = getattr(renderer_context['request'], 'apimethod', None)
72
73 if data["fType"] == "ERROR" and apimethod:
74 template_obj = apimethod.templates.filter(
75 output_format=renderer_context['kwargs']['format'],
76 error_code=data["fNum"]).first()
77
78 if not template_obj: # si no existe template de error por numero, se busca el generico al metodo
79 template_obj = apimethod.templates.filter(
80 output_format=renderer_context['kwargs']['format'],
81 error_code=-1).first()
82
83 if not template_obj: # si no existe generico al metodo, se busca generico a la cuenta
84 # se excluyen genericos a la cuenta que esten relacionados a un metodo
85 excluded_templates = ApiVersionMethod.objects.filter(
86 account=renderer_context['request'].auth['account']).distinct().values_list('templates', flat=True)
87 excluded_templates = [int(item) for item in filter(None, excluded_templates)]
88
89 template_obj = Template.objects.exclude(id__in=excluded_templates).filter(
90 account=renderer_context['request'].auth['account'],
91 output_format=renderer_context['kwargs']['format'],
92 error_code=-2).first()
93
94 if not template_obj: # si no existe template de error generico, se busca el por defecto para la app
95 template_obj = type('obj', (object,), {'body': DEFAULT_ERROR_TEMPLATE})
96
97 template_body = template_obj.body
98
99 try:
100 data = self.format_data(data)
101 template = TemplateJinja(template_body)
102 output = template.render(result=data)
103 except (TemplateSyntaxError, TypeError) as e:
104 print '\n\n\nEXCEPT ', e
105 return ""
106
107 # nos aseguramos que la string sea json valido reconstruyo las barras escapadas en el output original
108 # output = output.replace('\\', '\\\\')
109 return output
110
111 def format_data(self, data):
112 """
113 Formatea los datos del motor a la estructura que espera el template
114 """
115 # 1) vamos a usar format="json"
116 # 2) vamos a devolver un array de arrays y no un array de dicionarios
117 # 3) vamos a sacar los headers del resultado y ponerlos en un array en headers
118 # 4) si el header esta definido en la vista, se agrega al array, si no, el array headers queda vacio
119 try:
120 new_data = {}
121 if "fCols" in data:
122 new_data["cols"] = data["fCols"]
123 # ver si hay que restar uno si hay headers
124 new_data["rows"] = data["fRows"]
125 new_data["length"] = data["fLength"]
126 new_data["timestamp"] = data["fTimestamp"]
127
128 headers = []
129 rows = []
130 cols = int(data["fCols"])
131 c = 0
132 row = []
133 alias = {}
134 # debe haber formas mas eficientes de hacer esto, pero no estoy seguro que los headers esten al principio...
135 for col in data['fArray']:
136 if 'fHeader' in col:
137 # puede haber otros tipos de datos? agregar aca
138 if col['fType'] == "TEXT":
139 value = col['fStr'].replace('\\', '\\\\').replace('"', '\\"')
140 headers.append(value)
141 else:
142 if col['fType'] == "TEXT":
143 value = col['fStr'].replace('\\', '\\\\').replace('"', '\\"')
144 elif col['fType'] == "NUMBER":
145 value = col['fNum']
146 elif col['fType'] == "LINK":
147 value = col['fStr']
148 elif col['fType'] == "DATE":
149 value = self.format_datetime(col['fNum'])
150 elif col['fType'] == "JSON":
151 value = json.loads(col['fStr'])
152 elif col['fType'] == "MISSING":
153 value = "-"
154 else:
155 value = ""
156
157 # si tiene alias los agrego como valores al diccionario.
158 if 'fAlias' in col:
159 alias[col['fAlias']] = c
160
161 row.append(value)
162 c = c + 1
163 if c >= cols:
164 c = 0
165
166 # a row lo transformo a dict, usando como key la posicion.
167 # row = {v: k for v, k in enumerate(row)}
168 # a row le agrego los elementos con alias, utilizando el alias como key.
169 # row.update(alias)
170
171 asd = Row(row, alias)
172 qws = asd
173 rows.append(asd)
174
175 alias = {}
176 row = []
177
178
179 new_data['headers'] = headers
180 new_data['data'] = rows
181
182 if "fFields" in data:
183 new_data['fields'] = {}
184 for (k, v) in data['fFields'].iteritems():
185 new_data['fields'][k] = v
186
187 else:
188 new_data['error_code'] = int(data["fNum"])
189 new_data['error_description'] = data["fStr"]
190 new_data['error_message'] = ugettext('API-UNEXPECTED-ERROR')
191
192 return new_data
193 except Exception as e:
194 print 'Exception ', e
195
196 def format_datetime(self, seconds):
197 # adaptado del metodo definido en core/v8/renderers
198 myutc = datetime.datetime.utcfromtimestamp(seconds / 1000).replace(tzinfo=pytz.utc)
199
200 return myutc
201
202
203class MethodRendererRaw(UTF8JSONRenderer):
204 def render(self, data, media_type=None, renderer_context=None):
205 response = renderer_context['response']
206 if response.exception:
207 return super(MethodRendererRaw, self).render(data, media_type, renderer_context)
208
209 template_body = getattr(renderer_context['request'], 'template', None)
210 apimethod = getattr(renderer_context['request'], 'apimethod', None)
211 if data["fType"] == "ERROR" and apimethod:
212 template_obj = apimethod.templates.filter(
213 output_format=renderer_context['kwargs']['format'],
214 error_code=data["fNum"]).first()
215
216 if not template_obj: # si no existe template de error por numero, se busca el generico al metodo
217 template_obj = apimethod.templates.filter(
218 output_format=renderer_context['kwargs']['format'],
219 error_code=-1).first()
220
221 if not template_obj: # si no existe generico al metodo, se busca generico a la cuenta
222 # se excluyen genericos a la cuenta que esten relacionados a un metodo
223 excluded_templates = ApiVersionMethod.objects.filter(
224 account=renderer_context['request'].auth['account']).distinct().values_list('templates', flat=True)
225 excluded_templates = [int(item) for item in filter(None, excluded_templates)]
226
227 template_obj = Template.objects.exclude(id__in=excluded_templates).filter(
228 account=renderer_context['request'].auth['account'],
229 output_format=renderer_context['kwargs']['format'],
230 error_code=-2).first()
231
232 if not template_obj: # si no existe template de error generico, se busca el por defecto para la app
233 template_obj = type('obj', (object,), {'body': DEFAULT_ERROR_TEMPLATE})
234
235 template_body = template_obj.body
236 try:
237 template = TemplateJinja(template_body)
238 output = template.render(result=data)
239 except (TemplateSyntaxError, TypeError) as e:
240 return ""
241 return output
242
243 def format_datetime(seconds):
244 # adaptado del metodo definido en core/v8/renderers
245 myutc = datetime.datetime.utcfromtimestamp(seconds / 1000).replace(tzinfo=pytz.utc)
246
247 return myutc