diff --git a/modoboa/core/__init__.py b/modoboa/core/__init__.py
index cc91ec6c1..210c9f167 100644
--- a/modoboa/core/__init__.py
+++ b/modoboa/core/__init__.py
@@ -72,15 +72,16 @@ def check_for_new_version(request, include_all):
"""
Check if a new version of Modoboa is available.
"""
- from modoboa.core.utils import new_version_available
+ from modoboa.core.utils import check_for_updates
if not request.user.is_superuser:
return []
- if new_version_available(request) is None:
+ status, extensions = check_for_updates(request)
+ if not status:
return [{"id": "newversionavailable"}] if include_all else []
return [{
"id": "newversionavailable",
"url": reverse("core:index") + "#info/",
- "text": _("New Modoboa version available"),
+ "text": _("One or more updates are available"),
"level": "info",
}]
diff --git a/modoboa/core/extensions.py b/modoboa/core/extensions.py
index 82e5fd30e..6037c1cd8 100644
--- a/modoboa/core/extensions.py
+++ b/modoboa/core/extensions.py
@@ -3,6 +3,11 @@
from django.conf import settings
from django.conf.urls import include
+from versionfield.constants import DEFAULT_NUMBER_BITS
+from versionfield.version import Version
+
+from modoboa.lib.api_client import ModoAPIClient
+
class ModoExtension(object):
@@ -101,14 +106,29 @@ class ExtensionsPool(object):
extinstance.load()
return result
- def list_all(self):
+ def list_all(self, check_new_versions=False):
"""List all defined extensions."""
result = []
+ if check_new_versions:
+ new_extensions = ModoAPIClient().list_extensions()
+ new_extensions = dict(
+ (ext["name"], ext["version"]) for ext in new_extensions
+ )
+ else:
+ new_extensions = {}
for extname, extdef in self.extensions.iteritems():
if not extdef["show"]:
continue
infos = self.get_extension_infos(extname)
infos["id"] = extname
+ local_version = Version(infos["version"], DEFAULT_NUMBER_BITS)
+ pkgname = infos["name"].replace("_", "-")
+ if pkgname in new_extensions:
+ infos["last_version"] = new_extensions[pkgname]
+ last_version = Version(
+ new_extensions[pkgname], DEFAULT_NUMBER_BITS)
+ if last_version > local_version:
+ infos["update"] = True
result += [infos]
return sorted(result, key=lambda i: i["name"])
diff --git a/modoboa/core/templates/core/extensions.html b/modoboa/core/templates/core/extensions.html
deleted file mode 100644
index 6415135e3..000000000
--- a/modoboa/core/templates/core/extensions.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{% load i18n %}
-{% load url from future %}
-
-
{% trans "Extensions" %} {% trans "The extension(s) you are using" %}
-
-
-
- | {% trans "Name" %} |
- {% trans "Version" %} |
- {% trans "Description" %} |
-
-
-
- {% for extension in extensions %}
-
- | {{ extension.label }} |
- {{ extension.version }} |
- {{ extension.description }} |
-
- {% endfor %}
-
-
diff --git a/modoboa/core/templates/core/information.html b/modoboa/core/templates/core/information.html
index 23f6264c2..9d1fff110 100644
--- a/modoboa/core/templates/core/information.html
+++ b/modoboa/core/templates/core/information.html
@@ -1,25 +1,50 @@
{% load i18n core_tags lib_tags %}
{% trans "Information" %} {% trans "Various information about Modoboa" %}
-{% if new_version %}
+{% if update_avail %}
-
{% trans "An update is available!" %}
- {% blocktrans with version=new_version.version changelog_url=new_version.changelog_url %}
- Modoboa
{{ version }} is available for download. The list of all changes is available
here.
- {% endblocktrans %}
+
{% trans "One or more updates are available!" %}
+
{% trans "Check the following list to find the component(s) that can be updated." %}
{% endif %}
-Modoboa {% get_version %} {% trans "is currently in use." %}
+
+{% trans "Applications" %}
+
+
+
+ | {% trans "Name" %} |
+ {% trans "Installed version" %} |
+ {% trans "Last version" %} |
+ {% trans "Description" %} |
+
+
+
+ {% for extension in extensions %}
+
+ | {{ extension.label }} |
+ {{ extension.version }} |
+ {% if extension.update %}{% if extension.changelog_url %}{{ extension.last_version }}{% else %}{{ extension.last_version }}{% endif %}{% else %}{{ extension.last_version }}{% endif %} |
+ {{ extension.description }} |
+
+ {% endfor %}
+
+
{% trans "Active users" %}
-
-
- | {% trans "Name" %} |
- {% trans "Group name" %} |
- {% trans "Last login" %} |
-
- {% connected_users as users %}{% for u in users %}
- | {{ u.username }} |
- {{ u.group }} |
- {{ u.last_login }} |
-
{% endfor %}
+
+
+
+ | {% trans "Name" %} |
+ {% trans "Group name" %} |
+ {% trans "Last login" %} |
+
+
+
+ {% connected_users as users %}{% for u in users %}
+
+ | {{ u.username }} |
+ {{ u.group }} |
+ {{ u.last_login }} |
+
+ {% endfor %}
+
diff --git a/modoboa/core/templatetags/core_tags.py b/modoboa/core/templatetags/core_tags.py
index bd50c7eb7..805fa289c 100644
--- a/modoboa/core/templatetags/core_tags.py
+++ b/modoboa/core/templatetags/core_tags.py
@@ -46,11 +46,6 @@ def extensions_menu(selection, user):
@register.simple_tag
def admin_menu(selection, user):
entries = [
- {"name": "extensions",
- "class": "ajaxnav",
- "url": "extensions/",
- "label": _("Extensions"),
- "img": ""},
{"name": "info",
"class": "ajaxnav",
"url": "info/",
@@ -151,7 +146,7 @@ def visirule(field):
% (rule["field"], rule["value"])
-@register.simple_tag
+@register.assignment_tag
def get_version():
import pkg_resources
return pkg_resources.get_distribution("modoboa").version
diff --git a/modoboa/core/urls.py b/modoboa/core/urls.py
index cf03287fa..e4fba293d 100644
--- a/modoboa/core/urls.py
+++ b/modoboa/core/urls.py
@@ -15,8 +15,6 @@ urlpatterns = patterns(
name="parameter_listl"),
url(r'^core/parameters/save/$', 'modoboa.core.views.admin.saveparameters',
name="parameter_save"),
- url(r'^core/extensions/$', 'modoboa.core.views.admin.viewextensions',
- name="extension_list"),
url(r'^core/info/$', 'modoboa.core.views.admin.information',
name="information"),
url(r'^core/logs/$', 'modoboa.core.views.admin.logs', name="log_list"),
diff --git a/modoboa/core/utils.py b/modoboa/core/utils.py
index a33fb5c48..fef7450b2 100644
--- a/modoboa/core/utils.py
+++ b/modoboa/core/utils.py
@@ -1,13 +1,31 @@
"""Utility functions."""
+from django.utils.translation import ugettext as _
+
from django.contrib.sites.models import get_current_site
+from modoboa.core.extensions import exts_pool
from modoboa.lib import parameters
from modoboa.lib.api_client import ModoAPIClient
-def new_version_available(request):
+def check_for_updates(request):
"""Check if a new version of Modoboa is available."""
if parameters.get_admin("CHECK_NEW_VERSIONS") == "no":
- return None
- return ModoAPIClient().current_version(get_current_site(request))
+ return False, []
+ client = ModoAPIClient()
+ extensions = exts_pool.list_all(True)
+ extensions = [{
+ "label": "Modoboa",
+ "description": _("The core part of Modoboa"),
+ "update": client.new_core_version(get_current_site(request)),
+ "last_version": client.latest_core_version,
+ "changelog_url": client.changelog_url,
+ "version": client.local_core_version
+ }] + extensions
+ update_avail = False
+ for extension in extensions:
+ if "update" in extension:
+ update_avail = True
+ break
+ return update_avail, extensions
diff --git a/modoboa/core/views/admin.py b/modoboa/core/views/admin.py
index f1844ff76..56d0b19df 100644
--- a/modoboa/core/views/admin.py
+++ b/modoboa/core/views/admin.py
@@ -8,8 +8,9 @@ from django.shortcuts import render
from django.template.loader import render_to_string
from django.utils.translation import ugettext as _
+from modoboa.core.extensions import exts_pool
from modoboa.core.models import Log
-from modoboa.core.utils import new_version_available
+from modoboa.core.utils import check_for_updates
from modoboa.lib import events, parameters
from modoboa.lib.listing import get_sort_order, get_listing_page
from modoboa.lib.web_utils import (
@@ -51,25 +52,14 @@ def saveparameters(request):
return render_to_json_response(_("Parameters saved"))
-@login_required
-@user_passes_test(lambda u: u.is_superuser)
-def viewextensions(request, tplname='core/extensions.html'):
- """List available extensions."""
- from modoboa.core.extensions import exts_pool
-
- exts = exts_pool.list_all()
- return render_to_json_response({
- "callback": "extensions",
- "content": _render_to_string(request, tplname, {"extensions": exts})
- })
-
-
@login_required
@user_passes_test(lambda u: u.is_superuser)
def information(request, tplname="core/information.html"):
+ status, extensions = check_for_updates(request)
return render_to_json_response({
"content": render_to_string(tplname, {
- "new_version": new_version_available(request)
+ "update_avail": status,
+ "extensions": extensions,
}),
})
diff --git a/modoboa/lib/api_client.py b/modoboa/lib/api_client.py
index 19490ad83..698ce6141 100644
--- a/modoboa/lib/api_client.py
+++ b/modoboa/lib/api_client.py
@@ -22,6 +22,9 @@ class ModoAPIClient(object):
settings.MODOBOA_API_URL if api_url is None
else api_url
)
+ self._local_core_version = None
+ self._latest_core_version = None
+ self.changelog_url = None
def __send_request(self, url, params=None):
"""Send a request to the API."""
@@ -35,18 +38,34 @@ class ModoAPIClient(object):
return None
return resp.json()
- def current_version(self, site):
+ @property
+ def local_core_version(self):
+ """Return the version installed locally."""
+ if self._local_core_version is None:
+ self._local_core_version = pkg_resources.get_distribution(
+ "modoboa").version
+ return self._local_core_version
+
+ @property
+ def latest_core_version(self):
+ """Return the latest core version."""
+ if self._latest_core_version is None:
+ return self._local_core_version
+ return self._latest_core_version
+
+ def new_core_version(self, site):
"""Check the latest version."""
- client_version = pkg_resources.get_distribution("modoboa").version
url = os.path.join(self._api_url, "current_version/")
- params = {"client_version": client_version, "site": site}
+ params = {"client_version": self.local_core_version, "site": site}
resp = self.__send_request(url, params)
if resp is None:
return None
version = Version(resp["version"], DEFAULT_NUMBER_BITS)
- if version <= Version(client_version, DEFAULT_NUMBER_BITS):
- return None
- return resp
+ if version <= Version(self.local_core_version, DEFAULT_NUMBER_BITS):
+ return False
+ self._latest_core_version = resp["version"]
+ self.changelog_url = resp["changelog_url"]
+ return True
def list_extensions(self):
"""List all official extensions."""