[feature] show popup for version update

- added a new weekly hook to check if new version update is available
- added function to desk.js to show popup in case a new version is
available
- added redis wrappers for set related commands, namely sadd, srem,
sismember, spop, srandmember, smembers
This commit is contained in:
Ameya Shenoy 2018-08-14 15:22:25 +00:00
parent 04bc51a398
commit 21bbbd2dbb
No known key found for this signature in database
GPG key ID: AC016A555657D0A3
4 changed files with 103 additions and 1 deletions

View file

@ -153,7 +153,8 @@ scheduler_events = {
"frappe.utils.scheduler.restrict_scheduler_events_if_dormant",
"frappe.email.doctype.auto_email_report.auto_email_report.send_daily",
"frappe.core.doctype.feedback_request.feedback_request.delete_feedback_request",
"frappe.core.doctype.activity_log.activity_log.clear_authentication_logs"
"frappe.core.doctype.activity_log.activity_log.clear_authentication_logs",
"frappe.utils.change_log.check_for_update"
],
"daily_long": [
"frappe.integrations.doctype.dropbox_settings.dropbox_settings.take_backups_daily",

View file

@ -79,6 +79,8 @@ frappe.Application = Class.extend({
this.show_notes();
}
this.show_update_available();
// listen to csrf_update
frappe.realtime.on("csrf_generated", function(data) {
// handles the case when a user logs in again from another tab
@ -468,6 +470,12 @@ frappe.Application = Class.extend({
};
},
show_update_available: () => {
frappe.call({
"method": "frappe.utils.change_log.show_update_popup"
});
},
setup_analytics: function() {
if(window.mixpanel) {
window.mixpanel.identify(frappe.session.user);

View file

@ -7,6 +7,7 @@ import json, subprocess, os
from semantic_version import Version
import frappe
from frappe.utils import cstr
import requests, shlex
def get_change_log(user=None):
if not user: user = frappe.session.user
@ -124,3 +125,72 @@ def get_app_last_commit_ref(app):
shell=True).strip()[:7]
except Exception as e:
return ''
def check_for_update():
updates = frappe._dict(major=[], minor=[], patch=[])
apps = get_versions()
for app in apps:
# Check if repo remote is on github
remote_url = subprocess.check_output("cd ../apps/{} && git ls-remote --get-url".format(app), shell=True)
if "github.com" not in remote_url:
continue
# Get latest version from github
if 'https' not in remote_url:
continue
org_name = remote_url.split('/')[3]
r = requests.get('https://api.github.com/repos/{}/{}/releases'.format(org_name, app))
if r.status_code == 200 and r.json():
# 0 => latest release
github_version = Version(r.json()[0]['tag_name'].strip('v'))
else:
# In case of an improper response or if there are no releases
continue
# Get local instance's current version or the app
instance_version = Version(apps[app]['version'])
# Compare and popup update message
for update_type in updates:
if github_version.__dict__[update_type] > instance_version.__dict__[update_type]:
updates[update_type].append(frappe._dict(
current_version = str(instance_version),
available_version = str(github_version),
org_name = org_name,
app_name = app,
title = apps[app]['title'],
))
break
update_message = ""
for update_type in updates:
release_links = ""
for app in updates[update_type]:
release_links += "<a href='https://github.com/{org_name}/{app_name}/releases/tag/v{available_version}'><b>{title}</b>: v{available_version}</a><br>".format(
available_version = app.available_version,
org_name = app.org_name,
app_name = app.app_name,
title = app.title
)
if release_links:
update_message += "New {} releases for the following apps are available:<br><br>{}<hr>".format(update_type, release_links)
# "update-message" will store the update message string
# "update-user-set" will be a set of users
if update_message:
update_message += "<b>Please ask your system manager to update your instance</b>"
cache = frappe.cache()
cache.set_value("update-message", update_message)
user_list = [x.name for x in frappe.get_all("User", filters={"enabled": True})]
cache.sadd("update-user-set", *user_list)
@frappe.whitelist()
def show_update_popup():
cache = frappe.cache()
user = frappe.session.user
# Check if user is int the set of users to send update message to
if cache.sismember("update-user-set", user):
frappe.msgprint(cache.get_value("update-message"), title="New updates are available", indicator='green')
cache.srem("update-user-set", user)

View file

@ -200,4 +200,27 @@ class RedisWrapper(redis.Redis):
except redis.exceptions.ConnectionError:
return []
def sadd(self, name, *values):
"""Add a member/members to a given set"""
super(redis.Redis, self).sadd(self.make_key(name), *values)
def srem(self, name, *values):
"""Remove a specific member/list of members from the set"""
super(redis.Redis, self).srem(self.make_key(name), *values)
def sismember(self, name, value):
"""Returns True or False based on if a given value is present in the set"""
return super(redis.Redis, self).sismember(self.make_key(name), value)
def spop(self, name):
"""Removes and returns a random member from the set"""
return super(redis.Redis, self).spop(self.make_key(name))
def srandmember(self, name, count=None):
"""Returns a random member from the set"""
return super(redis.Redis, self).srandmember(self.make_key(name))
def smembers(self, name):
"""Return all members of the set"""
return super(redis.Redis, self).smembers(self.make_key(name))