Retrait fonctions specifiques au format csv

This commit is contained in:
Paul Marillonnet 2017-02-28 15:57:16 +01:00
parent 429cc1d5f5
commit f6664aede0
1 changed files with 168 additions and 195 deletions

View File

@ -1,11 +1,13 @@
from django.core.urlresolvers import reverse
from django.db import models
from django.utils.encoding import smart_text
#from django import forms
from passerelle.base.models import BaseResource
from passerelle.utils.jsonresponse import APIError
from passerelle.utils.api import endpoint
import sys
import jsonfield
from .utils import base
@ -28,14 +30,14 @@ def get_org_unit(u):
return 0
class LDAPResource(BaseResource):
ldif_file = models.FileField(_('LDIF File'), upload_to='ldif')
ldif_file = models.FileField('LDIF File', upload_to='ldif')
#columns_keynames = models.CharField(
# max_length=256,
# verbose_name=_('Column keynames'),
# default='id, text',
# help_text=_('ex: id,text,data1,data2'), blank=True)
#skip_header = models.BooleanField(_('Skip first line'), default=False)
_dialect_options = jsonfield.JSONField(editable=False, null=True)
_dialect_options = jsonfield.JSONField(editable=False, null=True) #FIXME
#sheet_name = models.CharField(_('Sheet name'), blank=True, max_length=150)
category = 'Identity Management Connectors'
@ -65,25 +67,23 @@ class LDAPResource(BaseResource):
return True
def clean(self, *args, **kwargs):
file_type = self.ldif_file.name.split('.')[-1]
#file_type = self.ldif_file.name.split('.')[-1]
#if file_type in ('ods', 'xls', 'xlsx') and not self.sheet_name:
# raise ValidationError(_('You must specify a sheet name'))
#return super(CsvDataSource, self).clean(*args, **kwargs)
return "TODO"
return super(LDAPResource, self).clean(*args, **kwargs)
def save(self, *args, **kwargs):
file_type = self.ldif_file.name.split('.')[-1]
#file_type = self.ldif_file.name.split('.')[-1]
#if file_type not in ('ods', 'xls', 'xlsx'):
# content = self.get_content_without_bom()
# dialect = csv.Sniffer().sniff(content)
# self.dialect_options = {
# k: v for k, v in vars(dialect).items() if not k.startswith('_')
# }
#return super(CsvDataSource, self).save(*args, **kwargs)
return "TODO"
return super(LDAPResource, self).save(*args, **kwargs)
@property
def dialect_options(self):
def dialect_options(self): #FIXME
"""turn dict items into string
"""
# Set dialect_options if None
@ -102,219 +102,192 @@ class LDAPResource(BaseResource):
def dialect_options(self, value):
self._dialect_options = value
def get_content_without_bom(self):
def get_content_without_bom(self): # Useless here ?
self.ldif_file.seek(0)
content = self.ldif_file.read()
return content.decode('utf-8-sig', 'ignore').encode('utf-8')
def get_rows(self):
#file_type = self.csv_file.name.split('.')[-1]
#if file_type not in ('ods', 'xls', 'xlsx'):
# content = self.get_content_without_bom()
# reader = csv.reader(content.splitlines(), **self.dialect_options)
# rows = list(reader)
#else:
# if file_type == 'ods':
# content = get_data_ods(self.csv_file)
# elif file_type == 'xls' or file_type == 'xlsx':
# content = get_data_xls(self.csv_file.path)
# if self.sheet_name not in content:
# return []
# rows = content[self.sheet_name]
#if not rows:
# return []
#if self.skip_header:
# rows = rows[1:]
#return [[smart_text(x) for x in y] for y in rows]
return "TODO"
def get_data(self, filters=None):
titles = [t.strip() for t in self.columns_keynames.split(',')]
indexes = [titles.index(t) for t in titles if t]
caption = [titles[i] for i in indexes]
#titles = [t.strip() for t in self.columns_keynames.split(',')] #FIXME
#indexes = [titles.index(t) for t in titles if t] #FIXME
#caption = [titles[i] for i in indexes] #FIXME
# validate filters (appropriate columns must exist)
if filters:
for filter_key in filters.keys():
if not filter_key.split(lookups.DELIMITER)[0] in titles:
del filters[filter_key]
## validate filters (appropriate columns must exist)
#if filters:
# for filter_key in filters.keys():
# if not filter_key.split(lookups.DELIMITER)[0] in titles:
# del filters[filter_key]
rows = self.get_rows()
#rows = self.get_rows()
data = []
#data = []
# build a generator of all filters
def filters_generator(filters, titles):
if not filters:
return
for key, value in filters.items():
try:
key, op = key.split(lookups.DELIMITER)
except (ValueError,):
op = 'eq'
## build a generator of all filters
#def filters_generator(filters, titles): #FIXME
# if not filters:
# return
# for key, value in filters.items():
# try:
# key, op = key.split(lookups.DELIMITER)
# except (ValueError,):
# op = 'eq'
index = titles.index(key)
# index = titles.index(key)
yield lookups.get_lookup(op, index, value)
# yield lookups.get_lookup(op, index, value)
# apply filters to data
def super_filter(filters, data):
for f in filters:
data = itertools.ifilter(f, data)
return data
## apply filters to data #FIXME
#def super_filter(filters, data):
# for f in filters:
# data = itertools.ifilter(f, data)
# return data
matches = super_filter(
filters_generator(filters, titles), rows
)
#matches = super_filter(
# filters_generator(filters, titles), rows
#)
for row in matches:
line = []
for i in indexes:
try:
line.append(row[i])
except IndexError:
line.append('')
#for row in matches:
# line = []
# for i in indexes:
# try:
# line.append(row[i])
# except IndexError:
# line.append('')
data.append(dict(zip(caption, line)))
# data.append(dict(zip(caption, line)))
return data
#return data
return 0
@property
def titles(self):
return [smart_text(t.strip()) for t in self.columns_keynames.split(',')]
#@property
#def titles(self): #FIXME
# return [smart_text(t.strip()) for t in self.columns_keynames.split(',')]
@endpoint('json-api', perm='can_access', methods=['get'],
name='query', pattern='^(?P<query_name>[\w-]+)/$')
def select(self, request, query_name, **kwargs):
try:
query = Query.objects.get(resource=self.id, slug=query_name)
except Query.DoesNotExist:
raise APIError(u'no such query')
#@endpoint('json-api', perm='can_access', methods=['get'],
# name='query', pattern='^(?P<query_name>[\w-]+)/$')
#def select(self, request, query_name, **kwargs):
# try:
# query = Query.objects.get(resource=self.id, slug=query_name)
# except Query.DoesNotExist:
# raise APIError(u'no such query')
titles = self.titles
rows = self.get_rows()
data = [dict(zip(titles, line)) for line in rows]
# titles = self.titles
# rows = self.get_rows()
# data = [dict(zip(titles, line)) for line in rows]
def stream_expressions(expressions, data, kind, titles=None):
codes = []
for i, expr in enumerate(expressions):
try:
code = get_code(expr)
except (TypeError, SyntaxError) as e:
data = {
'expr': expr,
'error': unicode(e)
}
if titles:
data['name'] = titles[i]
else:
data['idx'] = i
raise APIError(u'invalid %s expression' % kind, data=data)
codes.append((code, expr))
for row in data:
new_row = []
row_vars = dict(row)
row_vars['query'] = kwargs
for i, (code, expr) in enumerate(codes):
try:
result = eval(code, {}, row_vars)
except Exception as e:
data = {
'expr': expr,
'row': repr(row),
}
if titles:
data['name'] = titles[i]
else:
data['idx'] = i
raise APIError(u'invalid %s expression' % kind, data=data)
new_row.append(result)
yield new_row, row
# def stream_expressions(expressions, data, kind, titles=None):
# codes = []
# for i, expr in enumerate(expressions):
# try:
# code = get_code(expr)
# except (TypeError, SyntaxError) as e:
# data = {
# 'expr': expr,
# 'error': unicode(e)
# }
# if titles:
# data['name'] = titles[i]
# else:
# data['idx'] = i
# raise APIError(u'invalid %s expression' % kind, data=data)
# codes.append((code, expr))
# for row in data:
# new_row = []
# row_vars = dict(row)
# row_vars['query'] = kwargs
# for i, (code, expr) in enumerate(codes):
# try:
# result = eval(code, {}, row_vars)
# except Exception as e:
# data = {
# 'expr': expr,
# 'row': repr(row),
# }
# if titles:
# data['name'] = titles[i]
# else:
# data['idx'] = i
# raise APIError(u'invalid %s expression' % kind, data=data)
# new_row.append(result)
# yield new_row, row
filters = query.get_list('filters')
# filters = query.get_list('filters')
if filters:
data = [row for new_row, row in stream_expressions(filters, data, kind='filters')
if all(new_row)]
# if filters:
# data = [row for new_row, row in stream_expressions(filters, data, kind='filters')
# if all(new_row)]
order = query.get_list('order')
if order:
generator = stream_expressions(order, data, kind='order')
new_data = [(tuple(new_row), row) for new_row, row in generator]
new_data.sort(key=lambda (k, row): k)
data = [row for key, row in new_data]
# order = query.get_list('order')
# if order:
# generator = stream_expressions(order, data, kind='order')
# new_data = [(tuple(new_row), row) for new_row, row in generator]
# new_data.sort(key=lambda (k, row): k)
# data = [row for key, row in new_data]
distinct = query.get_list('distinct')
if distinct:
generator = stream_expressions(distinct, data, kind='distinct')
seen = set()
new_data = []
for new_row, row in generator:
new_row = tuple(new_row)
try:
hash(new_row)
except TypeError:
raise APIError(u'distinct value is unhashable',
data={
'row': repr(row),
'distinct': repr(new_row),
})
if new_row in seen:
continue
new_data.append(row)
seen.add(new_row)
data = new_data
# distinct = query.get_list('distinct')
# if distinct:
# generator = stream_expressions(distinct, data, kind='distinct')
# seen = set()
# new_data = []
# for new_row, row in generator:
# new_row = tuple(new_row)
# try:
# hash(new_row)
# except TypeError:
# raise APIError(u'distinct value is unhashable',
# data={
# 'row': repr(row),
# 'distinct': repr(new_row),
# })
# if new_row in seen:
# continue
# new_data.append(row)
# seen.add(new_row)
# data = new_data
projection = query.get_list('projections')
if projection:
expressions = []
titles = []
for mapping in projection:
name, expr = mapping.split(':', 1)
if not identifier_re.match(name):
raise APIError(u'invalid projection name', data=name)
titles.append(name)
expressions.append(expr)
new_data = []
for new_row, row in stream_expressions(expressions, data, kind='projection',
titles=titles):
new_data.append(dict(zip(titles, new_row)))
data = new_data
# projection = query.get_list('projections')
# if projection:
# expressions = []
# titles = []
# for mapping in projection:
# name, expr = mapping.split(':', 1)
# if not identifier_re.match(name):
# raise APIError(u'invalid projection name', data=name)
# titles.append(name)
# expressions.append(expr)
# new_data = []
# for new_row, row in stream_expressions(expressions, data, kind='projection',
# titles=titles):
# new_data.append(dict(zip(titles, new_row)))
# data = new_data
# allow jsonp queries by select2
# filtering is done there afater projection because we need a projection named text for
# retro-compatibility with previous use of the csvdatasource with select2
if 'q' in request.GET:
if 'case-insensitive' in request.GET:
filters = ["query['q'].lower() in text.lower()"]
else:
filters = ["query['q'] in text"]
data = [row for new_row, row in stream_expressions(filters, data, kind='filters')
if new_row[0]]
# # allow jsonp queries by select2
# # filtering is done there afater projection because we need a projection named text for
# # retro-compatibility with previous use of the csvdatasource with select2
# if 'q' in request.GET:
# if 'case-insensitive' in request.GET:
# filters = ["query['q'].lower() in text.lower()"]
# else:
# filters = ["query['q'] in text"]
# data = [row for new_row, row in stream_expressions(filters, data, kind='filters')
# if new_row[0]]
if query.structure == 'array':
return [[row[t] for t in titles] for row in data]
elif query.structure == 'dict':
return data
elif query.structure == 'tuples':
return [[[t, row[t]] for t in titles] for row in data]
elif query.structure == 'onerow':
if len(data) != 1:
raise APIError('more or less than one row', data=data)
return data[0]
elif query.structure == 'one':
if len(data) != 1:
raise APIError('more or less than one row', data=data)
if len(data[0]) != 1:
raise APIError('more or less than one column', data=data)
return data[0].values()[0]
# if query.structure == 'array':
# return [[row[t] for t in titles] for row in data]
# elif query.structure == 'dict':
# return data
# elif query.structure == 'tuples':
# return [[[t, row[t]] for t in titles] for row in data]
# elif query.structure == 'onerow':
# if len(data) != 1:
# raise APIError('more or less than one row', data=data)
# return data[0]
# elif query.structure == 'one':
# if len(data) != 1:
# raise APIError('more or less than one row', data=data)
# if len(data[0]) != 1:
# raise APIError('more or less than one column', data=data)
# return data[0].values()[0]
class Query(models.Model):
resource = models.ForeignKey('LDAPResource')