diff --git a/app/app/pods/setup/route.js b/app/app/pods/setup/route.js index 36ded21b..587c4d1b 100644 --- a/app/app/pods/setup/route.js +++ b/app/app/pods/setup/route.js @@ -17,8 +17,6 @@ export default Ember.Route.extend({ 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.session.clearSession(); }, model() { diff --git a/app/app/services/app-meta.js b/app/app/services/app-meta.js index 0c0854bc..39b8c09b 100644 --- a/app/app/services/app-meta.js +++ b/app/app/services/app-meta.js @@ -20,6 +20,7 @@ const { export default Ember.Service.extend({ ajax: service(), + localStorage: service(), endpoint: `${config.apiHost}/${config.apiNamespace}`, orgId: '', @@ -27,6 +28,7 @@ export default Ember.Service.extend({ version: '', message: '', allowAnonymousAccess: false, + setupMode: false, getBaseUrl(endpoint) { return [this.get('host'), endpoint].join('/'); @@ -40,12 +42,14 @@ export default Ember.Service.extend({ let isInSetupMode = dbhash && dbhash !== "{{.DBhash}}"; if (isInSetupMode) { - this.setProperites({ + this.setProperties({ 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) => { diff --git a/app/app/services/local-storage.js b/app/app/services/local-storage.js index 99db2e50..28d12e5a 100644 --- a/app/app/services/local-storage.js +++ b/app/app/services/local-storage.js @@ -22,5 +22,9 @@ export default Ember.Service.extend({ clearSessionItem: function (key) { delete localStorage[key]; + }, + + clearAll() { + localStorage.clear(); } }); \ No newline at end of file diff --git a/build.sh b/build.sh index 138c8062..6357c452 100755 --- a/build.sh +++ b/build.sh @@ -37,7 +37,7 @@ go generate echo "Compiling app..." cd ../.. -for arch in amd64 386 ; do +for arch in amd64 ; do for os in darwin linux windows ; do if [ "$os" == "windows" ] ; then echo "Compiling documize-$os-$arch.exe" diff --git a/documize/api/endpoint/authentication_endpoint.go b/documize/api/endpoint/authentication_endpoint.go index 8824041c..f664ad05 100644 --- a/documize/api/endpoint/authentication_endpoint.go +++ b/documize/api/endpoint/authentication_endpoint.go @@ -28,6 +28,7 @@ import ( "github.com/documize/community/documize/api/request" "github.com/documize/community/documize/api/util" "github.com/documize/community/documize/section/provider" + "github.com/documize/community/documize/web" "github.com/documize/community/wordsmith/environment" "github.com/documize/community/wordsmith/log" "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) == "/robots.txt" || 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 } diff --git a/documize/api/endpoint/router.go b/documize/api/endpoint/router.go index 872d33b9..af80564c 100644 --- a/documize/api/endpoint/router.go +++ b/documize/api/endpoint/router.go @@ -134,6 +134,10 @@ func buildUnsecureRoutes() *mux.Router { func buildSecureRoutes() *mux.Router { router := mux.NewRouter() + if web.SiteMode == web.SiteModeSetup { + router.HandleFunc("/api/setup", database.Create).Methods("POST", "OPTIONS") + } + // Import & Convert Document router.HandleFunc("/api/import/folder/{folderID}", UploadConvertDocument).Methods("POST", "OPTIONS") @@ -254,7 +258,6 @@ func AppRouter() *mux.Router { log.Info("Serving OFFLINE web app") case web.SiteModeSetup: log.Info("Serving SETUP web app") - router.HandleFunc("/setup", database.Create).Methods("POST", "OPTIONS") case web.SiteModeBadDB: log.Info("Serving BAD DATABASE web app") default: diff --git a/documize/api/request/account.go b/documize/api/request/account.go index 294a9464..c0d4f21f 100644 --- a/documize/api/request/account.go +++ b/documize/api/request/account.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com diff --git a/documize/api/request/account_test.go b/documize/api/request/account_test.go index 648d0468..9e82fcca 100644 --- a/documize/api/request/account_test.go +++ b/documize/api/request/account_test.go @@ -1,15 +1,16 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com package request + /* TODO(Elliott) import ( "github.com/documize/community/documize/api/entity" diff --git a/documize/api/request/attachment.go b/documize/api/request/attachment.go index 31bbd86c..3b6e8c05 100644 --- a/documize/api/request/attachment.go +++ b/documize/api/request/attachment.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com diff --git a/documize/api/request/attachment_test.go b/documize/api/request/attachment_test.go index 7d791532..26407d3d 100644 --- a/documize/api/request/attachment_test.go +++ b/documize/api/request/attachment_test.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com @@ -103,4 +103,4 @@ func TestAttachment(t *testing.T) { } p.testRollback(t) } -*/ \ No newline at end of file +*/ diff --git a/documize/api/request/config.go b/documize/api/request/config.go index 59063f9d..86ccab32 100644 --- a/documize/api/request/config.go +++ b/documize/api/request/config.go @@ -67,6 +67,29 @@ func ConfigString(area, path string) (ret string) { 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. // Errors return the empty string. A blank path returns the whole JSON object, as JSON. 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) - _,err= stmt.Exec() + _, err = stmt.Exec() return err } diff --git a/documize/api/request/context.go b/documize/api/request/context.go index 6cc69810..87061f49 100644 --- a/documize/api/request/context.go +++ b/documize/api/request/context.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com diff --git a/documize/api/request/context_test.go b/documize/api/request/context_test.go index dfc1fed8..492e78d8 100644 --- a/documize/api/request/context_test.go +++ b/documize/api/request/context_test.go @@ -1,15 +1,16 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com package request + /* TODO(Elliott) import ( "github.com/documize/community/wordsmith/environment" @@ -76,4 +77,4 @@ func TestContext(t *testing.T) { } } -*/ \ No newline at end of file +*/ diff --git a/documize/api/request/doc.go b/documize/api/request/doc.go index 32c405a3..d1936914 100644 --- a/documize/api/request/doc.go +++ b/documize/api/request/doc.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com diff --git a/documize/api/request/document_test.go b/documize/api/request/document_test.go index 80529509..2b74a40c 100644 --- a/documize/api/request/document_test.go +++ b/documize/api/request/document_test.go @@ -1,15 +1,16 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com package request + /* TODO(Elliott) import ( "github.com/documize/community/documize/api/entity" diff --git a/documize/api/request/domain.go b/documize/api/request/domain.go index 78ef82c7..8561b98e 100644 --- a/documize/api/request/domain.go +++ b/documize/api/request/domain.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com diff --git a/documize/api/request/domain_test.go b/documize/api/request/domain_test.go index 52672bd2..fa33cd42 100644 --- a/documize/api/request/domain_test.go +++ b/documize/api/request/domain_test.go @@ -1,15 +1,16 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com package request + /* TODO(Elliott) import "testing" import "net/http" @@ -38,4 +39,4 @@ func ds(t *testing.T, in, out1, out2 string) { t.Errorf("GetSubdomainFromHost input `%s` got `%s` expected `%s`\n", in, got2, out2) } } -*/ \ No newline at end of file +*/ diff --git a/documize/api/request/init.go b/documize/api/request/init.go index 0b848f7d..f843fe55 100644 --- a/documize/api/request/init.go +++ b/documize/api/request/init.go @@ -1,18 +1,17 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com package request import ( - "errors" "fmt" "os" "strings" @@ -69,18 +68,8 @@ func init() { } // go into setup mode if required - if database.Check(Db, connectionString, - func() (bool, error) { - // 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 { + if database.Check(Db, connectionString) { + if err := database.Migrate(true /* the config table exists */); err != nil { log.Error("Unable to run database migration: ", err) os.Exit(2) } diff --git a/documize/api/request/init_test.go b/documize/api/request/init_test.go index 1410d305..b84bedb6 100644 --- a/documize/api/request/init_test.go +++ b/documize/api/request/init_test.go @@ -1,15 +1,16 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com package request + /* TODO(Elliott) import ( "fmt" @@ -33,4 +34,4 @@ func TestInit(t *testing.T) { _ = p.Base.SQLPrepareError("method", "id") // noting to test, just for coverage stats _ = p.Base.SQLSelectError("method", "id") // noting to test, just for coverage stats } -*/ \ No newline at end of file +*/ diff --git a/documize/api/request/label.go b/documize/api/request/label.go index d08c5c77..6b988123 100644 --- a/documize/api/request/label.go +++ b/documize/api/request/label.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com diff --git a/documize/api/request/label_test.go b/documize/api/request/label_test.go index 367d67cf..b0ff22d6 100644 --- a/documize/api/request/label_test.go +++ b/documize/api/request/label_test.go @@ -1,15 +1,16 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com package request + /* TODO(Elliott) import ( "testing" @@ -145,4 +146,4 @@ foundLabel: p.Context.UserID = u // put back the right one, so that we delete correctly on tidy-up } -*/ \ No newline at end of file +*/ diff --git a/documize/api/request/labelrole.go b/documize/api/request/labelrole.go index 158df72c..4cb98674 100644 --- a/documize/api/request/labelrole.go +++ b/documize/api/request/labelrole.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com diff --git a/documize/api/request/labelrole_test.go b/documize/api/request/labelrole_test.go index 528dbc41..98b0155a 100644 --- a/documize/api/request/labelrole_test.go +++ b/documize/api/request/labelrole_test.go @@ -1,15 +1,16 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com package request + /* TODO(Elliott) import ( "testing" @@ -231,5 +232,5 @@ func TestLabelRole(t *testing.T) { } p.testRollback(t) - */ +*/ //} diff --git a/documize/api/request/organization.go b/documize/api/request/organization.go index 36323f48..044c9eef 100644 --- a/documize/api/request/organization.go +++ b/documize/api/request/organization.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com diff --git a/documize/api/request/page.go b/documize/api/request/page.go index 7e220d58..e191e7fa 100644 --- a/documize/api/request/page.go +++ b/documize/api/request/page.go @@ -292,11 +292,11 @@ func (p *Persister) UpdatePage(page entity.Page, refID, userID string, skipRevis } // 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 meta.Revised = time.Now().UTC() if updateUserID { - meta.UserID=p.Context.UserID + meta.UserID = p.Context.UserID } var stmt *sqlx.NamedStmt diff --git a/documize/api/request/page_test.go b/documize/api/request/page_test.go index 1746c4c8..12097b9f 100644 --- a/documize/api/request/page_test.go +++ b/documize/api/request/page_test.go @@ -1,15 +1,16 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com package request + /* TODO(Elliott) import ( "strings" @@ -114,7 +115,7 @@ func testDeletePages(t *testing.T, p *Persister, pages []entity.Page) { t.Error(err) //t.Fail() } - // this code is belt-and-braces, as document delete should also delete any pages + // this code is belt-and-braces, as document delete should also delete any pages //if rows != 1 { // t.Errorf("expected 1 page row deleted got %d", rows) // //t.Fail() @@ -274,4 +275,4 @@ func TestPage(t *testing.T) { } p.testRollback(t) } -*/ \ No newline at end of file +*/ diff --git a/documize/api/request/search.go b/documize/api/request/search.go index bd753b21..e688fe92 100644 --- a/documize/api/request/search.go +++ b/documize/api/request/search.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com diff --git a/documize/api/request/setup.go b/documize/api/request/setup.go index 806835ee..f783abdb 100644 --- a/documize/api/request/setup.go +++ b/documize/api/request/setup.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com diff --git a/documize/api/request/user.go b/documize/api/request/user.go index b5b83f57..db65479e 100644 --- a/documize/api/request/user.go +++ b/documize/api/request/user.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com diff --git a/documize/api/request/user_test.go b/documize/api/request/user_test.go index f90ec6aa..f7664a43 100644 --- a/documize/api/request/user_test.go +++ b/documize/api/request/user_test.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com @@ -215,4 +215,4 @@ func TestUser(t *testing.T) { p.testRollback(t) } -*/ \ No newline at end of file +*/ diff --git a/documize/database/check.go b/documize/database/check.go index c3ca616f..7e2a0e72 100644 --- a/documize/database/check.go +++ b/documize/database/check.go @@ -19,6 +19,7 @@ import ( "github.com/documize/community/documize/web" "github.com/documize/community/wordsmith/log" + "github.com/documize/community/wordsmith/utility" "github.com/jmoiron/sqlx" ) @@ -27,19 +28,13 @@ var dbCheckOK bool // default false // dbPtr is a pointer to the central connection to the database, used by all database requests. 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. -// It must be the first function called in the -func Check(Db *sqlx.DB, connectionString string, lDB func() (bool, error), ulDB func()) bool { +// It must be the first function called in this package. +func Check(Db *sqlx.DB, connectionString string) bool { dbPtr = &Db - lockDB = lDB - unlockDB = ulDB + log.Info("Running database checks, this may take a while...") + csBits := strings.Split(connectionString, "/") if len(csBits) > 1 { web.SiteInfo.DBname = strings.Split(csBits[len(csBits)-1], "?")[0] @@ -52,7 +47,7 @@ func Check(Db *sqlx.DB, connectionString string, lDB func() (bool, error), ulDB web.SiteMode = web.SiteModeBadDB return false } - defer rows.Close() // ignore error + defer utility.Close(rows) var version, charset, collation string if rows.Next() { err = rows.Scan(&version, &charset, &collation) diff --git a/documize/database/create.go b/documize/database/create.go index 478ad482..07ce6bac 100644 --- a/documize/database/create.go +++ b/documize/database/create.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com @@ -15,7 +15,6 @@ import ( "errors" "fmt" "net/http" - "regexp" "strings" "time" @@ -25,6 +24,7 @@ import ( "github.com/documize/community/wordsmith/utility" ) +// runSQL creates a transaction per call func runSQL(sql string) (id uint64, err error) { if strings.TrimSpace(sql) == "" { @@ -41,7 +41,7 @@ func runSQL(sql string) (id uint64, err error) { result, err := tx.Exec(sql) 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) return } @@ -59,14 +59,6 @@ func runSQL(sql string) (id uint64, err error) { // Create the tables in a blank database 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() { target := "/setup" @@ -92,14 +84,9 @@ func Create(w http.ResponseWriter, r *http.Request) { return } - txt += fmt.Sprintf("\n%#v\n", r.Form) - dbname := r.Form.Get("dbname") 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 { log.Error("database.Create()'s security credentials error ", errors.New("bad db name or validation code")) return @@ -117,8 +104,6 @@ func Create(w http.ResponseWriter, r *http.Request) { Revised: time.Now(), } - txt += fmt.Sprintf("\n%#v\n", details) - if details.Company == "" || details.CompanyLong == "" || details.Message == "" || @@ -126,43 +111,12 @@ func Create(w http.ResponseWriter, r *http.Request) { details.Password == "" || details.Firstname == "" || details.Lastname == "" { - txt += "ERROR: required field blank" + log.Error("database.Create() error ", + errors.New("required field in database set-up form blank")) return } - firstSQL := "db_00000.sql" - - 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 { + if err = Migrate(false /* no tables exist yet */); err != nil { log.Error("database.Create()", err) return } @@ -174,7 +128,6 @@ func Create(w http.ResponseWriter, r *http.Request) { } web.SiteMode = web.SiteModeNormal - txt += "\n Success!\n" } // 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) return err } - //} // Link user to organization. accountID := util.UniqueID() @@ -250,19 +202,3 @@ func setupAccount(completion onboardRequest, serial string) (err error) { 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 -} diff --git a/documize/database/migrate.go b/documize/database/migrate.go index d7c031f3..70c9ed6f 100644 --- a/documize/database/migrate.go +++ b/documize/database/migrate.go @@ -1,22 +1,28 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com package database import ( - "fmt" + "bytes" + "database/sql" + "regexp" "sort" "strings" + "github.com/jmoiron/sqlx" + "github.com/documize/community/documize/web" + "github.com/documize/community/wordsmith/log" + "github.com/documize/community/wordsmith/utility" ) const migrationsDir = "bindata/scripts" @@ -41,6 +47,10 @@ func migrations(lastMigration string) (migrationsT, error) { hadLast := false + if len(lastMigration) == 0 { + hadLast = true + } + for _, v := range files { if v == lastMigration { hadLast = true @@ -56,35 +66,130 @@ func migrations(lastMigration string) (migrationsT, error) { } // 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 { + log.Info("Processing migration file: " + v) buf, err := web.Asset(migrationsDir + "/" + v) if err != nil { 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 } +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. -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) if err != nil { - return err + return migrateEnd(tx, err) } + 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() - if err != nil { - return err - } - if locked { - defer unlockDB() - if err := mig.migrate(); err != nil { + log.Info("Database migration will execute the following update files: " + strings.Join([]string(mig), ", ")) + + return migrateEnd(tx, mig.migrate(tx)) +} + +func processSQLfile(tx *sqlx.Tx, buf []byte) error { + + stmts := getStatements(buf) + + for _, stmt := range stmts { + + _, err := tx.Exec(stmt) + if err != nil { return err } + } + 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 +} diff --git a/wordsmith/environment/environment.go b/wordsmith/environment/environment.go index 82455d8c..b40c0a23 100644 --- a/wordsmith/environment/environment.go +++ b/wordsmith/environment/environment.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com @@ -19,6 +19,7 @@ import ( "os" "sort" "strings" + "sync" ) // CallbackT is the type signature of the callback function of GetString(). @@ -36,6 +37,7 @@ type varsT struct { } var vars varsT +var varsMutex sync.Mutex // Len is part of sort.Interface. 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(). func GetString(target *string, name string, required bool, usage string, callback CallbackT) { + varsMutex.Lock() + defer varsMutex.Unlock() name = strings.ToLower(strings.TrimSpace(name)) setter := Prefix + strings.ToUpper(name) 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. // If all the required variables are not present, it prints an error and calls os.Exit(2) like flag.Parse(). func Parse(doFirst string) { + varsMutex.Lock() + defer varsMutex.Unlock() flag.Parse() sort.Sort(&vars) for pass := 1; pass <= 2; pass++ { diff --git a/wordsmith/log/logger.go b/wordsmith/log/logger.go index f4f1545f..0eb01780 100644 --- a/wordsmith/log/logger.go +++ b/wordsmith/log/logger.go @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// This software (Documize Community Edition) is licensed under // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html // // You can operate outside the AGPL restrictions by purchasing // Documize Enterprise Edition and obtaining a commercial license -// by contacting . +// by contacting . // // https://documize.com