2016-07-07 18:54:16 -07:00
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
2016-07-15 16:54:07 +01:00
// This software (Documize Community Edition) is licensed under
2016-07-07 18:54:16 -07:00
// 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
2016-07-15 16:54:07 +01:00
// by contacting <sales@documize.com>.
2016-07-07 18:54:16 -07:00
//
// https://documize.com
package database
import (
"errors"
"fmt"
"net/http"
"strings"
"time"
2017-08-29 17:55:41 +01:00
"github.com/documize/community/core/api/plugins"
2017-07-24 16:24:21 +01:00
"github.com/documize/community/core/env"
2017-07-18 21:55:17 +01:00
"github.com/documize/community/core/secrets"
"github.com/documize/community/core/stringutil"
2017-07-18 22:03:23 +01:00
"github.com/documize/community/core/uniqueid"
2017-08-02 15:26:31 +01:00
"github.com/documize/community/domain"
2017-07-21 18:14:19 +01:00
"github.com/documize/community/server/web"
2016-07-07 18:54:16 -07:00
)
2017-08-02 15:26:31 +01:00
// Handler contains the runtime information such as logging and database.
type Handler struct {
Runtime * env . Runtime
Store * domain . Store
2016-07-07 18:54:16 -07:00
}
2017-08-29 17:55:41 +01:00
// Setup the tables in a blank database
func ( h * Handler ) Setup ( w http . ResponseWriter , r * http . Request ) {
2016-07-07 18:54:16 -07:00
defer func ( ) {
target := "/setup"
status := http . StatusBadRequest
2017-08-02 15:26:31 +01:00
if h . Runtime . Flags . SiteMode == env . SiteModeNormal {
2016-07-07 18:54:16 -07:00
target = "/"
status = http . StatusOK
}
req , err := http . NewRequest ( "GET" , target , nil )
if err != nil {
2017-08-29 17:55:41 +01:00
h . Runtime . Log . Error ( "database.Setup error in defer " , err )
2016-07-07 18:54:16 -07:00
}
http . Redirect ( w , req , target , status )
} ( )
err := r . ParseForm ( )
if err != nil {
2017-08-29 17:55:41 +01:00
h . Runtime . Log . Error ( "database.Setup r.ParseForm()" , err )
2016-07-07 18:54:16 -07:00
return
}
dbname := r . Form . Get ( "dbname" )
dbhash := r . Form . Get ( "dbhash" )
if dbname != web . SiteInfo . DBname || dbhash != web . SiteInfo . DBhash {
2017-08-29 17:55:41 +01:00
h . Runtime . Log . Error ( "database.Setup security credentials error " , errors . New ( "bad db name or validation code" ) )
2016-07-07 18:54:16 -07:00
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" ) ,
2016-11-20 13:41:43 -08:00
Revised : time . Now ( ) . UTC ( ) ,
2016-07-07 18:54:16 -07:00
}
if details . Company == "" ||
details . CompanyLong == "" ||
details . Message == "" ||
details . Email == "" ||
details . Password == "" ||
details . Firstname == "" ||
details . Lastname == "" {
2017-08-29 17:55:41 +01:00
h . Runtime . Log . Error ( "database.Setup error " , errors . New ( "required field in database set-up form blank" ) )
2016-07-07 18:54:16 -07:00
return
}
2017-08-02 15:26:31 +01:00
if err = Migrate ( h . Runtime , false /* no tables exist yet */ ) ; err != nil {
2017-08-29 17:55:41 +01:00
h . Runtime . Log . Error ( "database.Setup migrate" , err )
2016-07-07 18:54:16 -07:00
return
}
2017-08-02 15:26:31 +01:00
err = setupAccount ( h . Runtime , details , secrets . GenerateSalt ( ) )
2016-07-07 18:54:16 -07:00
if err != nil {
2017-08-29 17:55:41 +01:00
h . Runtime . Log . Error ( "database.Setup setup account " , err )
2016-07-07 18:54:16 -07:00
return
}
2017-08-02 15:26:31 +01:00
h . Runtime . Flags . SiteMode = env . SiteModeNormal
2017-08-29 17:55:41 +01:00
err = plugins . Setup ( h . Store )
if err != nil {
h . Runtime . Log . Error ( "database.Setup plugin setup failed" , err )
}
2016-07-07 18:54:16 -07:00
}
// 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.
2017-08-02 15:26:31 +01:00
func setupAccount ( rt * env . Runtime , completion onboardRequest , serial string ) ( err error ) {
2016-07-07 18:54:16 -07:00
//accountTitle := "This is where you will find documentation for your all projects. You can customize this message from the settings screen."
2017-07-18 21:55:17 +01:00
salt := secrets . GenerateSalt ( )
password := secrets . GeneratePassword ( completion . Password , salt )
2016-07-07 18:54:16 -07:00
// Allocate organization to the user.
2017-07-18 22:03:23 +01:00
orgID := uniqueid . Generate ( )
2016-07-07 18:54:16 -07:00
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 )
2017-08-02 15:26:31 +01:00
_ , err = runSQL ( rt , sql )
2016-07-07 18:54:16 -07:00
if err != nil {
2017-08-02 15:26:31 +01:00
rt . Log . Error ( "Failed to insert into organization" , err )
2016-07-07 18:54:16 -07:00
return
}
2017-07-18 22:03:23 +01:00
userID := uniqueid . Generate ( )
2016-07-07 18:54:16 -07:00
2016-10-18 19:20:51 -07:00
sql = fmt . Sprintf ( "insert into user (refid, firstname, lastname, email, initials, salt, password, global) values (\"%s\",\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", 1)" ,
2017-07-18 21:55:17 +01:00
userID , completion . Firstname , completion . Lastname , completion . Email , stringutil . MakeInitials ( completion . Firstname , completion . Lastname ) , salt , password )
2017-08-02 15:26:31 +01:00
_ , err = runSQL ( rt , sql )
2016-07-07 18:54:16 -07:00
if err != nil {
2017-08-02 15:26:31 +01:00
rt . Log . Error ( "Failed with error" , err )
2016-07-07 18:54:16 -07:00
return err
}
// Link user to organization.
2017-07-18 22:03:23 +01:00
accountID := uniqueid . Generate ( )
2018-06-04 14:39:38 +01:00
sql = fmt . Sprintf ( "insert into account (refid, userid, orgid, `admin`, editor, users, analytics) values (\"%s\", \"%s\", \"%s\", 1, 1, 1, 1)" , accountID , userID , orgID )
2017-08-02 15:26:31 +01:00
_ , err = runSQL ( rt , sql )
2016-07-07 18:54:16 -07:00
if err != nil {
2017-08-02 15:26:31 +01:00
rt . Log . Error ( "Failed with error" , err )
2016-07-07 18:54:16 -07:00
return err
}
2017-09-15 11:08:05 +01:00
// create space
2017-07-18 22:03:23 +01:00
labelID := uniqueid . Generate ( )
2016-07-07 18:54:16 -07:00
sql = fmt . Sprintf ( "insert into label (refid, orgid, label, type, userid) values (\"%s\", \"%s\", \"My Project\", 2, \"%s\")" , labelID , orgID , userID )
2017-08-02 15:26:31 +01:00
_ , err = runSQL ( rt , sql )
2016-07-07 18:54:16 -07:00
if err != nil {
2017-08-02 15:26:31 +01:00
rt . Log . Error ( "insert into label failed" , err )
2016-07-07 18:54:16 -07:00
}
2017-09-15 11:08:05 +01:00
// assign permissions to space
2018-03-14 13:38:37 +00:00
perms := [ ] string { "view" , "manage" , "own" , "doc-add" , "doc-edit" , "doc-delete" , "doc-move" , "doc-copy" , "doc-template" , "doc-approve" , "doc-version" , "doc-lifecycle" }
2017-09-15 11:08:05 +01:00
for _ , p := range perms {
2017-10-06 13:59:58 -04:00
sql = fmt . Sprintf ( "insert into permission (orgid, who, whoid, action, scope, location, refid) values (\"%s\", 'user', \"%s\", \"%s\", 'object', 'space', \"%s\")" , orgID , userID , p , labelID )
2017-09-15 11:08:05 +01:00
_ , err = runSQL ( rt , sql )
if err != nil {
rt . Log . Error ( "insert into permission failed" , err )
}
2016-07-07 18:54:16 -07:00
}
2018-03-08 11:54:57 +00:00
// Create some user groups
groupDevID := uniqueid . Generate ( )
sql = fmt . Sprintf ( "INSERT INTO role (refid, orgid, role, purpose) VALUES (\"%s\", \"%s\", \"Technology\", \"On-site and remote development teams\")" , groupDevID , orgID )
_ , err = runSQL ( rt , sql )
if err != nil {
rt . Log . Error ( "insert into role failed" , err )
}
groupProjectID := uniqueid . Generate ( )
sql = fmt . Sprintf ( "INSERT INTO role (refid, orgid, role, purpose) VALUES (\"%s\", \"%s\", \"Project Management\", \"HQ project management\")" , groupProjectID , orgID )
_ , err = runSQL ( rt , sql )
if err != nil {
rt . Log . Error ( "insert into role failed" , err )
}
groupBackofficeID := uniqueid . Generate ( )
sql = fmt . Sprintf ( "INSERT INTO role (refid, orgid, role, purpose) VALUES (\"%s\", \"%s\", \"Back Office\", \"Non-IT and PMO personnel\")" , groupBackofficeID , orgID )
_ , err = runSQL ( rt , sql )
if err != nil {
rt . Log . Error ( "insert into role failed" , err )
}
// Join some groups
sql = fmt . Sprintf ( "INSERT INTO rolemember (orgid, roleid, userid) VALUES (\"%s\", \"%s\", \"%s\")" , orgID , groupDevID , userID )
_ , err = runSQL ( rt , sql )
if err != nil {
rt . Log . Error ( "insert into rolemember failed" , err )
}
sql = fmt . Sprintf ( "INSERT INTO rolemember (orgid, roleid, userid) VALUES (\"%s\", \"%s\", \"%s\")" , orgID , groupProjectID , userID )
_ , err = runSQL ( rt , sql )
if err != nil {
rt . Log . Error ( "insert into rolemember failed" , err )
}
sql = fmt . Sprintf ( "INSERT INTO rolemember (orgid, roleid, userid) VALUES (\"%s\", \"%s\", \"%s\")" , orgID , groupBackofficeID , userID )
_ , err = runSQL ( rt , sql )
if err != nil {
rt . Log . Error ( "insert into rolemember failed" , err )
}
2016-07-07 18:54:16 -07:00
return
}
2017-08-02 15:26:31 +01:00
// runSQL creates a transaction per call
func runSQL ( rt * env . Runtime , sql string ) ( id uint64 , err error ) {
if strings . TrimSpace ( sql ) == "" {
return 0 , nil
}
tx , err := rt . Db . Beginx ( )
if err != nil {
rt . Log . Error ( "runSql - failed to get transaction" , err )
return
}
result , err := tx . Exec ( sql )
if err != nil {
tx . Rollback ( )
rt . Log . Error ( "runSql - unable to run sql" , err )
return
}
if err = tx . Commit ( ) ; err != nil {
rt . Log . Error ( "runSql - unable to commit sql" , err )
return
}
tempID , _ := result . LastInsertId ( )
id = uint64 ( tempID )
return
}