Repository: learningequality/kolibri

Issue:
Sync status as 'Never synced' on Linux
<!--
Instructions:
 * Fill out the sections below, replace …'s with information about your issue
 * Use the 'preview' function above this text box to verify formatting before submitting
-->

### Observed behavior
<!--
Description of the behavior that was observed, including screenshots or other references when applicable
-->

The sync status is always `Never synced` on Linux systems whereas it shows the correct status on Windows.

![sync_status](https://user-images.githubusercontent.com/2577060/89064334-71b5b180-d387-11ea-9df9-75cbaa6c7775.gif)

### Expected behavior
<!--
Description of what behavior was expected but did not occur
-->

Correct sync status should be visible as it is on Windows -

![image](https://user-images.githubusercontent.com/2577060/89064522-c48f6900-d387-11ea-8984-b875df9503c4.png)


### User-facing consequences
<!--
Implications and real-world consequences for learners, coaches, admins, and other users of the application
-->

Confusion and misinformation.

### Errors and logs
<!--
Relevant logs from:
 * the command line
 * ~/.kolibri/logs/kolibri.txt
 * the browser console

Please wrap errors in triple backticks for clean formatting like this:
```
01:10 info: something happened
01:12 error: something bad happened
```
-->

No errors visible in logs.

However, I do notice this every time I start Kolibri -
```
Jul 31 23:51:24 myscoolserver kolibri-server[18533]: /usr/lib/python3/dist-packages/kolibri/dist/tzlocal/unix.py:108: SyntaxWarning: "is not" with a literal. Did you mean "!="?
Jul 31 23:51:24 myscoolserver kolibri-server[18533]:   while start is not 0:
Jul 31 23:51:25 myscoolserver kolibri-server[18533]: /usr/lib/python3/dist-packages/kolibri/dist/rest_framework/utils/serializer_helpers.py:107: SyntaxWarning: "is" with a literal. Did you mean "=="?
Jul 31 23:51:25 myscoolserver kolibri-server[18533]:   if value is None or value is '':
```

Not sure if this may be related.

Not sure if this could be related.

### Steps to reproduce
<!--
Precise steps that someone else can follow in order to see this behavior
-->

Initiate a sync from Linux based Kolibri installation.

### Context
<!--
Tell us about your environment, including:
 * Kolibri version
 * Operating system
 * Browser
-->

Linux based installations :
```
Version:           0.14.0b15
OS:                Linux-5.4.0-42-generic-x86_64-with-glibc2.29
Python:            3.8.2
Installer:         kolibri(apt) with kolibri-server Version: 0.3.8~beta2-0ubuntu1
Server:            nginx/1.18.0 (Ubuntu)
Database:          postgresql
```

```
Version:           0.14.0b15
OS:                Linux-5.4.0-1015-raspi-aarch64-with-glibc2.29
Python:            3.8.2
Installer:         kolibri(apt) with kolibri-server Version: 0.3.8~beta2-0ubuntu1
Server:            nginx/1.18.0 (Ubuntu)
Database:          postgresql
```

Windows : 

```
Version:           0.14.0b15
OS:                Windows-10-10.0.18362-SP0
Python:            3.6.8
Installer:         Windows
Server:            Kolibri internal server
Database:          C:\Users\SHRENIK BHURA\.kolibri\db.sqlite3
```


Discussion:
This is a guess, but the errors in Linux related to the `tzlocal/unix.py` library might be related to the incorrect syncing information, since the `last_synced` field on `FacilityViewset` (which underlies the data on these screenshots) depends on interpreting and sorting by DateTimes

https://github.com/learningequality/kolibri/blob/5cd3b24230c6a360e96fd0faed19f108c9faf83e/kolibri/core/auth/api.py#L357-L365
Solved with #7428 
@jredrejo Upgraded to 0.14.0b16 but the status displayed is still 'Never sycned'. 

What do I need to do different to test this reliably or what further information I may furnish to help replicate this at your end?
Can you give exact instructions to reproduce it?
i.e. what are the steps you doing in both servers and versions you have on them?

1. Login as superuser
2. Navigate to `Devices` -> `Facilities`
3. Execute `Sync` for any facility added therein
4. Sync completes and shows when clicked on `View Task Manager` but below the facility name it always shows as `Never synced` (as given in the gif above)

@jredrejo forgot to mention that kolibri version on both source and destination devices is now 0.14.0b16.
@jredrejo The status is working correctly for systems updated from 0.13.3 to 0.14.0 and now even to 0.14.1.

But it is still broken on 3 systems which had this upgrade path - 0.13.3 to 0.14.b{14,15,16,rc1} to 0.14.0 and 0.14.1.

What could we try to remove / change to get it working on the later systems?
This has nothing to do with upgrade path. This happens on fresh install using **postgres database**. Shows correct status when sqlite is used.
@intelliant01 I'm trying to reproduce this issue without success. I have tried the upgrade path you mentioned above and it works for me in Linux (I have even tested kolibri in one machine against kolibri-server in the other).
Could the problem be related to postgres as @cyberorg mentioned or are you still to reproduce it in sqlite?
It is related to a fresh install on Postgres. Sorry, Cyberorg is my teammate, hence I did not reconfirm on his comment.

Resolving patch:
diff --git a/kolibri/core/auth/api.py b/kolibri/core/auth/api.py
--- a/kolibri/core/auth/api.py
+++ b/kolibri/core/auth/api.py
@@ -15,10 +15,12 @@
 from django.contrib.auth.models import AnonymousUser
 from django.core.exceptions import ObjectDoesNotExist
 from django.db import transaction
+from django.db.models import Func
 from django.db.models import OuterRef
 from django.db.models import Q
 from django.db.models import Subquery
 from django.db.models import TextField
+from django.db.models import Value
 from django.db.models.functions import Cast
 from django.db.models.query import F
 from django.http import Http404
@@ -355,7 +357,13 @@ def annotate_queryset(self, queryset):
             .annotate(
                 last_synced=Subquery(
                     TransferSession.objects.filter(
-                        filter=Cast(OuterRef("dataset"), TextField())
+                        filter=Func(
+                            Cast(OuterRef("dataset"), TextField()),
+                            Value("-"),
+                            Value(""),
+                            function="replace",
+                            output_field=TextField(),
+                        )
                     )
                     .order_by("-last_activity_timestamp")
                     .values("last_activity_timestamp")


Test patch: