We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
prevent timezone warnings during session logging
**Describe the feature you'd like and what it will do**
Most actions within HS result in at least 4 RuntimeWarnings to be logged
Example creating a resource:
![image](https://user-images.githubusercontent.com/17934193/209165319-7e97eb58-2e23-4ee1-9095-0c5beeef0a8e.png)
This makes it difficult to sift through the logs and find what we need.
Get rid of these unnecessary warnings

**Why is this feature important?**
Make debugging and audit trail easier


--- 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/models.py`
Content:
```
1 from datetime import datetime, timedelta
2 
3 from django.db import models
4 from django.db.models import F
5 from django.core import signing
6 from django.conf import settings
7 from django.core.exceptions import ImproperlyConfigured
8 from django.contrib.auth.models import User
9 
10 from theme.models import UserProfile
11 from .utils import get_std_log_fields
12 from hs_core.models import BaseResource
13 from hs_core.hydroshare import get_resource_by_shortkey
14 
15 SESSION_TIMEOUT = settings.TRACKING_SESSION_TIMEOUT
16 PROFILE_FIELDS = settings.TRACKING_PROFILE_FIELDS
17 USER_FIELDS = settings.TRACKING_USER_FIELDS
18 VISITOR_FIELDS = ["id"] + USER_FIELDS + PROFILE_FIELDS
19 if set(PROFILE_FIELDS) & set(USER_FIELDS):
20     raise ImproperlyConfigured("hs_tracking PROFILE_FIELDS and USER_FIELDS must not contain"
21                                " overlapping field names")
22 
23 
24 class SessionManager(models.Manager):
25     def for_request(self, request, user=None):
26         if hasattr(request, 'user'):
27             user = request.user
28 
29         signed_id = request.session.get('hs_tracking_id')
30         if signed_id:
31             tracking_id = signing.loads(signed_id)
32             cut_off = datetime.now() - timedelta(seconds=SESSION_TIMEOUT)
33             session = None
34 
35             try:
36                 session = Session.objects.filter(
37                     variable__timestamp__gte=cut_off).filter(id=tracking_id['id']).first()
38             except Session.DoesNotExist:
39                 pass
40 
41             if session is not None and user is not None:
42                 if session.visitor.user is None and user.is_authenticated:
43                     try:
44                         session.visitor = Visitor.objects.get(user=user)
45                         session.save()
46                     except Visitor.DoesNotExist:
47                         session.visitor.user = user
48                         session.visitor.save()
49                 return session
50 
51         # No session found, create one
52         if user.is_authenticated:
53             visitor, _ = Visitor.objects.get_or_create(user=user)
54         else:
55             visitor = Visitor.objects.create()
56 
57         session = Session.objects.create(visitor=visitor)
58 
59         # get standard fields and format
60         fields = get_std_log_fields(request, session)
61         msg = Variable.format_kwargs(**fields)
62 
63         session.record('begin_session', msg)
64         request.session['hs_tracking_id'] = signing.dumps({'id': session.id})
65         return session
66 
67 
68 class Visitor(models.Model):
69     first_seen = models.DateTimeField(auto_now_add=True)
70     user = models.OneToOneField(settings.AUTH_USER_MODEL, null=True,
71                                 on_delete=models.SET_NULL,
72                                 related_name='visitor')
73 
74     def export_visitor_information(self):
75         """Exports visitor profile information."""
76         info = {
77             "id": self.id,
78         }
79         if self.user:
80             profile = UserProfile.objects.get(user=self.user)
81             for field in PROFILE_FIELDS:
82                 info[field] = getattr(profile, field)
83             for field in USER_FIELDS:
84                 info[field] = getattr(self.user, field)
85         else:
86             profile = None
87             for field in PROFILE_FIELDS:
88                 info[field] = None
89             for field in USER_FIELDS:
90                 info[field] = None
91         return info
92 
93 
94 class Session(models.Model):
95     begin = models.DateTimeField(auto_now_add=True)
96     visitor = models.ForeignKey(Visitor, on_delete=models.CASCADE,  related_name='session')
97     # TODO: hostname = models.CharField(null=True, default=None, max_length=256)
98 
99     objects = SessionManager()
100 
101     def get(self, name):
102         return Variable.objects.filter(session=self, name=name).first().get_value()
103 
104     def getlist(self, name):
105         return [v.get_value() for v in Variable.objects.filter(session=self, name=name)]
106 
107     def record(self, *args, **kwargs):
108         args = (self,) + args
109         return Variable.record(*args, **kwargs)
110 
111 
112 class Variable(models.Model):
113     TYPES = (
114         ('Integer', int),
115         ('Floating Point', float),
116         ('Text', str),
117         ('Flag', bool),
118         ('None', lambda o: None)
119     )
120     TYPE_CHOICES = [
121         (i, label)
122         for (i, label) in
123         enumerate(label for (label, coercer) in TYPES)
124     ]
125 
126     from hs_core.models import BaseResource
127 
128     session = models.ForeignKey(Session, on_delete=models.CASCADE,  related_name='variable')
129     timestamp = models.DateTimeField(auto_now_add=True)
130     name = models.CharField(max_length=32)
131     type = models.IntegerField(choices=TYPE_CHOICES)
132     # change value to TextField to be less restrictive as max_length of CharField has been
133     # exceeded a couple of times
134     value = models.TextField()
135 
136     # If a resource no longer exists, last_resource_id remains valid but resource is NULL
137     resource = models.ForeignKey(BaseResource, null=True,
138                                  related_name='variable',
139                                  on_delete=models.SET_NULL)
140     last_resource_id = models.CharField(null=True, max_length=32)
141 
142     # flags describe kind of visit. False for non-visits
143     landing = models.BooleanField(null=False, default=False)
144     rest = models.BooleanField(null=False, default=False)
145     # REDUNDANT: internal = models.BooleanField(null=False, default=False)
146 
147     def get_value(self):
148         v = self.value
149         if self.type == 3:  # boolean types don't coerce reflexively
150             if v == 'true':
151                 return True
152             else:
153                 return False
154         else:
155             t = self.TYPES[self.type][1]
156             return t(v)
157 
158     @classmethod
159     def format_kwargs(cls, **kwargs):
160         msg_items = []
161         for k, v in list(kwargs.items()):
162             msg_items.append('%s=%s' % (str(k), str(v)))
163         return '|'.join(msg_items)
164 
165     @classmethod
166     def record(cls, session, name, value=None, resource=None, resource_id=None,
167                rest=False, landing=False):
168         if resource is None and resource_id is not None:
169             try:
170                 resource = get_resource_by_shortkey(resource_id, or_404=False)
171             except BaseResource.DoesNotExist:
172                 resource = None
173         return Variable.objects.create(session=session, name=name,
174                                        type=cls.encode_type(value),
175                                        value=cls.encode(value),
176                                        last_resource_id=resource_id,
177                                        resource=resource,
178                                        rest=rest,
179                                        landing=landing)
180 
181     @classmethod
182     def encode(cls, value):
183         if value is None:
184             return ''
185         elif isinstance(value, bool):
186             return 'true' if value else 'false'  # only empty strings are False
187         elif isinstance(value, (int, float, str)):
188             return str(value)
189         else:
190             raise ValueError("Unknown type (%s) for tracking variable: %r",
191                              type(value).__name__, value)
192 
193     @classmethod
194     def encode_type(cls, value):
195         if value is None:
196             return 4
197         elif isinstance(value, bool):
198             return 3
199         elif isinstance(value, str):
200             return 2
201         elif isinstance(value, float):
202             return 1
203         elif isinstance(value, int):
204             return 0
205         else:
206             raise TypeError("Unable to record variable of unrecognized type %s",
207                             type(value).__name__)
208 
209     @classmethod
210     def recent_resources(cls, user, n_resources=5, days=60):
211         """
212         fetch the most recent n resources with which a specific user has interacted
213 
214         :param user: The user to document.
215         :param n_resources: the number of resources to return.
216         :param days: the number of days to scan.
217 
218         The reason for the parameter `days` is that the runtime of this method
219         is very dependent upon the days that one scans. Thus, there is a tradeoff
220         between reporting history and timely responsiveness of the dashboard.
221         """
222         # TODO: document actions like labeling and commenting (currently these are 'visit's)
223         return BaseResource.objects.filter(
224                 variable__session__visitor__user=user,
225                 variable__timestamp__gte=(datetime.now()-timedelta(days)),
226                 variable__resource__isnull=False,
227                 variable__name='visit')\
228             .only('short_id', 'created')\
229             .distinct()\
230             .annotate(public=F('raccess__public'),
231                       discoverable=F('raccess__discoverable'),
232                       published=F('raccess__published'),
233                       last_accessed=models.Max('variable__timestamp'))\
234             .filter(variable__timestamp=F('last_accessed'))\
235             .order_by('-last_accessed')[:n_resources]
236 
237     @classmethod
238     def popular_resources(cls, n_resources=5, days=60, today=None):
239         """
240         fetch the most recent n resources with which a specific user has interacted
241 
242         :param n_resources: the number of resources to return.
243         :param days: the number of days to scan.
244 
245         The reason for the parameter `days` is that the runtime of this method
246         is very dependent upon the days that one scans. Thus, there is a tradeoff
247         between reporting history and timely responsiveness of the dashboard.
248         """
249         # TODO: document actions like labeling and commenting (currently these are 'visit's)
250         if today is None:
251             today = datetime.now()
252         return BaseResource.objects.filter(
253                 variable__timestamp__gte=(today-timedelta(days)),
254                 variable__timestamp__lt=(today),
255                 variable__resource__isnull=False,
256                 variable__name='visit')\
257             .distinct()\
258             .annotate(users=models.Count('variable__session__visitor__user'))\
259             .annotate(public=F('raccess__public'),
260                       discoverable=F('raccess__discoverable'),
261                       published=F('raccess__published'),
262                       last_accessed=models.Max('variable__timestamp'))\
263             .order_by('-users')[:n_resources]
264 
265     @classmethod
266     def recent_users(cls, resource, n_users=5, days=60):
267         """
268         fetch the identities of the most recent users who have accessed a resource
269 
270         :param resource: The resource to document.
271         :param n_users: the number of users to return.
272         :param days: the number of days to scan.
273 
274         The reason for the parameter `days` is that the runtime of this method
275         is very dependent upon the number of days that one scans. Thus, there is a
276         tradeoff between reporting history and timely responsiveness of the dashboard.
277         """
278         return User.objects\
279             .filter(visitor__session__variable__resource=resource,
280                     visitor__session__variable__name='visit',
281                     visitor__session__variable__timestamp__gte=(datetime.now() -
282                                                                 timedelta(days)))\
283             .distinct()\
284             .annotate(last_accessed=models.Max('visitor__session__variable__timestamp'))\
285             .filter(visitor__session__variable__timestamp=F('last_accessed'))\
286             .order_by('-last_accessed')[:n_users]
287
```
--- 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/models.py b/hs_tracking/models.py
--- a/hs_tracking/models.py
+++ b/hs_tracking/models.py
@@ -1,4 +1,5 @@
 from datetime import datetime, timedelta
+from django.utils import timezone
 
 from django.db import models
 from django.db.models import F
@@ -30,6 +31,7 @@
         if signed_id:
             tracking_id = signing.loads(signed_id)
             cut_off = datetime.now() - timedelta(seconds=SESSION_TIMEOUT)
+            cut_off = timezone.make_aware(cut_off)
             session = None
 
             try:

{"golden_diff": "diff --git a/hs_tracking/models.py b/hs_tracking/models.py\n--- a/hs_tracking/models.py\n+++ b/hs_tracking/models.py\n@@ -1,4 +1,5 @@\n from datetime import datetime, timedelta\n+from django.utils import timezone\n \n from django.db import models\n from django.db.models import F\n@@ -30,6 +31,7 @@\n         if signed_id:\n             tracking_id = signing.loads(signed_id)\n             cut_off = datetime.now() - timedelta(seconds=SESSION_TIMEOUT)\n+            cut_off = timezone.make_aware(cut_off)\n             session = None\n \n             try:\n", "issue": "prevent timezone warnings during session logging\n**Describe the feature you'd like and what it will do**\r\nMost actions within HS result in at least 4 RuntimeWarnings to be logged\r\nExample creating a resource:\r\n![image](https://user-images.githubusercontent.com/17934193/209165319-7e97eb58-2e23-4ee1-9095-0c5beeef0a8e.png)\r\nThis makes it difficult to sift through the logs and find what we need.\r\nGet rid of these unnecessary warnings\r\n\r\n**Why is this feature important?**\r\nMake debugging and audit trail easier\r\n\n", "before_files": [{"content": "from datetime import datetime, timedelta\n\nfrom django.db import models\nfrom django.db.models import F\nfrom django.core import signing\nfrom django.conf import settings\nfrom django.core.exceptions import ImproperlyConfigured\nfrom django.contrib.auth.models import User\n\nfrom theme.models import UserProfile\nfrom .utils import get_std_log_fields\nfrom hs_core.models import BaseResource\nfrom hs_core.hydroshare import get_resource_by_shortkey\n\nSESSION_TIMEOUT = settings.TRACKING_SESSION_TIMEOUT\nPROFILE_FIELDS = settings.TRACKING_PROFILE_FIELDS\nUSER_FIELDS = settings.TRACKING_USER_FIELDS\nVISITOR_FIELDS = [\"id\"] + USER_FIELDS + PROFILE_FIELDS\nif set(PROFILE_FIELDS) & set(USER_FIELDS):\n    raise ImproperlyConfigured(\"hs_tracking PROFILE_FIELDS and USER_FIELDS must not contain\"\n                               \" overlapping field names\")\n\n\nclass SessionManager(models.Manager):\n    def for_request(self, request, user=None):\n        if hasattr(request, 'user'):\n            user = request.user\n\n        signed_id = request.session.get('hs_tracking_id')\n        if signed_id:\n            tracking_id = signing.loads(signed_id)\n            cut_off = datetime.now() - timedelta(seconds=SESSION_TIMEOUT)\n            session = None\n\n            try:\n                session = Session.objects.filter(\n                    variable__timestamp__gte=cut_off).filter(id=tracking_id['id']).first()\n            except Session.DoesNotExist:\n                pass\n\n            if session is not None and user is not None:\n                if session.visitor.user is None and user.is_authenticated:\n                    try:\n                        session.visitor = Visitor.objects.get(user=user)\n                        session.save()\n                    except Visitor.DoesNotExist:\n                        session.visitor.user = user\n                        session.visitor.save()\n                return session\n\n        # No session found, create one\n        if user.is_authenticated:\n            visitor, _ = Visitor.objects.get_or_create(user=user)\n        else:\n            visitor = Visitor.objects.create()\n\n        session = Session.objects.create(visitor=visitor)\n\n        # get standard fields and format\n        fields = get_std_log_fields(request, session)\n        msg = Variable.format_kwargs(**fields)\n\n        session.record('begin_session', msg)\n        request.session['hs_tracking_id'] = signing.dumps({'id': session.id})\n        return session\n\n\nclass Visitor(models.Model):\n    first_seen = models.DateTimeField(auto_now_add=True)\n    user = models.OneToOneField(settings.AUTH_USER_MODEL, null=True,\n                                on_delete=models.SET_NULL,\n                                related_name='visitor')\n\n    def export_visitor_information(self):\n        \"\"\"Exports visitor profile information.\"\"\"\n        info = {\n            \"id\": self.id,\n        }\n        if self.user:\n            profile = UserProfile.objects.get(user=self.user)\n            for field in PROFILE_FIELDS:\n                info[field] = getattr(profile, field)\n            for field in USER_FIELDS:\n                info[field] = getattr(self.user, field)\n        else:\n            profile = None\n            for field in PROFILE_FIELDS:\n                info[field] = None\n            for field in USER_FIELDS:\n                info[field] = None\n        return info\n\n\nclass Session(models.Model):\n    begin = models.DateTimeField(auto_now_add=True)\n    visitor = models.ForeignKey(Visitor, on_delete=models.CASCADE,  related_name='session')\n    # TODO: hostname = models.CharField(null=True, default=None, max_length=256)\n\n    objects = SessionManager()\n\n    def get(self, name):\n        return Variable.objects.filter(session=self, name=name).first().get_value()\n\n    def getlist(self, name):\n        return [v.get_value() for v in Variable.objects.filter(session=self, name=name)]\n\n    def record(self, *args, **kwargs):\n        args = (self,) + args\n        return Variable.record(*args, **kwargs)\n\n\nclass Variable(models.Model):\n    TYPES = (\n        ('Integer', int),\n        ('Floating Point', float),\n        ('Text', str),\n        ('Flag', bool),\n        ('None', lambda o: None)\n    )\n    TYPE_CHOICES = [\n        (i, label)\n        for (i, label) in\n        enumerate(label for (label, coercer) in TYPES)\n    ]\n\n    from hs_core.models import BaseResource\n\n    session = models.ForeignKey(Session, on_delete=models.CASCADE,  related_name='variable')\n    timestamp = models.DateTimeField(auto_now_add=True)\n    name = models.CharField(max_length=32)\n    type = models.IntegerField(choices=TYPE_CHOICES)\n    # change value to TextField to be less restrictive as max_length of CharField has been\n    # exceeded a couple of times\n    value = models.TextField()\n\n    # If a resource no longer exists, last_resource_id remains valid but resource is NULL\n    resource = models.ForeignKey(BaseResource, null=True,\n                                 related_name='variable',\n                                 on_delete=models.SET_NULL)\n    last_resource_id = models.CharField(null=True, max_length=32)\n\n    # flags describe kind of visit. False for non-visits\n    landing = models.BooleanField(null=False, default=False)\n    rest = models.BooleanField(null=False, default=False)\n    # REDUNDANT: internal = models.BooleanField(null=False, default=False)\n\n    def get_value(self):\n        v = self.value\n        if self.type == 3:  # boolean types don't coerce reflexively\n            if v == 'true':\n                return True\n            else:\n                return False\n        else:\n            t = self.TYPES[self.type][1]\n            return t(v)\n\n    @classmethod\n    def format_kwargs(cls, **kwargs):\n        msg_items = []\n        for k, v in list(kwargs.items()):\n            msg_items.append('%s=%s' % (str(k), str(v)))\n        return '|'.join(msg_items)\n\n    @classmethod\n    def record(cls, session, name, value=None, resource=None, resource_id=None,\n               rest=False, landing=False):\n        if resource is None and resource_id is not None:\n            try:\n                resource = get_resource_by_shortkey(resource_id, or_404=False)\n            except BaseResource.DoesNotExist:\n                resource = None\n        return Variable.objects.create(session=session, name=name,\n                                       type=cls.encode_type(value),\n                                       value=cls.encode(value),\n                                       last_resource_id=resource_id,\n                                       resource=resource,\n                                       rest=rest,\n                                       landing=landing)\n\n    @classmethod\n    def encode(cls, value):\n        if value is None:\n            return ''\n        elif isinstance(value, bool):\n            return 'true' if value else 'false'  # only empty strings are False\n        elif isinstance(value, (int, float, str)):\n            return str(value)\n        else:\n            raise ValueError(\"Unknown type (%s) for tracking variable: %r\",\n                             type(value).__name__, value)\n\n    @classmethod\n    def encode_type(cls, value):\n        if value is None:\n            return 4\n        elif isinstance(value, bool):\n            return 3\n        elif isinstance(value, str):\n            return 2\n        elif isinstance(value, float):\n            return 1\n        elif isinstance(value, int):\n            return 0\n        else:\n            raise TypeError(\"Unable to record variable of unrecognized type %s\",\n                            type(value).__name__)\n\n    @classmethod\n    def recent_resources(cls, user, n_resources=5, days=60):\n        \"\"\"\n        fetch the most recent n resources with which a specific user has interacted\n\n        :param user: The user to document.\n        :param n_resources: the number of resources to return.\n        :param days: the number of days to scan.\n\n        The reason for the parameter `days` is that the runtime of this method\n        is very dependent upon the days that one scans. Thus, there is a tradeoff\n        between reporting history and timely responsiveness of the dashboard.\n        \"\"\"\n        # TODO: document actions like labeling and commenting (currently these are 'visit's)\n        return BaseResource.objects.filter(\n                variable__session__visitor__user=user,\n                variable__timestamp__gte=(datetime.now()-timedelta(days)),\n                variable__resource__isnull=False,\n                variable__name='visit')\\\n            .only('short_id', 'created')\\\n            .distinct()\\\n            .annotate(public=F('raccess__public'),\n                      discoverable=F('raccess__discoverable'),\n                      published=F('raccess__published'),\n                      last_accessed=models.Max('variable__timestamp'))\\\n            .filter(variable__timestamp=F('last_accessed'))\\\n            .order_by('-last_accessed')[:n_resources]\n\n    @classmethod\n    def popular_resources(cls, n_resources=5, days=60, today=None):\n        \"\"\"\n        fetch the most recent n resources with which a specific user has interacted\n\n        :param n_resources: the number of resources to return.\n        :param days: the number of days to scan.\n\n        The reason for the parameter `days` is that the runtime of this method\n        is very dependent upon the days that one scans. Thus, there is a tradeoff\n        between reporting history and timely responsiveness of the dashboard.\n        \"\"\"\n        # TODO: document actions like labeling and commenting (currently these are 'visit's)\n        if today is None:\n            today = datetime.now()\n        return BaseResource.objects.filter(\n                variable__timestamp__gte=(today-timedelta(days)),\n                variable__timestamp__lt=(today),\n                variable__resource__isnull=False,\n                variable__name='visit')\\\n            .distinct()\\\n            .annotate(users=models.Count('variable__session__visitor__user'))\\\n            .annotate(public=F('raccess__public'),\n                      discoverable=F('raccess__discoverable'),\n                      published=F('raccess__published'),\n                      last_accessed=models.Max('variable__timestamp'))\\\n            .order_by('-users')[:n_resources]\n\n    @classmethod\n    def recent_users(cls, resource, n_users=5, days=60):\n        \"\"\"\n        fetch the identities of the most recent users who have accessed a resource\n\n        :param resource: The resource to document.\n        :param n_users: the number of users to return.\n        :param days: the number of days to scan.\n\n        The reason for the parameter `days` is that the runtime of this method\n        is very dependent upon the number of days that one scans. Thus, there is a\n        tradeoff between reporting history and timely responsiveness of the dashboard.\n        \"\"\"\n        return User.objects\\\n            .filter(visitor__session__variable__resource=resource,\n                    visitor__session__variable__name='visit',\n                    visitor__session__variable__timestamp__gte=(datetime.now() -\n                                                                timedelta(days)))\\\n            .distinct()\\\n            .annotate(last_accessed=models.Max('visitor__session__variable__timestamp'))\\\n            .filter(visitor__session__variable__timestamp=F('last_accessed'))\\\n            .order_by('-last_accessed')[:n_users]\n", "path": "hs_tracking/models.py"}], "after_files": [{"content": "from datetime import datetime, timedelta\nfrom django.utils import timezone\n\nfrom django.db import models\nfrom django.db.models import F\nfrom django.core import signing\nfrom django.conf import settings\nfrom django.core.exceptions import ImproperlyConfigured\nfrom django.contrib.auth.models import User\n\nfrom theme.models import UserProfile\nfrom .utils import get_std_log_fields\nfrom hs_core.models import BaseResource\nfrom hs_core.hydroshare import get_resource_by_shortkey\n\nSESSION_TIMEOUT = settings.TRACKING_SESSION_TIMEOUT\nPROFILE_FIELDS = settings.TRACKING_PROFILE_FIELDS\nUSER_FIELDS = settings.TRACKING_USER_FIELDS\nVISITOR_FIELDS = [\"id\"] + USER_FIELDS + PROFILE_FIELDS\nif set(PROFILE_FIELDS) & set(USER_FIELDS):\n    raise ImproperlyConfigured(\"hs_tracking PROFILE_FIELDS and USER_FIELDS must not contain\"\n                               \" overlapping field names\")\n\n\nclass SessionManager(models.Manager):\n    def for_request(self, request, user=None):\n        if hasattr(request, 'user'):\n            user = request.user\n\n        signed_id = request.session.get('hs_tracking_id')\n        if signed_id:\n            tracking_id = signing.loads(signed_id)\n            cut_off = datetime.now() - timedelta(seconds=SESSION_TIMEOUT)\n            cut_off = timezone.make_aware(cut_off)\n            session = None\n\n            try:\n                session = Session.objects.filter(\n                    variable__timestamp__gte=cut_off).filter(id=tracking_id['id']).first()\n            except Session.DoesNotExist:\n                pass\n\n            if session is not None and user is not None:\n                if session.visitor.user is None and user.is_authenticated:\n                    try:\n                        session.visitor = Visitor.objects.get(user=user)\n                        session.save()\n                    except Visitor.DoesNotExist:\n                        session.visitor.user = user\n                        session.visitor.save()\n                return session\n\n        # No session found, create one\n        if user.is_authenticated:\n            visitor, _ = Visitor.objects.get_or_create(user=user)\n        else:\n            visitor = Visitor.objects.create()\n\n        session = Session.objects.create(visitor=visitor)\n\n        # get standard fields and format\n        fields = get_std_log_fields(request, session)\n        msg = Variable.format_kwargs(**fields)\n\n        session.record('begin_session', msg)\n        request.session['hs_tracking_id'] = signing.dumps({'id': session.id})\n        return session\n\n\nclass Visitor(models.Model):\n    first_seen = models.DateTimeField(auto_now_add=True)\n    user = models.OneToOneField(settings.AUTH_USER_MODEL, null=True,\n                                on_delete=models.SET_NULL,\n                                related_name='visitor')\n\n    def export_visitor_information(self):\n        \"\"\"Exports visitor profile information.\"\"\"\n        info = {\n            \"id\": self.id,\n        }\n        if self.user:\n            profile = UserProfile.objects.get(user=self.user)\n            for field in PROFILE_FIELDS:\n                info[field] = getattr(profile, field)\n            for field in USER_FIELDS:\n                info[field] = getattr(self.user, field)\n        else:\n            profile = None\n            for field in PROFILE_FIELDS:\n                info[field] = None\n            for field in USER_FIELDS:\n                info[field] = None\n        return info\n\n\nclass Session(models.Model):\n    begin = models.DateTimeField(auto_now_add=True)\n    visitor = models.ForeignKey(Visitor, on_delete=models.CASCADE,  related_name='session')\n    # TODO: hostname = models.CharField(null=True, default=None, max_length=256)\n\n    objects = SessionManager()\n\n    def get(self, name):\n        return Variable.objects.filter(session=self, name=name).first().get_value()\n\n    def getlist(self, name):\n        return [v.get_value() for v in Variable.objects.filter(session=self, name=name)]\n\n    def record(self, *args, **kwargs):\n        args = (self,) + args\n        return Variable.record(*args, **kwargs)\n\n\nclass Variable(models.Model):\n    TYPES = (\n        ('Integer', int),\n        ('Floating Point', float),\n        ('Text', str),\n        ('Flag', bool),\n        ('None', lambda o: None)\n    )\n    TYPE_CHOICES = [\n        (i, label)\n        for (i, label) in\n        enumerate(label for (label, coercer) in TYPES)\n    ]\n\n    from hs_core.models import BaseResource\n\n    session = models.ForeignKey(Session, on_delete=models.CASCADE,  related_name='variable')\n    timestamp = models.DateTimeField(auto_now_add=True)\n    name = models.CharField(max_length=32)\n    type = models.IntegerField(choices=TYPE_CHOICES)\n    # change value to TextField to be less restrictive as max_length of CharField has been\n    # exceeded a couple of times\n    value = models.TextField()\n\n    # If a resource no longer exists, last_resource_id remains valid but resource is NULL\n    resource = models.ForeignKey(BaseResource, null=True,\n                                 related_name='variable',\n                                 on_delete=models.SET_NULL)\n    last_resource_id = models.CharField(null=True, max_length=32)\n\n    # flags describe kind of visit. False for non-visits\n    landing = models.BooleanField(null=False, default=False)\n    rest = models.BooleanField(null=False, default=False)\n    # REDUNDANT: internal = models.BooleanField(null=False, default=False)\n\n    def get_value(self):\n        v = self.value\n        if self.type == 3:  # boolean types don't coerce reflexively\n            if v == 'true':\n                return True\n            else:\n                return False\n        else:\n            t = self.TYPES[self.type][1]\n            return t(v)\n\n    @classmethod\n    def format_kwargs(cls, **kwargs):\n        msg_items = []\n        for k, v in list(kwargs.items()):\n            msg_items.append('%s=%s' % (str(k), str(v)))\n        return '|'.join(msg_items)\n\n    @classmethod\n    def record(cls, session, name, value=None, resource=None, resource_id=None,\n               rest=False, landing=False):\n        if resource is None and resource_id is not None:\n            try:\n                resource = get_resource_by_shortkey(resource_id, or_404=False)\n            except BaseResource.DoesNotExist:\n                resource = None\n        return Variable.objects.create(session=session, name=name,\n                                       type=cls.encode_type(value),\n                                       value=cls.encode(value),\n                                       last_resource_id=resource_id,\n                                       resource=resource,\n                                       rest=rest,\n                                       landing=landing)\n\n    @classmethod\n    def encode(cls, value):\n        if value is None:\n            return ''\n        elif isinstance(value, bool):\n            return 'true' if value else 'false'  # only empty strings are False\n        elif isinstance(value, (int, float, str)):\n            return str(value)\n        else:\n            raise ValueError(\"Unknown type (%s) for tracking variable: %r\",\n                             type(value).__name__, value)\n\n    @classmethod\n    def encode_type(cls, value):\n        if value is None:\n            return 4\n        elif isinstance(value, bool):\n            return 3\n        elif isinstance(value, str):\n            return 2\n        elif isinstance(value, float):\n            return 1\n        elif isinstance(value, int):\n            return 0\n        else:\n            raise TypeError(\"Unable to record variable of unrecognized type %s\",\n                            type(value).__name__)\n\n    @classmethod\n    def recent_resources(cls, user, n_resources=5, days=60):\n        \"\"\"\n        fetch the most recent n resources with which a specific user has interacted\n\n        :param user: The user to document.\n        :param n_resources: the number of resources to return.\n        :param days: the number of days to scan.\n\n        The reason for the parameter `days` is that the runtime of this method\n        is very dependent upon the days that one scans. Thus, there is a tradeoff\n        between reporting history and timely responsiveness of the dashboard.\n        \"\"\"\n        # TODO: document actions like labeling and commenting (currently these are 'visit's)\n        return BaseResource.objects.filter(\n                variable__session__visitor__user=user,\n                variable__timestamp__gte=(datetime.now()-timedelta(days)),\n                variable__resource__isnull=False,\n                variable__name='visit')\\\n            .only('short_id', 'created')\\\n            .distinct()\\\n            .annotate(public=F('raccess__public'),\n                      discoverable=F('raccess__discoverable'),\n                      published=F('raccess__published'),\n                      last_accessed=models.Max('variable__timestamp'))\\\n            .filter(variable__timestamp=F('last_accessed'))\\\n            .order_by('-last_accessed')[:n_resources]\n\n    @classmethod\n    def popular_resources(cls, n_resources=5, days=60, today=None):\n        \"\"\"\n        fetch the most recent n resources with which a specific user has interacted\n\n        :param n_resources: the number of resources to return.\n        :param days: the number of days to scan.\n\n        The reason for the parameter `days` is that the runtime of this method\n        is very dependent upon the days that one scans. Thus, there is a tradeoff\n        between reporting history and timely responsiveness of the dashboard.\n        \"\"\"\n        # TODO: document actions like labeling and commenting (currently these are 'visit's)\n        if today is None:\n            today = datetime.now()\n        return BaseResource.objects.filter(\n                variable__timestamp__gte=(today-timedelta(days)),\n                variable__timestamp__lt=(today),\n                variable__resource__isnull=False,\n                variable__name='visit')\\\n            .distinct()\\\n            .annotate(users=models.Count('variable__session__visitor__user'))\\\n            .annotate(public=F('raccess__public'),\n                      discoverable=F('raccess__discoverable'),\n                      published=F('raccess__published'),\n                      last_accessed=models.Max('variable__timestamp'))\\\n            .order_by('-users')[:n_resources]\n\n    @classmethod\n    def recent_users(cls, resource, n_users=5, days=60):\n        \"\"\"\n        fetch the identities of the most recent users who have accessed a resource\n\n        :param resource: The resource to document.\n        :param n_users: the number of users to return.\n        :param days: the number of days to scan.\n\n        The reason for the parameter `days` is that the runtime of this method\n        is very dependent upon the number of days that one scans. Thus, there is a\n        tradeoff between reporting history and timely responsiveness of the dashboard.\n        \"\"\"\n        return User.objects\\\n            .filter(visitor__session__variable__resource=resource,\n                    visitor__session__variable__name='visit',\n                    visitor__session__variable__timestamp__gte=(datetime.now() -\n                                                                timedelta(days)))\\\n            .distinct()\\\n            .annotate(last_accessed=models.Max('visitor__session__variable__timestamp'))\\\n            .filter(visitor__session__variable__timestamp=F('last_accessed'))\\\n            .order_by('-last_accessed')[:n_users]\n", "path": "hs_tracking/models.py"}]}