diff --git a/passbook/lib/sentry.py b/passbook/lib/sentry.py
index d119f8387..dbe24ab18 100644
--- a/passbook/lib/sentry.py
+++ b/passbook/lib/sentry.py
@@ -5,12 +5,12 @@ from celery.exceptions import CeleryError
from django.core.exceptions import DisallowedHost, ValidationError
from django.db import InternalError, OperationalError, ProgrammingError
from django_redis.exceptions import ConnectionInterrupted
+from ldap3.core.exceptions import LDAPException
from redis.exceptions import ConnectionError as RedisConnectionError
from redis.exceptions import RedisError
from rest_framework.exceptions import APIException
from structlog import get_logger
from websockets.exceptions import WebSocketException
-from ldap3.core.exceptions import LDAPException
LOGGER = get_logger()
diff --git a/passbook/sources/ldap/models.py b/passbook/sources/ldap/models.py
index 16cb14691..eb5836641 100644
--- a/passbook/sources/ldap/models.py
+++ b/passbook/sources/ldap/models.py
@@ -1,6 +1,8 @@
"""passbook LDAP Models"""
+from datetime import datetime
from typing import Optional, Type
+from django.core.cache import cache
from django.db import models
from django.forms import ModelForm
from django.utils.translation import gettext_lazy as _
@@ -8,6 +10,7 @@ from ldap3 import Connection, Server
from passbook.core.models import Group, PropertyMapping, Source
from passbook.lib.models import DomainlessURLValidator
+from passbook.lib.utils.template import render_to_string
class LDAPSource(Source):
@@ -59,6 +62,20 @@ class LDAPSource(Source):
return LDAPSourceForm
+ def state_cache_prefix(self, suffix: str) -> str:
+ """Key by which the ldap source status is saved"""
+ return f"source_ldap_{self.pk}_state_{suffix}"
+
+ @property
+ def ui_additional_info(self) -> str:
+ last_sync = cache.get(self.state_cache_prefix("last_sync"), None)
+ if last_sync:
+ last_sync = datetime.fromtimestamp(last_sync)
+
+ return render_to_string(
+ "ldap/source_list_status.html", {"source": self, "last_sync": last_sync}
+ )
+
_connection: Optional[Connection] = None
@property
diff --git a/passbook/sources/ldap/tasks.py b/passbook/sources/ldap/tasks.py
index a200258cd..69a18aed3 100644
--- a/passbook/sources/ldap/tasks.py
+++ b/passbook/sources/ldap/tasks.py
@@ -1,4 +1,8 @@
"""LDAP Sync tasks"""
+from time import time
+
+from django.core.cache import cache
+
from passbook.root.celery import CELERY_APP
from passbook.sources.ldap.connector import Connector
from passbook.sources.ldap.models import LDAPSource
@@ -14,8 +18,10 @@ def sync():
@CELERY_APP.task()
def sync_single(source_pk):
"""Sync a single source"""
- source = LDAPSource.objects.get(pk=source_pk)
+ source: LDAPSource = LDAPSource.objects.get(pk=source_pk)
connector = Connector(source)
connector.sync_users()
connector.sync_groups()
connector.sync_membership()
+ cache_key = source.state_cache_prefix("last_sync")
+ cache.set(cache_key, time(), timeout=60 * 60)
diff --git a/passbook/sources/ldap/templates/ldap/source_list_status.html b/passbook/sources/ldap/templates/ldap/source_list_status.html
new file mode 100644
index 000000000..05c187d6a
--- /dev/null
+++ b/passbook/sources/ldap/templates/ldap/source_list_status.html
@@ -0,0 +1,8 @@
+{% load humanize %}
+{% load i18n %}
+
+{% if last_sync %}
+ {% blocktrans with last_sync=last_sync|naturaltime %}Synced {{ last_sync }}.{% endblocktrans %}
+{% else %}
+ Not synced yet/Sync in Progress
+{% endif %}