summaryrefslogtreecommitdiff
path: root/ishtar_common/views_item.py
diff options
context:
space:
mode:
Diffstat (limited to 'ishtar_common/views_item.py')
-rw-r--r--ishtar_common/views_item.py182
1 files changed, 143 insertions, 39 deletions
diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py
index cde3f8d87..6f4abdee9 100644
--- a/ishtar_common/views_item.py
+++ b/ishtar_common/views_item.py
@@ -22,7 +22,8 @@ from django.db.models.fields import FieldDoesNotExist
from django.http import HttpResponse
from django.shortcuts import render
from django.template import loader
-from django.utils.translation import ugettext, ugettext_lazy as _
+from django.utils.translation import ugettext, ugettext_lazy as _, \
+ activate, deactivate, pgettext_lazy
from tidylib import tidy_document as tidy
from unidecode import unidecode
from weasyprint import HTML, CSS
@@ -65,17 +66,29 @@ CURRENT_ITEM_KEYS = (
CURRENT_ITEM_KEYS_DICT = dict(CURRENT_ITEM_KEYS)
+def get_autocomplete_query(request, label_attributes, extra=None):
+ q = request.GET.get('term') or ""
+ if not label_attributes:
+ return Q(pk__isnull=True)
+ query = Q()
+ if extra:
+ query = Q(**extra)
+ for q in q.split(' '):
+ if not q:
+ continue
+ sub_q = Q(**{label_attributes[0] + "__icontains": q})
+ for other_label in label_attributes[1:]:
+ sub_q = sub_q | Q(**{other_label + "__icontains": q})
+ query = query & sub_q
+ return query
+
+
def get_autocomplete_item(model, extra=None):
if not extra:
extra = {}
def func(request, current_right=None):
- q = request.GET.get('term') or ""
- query = Q(**extra)
- for q in q.split(' '):
- if not q:
- continue
- query = query & Q(cached_label__icontains=q)
+ query = get_autocomplete_query(request, ['cached_label'], extra=extra)
limit = 20
objects = model.objects.filter(query)[:limit]
data = json.dumps([{'id': obj.pk, 'value': obj.cached_label}
@@ -133,22 +146,25 @@ def display_item(model, extra_dct=None, show_url=None):
return func
-def show_item(model, name, extra_dct=None):
+def show_item(model, name, extra_dct=None, model_for_perms=None):
def func(request, pk, **dct):
- allowed, own = check_model_access_control(request, model)
+ check_model = model
+ if model_for_perms:
+ check_model = model_for_perms
+ allowed, own = check_model_access_control(request, check_model)
if not allowed:
return HttpResponse('', content_type="application/xhtml")
q = model.objects
if own:
if not hasattr(request.user, 'ishtaruser'):
- return HttpResponse('NOK')
+ return HttpResponse('')
query_own = model.get_query_owns(request.user.ishtaruser)
if query_own:
q = q.filter(query_own).distinct()
try:
item = q.get(pk=pk)
- except ObjectDoesNotExist:
- return HttpResponse('NOK')
+ except (ObjectDoesNotExist, ValueError):
+ return HttpResponse('')
doc_type = 'type' in dct and dct.pop('type')
url_name = u"/".join(reverse('show-' + name, args=['0', '']
).split('/')[:-2]) + u"/"
@@ -325,6 +341,12 @@ def _push_to_list(obj, current_group, depth):
current_group.append(obj)
+def is_true_string(val):
+ val = unicode(val).lower().replace(u'"', u"")
+ if val in (u"1", u"true", unicode(_(u"True")).lower()):
+ return True
+
+
def _parse_parentheses(s):
"""
Parse parentheses into list.
@@ -368,14 +390,31 @@ def _parse_query_string(string, request_keys, current_dct, exc_dct):
if excluded:
term = term[1:]
if term in request_keys:
- term = request_keys[term]
dct = current_dct
- if excluded:
- dct = exc_dct
- if term in dct:
- dct[term] += u";" + query
+ term = request_keys[term]
+ # callable request key for complex queries
+ if callable(term):
+ is_true = is_true_string(query)
+ if excluded:
+ is_true = not is_true
+ cfltr, cexclude, cextra = term(is_true=is_true)
+ if cfltr:
+ if 'and_reqs' not in dct:
+ dct['and_reqs'] = []
+ dct['and_reqs'].append(cfltr)
+ if cexclude:
+ if 'exc_and_reqs' not in dct:
+ dct['exc_and_reqs'] = []
+ dct['exc_and_reqs'].append(cexclude)
+ if cextra:
+ dct['extras'].append(cextra)
else:
- dct[term] = query
+ if excluded:
+ dct = exc_dct
+ if term in dct:
+ dct[term] += u";" + query
+ else:
+ dct[term] = query
return u""
for reserved_char in FORBIDDEN_CHAR:
string = string.replace(reserved_char, u"")
@@ -487,6 +526,8 @@ def _search_manage_search_vector(model, dct, exc_dct, request_keys):
search_query = \
search_query.replace(u'(', u'').replace(u')', u'').strip()
if search_query:
+ if 'extras' not in dct:
+ dct['extras'] = []
dct['extras'].append(
{'where': [model._meta.db_table +
".search_vector @@ (to_tsquery(%s, %s)) = true"],
@@ -526,13 +567,47 @@ def _manage_bool_fields(model, bool_fields, reversed_bool_fields, dct, or_reqs):
pass
+today_lbl = pgettext_lazy("key for text search", u"today"),
+TODAYS = ['today']
+
+for language_code, language_lbl in settings.LANGUAGES:
+ activate(language_code)
+ TODAYS.append(unicode(today_lbl))
+ deactivate()
+
+
def _manage_dated_fields(dated_fields, dct):
for k in dated_fields:
if k in dct:
if not dct[k]:
dct.pop(k)
+ continue
+ value = dct[k].replace('"', '').strip()
+ has_today = False
+ for today in TODAYS:
+ if value.startswith(today):
+ base_date = datetime.date.today()
+ value = value[len(today):].replace(' ', '')
+ if value and value[0] in (u"-", u"+"):
+ sign = value[0]
+ try:
+ days = int(value[1:])
+ except ValueError:
+ days = 0
+ if days:
+ if sign == u"-":
+ base_date = base_date - datetime.timedelta(
+ days=days)
+ else:
+ base_date = base_date + datetime.timedelta(
+ days=days)
+ dct[k] = base_date.strftime('%Y-%m-%d')
+ has_today = True
+ break
+ if has_today:
+ continue
try:
- items = dct[k].replace('"', '').split('/')
+ items = value.split('/')
assert len(items) == 3
dct[k] = virtualtime.datetime(*map(lambda x: int(x),
reversed(items))) \
@@ -795,7 +870,12 @@ def _construct_query(relation_types, dct, or_reqs, and_reqs):
query |= Q(**alt_dct)
query = _manage_relation_types(relation_types, dct, query, or_reqs)
+ done = []
for and_req in and_reqs:
+ str_q = unicode(and_req)
+ if str_q in done:
+ continue
+ done.append(str_q)
query = query & and_req
return query
@@ -880,11 +960,13 @@ DEFAULT_ROW_NUMBER = 10
EXCLUDED_FIELDS = ['length']
-def get_item(model, func_name, default_name, extra_request_keys=[],
- base_request=None, bool_fields=[], reversed_bool_fields=[],
- dated_fields=[], associated_models=[], relative_session_names=[],
- specific_perms=[], own_table_cols=None, relation_types_prefix={},
- do_not_deduplicate=False):
+def get_item(model, func_name, default_name, extra_request_keys=None,
+ base_request=None, bool_fields=None, reversed_bool_fields=None,
+ dated_fields=None, associated_models=None,
+ relative_session_names=None, specific_perms=None,
+ own_table_cols=None, relation_types_prefix=None,
+ do_not_deduplicate=False, model_for_perms=None,
+ alt_query_own=None):
"""
Generic treatment of tables
@@ -904,6 +986,8 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
:param do_not_deduplicate: duplication of id can occurs on large queryset a
mecanism of deduplication is used. But duplicate ids can be normal (for
instance for record_relations view).
+ :param model_for_perms: use another model to check permission
+ :param alt_query_own: name of alternate method to get query_own
:return:
"""
def func(request, data_type='json', full=False, force_own=False,
@@ -915,10 +999,15 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
if 'type' in dct:
data_type = dct.pop('type')
if not data_type:
- EMPTY = '[]'
data_type = 'json'
+ if data_type == "json":
+ EMPTY = '[]'
- allowed, own = check_model_access_control(request, model,
+ model_to_check = model
+ if model_for_perms:
+ model_to_check = model_for_perms
+
+ allowed, own = check_model_access_control(request, model_to_check,
available_perms)
if not allowed:
return HttpResponse(EMPTY, content_type='text/plain')
@@ -934,13 +1023,16 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
q = models.IshtarUser.objects.filter(user_ptr=request.user)
if not q.count():
return HttpResponse(EMPTY, content_type='text/plain')
- query_own = model.get_query_owns(q.all()[0])
+ if alt_query_own:
+ query_own = getattr(model, alt_query_own)(q.all()[0])
+ else:
+ query_own = model.get_query_owns(q.all()[0])
# get defaults from model
if not extra_request_keys and hasattr(model, 'EXTRA_REQUEST_KEYS'):
my_extra_request_keys = copy(model.EXTRA_REQUEST_KEYS)
else:
- my_extra_request_keys = copy(extra_request_keys)
+ my_extra_request_keys = copy(extra_request_keys or [])
if base_request is None and hasattr(model, 'BASE_REQUEST'):
if callable(model.BASE_REQUEST):
my_base_request = model.BASE_REQUEST(request)
@@ -953,32 +1045,35 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
if not bool_fields and hasattr(model, 'BOOL_FIELDS'):
my_bool_fields = model.BOOL_FIELDS[:]
else:
- my_bool_fields = bool_fields[:]
+ my_bool_fields = bool_fields[:] if bool_fields else []
if not reversed_bool_fields and hasattr(model, 'REVERSED_BOOL_FIELDS'):
my_reversed_bool_fields = model.REVERSED_BOOL_FIELDS[:]
else:
- my_reversed_bool_fields = reversed_bool_fields[:]
+ my_reversed_bool_fields = reversed_bool_fields[:] \
+ if reversed_bool_fields else []
if not dated_fields and hasattr(model, 'DATED_FIELDS'):
my_dated_fields = model.DATED_FIELDS[:]
else:
- my_dated_fields = dated_fields[:]
+ my_dated_fields = dated_fields[:] if dated_fields else []
if not associated_models and hasattr(model, 'ASSOCIATED_MODELS'):
my_associated_models = model.ASSOCIATED_MODELS[:]
else:
- my_associated_models = associated_models[:]
+ my_associated_models = associated_models[:] \
+ if associated_models else []
if not relative_session_names and hasattr(model,
'RELATIVE_SESSION_NAMES'):
my_relative_session_names = model.RELATIVE_SESSION_NAMES[:]
else:
- my_relative_session_names = relative_session_names[:]
+ my_relative_session_names = relative_session_names[:] \
+ if relative_session_names else []
if not relation_types_prefix and hasattr(model,
'RELATION_TYPES_PREFIX'):
my_relation_types_prefix = copy(model.RELATION_TYPES_PREFIX)
else:
- my_relation_types_prefix = copy(relation_types_prefix)
+ my_relation_types_prefix = copy(relation_types_prefix) \
+ if relation_types_prefix else {}
- fields = [model._meta.get_field(k)
- for k in get_all_field_names(model)]
+ fields = [model._meta.get_field(k) for k in get_all_field_names(model)]
request_keys = dict([
(field.name,
@@ -1039,6 +1134,7 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
excluded_dct = {}
and_reqs, or_reqs = [], []
exc_and_reqs, exc_or_reqs = [], []
+ dct['extras'], dct['and_reqs'], dct['exc_and_reqs'] = [], [], []
if full == 'shortcut':
if model.SLUG == "warehouse":
@@ -1057,7 +1153,10 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
if not val:
continue
req_keys = request_keys[k]
- if type(req_keys) not in (list, tuple):
+ if callable(req_keys):
+ # callable request key for complex queries not managed on GET
+ continue
+ elif type(req_keys) not in (list, tuple):
dct[req_keys] = val
continue
# multiple choice target
@@ -1080,7 +1179,6 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
else:
request.session[func_name] = dct
- dct['extras'] = []
dct, excluded_dct = _search_manage_search_vector(
model, dct, excluded_dct, request_keys)
search_vector = ""
@@ -1116,7 +1214,13 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
_manage_facet_search(model, dct, and_reqs)
_manage_facet_search(model, excluded_dct, exc_and_reqs)
- extras = dct.pop('extras')
+ extras = []
+ if 'extras' in dct:
+ extras = dct.pop('extras')
+ if 'and_reqs' in dct:
+ and_reqs += dct.pop('and_reqs')
+ if 'exc_and_reqs' in dct:
+ exc_and_reqs += dct.pop('exc_and_reqs')
_manage_clean_search_field(dct)
_manage_clean_search_field(excluded_dct)