85 lines
3 KiB
Python
85 lines
3 KiB
Python
# Copyright The IETF Trust 2014-2020, All Rights Reserved
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
from __future__ import absolute_import, print_function, unicode_literals
|
|
|
|
import json
|
|
import six
|
|
|
|
from django.utils.html import escape
|
|
from django import forms
|
|
from django.urls import reverse as urlreverse
|
|
|
|
from ietf.liaisons.models import LiaisonStatement
|
|
|
|
def select2_id_liaison_json(objs):
|
|
return json.dumps([{ "id": o.pk, "text":"[{}] {}".format(o.pk, escape(o.title)) } for o in objs])
|
|
|
|
def select2_id_group_json(objs):
|
|
return json.dumps([{ "id": o.pk, "text": escape(o.acronym) } for o in objs])
|
|
|
|
class SearchableLiaisonStatementsField(forms.CharField):
|
|
"""Server-based multi-select field for choosing liaison statements using
|
|
select2.js."""
|
|
|
|
def __init__(self,
|
|
max_entries = None,
|
|
hint_text="Type in title to search for document",
|
|
model = LiaisonStatement,
|
|
*args, **kwargs):
|
|
kwargs["max_length"] = 10000
|
|
self.model = model
|
|
self.max_entries = max_entries
|
|
|
|
super(SearchableLiaisonStatementsField, self).__init__(*args, **kwargs)
|
|
|
|
self.widget.attrs["class"] = "select2-field form-control"
|
|
self.widget.attrs["data-placeholder"] = hint_text
|
|
if self.max_entries != None:
|
|
self.widget.attrs["data-max-entries"] = self.max_entries
|
|
|
|
def parse_select2_value(self, value):
|
|
return [x.strip() for x in value.split(",") if x.strip()]
|
|
|
|
def check_pks(self, pks):
|
|
for pk in pks:
|
|
if not pk.isdigit():
|
|
raise forms.ValidationError("Unexpected value: %s" % pk)
|
|
return pks
|
|
|
|
def prepare_value(self, value):
|
|
if not value:
|
|
value = ""
|
|
if isinstance(value, six.integer_types):
|
|
value = str(value)
|
|
if isinstance(value, six.string_types):
|
|
pks = self.parse_select2_value(value)
|
|
value = self.model.objects.filter(pk__in=pks)
|
|
if isinstance(value, LiaisonStatement):
|
|
value = [value]
|
|
|
|
self.widget.attrs["data-pre"] = select2_id_liaison_json(value)
|
|
|
|
# doing this in the constructor is difficult because the URL
|
|
# patterns may not have been fully constructed there yet
|
|
self.widget.attrs["data-ajax-url"] = urlreverse("ietf.liaisons.views.ajax_select2_search_liaison_statements")
|
|
|
|
return ",".join(str(o.pk) for o in value)
|
|
|
|
def clean(self, value):
|
|
value = super(SearchableLiaisonStatementsField, self).clean(value)
|
|
pks = self.check_pks(self.parse_select2_value(value))
|
|
|
|
objs = self.model.objects.filter(pk__in=pks)
|
|
|
|
found_pks = [str(o.pk) for o in objs]
|
|
failed_pks = [x for x in pks if x not in found_pks]
|
|
if failed_pks:
|
|
raise forms.ValidationError("Could not recognize the following groups: {pks}.".format(pks=", ".join(failed_pks)))
|
|
|
|
if self.max_entries != None and len(objs) > self.max_entries:
|
|
raise forms.ValidationError("You can select at most %s entries only." % self.max_entries)
|
|
|
|
return objs
|