1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-19 05:09:42 +02:00

Enable in-app backup/restore for global/tenants

Re-mapping of ORG and USER ID values ensures conflict-free merging.

Version numbers bumped.

Co-Authored-By: Harvey Kandola <harvey@documize.com>
This commit is contained in:
sauls8t 2018-10-19 12:40:45 +01:00
parent ec1939c01d
commit db04057d9e
10 changed files with 913 additions and 788 deletions

View file

@ -58,9 +58,9 @@ Space view.
## Latest version
[Community edition: v1.71.0](https://github.com/documize/community/releases)
[Community edition: v1.72.0](https://github.com/documize/community/releases)
[Enterprise edition: v1.73.0](https://documize.com/downloads)
[Enterprise edition: v1.74.0](https://documize.com/downloads)
## OS support

1
core/env/logger.go vendored
View file

@ -15,6 +15,7 @@ package env
// Logger provides the interface for Documize compatible loggers.
type Logger interface {
Info(message string)
Infof(message string, a ...interface{})
Trace(message string)
Error(message string, err error)
// SetDB(l Logger, db *sqlx.DB) Logger

View file

@ -194,6 +194,7 @@ func (h *Handler) Restore(w http.ResponseWriter, r *http.Request) {
spec := m.ImportSpec{OverwriteOrg: overwriteOrg, CreateUsers: createUsers, Org: org}
rh := restoreHandler{Runtime: h.Runtime, Store: h.Store, Context: ctx, Spec: spec}
// Run the restore process.
err = rh.PerformRestore(b.Bytes(), r.ContentLength)
if err != nil {
response.WriteServerError(w, method, err)
@ -201,6 +202,8 @@ func (h *Handler) Restore(w http.ResponseWriter, r *http.Request) {
return
}
h.Runtime.Log.Infof("Restore remapped %d OrgID values", len(rh.MapOrgID))
h.Runtime.Log.Infof("Restore remapped %d UserID values", len(rh.MapUserID))
h.Runtime.Log.Info("Restore completed")
response.WriteEmpty(w)

View file

@ -18,6 +18,7 @@ package backup
import (
"archive/zip"
"bytes"
"database/sql"
"encoding/json"
"fmt"
"github.com/documize/community/model/account"
@ -48,11 +49,32 @@ import (
// Handler contains the runtime information such as logging and database.
type restoreHandler struct {
Runtime *env.Runtime
Store *store.Store
Spec m.ImportSpec
Context domain.RequestContext
Zip *zip.Reader
Runtime *env.Runtime
Store *store.Store
Spec m.ImportSpec
Context domain.RequestContext
Zip *zip.Reader
MapOrgID map[string]string
MapUserID map[string]string
}
// During the restore process, it may be necessary to change
// ID values found in backup file with a value that exists in the
// target database.
//
// NOTE: this only applies to tenant backups as we have to restore data
// into the active tenant.
func (r *restoreHandler) remapOrg(id string) string {
if n, ok := r.MapOrgID[id]; ok {
return n
}
return id
}
func (r *restoreHandler) remapUser(id string) string {
if n, ok := r.MapUserID[id]; ok {
return n
}
return id
}
// PerformRestore will unzip backup file and verify contents
@ -79,12 +101,40 @@ func (r *restoreHandler) PerformRestore(b []byte, l int64) (err error) {
r.Spec.GlobalBackup = false
}
// Process might require reassignment of ID's so prepare map.
r.MapOrgID = make(map[string]string)
r.MapUserID = make(map[string]string)
// Organization.
err = r.dmzOrg()
if err != nil {
return
}
// User.
err = r.dmzUser()
if err != nil {
return
}
// User Account.
err = r.dmzUserAccount()
if err != nil {
return
}
// User Activity.
err = r.dmzUserActivity()
if err != nil {
return
}
// User Config.
err = r.dmzUserConfig()
if err != nil {
return
}
// Config.
err = r.dmzConfig()
if err != nil {
@ -205,30 +255,6 @@ func (r *restoreHandler) PerformRestore(b []byte, l int64) (err error) {
return
}
// User.
err = r.dmzUser()
if err != nil {
return
}
// User Account.
err = r.dmzUserAccount()
if err != nil {
return
}
// User Activity.
err = r.dmzUserActivity()
if err != nil {
return
}
// User Config.
err = r.dmzUserConfig()
if err != nil {
return
}
return nil
}
@ -319,25 +345,24 @@ func (r *restoreHandler) dmzOrg() (err error) {
return
}
// Nuke all existing data.
_, err = r.Context.Transaction.Exec("TRUNCATE TABLE dmz_org")
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
return
}
// For global backup we recreate everything.
// For tenant backup we just update the current OrgID to match
// the one in the backup file, ensuring correct data linkage.
if r.Spec.GlobalBackup {
// Nuke all existing data.
_, err = r.Context.Transaction.Exec("TRUNCATE TABLE dmz_org")
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
for i := range org {
_, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind(`
INSERT INTO dmz_org (c_refid, c_company, c_title, c_message,
c_domain, c_service, c_email, c_anonaccess, c_authprovider, c_authconfig,
c_maxtags, c_verified, c_serial, c_active, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
INSERT INTO dmz_org (c_refid, c_company, c_title, c_message,
c_domain, c_service, c_email, c_anonaccess, c_authprovider, c_authconfig,
c_maxtags, c_verified, c_serial, c_active, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
org[i].RefID, org[i].Company, org[i].Title, org[i].Message,
strings.ToLower(org[i].Domain), org[i].ConversionEndpoint, strings.ToLower(org[i].Email),
org[i].AllowAnonymousAccess, org[i].AuthProvider, org[i].AuthConfig,
@ -356,7 +381,10 @@ func (r *restoreHandler) dmzOrg() (err error) {
return
}
org[1].RefID = r.Spec.Org.RefID
// Existing orgID from database overrides all incoming orgID values
// by using remapOrg().
r.MapOrgID[org[0].RefID] = r.Spec.Org.RefID
org[0].RefID = r.remapOrg(org[0].RefID) // e.g. remap orgID
// Update org settings if allowed to do so.
if !r.Spec.OverwriteOrg {
@ -373,17 +401,17 @@ func (r *restoreHandler) dmzOrg() (err error) {
}
_, err = r.Context.Transaction.NamedExec(`UPDATE dmz_org SET
c_anonaccess=:allowanonymousaccess,
c_authprovider=:authprovider,
c_authconfig=:authconfig,
c_company=:company,
c_service=:conversionendpoint,
c_email=:email,
c_maxtags=:maxtags,
c_message=:message,
c_title=:title,
c_serial=:serial
WHERE c_refid=:refid`, &org[0])
c_anonaccess=:allowanonymousaccess,
c_authprovider=:authprovider,
c_authconfig=:authconfig,
c_company=:company,
c_service=:conversionendpoint,
c_email=:email,
c_maxtags=:maxtags,
c_message=:message,
c_title=:title,
c_serial=:serial
WHERE c_refid=:refid`, &org[0])
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, "unable to overwrite current organization settings")
@ -460,13 +488,13 @@ func (r *restoreHandler) dmzAudit() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
for i := range log {
_, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind("INSERT INTO dmz_audit_log (c_orgid, c_userid, c_eventtype, c_ip, c_created) VALUES (?, ?, ?, ?, ?)"),
log[i].OrgID, log[i].UserID, log[i].Type, log[i].IP, log[i].Created)
r.remapOrg(log[i].OrgID), r.remapUser(log[i].UserID), log[i].Type, log[i].IP, log[i].Created)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to insert %s %d", filename, log[i].ID))
@ -516,13 +544,13 @@ func (r *restoreHandler) dmzAction() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
for i := range ac {
_, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind("INSERT INTO dmz_action (c_refid, c_orgid, c_userid, c_docid, c_actiontype, c_note, c_requestorid, c_requested, c_due, c_reftype, c_reftypeid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"),
ac[i].RefID, ac[i].OrgID, ac[i].UserID, ac[i].DocumentID, ac[i].ActionType, ac[i].Note, ac[i].RequestorID, ac[i].Requested, ac[i].Due, ac[i].RefType, ac[i].RefTypeID)
ac[i].RefID, r.remapOrg(ac[i].OrgID), r.remapUser(ac[i].UserID), ac[i].DocumentID, ac[i].ActionType, ac[i].Note, ac[i].RequestorID, ac[i].Requested, ac[i].Due, ac[i].RefType, ac[i].RefTypeID)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to insert %s %s", filename, ac[i].RefID))
@ -569,13 +597,13 @@ func (r *restoreHandler) dmzSpace() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
for i := range sp {
_, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind("INSERT INTO dmz_space (c_refid, c_name, c_orgid, c_userid, c_type, c_lifecycle, c_likes, c_created, c_revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"),
sp[i].RefID, sp[i].Name, sp[i].OrgID, sp[i].UserID, sp[i].Type, sp[i].Lifecycle, sp[i].Likes, sp[i].Created, sp[i].Revised)
sp[i].RefID, sp[i].Name, r.remapOrg(sp[i].OrgID), r.remapUser(sp[i].UserID), sp[i].Type, sp[i].Lifecycle, sp[i].Likes, sp[i].Created, sp[i].Revised)
if err != nil {
r.Context.Transaction.Rollback()
@ -623,7 +651,7 @@ func (r *restoreHandler) dmzCategory() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -631,7 +659,7 @@ func (r *restoreHandler) dmzCategory() (err error) {
_, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind(`
INSERT INTO dmz_category (c_refid, c_orgid, c_spaceid, c_name, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?)`),
ct[i].RefID, ct[i].OrgID, ct[i].SpaceID, ct[i].Name, ct[i].Created, ct[i].Revised)
ct[i].RefID, r.remapOrg(ct[i].OrgID), ct[i].SpaceID, ct[i].Name, ct[i].Created, ct[i].Revised)
if err != nil {
r.Context.Transaction.Rollback()
@ -679,7 +707,7 @@ func (r *restoreHandler) dmzCategoryMember() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -688,7 +716,7 @@ func (r *restoreHandler) dmzCategoryMember() (err error) {
INSERT INTO dmz_category_member
(c_refid, c_orgid, c_categoryid, c_spaceid, c_docid, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?)`),
cm[i].RefID, cm[i].OrgID, cm[i].CategoryID, cm[i].SpaceID, cm[i].DocumentID, cm[i].Created, cm[i].Revised)
cm[i].RefID, r.remapOrg(cm[i].OrgID), cm[i].CategoryID, cm[i].SpaceID, cm[i].DocumentID, cm[i].Created, cm[i].Revised)
if err != nil {
r.Context.Transaction.Rollback()
@ -736,7 +764,7 @@ func (r *restoreHandler) dmzGroup() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -745,7 +773,7 @@ func (r *restoreHandler) dmzGroup() (err error) {
INSERT INTO dmz_group
(c_refid, c_orgid, c_name, c_desc, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?)`),
gr[i].RefID, gr[i].OrgID, gr[i].Name, gr[i].Purpose, gr[i].Created, gr[i].Revised)
gr[i].RefID, r.remapOrg(gr[i].OrgID), gr[i].Name, gr[i].Purpose, gr[i].Created, gr[i].Revised)
if err != nil {
r.Context.Transaction.Rollback()
@ -793,7 +821,7 @@ func (r *restoreHandler) dmzGroupMember() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -802,7 +830,7 @@ func (r *restoreHandler) dmzGroupMember() (err error) {
INSERT INTO dmz_group_member
(c_orgid, c_groupid, c_userid)
VALUES (?, ?, ?)`),
gm[i].OrgID, gm[i].GroupID, gm[i].UserID)
r.remapOrg(gm[i].OrgID), gm[i].GroupID, r.remapUser(gm[i].UserID))
if err != nil {
r.Context.Transaction.Rollback()
@ -850,7 +878,7 @@ func (r *restoreHandler) dmzPermission() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -859,7 +887,9 @@ func (r *restoreHandler) dmzPermission() (err error) {
INSERT INTO dmz_permission
(c_orgid, c_who, c_whoid, c_action, c_scope, c_location, c_refid, c_created)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`),
pm[i].OrgID, string(pm[i].Who), pm[i].WhoID, string(pm[i].Action), string(pm[i].Scope), string(pm[i].Location), pm[i].RefID, pm[i].Created)
r.remapOrg(pm[i].OrgID), string(pm[i].Who), r.remapUser(pm[i].WhoID),
string(pm[i].Action), string(pm[i].Scope),
string(pm[i].Location), pm[i].RefID, pm[i].Created)
if err != nil {
r.Context.Transaction.Rollback()
@ -907,7 +937,7 @@ func (r *restoreHandler) dmzPin() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -916,7 +946,8 @@ func (r *restoreHandler) dmzPin() (err error) {
INSERT INTO dmz_pin
(c_refid, c_orgid, c_userid, c_spaceid, c_docid, c_name, c_sequence, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`),
pin[i].RefID, pin[i].OrgID, pin[i].UserID, pin[i].SpaceID, pin[i].DocumentID, pin[i].Name, pin[i].Sequence, pin[i].Created, pin[i].Revised)
pin[i].RefID, r.remapOrg(pin[i].OrgID), r.remapUser(pin[i].UserID), pin[i].SpaceID,
pin[i].DocumentID, pin[i].Name, pin[i].Sequence, pin[i].Created, pin[i].Revised)
if err != nil {
r.Context.Transaction.Rollback()
@ -964,7 +995,7 @@ func (r *restoreHandler) dmzSection() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -974,7 +1005,7 @@ func (r *restoreHandler) dmzSection() (err error) {
(c_refid, c_orgid, c_docid, c_userid, c_contenttype, c_type, c_level, c_name, c_body,
c_revisions, c_sequence, c_templateid, c_status, c_relativeid, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
sc[i].RefID, sc[i].OrgID, sc[i].DocumentID, sc[i].UserID,
sc[i].RefID, r.remapOrg(sc[i].OrgID), sc[i].DocumentID, r.remapUser(sc[i].UserID),
sc[i].ContentType, sc[i].Type, sc[i].Level, sc[i].Name,
sc[i].Body, sc[i].Revisions, sc[i].Sequence, sc[i].TemplateID,
sc[i].Status, sc[i].RelativeID, sc[i].Created, sc[i].Revised)
@ -1026,7 +1057,7 @@ func (r *restoreHandler) dmzSectionMeta() (err error) {
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -1036,7 +1067,7 @@ func (r *restoreHandler) dmzSectionMeta() (err error) {
(c_sectionid, c_orgid, c_userid, c_docid, c_rawbody,
c_config, c_external, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`),
sm[i].SectionID, sm[i].OrgID, sm[i].UserID, sm[i].DocumentID,
sm[i].SectionID, r.remapOrg(sm[i].OrgID), r.remapUser(sm[i].UserID), sm[i].DocumentID,
sm[i].RawBody, sm[i].Config, sm[i].ExternalSource,
sm[i].Created, sm[i].Revised)
@ -1086,7 +1117,7 @@ func (r *restoreHandler) dmzSectionRevision() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -1096,8 +1127,8 @@ func (r *restoreHandler) dmzSectionRevision() (err error) {
(c_refid, c_orgid, c_docid, c_ownerid, c_sectionid, c_userid, c_contenttype,
c_type, c_name, c_body, c_rawbody, c_config, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
sr[i].RefID, sr[i].OrgID, sr[i].DocumentID, sr[i].OwnerID,
sr[i].SectionID, sr[i].UserID, sr[i].ContentType, sr[i].Type, sr[i].Name,
sr[i].RefID, r.remapOrg(sr[i].OrgID), sr[i].DocumentID, sr[i].OwnerID,
sr[i].SectionID, r.remapUser(sr[i].UserID), sr[i].ContentType, sr[i].Type, sr[i].Name,
sr[i].Body, sr[i].RawBody, sr[i].Config, sr[i].Created, sr[i].Revised)
if err != nil {
@ -1146,7 +1177,7 @@ func (r *restoreHandler) dmzSectionTemplate() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -1157,7 +1188,8 @@ func (r *restoreHandler) dmzSectionTemplate() (err error) {
c_type, c_name, c_body, c_desc, c_rawbody, c_used,
c_config, c_external, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
st[i].RefID, st[i].OrgID, st[i].SpaceID, st[i].UserID, st[i].ContentType, st[i].Type,
st[i].RefID, r.remapOrg(st[i].OrgID), st[i].SpaceID, r.remapUser(st[i].UserID),
st[i].ContentType, st[i].Type,
st[i].Name, st[i].Body, st[i].Excerpt, st[i].RawBody, st[i].Used,
st[i].Config, st[i].ExternalSource, st[i].Created, st[i].Revised)
@ -1207,7 +1239,7 @@ func (r *restoreHandler) dmzDoc() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -1218,7 +1250,7 @@ func (r *restoreHandler) dmzDoc() (err error) {
c_name, c_desc, c_slug, c_tags, c_template, c_protection, c_approval,
c_lifecycle, c_versioned, c_versionid, c_versionorder, c_groupid, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
doc[i].RefID, doc[i].OrgID, doc[i].SpaceID, doc[i].UserID, doc[i].Job,
doc[i].RefID, r.remapOrg(doc[i].OrgID), doc[i].SpaceID, r.remapUser(doc[i].UserID), doc[i].Job,
doc[i].Location, doc[i].Name, doc[i].Excerpt, doc[i].Slug, doc[i].Tags,
doc[i].Template, doc[i].Protection, doc[i].Approval, doc[i].Lifecycle,
doc[i].Versioned, doc[i].VersionID, doc[i].VersionOrder, doc[i].GroupID,
@ -1279,7 +1311,7 @@ func (r *restoreHandler) dmzDocVote() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -1287,7 +1319,7 @@ func (r *restoreHandler) dmzDocVote() (err error) {
_, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind(`
INSERT INTO dmz_doc_vote (c_refid, c_orgid, c_docid, c_voter, c_vote, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?)`),
v[i].RefID, v[i].OrgID, v[i].DocumentID, v[i].VoterID, v[i].Vote, v[i].Created, v[i].Revised)
v[i].RefID, r.remapOrg(v[i].OrgID), v[i].DocumentID, v[i].VoterID, v[i].Vote, v[i].Created, v[i].Revised)
if err != nil {
r.Context.Transaction.Rollback()
@ -1335,7 +1367,7 @@ func (r *restoreHandler) dmzDocLink() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -1345,7 +1377,8 @@ func (r *restoreHandler) dmzDocLink() (err error) {
(c_refid, c_orgid, c_spaceid, c_userid, c_sourcedocid, c_sourcesectionid,
c_targetdocid, c_targetid, c_externalid, c_type, c_orphan, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
lk[i].RefID, lk[i].OrgID, lk[i].SpaceID, lk[i].UserID, lk[i].SourceDocumentID, lk[i].SourceSectionID,
lk[i].RefID, r.remapOrg(lk[i].OrgID), lk[i].SpaceID, r.remapUser(lk[i].UserID),
lk[i].SourceDocumentID, lk[i].SourceSectionID,
lk[i].TargetDocumentID, lk[i].TargetID, lk[i].ExternalID, lk[i].LinkType, lk[i].Orphan,
lk[i].Created, lk[i].Revised)
@ -1395,7 +1428,7 @@ func (r *restoreHandler) dmzDocAttachment() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -1405,7 +1438,8 @@ func (r *restoreHandler) dmzDocAttachment() (err error) {
(c_refid, c_orgid, c_docid, c_job, c_fileid,
c_filename, c_data, c_extension, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
at[i].RefID, at[i].OrgID, at[i].DocumentID, at[i].Job, at[i].FileID, at[i].Filename,
at[i].RefID, r.remapOrg(at[i].OrgID), at[i].DocumentID, at[i].Job,
at[i].FileID, at[i].Filename,
at[i].Data, at[i].Extension, at[i].Created, at[i].Revised)
if err != nil {
@ -1440,7 +1474,6 @@ func (r *restoreHandler) dmzDocComment() (err error) {
Feedback string `json:"feedback"`
Created string `json:"created"`
}
cm := []comment{}
err = r.fileJSON(filename, &cm)
if err != nil {
@ -1464,7 +1497,7 @@ func (r *restoreHandler) dmzDocComment() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -1473,7 +1506,7 @@ func (r *restoreHandler) dmzDocComment() (err error) {
INSERT INTO dmz_doc_comment
(c_refid, c_orgid, c_userid, c_docid, c_email, c_feedback, c_created)
VALUES (?, ?, ?, ?, ?, ?, ?)`),
cm[i].RefID, cm[i].OrgID, cm[i].UserID, cm[i].DocumentID,
cm[i].RefID, r.remapOrg(cm[i].OrgID), r.remapUser(cm[i].UserID), cm[i].DocumentID,
cm[i].Email, cm[i].Feedback, cm[i].Created)
if err != nil {
@ -1512,7 +1545,6 @@ func (r *restoreHandler) dmzDocShare() (err error) {
Active bool `json:"active"`
Created time.Time `json:"created"`
}
sh := []share{}
err = r.fileJSON(filename, &sh)
if err != nil {
@ -1536,7 +1568,7 @@ func (r *restoreHandler) dmzDocShare() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -1546,7 +1578,7 @@ func (r *restoreHandler) dmzDocShare() (err error) {
(c_orgid, c_userid, c_docid, c_email, c_message,
c_secret, c_expires, c_active, c_created)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`),
sh[i].OrgID, sh[i].UserID, sh[i].DocumentID, sh[i].Email, sh[i].Message,
r.remapOrg(sh[i].OrgID), r.remapUser(sh[i].UserID), sh[i].DocumentID, sh[i].Email, sh[i].Message,
sh[i].Secret, sh[i].Expires, sh[i].Active, sh[i].Created)
if err != nil {
@ -1592,25 +1624,49 @@ func (r *restoreHandler) dmzUser() (err error) {
_, err = r.Context.Transaction.Exec("TRUNCATE TABLE dmz_user")
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
}
for i := range u {
_, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind(`
// For tenant backups we first check to see if user exists.
insert := true
if !r.Spec.GlobalBackup {
row := r.Runtime.Db.QueryRow(r.Runtime.Db.Rebind("SELECT COALESCE(c_refid, '') AS userid FROM dmz_user WHERE c_email=?"), u[i].Email)
userID := ""
err = row.Scan(&userID)
if err == sql.ErrNoRows {
err = nil
insert = true
}
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("unable to check email %s", u[i].Email))
return
}
// Existing userID from database overrides all incoming userID values
// by using remapUser().
if len(userID) > 0 {
r.MapUserID[u[i].RefID] = userID
insert = false
}
}
if insert {
_, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind(`
INSERT INTO dmz_user
(c_refid, c_firstname, c_lastname, c_email, c_initials, c_globaladmin,
c_password, c_salt, c_reset, c_active, c_lastversion, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
u[i].RefID, u[i].Firstname, u[i].Lastname, strings.ToLower(u[i].Email), u[i].Initials,
u[i].GlobalAdmin, u[i].Password, u[i].Salt, u[i].Reset, u[i].Active,
u[i].LastVersion, u[i].Created, u[i].Revised)
r.remapUser(u[i].RefID), u[i].Firstname, u[i].Lastname, strings.ToLower(u[i].Email), u[i].Initials,
u[i].GlobalAdmin, u[i].Password, u[i].Salt, u[i].Reset, u[i].Active,
u[i].LastVersion, u[i].Created, u[i].Revised)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to insert %s %s", filename, u[i].RefID))
return
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to insert %s %s", filename, u[i].RefID))
return
}
}
}
@ -1653,7 +1709,7 @@ func (r *restoreHandler) dmzUserAccount() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -1663,7 +1719,7 @@ func (r *restoreHandler) dmzUserAccount() (err error) {
(c_refid, c_orgid, c_userid, c_admin, c_editor, c_users,
c_analytics, c_active, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
ac[i].RefID, ac[i].OrgID, ac[i].UserID, ac[i].Admin, ac[i].Editor,
ac[i].RefID, r.remapOrg(ac[i].OrgID), r.remapUser(ac[i].UserID), ac[i].Admin, ac[i].Editor,
ac[i].Users, ac[i].Analytics, ac[i].Active, ac[i].Created, ac[i].Revised)
if err != nil {
@ -1712,7 +1768,7 @@ func (r *restoreHandler) dmzUserActivity() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -1722,7 +1778,7 @@ func (r *restoreHandler) dmzUserActivity() (err error) {
(c_orgid, c_userid, c_spaceid, c_docid, c_sectionid, c_sourcetype,
c_activitytype, c_metadata, c_created)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`),
ac[i].OrgID, ac[i].UserID, ac[i].SpaceID, ac[i].DocumentID,
r.remapOrg(ac[i].OrgID), r.remapUser(ac[i].UserID), ac[i].SpaceID, ac[i].DocumentID,
ac[i].SectionID, ac[i].SourceType, ac[i].ActivityType,
ac[i].Metadata, ac[i].Created)
@ -1778,7 +1834,7 @@ func (r *restoreHandler) dmzUserConfig() (err error) {
_, err = r.Context.Transaction.Exec(nuke)
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table", filename))
err = errors.Wrap(err, fmt.Sprintf("unable to truncate table %s", filename))
return
}
@ -1787,7 +1843,7 @@ func (r *restoreHandler) dmzUserConfig() (err error) {
INSERT INTO dmz_user_config
(c_orgid, c_userid, c_key, c_config)
VALUES (?, ?, ?, ?)`),
uc[i].OrgID, uc[i].UserID, uc[i].ConfigKey, uc[i].ConfigValue)
r.remapOrg(uc[i].OrgID), r.remapUser(uc[i].UserID), uc[i].ConfigKey, uc[i].ConfigValue)
if err != nil {
r.Context.Transaction.Rollback()

View file

@ -0,0 +1,59 @@
// 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 backup
import (
"testing"
)
// go test github.com/documize/community/domain/backup -run TestRemapORg
func TestRemapOrg(t *testing.T) {
r := restoreHandler{MapOrgID: make(map[string]string)}
r.MapOrgID["abc"] = "def"
r.MapOrgID["xyz"] = "123"
n := r.remapOrg("abc")
if n != "def" {
t.Errorf("expected def got %s", n)
}
n = r.remapOrg("xyz")
if n != "123" {
t.Errorf("expected 123 got %s", n)
}
n = r.remapOrg("jkl")
if n != "jkl" {
t.Errorf("expected jkl got %s", n)
}
}
func TestRemapUser(t *testing.T) {
r := restoreHandler{MapUserID: make(map[string]string)}
r.MapUserID["abc"] = "def"
r.MapUserID["xyz"] = "123"
n := r.remapUser("abc")
if n != "def" {
t.Errorf("expected def got %s", n)
}
n = r.remapUser("xyz")
if n != "123" {
t.Errorf("expected 123 got %s", n)
}
n = r.remapUser("jkl")
if n != "jkl" {
t.Errorf("expected jkl got %s", n)
}
}

View file

@ -38,7 +38,7 @@ func main() {
// product details
rt.Product = env.ProdInfo{}
rt.Product.Major = "1"
rt.Product.Minor = "71"
rt.Product.Minor = "72"
rt.Product.Patch = "0"
rt.Product.Revision = 181007125514
rt.Product.Version = fmt.Sprintf("%s.%s.%s", rt.Product.Major, rt.Product.Minor, rt.Product.Patch)

View file

@ -35,6 +35,11 @@ func (l Logger) Info(message string) {
l.log.Println(message)
}
// Infof logs message via Sprintf.
func (l Logger) Infof(message string, a ...interface{}) {
l.log.Println(fmt.Sprintf(message, a))
}
// Trace logs message if tracing enabled.
func (l Logger) Trace(message string) {
if l.trace {

File diff suppressed because one or more lines are too long

View file

@ -24,6 +24,7 @@
As a Documize <b>Tenant Administrator</b> you can perform a tenant-level backup (e.g. marketing.mycompany.com).
</p>
{{/if}}
<p>Please use a Tenant Backup when migrating between self-host and Documize Cloud hosting.</p>
<p>It can take <b>several minutes</b> to complete the backup process &mdash; please be patient while the backup operation is in progress.</p>
<div class="margin-top-30 margin-bottom-20">
@ -35,10 +36,10 @@
{{#if backupRunning}}
<h3 class="text-success">Backup running, please wait...</h3>
{{else}}
<button class="btn btn-success mb-3" {{action 'onBackup'}}>BACKUP TENANT</button>
<button class="btn btn-success mb-3" {{action 'onBackup'}}>TENANT BACKUP ({{appMeta.appHost}})</button>
{{#if session.isGlobalAdmin}}
<div class="button-gap" />
<button class="btn btn-success mb-3" {{action 'onSystemBackup'}}>BACKUP SYSTEM</button>
<button class="btn btn-success mb-3" {{action 'onSystemBackup'}}>SYSTEM BACKUP</button>
{{/if}}
{{/if}}
{{#if backupFailed}}

View file

@ -1,6 +1,6 @@
{
"name": "documize",
"version": "1.71.0",
"version": "1.72.0",
"description": "The Document IDE",
"private": true,
"repository": "",