mirror of
https://github.com/documize/community.git
synced 2025-07-29 01:59:41 +02:00
Semver based in-app news and update notification
Ignore semver.patch for Whats New notifications. Use semver.major.minor.patch for Admin notifications. Changed endpoint to /news.
This commit is contained in:
parent
8d65c2d571
commit
0b85657536
8 changed files with 715 additions and 681 deletions
|
@ -347,11 +347,8 @@ func (h *Handler) GetViewable(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := domain.GetRequestContext(r)
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
sp, err := h.Store.Space.GetViewable(ctx)
|
sp, err := h.Store.Space.GetViewable(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// response.WriteServerError(w, method, err)
|
|
||||||
h.Runtime.Log.Error(method, err)
|
h.Runtime.Log.Error(method, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
response.WriteJSON(w, sp)
|
response.WriteJSON(w, sp)
|
||||||
|
@ -369,15 +366,8 @@ func (h *Handler) GetAll(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sp, err := h.Store.Space.GetAll(ctx)
|
sp, err := h.Store.Space.GetAll(ctx)
|
||||||
|
if err != nil {
|
||||||
if err != nil && err != sql.ErrNoRows {
|
|
||||||
response.WriteServerError(w, method, err)
|
|
||||||
h.Runtime.Log.Error(method, err)
|
h.Runtime.Log.Error(method, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(sp) == 0 {
|
|
||||||
sp = []space.Space{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
response.WriteJSON(w, sp)
|
response.WriteJSON(w, sp)
|
||||||
|
|
|
@ -59,10 +59,14 @@ func (s Scope) Get(ctx domain.RequestContext, id string) (sp space.Space, err er
|
||||||
|
|
||||||
// PublicSpaces returns spaces that anyone can see.
|
// PublicSpaces returns spaces that anyone can see.
|
||||||
func (s Scope) PublicSpaces(ctx domain.RequestContext, orgID string) (sp []space.Space, err error) {
|
func (s Scope) PublicSpaces(ctx domain.RequestContext, orgID string) (sp []space.Space, err error) {
|
||||||
sql := "SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label a where orgid=? AND type=1"
|
qry := "SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label a where orgid=? AND type=1"
|
||||||
|
|
||||||
err = s.Runtime.Db.Select(&sp, sql, orgID)
|
err = s.Runtime.Db.Select(&sp, qry, orgID)
|
||||||
|
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
err = nil
|
||||||
|
sp = []space.Space{}
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, fmt.Sprintf("Unable to execute GetPublicFolders for org %s", orgID))
|
err = errors.Wrap(err, fmt.Sprintf("Unable to execute GetPublicFolders for org %s", orgID))
|
||||||
}
|
}
|
||||||
|
@ -78,7 +82,7 @@ func (s Scope) GetViewable(ctx domain.RequestContext) (sp []space.Space, err err
|
||||||
WHERE orgid=?
|
WHERE orgid=?
|
||||||
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
||||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' AND action='view' UNION ALL
|
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' AND action='view' UNION ALL
|
||||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role'
|
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role'
|
||||||
AND p.location='space' AND p.action='view' AND (r.userid=? OR r.userid='0')
|
AND p.location='space' AND p.action='view' AND (r.userid=? OR r.userid='0')
|
||||||
))
|
))
|
||||||
ORDER BY name`
|
ORDER BY name`
|
||||||
|
@ -104,13 +108,17 @@ func (s Scope) GetViewable(ctx domain.RequestContext) (sp []space.Space, err err
|
||||||
|
|
||||||
// GetAll for admin users!
|
// GetAll for admin users!
|
||||||
func (s Scope) GetAll(ctx domain.RequestContext) (sp []space.Space, err error) {
|
func (s Scope) GetAll(ctx domain.RequestContext) (sp []space.Space, err error) {
|
||||||
sql := `
|
qry := `
|
||||||
SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label
|
SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label
|
||||||
WHERE orgid=?
|
WHERE orgid=?
|
||||||
ORDER BY name`
|
ORDER BY name`
|
||||||
|
|
||||||
err = s.Runtime.Db.Select(&sp, sql, ctx.OrgID)
|
err = s.Runtime.Db.Select(&sp, qry, ctx.OrgID)
|
||||||
|
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
err = nil
|
||||||
|
sp = []space.Space{}
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, fmt.Sprintf("failed space.GetAll org %s", ctx.OrgID))
|
err = errors.Wrap(err, fmt.Sprintf("failed space.GetAll org %s", ctx.OrgID))
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ func (s Scope) Add(ctx domain.RequestContext, u user.User) (err error) {
|
||||||
u.Created = time.Now().UTC()
|
u.Created = time.Now().UTC()
|
||||||
u.Revised = time.Now().UTC()
|
u.Revised = time.Now().UTC()
|
||||||
|
|
||||||
_, err = ctx.Transaction.Exec("INSERT INTO user (refid, firstname, lastname, email, initials, password, salt, reset, lastversion, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
_, err = ctx.Transaction.Exec("INSERT INTO user (refid, firstname, lastname, email, initials, password, salt, reset, lastversion, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
u.RefID, u.Firstname, u.Lastname, strings.ToLower(u.Email), u.Initials, u.Password, u.Salt, "", u.LastVersion, u.Created, u.Revised)
|
u.RefID, u.Firstname, u.Lastname, strings.ToLower(u.Email), u.Initials, u.Password, u.Salt, "", u.LastVersion, u.Created, u.Revised)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -25,7 +25,7 @@ export default Component.extend({
|
||||||
let self = this;
|
let self = this;
|
||||||
let cacheBuster = + new Date();
|
let cacheBuster = + new Date();
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: `https://storage.googleapis.com/documize/downloads/updates/summary.html?cb=${cacheBuster}`,
|
url: `https://storage.googleapis.com/documize/news/summary.html?cb=${cacheBuster}`,
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
dataType: 'html',
|
dataType: 'html',
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
|
|
|
@ -48,7 +48,7 @@ export default Component.extend(ModalMixin, {
|
||||||
let self = this;
|
let self = this;
|
||||||
let cacheBuster = + new Date();
|
let cacheBuster = + new Date();
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: `https://storage.googleapis.com/documize/downloads/updates/${version}.html?cb=${cacheBuster}`,
|
url: `https://storage.googleapis.com/documize/news/${version}.html?cb=${cacheBuster}`,
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
dataType: 'html',
|
dataType: 'html',
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import $ from 'jquery';
|
||||||
import { htmlSafe } from '@ember/string';
|
import { htmlSafe } from '@ember/string';
|
||||||
import { resolve } from 'rsvp';
|
import { resolve } from 'rsvp';
|
||||||
import Service, { inject as service } from '@ember/service';
|
import Service, { inject as service } from '@ember/service';
|
||||||
|
import miscUtil from '../utils/misc';
|
||||||
import config from '../config/environment';
|
import config from '../config/environment';
|
||||||
import constants from '../utils/constants';
|
import constants from '../utils/constants';
|
||||||
|
|
||||||
|
@ -28,6 +29,9 @@ export default Service.extend({
|
||||||
version: '',
|
version: '',
|
||||||
message: '',
|
message: '',
|
||||||
edition: 'Community',
|
edition: 'Community',
|
||||||
|
// for major.minor semver release detection
|
||||||
|
// for bugfix releases, only admin is made aware of new release and end users see no Whats New messaging
|
||||||
|
updateAvailable: false,
|
||||||
valid: true,
|
valid: true,
|
||||||
allowAnonymousAccess: false,
|
allowAnonymousAccess: false,
|
||||||
authProvider: constants.AuthProvider.Documize,
|
authProvider: constants.AuthProvider.Documize,
|
||||||
|
@ -80,7 +84,7 @@ export default Service.extend({
|
||||||
|
|
||||||
let self = this;
|
let self = this;
|
||||||
let cacheBuster = + new Date();
|
let cacheBuster = + new Date();
|
||||||
$.getJSON(`https://storage.googleapis.com/documize/downloads/updates/meta.json?cb=${cacheBuster}`, function (versions) {
|
$.getJSON(`https://storage.googleapis.com/documize/news/meta.json?cb=${cacheBuster}`, function (versions) {
|
||||||
let cv = 'v' + versions.community.version;
|
let cv = 'v' + versions.community.version;
|
||||||
let ev = 'v' + versions.enterprise.version;
|
let ev = 'v' + versions.enterprise.version;
|
||||||
let re = self.get('edition');
|
let re = self.get('edition');
|
||||||
|
@ -90,12 +94,11 @@ export default Service.extend({
|
||||||
self.set('enterpriseLatest', ev);
|
self.set('enterpriseLatest', ev);
|
||||||
self.set('updateAvailable', false); // set to true for testing
|
self.set('updateAvailable', false); // set to true for testing
|
||||||
|
|
||||||
if (re === 'Community' && rv < cv) {
|
let isNewCommunity = miscUtil.isNewVersion(rv, cv, true);
|
||||||
self.set('updateAvailable', true);
|
let isNewEnterprise = miscUtil.isNewVersion(rv, ev, true);
|
||||||
}
|
|
||||||
if (re === 'Enterprise' && rv < ev) {
|
if (re === 'Community' && isNewCommunity) self.set('updateAvailable', true);
|
||||||
self.set('updateAvailable', true);
|
if (re === 'Enterprise' && isNewEnterprise) self.set('updateAvailable', true);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
|
|
@ -61,8 +61,41 @@ function insertAtCursor(myField, myValue) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expects to receive semver version strings like "1.2.3" or "v1.2.3".
|
||||||
|
function isNewVersion(v1, v2, compareRevision) {
|
||||||
|
// Remove any "v" from version strings.
|
||||||
|
v1 = v1.replace('v', '');
|
||||||
|
v2 = v2.replace('v', '');
|
||||||
|
|
||||||
|
// Clean up strings.
|
||||||
|
v1 = v1.trim().toLowerCase();
|
||||||
|
v2 = v2.trim().toLowerCase();
|
||||||
|
|
||||||
|
// Format expected is "1.2.3".
|
||||||
|
let v1parts = v1.split('.');
|
||||||
|
let v2parts = v2.split('.');
|
||||||
|
|
||||||
|
// Must be 3+ parts per version string supporting
|
||||||
|
// v1.2.3 and v.1.2.3.beta1
|
||||||
|
if (v1parts.length < 3) return false;
|
||||||
|
if (v2parts.length < 3) return false;
|
||||||
|
|
||||||
|
// Compare Major and Minor verson parts.
|
||||||
|
if (v2parts[0] > v1parts[0]) return true;
|
||||||
|
if (v2parts[0] === v1parts[0] && v2parts[1] > v1parts[1]) return true;
|
||||||
|
|
||||||
|
if (compareRevision) {
|
||||||
|
if (v2parts[0] === v1parts[0] &&
|
||||||
|
v2parts[1] === v1parts[1] &&
|
||||||
|
v2parts[2] > v1parts[2]) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
interval,
|
interval,
|
||||||
wrapFunction,
|
wrapFunction,
|
||||||
insertAtCursor
|
insertAtCursor,
|
||||||
|
isNewVersion
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue