mirror of
https://github.com/documize/community.git
synced 2025-07-24 07:39:43 +02:00
Xid dependency updated. Moved to 20 length ID values. Added new revision number to version and meta information. Revision number is timestamp format.
186 lines
4.7 KiB
Go
186 lines
4.7 KiB
Go
// 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 (
|
|
"archive/zip"
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"os"
|
|
|
|
"github.com/documize/community/core/env"
|
|
"github.com/documize/community/core/response"
|
|
"github.com/documize/community/core/streamutil"
|
|
"github.com/documize/community/core/uniqueid"
|
|
"github.com/documize/community/domain"
|
|
indexer "github.com/documize/community/domain/search"
|
|
"github.com/documize/community/domain/store"
|
|
)
|
|
|
|
// Handler contains the runtime information such as logging and database.
|
|
type Handler struct {
|
|
Runtime *env.Runtime
|
|
Store *store.Store
|
|
Indexer indexer.Indexer
|
|
}
|
|
|
|
// Backup generates binary file of all instance settings and contents.
|
|
// The content is pulled directly from the database and marshalled to JSON.
|
|
// A zip file is then sent to the caller.
|
|
func (h *Handler) Backup(w http.ResponseWriter, r *http.Request) {
|
|
method := "system.backup"
|
|
ctx := domain.GetRequestContext(r)
|
|
|
|
if !ctx.Administrator {
|
|
response.WriteForbiddenError(w)
|
|
h.Runtime.Log.Info(fmt.Sprintf("Non-admin attempted system backup operation (user ID: %s)", ctx.UserID))
|
|
return
|
|
}
|
|
|
|
defer streamutil.Close(r.Body)
|
|
body, err := ioutil.ReadAll(r.Body)
|
|
if err != nil {
|
|
response.WriteBadRequestError(w, method, err.Error())
|
|
h.Runtime.Log.Error(method, err)
|
|
return
|
|
}
|
|
|
|
spec := backupSpec{}
|
|
err = json.Unmarshal(body, &spec)
|
|
if err != nil {
|
|
response.WriteBadRequestError(w, method, err.Error())
|
|
h.Runtime.Log.Error(method, err)
|
|
return
|
|
}
|
|
|
|
// data, err := backup(ctx, *h.Store, spec)
|
|
// if err != nil {
|
|
// response.WriteServerError(w, method, err)
|
|
// h.Runtime.Log.Error(method, err)
|
|
// return
|
|
// }
|
|
|
|
// Filename is current timestamp
|
|
fn := fmt.Sprintf("dmz-backup-%s.zip", uniqueid.Generate())
|
|
|
|
ziptest(fn)
|
|
|
|
bb, err := ioutil.ReadFile(fn)
|
|
if err != nil {
|
|
response.WriteServerError(w, method, err)
|
|
h.Runtime.Log.Error(method, err)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/zip")
|
|
w.Header().Set("Content-Disposition", `attachment; filename="`+fn+`" ; `+`filename*="`+fn+`"`)
|
|
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(bb)))
|
|
w.Header().Set("x-documize-filename", fn)
|
|
|
|
x, err := w.Write(bb)
|
|
if err != nil {
|
|
response.WriteServerError(w, method, err)
|
|
h.Runtime.Log.Error(method, err)
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
h.Runtime.Log.Info(fmt.Sprintf("Backup completed for %s by %s, size %d", ctx.OrgID, ctx.UserID, x))
|
|
}
|
|
|
|
type backupSpec struct {
|
|
}
|
|
|
|
func backup(ctx domain.RequestContext, s store.Store, spec backupSpec) (file []byte, err error) {
|
|
buf := new(bytes.Buffer)
|
|
zw := zip.NewWriter(buf)
|
|
|
|
// Add some files to the archive.
|
|
var files = []struct {
|
|
Name, Body string
|
|
}{
|
|
{"readme.txt", "This archive contains some text files."},
|
|
{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
|
|
{"todo.txt", "Get animal handling licence.\nWrite more examples."},
|
|
}
|
|
|
|
for _, file := range files {
|
|
f, err := zw.Create(file.Name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
_, err = f.Write([]byte(file.Body))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// Make sure to check the error on Close.
|
|
err = zw.Close()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
func ziptest(filename string) {
|
|
// Create a file to write the archive buffer to
|
|
// Could also use an in memory buffer.
|
|
outFile, err := os.Create(filename)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
defer outFile.Close()
|
|
|
|
// Create a zip writer on top of the file writer
|
|
zipWriter := zip.NewWriter(outFile)
|
|
|
|
// Add files to archive
|
|
// We use some hard coded data to demonstrate,
|
|
// but you could iterate through all the files
|
|
// in a directory and pass the name and contents
|
|
// of each file, or you can take data from your
|
|
// program and write it write in to the archive
|
|
// without
|
|
var filesToArchive = []struct {
|
|
Name, Body string
|
|
}{
|
|
{"test.txt", "String contents of file"},
|
|
{"test2.txt", "\x61\x62\x63\n"},
|
|
}
|
|
|
|
// Create and write files to the archive, which in turn
|
|
// are getting written to the underlying writer to the
|
|
// .zip file we created at the beginning
|
|
for _, file := range filesToArchive {
|
|
fileWriter, err := zipWriter.Create(file.Name)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
_, err = fileWriter.Write([]byte(file.Body))
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
}
|
|
|
|
// Clean up
|
|
err = zipWriter.Close()
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
}
|