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" %}


- - - - - - - - - - {% for extension in extensions %} - - - - - - {% endfor %} - -
{% trans "Name" %}{% trans "Version" %}{% trans "Description" %}
{{ extension.label }}{{ extension.version }}{{ extension.description }}
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" %}

+ + + + + + + + + + + {% for extension in extensions %} + + + + + + + {% endfor %} + +
{% trans "Name" %}{% trans "Installed version" %}{% trans "Last version" %}{% trans "Description" %}
{{ 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 }}

{% trans "Active users" %}

- - - - - - - {% connected_users as users %}{% for u in users %} - - - - {% endfor %} +
{% trans "Name" %}{% trans "Group name" %}{% trans "Last login" %}
{{ u.username }}{{ u.group }}{{ u.last_login }}
+ + + + + + + + + {% connected_users as users %}{% for u in users %} + + + + + + {% endfor %} +
{% trans "Name" %}{% trans "Group name" %}{% trans "Last login" %}
{{ u.username }}{{ u.group }}{{ u.last_login }}
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."""