We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
track users' full email domain
**Describe the feature you'd like and what it will do**
In HS v2.5.4, we don't track full user email domain in our metrics.


**Why is this feature important?**
We need more insight into how HS' ecosystem of tools are being used. This information should drive our continued development on existing tools and our consideration of additions for future use.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `hs_tracking/middleware.py`
Content:
```
1 from django.utils.deprecation import MiddlewareMixin
2 
3 from .models import Session
4 from . import utils
5 import re
6 
7 RESOURCE_RE = re.compile('resource/([0-9a-f]{32})/')  # parser for resource id
8 BAG_RE = re.compile('bags/([0-9a-f]{32})\.zip')  # parser for resource id # noqa
9 LANDING_RE = re.compile('resource/([0-9a-f]{32})/$')  # reference to resource home page
10 REST_RE = re.compile('/hsapi/')  # reference to REST or internal
11 INTERNAL_RE = re.compile('/hsapi/_internal/')  # reference to an internal page
12 
13 
14 def get_resource_id_from_url(path):
15     """ read a resource id from a URL """
16     m = RESOURCE_RE.search(path)
17     if m and m.group(1):
18         return m.group(1)
19     m = BAG_RE.search(path)
20     if m and m.group(1):
21         return m.group(1)
22     return None
23 
24 
25 def get_rest_from_url(path):
26     """ determine whether a URL is a REST call or not
27 
28         This should always return boolean, not search result.
29     """
30     if REST_RE.search(path):
31         if INTERNAL_RE.search(path):
32             return False
33         else:
34             return True
35     else:
36         return False
37 
38 
39 def get_landing_from_url(path):
40     """ determine whether a URL is a landing page.
41 
42         This should always return boolean, not search result.
43     """
44     if LANDING_RE.search(path):
45         return True
46     else:
47         return False
48 
49 
50 class Tracking(MiddlewareMixin):
51     """The default tracking middleware logs all successful responses as a 'visit' variable with
52     the URL path as its value."""
53 
54     def process_response(self, request, response):
55 
56         # filter out heartbeat messages
57         if request.path.startswith('/heartbeat/'):
58             return response
59 
60         # filter out web crawlers
61         is_human = getattr(request, 'is_human', False)
62         if not is_human:
63             return response
64 
65         # filter out everything that is not an OK response
66         if response.status_code != 200:
67             return response
68 
69         if not hasattr(request, 'user'):
70             return response
71 
72         # get user info that will be recorded in the visit log
73         session = Session.objects.for_request(request)
74         usertype = utils.get_user_type(session)
75         emaildomain = utils.get_user_email_domain(session)
76         ip = utils.get_client_ip(request)
77 
78         # build the message string (key:value pairs)
79         msg = '|'.join([str(item) for item in
80                         ['user_ip=%s' % ip,
81                          'http_method=%s' % request.method,
82                          'http_code=%s' % response.status_code,
83                          'user_type=%s' % usertype,
84                          'user_email_domain=%s' % emaildomain,
85                          'request_url=%s' % request.path]])
86 
87         resource_id = get_resource_id_from_url(request.path)
88         rest = get_rest_from_url(request.path)
89         landing = get_landing_from_url(request.path)
90 
91         # save the activity in the database
92         session.record('visit', value=msg, resource_id=resource_id,
93                        landing=landing, rest=rest)
94 
95         return response
96
```

Path: `hs_tracking/utils.py`
Content:
```
1 import robot_detection
2 from ipware.ip import get_ip
3 from hs_tools_resource.models import RequestUrlBase, RequestUrlBaseAggregation, RequestUrlBaseFile
4 from urllib.parse import urlparse
5 
6 
7 def get_client_ip(request):
8     return get_ip(request)
9 
10 
11 def get_user_type(session):
12     try:
13         user = session.visitor.user
14         usertype = user.userprofile.user_type
15     except AttributeError:
16         usertype = None
17     return usertype
18 
19 
20 def get_user_email_domain(session):
21     try:
22         user = session.visitor.user
23         emaildomain = user.email.split('@')[-1]
24         shortdomain = '.'.join(emaildomain.split('.')[1:])
25     except AttributeError:
26         shortdomain = None
27     return shortdomain
28 
29 
30 def is_human(user_agent):
31     if robot_detection.is_robot(user_agent):
32         return False
33     return True
34 
35 
36 def get_std_log_fields(request, session=None):
37     """ returns a standard set of metadata that to each receiver function.
38     This ensures that all activities are reporting a consistent set of metrics
39     """
40     user_type = None
41     user_email = None
42     if session is not None:
43         user_type = get_user_type(session)
44         user_email = get_user_email_domain(session)
45 
46     return {
47         'user_ip': get_client_ip(request),
48         'user_type': user_type,
49         'user_email_domain': user_email,
50     }
51 
52 
53 def authentic_redirect_url(url):
54     """ Validates a url scheme and netloc is in an existing web app
55     :param url: String of a url
56     :return: Boolean, True if the url exists in a web app
57     """
58     if not url:
59         return False
60     u = urlparse(url)
61     url_base = "{}://{}".format(u.scheme, u.netloc)
62     return RequestUrlBase.objects.filter(value__startswith=url_base).exists() \
63         or RequestUrlBaseAggregation.objects.filter(value__startswith=url_base).exists() \
64         or RequestUrlBaseFile.objects.filter(value__startswith=url_base).exists()
65
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/hs_tracking/middleware.py b/hs_tracking/middleware.py
--- a/hs_tracking/middleware.py
+++ b/hs_tracking/middleware.py
@@ -72,7 +72,7 @@
         # get user info that will be recorded in the visit log
         session = Session.objects.for_request(request)
         usertype = utils.get_user_type(session)
-        emaildomain = utils.get_user_email_domain(session)
+        email_tld = utils.get_user_email_tld(session)
         ip = utils.get_client_ip(request)
 
         # build the message string (key:value pairs)
@@ -81,7 +81,7 @@
                          'http_method=%s' % request.method,
                          'http_code=%s' % response.status_code,
                          'user_type=%s' % usertype,
-                         'user_email_domain=%s' % emaildomain,
+                         'user_email_domain=%s' % email_tld,
                          'request_url=%s' % request.path]])
 
         resource_id = get_resource_id_from_url(request.path)
diff --git a/hs_tracking/utils.py b/hs_tracking/utils.py
--- a/hs_tracking/utils.py
+++ b/hs_tracking/utils.py
@@ -21,10 +21,20 @@
     try:
         user = session.visitor.user
         emaildomain = user.email.split('@')[-1]
-        shortdomain = '.'.join(emaildomain.split('.')[1:])
     except AttributeError:
-        shortdomain = None
-    return shortdomain
+        emaildomain = None
+    return emaildomain
+
+
+def get_user_email_tld(session, emaildomain=None):
+    try:
+        if not emaildomain:
+            emaildomain = get_user_email_domain(session)
+        if emaildomain:
+            shortdomain = '.'.join(emaildomain.split('.')[1:])
+            return shortdomain
+    except AttributeError:
+        return None
 
 
 def is_human(user_agent):
@@ -38,15 +48,18 @@
     This ensures that all activities are reporting a consistent set of metrics
     """
     user_type = None
-    user_email = None
+    user_email_tld = None
+    full_domain = None
     if session is not None:
         user_type = get_user_type(session)
-        user_email = get_user_email_domain(session)
+        full_domain = get_user_email_domain(session)
+        user_email_tld = get_user_email_tld(session, full_domain)
 
     return {
         'user_ip': get_client_ip(request),
         'user_type': user_type,
-        'user_email_domain': user_email,
+        'user_email_domain': user_email_tld,
+        'user_email_domain_full': full_domain
     }

{"golden_diff": "diff --git a/hs_tracking/middleware.py b/hs_tracking/middleware.py\n--- a/hs_tracking/middleware.py\n+++ b/hs_tracking/middleware.py\n@@ -72,7 +72,7 @@\n         # get user info that will be recorded in the visit log\n         session = Session.objects.for_request(request)\n         usertype = utils.get_user_type(session)\n-        emaildomain = utils.get_user_email_domain(session)\n+        email_tld = utils.get_user_email_tld(session)\n         ip = utils.get_client_ip(request)\n \n         # build the message string (key:value pairs)\n@@ -81,7 +81,7 @@\n                          'http_method=%s' % request.method,\n                          'http_code=%s' % response.status_code,\n                          'user_type=%s' % usertype,\n-                         'user_email_domain=%s' % emaildomain,\n+                         'user_email_domain=%s' % email_tld,\n                          'request_url=%s' % request.path]])\n \n         resource_id = get_resource_id_from_url(request.path)\ndiff --git a/hs_tracking/utils.py b/hs_tracking/utils.py\n--- a/hs_tracking/utils.py\n+++ b/hs_tracking/utils.py\n@@ -21,10 +21,20 @@\n     try:\n         user = session.visitor.user\n         emaildomain = user.email.split('@')[-1]\n-        shortdomain = '.'.join(emaildomain.split('.')[1:])\n     except AttributeError:\n-        shortdomain = None\n-    return shortdomain\n+        emaildomain = None\n+    return emaildomain\n+\n+\n+def get_user_email_tld(session, emaildomain=None):\n+    try:\n+        if not emaildomain:\n+            emaildomain = get_user_email_domain(session)\n+        if emaildomain:\n+            shortdomain = '.'.join(emaildomain.split('.')[1:])\n+            return shortdomain\n+    except AttributeError:\n+        return None\n \n \n def is_human(user_agent):\n@@ -38,15 +48,18 @@\n     This ensures that all activities are reporting a consistent set of metrics\n     \"\"\"\n     user_type = None\n-    user_email = None\n+    user_email_tld = None\n+    full_domain = None\n     if session is not None:\n         user_type = get_user_type(session)\n-        user_email = get_user_email_domain(session)\n+        full_domain = get_user_email_domain(session)\n+        user_email_tld = get_user_email_tld(session, full_domain)\n \n     return {\n         'user_ip': get_client_ip(request),\n         'user_type': user_type,\n-        'user_email_domain': user_email,\n+        'user_email_domain': user_email_tld,\n+        'user_email_domain_full': full_domain\n     }\n", "issue": "track users' full email domain\n**Describe the feature you'd like and what it will do**\r\nIn HS v2.5.4, we don't track full user email domain in our metrics.\r\n\r\n\r\n**Why is this feature important?**\r\nWe need more insight into how HS' ecosystem of tools are being used. This information should drive our continued development on existing tools and our consideration of additions for future use.\r\n\n", "before_files": [{"content": "from django.utils.deprecation import MiddlewareMixin\n\nfrom .models import Session\nfrom . import utils\nimport re\n\nRESOURCE_RE = re.compile('resource/([0-9a-f]{32})/')  # parser for resource id\nBAG_RE = re.compile('bags/([0-9a-f]{32})\\.zip')  # parser for resource id # noqa\nLANDING_RE = re.compile('resource/([0-9a-f]{32})/$')  # reference to resource home page\nREST_RE = re.compile('/hsapi/')  # reference to REST or internal\nINTERNAL_RE = re.compile('/hsapi/_internal/')  # reference to an internal page\n\n\ndef get_resource_id_from_url(path):\n    \"\"\" read a resource id from a URL \"\"\"\n    m = RESOURCE_RE.search(path)\n    if m and m.group(1):\n        return m.group(1)\n    m = BAG_RE.search(path)\n    if m and m.group(1):\n        return m.group(1)\n    return None\n\n\ndef get_rest_from_url(path):\n    \"\"\" determine whether a URL is a REST call or not\n\n        This should always return boolean, not search result.\n    \"\"\"\n    if REST_RE.search(path):\n        if INTERNAL_RE.search(path):\n            return False\n        else:\n            return True\n    else:\n        return False\n\n\ndef get_landing_from_url(path):\n    \"\"\" determine whether a URL is a landing page.\n\n        This should always return boolean, not search result.\n    \"\"\"\n    if LANDING_RE.search(path):\n        return True\n    else:\n        return False\n\n\nclass Tracking(MiddlewareMixin):\n    \"\"\"The default tracking middleware logs all successful responses as a 'visit' variable with\n    the URL path as its value.\"\"\"\n\n    def process_response(self, request, response):\n\n        # filter out heartbeat messages\n        if request.path.startswith('/heartbeat/'):\n            return response\n\n        # filter out web crawlers\n        is_human = getattr(request, 'is_human', False)\n        if not is_human:\n            return response\n\n        # filter out everything that is not an OK response\n        if response.status_code != 200:\n            return response\n\n        if not hasattr(request, 'user'):\n            return response\n\n        # get user info that will be recorded in the visit log\n        session = Session.objects.for_request(request)\n        usertype = utils.get_user_type(session)\n        emaildomain = utils.get_user_email_domain(session)\n        ip = utils.get_client_ip(request)\n\n        # build the message string (key:value pairs)\n        msg = '|'.join([str(item) for item in\n                        ['user_ip=%s' % ip,\n                         'http_method=%s' % request.method,\n                         'http_code=%s' % response.status_code,\n                         'user_type=%s' % usertype,\n                         'user_email_domain=%s' % emaildomain,\n                         'request_url=%s' % request.path]])\n\n        resource_id = get_resource_id_from_url(request.path)\n        rest = get_rest_from_url(request.path)\n        landing = get_landing_from_url(request.path)\n\n        # save the activity in the database\n        session.record('visit', value=msg, resource_id=resource_id,\n                       landing=landing, rest=rest)\n\n        return response\n", "path": "hs_tracking/middleware.py"}, {"content": "import robot_detection\nfrom ipware.ip import get_ip\nfrom hs_tools_resource.models import RequestUrlBase, RequestUrlBaseAggregation, RequestUrlBaseFile\nfrom urllib.parse import urlparse\n\n\ndef get_client_ip(request):\n    return get_ip(request)\n\n\ndef get_user_type(session):\n    try:\n        user = session.visitor.user\n        usertype = user.userprofile.user_type\n    except AttributeError:\n        usertype = None\n    return usertype\n\n\ndef get_user_email_domain(session):\n    try:\n        user = session.visitor.user\n        emaildomain = user.email.split('@')[-1]\n        shortdomain = '.'.join(emaildomain.split('.')[1:])\n    except AttributeError:\n        shortdomain = None\n    return shortdomain\n\n\ndef is_human(user_agent):\n    if robot_detection.is_robot(user_agent):\n        return False\n    return True\n\n\ndef get_std_log_fields(request, session=None):\n    \"\"\" returns a standard set of metadata that to each receiver function.\n    This ensures that all activities are reporting a consistent set of metrics\n    \"\"\"\n    user_type = None\n    user_email = None\n    if session is not None:\n        user_type = get_user_type(session)\n        user_email = get_user_email_domain(session)\n\n    return {\n        'user_ip': get_client_ip(request),\n        'user_type': user_type,\n        'user_email_domain': user_email,\n    }\n\n\ndef authentic_redirect_url(url):\n    \"\"\" Validates a url scheme and netloc is in an existing web app\n    :param url: String of a url\n    :return: Boolean, True if the url exists in a web app\n    \"\"\"\n    if not url:\n        return False\n    u = urlparse(url)\n    url_base = \"{}://{}\".format(u.scheme, u.netloc)\n    return RequestUrlBase.objects.filter(value__startswith=url_base).exists() \\\n        or RequestUrlBaseAggregation.objects.filter(value__startswith=url_base).exists() \\\n        or RequestUrlBaseFile.objects.filter(value__startswith=url_base).exists()\n", "path": "hs_tracking/utils.py"}], "after_files": [{"content": "from django.utils.deprecation import MiddlewareMixin\n\nfrom .models import Session\nfrom . import utils\nimport re\n\nRESOURCE_RE = re.compile('resource/([0-9a-f]{32})/')  # parser for resource id\nBAG_RE = re.compile('bags/([0-9a-f]{32})\\.zip')  # parser for resource id # noqa\nLANDING_RE = re.compile('resource/([0-9a-f]{32})/$')  # reference to resource home page\nREST_RE = re.compile('/hsapi/')  # reference to REST or internal\nINTERNAL_RE = re.compile('/hsapi/_internal/')  # reference to an internal page\n\n\ndef get_resource_id_from_url(path):\n    \"\"\" read a resource id from a URL \"\"\"\n    m = RESOURCE_RE.search(path)\n    if m and m.group(1):\n        return m.group(1)\n    m = BAG_RE.search(path)\n    if m and m.group(1):\n        return m.group(1)\n    return None\n\n\ndef get_rest_from_url(path):\n    \"\"\" determine whether a URL is a REST call or not\n\n        This should always return boolean, not search result.\n    \"\"\"\n    if REST_RE.search(path):\n        if INTERNAL_RE.search(path):\n            return False\n        else:\n            return True\n    else:\n        return False\n\n\ndef get_landing_from_url(path):\n    \"\"\" determine whether a URL is a landing page.\n\n        This should always return boolean, not search result.\n    \"\"\"\n    if LANDING_RE.search(path):\n        return True\n    else:\n        return False\n\n\nclass Tracking(MiddlewareMixin):\n    \"\"\"The default tracking middleware logs all successful responses as a 'visit' variable with\n    the URL path as its value.\"\"\"\n\n    def process_response(self, request, response):\n\n        # filter out heartbeat messages\n        if request.path.startswith('/heartbeat/'):\n            return response\n\n        # filter out web crawlers\n        is_human = getattr(request, 'is_human', False)\n        if not is_human:\n            return response\n\n        # filter out everything that is not an OK response\n        if response.status_code != 200:\n            return response\n\n        if not hasattr(request, 'user'):\n            return response\n\n        # get user info that will be recorded in the visit log\n        session = Session.objects.for_request(request)\n        usertype = utils.get_user_type(session)\n        email_tld = utils.get_user_email_tld(session)\n        ip = utils.get_client_ip(request)\n\n        # build the message string (key:value pairs)\n        msg = '|'.join([str(item) for item in\n                        ['user_ip=%s' % ip,\n                         'http_method=%s' % request.method,\n                         'http_code=%s' % response.status_code,\n                         'user_type=%s' % usertype,\n                         'user_email_domain=%s' % email_tld,\n                         'request_url=%s' % request.path]])\n\n        resource_id = get_resource_id_from_url(request.path)\n        rest = get_rest_from_url(request.path)\n        landing = get_landing_from_url(request.path)\n\n        # save the activity in the database\n        session.record('visit', value=msg, resource_id=resource_id,\n                       landing=landing, rest=rest)\n\n        return response\n", "path": "hs_tracking/middleware.py"}, {"content": "import robot_detection\nfrom ipware.ip import get_ip\nfrom hs_tools_resource.models import RequestUrlBase, RequestUrlBaseAggregation, RequestUrlBaseFile\nfrom urllib.parse import urlparse\n\n\ndef get_client_ip(request):\n    return get_ip(request)\n\n\ndef get_user_type(session):\n    try:\n        user = session.visitor.user\n        usertype = user.userprofile.user_type\n    except AttributeError:\n        usertype = None\n    return usertype\n\n\ndef get_user_email_domain(session):\n    try:\n        user = session.visitor.user\n        emaildomain = user.email.split('@')[-1]\n    except AttributeError:\n        emaildomain = None\n    return emaildomain\n\n\ndef get_user_email_tld(session, emaildomain=None):\n    try:\n        if not emaildomain:\n            emaildomain = get_user_email_domain(session)\n        if emaildomain:\n            shortdomain = '.'.join(emaildomain.split('.')[1:])\n            return shortdomain\n    except AttributeError:\n        return None\n\n\ndef is_human(user_agent):\n    if robot_detection.is_robot(user_agent):\n        return False\n    return True\n\n\ndef get_std_log_fields(request, session=None):\n    \"\"\" returns a standard set of metadata that to each receiver function.\n    This ensures that all activities are reporting a consistent set of metrics\n    \"\"\"\n    user_type = None\n    user_email_tld = None\n    full_domain = None\n    if session is not None:\n        user_type = get_user_type(session)\n        full_domain = get_user_email_domain(session)\n        user_email_tld = get_user_email_tld(session, full_domain)\n\n    return {\n        'user_ip': get_client_ip(request),\n        'user_type': user_type,\n        'user_email_domain': user_email_tld,\n        'user_email_domain_full': full_domain\n    }\n\n\ndef authentic_redirect_url(url):\n    \"\"\" Validates a url scheme and netloc is in an existing web app\n    :param url: String of a url\n    :return: Boolean, True if the url exists in a web app\n    \"\"\"\n    if not url:\n        return False\n    u = urlparse(url)\n    url_base = \"{}://{}\".format(u.scheme, u.netloc)\n    return RequestUrlBase.objects.filter(value__startswith=url_base).exists() \\\n        or RequestUrlBaseAggregation.objects.filter(value__startswith=url_base).exists() \\\n        or RequestUrlBaseFile.objects.filter(value__startswith=url_base).exists()\n", "path": "hs_tracking/utils.py"}]}