mirror of
https://github.com/documize/community.git
synced 2025-08-04 13:05:23 +02:00
commit
e0e6aeb021
37 changed files with 414 additions and 333 deletions
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
|
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
|
||||||
|
import { isNotFoundError } from 'ember-ajax/errors';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isPresent
|
isPresent
|
||||||
|
@ -31,20 +32,23 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
|
||||||
|
|
||||||
if (is.empty(params)) {
|
if (is.empty(params)) {
|
||||||
let lastFolder = this.get('localStorage').getSessionItem("folder");
|
let lastFolder = this.get('localStorage').getSessionItem("folder");
|
||||||
|
let self = this;
|
||||||
|
|
||||||
//If folder lastFolder is defined
|
//If folder lastFolder is defined
|
||||||
if (isPresent(lastFolder)) {
|
if (isPresent(lastFolder)) {
|
||||||
return this.get('folderService').getFolder(lastFolder).then((folder) => {
|
return this.get('folderService').getFolder(lastFolder).then((folder) => {
|
||||||
//if Response is null or undefined redirect to login else transitionTo dashboard
|
//if Response is null or undefined redirect to login else transitionTo dashboard
|
||||||
if (Ember.isNone(folder)) {
|
if (Ember.isNone(folder)) {
|
||||||
this.transitionTo('auth.login');
|
self.get('localStorage').clearSessionItem("folder");
|
||||||
|
this.transitionTo('application');
|
||||||
}
|
}
|
||||||
|
|
||||||
Ember.set(this, 'folder', folder);
|
Ember.set(this, 'folder', folder);
|
||||||
this.transitionTo('folders.folder', folder.get('id'), folder.get('slug'));
|
this.transitionTo('folders.folder', folder.get('id'), folder.get('slug'));
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
//if there was an error redirect to login
|
//if there was an error redirect to login
|
||||||
this.transitionTo('auth.login');
|
self.get('localStorage').clearSessionItem("folder");
|
||||||
|
this.transitionTo('application');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,11 +68,16 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
|
||||||
|
|
||||||
//If folder route has params
|
//If folder route has params
|
||||||
if (isPresent(params)) {
|
if (isPresent(params)) {
|
||||||
|
let self = this;
|
||||||
let folderId = this.paramsFor('folders.folder').folder_id;
|
let folderId = this.paramsFor('folders.folder').folder_id;
|
||||||
|
|
||||||
return this.get('folderService').getFolder(folderId).then((folder) => {
|
return this.get('folderService').getFolder(folderId).then((folder) => {
|
||||||
Ember.set(this, 'folder', folder);
|
Ember.set(this, 'folder', folder);
|
||||||
|
}).catch(function (error) {
|
||||||
|
if (isNotFoundError(error)) {
|
||||||
|
// handle 404 errors here
|
||||||
|
self.transitionTo('application');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,6 @@ export default Ember.Route.extend({
|
||||||
if (pwd.length === 0 || pwd === "{{.DBhash}}") {
|
if (pwd.length === 0 || pwd === "{{.DBhash}}") {
|
||||||
this.transitionTo('auth.login'); // don't allow access to this page if we are not in setup mode, kick them out altogether
|
this.transitionTo('auth.login'); // don't allow access to this page if we are not in setup mode, kick them out altogether
|
||||||
}
|
}
|
||||||
|
|
||||||
this.session.clearSession();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
model() {
|
model() {
|
||||||
|
|
|
@ -20,6 +20,7 @@ const {
|
||||||
|
|
||||||
export default Ember.Service.extend({
|
export default Ember.Service.extend({
|
||||||
ajax: service(),
|
ajax: service(),
|
||||||
|
localStorage: service(),
|
||||||
|
|
||||||
endpoint: `${config.apiHost}/${config.apiNamespace}`,
|
endpoint: `${config.apiHost}/${config.apiNamespace}`,
|
||||||
orgId: '',
|
orgId: '',
|
||||||
|
@ -27,6 +28,7 @@ export default Ember.Service.extend({
|
||||||
version: '',
|
version: '',
|
||||||
message: '',
|
message: '',
|
||||||
allowAnonymousAccess: false,
|
allowAnonymousAccess: false,
|
||||||
|
setupMode: false,
|
||||||
|
|
||||||
getBaseUrl(endpoint) {
|
getBaseUrl(endpoint) {
|
||||||
return [this.get('host'), endpoint].join('/');
|
return [this.get('host'), endpoint].join('/');
|
||||||
|
@ -40,12 +42,14 @@ export default Ember.Service.extend({
|
||||||
|
|
||||||
let isInSetupMode = dbhash && dbhash !== "{{.DBhash}}";
|
let isInSetupMode = dbhash && dbhash !== "{{.DBhash}}";
|
||||||
if (isInSetupMode) {
|
if (isInSetupMode) {
|
||||||
this.setProperites({
|
this.setProperties({
|
||||||
title: htmlSafe("Documize Setup"),
|
title: htmlSafe("Documize Setup"),
|
||||||
allowAnonymousAccess: false
|
allowAnonymousAccess: true,
|
||||||
|
setupMode: true
|
||||||
});
|
});
|
||||||
|
this.get('localStorage').clearAll();
|
||||||
|
|
||||||
return resolve();
|
return resolve(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.get('ajax').request('public/meta').then((response) => {
|
return this.get('ajax').request('public/meta').then((response) => {
|
||||||
|
|
|
@ -14,194 +14,193 @@ import models from '../utils/model';
|
||||||
import BaseService from '../services/base';
|
import BaseService from '../services/base';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
get
|
get
|
||||||
} = Ember;
|
} = Ember;
|
||||||
|
|
||||||
export default BaseService.extend({
|
export default BaseService.extend({
|
||||||
sessionService: Ember.inject.service('session'),
|
sessionService: Ember.inject.service('session'),
|
||||||
ajax: Ember.inject.service(),
|
ajax: Ember.inject.service(),
|
||||||
localStorage: Ember.inject.service(),
|
localStorage: Ember.inject.service(),
|
||||||
|
|
||||||
|
// selected folder
|
||||||
|
currentFolder: null,
|
||||||
|
canEditCurrentFolder: false,
|
||||||
|
|
||||||
// selected folder
|
// Add a new folder.
|
||||||
currentFolder: null,
|
add(folder) {
|
||||||
canEditCurrentFolder: false,
|
|
||||||
|
|
||||||
// Add a new folder.
|
return this.get('ajax').post(`folders`, {
|
||||||
add(folder) {
|
contentType: 'json',
|
||||||
|
data: JSON.stringify(folder)
|
||||||
|
}).then((folder) => {
|
||||||
|
let folderModel = models.FolderModel.create(folder);
|
||||||
|
return folderModel;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
return this.get('ajax').post(`folders`, {
|
// Returns folder model for specified folder id.
|
||||||
contentType: 'json',
|
getFolder(id) {
|
||||||
data: JSON.stringify(folder)
|
|
||||||
}).then((folder)=>{
|
|
||||||
let folderModel = models.FolderModel.create(folder);
|
|
||||||
return folderModel;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// Returns folder model for specified folder id.
|
return this.get('ajax').request(`folders/${id}`, {
|
||||||
getFolder(id) {
|
method: 'GET'
|
||||||
|
}).then((response) => {
|
||||||
|
let folder = models.FolderModel.create(response);
|
||||||
|
return folder;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
return this.get('ajax').request(`folders/${id}`, {
|
// Returns all folders that user can see.
|
||||||
method: 'GET'
|
getAll() {
|
||||||
}).then((response)=>{
|
let self = this;
|
||||||
let folder = models.FolderModel.create(response);
|
|
||||||
return folder;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// Returns all folders that user can see.
|
if (this.get('folders') != null) {
|
||||||
getAll() {
|
return new Ember.RSVP.Promise(function (resolve) {
|
||||||
let self = this;
|
resolve(self.get('folders'));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return this.reload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
if (this.get('folders') != null) {
|
// Updates an existing folder record.
|
||||||
return new Ember.RSVP.Promise(function(resolve) {
|
save(folder) {
|
||||||
resolve(self.get('folders'));
|
let id = folder.get('id');
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return this.reload();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Updates an existing folder record.
|
return this.get('ajax').request(`folders/${id}`, {
|
||||||
save(folder) {
|
method: 'PUT',
|
||||||
let id = folder.get('id');
|
contentType: 'json',
|
||||||
|
data: JSON.stringify(folder)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
return this.get('ajax').request(`folders/${id}`, {
|
remove: function (folderId, moveToId) {
|
||||||
method: 'PUT',
|
let url = `folders/${folderId}/move/${moveToId}`;
|
||||||
contentType: 'json',
|
|
||||||
data: JSON.stringify(folder)
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
remove: function(folderId, moveToId) {
|
return this.get('ajax').request(url, {
|
||||||
let url = `folders/${folderId}/move/${moveToId}`;
|
method: 'DELETE'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
return this.get('ajax').request(url, {
|
onboard: function (folderId, payload) {
|
||||||
method: 'DELETE'
|
let url = `public/share/${folderId}`;
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onboard: function(folderId, payload) {
|
return this.get('ajax').post(url, {
|
||||||
let url = `public/share/${folderId}`;
|
contentType: "application/json",
|
||||||
|
data: payload
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
return this.get('ajax').post(url, {
|
// getProtectedFolderInfo returns non-private folders and who has access to them.
|
||||||
contentType: "application/json",
|
getProtectedFolderInfo: function () {
|
||||||
data: payload
|
return this.get('ajax').request(`folders?filter=viewers`, {
|
||||||
});
|
method: "GET"
|
||||||
},
|
}).then((response) => {
|
||||||
|
let data = [];
|
||||||
|
_.each(response, function (obj) {
|
||||||
|
data.pushObject(models.ProtectedFolderParticipant.create(obj));
|
||||||
|
});
|
||||||
|
|
||||||
// getProtectedFolderInfo returns non-private folders and who has access to them.
|
return data;
|
||||||
getProtectedFolderInfo: function() {
|
});
|
||||||
return this.get('ajax').request(`folders?filter=viewers`, {
|
},
|
||||||
method: "GET"
|
|
||||||
}).then((response)=>{
|
|
||||||
let data = [];
|
|
||||||
_.each(response, function(obj) {
|
|
||||||
data.pushObject(models.ProtectedFolderParticipant.create(obj));
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
// reloads and caches folders.
|
||||||
});
|
reload() {
|
||||||
},
|
|
||||||
|
|
||||||
// reloads and caches folders.
|
return this.get('ajax').request(`folders`, {
|
||||||
reload() {
|
method: "GET"
|
||||||
|
}).then((response) => {
|
||||||
|
let data = [];
|
||||||
|
_.each(response, function (obj) {
|
||||||
|
data.pushObject(models.FolderModel.create(obj));
|
||||||
|
});
|
||||||
|
|
||||||
return this.get('ajax').request(`folders`, {
|
return data;
|
||||||
method: "GET"
|
});
|
||||||
}).then((response)=>{
|
},
|
||||||
let data = [];
|
|
||||||
_.each(response, function(obj) {
|
|
||||||
data.pushObject(models.FolderModel.create(obj));
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
// so who can see/edit this folder?
|
||||||
});
|
getPermissions(folderId) {
|
||||||
},
|
|
||||||
|
|
||||||
// so who can see/edit this folder?
|
return this.get('ajax').request(`folders/${folderId}/permissions`, {
|
||||||
getPermissions(folderId) {
|
method: "GET"
|
||||||
|
}).then((response) => {
|
||||||
|
let data = [];
|
||||||
|
_.each(response, function (obj) {
|
||||||
|
data.pushObject(models.FolderPermissionModel.create(obj));
|
||||||
|
});
|
||||||
|
|
||||||
return this.get('ajax').request(`folders/${folderId}/permissions`, {
|
return data;
|
||||||
method: "GET"
|
});
|
||||||
}).then((response)=>{
|
},
|
||||||
let data = [];
|
|
||||||
_.each(response, function(obj) {
|
|
||||||
data.pushObject(models.FolderPermissionModel.create(obj));
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
// persist folder permissions
|
||||||
});
|
savePermissions(folderId, payload) {
|
||||||
},
|
|
||||||
|
|
||||||
// persist folder permissions
|
return this.get('ajax').request(`folders/${folderId}/permissions`, {
|
||||||
savePermissions(folderId, payload) {
|
method: 'PUT',
|
||||||
|
contentType: 'json',
|
||||||
|
data: JSON.stringify(payload)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
return this.get('ajax').request(`folders/${folderId}/permissions`, {
|
// share this folder with new users!
|
||||||
method: 'PUT',
|
share(folderId, invitation) {
|
||||||
contentType: 'json',
|
|
||||||
data: JSON.stringify(payload)
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// share this folder with new users!
|
return this.get('ajax').post(`folders/${folderId}/invitation`, {
|
||||||
share(folderId, invitation) {
|
contentType: 'json',
|
||||||
|
data: JSON.stringify(invitation)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
return this.get('ajax').post(`folders/${folderId}/invitation`, {
|
// Current folder caching
|
||||||
contentType: 'json',
|
setCurrentFolder(folder) {
|
||||||
data: JSON.stringify(invitation)
|
if (is.undefined(folder) || is.null(folder)) {
|
||||||
});
|
return;
|
||||||
},
|
}
|
||||||
|
|
||||||
// Current folder caching
|
this.set('currentFolder', folder);
|
||||||
setCurrentFolder(folder) {
|
this.get('localStorage').storeSessionItem("folder", get(folder, 'id'));
|
||||||
if (is.undefined(folder) || is.null(folder)) {
|
this.set('canEditCurrentFolder', false);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.set('currentFolder', folder);
|
let userId = this.get('sessionService.user.id');
|
||||||
this.get('localStorage').storeSessionItem("folder", get(folder, 'id'));
|
if (userId === "") {
|
||||||
this.set('canEditCurrentFolder', false);
|
userId = "0";
|
||||||
|
}
|
||||||
|
|
||||||
let userId = this.get('sessionService.user.id');
|
let url = `users/${userId}/permissions`;
|
||||||
if (userId === "") {
|
|
||||||
userId = "0";
|
|
||||||
}
|
|
||||||
|
|
||||||
let url = `users/${userId}/permissions`;
|
return this.get('ajax').request(url).then((folderPermissions) => {
|
||||||
|
// safety check
|
||||||
|
this.set('canEditCurrentFolder', false);
|
||||||
|
|
||||||
return this.get('ajax').request(url).then((folderPermissions) => {
|
if (folderPermissions.length === 0) {
|
||||||
// safety check
|
return;
|
||||||
this.set('canEditCurrentFolder', false);
|
}
|
||||||
|
|
||||||
if (folderPermissions.length === 0) {
|
let result = [];
|
||||||
return;
|
let folderId = folder.get('id');
|
||||||
}
|
|
||||||
|
|
||||||
let result = [];
|
folderPermissions.forEach(function (item) {
|
||||||
let folderId = folder.get('id');
|
if (item.folderId === folderId) {
|
||||||
|
result.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
folderPermissions.forEach(function(item) {
|
let canEdit = false;
|
||||||
if (item.folderId === folderId) {
|
|
||||||
result.push(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let canEdit = false;
|
result.forEach(function (permission) {
|
||||||
|
if (permission.userId === userId) {
|
||||||
|
canEdit = permission.canEdit;
|
||||||
|
}
|
||||||
|
|
||||||
result.forEach(function(permission) {
|
if (permission.userId === "" && !canEdit) {
|
||||||
if (permission.userId === userId) {
|
canEdit = permission.canEdit;
|
||||||
canEdit = permission.canEdit;
|
}
|
||||||
}
|
});
|
||||||
|
Ember.run(() => {
|
||||||
if (permission.userId === "" && !canEdit) {
|
this.set('canEditCurrentFolder', canEdit && this.get('sessionService.authenticated'));
|
||||||
canEdit = permission.canEdit;
|
});
|
||||||
}
|
});
|
||||||
});
|
},
|
||||||
Ember.run(() => {
|
|
||||||
this.set('canEditCurrentFolder', canEdit && this.get('sessionService.authenticated'));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
});
|
|
@ -22,5 +22,9 @@ export default Ember.Service.extend({
|
||||||
|
|
||||||
clearSessionItem: function (key) {
|
clearSessionItem: function (key) {
|
||||||
delete localStorage[key];
|
delete localStorage[key];
|
||||||
|
},
|
||||||
|
|
||||||
|
clearAll() {
|
||||||
|
localStorage.clear();
|
||||||
}
|
}
|
||||||
});
|
});
|
2
build.sh
2
build.sh
|
@ -37,7 +37,7 @@ go generate
|
||||||
|
|
||||||
echo "Compiling app..."
|
echo "Compiling app..."
|
||||||
cd ../..
|
cd ../..
|
||||||
for arch in amd64 386 ; do
|
for arch in amd64 ; do
|
||||||
for os in darwin linux windows ; do
|
for os in darwin linux windows ; do
|
||||||
if [ "$os" == "windows" ] ; then
|
if [ "$os" == "windows" ] ; then
|
||||||
echo "Compiling documize-$os-$arch.exe"
|
echo "Compiling documize-$os-$arch.exe"
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/documize/community/documize/api/request"
|
"github.com/documize/community/documize/api/request"
|
||||||
"github.com/documize/community/documize/api/util"
|
"github.com/documize/community/documize/api/util"
|
||||||
"github.com/documize/community/documize/section/provider"
|
"github.com/documize/community/documize/section/provider"
|
||||||
|
"github.com/documize/community/documize/web"
|
||||||
"github.com/documize/community/wordsmith/environment"
|
"github.com/documize/community/wordsmith/environment"
|
||||||
"github.com/documize/community/wordsmith/log"
|
"github.com/documize/community/wordsmith/log"
|
||||||
"github.com/documize/community/wordsmith/utility"
|
"github.com/documize/community/wordsmith/utility"
|
||||||
|
@ -293,7 +294,8 @@ func preAuthorizeStaticAssets(r *http.Request) bool {
|
||||||
strings.ToLower(r.URL.Path) == "/favicon.ico" ||
|
strings.ToLower(r.URL.Path) == "/favicon.ico" ||
|
||||||
strings.ToLower(r.URL.Path) == "/robots.txt" ||
|
strings.ToLower(r.URL.Path) == "/robots.txt" ||
|
||||||
strings.ToLower(r.URL.Path) == "/version" ||
|
strings.ToLower(r.URL.Path) == "/version" ||
|
||||||
strings.HasPrefix(strings.ToLower(r.URL.Path), "/api/public/") {
|
strings.HasPrefix(strings.ToLower(r.URL.Path), "/api/public/") ||
|
||||||
|
((web.SiteMode == web.SiteModeSetup) && (strings.ToLower(r.URL.Path) == "/api/setup")) {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,10 @@ func buildUnsecureRoutes() *mux.Router {
|
||||||
func buildSecureRoutes() *mux.Router {
|
func buildSecureRoutes() *mux.Router {
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
|
|
||||||
|
if web.SiteMode == web.SiteModeSetup {
|
||||||
|
router.HandleFunc("/api/setup", database.Create).Methods("POST", "OPTIONS")
|
||||||
|
}
|
||||||
|
|
||||||
// Import & Convert Document
|
// Import & Convert Document
|
||||||
router.HandleFunc("/api/import/folder/{folderID}", UploadConvertDocument).Methods("POST", "OPTIONS")
|
router.HandleFunc("/api/import/folder/{folderID}", UploadConvertDocument).Methods("POST", "OPTIONS")
|
||||||
|
|
||||||
|
@ -254,7 +258,6 @@ func AppRouter() *mux.Router {
|
||||||
log.Info("Serving OFFLINE web app")
|
log.Info("Serving OFFLINE web app")
|
||||||
case web.SiteModeSetup:
|
case web.SiteModeSetup:
|
||||||
log.Info("Serving SETUP web app")
|
log.Info("Serving SETUP web app")
|
||||||
router.HandleFunc("/setup", database.Create).Methods("POST", "OPTIONS")
|
|
||||||
case web.SiteModeBadDB:
|
case web.SiteModeBadDB:
|
||||||
log.Info("Serving BAD DATABASE web app")
|
log.Info("Serving BAD DATABASE web app")
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
package request
|
package request
|
||||||
|
|
||||||
/* TODO(Elliott)
|
/* TODO(Elliott)
|
||||||
import (
|
import (
|
||||||
"github.com/documize/community/documize/api/entity"
|
"github.com/documize/community/documize/api/entity"
|
||||||
|
|
|
@ -67,6 +67,29 @@ func ConfigString(area, path string) (ret string) {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConfigSet writes a configuration JSON element to the config table.
|
||||||
|
func ConfigSet(area, json string) error {
|
||||||
|
if Db == nil {
|
||||||
|
return errors.New("no database")
|
||||||
|
}
|
||||||
|
if area == "" {
|
||||||
|
return errors.New("no area")
|
||||||
|
}
|
||||||
|
sql := "INSERT INTO `config` (`key`,`config`) " +
|
||||||
|
"VALUES ('" + area + "','" + json +
|
||||||
|
"') ON DUPLICATE KEY UPDATE `config`='" + json + "';"
|
||||||
|
|
||||||
|
stmt, err := Db.Preparex(sql)
|
||||||
|
if err != nil {
|
||||||
|
//fmt.Printf("DEBUG: Unable to prepare select SQL for ConfigSet: %s -- error: %v\n", sql, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer utility.Close(stmt)
|
||||||
|
|
||||||
|
_, err = stmt.Exec()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// UserConfigGetJSON fetches a configuration JSON element from the userconfig table for a given orgid/userid combination.
|
// UserConfigGetJSON fetches a configuration JSON element from the userconfig table for a given orgid/userid combination.
|
||||||
// Errors return the empty string. A blank path returns the whole JSON object, as JSON.
|
// Errors return the empty string. A blank path returns the whole JSON object, as JSON.
|
||||||
func UserConfigGetJSON(orgid, userid, area, path string) (ret string) {
|
func UserConfigGetJSON(orgid, userid, area, path string) (ret string) {
|
||||||
|
@ -124,6 +147,6 @@ func UserConfigSetJSON(orgid, userid, area, json string) error {
|
||||||
}
|
}
|
||||||
defer utility.Close(stmt)
|
defer utility.Close(stmt)
|
||||||
|
|
||||||
_,err= stmt.Exec()
|
_, err = stmt.Exec()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
package request
|
package request
|
||||||
|
|
||||||
/* TODO(Elliott)
|
/* TODO(Elliott)
|
||||||
import (
|
import (
|
||||||
"github.com/documize/community/wordsmith/environment"
|
"github.com/documize/community/wordsmith/environment"
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
package request
|
package request
|
||||||
|
|
||||||
/* TODO(Elliott)
|
/* TODO(Elliott)
|
||||||
import (
|
import (
|
||||||
"github.com/documize/community/documize/api/entity"
|
"github.com/documize/community/documize/api/entity"
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
package request
|
package request
|
||||||
|
|
||||||
/* TODO(Elliott)
|
/* TODO(Elliott)
|
||||||
import "testing"
|
import "testing"
|
||||||
import "net/http"
|
import "net/http"
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
package request
|
package request
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -69,18 +68,8 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// go into setup mode if required
|
// go into setup mode if required
|
||||||
if database.Check(Db, connectionString,
|
if database.Check(Db, connectionString) {
|
||||||
func() (bool, error) {
|
if err := database.Migrate(true /* the config table exists */); err != nil {
|
||||||
// LockDB locks the database for migrations, returning if locked and an error.
|
|
||||||
// TODO, and if lock fails, wait here until it unlocks
|
|
||||||
return false, errors.New("LockDB TODO")
|
|
||||||
},
|
|
||||||
func() {
|
|
||||||
// UnlockDB unlocks the database for migrations.
|
|
||||||
// Reports errors in the log.
|
|
||||||
// TODO
|
|
||||||
}) {
|
|
||||||
if err := database.Migrate(ConfigString("META", "database")); err != nil {
|
|
||||||
log.Error("Unable to run database migration: ", err)
|
log.Error("Unable to run database migration: ", err)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
package request
|
package request
|
||||||
|
|
||||||
/* TODO(Elliott)
|
/* TODO(Elliott)
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
package request
|
package request
|
||||||
|
|
||||||
/* TODO(Elliott)
|
/* TODO(Elliott)
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
package request
|
package request
|
||||||
|
|
||||||
/* TODO(Elliott)
|
/* TODO(Elliott)
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -231,5 +232,5 @@ func TestLabelRole(t *testing.T) {
|
||||||
}
|
}
|
||||||
p.testRollback(t)
|
p.testRollback(t)
|
||||||
|
|
||||||
*/
|
*/
|
||||||
//}
|
//}
|
||||||
|
|
|
@ -292,11 +292,11 @@ func (p *Persister) UpdatePage(page entity.Page, refID, userID string, skipRevis
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePageMeta persists meta information associated with a document page.
|
// UpdatePageMeta persists meta information associated with a document page.
|
||||||
func (p *Persister) UpdatePageMeta(meta entity.PageMeta,updateUserID bool) (err error) {
|
func (p *Persister) UpdatePageMeta(meta entity.PageMeta, updateUserID bool) (err error) {
|
||||||
err = nil
|
err = nil
|
||||||
meta.Revised = time.Now().UTC()
|
meta.Revised = time.Now().UTC()
|
||||||
if updateUserID {
|
if updateUserID {
|
||||||
meta.UserID=p.Context.UserID
|
meta.UserID = p.Context.UserID
|
||||||
}
|
}
|
||||||
|
|
||||||
var stmt *sqlx.NamedStmt
|
var stmt *sqlx.NamedStmt
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
package request
|
package request
|
||||||
|
|
||||||
/* TODO(Elliott)
|
/* TODO(Elliott)
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
|
|
||||||
"github.com/documize/community/documize/web"
|
"github.com/documize/community/documize/web"
|
||||||
"github.com/documize/community/wordsmith/log"
|
"github.com/documize/community/wordsmith/log"
|
||||||
|
"github.com/documize/community/wordsmith/utility"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,18 +28,12 @@ var dbCheckOK bool // default false
|
||||||
// dbPtr is a pointer to the central connection to the database, used by all database requests.
|
// dbPtr is a pointer to the central connection to the database, used by all database requests.
|
||||||
var dbPtr **sqlx.DB
|
var dbPtr **sqlx.DB
|
||||||
|
|
||||||
// lockDB locks the database
|
|
||||||
var lockDB func() (bool, error)
|
|
||||||
|
|
||||||
// unlockDB unlocks the database
|
|
||||||
var unlockDB func()
|
|
||||||
|
|
||||||
// Check that the database is configured correctly and that all the required tables exist.
|
// Check that the database is configured correctly and that all the required tables exist.
|
||||||
// It must be the first function called in the
|
// It must be the first function called in this package.
|
||||||
func Check(Db *sqlx.DB, connectionString string, lDB func() (bool, error), ulDB func()) bool {
|
func Check(Db *sqlx.DB, connectionString string) bool {
|
||||||
dbPtr = &Db
|
dbPtr = &Db
|
||||||
lockDB = lDB
|
|
||||||
unlockDB = ulDB
|
log.Info("Running database checks, this may take a while...")
|
||||||
|
|
||||||
csBits := strings.Split(connectionString, "/")
|
csBits := strings.Split(connectionString, "/")
|
||||||
if len(csBits) > 1 {
|
if len(csBits) > 1 {
|
||||||
|
@ -52,7 +47,7 @@ func Check(Db *sqlx.DB, connectionString string, lDB func() (bool, error), ulDB
|
||||||
web.SiteMode = web.SiteModeBadDB
|
web.SiteMode = web.SiteModeBadDB
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer rows.Close() // ignore error
|
defer utility.Close(rows)
|
||||||
var version, charset, collation string
|
var version, charset, collation string
|
||||||
if rows.Next() {
|
if rows.Next() {
|
||||||
err = rows.Scan(&version, &charset, &collation)
|
err = rows.Scan(&version, &charset, &collation)
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -25,6 +24,7 @@ import (
|
||||||
"github.com/documize/community/wordsmith/utility"
|
"github.com/documize/community/wordsmith/utility"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// runSQL creates a transaction per call
|
||||||
func runSQL(sql string) (id uint64, err error) {
|
func runSQL(sql string) (id uint64, err error) {
|
||||||
|
|
||||||
if strings.TrimSpace(sql) == "" {
|
if strings.TrimSpace(sql) == "" {
|
||||||
|
@ -41,7 +41,7 @@ func runSQL(sql string) (id uint64, err error) {
|
||||||
result, err := tx.Exec(sql)
|
result, err := tx.Exec(sql)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback() // ignore error as already in an error state
|
log.IfErr(tx.Rollback())
|
||||||
log.Error("runSql - unable to run sql", err)
|
log.Error("runSql - unable to run sql", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -59,14 +59,6 @@ func runSQL(sql string) (id uint64, err error) {
|
||||||
|
|
||||||
// Create the tables in a blank database
|
// Create the tables in a blank database
|
||||||
func Create(w http.ResponseWriter, r *http.Request) {
|
func Create(w http.ResponseWriter, r *http.Request) {
|
||||||
txt := "database.Create()"
|
|
||||||
//defer func(){fmt.Println("DEBUG"+txt)}()
|
|
||||||
|
|
||||||
if dbCheckOK {
|
|
||||||
txt += " Check OK"
|
|
||||||
} else {
|
|
||||||
txt += " Check not OK"
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
target := "/setup"
|
target := "/setup"
|
||||||
|
@ -92,14 +84,9 @@ func Create(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
txt += fmt.Sprintf("\n%#v\n", r.Form)
|
|
||||||
|
|
||||||
dbname := r.Form.Get("dbname")
|
dbname := r.Form.Get("dbname")
|
||||||
dbhash := r.Form.Get("dbhash")
|
dbhash := r.Form.Get("dbhash")
|
||||||
|
|
||||||
txt += fmt.Sprintf("DBname:%s (want:%s) DBhash: %s (want:%s)\n",
|
|
||||||
dbname, web.SiteInfo.DBname, dbhash, web.SiteInfo.DBhash)
|
|
||||||
|
|
||||||
if dbname != web.SiteInfo.DBname || dbhash != web.SiteInfo.DBhash {
|
if dbname != web.SiteInfo.DBname || dbhash != web.SiteInfo.DBhash {
|
||||||
log.Error("database.Create()'s security credentials error ", errors.New("bad db name or validation code"))
|
log.Error("database.Create()'s security credentials error ", errors.New("bad db name or validation code"))
|
||||||
return
|
return
|
||||||
|
@ -117,8 +104,6 @@ func Create(w http.ResponseWriter, r *http.Request) {
|
||||||
Revised: time.Now(),
|
Revised: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
txt += fmt.Sprintf("\n%#v\n", details)
|
|
||||||
|
|
||||||
if details.Company == "" ||
|
if details.Company == "" ||
|
||||||
details.CompanyLong == "" ||
|
details.CompanyLong == "" ||
|
||||||
details.Message == "" ||
|
details.Message == "" ||
|
||||||
|
@ -126,43 +111,12 @@ func Create(w http.ResponseWriter, r *http.Request) {
|
||||||
details.Password == "" ||
|
details.Password == "" ||
|
||||||
details.Firstname == "" ||
|
details.Firstname == "" ||
|
||||||
details.Lastname == "" {
|
details.Lastname == "" {
|
||||||
txt += "ERROR: required field blank"
|
log.Error("database.Create() error ",
|
||||||
|
errors.New("required field in database set-up form blank"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
firstSQL := "db_00000.sql"
|
if err = Migrate(false /* no tables exist yet */); err != nil {
|
||||||
|
|
||||||
buf, err := web.ReadFile("scripts/" + firstSQL)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("database.Create()'s web.ReadFile()", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tx, err := (*dbPtr).Beginx()
|
|
||||||
if err != nil {
|
|
||||||
log.Error(" failed to get transaction", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stmts := getStatements(buf)
|
|
||||||
|
|
||||||
for i, stmt := range stmts {
|
|
||||||
_, err = tx.Exec(stmt)
|
|
||||||
txt += fmt.Sprintf("%d: %s\nResult: %v\n\n", i, stmt, err)
|
|
||||||
if err != nil {
|
|
||||||
tx.Rollback() // ignore error as already in an error state
|
|
||||||
log.Error("database.Create() unable to run table create sql", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tx.Commit()
|
|
||||||
if err != nil {
|
|
||||||
log.Error("database.Create()", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := Migrate(firstSQL); err != nil {
|
|
||||||
log.Error("database.Create()", err)
|
log.Error("database.Create()", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -174,7 +128,6 @@ func Create(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
web.SiteMode = web.SiteModeNormal
|
web.SiteMode = web.SiteModeNormal
|
||||||
txt += "\n Success!\n"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The result of completing the onboarding process.
|
// The result of completing the onboarding process.
|
||||||
|
@ -219,7 +172,6 @@ func setupAccount(completion onboardRequest, serial string) (err error) {
|
||||||
log.Error("Failed with error", err)
|
log.Error("Failed with error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
|
|
||||||
// Link user to organization.
|
// Link user to organization.
|
||||||
accountID := util.UniqueID()
|
accountID := util.UniqueID()
|
||||||
|
@ -250,19 +202,3 @@ func setupAccount(completion onboardRequest, serial string) (err error) {
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// getStatement strips out the comments and returns all the individual SQL commands (apart from "USE") as a []string.
|
|
||||||
func getStatements(bytes []byte) []string {
|
|
||||||
/* Strip comments of the form '-- comment' or like this one */
|
|
||||||
stripped := regexp.MustCompile("(?s)--.*?\n|/\\*.*?\\*/").ReplaceAll(bytes, []byte("\n"))
|
|
||||||
sqls := strings.Split(string(stripped), ";")
|
|
||||||
ret := make([]string, 0, len(sqls))
|
|
||||||
for _, v := range sqls {
|
|
||||||
trimmed := strings.TrimSpace(v)
|
|
||||||
if len(trimmed) > 0 &&
|
|
||||||
!strings.HasPrefix(strings.ToUpper(trimmed), "USE ") { // make sure we don't USE the wrong database
|
|
||||||
ret = append(ret, trimmed+";")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,11 +12,17 @@
|
||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"bytes"
|
||||||
|
"database/sql"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
"github.com/documize/community/documize/web"
|
"github.com/documize/community/documize/web"
|
||||||
|
"github.com/documize/community/wordsmith/log"
|
||||||
|
"github.com/documize/community/wordsmith/utility"
|
||||||
)
|
)
|
||||||
|
|
||||||
const migrationsDir = "bindata/scripts"
|
const migrationsDir = "bindata/scripts"
|
||||||
|
@ -41,6 +47,10 @@ func migrations(lastMigration string) (migrationsT, error) {
|
||||||
|
|
||||||
hadLast := false
|
hadLast := false
|
||||||
|
|
||||||
|
if len(lastMigration) == 0 {
|
||||||
|
hadLast = true
|
||||||
|
}
|
||||||
|
|
||||||
for _, v := range files {
|
for _, v := range files {
|
||||||
if v == lastMigration {
|
if v == lastMigration {
|
||||||
hadLast = true
|
hadLast = true
|
||||||
|
@ -56,35 +66,130 @@ func migrations(lastMigration string) (migrationsT, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// migrate the database as required, by applying the migrations.
|
// migrate the database as required, by applying the migrations.
|
||||||
func (m migrationsT) migrate() error {
|
func (m migrationsT) migrate(tx *sqlx.Tx) error {
|
||||||
for _, v := range m {
|
for _, v := range m {
|
||||||
|
log.Info("Processing migration file: " + v)
|
||||||
buf, err := web.Asset(migrationsDir + "/" + v)
|
buf, err := web.Asset(migrationsDir + "/" + v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("DEBUG database.Migrate() ", v, ":\n", string(buf)) // TODO actually run the SQL
|
//fmt.Println("DEBUG database.Migrate() ", v, ":\n", string(buf)) // TODO actually run the SQL
|
||||||
|
err = processSQLfile(tx, buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
json := `{"database":"` + v + `"}`
|
||||||
|
sql := "INSERT INTO `config` (`key`,`config`) " +
|
||||||
|
"VALUES ('META','" + json +
|
||||||
|
"') ON DUPLICATE KEY UPDATE `config`='" + json + "';"
|
||||||
|
|
||||||
|
_, err = tx.Exec(sql)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//fmt.Println("DEBUG insert 10s wait for testing")
|
||||||
|
//time.Sleep(10 * time.Second)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func migrateEnd(tx *sqlx.Tx, err error) error {
|
||||||
|
if tx != nil {
|
||||||
|
_, ulerr := tx.Exec("UNLOCK TABLES;")
|
||||||
|
log.IfErr(ulerr)
|
||||||
|
if err == nil {
|
||||||
|
log.IfErr(tx.Commit())
|
||||||
|
log.Info("Database migration completed.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
log.IfErr(tx.Rollback())
|
||||||
|
}
|
||||||
|
log.Error("Database migration failed: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Migrate the database as required, consolidated action.
|
// Migrate the database as required, consolidated action.
|
||||||
func Migrate(lastMigration string) error {
|
func Migrate(ConfigTableExists bool) error {
|
||||||
|
|
||||||
|
lastMigration := ""
|
||||||
|
|
||||||
|
tx, err := (*dbPtr).Beginx()
|
||||||
|
if err != nil {
|
||||||
|
return migrateEnd(tx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ConfigTableExists {
|
||||||
|
_, err = tx.Exec("LOCK TABLE `config` WRITE;")
|
||||||
|
if err != nil {
|
||||||
|
return migrateEnd(tx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Database migration lock taken.")
|
||||||
|
|
||||||
|
var stmt *sql.Stmt
|
||||||
|
stmt, err = tx.Prepare("SELECT JSON_EXTRACT(`config`,'$.database') FROM `config` WHERE `key` = 'META';")
|
||||||
|
if err == nil {
|
||||||
|
defer utility.Close(stmt)
|
||||||
|
var item = make([]uint8, 0)
|
||||||
|
|
||||||
|
row := stmt.QueryRow()
|
||||||
|
|
||||||
|
err = row.Scan(&item)
|
||||||
|
if err != nil {
|
||||||
|
return migrateEnd(tx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(item) > 1 {
|
||||||
|
q := []byte(`"`)
|
||||||
|
lastMigration = string(bytes.TrimPrefix(bytes.TrimSuffix(item, q), q))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Info("Database migration last previously applied file was: " + lastMigration)
|
||||||
|
}
|
||||||
|
|
||||||
mig, err := migrations(lastMigration)
|
mig, err := migrations(lastMigration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return migrateEnd(tx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(mig) == 0 {
|
if len(mig) == 0 {
|
||||||
return nil // no migrations to perform
|
log.Info("Database migration no updates to perform.")
|
||||||
|
return migrateEnd(tx, nil) // no migrations to perform
|
||||||
}
|
}
|
||||||
locked, err := lockDB()
|
log.Info("Database migration will execute the following update files: " + strings.Join([]string(mig), ", "))
|
||||||
if err != nil {
|
|
||||||
return err
|
return migrateEnd(tx, mig.migrate(tx))
|
||||||
}
|
}
|
||||||
if locked {
|
|
||||||
defer unlockDB()
|
func processSQLfile(tx *sqlx.Tx, buf []byte) error {
|
||||||
if err := mig.migrate(); err != nil {
|
|
||||||
|
stmts := getStatements(buf)
|
||||||
|
|
||||||
|
for _, stmt := range stmts {
|
||||||
|
|
||||||
|
_, err := tx.Exec(stmt)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getStatement strips out the comments and returns all the individual SQL commands (apart from "USE") as a []string.
|
||||||
|
func getStatements(bytes []byte) []string {
|
||||||
|
/* Strip comments of the form '-- comment' or like this one */
|
||||||
|
stripped := regexp.MustCompile("(?s)--.*?\n|/\\*.*?\\*/").ReplaceAll(bytes, []byte("\n"))
|
||||||
|
sqls := strings.Split(string(stripped), ";")
|
||||||
|
ret := make([]string, 0, len(sqls))
|
||||||
|
for _, v := range sqls {
|
||||||
|
trimmed := strings.TrimSpace(v)
|
||||||
|
if len(trimmed) > 0 &&
|
||||||
|
!strings.HasPrefix(strings.ToUpper(trimmed), "USE ") { // make sure we don't USE the wrong database
|
||||||
|
ret = append(ret, trimmed+";")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CallbackT is the type signature of the callback function of GetString().
|
// CallbackT is the type signature of the callback function of GetString().
|
||||||
|
@ -36,6 +37,7 @@ type varsT struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var vars varsT
|
var vars varsT
|
||||||
|
var varsMutex sync.Mutex
|
||||||
|
|
||||||
// Len is part of sort.Interface.
|
// Len is part of sort.Interface.
|
||||||
func (v *varsT) Len() int {
|
func (v *varsT) Len() int {
|
||||||
|
@ -59,6 +61,8 @@ const goInit = "(default)"
|
||||||
|
|
||||||
// GetString sets-up the flag for later use, it must be called before ParseOK(), usually in an init().
|
// GetString sets-up the flag for later use, it must be called before ParseOK(), usually in an init().
|
||||||
func GetString(target *string, name string, required bool, usage string, callback CallbackT) {
|
func GetString(target *string, name string, required bool, usage string, callback CallbackT) {
|
||||||
|
varsMutex.Lock()
|
||||||
|
defer varsMutex.Unlock()
|
||||||
name = strings.ToLower(strings.TrimSpace(name))
|
name = strings.ToLower(strings.TrimSpace(name))
|
||||||
setter := Prefix + strings.ToUpper(name)
|
setter := Prefix + strings.ToUpper(name)
|
||||||
value := os.Getenv(setter)
|
value := os.Getenv(setter)
|
||||||
|
@ -76,6 +80,8 @@ var showSettings = flag.Bool("showsettings", false, "if true, show settings in t
|
||||||
// It should be the first thing called by any main() that uses this library.
|
// It should be the first thing called by any main() that uses this library.
|
||||||
// If all the required variables are not present, it prints an error and calls os.Exit(2) like flag.Parse().
|
// If all the required variables are not present, it prints an error and calls os.Exit(2) like flag.Parse().
|
||||||
func Parse(doFirst string) {
|
func Parse(doFirst string) {
|
||||||
|
varsMutex.Lock()
|
||||||
|
defer varsMutex.Unlock()
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
sort.Sort(&vars)
|
sort.Sort(&vars)
|
||||||
for pass := 1; pass <= 2; pass++ {
|
for pass := 1; pass <= 2; pass++ {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue