Repository: ietf-tools/datatracker

Issue:
person_link error in charter document view
### What happened?

A 500 error occurs when retrieving some group charter documents. E.g., when getting `/doc/charter-ietf-cat/`:
```
ERROR: django.request:228: Internal Server Error: /doc/charter-ietf-cat/
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/workspace/ietf/doc/views_doc.py", line 548, in document_main
    can_manage=can_manage,
  File "/usr/local/lib/python3.6/site-packages/django/shortcuts.py", line 36, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader.py", line 62, in render_to_string
    return template.render(context, request)
  File "/usr/local/lib/python3.6/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 171, in render
    return self._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 163, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 937, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 904, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 150, in render
    return compiled_parent._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 163, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 937, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 904, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 62, in render
    result = block.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 937, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 904, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/defaulttags.py", line 312, in render
    return nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 937, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 904, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/library.py", line 214, in render
    _dict = self.func(*resolved_args, **resolved_kwargs)
  File "/workspace/ietf/person/templatetags/person_filters.py", line 44, in person_link
    plain_name = person.plain_name()
AttributeError: 'str' object has no attribute 'plain_name'
ERROR: django.request:228: Internal Server Error: /doc/charter-ietf-cat/
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/workspace/ietf/doc/views_doc.py", line 548, in document_main
    can_manage=can_manage,
  File "/usr/local/lib/python3.6/site-packages/django/shortcuts.py", line 36, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader.py", line 62, in render_to_string
    return template.render(context, request)
  File "/usr/local/lib/python3.6/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 171, in render
    return self._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 163, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 937, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 904, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 150, in render
    return compiled_parent._render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 163, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 937, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 904, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py", line 62, in render
    result = block.nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 937, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 904, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/defaulttags.py", line 312, in render
    return nodelist.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 937, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/base.py", line 904, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.6/site-packages/django/template/library.py", line 214, in render
    _dict = self.func(*resolved_args, **resolved_kwargs)
  File "/workspace/ietf/person/templatetags/person_filters.py", line 44, in person_link
    plain_name = person.plain_name()
AttributeError: 'str' object has no attribute 'plain_name'
```

### What browser(s) are you seeing the problem on?

Not Applicable

### Code of Conduct

- [X] I agree to follow the IETF's Code of Conduct


Discussion:
Happening on `{% person_link group.ad_role.person %}` for groups that have no such person. The tag is called with `person="** No value found for 'group.ad_role.person' **"`, which is `True` for the boolean checks in `person_link()`

Resolving patch:
diff --git a/ietf/person/templatetags/person_filters.py b/ietf/person/templatetags/person_filters.py
--- a/ietf/person/templatetags/person_filters.py
+++ b/ietf/person/templatetags/person_filters.py
@@ -37,10 +37,19 @@ def person_by_name(name):
 
 @register.inclusion_tag("person/person_link.html")
 def person_link(person, **kwargs):
+    """Render a link to a Person
+
+    If person is None or a string, renders as a span containing '(None)'.
+    """
+    if isinstance(person, str):
+        # If person is a string, most likely an invalid template variable was referenced.
+        # That normally comes in as an empty string, but may be non-empty if string_if_invalid
+        # is set. Translate strings into None to try to get consistent behavior.
+        person = None
     title = kwargs.get("title", "")
     cls = kwargs.get("class", "")
     with_email = kwargs.get("with_email", True)
-    if person:
+    if person is not None:
         plain_name = person.plain_name()
         name = (
             person.name


Test patch: