mirror of
https://github.com/documize/community.git
synced 2025-07-23 07:09:43 +02:00
restructure directories
This commit is contained in:
parent
7e4ed6545b
commit
a2ce777762
159 changed files with 320 additions and 323 deletions
150
core/database/check.go
Normal file
150
core/database/check.go
Normal file
|
@ -0,0 +1,150 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// 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 <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
package database
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/documize/community/core/web"
|
||||
"github.com/documize/community/core/log"
|
||||
"github.com/documize/community/core/utility"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
// Check that the database is configured correctly and that all the required tables exist.
|
||||
// It must be the first function called in this package.
|
||||
func Check(Db *sqlx.DB, connectionString string) bool {
|
||||
dbPtr = &Db
|
||||
|
||||
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]
|
||||
}
|
||||
|
||||
rows, err := Db.Query("SELECT VERSION() AS version, @@character_set_database AS charset, @@collation_database AS collation;")
|
||||
if err != nil {
|
||||
log.Error("Can't get MySQL configuration", err)
|
||||
web.SiteInfo.Issue = "Can't get MySQL configuration: " + err.Error()
|
||||
web.SiteMode = web.SiteModeBadDB
|
||||
return false
|
||||
}
|
||||
defer utility.Close(rows)
|
||||
var version, charset, collation string
|
||||
if rows.Next() {
|
||||
err = rows.Scan(&version, &charset, &collation)
|
||||
}
|
||||
if err == nil {
|
||||
err = rows.Err() // get any error encountered during iteration
|
||||
}
|
||||
if err != nil {
|
||||
log.Error("no MySQL configuration returned", err)
|
||||
web.SiteInfo.Issue = "no MySQL configuration return issue: " + err.Error()
|
||||
web.SiteMode = web.SiteModeBadDB
|
||||
return false
|
||||
}
|
||||
|
||||
// See http://dba.stackexchange.com/questions/63763/is-there-any-difference-between-these-two-version-of-mysql-5-1-73-community-lo
|
||||
version = strings.Replace(version, "-log", "", 1)
|
||||
version = strings.Replace(version, "-debug", "", 1)
|
||||
version = strings.Replace(version, "-demo", "", 1)
|
||||
|
||||
{ // check minimum MySQL version as we need JSON column type. 5.7.10
|
||||
vParts := strings.Split(version, ".")
|
||||
if len(vParts) < 3 {
|
||||
log.Error("MySQL version not of the form a.b.c:", errors.New(version))
|
||||
web.SiteInfo.Issue = "MySQL version in the wrong format: " + version
|
||||
web.SiteMode = web.SiteModeBadDB
|
||||
return false
|
||||
}
|
||||
verInts := []int{5, 7, 10} // Minimum MySQL version
|
||||
for k, v := range verInts {
|
||||
i, err := strconv.Atoi(vParts[k])
|
||||
if err != nil {
|
||||
log.Error("MySQL version element "+strconv.Itoa(k+1)+" of '"+version+"' not an integer:", err)
|
||||
web.SiteInfo.Issue = "MySQL version element " + strconv.Itoa(k+1) + " of '" + version + "' not an integer: " + err.Error()
|
||||
web.SiteMode = web.SiteModeBadDB
|
||||
return false
|
||||
}
|
||||
if i < v {
|
||||
want := fmt.Sprintf("%d.%d.%d", verInts[0], verInts[1], verInts[2])
|
||||
log.Error("MySQL version element "+strconv.Itoa(k+1)+" of '"+version+"' not high enough, need at least version "+want, errors.New("bad MySQL version"))
|
||||
web.SiteInfo.Issue = "MySQL version element " + strconv.Itoa(k+1) + " of '" + version + "' not high enough, need at least version " + want
|
||||
web.SiteMode = web.SiteModeBadDB
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ // check the MySQL character set and collation
|
||||
if charset != "utf8" {
|
||||
log.Error("MySQL character set not utf8:", errors.New(charset))
|
||||
web.SiteInfo.Issue = "MySQL character set not utf8: " + charset
|
||||
web.SiteMode = web.SiteModeBadDB
|
||||
return false
|
||||
}
|
||||
if !strings.HasPrefix(collation, "utf8") {
|
||||
log.Error("MySQL collation sequence not utf8...:", errors.New(collation))
|
||||
web.SiteInfo.Issue = "MySQL collation sequence not utf8...: " + collation
|
||||
web.SiteMode = web.SiteModeBadDB
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
{ // if there are no rows in the database, enter set-up mode
|
||||
var flds []string
|
||||
if err := Db.Select(&flds,
|
||||
`SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '`+web.SiteInfo.DBname+
|
||||
`' and TABLE_TYPE='BASE TABLE'`); err != nil {
|
||||
log.Error("Can't get MySQL number of tables", err)
|
||||
web.SiteInfo.Issue = "Can't get MySQL number of tables: " + err.Error()
|
||||
web.SiteMode = web.SiteModeBadDB
|
||||
return false
|
||||
}
|
||||
if strings.TrimSpace(flds[0]) == "0" {
|
||||
log.Error("Entering database set-up mode because the database is empty.", errors.New("no tables"))
|
||||
web.SiteMode = web.SiteModeSetup
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
{ // check all the required tables exist
|
||||
var tables = []string{`account`,
|
||||
`attachment`, `audit`, `document`,
|
||||
`label`, `labelrole`, `organization`,
|
||||
`page`, `revision`, `search`, `user`}
|
||||
|
||||
for _, table := range tables {
|
||||
var dummy []string
|
||||
if err := Db.Select(&dummy, "SELECT 1 FROM "+table+" LIMIT 1;"); err != nil {
|
||||
log.Error("Entering bad database mode because: SELECT 1 FROM "+table+" LIMIT 1;", err)
|
||||
web.SiteInfo.Issue = "MySQL database is not empty, but does not contain table: " + table
|
||||
web.SiteMode = web.SiteModeBadDB
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
web.SiteMode = web.SiteModeNormal // actually no need to do this (as already ""), this for documentation
|
||||
web.SiteInfo.DBname = "" // do not give this info when not in set-up mode
|
||||
dbCheckOK = true
|
||||
return true
|
||||
}
|
204
core/database/create.go
Normal file
204
core/database/create.go
Normal file
|
@ -0,0 +1,204 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// 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 <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
package database
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/documize/community/core/api/util"
|
||||
"github.com/documize/community/core/web"
|
||||
"github.com/documize/community/core/log"
|
||||
"github.com/documize/community/core/utility"
|
||||
)
|
||||
|
||||
// runSQL creates a transaction per call
|
||||
func runSQL(sql string) (id uint64, err error) {
|
||||
|
||||
if strings.TrimSpace(sql) == "" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
tx, err := (*dbPtr).Beginx()
|
||||
|
||||
if err != nil {
|
||||
log.Error("runSql - failed to get transaction", err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := tx.Exec(sql)
|
||||
|
||||
if err != nil {
|
||||
log.IfErr(tx.Rollback())
|
||||
log.Error("runSql - unable to run sql", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = tx.Commit(); err != nil {
|
||||
log.Error("runSql - unable to commit sql", err)
|
||||
return
|
||||
}
|
||||
|
||||
tempID, _ := result.LastInsertId()
|
||||
id = uint64(tempID)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Create the tables in a blank database
|
||||
func Create(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
defer func() {
|
||||
target := "/setup"
|
||||
status := http.StatusBadRequest
|
||||
|
||||
if web.SiteMode == web.SiteModeNormal {
|
||||
target = "/"
|
||||
status = http.StatusOK
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", target, nil)
|
||||
|
||||
if err != nil {
|
||||
log.Error("database.Create()'s error in defer ", err)
|
||||
}
|
||||
|
||||
http.Redirect(w, req, target, status)
|
||||
}()
|
||||
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
log.Error("database.Create()'s r.ParseForm()", err)
|
||||
return
|
||||
}
|
||||
|
||||
dbname := r.Form.Get("dbname")
|
||||
dbhash := r.Form.Get("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
|
||||
}
|
||||
|
||||
details := onboardRequest{
|
||||
URL: "",
|
||||
Company: r.Form.Get("title"),
|
||||
CompanyLong: r.Form.Get("title"),
|
||||
Message: r.Form.Get("message"),
|
||||
Email: r.Form.Get("email"),
|
||||
Password: r.Form.Get("password"),
|
||||
Firstname: r.Form.Get("firstname"),
|
||||
Lastname: r.Form.Get("lastname"),
|
||||
Revised: time.Now(),
|
||||
}
|
||||
|
||||
if details.Company == "" ||
|
||||
details.CompanyLong == "" ||
|
||||
details.Message == "" ||
|
||||
details.Email == "" ||
|
||||
details.Password == "" ||
|
||||
details.Firstname == "" ||
|
||||
details.Lastname == "" {
|
||||
log.Error("database.Create() error ",
|
||||
errors.New("required field in database set-up form blank"))
|
||||
return
|
||||
}
|
||||
|
||||
if err = Migrate(false /* no tables exist yet */); err != nil {
|
||||
log.Error("database.Create()", err)
|
||||
return
|
||||
}
|
||||
|
||||
err = setupAccount(details, util.GenerateSalt())
|
||||
if err != nil {
|
||||
log.Error("database.Create()", err)
|
||||
return
|
||||
}
|
||||
|
||||
web.SiteMode = web.SiteModeNormal
|
||||
}
|
||||
|
||||
// The result of completing the onboarding process.
|
||||
type onboardRequest struct {
|
||||
URL string
|
||||
Company string
|
||||
CompanyLong string
|
||||
Message string
|
||||
Email string
|
||||
Password string
|
||||
Firstname string
|
||||
Lastname string
|
||||
Revised time.Time
|
||||
}
|
||||
|
||||
// setupAccount prepares the database for a newly onboard customer.
|
||||
// Once done, they can then login and use Documize.
|
||||
func setupAccount(completion onboardRequest, serial string) (err error) {
|
||||
//accountTitle := "This is where you will find documentation for your all projects. You can customize this message from the settings screen."
|
||||
salt := util.GenerateSalt()
|
||||
password := util.GeneratePassword(completion.Password, salt)
|
||||
|
||||
// Allocate organization to the user.
|
||||
orgID := util.UniqueID()
|
||||
|
||||
sql := fmt.Sprintf("insert into organization (refid, company, title, message, domain, email, serial) values (\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\")",
|
||||
orgID, completion.Company, completion.CompanyLong, completion.Message, completion.URL, completion.Email, serial)
|
||||
_, err = runSQL(sql)
|
||||
|
||||
if err != nil {
|
||||
log.Error("Failed to insert into organization", err)
|
||||
return
|
||||
}
|
||||
|
||||
userID := util.UniqueID()
|
||||
|
||||
sql = fmt.Sprintf("insert into user (refid, firstname, lastname, email, initials, salt, password) values (\"%s\",\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\")",
|
||||
userID, completion.Firstname, completion.Lastname, completion.Email, utility.MakeInitials(completion.Firstname, completion.Lastname), salt, password)
|
||||
_, err = runSQL(sql)
|
||||
|
||||
if err != nil {
|
||||
log.Error("Failed with error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Link user to organization.
|
||||
accountID := util.UniqueID()
|
||||
sql = fmt.Sprintf("insert into account (refid, userid, orgid, admin, editor) values (\"%s\", \"%s\", \"%s\",1, 1)", accountID, userID, orgID)
|
||||
_, err = runSQL(sql)
|
||||
|
||||
if err != nil {
|
||||
log.Error("Failed with error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Set up default labels for main collection.
|
||||
labelID := util.UniqueID()
|
||||
sql = fmt.Sprintf("insert into label (refid, orgid, label, type, userid) values (\"%s\", \"%s\", \"My Project\", 2, \"%s\")", labelID, orgID, userID)
|
||||
_, err = runSQL(sql)
|
||||
|
||||
if err != nil {
|
||||
log.Error("insert into label failed", err)
|
||||
}
|
||||
|
||||
labelRoleID := util.UniqueID()
|
||||
sql = fmt.Sprintf("insert into labelrole (refid, labelid, orgid, userid, canview, canedit) values (\"%s\", \"%s\", \"%s\", \"%s\", 1, 1)", labelRoleID, labelID, orgID, userID)
|
||||
_, err = runSQL(sql)
|
||||
|
||||
if err != nil {
|
||||
log.Error("insert into labelrole failed", err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
13
core/database/database_test.go
Normal file
13
core/database/database_test.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// 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 <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
package database
|
||||
|
195
core/database/migrate.go
Normal file
195
core/database/migrate.go
Normal file
|
@ -0,0 +1,195 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// 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 <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
package database
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
||||
"github.com/documize/community/core/web"
|
||||
"github.com/documize/community/core/log"
|
||||
"github.com/documize/community/core/utility"
|
||||
)
|
||||
|
||||
const migrationsDir = "bindata/scripts"
|
||||
|
||||
// migrationsT holds a list of migration sql files to run.
|
||||
type migrationsT []string
|
||||
|
||||
// migrations returns a list of the migrations to update the database as required for this version of the code.
|
||||
func migrations(lastMigration string) (migrationsT, error) {
|
||||
|
||||
lastMigration = strings.TrimPrefix(strings.TrimSuffix(lastMigration, `"`), `"`)
|
||||
|
||||
//fmt.Println(`DEBUG Migrations("`+lastMigration+`")`)
|
||||
|
||||
files, err := web.AssetDir(migrationsDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Strings(files)
|
||||
|
||||
ret := make(migrationsT, 0, len(files))
|
||||
|
||||
hadLast := false
|
||||
|
||||
if len(lastMigration) == 0 {
|
||||
hadLast = true
|
||||
}
|
||||
|
||||
for _, v := range files {
|
||||
if v == lastMigration {
|
||||
hadLast = true
|
||||
} else {
|
||||
if hadLast {
|
||||
ret = append(ret, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//fmt.Println(`DEBUG Migrations("`+lastMigration+`")=`,ret)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// migrate the database as required, by applying the migrations.
|
||||
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
|
||||
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 checks: completed")
|
||||
return nil
|
||||
}
|
||||
log.IfErr(tx.Rollback())
|
||||
}
|
||||
log.Error("Database checks: failed: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Migrate the database as required, consolidated action.
|
||||
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 checks: 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 checks: last previously applied file was " + lastMigration)
|
||||
}
|
||||
|
||||
mig, err := migrations(lastMigration)
|
||||
if err != nil {
|
||||
return migrateEnd(tx, err)
|
||||
}
|
||||
|
||||
if len(mig) == 0 {
|
||||
log.Info("Database checks: no updates to perform")
|
||||
return migrateEnd(tx, nil) // no migrations to perform
|
||||
}
|
||||
log.Info("Database checks: 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
|
||||
}
|
280
core/database/scripts/autobuild/db_00000.sql
Normal file
280
core/database/scripts/autobuild/db_00000.sql
Normal file
|
@ -0,0 +1,280 @@
|
|||
-- SQL to set up the Documize database
|
||||
|
||||
DROP TABLE IF EXISTS `user`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `user` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`refid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`firstname` NVARCHAR(500) NOT NULL,
|
||||
`lastname` NVARCHAR(500) NOT NULL,
|
||||
`email` NVARCHAR(250) NOT NULL UNIQUE,
|
||||
`initials` NVARCHAR(10) NOT NULL DEFAULT "",
|
||||
`password` NVARCHAR(500) NOT NULL DEFAULT "",
|
||||
`salt` NVARCHAR(100) NOT NULL DEFAULT "",
|
||||
`reset` NVARCHAR(100) NOT NULL DEFAULT "",
|
||||
`active` BOOL NOT NULL DEFAULT 1,
|
||||
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_refid PRIMARY KEY (refid),
|
||||
UNIQUE INDEX `idx_user_id` (`id` ASC))
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
|
||||
ENGINE = InnoDB;
|
||||
|
||||
DROP TABLE IF EXISTS `audit`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `audit` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`userid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`documentid` CHAR(16) NOT NULL DEFAULT "" COLLATE utf8_bin,
|
||||
`pageid` CHAR(16) NOT NULL DEFAULT "" COLLATE utf8_bin,
|
||||
`action` NVARCHAR(200) NOT NULL DEFAULT "",
|
||||
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE INDEX `idx_audit_id` (`id` ASC),
|
||||
INDEX `idx_orgid_url` (`orgid`))
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
|
||||
ENGINE = InnoDB;
|
||||
|
||||
DROP TABLE IF EXISTS `organization`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `organization` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`refid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`company` NVARCHAR(500) NOT NULL,
|
||||
`title` NVARCHAR(500) NOT NULL,
|
||||
`message` NVARCHAR(500) NOT NULL,
|
||||
`url` NVARCHAR(200) NOT NULL DEFAULT "",
|
||||
`domain` NVARCHAR(200) NOT NULL DEFAULT "",
|
||||
`email` NVARCHAR(500) NOT NULL DEFAULT "",
|
||||
`allowanonymousaccess` BOOL NOT NULL DEFAULT 0,
|
||||
`verified` BOOL NOT NULL DEFAULT 0,
|
||||
`serial` NVARCHAR(50) NOT NULL DEFAULT "",
|
||||
`active` BOOL NOT NULL DEFAULT 1,
|
||||
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_refid PRIMARY KEY (refid),
|
||||
UNIQUE INDEX `idx_organization_id` (`id` ASC),
|
||||
INDEX `idx_organization_url` (`url`),
|
||||
INDEX `idx_organization_domain` (`domain`))
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
|
||||
ENGINE = InnoDB;
|
||||
|
||||
DROP TABLE IF EXISTS `account`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `account` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`refid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`userid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`editor` BOOL NOT NULL DEFAULT 0,
|
||||
`admin` BOOL NOT NULL DEFAULT 0,
|
||||
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_refid PRIMARY KEY (refid),
|
||||
UNIQUE INDEX `idx_account_id` (`id` ASC),
|
||||
INDEX `idx_account_userid` (`userid` ASC),
|
||||
INDEX `idx_account_orgid` (`orgid` ASC))
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
|
||||
ENGINE = InnoDB;
|
||||
|
||||
DROP TABLE IF EXISTS `label`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `label` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`refid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`label` NVARCHAR(255) NOT NULL,
|
||||
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`userid` CHAR(16) NOT NULL DEFAULT "" COLLATE utf8_bin,
|
||||
`type` INT NOT NULL DEFAULT 1,
|
||||
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_refid PRIMARY KEY (refid),
|
||||
UNIQUE INDEX `idx_label_id` (`id` ASC),
|
||||
INDEX `idx_label_userid` (`userid` ASC),
|
||||
INDEX `idx_label_orgid` (`orgid` ASC))
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
|
||||
ENGINE = InnoDB;
|
||||
|
||||
DROP TABLE IF EXISTS `labelrole`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `labelrole` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`refid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`labelid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`userid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`canview` BOOL NOT NULL DEFAULT 0,
|
||||
`canedit` BOOL NOT NULL DEFAULT 0,
|
||||
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_refid PRIMARY KEY (refid),
|
||||
UNIQUE INDEX `idx_labelrole_id` (`id` ASC),
|
||||
INDEX `idx_labelrole_userid` (`userid` ASC),
|
||||
INDEX `idx_labelrole_labelid` (`labelid` ASC),
|
||||
INDEX `idx_labelrole_orgid` (`orgid` ASC))
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
|
||||
ENGINE = InnoDB;
|
||||
|
||||
DROP TABLE IF EXISTS `document`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `document` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`refid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`labelid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`userid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`job` CHAR(36) NOT NULL,
|
||||
`location` NVARCHAR(2000) NOT NULL,
|
||||
`title` NVARCHAR(2000) NOT NULL,
|
||||
`excerpt` NVARCHAR(2000) NOT NULL,
|
||||
`slug` NVARCHAR(2000) NOT NULL,
|
||||
`tags` NVARCHAR(1000) NOT NULL DEFAULT '',
|
||||
`template` BOOL NOT NULL DEFAULT 0,
|
||||
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_refid PRIMARY KEY (refid),
|
||||
UNIQUE INDEX `idx_document_id` (`id` ASC),
|
||||
INDEX `idx_document_orgid` (`orgid` ASC),
|
||||
INDEX `idx_document_labelid` (`labelid` ASC))
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
|
||||
ENGINE = InnoDB;
|
||||
|
||||
DROP TABLE IF EXISTS `page`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `page` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`refid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`documentid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`userid` CHAR(16) DEFAULT '' COLLATE utf8_bin,
|
||||
`contenttype` CHAR(20) NOT NULL DEFAULT 'wysiwyg',
|
||||
`level` INT UNSIGNED NOT NULL,
|
||||
`sequence` DOUBLE NOT NULL,
|
||||
`title` NVARCHAR(2000) NOT NULL,
|
||||
`body` LONGTEXT,
|
||||
`revisions` INT UNSIGNED NOT NULL,
|
||||
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_refid PRIMARY KEY (refid),
|
||||
UNIQUE INDEX `idx_page_id` (`id` ASC),
|
||||
INDEX `idx_page_orgid` (`orgid` ASC),
|
||||
INDEX `idx_page_documentid` (`documentid` ASC))
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
|
||||
ENGINE = InnoDB;
|
||||
|
||||
DROP TABLE IF EXISTS `pagemeta`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `pagemeta` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`pageid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`userid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`documentid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`rawbody` LONGBLOB,
|
||||
`config` JSON,
|
||||
`externalsource` BOOL DEFAULT 0,
|
||||
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_pageid PRIMARY KEY (pageid),
|
||||
UNIQUE INDEX `idx_pagemeta_id` (`id` ASC),
|
||||
INDEX `idx_pagemeta_pageid` (`pageid` ASC),
|
||||
INDEX `idx_pagemeta_orgid` (`orgid` ASC),
|
||||
INDEX `idx_pagemeta_documentid` (`documentid` ASC))
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
|
||||
ENGINE = InnoDB;
|
||||
|
||||
DROP TABLE IF EXISTS `attachment`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `attachment` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`refid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`documentid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`job` CHAR(36) NOT NULL,
|
||||
`fileid` CHAR(10) NOT NULL,
|
||||
`filename` NVARCHAR(255) NOT NULL,
|
||||
`data` LONGBLOB,
|
||||
`extension` CHAR(6) NOT NULL,
|
||||
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_refid PRIMARY KEY (refid),
|
||||
UNIQUE INDEX `idx_attachment_id` (`id` ASC),
|
||||
INDEX `idx_attachment_orgid` (`orgid` ASC),
|
||||
INDEX `idx_attachment_documentid` (`documentid` ASC),
|
||||
INDEX `idx_attachment_job_and_fileid` (`job`,`fileid` ASC))
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
|
||||
ENGINE = InnoDB;
|
||||
|
||||
DROP TABLE IF EXISTS `search`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `search` (
|
||||
`id` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`documentid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`level` INT UNSIGNED NOT NULL,
|
||||
`sequence` DOUBLE NOT NULL,
|
||||
`documenttitle` NVARCHAR(2000) NOT NULL,
|
||||
`pagetitle` NVARCHAR(2000) NOT NULL,
|
||||
`slug` NVARCHAR(2000) NOT NULL,
|
||||
`body` LONGTEXT,
|
||||
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE INDEX `idx_search_id` (`id` ASC),
|
||||
INDEX `idx_search_orgid` (`orgid` ASC),
|
||||
INDEX `idx_search_documentid` (`documentid` ASC),
|
||||
INDEX `idx_search_sequence` (`sequence` ASC),
|
||||
FULLTEXT(`pagetitle`,`body`))
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
|
||||
ENGINE = MyISAM;
|
||||
|
||||
DROP TABLE IF EXISTS `revision`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `revision` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`refid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`documentid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`ownerid` CHAR(16) DEFAULT '' COLLATE utf8_bin,
|
||||
`pageid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`userid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`contenttype` CHAR(20) NOT NULL DEFAULT 'wysiwyg',
|
||||
`title` NVARCHAR(2000) NOT NULL,
|
||||
`body` LONGTEXT,
|
||||
`rawbody` LONGBLOB,
|
||||
`config` JSON,
|
||||
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT pk_refid PRIMARY KEY (refid),
|
||||
UNIQUE INDEX `idx_revision_id` (`id` ASC),
|
||||
INDEX `idx_revision_orgid` (`orgid` ASC),
|
||||
INDEX `idx_revision_documentid` (`documentid` ASC),
|
||||
INDEX `idx_revision_pageid` (`pageid` ASC))
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
|
||||
ENGINE = InnoDB;
|
||||
|
||||
DROP TABLE IF EXISTS `config`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `config` (
|
||||
`key` CHAR(255) NOT NULL,
|
||||
`config` JSON,
|
||||
UNIQUE INDEX `idx_config_area` (`key` ASC))
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||
|
||||
INSERT INTO `config` VALUES ('SMTP','{\"userid\": \"\",\"password\": \"\",\"host\": \"\",\"port\": \"\",\"sender\": \"\"}');
|
||||
INSERT INTO `config` VALUES ('FILEPLUGINS',
|
||||
'[{\"Comment\": \"Disable (or not) built-in html import (NOTE: no Plugin name)\",\"Disabled\": false,\"API\": \"Convert\",\"Actions\": [\"htm\",\"html\"]},{\"Comment\": \"Disable (or not) built-in Documize API import used from SDK (NOTE: no Plugin name)\",\"Disabled\": false,\"API\": \"Convert\",\"Actions\": [\"documizeapi\"]}]');
|
||||
INSERT INTO `config` VALUES ('LICENSE','{\"token\": \"\",\"endpoint\": \"https://api.documize.com\"}');
|
||||
INSERT INTO `config` VALUES ('META','{\"database\": \"db_00000.sql\"}');
|
||||
INSERT INTO `config` VALUES ('SECTION-GITHUB', '{\"clientID\": \"\", \"clientSecret\": \"\", \"authorizationCallbackURL\": \"https://localhost:5001/api/public/validate?section=github\"}');
|
||||
INSERT INTO `config` VALUES ('SECTION-TRELLO','{\"appKey\": \"\"}');
|
||||
|
||||
DROP TABLE IF EXISTS `userconfig`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `userconfig` (
|
||||
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`userid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||
`key` CHAR(255) NOT NULL,
|
||||
`config` JSON,
|
||||
UNIQUE INDEX `idx_userconfig_orguserkey` (`orgid`, `userid`, `key` ASC))
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
|
||||
ENGINE = InnoDB;
|
122
core/database/templates/db-error.html
Normal file
122
core/database/templates/db-error.html
Normal file
|
@ -0,0 +1,122 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,600,700,300' rel='stylesheet' type='text/css'>
|
||||
|
||||
<title>Documize - Issue using the given MySQL database</title>
|
||||
|
||||
<style>
|
||||
html {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
background-color: #1b75bb;
|
||||
font-size: 16px;
|
||||
color: #ffffff;
|
||||
padding-top: 50px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin: 0 15px;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin: 0 15px;
|
||||
}
|
||||
|
||||
.content > div {
|
||||
margin: 50px 0;
|
||||
}
|
||||
|
||||
.content h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 400;
|
||||
text-transform: uppercase;
|
||||
margin: 0 0 30px;
|
||||
}
|
||||
|
||||
.content p {
|
||||
font-size: 18px;
|
||||
line-height: 28px;
|
||||
margin: 30px 0 0 0;
|
||||
}
|
||||
|
||||
.content .image {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.clearfix {
|
||||
overflow: auto;
|
||||
zoom: 1;
|
||||
}
|
||||
|
||||
.btn-main {
|
||||
border: 1px solid #ffffff;
|
||||
padding: 12px 20px;
|
||||
border-radius: 5px;
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
body {
|
||||
margin-top: 100px;
|
||||
}
|
||||
.container {
|
||||
text-align: left;
|
||||
}
|
||||
.content {
|
||||
margin: 50px 15px 0;
|
||||
}
|
||||
.content > div {
|
||||
width: 50%;
|
||||
float: left;
|
||||
margin: 0;
|
||||
}
|
||||
.content h1 {
|
||||
font-size: 28px;
|
||||
line-height: 72px;
|
||||
}
|
||||
.content .image {
|
||||
float: right;
|
||||
}
|
||||
.content .text {
|
||||
max-width: 430px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<div class="container">
|
||||
<div class="logo">
|
||||
<img src="/assets/img/setup/logo.png" alt="Documize">
|
||||
</div>
|
||||
<div class="content clearfix">
|
||||
<div class="image">
|
||||
<img style="-webkit-user-select: none;" src="/assets/img/setup/error.png" width="184" height="159" alt="Database error">
|
||||
</div>
|
||||
<div class="text">
|
||||
<h1>Database Error</h1>
|
||||
<p>There seems to be a problem with the Documize database: <strong>{{.DBname}}</strong></p>
|
||||
<p><em>{{.Issue}}</em></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
126
core/database/templates/offline.html
Normal file
126
core/database/templates/offline.html
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue