1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-08-09 07:25:23 +02:00

Compare commits

..

No commits in common. "master" and "v1.66.0" have entirely different histories.

2429 changed files with 154915 additions and 456451 deletions

View file

@ -1,6 +1,3 @@
.DS_Store
.git
bin
.idea
selfcert
gui/dist-prod

9
.editorconfig Normal file
View file

@ -0,0 +1,9 @@
root = true
[*]
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
indent_size = 4
insert_final_newline = true

5
.gitignore vendored
View file

@ -18,7 +18,6 @@ _convert
bin/*
dist/*
embed/bindata/*
edition/static/*
gui/dist/*
gui/dist-prod/*
@ -53,12 +52,14 @@ _testmain.go
node_modules
# Misc.
build
plugin-msword/plugin-msword
plugin-msword/plugin-msword-osx
npm-debug.log
debug
*.pem
*.crt
Dockerfile
container.sh
make.sh
jsconfig.json
@ -69,5 +70,3 @@ testem.log
bower.json.ember-try
package.json.ember-try
embed/bindata_assetfs.go
dmz-backup*.zip
*.conf

62
.jsbeautifyrc Normal file
View file

@ -0,0 +1,62 @@
{
"css": {
"indent_size": 4,
"indent_level": 0,
"indent_with_tabs": true,
"preserve_newlines": true,
"max_preserve_newlines": 2,
"newline_between_rules": true,
"selector_separator_newlines": true
},
"scss": {
"indent_size": 4,
"indent_level": 0,
"indent_with_tabs": true,
"preserve_newlines": true,
"max_preserve_newlines": 2,
"newline_between_rules": true,
"selector_separator_newlines": true
},
"html": {
"indent_size": 4,
"indent_level": 0,
"indent_with_tabs": true,
"preserve_newlines": true,
"max_preserve_newlines": 2,
"wrap_line_length": 0,
"indent_handlebars": true,
"indent_inner_html": false,
"indent_scripts": "keep"
},
"hbs": {
"indent_size": 4,
"indent_level": 0,
"indent_with_tabs": true,
"max_preserve_newlines": 2,
"preserve_newlines": true,
"wrap_line_length": 0
},
"js": {
"indent_size": 4,
"indent_level": 0,
"indent_with_tabs": true,
"preserve_newlines": true,
"wrap_line_length": 0,
"break_chained_methods": false,
"max_preserve_newlines": 2,
"jslint_happy": true,
"brace_style": "collapse-preserve-inline",
"keep_function_indentation": false,
"space_after_anon_function": false,
"space_before_anon_function": false,
"space_before_conditional": true,
"space_in_empty_paren": false,
"space_before_func_paren": false,
"space_in_paren": false
},
"sql": {
"indent_size": 4,
"indent_level": 0,
"indent_with_tabs": true
}
}

3
.jshintignore Normal file
View file

@ -0,0 +1,3 @@
gui/public/tinymce/**
gui/public/tinymce/
gui/public/tinymce

3
.jshintrc Normal file
View file

@ -0,0 +1,3 @@
{
"esversion":6
}

View file

@ -1,32 +0,0 @@
FROM node:16-alpine as frontbuilder
WORKDIR /go/src/github.com/documize/community/gui
COPY ./gui /go/src/github.com/documize/community/gui
RUN npm --network-timeout=100000 install
RUN npm run build -- --environment=production --output-path dist-prod --suppress-sizes true
FROM golang:1.21-alpine as builder
WORKDIR /go/src/github.com/documize/community
COPY . /go/src/github.com/documize/community
COPY --from=frontbuilder /go/src/github.com/documize/community/gui/dist-prod/assets /go/src/github.com/documize/community/edition/static/public/assets
COPY --from=frontbuilder /go/src/github.com/documize/community/gui/dist-prod/codemirror /go/src/github.com/documize/community/edition/static/public/codemirror
COPY --from=frontbuilder /go/src/github.com/documize/community/gui/dist-prod/prism /go/src/github.com/documize/community/edition/static/public/prism
COPY --from=frontbuilder /go/src/github.com/documize/community/gui/dist-prod/sections /go/src/github.com/documize/community/edition/static/public/sections
COPY --from=frontbuilder /go/src/github.com/documize/community/gui/dist-prod/tinymce /go/src/github.com/documize/community/edition/static/public/tinymce
COPY --from=frontbuilder /go/src/github.com/documize/community/gui/dist-prod/pdfjs /go/src/github.com/documize/community/edition/static/public/pdfjs
COPY --from=frontbuilder /go/src/github.com/documize/community/gui/dist-prod/i18n /go/src/github.com/documize/community/edition/static/public/i18n
COPY --from=frontbuilder /go/src/github.com/documize/community/gui/dist-prod/*.* /go/src/github.com/documize/community/edition/static/
COPY --from=frontbuilder /go/src/github.com/documize/community/gui/dist-prod/i18n/*.json /go/src/github.com/documize/community/edition/static/i18n/
COPY domain/mail/*.html /go/src/github.com/documize/community/edition/static/mail/
COPY core/database/templates/*.html /go/src/github.com/documize/community/edition/static/
COPY core/database/scripts/mysql/*.sql /go/src/github.com/documize/community/edition/static/scripts/mysql/
COPY core/database/scripts/postgresql/*.sql /go/src/github.com/documize/community/edition/static/scripts/postgresql/
COPY core/database/scripts/sqlserver/*.sql /go/src/github.com/documize/community/edition/static/scripts/sqlserver/
COPY domain/onboard/*.json /go/src/github.com/documize/community/edition/static/onboard/
RUN env GODEBUG=tls13=1 go build -mod=vendor -o bin/documize-community ./edition/community.go
# build release image
FROM alpine:3.16
RUN apk add --no-cache ca-certificates
COPY --from=builder /go/src/github.com/documize/community/bin/documize-community /documize
EXPOSE 5001
ENTRYPOINT [ "/documize" ]

175
Gopkg.lock generated Normal file
View file

@ -0,0 +1,175 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/codegangsta/negroni"
packages = ["."]
revision = "5dbbc83f748fc3ad38585842b0aedab546d0ea1e"
version = "v0.3.0"
[[projects]]
name = "github.com/dgrijalva/jwt-go"
packages = ["."]
revision = "dbeaa9332f19a944acb5736b4456cfcc02140e29"
version = "v3.1.0"
[[projects]]
name = "github.com/documize/blackfriday"
packages = ["."]
revision = "cadec560ec52d93835bf2f15bd794700d3a2473b"
version = "v2.0.0"
[[projects]]
branch = "master"
name = "github.com/documize/glick"
packages = ["."]
revision = "a8ccbef88237fcafe9cef3c9aee7ad83d0e132f9"
[[projects]]
branch = "master"
name = "github.com/documize/html-diff"
packages = ["."]
revision = "f61c192c7796644259832ef705c49259797e7fff"
[[projects]]
name = "github.com/documize/slug"
packages = ["."]
revision = "e9f42fa127660e552d0ad2b589868d403a9be7c6"
version = "v1.1.1"
[[projects]]
name = "github.com/elazarl/go-bindata-assetfs"
packages = ["."]
revision = "30f82fa23fd844bd5bb1e5f216db87fd77b5eb43"
version = "v1.0.0"
[[projects]]
name = "github.com/go-sql-driver/mysql"
packages = ["."]
revision = "a0583e0143b1624142adab07e0e97fe106d99561"
version = "v1.3"
[[projects]]
name = "github.com/golang/protobuf"
packages = ["proto"]
revision = "925541529c1fa6821df4e44ce2723319eb2be768"
version = "v1.0.0"
[[projects]]
name = "github.com/google/go-github"
packages = ["github"]
revision = "e48060a28fac52d0f1cb758bc8b87c07bac4a87d"
version = "v15.0.0"
[[projects]]
branch = "master"
name = "github.com/google/go-querystring"
packages = ["query"]
revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a"
[[projects]]
name = "github.com/gorilla/context"
packages = ["."]
revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a"
version = "v1.1"
[[projects]]
name = "github.com/gorilla/mux"
packages = ["."]
revision = "53c1911da2b537f792e7cafcb446b05ffe33b996"
version = "v1.6.1"
[[projects]]
branch = "master"
name = "github.com/jmoiron/sqlx"
packages = [
".",
"reflectx"
]
revision = "05cef0741ade10ca668982355b3f3f0bcf0ff0a8"
[[projects]]
branch = "master"
name = "github.com/mb0/diff"
packages = ["."]
revision = "d8d9a906c24d7b0ee77287e0463e5ca7f026032e"
[[projects]]
branch = "master"
name = "github.com/nu7hatch/gouuid"
packages = ["."]
revision = "179d4d0c4d8d407a32af483c2354df1d2c91e6c3"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
branch = "master"
name = "github.com/rainycape/unidecode"
packages = ["."]
revision = "cb7f23ec59bec0d61b19c56cd88cee3d0cc1870c"
[[projects]]
branch = "master"
name = "github.com/shurcooL/sanitized_anchor_name"
packages = ["."]
revision = "86672fcb3f950f35f2e675df2240550f2a50762f"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = [
"bcrypt",
"blowfish"
]
revision = "650f4a345ab4e5b245a3034b110ebc7299e68186"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = [
"context",
"context/ctxhttp",
"html",
"html/atom"
]
revision = "f5dfe339be1d06f81b22525fe34671ee7d2c8904"
[[projects]]
branch = "master"
name = "golang.org/x/oauth2"
packages = [
".",
"internal"
]
revision = "543e37812f10c46c622c9575afd7ad22f22a12ba"
[[projects]]
name = "google.golang.org/appengine"
packages = [
"internal",
"internal/base",
"internal/datastore",
"internal/log",
"internal/remote_api",
"internal/urlfetch",
"urlfetch"
]
revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
version = "v1.0.0"
[[projects]]
branch = "v3"
name = "gopkg.in/alexcesaro/quotedprintable.v3"
packages = ["."]
revision = "2caba252f4dc53eaf6b553000885530023f54623"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "a21753e8c217630ea2893ea4a4ee682749e28d4eb6acf70b9b5982ab8c521a20"
solver-name = "gps-cdcl"
solver-version = 1

98
Gopkg.toml Normal file
View file

@ -0,0 +1,98 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[[constraint]]
name = "github.com/codegangsta/negroni"
version = "0.3.0"
[[constraint]]
name = "github.com/dgrijalva/jwt-go"
version = "3.1.0"
[[constraint]]
name = "github.com/documize/blackfriday"
version = "2.0.0"
[[constraint]]
branch = "master"
name = "github.com/documize/glick"
[[constraint]]
branch = "master"
name = "github.com/documize/html-diff"
[[constraint]]
name = "github.com/elazarl/go-bindata-assetfs"
version = "1.0.0"
[[constraint]]
name = "github.com/go-sql-driver/mysql"
version = "1.3.0"
[[constraint]]
name = "github.com/google/go-github"
version = "15.0.0"
[[constraint]]
name = "github.com/gorilla/mux"
version = "1.6.1"
[[constraint]]
branch = "master"
name = "github.com/jmoiron/sqlx"
[[constraint]]
branch = "master"
name = "github.com/nu7hatch/gouuid"
[[constraint]]
name = "github.com/pkg/errors"
version = "0.8.0"
[[constraint]]
branch = "master"
name = "golang.org/x/crypto"
[[constraint]]
branch = "master"
name = "golang.org/x/net"
[[constraint]]
branch = "master"
name = "golang.org/x/oauth2"
[prune]
go-tests = true
unused-packages = true
[[constraint]]
branch = "master"
name = "github.com/documize/unidecode"
[[constraint]]
name = "github.com/documize/slug"
version = "1.1.1"

2572
NOTICES.md

File diff suppressed because it is too large Load diff

162
README.md
View file

@ -1,110 +1,128 @@
Documize Community is an open source, modern, self-hosted, enterprise-grade knowledge management solution.
> We're committed to providing frequent product releases to ensure self-host customers enjoy the same product as our cloud/SaaS customers.
>
> Harvey Kandola, CEO & Founder, Documize Inc.
- Built for technical and non-technical users
- Designed to unify both customer-facing and internal documentation
- Organization through labels, spaces and categories
## The mission
It's built with Golang + EmberJS and compiled down to a single executable binary that is available for Linux, Windows and Mac.
To bring software development inspired features to the world of documenting -- refactoring, importing, testing, linting, metrics, PRs, versioning....
All you need to provide is your database -- PostgreSQL, Microsoft SQL Server or any MySQL variant.
## What is it?
![Documize Community](https://github.com/documize/community/blob/master/screenshot.png?raw=true)
Documize is an intelligent document environment (IDE) for authoring, tracking and delivering documentation -- everything you need in one place.
## Latest Release
## Why should I care?
[Community edition: v5.13.0](https://github.com/documize/community/releases)
Because maybe like us you're tired of:
[Community+ edition: v5.13.0](https://www.documize.com/community/get-started)
* juggling WYSIWYG editors, wiki software and other document related solutions
* playing email tennis with documents, contributions, versions and feedback
* sharing not-so-secure folders with external participants
The Community+ edition is the "enterprise" offering with advanced capabilities and customer support:
Sound familiar? Read on.
- content approval workflows
- content organization by label, space and category
- content version management
- content lifecycle management
- content feedback capture
- content PDF export
- analytics and reporting
- activity streams
- audit logs
- actions assignments
- product support
## Who is it for?
The Community+ edition is [free](https://www.documize.com/community/get-started) for the first five users -- thereafter pricing starts at just $900 annually for 100 users.
Anyone who wants a single place for any kind of document.
## OS Support
Anyone who wants to loop in external participants with complete security.
Anyone who wishes documentation and knowledge capture worked like agile software development.
Anyone who knows that nested folders fail miserably.
Anyone who wants to move on from wiki software.
## What's different about Documize?
Sane organization through personal, team and public spaces.
Granular document access control via categories.
Section based approach to document construction.
Reusable templates and content blocks.
Documentation related tasking and delegation.
Integrations for embedding SaaS data within documents, zero add-on/marketplace fees.
## What does it look like?
All spaces.
![Documize](screenshot-1.png "Documize")
Space view.
![Documize](screenshot-2.png "Documize")
## Latest version
[Community edition: v1.66.0](https://github.com/documize/community/releases)
[Enterprise edition: v1.68.0](https://documize.com/downloads)
## OS support
Documize runs on the following:
- Linux
- Windows
- macOS
- Raspberry Pi (ARM build)
Support for AMD and ARM 64 bit architectures.
# Browser support
## Database Support
Documize supports the following (evergreen) browsers:
For all database types, Full-Text Search (FTS) support is mandatory.
- Chrome
- Firefox
- Safari
- Brave
- MS Edge (16+)
- PostgreSQL (v9.6+)
- Microsoft SQL Server (2016+ with FTS)
- Microsoft SQL Azure (v12+)
- MySQL (v5.7.10+ and v8.0.12+)
## Technology stack
Documize is built with the following technologies:
- EmberJS (v3.1.2)
- Go (v1.10.3)
...and supports the following databases:
- MySQL (v5.7.10+)
- Percona (v5.7.16-10+)
- MariaDB (10.3.0+)
## Browser Support
Coming soon, PostgreSQL and Microsoft SQL Server database support.
- Firefox
- Chrome
- Safari
- Microsoft Edge
- Brave
- Vivaldi
- Opera
## Authentication options
## Technology Stack
Besides email/password login, you can also leverage the following options.
- Go (v1.23.4)
- Ember JS (v3.12.0)
### Keycloak Integration
## Authentication Options
Documize provides out-of-the-box integration with [Redhat Keycloak](http://www.keycloak.org) for open source identity and access management.
Besides email/password login, you can also authenticate via:
Connect and authenticate with LDAP, Active Directory and more.
* LDAP
* Active Directory
* Red Hat Keycloak
* Central Authentication Service (CAS)
<https://docs.documize.com>
When using LDAP/Active Directory, you can enable dual-authentication with email/password.
### Auth0 Compatible
## Localization
Documize is compatible with Auth0 identity as a service.
Languages supported out-of-the-box:
[![JWT Auth for open source projects](https://cdn.auth0.com/oss/badges/a0-badge-dark.png)](https://auth0.com/?utm_source=oss&utm_medium=gp&utm_campaign=oss)
- English
- German
- French
- Chinese (中文)
- Portuguese (Brazil) (Português - Brasil)
- Japanese (日本語)
- Italian
- Spanish Argentinian
Open Source Identity and Access Management
PR's welcome for additional languages.
## Developer's Note
## Product/Technical Support
We try to follow sound advice when writing commit messages:
For both Community and Community+ editions, please contact our help desk for product help, suggestions and other enquiries.
https://chris.beams.io/posts/git-commit/
<support@documize.com>
## The legal bit
We aim to respond within two working days.
<https://documize.com>
## The Legal Bit
<https://www.documize.com>
This software (Documize Community edition) is licensed under GNU AGPL v3 <http://www.gnu.org/licenses/agpl-3.0.en.html>.
Documize Community uses other open source components and we acknowledge them in [NOTICES](NOTICES.md)
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>. Documize® is a registered trade mark of Documize Inc.

View file

@ -7,61 +7,50 @@ echo "Building Ember assets..."
cd gui
call ember b -o dist-prod/ --environment=production
::Call allows the rest of the file to run
echo "Copying Ember assets..."
cd ..
rd /s /q edition\static\public
mkdir edition\static\public
rd /s /q embed\bindata\public
mkdir embed\bindata\public
echo "Copying Ember assets folder"
robocopy /e /NFL /NDL /NJH gui\dist-prod\assets edition\static\public\assets
robocopy /e /NFL /NDL /NJH gui\dist-prod\assets embed\bindata\public\assets
echo "Copying Ember codemirror folder"
robocopy /e /NFL /NDL /NJH gui\dist-prod\codemirror edition\static\public\codemirror
echo "Copying Ember prism folder"
robocopy /e /NFL /NDL /NJH gui\dist-prod\prism edition\static\public\prism
robocopy /e /NFL /NDL /NJH gui\dist-prod\codemirror embed\bindata\public\codemirror
echo "Copying Ember tinymce folder"
robocopy /e /NFL /NDL /NJH gui\dist-prod\tinymce edition\static\public\tinymce
echo "Copying Ember pdfjs folder"
robocopy /e /NFL /NDL /NJH gui\dist-prod\pdfjs edition\static\public\pdfjs
robocopy /e /NFL /NDL /NJH gui\dist-prod\tinymce embed\bindata\public\tinymce
echo "Copying Ember sections folder"
robocopy /e /NFL /NDL /NJH gui\dist-prod\sections edition\static\public\sections
echo "Copying i18n folder"
robocopy /e /NFL /NDL /NJH gui\dist-prod\i18n edition\static\public\i18n
robocopy /e /NFL /NDL /NJH gui\dist-prod\sections embed\bindata\public\sections
echo "Copying static files"
copy gui\dist-prod\*.* edition\static
copy gui\dist-prod\*.* embed\bindata
copy gui\dist-prod\favicon.ico embed\bindata\public
copy gui\dist-prod\manifest.json embed\bindata\public
echo "Copying favicon.ico"
copy gui\dist-prod\favicon.ico edition\static\public
rd /s /q embed\bindata\mail
mkdir embed\bindata\mail
copy domain\mail\*.html embed\bindata\mail
copy core\database\templates\*.html embed\bindata
echo "Copying manifest.json"
copy gui\dist-prod\manifest.json edition\static\public
echo "Copying mail templates"
rd /s /q edition\static\mail
mkdir edition\static\mail
copy domain\mail\*.html edition\static\mail
echo "Copying database templates"
copy core\database\templates\*.html edition\static
rd /s /q edition\static\i18n
mkdir edition\static\i18n
robocopy /e /NFL /NDL /NJH gui\dist-prod\i18n edition\static\i18n *.json
rd /s /q edition\static\scripts
mkdir edition\static\scripts
mkdir edition\static\scripts\mysql
mkdir edition\static\scripts\postgresql
mkdir edition\static\scripts\sqlserver
rd /s /q embed\bindata\scripts
mkdir embed\bindata\scripts
echo "Copying database scripts folder"
robocopy /e /NFL /NDL /NJH core\database\scripts\mysql edition\static\scripts\mysql
robocopy /e /NFL /NDL /NJH core\database\scripts\postgresql edition\static\scripts\postgresql
robocopy /e /NFL /NDL /NJH core\database\scripts\sqlserver edition\static\scripts\sqlserver
robocopy /e /NFL /NDL /NJH core\database\scripts\autobuild embed\bindata\scripts
rd /s /q edition\static\onboard
mkdir edition\static\onboard
robocopy /e /NFL /NDL /NJH domain\onboard edition\static\onboard *.json
echo "Generating in-memory static assets..."
go get -u github.com/jteeuwen/go-bindata/...
go get -u github.com/elazarl/go-bindata-assetfs/...
cd embed
go generate
cd ..
echo "Compiling Windows"
set GOOS=windows
go build -mod=vendor -trimpath -gcflags="all=-trimpath=$GOPATH" -o bin/documize-community-windows-amd64.exe edition/community.go
go build -gcflags=-trimpath=%GOPATH% -asmflags=-trimpath=%GOPATH% -o bin/documize-community-windows-amd64.exe edition/community.go
echo "Compiling Linux"
set GOOS=linux
go build -gcflags=-trimpath=%GOPATH% -asmflags=-trimpath=%GOPATH% -o bin/documize-community-linux-amd64 edition/community.go
echo "Compiling Darwin"
set GOOS=darwin
go build -gcflags=-trimpath=%GOPATH% -asmflags=-trimpath=%GOPATH% -o bin/documize-community-darwin-amd64 edition/community.go

View file

@ -8,65 +8,50 @@ echo "Build process started $NOW"
echo "Building Ember assets..."
cd gui
# export NODE_OPTIONS=--openssl-legacy-provider
ember build ---environment=production --output-path dist-prod --suppress-sizes true
cd ..
ember b -o dist-prod/ --environment=production
echo "Copying Ember assets..."
rm -rf edition/static/public
mkdir -p edition/static/public
cp -r gui/dist-prod/assets edition/static/public
cp -r gui/dist-prod/codemirror edition/static/public/codemirror
cp -r gui/dist-prod/prism edition/static/public/prism
cp -r gui/dist-prod/sections edition/static/public/sections
cp -r gui/dist-prod/tinymce edition/static/public/tinymce
cp -r gui/dist-prod/pdfjs edition/static/public/pdfjs
cp -r gui/dist-prod/i18n edition/static/public/i18n
cp gui/dist-prod/*.* edition/static
cp gui/dist-prod/favicon.ico edition/static/public
cp gui/dist-prod/manifest.json edition/static/public
cd ..
rm -rf embed/bindata/public
mkdir -p embed/bindata/public
cp -r gui/dist-prod/assets embed/bindata/public
cp -r gui/dist-prod/codemirror embed/bindata/public/codemirror
cp -r gui/dist-prod/tinymce embed/bindata/public/tinymce
cp -r gui/dist-prod/sections embed/bindata/public/sections
cp gui/dist-prod/*.* embed/bindata
cp gui/dist-prod/favicon.ico embed/bindata/public
cp gui/dist-prod/manifest.json embed/bindata/public
rm -rf embed/bindata/mail
mkdir -p embed/bindata/mail
cp domain/mail/*.html embed/bindata/mail
cp core/database/templates/*.html embed/bindata
rm -rf embed/bindata/scripts
mkdir -p embed/bindata/scripts
cp -r core/database/scripts/autobuild/*.sql embed/bindata/scripts
rm -rf edition/static/mail
mkdir -p edition/static/mail
cp domain/mail/*.html edition/static/mail
cp core/database/templates/*.html edition/static
echo "Generating in-memory static assets..."
# go get -u github.com/jteeuwen/go-bindata/...
# go get -u github.com/elazarl/go-bindata-assetfs/...
cd embed
go generate
rm -rf edition/static/i18n
mkdir -p edition/static/i18n
cp -r gui/dist-prod/i18n/*.json edition/static/i18n
rm -rf edition/static/scripts
mkdir -p edition/static/scripts
mkdir -p edition/static/scripts/mysql
mkdir -p edition/static/scripts/postgresql
mkdir -p edition/static/scripts/sqlserver
cp -r core/database/scripts/mysql/*.sql edition/static/scripts/mysql
cp -r core/database/scripts/postgresql/*.sql edition/static/scripts/postgresql
cp -r core/database/scripts/sqlserver/*.sql edition/static/scripts/sqlserver
rm -rf edition/static/onboard
mkdir -p edition/static/onboard
cp -r domain/onboard/*.json edition/static/onboard
echo "Compiling for macOS Intel..."
env GOOS=darwin GOARCH=amd64 go build -mod=vendor -trimpath -o bin/documize-community-darwin-amd64 ./edition/community.go
echo "Compiling for macOS ARM..."
env GOOS=darwin GOARCH=arm64 go build -mod=vendor -trimpath -o bin/documize-community-darwin-arm64 ./edition/community.go
echo "Compiling for Windows AMD..."
env GOOS=windows GOARCH=amd64 go build -mod=vendor -trimpath -o bin/documize-community-windows-amd64.exe ./edition/community.go
echo "Compiling for Linux AMD..."
env GOOS=linux GOARCH=amd64 go build -mod=vendor -trimpath -o bin/documize-community-linux-amd64 ./edition/community.go
echo "Compiling for Linux ARM..."
env GOOS=linux GOARCH=arm go build -mod=vendor -trimpath -o bin/documize-community-linux-arm ./edition/community.go
echo "Compiling for Linux ARM64..."
env GOOS=linux GOARCH=arm64 go build -mod=vendor -trimpath -o bin/documize-community-linux-arm64 ./edition/community.go
echo "Compiling for FreeBSD ARM64..."
env GOOS=freebsd GOARCH=arm64 go build -mod=vendor -trimpath -o bin/documize-community-freebsd-arm64 ./edition/community.go
echo "Compiling for FreeBSD AMD64..."
env GOOS=freebsd GOARCH=amd64 go build -mod=vendor -trimpath -o bin/documize-community-freebsd-amd64 ./edition/community.go
echo "Compiling app..."
cd ..
for arch in amd64 ; do
for os in darwin linux windows ; do
if [ "$os" == "windows" ] ; then
echo "Compiling documize-community-$os-$arch.exe"
env GOOS=$os GOARCH=$arch go build -gcflags=-trimpath=$GOPATH -asmflags=-trimpath=$GOPATH -o bin/documize-community-$os-$arch.exe ./edition/community.go
else
echo "Compiling documize-community-$os-$arch"
env GOOS=$os GOARCH=$arch go build -gcflags=-trimpath=$GOPATH -asmflags=-trimpath=$GOPATH -o bin/documize-community-$os-$arch ./edition/community.go
fi
done
done
echo "Finished."
# CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w" -installsuffix cgo
# go build -ldflags '-d -s -w' -a -tags netgo -installsuffix netgo test.go
# ldd test

23
compile.sh Executable file
View file

@ -0,0 +1,23 @@
#! /bin/bash
echo "Generating in-memory static assets..."
# go get -u github.com/jteeuwen/go-bindata/...
# go get -u github.com/elazarl/go-bindata-assetfs/...
cd embed
go generate
echo "Compiling app..."
cd ..
for arch in amd64 ; do
for os in darwin linux windows ; do
if [ "$os" == "windows" ] ; then
echo "Compiling documize-community-$os-$arch.exe"
env GOOS=$os GOARCH=$arch go build -gcflags=-trimpath=$GOPATH -asmflags=-trimpath=$GOPATH -o bin/documize-community-$os-$arch.exe ./edition/community.go
else
echo "Compiling documize-community-$os-$arch"
env GOOS=$os GOARCH=$arch go build -gcflags=-trimpath=$GOPATH -asmflags=-trimpath=$GOPATH -o bin/documize-community-$os-$arch ./edition/community.go
fi
done
done
echo "Finished."

View file

@ -19,8 +19,8 @@ import (
"net/http"
"path/filepath"
"context"
api "github.com/documize/community/core/convapi"
"golang.org/x/net/context"
)
// Msword type provides a peg to hang the Convert method on.

View file

@ -19,7 +19,7 @@ import (
"github.com/documize/community/core/api/plugins"
api "github.com/documize/community/core/convapi"
"context"
"golang.org/x/net/context"
)
// Convert provides the entry-point into the document conversion process.

View file

@ -0,0 +1,155 @@
// 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 convert_test
import (
"strings"
"testing"
"github.com/documize/community/core/api/convert"
"github.com/documize/community/core/api/plugins"
api "github.com/documize/community/core/convapi"
"github.com/documize/community/core/log"
"golang.org/x/net/context"
)
func TestConvert(t *testing.T) {
plugins.PluginFile = "" // no file as html is built-in
if lerr := plugins.LibSetup(); lerr == nil {
//t.Error("did not error on plugin.Libsetup() with no plugin.json file")
//return
}
defer log.IfErr(plugins.Lib.KillSubProcs())
ctx := context.Background()
xtn := "html"
fileRequest := new(api.DocumentConversionRequest)
fileRequest.Filedata = []byte(yorkweb)
resp, err := convert.Convert(ctx, xtn, fileRequest)
if err != nil {
t.Error(err)
return
}
if len(resp.Pages) != 3 ||
!strings.HasPrefix(resp.Pages[1].Title, "STARTING") ||
!strings.HasPrefix(resp.Pages[2].Title, "EXERCISE") {
for p, pg := range resp.Pages {
t.Error(p, pg.Level, len(pg.Body), pg.Title)
}
}
exp := "There are lots of ways to create web pages using already coded programmes. … HTML isn' t computer code, but is a language that uses US English to enable texts( words, images, sounds) to be inserted and formatting such as colo( u) r and centre/ erin…"
if resp.Excerpt != exp {
t.Errorf("unexpected excerpt wanted: `%s` got: `%s`", exp, resp.Excerpt)
}
// check errors are caught
resp, err = convert.Convert(ctx, "unknown", fileRequest)
if err == nil {
t.Error("does not error on unknown extension")
}
}
// www.york.ac.uk/teaching/cws/wws/webpage1.html
const yorkweb = `
<HMTL>
<HEAD>
<TITLE>webpage1</TITLE>
</HEAD>
<BODY BGCOLOR="FFFFFf" LINK="006666" ALINK="8B4513" VLINK="006666">
<TABLE WIDTH="75%" ALIGN="center">
<TR>
<TD>
<DIV ALIGN="center"><H1>STARTING . . . </H1></DIV>
<DIV ALIGN="justify"><P>There are lots of ways to create web pages using already coded programmes. These lessons will teach you how to use the underlying HyperText Markup Language - HTML.
<BR>
<P>HTML isn't computer code, but is a language that uses US English to enable texts (words, images, sounds) to be inserted and formatting such as colo(u)r and centre/ering to be written in. The process is fairly simple; the main difficulties often lie in small mistakes - if you slip up while word processing your reader may pick up your typos, but the page will still be legible. However, if your HTML is inaccurate the page may not appear - writing web pages is, at the least, very good practice for proof reading!</P>
<P>Learning HTML will enable you to:
<UL>
<LI>create your own simple pages
<LI>read and appreciate pages created by others
<LI>develop an understanding of the creative and literary implications of web-texts
<LI>have the confidence to branch out into more complex web design
</UL></P>
<P>A HTML web page is made up of tags. Tags are placed in brackets like this <B>< tag > </B>. A tag tells the browser how to display information. Most tags need to be opened < tag > and closed < /tag >.
<P> To make a simple web page you need to know only four tags:
<UL>
<LI>< HTML > tells the browser your page is written in HTML format
<LI>< HEAD > this is a kind of preface of vital information that doesn't appear on the screen.
<LI>< TITLE >Write the title of the web page here - this is the information that viewers see on the upper bar of their screen. (I've given this page the title 'webpage1').
<LI>< BODY >This is where you put the content of your page, the words and pictures that people read on the screen.
</UL>
<P>All these tags need to be closed.
<H4>EXERCISE</H4>
<P>Write a simple web page.</P>
<P> Copy out exactly the HTML below, using a WP program such as Notepad.<BR>
Information in <I>italics</I> indicates where you can insert your own text, other information is HTML and needs to be exact. However, make sure there are no spaces between the tag brackets and the text inside.<BR>
(Find Notepad by going to the START menu\ PROGRAMS\ ACCESSORIES\ NOTEPAD).
<P>
< HTML ><BR>
< HEAD ><BR>
< TITLE ><I> title of page</I>< /TITLE ><BR>
< /HEAD ><BR>
< BODY><BR>
<I> write what you like here: 'my first web page', or a piece about what you are reading, or a few thoughts on the course, or copy out a few words from a book or cornflake packet. Just type in your words using no extras such as bold, or italics, as these have special HTML tags, although you may use upper and lower case letters and single spaces. </I><BR>
< /BODY ><BR>
< /HTML ><BR>
<P>Save the file as 'first.html' (ie. call the file anything at all) It's useful if you start a folder - just as you would for word-processing - and call it something like WEBPAGES, and put your first.html file in the folder.
<P>NOW - open your browser.<BR>
On Netscape the process is: <BR>
Top menu; FILE\ OPEN PAGE\ CHOOSE FILE<BR>
Click on your WEBPAGES folder\ FIRST file<BR>
Click 'open' and your page should appear.
<P>On Internet Explorer: <BR>
Top menu; FILE\ OPEN\ BROWSE <BR>
Click on your WEBPAGES folder\ FIRST file<BR>
Click 'open' and your page should appear.<BR>
<P>If the page doesn't open, go back over your notepad typing and make sure that all the HTML tags are correct. Check there are no spaces between tags and internal text; check that all tags are closed; check that you haven't written < HTLM > or < BDDY >. Your page will work eventually.
<P>
Make another page. Call it somethingdifferent.html and place it in the same WEBPAGES folder as detailed above.
<P>start formatting in <A HREF="webpage2.html">lesson two</A>
<BR><A HREF="col3.html">back to wws index</A> </P>
</P>
</DIV>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>
`

View file

@ -16,7 +16,7 @@ import (
api "github.com/documize/community/core/convapi"
"context"
"golang.org/x/net/context"
)
// Convert provides the standard interface for conversion of a ".documizeapi" json document.

View file

@ -16,9 +16,9 @@ import (
"fmt"
"strings"
"context"
api "github.com/documize/community/core/convapi"
"github.com/documize/community/core/stringutil"
"golang.org/x/net/context"
"golang.org/x/net/html"
"golang.org/x/net/html/atom"
)

View file

@ -16,7 +16,7 @@ import (
"github.com/documize/blackfriday"
"context"
"golang.org/x/net/context"
)
// Convert provides the standard interface for conversion of a Markdown document.

View file

@ -22,7 +22,7 @@ import (
"github.com/documize/community/core/api/convert/html"
"github.com/documize/community/core/api/convert/md"
api "github.com/documize/community/core/convapi"
"github.com/documize/community/domain/store"
"github.com/documize/community/domain"
"github.com/documize/glick"
)
@ -49,7 +49,7 @@ var Lib *glick.Library
// Setup configures the global library at Lib,
// largely based on the "config.json" file. It should be called only once.
func Setup(s *store.Store) error {
func Setup(s *domain.Store) error {
if insecure == "true" {
glick.InsecureSkipVerifyTLS = true
}

View file

@ -0,0 +1,61 @@
// 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 plugins
import (
"os"
"testing"
)
func TestSetup(t *testing.T) {
err := LibSetup()
if err == nil {
//t.Error("should error on non-existent config file")
//t.Fail()
}
ssc, err := Lib.Actions("Convert")
if err != nil {
t.Error(err)
}
// TODO(Elliott) review for empty database
//if len(ssc) > 3 {
// t.Errorf("extra convert formats:%v", ssc)
//}
/* this code leaves plugins still running */
err = os.Chdir("../../..")
if err != nil {
t.Error(err)
}
err = LibSetup()
if err != nil {
t.Error(err)
}
ssc, err = Lib.Actions("Convert")
if err != nil {
t.Error(err)
}
if len(ssc) == 0 {
t.Error("no extra convert formats (defined)")
}
err = os.Chdir("documize/api/plugins")
if err != nil {
t.Error(err)
}
err = Lib.KillSubProcs()
if err != nil {
t.Error(err)
}
}

View file

@ -1,70 +0,0 @@
package asset
import (
"embed"
"errors"
"io"
"io/fs"
"mime"
"net/http"
"path"
"path/filepath"
)
// GetPublicFileSystem
func GetPublicFileSystem(e embed.FS) (hfs http.FileSystem, err error) {
fsys, err := fs.Sub(e, "static/public")
if err != nil {
return nil, errors.New("failed GetPublicFileSystem")
}
return http.FS(fsys), nil
}
// FetchStatic loads static asset from embed file system.
func FetchStatic(e embed.FS, filename string) (content, contentType string, err error) {
data, err := e.ReadFile("static/" + filename)
if err != nil {
return
}
contentType = mime.TypeByExtension(filepath.Ext(filename))
content = string(data)
return
}
// FetchStaticDir returns filenames within specified directory
func FetchStaticDir(fs embed.FS, directory string) (files []string, err error) {
entries, err := fs.ReadDir("static/" + directory)
if err != nil {
return
}
for i := range entries {
if !entries[i].Type().IsDir() {
files = append(files, entries[i].Name())
}
}
return files, nil
}
// WriteStatic loads static asset from embed file system and writes to HTTP.
func WriteStatic(fs embed.FS, prefix, requestedPath string, w http.ResponseWriter) error {
f, err := fs.Open(path.Join(prefix, requestedPath))
if err != nil {
return err
}
defer f.Close()
stat, _ := f.Stat()
if stat.IsDir() {
return errors.New("cannot write static file")
}
contentType := mime.TypeByExtension(filepath.Ext(requestedPath))
w.Header().Set("Content-Type", contentType)
_, err = io.Copy(w, f)
return err
}

View file

@ -12,85 +12,191 @@
package database
import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/documize/community/core/env"
"github.com/documize/community/core/streamutil"
"github.com/documize/community/server/web"
)
var dbCheckOK bool // default false
// 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(runtime *env.Runtime) bool {
runtime.Log.Info("Database: checking state")
runtime.Log.Info("Database checks: started")
web.SiteInfo.DBname = runtime.StoreProvider.DatabaseName()
csBits := strings.Split(runtime.Flags.DBConn, "/")
if len(csBits) > 1 {
web.SiteInfo.DBname = strings.Split(csBits[len(csBits)-1], "?")[0]
}
rows, err := runtime.Db.Query(runtime.StoreProvider.QueryMeta())
rows, err := runtime.Db.Query("SELECT VERSION() AS version, @@version_comment as comment, @@character_set_database AS charset, @@collation_database AS collation")
if err != nil {
runtime.Log.Error("Database: unable to load meta information from database provider", err)
web.SiteInfo.Issue = "Unable to load meta information from database provider: " + err.Error()
runtime.Log.Error("Can't get MySQL configuration", err)
web.SiteInfo.Issue = "Can't get MySQL configuration: " + err.Error()
runtime.Flags.SiteMode = env.SiteModeBadDB
return false
}
defer streamutil.Close(rows)
var version, dbComment, charset, collation string
if rows.Next() {
err = rows.Scan(&version, &dbComment, &charset, &collation)
}
if err == nil {
err = rows.Err() // get any error encountered during iteration
}
if err != nil {
runtime.Log.Error("Database: no meta data returned by database provider", err)
web.SiteInfo.Issue = "No meta data returned by database provider: " + err.Error()
runtime.Log.Error("no MySQL configuration returned", err)
web.SiteInfo.Issue = "no MySQL configuration return issue: " + err.Error()
runtime.Flags.SiteMode = env.SiteModeBadDB
return false
}
runtime.Log.Info(fmt.Sprintf("Database: provider name %v", runtime.StoreProvider.Type()))
runtime.Log.Info(fmt.Sprintf("Database: provider version %s", version))
// Get SQL variant as this affects minimum version checking logic.
// MySQL and Percona share same version scheme (e..g 5.7.10).
// MariaDB starts at 10.2.x
runtime.DbVariant = GetSQLVariant(runtime.Flags.DBType, dbComment)
runtime.Log.Info(fmt.Sprintf("Database checks: SQL variant %v", runtime.DbVariant))
runtime.Log.Info("Database checks: SQL version " + version)
// Version OK?
versionOK, minVersion := runtime.StoreProvider.VerfiyVersion(version)
if !versionOK {
msg := fmt.Sprintf("*** ERROR: database version needs to be %s or above ***", minVersion)
runtime.Log.Info(msg)
web.SiteInfo.Issue = msg
runtime.Flags.SiteMode = env.SiteModeBadDB
return false
verNums, err := GetSQLVersion(version)
if err != nil {
runtime.Log.Error("Database version check failed", err)
}
// Character set and collation OK?
charOK, charRequired := runtime.StoreProvider.VerfiyCharacterCollation(charset, collation)
if !charOK {
msg := fmt.Sprintf("*** ERROR: %s ***", charRequired)
runtime.Log.Info(msg)
web.SiteInfo.Issue = msg
runtime.Flags.SiteMode = env.SiteModeBadDB
return false
// Check minimum MySQL version as we need JSON column type.
verInts := []int{5, 7, 10} // Minimum MySQL version
if runtime.DbVariant == env.DBVariantMariaDB {
verInts = []int{10, 3, 0} // Minimum MariaDB version
}
// if there are no rows in the database, enter set-up mode
var flds []string
if err := runtime.Db.Select(&flds, runtime.StoreProvider.QueryTableList()); err != nil {
msg := fmt.Sprintf("Database: unable to get database table list ")
runtime.Log.Error(msg, err)
web.SiteInfo.Issue = msg + err.Error()
runtime.Flags.SiteMode = env.SiteModeBadDB
return false
for k, v := range verInts {
// If major release is higher then skip minor/patch checks (e.g. 8.x.x > 5.x.x)
if k == 0 && len(verNums) > 0 && verNums[0] > verInts[0] {
break
}
if verNums[k] < v {
want := fmt.Sprintf("%d.%d.%d", verInts[0], verInts[1], verInts[2])
runtime.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
runtime.Flags.SiteMode = env.SiteModeBadDB
return false
}
}
if len(flds) <= 5 {
runtime.Log.Info("Database: starting setup mode for empty database")
runtime.Flags.SiteMode = env.SiteModeSetup
return false
{ // check the MySQL character set and collation
if charset != "utf8" && charset != "utf8mb4" {
runtime.Log.Error("MySQL character set not utf8/utf8mb4:", errors.New(charset))
web.SiteInfo.Issue = "MySQL character set not utf8/utf8mb4: " + charset
runtime.Flags.SiteMode = env.SiteModeBadDB
return false
}
if !strings.HasPrefix(collation, "utf8") {
runtime.Log.Error("MySQL collation sequence not utf8...:", errors.New(collation))
web.SiteInfo.Issue = "MySQL collation sequence not utf8...: " + collation
runtime.Flags.SiteMode = env.SiteModeBadDB
return false
}
}
// We have good database, so proceed with app boot process.
runtime.Flags.SiteMode = env.SiteModeNormal
web.SiteInfo.DBname = ""
{ // if there are no rows in the database, enter set-up mode
var flds []string
if err := runtime.Db.Select(&flds,
`SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '`+web.SiteInfo.DBname+
`' and TABLE_TYPE='BASE TABLE'`); err != nil {
runtime.Log.Error("Can't get MySQL number of tables", err)
web.SiteInfo.Issue = "Can't get MySQL number of tables: " + err.Error()
runtime.Flags.SiteMode = env.SiteModeBadDB
return false
}
if strings.TrimSpace(flds[0]) == "0" {
runtime.Log.Info("Entering database set-up mode because the database is empty.....")
runtime.Flags.SiteMode = env.SiteModeSetup
return false
}
}
{ // check all the required tables exist
var tables = []string{`account`,
`attachment`, `document`,
`label`, `organization`,
`page`, `revision`, `search`, `user`}
for _, table := range tables {
var dummy []string
if err := runtime.Db.Select(&dummy, "SELECT 1 FROM "+table+" LIMIT 1;"); err != nil {
runtime.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
runtime.Flags.SiteMode = env.SiteModeBadDB
return false
}
}
}
runtime.Flags.SiteMode = env.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
}
// GetSQLVariant uses database value form @@version_comment to deduce MySQL variant.
func GetSQLVariant(dbType, vc string) env.DbVariant {
vc = strings.ToLower(vc)
dbType = strings.ToLower(dbType)
// determine type from database
if strings.Contains(vc, "mariadb") {
return env.DBVariantMariaDB
} else if strings.Contains(vc, "percona") {
return env.DBVariantPercona
} else if strings.Contains(vc, "mysql") {
return env.DbVariantMySQL
}
// now determine type from command line switch
if strings.Contains(dbType, "mariadb") {
return env.DBVariantMariaDB
} else if strings.Contains(dbType, "percona") {
return env.DBVariantPercona
} else if strings.Contains(dbType, "mysql") {
return env.DbVariantMySQL
}
// horrid default could cause app to crash
return env.DbVariantMySQL
}
// GetSQLVersion returns SQL version as major,minor,patch numerics.
func GetSQLVersion(v string) (ints []int, err error) {
ints = []int{0, 0, 0}
pos := strings.Index(v, "-")
if pos > 1 {
v = v[:pos]
}
vs := strings.Split(v, ".")
if len(vs) < 3 {
err = errors.New("MySQL version not of the form a.b.c")
return
}
for key, val := range vs {
num, err := strconv.Atoi(val)
if err != nil {
return ints, err
}
ints[key] = num
}
return
}

View file

@ -0,0 +1,42 @@
// 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 "testing"
// go test github.com/documize/community/core/database -run TestGetVersion
func TestGetVersion(t *testing.T) {
ts2(t, "5.7.10", []int{5, 7, 10})
ts2(t, "5.7.10-log", []int{5, 7, 10})
ts2(t, "5.7.10-demo", []int{5, 7, 10})
ts2(t, "5.7.10-debug", []int{5, 7, 10})
ts2(t, "5.7.16-10", []int{5, 7, 16})
ts2(t, "5.7.12-0ubuntu0-12.12.3", []int{5, 7, 12})
ts2(t, "10.1.20-MariaDB-1~jessie", []int{10, 1, 20})
ts2(t, "ubuntu0-12.12.3", []int{0, 0, 0})
ts2(t, "junk-string", []int{0, 0, 0})
ts2(t, "somethingstring", []int{0, 0, 0})
}
func ts2(t *testing.T, in string, out []int) {
got, _ := GetSQLVersion(in)
// if err != nil {
// t.Errorf("Unable to GetSQLVersion %s", err)
// }
for k, v := range got {
if v != out[k] {
t.Errorf("version input of %s got %d for position %d but expected %d\n", in, v, k, out[k])
}
}
}

View file

@ -1,74 +0,0 @@
// 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 (
"github.com/documize/community/core/env"
"testing"
)
// go test github.com/documize/community/core/database -run TestGetVersion
// func TestGetVersion(t *testing.T) {
// ts2(t, "5.7.10", []int{5, 7, 10})
// ts2(t, "5.7.10-log", []int{5, 7, 10})
// ts2(t, "5.7.10-demo", []int{5, 7, 10})
// ts2(t, "5.7.10-debug", []int{5, 7, 10})
// ts2(t, "5.7.16-10", []int{5, 7, 16})
// ts2(t, "5.7.12-0ubuntu0-12.12.3", []int{5, 7, 12})
// ts2(t, "10.1.20-MariaDB-1~jessie", []int{10, 1, 20})
// ts2(t, "ubuntu0-12.12.3", []int{0, 0, 0})
// ts2(t, "junk-string", []int{0, 0, 0})
// ts2(t, "somethingstring", []int{0, 0, 0})
// }
// func ts2(t *testing.T, in string, out []int) {
// got, _ := GetSQLVersion(in)
// // if err != nil {
// // t.Errorf("Unable to GetSQLVersion %s", err)
// // }
// for k, v := range got {
// if v != out[k] {
// t.Errorf("version input of %s got %d for position %d but expected %d\n", in, v, k, out[k])
// }
// }
// }
func TestDatabaseVersionLegacy(t *testing.T) {
i := extractVersionNumber("db_00021.sql")
if i != 21 {
t.Errorf("expected 21 got %d", i)
}
i = extractVersionNumber("db_000.sql")
if i != 0 {
t.Errorf("expected 0 got %d", i)
}
i = extractVersionNumber("26")
if i != 26 {
t.Errorf("expected 26 got %d", i)
}
}
func TestParamRebind(t *testing.T) {
q1in := "INSERT INTO dmz_org (c_refid, c_company, c_title) VALUES (?, ?, ?)"
q1out := "INSERT INTO dmz_org (c_refid, c_company, c_title) VALUES ($1, $2, $3)"
test1 := RebindParams(q1in, env.StoreTypePostgreSQL)
if test1 != q1out {
t.Errorf("expected %s got %s", q1in, test1)
}
t.Log(test1)
}

253
core/database/endpoint.go Normal file
View file

@ -0,0 +1,253 @@
// 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/plugins"
"github.com/documize/community/core/env"
"github.com/documize/community/core/secrets"
"github.com/documize/community/core/stringutil"
"github.com/documize/community/core/uniqueid"
"github.com/documize/community/domain"
"github.com/documize/community/server/web"
)
// Handler contains the runtime information such as logging and database.
type Handler struct {
Runtime *env.Runtime
Store *domain.Store
}
// Setup the tables in a blank database
func (h *Handler) Setup(w http.ResponseWriter, r *http.Request) {
defer func() {
target := "/setup"
status := http.StatusBadRequest
if h.Runtime.Flags.SiteMode == env.SiteModeNormal {
target = "/"
status = http.StatusOK
}
req, err := http.NewRequest("GET", target, nil)
if err != nil {
h.Runtime.Log.Error("database.Setup error in defer ", err)
}
http.Redirect(w, req, target, status)
}()
err := r.ParseForm()
if err != nil {
h.Runtime.Log.Error("database.Setup r.ParseForm()", err)
return
}
dbname := r.Form.Get("dbname")
dbhash := r.Form.Get("dbhash")
if dbname != web.SiteInfo.DBname || dbhash != web.SiteInfo.DBhash {
h.Runtime.Log.Error("database.Setup 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().UTC(),
}
if details.Company == "" ||
details.CompanyLong == "" ||
details.Message == "" ||
details.Email == "" ||
details.Password == "" ||
details.Firstname == "" ||
details.Lastname == "" {
h.Runtime.Log.Error("database.Setup error ", errors.New("required field in database set-up form blank"))
return
}
if err = Migrate(h.Runtime, false /* no tables exist yet */); err != nil {
h.Runtime.Log.Error("database.Setup migrate", err)
return
}
err = setupAccount(h.Runtime, details, secrets.GenerateSalt())
if err != nil {
h.Runtime.Log.Error("database.Setup setup account ", err)
return
}
h.Runtime.Flags.SiteMode = env.SiteModeNormal
err = plugins.Setup(h.Store)
if err != nil {
h.Runtime.Log.Error("database.Setup plugin setup failed", err)
}
}
// 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(rt *env.Runtime, 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 := secrets.GenerateSalt()
password := secrets.GeneratePassword(completion.Password, salt)
// Allocate organization to the user.
orgID := uniqueid.Generate()
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(rt, sql)
if err != nil {
rt.Log.Error("Failed to insert into organization", err)
return
}
userID := uniqueid.Generate()
sql = fmt.Sprintf("insert into user (refid, firstname, lastname, email, initials, salt, password, global) values (\"%s\",\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", 1)",
userID, completion.Firstname, completion.Lastname, completion.Email, stringutil.MakeInitials(completion.Firstname, completion.Lastname), salt, password)
_, err = runSQL(rt, sql)
if err != nil {
rt.Log.Error("Failed with error", err)
return err
}
// Link user to organization.
accountID := uniqueid.Generate()
sql = fmt.Sprintf("insert into account (refid, userid, orgid, `admin`, editor, users, analytics) values (\"%s\", \"%s\", \"%s\", 1, 1, 1, 1)", accountID, userID, orgID)
_, err = runSQL(rt, sql)
if err != nil {
rt.Log.Error("Failed with error", err)
return err
}
// create space
labelID := uniqueid.Generate()
sql = fmt.Sprintf("insert into label (refid, orgid, label, type, userid) values (\"%s\", \"%s\", \"My Project\", 2, \"%s\")", labelID, orgID, userID)
_, err = runSQL(rt, sql)
if err != nil {
rt.Log.Error("insert into label failed", err)
}
// assign permissions to space
perms := []string{"view", "manage", "own", "doc-add", "doc-edit", "doc-delete", "doc-move", "doc-copy", "doc-template", "doc-approve", "doc-version", "doc-lifecycle"}
for _, p := range perms {
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)
_, err = runSQL(rt, sql)
if err != nil {
rt.Log.Error("insert into permission failed", err)
}
}
// 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)
}
return
}
// 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
}

View file

@ -1,232 +0,0 @@
// 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 (
"fmt"
"regexp"
"strconv"
"strings"
"github.com/documize/community/core/env"
"github.com/jmoiron/sqlx"
)
// InstallUpgrade creates new database or upgrades existing database.
func InstallUpgrade(runtime *env.Runtime, existingDB bool) (err error) {
// amLeader := false
// Get all SQL scripts.
scripts, err := LoadScripts(runtime)
if err != nil {
runtime.Log.Error("Database: unable to load scripts", err)
return
}
// Get current database version.
currentVersion := 0
if existingDB {
currentVersion, err = CurrentVersion(runtime)
if err != nil {
runtime.Log.Error("Database: unable to get current version", err)
return
}
runtime.Log.Info(fmt.Sprintf("Database: current version number is %d", currentVersion))
}
// Filter out database specific scripts.
dbTypeScripts := SpecificScripts(runtime, scripts)
if len(dbTypeScripts) == 0 {
runtime.Log.Info(fmt.Sprintf("Database: unable to load scripts for database type %s", runtime.StoreProvider.Type()))
return
}
runtime.Log.Info(fmt.Sprintf("Database: loaded %d SQL scripts for provider %s", len(dbTypeScripts), runtime.StoreProvider.Type()))
// Make a list of scripts to execute based upon current database state.
toProcess := []Script{}
for _, s := range dbTypeScripts {
if s.Version > currentVersion || currentVersion == 0 {
toProcess = append(toProcess, s)
}
}
runtime.Log.Info(fmt.Sprintf("Database: %d scripts to process", len(toProcess)))
// For MySQL type there was major new schema introduced in v24.
// We check for this release and bypass usual locking code
// because tables have changed.
legacyMigration := runtime.StoreProvider.Type() == env.StoreTypeMySQL &&
currentVersion > 0 && currentVersion < 25 && len(toProcess) >= 26 && toProcess[len(toProcess)-1].Version == 25
if legacyMigration {
// Bypass all DB locking/checking processes as these look for new schema
// which we are about to install.
toProcess = toProcess[len(toProcess)-1:]
runtime.Log.Info(fmt.Sprintf("Database: legacy schema has %d scripts to process", len(toProcess)))
}
err = runScripts(runtime, toProcess)
if err != nil {
runtime.Log.Error("Database: error processing SQL scripts", err)
}
return nil
}
// Run SQL scripts to instal or upgrade this database.
// We do not use transactions for Microsoft SQL Server because
// CREATE FULLTEXT CATALOG statement cannot be used inside a user transaction.
func runScripts(runtime *env.Runtime, scripts []Script) (err error) {
tx, err := runtime.Db.Beginx()
if err != nil {
return err
}
// We can have multiple scripts as each Documize database change has it's own SQL script.
for _, script := range scripts {
runtime.Log.Info(fmt.Sprintf("Database: processing SQL script %d", script.Version))
err = executeSQL(tx, runtime, script.Script)
if err != nil {
runtime.Log.Error(fmt.Sprintf("error executing SQL script %d", script.Version), err)
if runtime.StoreProvider.Type() != env.StoreTypeSQLServer {
tx.Rollback()
}
return err
}
// Record the fact we have processed this database script version.
if runtime.StoreProvider.Type() != env.StoreTypeSQLServer {
_, err = tx.Exec(runtime.StoreProvider.QueryRecordVersionUpgrade(script.Version))
} else {
_, err = runtime.Db.Exec(runtime.StoreProvider.QueryRecordVersionUpgrade(script.Version))
}
if err != nil {
// For MySQL we try the legacy DB schema.
if runtime.StoreProvider.Type() == env.StoreTypeMySQL {
runtime.Log.Info(fmt.Sprintf("Database: attempting legacy fallback for SQL script %d", script.Version))
_, err = tx.Exec(runtime.StoreProvider.QueryRecordVersionUpgradeLegacy(script.Version))
if err != nil {
runtime.Log.Error(fmt.Sprintf("error recording execution of SQL script %d", script.Version), err)
if runtime.StoreProvider.Type() != env.StoreTypeSQLServer {
tx.Rollback()
}
return err
}
} else {
// Unknown issue running script on non-MySQL database.
runtime.Log.Error(fmt.Sprintf("error executing SQL script %d", script.Version), err)
if runtime.StoreProvider.Type() != env.StoreTypeSQLServer {
tx.Rollback()
}
return err
}
}
}
tx.Commit()
return nil
}
// executeSQL runs specified SQL commands.
func executeSQL(tx *sqlx.Tx, runtime *env.Runtime, SQLfile []byte) error {
// Turn SQL file contents into runnable SQL statements.
stmts := getStatements(SQLfile)
for _, stmt := range stmts {
// MariaDB has no specific JSON column type (but has JSON queries)
if runtime.StoreProvider.Type() == env.StoreTypeMySQL &&
runtime.StoreProvider.TypeVariant() == env.StoreTypeMariaDB {
stmt = strings.Replace(stmt, "` JSON", "` TEXT", -1)
}
var err error
if runtime.StoreProvider.Type() != env.StoreTypeSQLServer {
_, err = tx.Exec(stmt)
} else {
_, err = runtime.Db.Exec(stmt)
}
if err != nil {
fmt.Println("sql statement error:", stmt)
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) (stmts []string) {
// Strip comments of the form '-- comment' or like this one /**/
stripped := regexp.MustCompile("(?s)--.*?\n|/\\*.*?\\*/").ReplaceAll(bytes, []byte("\n"))
// Break into lines using ; terminator.
lines := strings.Split(string(stripped), ";")
// Prepare return data.
stmts = make([]string, 0, len(lines))
for _, v := range lines {
trimmed := strings.TrimSpace(v)
// Process non-empty lines and exclude "USE dbname" command
if len(trimmed) > 0 && !strings.HasPrefix(strings.ToUpper(trimmed), "USE ") {
stmts = append(stmts, trimmed+";")
}
}
return
}
// CurrentVersion returns number that represents the current database version number.
// For example 23 represents the 23rd iteration of the database.
func CurrentVersion(runtime *env.Runtime) (version int, err error) {
currentVersion := "0"
row := runtime.Db.QueryRow(runtime.StoreProvider.QueryGetDatabaseVersion())
err = row.Scan(&currentVersion)
if err != nil {
// For MySQL we try the legacy DB checks.
if runtime.StoreProvider.Type() == env.StoreTypeMySQL {
row := runtime.Db.QueryRow(runtime.StoreProvider.QueryGetDatabaseVersionLegacy())
err = row.Scan(&currentVersion)
}
}
return extractVersionNumber(currentVersion), nil
}
// Turns legacy "db_00021.sql" and new "21" format into version number 21.
func extractVersionNumber(s string) int {
// Good practice in case of human tampering.
s = strings.TrimSpace(s)
s = strings.ToLower(s)
// Remove any quotes from JSON string.
s = strings.Replace(s, "\"", "", -1)
// Remove legacy version string formatting.
// We know just store the number.
s = strings.Replace(s, "db_000", "", 1)
s = strings.Replace(s, ".sql", "", 1)
i, err := strconv.Atoi(s)
if err != nil {
i = 0
}
return i
}

281
core/database/migrate.go Normal file
View file

@ -0,0 +1,281 @@
// 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"
"crypto/rand"
"database/sql"
"fmt"
"os"
"regexp"
"sort"
"strings"
"time"
"github.com/documize/community/core/env"
"github.com/documize/community/core/streamutil"
"github.com/documize/community/server/web"
"github.com/jmoiron/sqlx"
)
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, `"`), `"`)
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(runtime *env.Runtime, tx *sqlx.Tx) error {
for _, v := range m {
runtime.Log.Info("Processing migration file: " + v)
buf, err := web.Asset(migrationsDir + "/" + v)
if err != nil {
return err
}
err = processSQLfile(tx, runtime.DbVariant, 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) // add a record in the config file to say we have done the upgrade
if err != nil {
return err
}
}
return nil
}
func lockDB(runtime *env.Runtime) (bool, error) {
b := make([]byte, 2)
_, err := rand.Read(b)
if err != nil {
return false, err
}
wait := ((time.Duration(b[0]) << 8) | time.Duration(b[1])) * time.Millisecond / 10 // up to 6.5 secs wait
time.Sleep(wait)
tx, err := runtime.Db.Beginx()
if err != nil {
return false, err
}
_, err = tx.Exec("LOCK TABLE `config` WRITE;")
if err != nil {
return false, err
}
defer func() {
_, err = tx.Exec("UNLOCK TABLES;")
if err != nil {
runtime.Log.Error("unable to unlock tables", err)
}
tx.Commit()
}()
_, err = tx.Exec("INSERT INTO `config` (`key`,`config`) " +
fmt.Sprintf(`VALUES ('DBLOCK','{"pid": "%d"}');`, os.Getpid()))
if err != nil {
// good error would be "Error 1062: Duplicate entry 'DBLOCK' for key 'idx_config_area'"
if strings.HasPrefix(err.Error(), "Error 1062:") {
runtime.Log.Info("Database locked by another Documize instance")
return false, nil
}
return false, err
}
runtime.Log.Info("Database locked by this Documize instance")
return true, err // success!
}
func unlockDB(rt *env.Runtime) error {
tx, err := rt.Db.Beginx()
if err != nil {
return err
}
_, err = tx.Exec("DELETE FROM `config` WHERE `key`='DBLOCK';")
if err != nil {
return err
}
return tx.Commit()
}
func migrateEnd(runtime *env.Runtime, tx *sqlx.Tx, err error, amLeader bool) error {
if amLeader {
defer func() { unlockDB(runtime) }()
if tx != nil {
if err == nil {
tx.Commit()
runtime.Log.Info("Database checks: completed")
return nil
}
tx.Rollback()
}
runtime.Log.Error("Database checks: failed: ", err)
return err
}
return nil // not the leader, so ignore errors
}
func getLastMigration(tx *sqlx.Tx) (lastMigration string, err error) {
var stmt *sql.Stmt
stmt, err = tx.Prepare("SELECT JSON_EXTRACT(`config`,'$.database') FROM `config` WHERE `key` = 'META';")
if err == nil {
defer streamutil.Close(stmt)
var item = make([]uint8, 0)
row := stmt.QueryRow()
err = row.Scan(&item)
if err == nil {
if len(item) > 1 {
q := []byte(`"`)
lastMigration = string(bytes.TrimPrefix(bytes.TrimSuffix(item, q), q))
}
}
}
return
}
// Migrate the database as required, consolidated action.
func Migrate(runtime *env.Runtime, ConfigTableExists bool) error {
amLeader := false
if ConfigTableExists {
var err error
amLeader, err = lockDB(runtime)
if err != nil {
runtime.Log.Error("unable to lock DB", err)
}
} else {
amLeader = true // what else can you do?
}
tx, err := runtime.Db.Beginx()
if err != nil {
return migrateEnd(runtime, tx, err, amLeader)
}
lastMigration := ""
if ConfigTableExists {
lastMigration, err = getLastMigration(tx)
if err != nil {
return migrateEnd(runtime, tx, err, amLeader)
}
runtime.Log.Info("Database checks: last applied " + lastMigration)
}
mig, err := migrations(lastMigration)
if err != nil {
return migrateEnd(runtime, tx, err, amLeader)
}
if len(mig) == 0 {
runtime.Log.Info("Database checks: no updates required")
return migrateEnd(runtime, tx, nil, amLeader) // no migrations to perform
}
if amLeader {
runtime.Log.Info("Database checks: will execute the following update files: " + strings.Join([]string(mig), ", "))
return migrateEnd(runtime, tx, mig.migrate(runtime, tx), amLeader)
}
// a follower instance
targetMigration := string(mig[len(mig)-1])
for targetMigration != lastMigration {
time.Sleep(time.Second)
runtime.Log.Info("Waiting for database migration completion")
tx.Rollback() // ignore error
tx, err := runtime.Db.Beginx() // need this in order to see the changed situation since last tx
if err != nil {
return migrateEnd(runtime, tx, err, amLeader)
}
lastMigration, _ = getLastMigration(tx)
}
return migrateEnd(runtime, tx, nil, amLeader)
}
func processSQLfile(tx *sqlx.Tx, v env.DbVariant, buf []byte) error {
stmts := getStatements(buf)
for _, stmt := range stmts {
// MariaDB has no specific JSON column type (but has JSON queries)
if v == env.DBVariantMariaDB {
stmt = strings.Replace(stmt, "` JSON", "` TEXT", -1)
}
_, 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
}

View file

@ -1,41 +0,0 @@
// 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 (
"github.com/documize/community/core/env"
"github.com/jmoiron/sqlx"
)
// RebindParams changes MySQL query parameter placeholder from "?" to
// correct value for given database provider.
//
// MySQL uses ?, ?, ? (default for all Documize queries)
// PostgreSQL uses $1, $2, $3
// MS SQL Server uses @p1, @p2, @p3
func RebindParams(sql string, s env.StoreType) string {
bindParam := sqlx.QUESTION
switch s {
case env.StoreTypePostgreSQL:
bindParam = sqlx.DOLLAR
case env.StoreTypeSQLServer:
bindParam = sqlx.AT
}
return sqlx.Rebind(bindParam, sql)
}
// RebindPostgreSQL is a helper method on top of RebindParams.
func RebindPostgreSQL(sql string) string {
return RebindParams(sql, env.StoreTypePostgreSQL)
}

38
core/database/readme.md Normal file
View file

@ -0,0 +1,38 @@
## PENDING REMOVALS
NONE
## MYSQL ENCODING
https://stackoverflow.com/questions/37307146/difference-between-utf8mb4-unicode-ci-and-utf8mb4-unicode-520-ci-collations-in-m
https://mathiasbynens.be/notes/mysql-utf8mb4
https://medium.com/@adamhooper/in-mysql-never-use-utf8-use-utf8mb4-11761243e434
## MIGRATE ENCODING
ALTER DATABASE documize CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE account CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE attachment CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE block CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE config CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE document CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE feedback CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE label CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE labelrole CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE link CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE organization CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE page CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE pagemeta CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE participant CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE pin CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE revision CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE search CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE share CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE useraction CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE useractivity CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE userconfig CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE userevent CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;

View file

@ -1,91 +0,0 @@
// 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 (
"embed"
"fmt"
"sort"
"github.com/documize/community/core/asset"
"github.com/documize/community/core/env"
)
// Scripts holds all .SQL files for all supported database providers.
type Scripts struct {
MySQL []Script
PostgreSQL []Script
SQLServer []Script
}
// Script holds SQL script and it's associated version number.
type Script struct {
Version int
Script []byte
}
// LoadScripts returns .SQL scripts for supported database providers.
func LoadScripts(runtime *env.Runtime) (s Scripts, err error) {
// MySQL
s.MySQL, err = loadFiles(runtime.Assets, "scripts/mysql")
if err != nil {
return
}
// PostgreSQL
s.PostgreSQL, err = loadFiles(runtime.Assets, "scripts/postgresql")
if err != nil {
return
}
// PostgreSQL
s.SQLServer, err = loadFiles(runtime.Assets, "scripts/sqlserver")
if err != nil {
return
}
return s, nil
}
// SpecificScripts returns SQL scripts for current databasse provider.
func SpecificScripts(runtime *env.Runtime, all Scripts) (s []Script) {
switch runtime.StoreProvider.Type() {
case env.StoreTypeMySQL, env.StoreTypeMariaDB, env.StoreTypePercona:
return all.MySQL
case env.StoreTypePostgreSQL:
return all.PostgreSQL
case env.StoreTypeSQLServer:
return all.SQLServer
}
return
}
// loadFiles returns all SQL scripts in specified folder as [][]byte.
func loadFiles(fs embed.FS, path string) (b []Script, err error) {
scripts, err := asset.FetchStaticDir(fs, path)
if err != nil {
return
}
sort.Strings(scripts)
for i := range scripts {
filename := scripts[i]
sqlfile, _, err := asset.FetchStatic(fs, fmt.Sprintf("%s/%s", path, filename))
if err != nil {
return b, err
}
b = append(b, Script{Version: extractVersionNumber(filename), Script: []byte(sqlfile)})
}
return b, nil
}

View file

@ -1,3 +1,3 @@
/* community edition */
ALTER TABLE organization ADD COLUMN `service` VARCHAR(100) NOT NULL DEFAULT '' AFTER `domain`;
ALTER TABLE organization ADD COLUMN `service` VARCHAR(100) NOT NULL DEFAULT 'https://api.documize.com' AFTER `domain`;

View file

@ -1,5 +1,6 @@
/* community edition */
ALTER DATABASE documize CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE account CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE attachment CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE block CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;

View file

@ -1,10 +0,0 @@
/* community edition */
-- max tags per document setting
ALTER TABLE organization ADD COLUMN `maxtags` INT NOT NULL DEFAULT 3 AFTER `authconfig`;
-- support for network location link types
ALTER TABLE link ADD COLUMN `externalid` NVARCHAR(1000) NOT NULL DEFAULT '' AFTER `targetid`;
-- deprecations
ALTER TABLE organization DROP COLUMN `url`;

View file

@ -1,335 +0,0 @@
/* community edition */
-- table renaming
RENAME TABLE
`organization` TO dmz_org,
`label` TO dmz_space,
`category` TO dmz_category,
`categorymember` TO dmz_category_member,
`role` TO dmz_group,
`rolemember` TO dmz_group_member,
`permission` TO dmz_permission,
`document` TO dmz_doc,
`share` TO dmz_doc_share,
`vote` TO dmz_doc_vote,
`feedback` TO dmz_doc_comment,
`attachment` TO dmz_doc_attachment,
`link` TO dmz_doc_link,
`page` TO dmz_section,
`pagemeta` TO dmz_section_meta,
`block` TO dmz_section_template,
`revision` TO dmz_section_revision,
`user` TO dmz_user,
`account` TO dmz_user_account,
`useractivity` TO dmz_user_activity,
`userconfig` TO dmz_user_config,
`config` TO dmz_config,
`pin` TO dmz_pin,
`search` TO dmz_search,
`userevent` TO dmz_audit_log,
`useraction` TO dmz_action;
-- field renaming
ALTER TABLE dmz_org
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `company` `c_company` VARCHAR(500) NOT NULL,
CHANGE `title` `c_title` VARCHAR(500) NOT NULL,
CHANGE `message` `c_message` VARCHAR(500) NOT NULL,
CHANGE `domain` `c_domain` VARCHAR(200) NOT NULL DEFAULT '',
CHANGE `service` `c_service` VARCHAR(200) NOT NULL DEFAULT '',
CHANGE `email` `c_email` VARCHAR(500) NOT NULL DEFAULT '',
CHANGE `allowanonymousaccess` `c_anonaccess` BOOL NOT NULL DEFAULT 0,
CHANGE `authprovider` `c_authprovider` CHAR(20) NOT NULL DEFAULT 'documize',
CHANGE `authconfig` `c_authconfig` JSON,
CHANGE `maxtags` `c_maxtags` INT NOT NULL DEFAULT 3,
CHANGE `verified` `c_verified` BOOL NOT NULL DEFAULT 0,
CHANGE `serial` `c_serial` VARCHAR(50) NOT NULL DEFAULT '',
CHANGE `active` `c_active` BOOL NOT NULL DEFAULT 1,
CHANGE `created` `c_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_space
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `type` `c_type` INT NOT NULL DEFAULT 1,
CHANGE `lifecycle` `c_lifecycle` INT NOT NULL DEFAULT 1,
CHANGE `label` `c_name` VARCHAR(300) NOT NULL,
CHANGE `likes` `c_likes` VARCHAR(1000) NOT NULL DEFAULT '',
CHANGE `created` `c_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_category
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `labelid` `c_spaceid` VARCHAR(20) NOT NULL,
CHANGE `category` `c_name` VARCHAR(50) NOT NULL,
CHANGE `created` `c_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_category_member
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `labelid` `c_spaceid` VARCHAR(20) NOT NULL,
CHANGE `categoryid` `c_categoryid` VARCHAR(20) NOT NULL,
CHANGE `documentid` `c_docid` VARCHAR(20) NOT NULL,
CHANGE `created` `c_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_group
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `role` `c_name` VARCHAR(50) NOT NULL DEFAULT '',
CHANGE `purpose` `c_desc` VARCHAR(100) DEFAULT '',
CHANGE `created` `c_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_group_member
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `roleid` `c_groupid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) NOT NULL;
ALTER TABLE dmz_permission
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `who` `c_who` VARCHAR(30) NOT NULL,
CHANGE `whoid` `c_whoid` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `action` `c_action` VARCHAR(30) NOT NULL,
CHANGE `scope` `c_scope` VARCHAR(30) NOT NULL,
CHANGE `location` `c_location` VARCHAR(100) NOT NULL,
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `created` `c_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_doc
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `labelid` `c_spaceid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `job` `c_job` CHAR(36) NOT NULL DEFAULT '',
CHANGE `location` `c_location` VARCHAR(2000) NOT NULL DEFAULT '',
CHANGE `title` `c_name` VARCHAR(2000) NOT NULL DEFAULT '',
CHANGE `excerpt` `c_desc` VARCHAR(2000) NOT NULL DEFAULT '',
CHANGE `slug` `c_slug` VARCHAR(2000) NOT NULL DEFAULT '',
CHANGE `tags` `c_tags` VARCHAR(1000) NOT NULL DEFAULT '',
CHANGE `template` `c_template` BOOL NOT NULL DEFAULT 0,
CHANGE `protection` `c_protection` INT NOT NULL DEFAULT 0,
CHANGE `approval` `c_approval` INT NOT NULL DEFAULT 0,
CHANGE `lifecycle` `c_lifecycle` INT NOT NULL DEFAULT 1,
CHANGE `versioned` `c_versioned` BOOL NOT NULL DEFAULT 0,
CHANGE `versionid` `c_versionid` VARCHAR(100) NOT NULL DEFAULT '',
CHANGE `versionorder` `c_versionorder` INT NOT NULL DEFAULT 0,
CHANGE `groupid` `c_groupid` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `created` `c_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_doc_share
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `documentid` `c_docid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) DEFAULT '',
CHANGE `email` `c_email` VARCHAR(250) NOT NULL DEFAULT '',
CHANGE `message` `c_message` VARCHAR(500) NOT NULL DEFAULT '',
CHANGE `viewed` `c_viewed` VARCHAR(500) NOT NULL DEFAULT '',
CHANGE `secret` `c_secret` VARCHAR(250) NOT NULL DEFAULT '',
CHANGE `expires` `c_expires` VARCHAR(20) DEFAULT '',
CHANGE `active` `c_active` BOOL NOT NULL DEFAULT 1,
CHANGE `created` `c_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_doc_vote
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `documentid` `c_docid` VARCHAR(20) NOT NULL,
CHANGE `voter` `c_voter` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `vote` `c_vote` INT NOT NULL DEFAULT 0,
CHANGE `created` `c_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_doc_comment
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `documentid` `c_docid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) DEFAULT '',
CHANGE `email` `c_email` VARCHAR(250) NOT NULL DEFAULT '',
CHANGE `feedback` `c_feedback` LONGTEXT,
CHANGE `created` `c_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_doc_attachment
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `documentid` `c_docid` VARCHAR(20) NOT NULL,
CHANGE `job` `c_job` CHAR(36) NOT NULL,
CHANGE `fileid` `c_fileid` CHAR(10) NOT NULL,
CHANGE `filename` `c_filename` VARCHAR(255) NOT NULL,
CHANGE `data` `c_data` LONGBLOB,
CHANGE `extension` `c_extension` CHAR(6) NOT NULL,
CHANGE `created` `c_created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_doc_link
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `folderid` `c_spaceid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) NOT NULL,
CHANGE `sourcedocumentid` `c_sourcedocid` VARCHAR(20) NOT NULL,
CHANGE `sourcepageid` `c_sourcesectionid` VARCHAR(20) NOT NULL,
CHANGE `linktype` `c_type` VARCHAR(20) NOT NULL,
CHANGE `targetdocumentid` `c_targetdocid` VARCHAR(20) NOT NULL,
CHANGE `targetid` `c_targetid` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `externalid` `c_externalid` VARCHAR(1000) NOT NULL DEFAULT '',
CHANGE `orphan` `c_orphan` BOOL NOT NULL DEFAULT 0,
CHANGE `created` `c_created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_section
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `documentid` `c_docid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `pagetype` `c_type` CHAR(10) NOT NULL DEFAULT 'section',
CHANGE `contenttype` `c_contenttype` CHAR(20) NOT NULL DEFAULT 'wysiwyg',
CHANGE `blockid` `c_templateid` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `level` `c_level` INT UNSIGNED NOT NULL,
CHANGE `sequence` `c_sequence` DOUBLE NOT NULL,
CHANGE `title` `c_name` VARCHAR(2000) NOT NULL DEFAULT '',
CHANGE `body` `c_body` LONGTEXT,
CHANGE `revisions` `c_revisions` INT UNSIGNED NOT NULL,
CHANGE `status` `c_status` INT NOT NULL DEFAULT 0,
CHANGE `relativeid` `c_relativeid` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `created` `c_created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_section_meta
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `documentid` `c_docid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `pageid` `c_sectionid` VARCHAR(20) NOT NULL,
CHANGE `rawbody` `c_rawbody` LONGBLOB,
CHANGE `config` `c_config` JSON,
CHANGE `externalsource` `c_external` BOOL DEFAULT 0,
CHANGE `created` `c_created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_section_template
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `labelid` `c_spaceid` VARCHAR(20) DEFAULT '',
CHANGE `userid` `c_userid` VARCHAR(20) DEFAULT '',
CHANGE `pagetype` `c_type` CHAR(10) NOT NULL DEFAULT 'section',
CHANGE `contenttype` `c_contenttype` CHAR(20) NOT NULL DEFAULT 'wysiwyg',
CHANGE `title` `c_name` VARCHAR(2000) NOT NULL DEFAULT '',
CHANGE `body` `c_body` LONGTEXT,
CHANGE `excerpt` `c_desc` VARCHAR(2000) NOT NULL DEFAULT '',
CHANGE `used` `c_used` INT UNSIGNED NOT NULL,
CHANGE `rawbody` `c_rawbody` LONGBLOB,
CHANGE `config` `c_config` JSON,
CHANGE `externalsource` `c_external` BOOL DEFAULT 0,
CHANGE `created` `c_created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_section_revision
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `documentid` `c_docid` VARCHAR(20) NOT NULL,
CHANGE `ownerid` `c_ownerid` VARCHAR(20) DEFAULT '',
CHANGE `pageid` `c_sectionid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) NOT NULL,
CHANGE `pagetype` `c_type` CHAR(10) NOT NULL DEFAULT 'section',
CHANGE `contenttype` `c_contenttype` CHAR(20) NOT NULL DEFAULT 'wysiwyg',
CHANGE `title` `c_name` VARCHAR(2000) NOT NULL DEFAULT '',
CHANGE `body` `c_body` LONGTEXT,
CHANGE `rawbody` `c_rawbody` LONGBLOB,
CHANGE `config` `c_config` JSON,
CHANGE `created` `c_created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_user
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `firstname` `c_firstname` VARCHAR(500) NOT NULL DEFAULT '',
CHANGE `lastname` `c_lastname` VARCHAR(500) NOT NULL DEFAULT '',
CHANGE `email` `c_email` VARCHAR(500) NOT NULL DEFAULT '',
CHANGE `initials` `c_initials` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `global` `c_globaladmin` BOOL NOT NULL DEFAULT 0,
CHANGE `password` `c_password` VARCHAR(500) NOT NULL DEFAULT '',
CHANGE `salt` `c_salt` VARCHAR(500) NOT NULL DEFAULT '',
CHANGE `reset` `c_reset` VARCHAR(500) NOT NULL DEFAULT '',
CHANGE `active` `c_active` BOOL NOT NULL DEFAULT 1,
CHANGE `lastversion` `c_lastversion` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `created` `c_created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_user_account
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) NOT NULL,
CHANGE `editor` `c_editor` BOOL NOT NULL DEFAULT 0,
CHANGE `admin` `c_admin` BOOL NOT NULL DEFAULT 0,
CHANGE `users` `c_users` BOOL NOT NULL DEFAULT 1,
CHANGE `analytics` `c_analytics` BOOL NOT NULL DEFAULT 0,
CHANGE `active` `c_active` BOOL NOT NULL DEFAULT 1,
CHANGE `created` `c_created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_user_activity
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) NOT NULL,
CHANGE `labelid` `c_spaceid` VARCHAR(20) NOT NULL,
CHANGE `documentid` `c_docid` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `pageid` `c_sectionid` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `sourcetype` `c_sourcetype` INT NOT NULL DEFAULT 0,
CHANGE `activitytype` `c_activitytype` INT NOT NULL DEFAULT 0,
CHANGE `metadata` `c_metadata` VARCHAR(1000) NOT NULL DEFAULT '',
CHANGE `created` `c_created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_user_config
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) NOT NULL,
CHANGE `key` `c_key` CHAR(200) NOT NULL,
CHANGE `config` `c_config` JSON;
ALTER TABLE dmz_config
CHANGE `key` `c_key` CHAR(200) NOT NULL,
CHANGE `config` `c_config` JSON;
ALTER TABLE dmz_pin
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) DEFAULT '',
CHANGE `labelid` `c_spaceid` VARCHAR(20) DEFAULT '',
CHANGE `documentid` `c_docid` VARCHAR(20) DEFAULT '',
CHANGE `sequence` `c_sequence` INT UNSIGNED NOT NULL DEFAULT 99,
CHANGE `pin` `c_name` CHAR(100) NOT NULL DEFAULT '',
CHANGE `created` `c_created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_search
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `documentid` `c_docid` VARCHAR(20) NOT NULL,
CHANGE `itemid` `c_itemid` VARCHAR(20) NOT NULL DEFAULT '',
CHANGE `itemtype` `c_itemtype` VARCHAR(10) NOT NULL,
CHANGE `content` `c_content` LONGTEXT,
CHANGE `created` `c_created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_audit_log
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) NOT NULL,
CHANGE `eventtype` `c_eventtype` VARCHAR(100) NOT NULL DEFAULT '',
CHANGE `ip` `c_ip` VARCHAR(39) NOT NULL DEFAULT '',
CHANGE `created` `c_created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE dmz_action
CHANGE `refid` `c_refid` VARCHAR(20) NOT NULL,
CHANGE `orgid` `c_orgid` VARCHAR(20) NOT NULL,
CHANGE `documentid` `c_docid` VARCHAR(20) NOT NULL,
CHANGE `userid` `c_userid` VARCHAR(20) NOT NULL,
CHANGE `requestorid` `c_requestorid` VARCHAR(20) NOT NULL,
CHANGE `actiontype` `c_actiontype` INT NOT NULL DEFAULT 0,
CHANGE `note` `c_note` VARCHAR(2000) NOT NULL DEFAULT '',
CHANGE `requested` `c_requested` TIMESTAMP NULL,
CHANGE `due` `c_due` TIMESTAMP NULL,
CHANGE `completed` `c_completed` TIMESTAMP NULL,
CHANGE `iscomplete` `c_iscomplete` BOOL NOT NULL DEFAULT 0,
CHANGE `reftype` `c_reftype` CHAR(1) NOT NULL DEFAULT 'D',
CHANGE `reftypeid` `c_reftypeid` VARCHAR(20) NOT NULL,
CHANGE `created` `c_created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CHANGE `revised` `c_revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
-- deprecations
DROP TABLE IF EXISTS `participant`;

View file

@ -1,6 +0,0 @@
/* community edition */
-- add subscription
ALTER TABLE dmz_org ADD COLUMN `c_sub` JSON NULL AFTER `c_authconfig`;
-- deprecations

View file

@ -1,37 +0,0 @@
/* Community Edition */
-- Space labels provide name/color grouping
DROP TABLE IF EXISTS `dmz_space_label`;
CREATE TABLE IF NOT EXISTS `dmz_space_label` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`c_refid` VARCHAR(20) NOT NULL COLLATE utf8_bin,
`c_orgid` VARCHAR(20) NOT NULL COLLATE utf8_bin,
`c_name` VARCHAR(50) NOT NULL DEFAULT '',
`c_color` VARCHAR(10) NOT NULL DEFAULT '',
`c_created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`c_revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE INDEX `idx_space_label_1` (`id` ASC),
INDEX `idx_space_label_2` (`c_refid` ASC),
INDEX `idx_space_label_3` (`c_orgid` ASC))
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
ENGINE = InnoDB;
-- Space table upgrade to support labelling, icon and summary stats
ALTER TABLE dmz_space ADD COLUMN `c_desc` VARCHAR(200) NOT NULL DEFAULT '' AFTER `c_name`;
ALTER TABLE dmz_space ADD COLUMN `c_labelid` VARCHAR(20) NOT NULL DEFAULT '' COLLATE utf8_bin AFTER `c_likes`;
ALTER TABLE dmz_space ADD COLUMN `c_icon` VARCHAR(20) NOT NULL DEFAULT '' AFTER `c_labelid`;
ALTER TABLE dmz_space ADD COLUMN `c_count_category` INT NOT NULL DEFAULT 0 AFTER `c_icon`;
ALTER TABLE dmz_space ADD COLUMN `c_count_content` INT NOT NULL DEFAULT 0 AFTER `c_count_category`;
-- Org/tenant upgrade to support theming and custom logo
ALTER TABLE dmz_org ADD COLUMN `c_theme` VARCHAR(20) NOT NULL DEFAULT '' AFTER `c_maxtags`;
ALTER TABLE dmz_org ADD COLUMN `c_logo` LONGBLOB AFTER `c_theme`;
-- Populate default values for new fields
UPDATE dmz_space s SET c_count_category=(SELECT COUNT(*) FROM dmz_category WHERE c_spaceid=s.c_refid);
UPDATE dmz_space s SET c_count_content=(SELECT COUNT(*) FROM dmz_doc WHERE c_spaceid=s.c_refid);
-- BUGFIX: Remove zombie group membership records
DELETE FROM dmz_group_member WHERE c_userid NOT IN (SELECT c_userid FROM dmz_user_account);
-- Deprecations

View file

@ -1,6 +0,0 @@
/* Community Edition */
-- BUGFIX: Increase column size
ALTER TABLE dmz_space MODIFY `c_icon` VARCHAR(50) NOT NULL DEFAULT '';
-- Deprecations

View file

@ -1,4 +0,0 @@
/* Community Edition */
-- Support per section attachments
ALTER TABLE dmz_doc_attachment ADD COLUMN `c_sectionid` VARCHAR(20) NOT NULL DEFAULT '' COLLATE utf8_bin AFTER `c_docid`;

View file

@ -1,5 +0,0 @@
/* Enterprise edition */
-- Feedback feature: support threaded comments and section references
ALTER TABLE dmz_doc_comment ADD COLUMN `c_replyto` VARCHAR(20) NOT NULL DEFAULT '' COLLATE utf8_bin AFTER `c_docid`;
ALTER TABLE dmz_doc_comment ADD COLUMN `c_sectionid` VARCHAR(20) NOT NULL DEFAULT '' COLLATE utf8_bin AFTER `c_docid`;

View file

@ -1,5 +0,0 @@
/* Community edition */
-- Indexes to improve performance
CREATE UNIQUE INDEX idx_doc_4 ON dmz_doc(c_orgid,c_refid);
CREATE UNIQUE INDEX idx_section_4 ON dmz_section(c_orgid,c_refid);

View file

@ -1,7 +0,0 @@
/* Community Edition */
-- Increase column sizes to support rich text data entry
ALTER TABLE dmz_org MODIFY `c_message` VARCHAR(800) NOT NULL DEFAULT '';
ALTER TABLE dmz_space MODIFY `c_desc` VARCHAR(800) NOT NULL DEFAULT '';
ALTER TABLE dmz_category MODIFY `c_name` VARCHAR(200) NOT NULL DEFAULT '';
ALTER TABLE dmz_category ADD COLUMN `c_default` BOOL NOT NULL DEFAULT 0 AFTER `c_name`;

View file

@ -1,4 +0,0 @@
/* Community Edition */
-- Allow for pinned documents per space.
ALTER TABLE dmz_doc ADD COLUMN `c_seq` INT NOT NULL DEFAULT 99999 AFTER `c_versionorder`;

View file

@ -1,5 +0,0 @@
/* Community Edition */
-- Local aware.
ALTER TABLE dmz_org ADD COLUMN `c_locale` VARCHAR(20) NOT NULL DEFAULT 'en-US';
ALTER TABLE dmz_user ADD COLUMN `c_locale` VARCHAR(20) NOT NULL DEFAULT 'en-US';

View file

@ -1,479 +0,0 @@
-- SQL to set up the Documize database
-- select * from information_schema.tables WHERE table_catalog='documize';
-- http://www.postgresqltutorial.com/postgresql-json/
-- https://en.wikibooks.org/wiki/Converting_MySQL_to_PostgreSQL
DROP TABLE IF EXISTS dmz_action;
CREATE TABLE dmz_action (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic NOT NULL,
c_docid varchar(20) COLLATE ucs_basic NOT NULL,
c_requestorid varchar(20) COLLATE ucs_basic NOT NULL,
c_actiontype int NOT NULL DEFAULT '0',
c_note varchar(2000) COLLATE ucs_basic NOT NULL DEFAULT '',
c_requested timestamp NULL DEFAULT NULL,
c_due timestamp NULL DEFAULT NULL,
c_completed timestamp NULL DEFAULT NULL,
c_iscomplete bool NOT NULL DEFAULT '0',
c_reftype varchar(1) COLLATE ucs_basic NOT NULL DEFAULT 'D',
c_reftypeid varchar(20) COLLATE ucs_basic NOT NULL,
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE INDEX idx_action_1 ON dmz_action (c_refid);
CREATE INDEX idx_action_2 ON dmz_action (c_userid);
CREATE INDEX idx_action_3 ON dmz_action (c_docid);
CREATE INDEX idx_action_4 ON dmz_action (c_requestorid);
DROP TABLE IF EXISTS dmz_audit_log;
CREATE TABLE dmz_audit_log (
id bigserial NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic NOT NULL,
c_eventtype varchar(100) COLLATE ucs_basic NOT NULL DEFAULT '',
c_ip varchar(39) COLLATE ucs_basic NOT NULL DEFAULT '',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE INDEX idx_audit_log_1 ON dmz_audit_log (c_orgid);
CREATE INDEX idx_audit_log_2 ON dmz_audit_log (c_userid);
CREATE INDEX idx_audit_log_3 ON dmz_audit_log (c_eventtype);
DROP TABLE IF EXISTS dmz_category;
CREATE TABLE dmz_category (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_spaceid varchar(20) COLLATE ucs_basic NOT NULL,
c_name varchar(50) COLLATE ucs_basic NOT NULL,
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE (id)
);
CREATE INDEX idx_category_1 ON dmz_category (c_refid);
CREATE INDEX idx_category_2 ON dmz_category (c_orgid);
CREATE INDEX idx_category_3 ON dmz_category (c_orgid,c_spaceid);
DROP TABLE IF EXISTS dmz_category_member;
CREATE TABLE dmz_category_member (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_spaceid varchar(20) COLLATE ucs_basic NOT NULL,
c_categoryid varchar(20) COLLATE ucs_basic NOT NULL,
c_docid varchar(20) COLLATE ucs_basic NOT NULL,
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE (id)
);
CREATE INDEX idx_category_member_1 ON dmz_category_member (c_docid);
CREATE INDEX idx_category_member_2 ON dmz_category_member (c_orgid,c_docid);
CREATE INDEX idx_category_member_3 ON dmz_category_member (c_orgid,c_spaceid);
DROP TABLE IF EXISTS dmz_config;
CREATE TABLE dmz_config (
c_key varchar(200) COLLATE ucs_basic NOT NULL,
c_config json DEFAULT NULL,
UNIQUE (c_key)
);
DROP TABLE IF EXISTS dmz_doc;
CREATE TABLE dmz_doc (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_spaceid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_job varchar(36) COLLATE ucs_basic NOT NULL DEFAULT '',
c_location varchar(2000) COLLATE ucs_basic NOT NULL DEFAULT '',
c_name varchar(2000) COLLATE ucs_basic NOT NULL DEFAULT '',
c_desc varchar(2000) COLLATE ucs_basic NOT NULL DEFAULT '',
c_slug varchar(2000) COLLATE ucs_basic NOT NULL DEFAULT '',
c_tags varchar(1000) COLLATE ucs_basic NOT NULL DEFAULT '',
c_template bool NOT NULL DEFAULT '0',
c_protection int NOT NULL DEFAULT '0',
c_approval int NOT NULL DEFAULT '0',
c_lifecycle int NOT NULL DEFAULT '1',
c_versioned bool NOT NULL DEFAULT '0',
c_versionid varchar(100) COLLATE ucs_basic NOT NULL DEFAULT '',
c_versionorder int NOT NULL DEFAULT '0',
c_groupid varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (c_refid)
);
CREATE INDEX idx_doc_1 ON dmz_doc (id);
CREATE INDEX idx_doc_2 ON dmz_doc (c_orgid);
CREATE INDEX idx_doc_3 ON dmz_doc (c_spaceid);
DROP TABLE IF EXISTS dmz_doc_attachment;
CREATE TABLE dmz_doc_attachment (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_docid varchar(20) COLLATE ucs_basic NOT NULL,
c_job varchar(36) COLLATE ucs_basic NOT NULL,
c_fileid varchar(10) COLLATE ucs_basic NOT NULL,
c_filename varchar(255) COLLATE ucs_basic NOT NULL,
c_data BYTEA,
c_extension varchar(6) COLLATE ucs_basic NOT NULL,
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (c_refid)
);
CREATE INDEX idx_doc_attachment_1 ON dmz_doc_attachment (id);
CREATE INDEX idx_doc_attachment_2 ON dmz_doc_attachment (c_orgid);
CREATE INDEX idx_doc_attachment_3 ON dmz_doc_attachment (c_docid);
CREATE INDEX idx_doc_attachment_4 ON dmz_doc_attachment (c_job,c_fileid);
DROP TABLE IF EXISTS dmz_doc_comment;
CREATE TABLE dmz_doc_comment (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_docid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic DEFAULT '',
c_email varchar(250) COLLATE ucs_basic NOT NULL DEFAULT '',
c_feedback text COLLATE ucs_basic,
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE INDEX idx_doc_comment_1 ON dmz_doc_comment (c_refid);
DROP TABLE IF EXISTS dmz_doc_link;
CREATE TABLE dmz_doc_link (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_spaceid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic NOT NULL,
c_sourcedocid varchar(20) COLLATE ucs_basic NOT NULL,
c_sourcesectionid varchar(20) COLLATE ucs_basic NOT NULL,
c_type varchar(20) COLLATE ucs_basic NOT NULL,
c_targetdocid varchar(20) COLLATE ucs_basic NOT NULL,
c_targetid varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_externalid varchar(1000) COLLATE ucs_basic NOT NULL DEFAULT '',
c_orphan bool NOT NULL DEFAULT '0',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
DROP TABLE IF EXISTS dmz_doc_share;
CREATE TABLE dmz_doc_share (
id bigserial NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_docid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic DEFAULT '',
c_email varchar(250) COLLATE ucs_basic NOT NULL DEFAULT '',
c_message varchar(500) COLLATE ucs_basic NOT NULL DEFAULT '',
c_viewed varchar(500) COLLATE ucs_basic NOT NULL DEFAULT '',
c_secret varchar(250) COLLATE ucs_basic NOT NULL DEFAULT '',
c_expires varchar(20) COLLATE ucs_basic DEFAULT '',
c_active bool NOT NULL DEFAULT '1',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
DROP TABLE IF EXISTS dmz_doc_vote;
CREATE TABLE dmz_doc_vote (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_docid varchar(20) COLLATE ucs_basic NOT NULL,
c_voter varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_vote int NOT NULL DEFAULT '0',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE (id)
);
CREATE INDEX idx_doc_vote_1 ON dmz_doc_vote (c_refid);
CREATE INDEX idx_doc_vote_2 ON dmz_doc_vote (c_docid);
CREATE INDEX idx_doc_vote_3 ON dmz_doc_vote (c_orgid);
CREATE INDEX idx_doc_vote_4 ON dmz_doc_vote (c_orgid,c_docid);
DROP TABLE IF EXISTS dmz_group;
CREATE TABLE dmz_group (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_name varchar(50) COLLATE ucs_basic NOT NULL DEFAULT '',
c_desc varchar(100) COLLATE ucs_basic DEFAULT '',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE (id)
);
CREATE INDEX idx_group_1 ON dmz_group (c_refid);
CREATE INDEX idx_group_2 ON dmz_group (c_orgid);
DROP TABLE IF EXISTS dmz_group_member;
CREATE TABLE dmz_group_member (
id bigserial NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_groupid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic NOT NULL,
UNIQUE (id)
);
CREATE INDEX idx_group_member_1 ON dmz_group_member (c_groupid,c_userid);
CREATE INDEX idx_group_member_2 ON dmz_group_member (c_orgid,c_groupid,c_userid);
DROP TABLE IF EXISTS dmz_org;
CREATE TABLE dmz_org (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_company varchar(500) COLLATE ucs_basic NOT NULL,
c_title varchar(500) COLLATE ucs_basic NOT NULL,
c_message varchar(500) COLLATE ucs_basic NOT NULL,
c_domain varchar(200) COLLATE ucs_basic NOT NULL DEFAULT '',
c_service varchar(200) COLLATE ucs_basic NOT NULL DEFAULT '',
c_email varchar(500) COLLATE ucs_basic NOT NULL DEFAULT '',
c_anonaccess bool NOT NULL DEFAULT '0',
c_authprovider varchar(20) COLLATE ucs_basic NOT NULL DEFAULT 'documize',
c_authconfig json DEFAULT NULL,
c_maxtags int NOT NULL DEFAULT '3',
c_verified bool NOT NULL DEFAULT '0',
c_serial varchar(50) COLLATE ucs_basic NOT NULL DEFAULT '',
c_active bool NOT NULL DEFAULT '1',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (c_refid)
);
CREATE INDEX idx_org_1 ON dmz_org (id);
CREATE INDEX idx_org_2 ON dmz_org (c_domain);
DROP TABLE IF EXISTS dmz_permission;
CREATE TABLE dmz_permission (
id bigserial NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_who varchar(30) COLLATE ucs_basic NOT NULL,
c_whoid varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_action varchar(30) COLLATE ucs_basic NOT NULL,
c_scope varchar(30) COLLATE ucs_basic NOT NULL,
c_location varchar(100) COLLATE ucs_basic NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE (id)
);
CREATE INDEX idx_permission_1 ON dmz_permission (c_orgid);
CREATE INDEX idx_permission_2 ON dmz_permission (c_orgid,c_who,c_whoid,c_location);
CREATE INDEX idx_permission_3 ON dmz_permission (c_orgid,c_who,c_whoid,c_location,c_action);
CREATE INDEX idx_permission_4 ON dmz_permission (c_orgid,c_location,c_refid);
CREATE INDEX idx_permission_5 ON dmz_permission (c_orgid,c_who,c_location,c_action);
DROP TABLE IF EXISTS dmz_pin;
CREATE TABLE dmz_pin (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic DEFAULT '',
c_spaceid varchar(20) COLLATE ucs_basic DEFAULT '',
c_docid varchar(20) COLLATE ucs_basic DEFAULT '',
c_sequence BIGINT NOT NULL DEFAULT '99',
c_name varchar(100) COLLATE ucs_basic NOT NULL DEFAULT '',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE INDEX idx_pin_1 ON dmz_pin (c_userid);
DROP TABLE IF EXISTS dmz_search;
CREATE TABLE dmz_search (
id bigserial NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_docid varchar(20) COLLATE ucs_basic NOT NULL,
c_itemid varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_itemtype varchar(10) COLLATE ucs_basic NOT NULL,
c_content text COLLATE ucs_basic,
c_token TSVECTOR,
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE (id)
);
CREATE INDEX idx_search_1 ON dmz_search (c_orgid);
CREATE INDEX idx_search_2 ON dmz_search (c_docid);
CREATE INDEX idx_search_3 ON dmz_search USING GIN(c_token);
DROP TABLE IF EXISTS dmz_section;
CREATE TABLE dmz_section (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_docid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_contenttype varchar(20) COLLATE ucs_basic NOT NULL DEFAULT 'wysiwyg',
c_type varchar(10) COLLATE ucs_basic NOT NULL DEFAULT 'section',
c_templateid varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_level bigint NOT NULL,
c_sequence double precision NOT NULL,
c_name varchar(2000) COLLATE ucs_basic NOT NULL DEFAULT '',
c_body text COLLATE ucs_basic,
c_revisions bigint NOT NULL,
c_status int NOT NULL DEFAULT '0',
c_relativeid varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (c_refid)
);
CREATE INDEX idx_section_1 ON dmz_section (id);
CREATE INDEX idx_section_2 ON dmz_section (c_orgid);
CREATE INDEX idx_section_3 ON dmz_section (c_docid);
DROP TABLE IF EXISTS dmz_section_meta;
CREATE TABLE dmz_section_meta (
id bigserial NOT NULL,
c_sectionid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_docid varchar(20) COLLATE ucs_basic NOT NULL,
c_rawbody BYTEA,
c_config json DEFAULT NULL,
c_external bool DEFAULT '0',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (c_sectionid)
);
CREATE INDEX idx_section_meta_1 ON dmz_section_meta (id);
CREATE INDEX idx_section_meta_2 ON dmz_section_meta (c_sectionid);
CREATE INDEX idx_section_meta_3 ON dmz_section_meta (c_orgid);
CREATE INDEX idx_section_meta_4 ON dmz_section_meta (c_docid);
DROP TABLE IF EXISTS dmz_section_revision;
CREATE TABLE dmz_section_revision (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_docid varchar(20) COLLATE ucs_basic NOT NULL,
c_ownerid varchar(20) COLLATE ucs_basic DEFAULT '',
c_sectionid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic NOT NULL,
c_contenttype varchar(20) COLLATE ucs_basic NOT NULL DEFAULT 'wysiwyg',
c_type varchar(10) COLLATE ucs_basic NOT NULL DEFAULT 'section',
c_name varchar(2000) COLLATE ucs_basic NOT NULL DEFAULT '',
c_body text COLLATE ucs_basic,
c_rawbody BYTEA,
c_config json DEFAULT NULL,
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (c_refid)
);
CREATE INDEX idx_section_revision_1 ON dmz_section_revision (id);
CREATE INDEX idx_section_revision_2 ON dmz_section_revision (c_orgid);
CREATE INDEX idx_section_revision_3 ON dmz_section_revision (c_docid);
CREATE INDEX idx_section_revision_4 ON dmz_section_revision (c_sectionid);
DROP TABLE IF EXISTS dmz_section_template;
CREATE TABLE dmz_section_template (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_spaceid varchar(20) COLLATE ucs_basic DEFAULT '',
c_userid varchar(20) COLLATE ucs_basic DEFAULT '',
c_contenttype varchar(20) COLLATE ucs_basic NOT NULL DEFAULT 'wysiwyg',
c_type varchar(10) COLLATE ucs_basic NOT NULL DEFAULT 'section',
c_name varchar(2000) COLLATE ucs_basic NOT NULL DEFAULT '',
c_body text COLLATE ucs_basic,
c_desc varchar(2000) COLLATE ucs_basic NOT NULL DEFAULT '',
c_used bigint NOT NULL,
c_rawbody BYTEA,
c_config json DEFAULT NULL,
c_external bool DEFAULT '0',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE INDEX idx_section_template_1 ON dmz_section_template (c_refid);
CREATE INDEX idx_section_template_2 ON dmz_section_template (c_spaceid);
DROP TABLE IF EXISTS dmz_space;
CREATE TABLE dmz_space (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_name varchar(300) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_type int NOT NULL DEFAULT '1',
c_lifecycle int NOT NULL DEFAULT '1',
c_likes varchar(1000) COLLATE ucs_basic NOT NULL DEFAULT '',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (c_refid)
);
CREATE INDEX idx_space_1 ON dmz_space (id);
CREATE INDEX idx_space_2 ON dmz_space (c_userid);
CREATE INDEX idx_space_3 ON dmz_space (c_orgid);
DROP TABLE IF EXISTS dmz_user;
CREATE TABLE dmz_user (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_firstname varchar(500) COLLATE ucs_basic NOT NULL DEFAULT '',
c_lastname varchar(500) COLLATE ucs_basic NOT NULL DEFAULT '',
c_email varchar(500) COLLATE ucs_basic NOT NULL DEFAULT '',
c_initials varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_globaladmin bool NOT NULL DEFAULT '0',
c_password varchar(500) COLLATE ucs_basic NOT NULL DEFAULT '',
c_salt varchar(500) COLLATE ucs_basic NOT NULL DEFAULT '',
c_reset varchar(500) COLLATE ucs_basic NOT NULL DEFAULT '',
c_active bool NOT NULL DEFAULT '1',
c_lastversion varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (c_refid)
);
CREATE INDEX idx_user_1 ON dmz_user (id);
CREATE INDEX idx_user_2 ON dmz_user (c_email);
DROP TABLE IF EXISTS dmz_user_account;
CREATE TABLE dmz_user_account (
id bigserial NOT NULL,
c_refid varchar(20) COLLATE ucs_basic NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic NOT NULL,
c_editor bool NOT NULL DEFAULT '0',
c_admin bool NOT NULL DEFAULT '0',
c_users bool NOT NULL DEFAULT '1',
c_analytics bool NOT NULL DEFAULT '0',
c_active bool NOT NULL DEFAULT '1',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (c_refid)
);
CREATE INDEX idx_user_account_1 ON dmz_user_account (id);
CREATE INDEX idx_user_account_2 ON dmz_user_account (c_userid);
CREATE INDEX idx_user_account_3 ON dmz_user_account (c_orgid);
DROP TABLE IF EXISTS dmz_user_activity;
CREATE TABLE dmz_user_activity (
id bigserial NOT NULL,
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic NOT NULL,
c_spaceid varchar(20) COLLATE ucs_basic NOT NULL,
c_docid varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_sectionid varchar(20) COLLATE ucs_basic NOT NULL DEFAULT '',
c_sourcetype int NOT NULL DEFAULT '0',
c_activitytype int NOT NULL DEFAULT '0',
c_metadata varchar(1000) COLLATE ucs_basic NOT NULL DEFAULT '',
c_created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE INDEX idx_user_activity_1 ON dmz_user_activity (c_orgid);
CREATE INDEX idx_user_activity_2 ON dmz_user_activity (c_userid);
CREATE INDEX idx_user_activity_3 ON dmz_user_activity (c_activitytype);
CREATE INDEX idx_user_activity_4 ON dmz_user_activity (c_orgid,c_docid,c_sourcetype);
CREATE INDEX idx_user_activity_5 ON dmz_user_activity (c_orgid,c_docid,c_userid,c_sourcetype);
DROP TABLE IF EXISTS dmz_user_config;
CREATE TABLE dmz_user_config (
c_orgid varchar(20) COLLATE ucs_basic NOT NULL,
c_userid varchar(20) COLLATE ucs_basic NOT NULL,
c_key varchar(200) COLLATE ucs_basic NOT NULL,
c_config json DEFAULT NULL,
UNIQUE (c_orgid,c_userid,c_key)
);
INSERT INTO dmz_config VALUES ('SMTP','{"userid": "","password": "","host": "","port": "","sender": ""}');
INSERT INTO dmz_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 dmz_config VALUES ('SECTION-TRELLO','{"appKey": ""}');
INSERT INTO dmz_config VALUES ('META','{"database": "0"}');

View file

@ -1,6 +0,0 @@
/* community edition */
-- add subscription
ALTER TABLE dmz_org ADD COLUMN c_sub JSON NULL;
-- deprecations

View file

@ -1,36 +0,0 @@
/* Community Edition */
-- Space labels provide name/color grouping
DROP TABLE IF EXISTS dmz_space_label;
CREATE TABLE dmz_space_label (
id bigserial NOT NULL,
c_refid VARCHAR(20) NOT NULL COLLATE ucs_basic,
c_orgid VARCHAR(20) NOT NULL COLLATE ucs_basic,
c_name VARCHAR(50) NOT NULL DEFAULT '',
c_color VARCHAR(10) NOT NULL DEFAULT '',
c_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
c_revised TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (c_refid)
);
CREATE INDEX idx_space_label_1 ON dmz_space_label (id);
CREATE INDEX idx_space_label_2 ON dmz_space_label (c_orgid);
-- Space table upgrade to support label, icon and summary stats
ALTER TABLE dmz_space ADD COLUMN c_desc VARCHAR(200) NOT NULL DEFAULT '';
ALTER TABLE dmz_space ADD COLUMN c_labelid VARCHAR(20) NOT NULL DEFAULT '' COLLATE ucs_basic;
ALTER TABLE dmz_space ADD COLUMN c_icon VARCHAR(20) NOT NULL DEFAULT '';
ALTER TABLE dmz_space ADD COLUMN c_count_category INT NOT NULL DEFAULT 0;
ALTER TABLE dmz_space ADD COLUMN c_count_content INT NOT NULL DEFAULT 0;
-- Org/tenant upgrade to support theming and custom logo
ALTER TABLE dmz_org ADD COLUMN c_theme VARCHAR(20) NOT NULL DEFAULT '';
ALTER TABLE dmz_org ADD COLUMN c_logo BYTEA;
-- Populate default values for new fields
UPDATE dmz_space s SET c_count_category=(SELECT COUNT(*) FROM dmz_category WHERE c_spaceid=s.c_refid);
UPDATE dmz_space s SET c_count_content=(SELECT COUNT(*) FROM dmz_doc WHERE c_spaceid=s.c_refid);
-- BUGFIX: Remove zombie group membership records
DELETE FROM dmz_group_member WHERE c_userid NOT IN (SELECT c_userid FROM dmz_user_account);
-- Deprecations

View file

@ -1,6 +0,0 @@
/* Community Edition */
-- BUGFIX: Increase column size
ALTER TABLE dmz_space ALTER COLUMN c_icon TYPE VARCHAR(50);
-- Deprecations

View file

@ -1,4 +0,0 @@
/* Community Edition */
-- Support per section attachments
ALTER TABLE dmz_doc_attachment ADD COLUMN c_sectionid VARCHAR(20) NOT NULL DEFAULT '' COLLATE ucs_basic;

View file

@ -1,5 +0,0 @@
/* Enterprise edition */
-- Feedback feature: support threaded comments and section references
ALTER TABLE dmz_doc_comment ADD COLUMN c_replyto VARCHAR(20) NOT NULL DEFAULT '' COLLATE ucs_basic;
ALTER TABLE dmz_doc_comment ADD COLUMN c_sectionid VARCHAR(20) NOT NULL DEFAULT '' COLLATE ucs_basic;

View file

@ -1,5 +0,0 @@
/* Community edition */
-- Indexes to improve performance
CREATE UNIQUE INDEX idx_doc_4 ON dmz_doc (c_orgid,c_refid);
CREATE UNIQUE INDEX idx_section_4 ON dmz_section (c_orgid,c_refid);

View file

@ -1,7 +0,0 @@
/* Community Edition */
-- Increase column sizes to support rich text data entry
ALTER TABLE dmz_org ALTER COLUMN c_message TYPE VARCHAR(2000);
ALTER TABLE dmz_space ALTER COLUMN c_desc TYPE VARCHAR(2000);
ALTER TABLE dmz_category ALTER COLUMN c_name TYPE VARCHAR(200);
ALTER TABLE dmz_category ADD COLUMN c_default bool NOT NULL DEFAULT '0';

View file

@ -1,5 +0,0 @@
/* Community Edition */
-- Allow for pinned documents per space.
ALTER TABLE dmz_doc ADD COLUMN c_seq INT NOT NULL DEFAULT '99999';

View file

@ -1,5 +0,0 @@
/* Community Edition */
-- Local aware.
ALTER TABLE dmz_org ADD COLUMN c_locale VARCHAR(20) NOT NULL DEFAULT 'en-US';
ALTER TABLE dmz_user ADD COLUMN c_locale VARCHAR(20) NOT NULL DEFAULT 'en-US';

View file

@ -1,469 +0,0 @@
-- SQL to set up the Documize database
DROP TABLE IF EXISTS dmz_action;
CREATE TABLE dmz_action (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_docid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_requestorid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_actiontype INT NOT NULL DEFAULT '0',
c_note NVARCHAR(2000) NOT NULL DEFAULT '',
c_requested DATETIME2 NULL DEFAULT NULL,
c_due DATETIME2 NULL DEFAULT NULL,
c_completed DATETIME2 NULL DEFAULT NULL,
c_iscomplete BIT NOT NULL DEFAULT '0',
c_reftype NVARCHAR(1) NOT NULL DEFAULT 'D',
c_reftypeid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_action_1 ON dmz_action (c_refid);
CREATE INDEX idx_action_2 ON dmz_action (c_userid);
CREATE INDEX idx_action_3 ON dmz_action (c_docid);
CREATE INDEX idx_action_4 ON dmz_action (c_requestorid);
DROP TABLE IF EXISTS dmz_audit_log;
CREATE TABLE dmz_audit_log (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_eventtype NVARCHAR(100) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_ip NVARCHAR(39) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_audit_log_1 ON dmz_audit_log (c_orgid);
CREATE INDEX idx_audit_log_2 ON dmz_audit_log (c_userid);
CREATE INDEX idx_audit_log_3 ON dmz_audit_log (c_eventtype);
DROP TABLE IF EXISTS dmz_category;
CREATE TABLE dmz_category (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_spaceid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_name NVARCHAR(50) COLLATE Latin1_General_CS_AS NOT NULL,
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_category_1 ON dmz_category (c_refid);
CREATE INDEX idx_category_2 ON dmz_category (c_orgid);
CREATE INDEX idx_category_3 ON dmz_category (c_orgid,c_spaceid);
DROP TABLE IF EXISTS dmz_category_member;
CREATE TABLE dmz_category_member (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_spaceid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_categoryid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_docid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_category_member_1 ON dmz_category_member (c_docid);
CREATE INDEX idx_category_member_2 ON dmz_category_member (c_orgid,c_docid);
CREATE INDEX idx_category_member_3 ON dmz_category_member (c_orgid,c_spaceid);
DROP TABLE IF EXISTS dmz_config;
CREATE TABLE dmz_config (
c_key NVARCHAR(200) COLLATE Latin1_General_CS_AS NOT NULL,
c_config NVARCHAR(MAX) DEFAULT NULL
);
DROP TABLE IF EXISTS dmz_doc;
CREATE TABLE dmz_doc (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_spaceid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_job NVARCHAR(36) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_location NVARCHAR(2000) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_name NVARCHAR(2000) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_desc NVARCHAR(2000) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_slug NVARCHAR(2000) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_tags NVARCHAR(1000) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_template BIT NOT NULL DEFAULT '0',
c_protection INT NOT NULL DEFAULT '0',
c_approval INT NOT NULL DEFAULT '0',
c_lifecycle INT NOT NULL DEFAULT '1',
c_versioned BIT NOT NULL DEFAULT '0',
c_versionid NVARCHAR(100) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_versionorder INT NOT NULL DEFAULT '0',
c_groupid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_doc_1 ON dmz_doc (id);
CREATE INDEX idx_doc_2 ON dmz_doc (c_orgid);
CREATE INDEX idx_doc_3 ON dmz_doc (c_spaceid);
DROP TABLE IF EXISTS dmz_doc_attachment;
CREATE TABLE dmz_doc_attachment (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_docid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_job NVARCHAR(36) COLLATE Latin1_General_CS_AS NOT NULL,
c_fileid NVARCHAR(10) COLLATE Latin1_General_CS_AS NOT NULL,
c_filename NVARCHAR(255) COLLATE Latin1_General_CS_AS NOT NULL,
c_data VARBINARY(MAX),
c_extension NVARCHAR(6) COLLATE Latin1_General_CS_AS NOT NULL,
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_doc_attachment_1 ON dmz_doc_attachment (id);
CREATE INDEX idx_doc_attachment_2 ON dmz_doc_attachment (c_orgid);
CREATE INDEX idx_doc_attachment_3 ON dmz_doc_attachment (c_docid);
CREATE INDEX idx_doc_attachment_4 ON dmz_doc_attachment (c_job,c_fileid);
DROP TABLE IF EXISTS dmz_doc_comment;
CREATE TABLE dmz_doc_comment (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_docid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS DEFAULT '',
c_email NVARCHAR(250) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_feedback NVARCHAR(MAX) COLLATE Latin1_General_CS_AS,
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_doc_comment_1 ON dmz_doc_comment (c_refid);
DROP TABLE IF EXISTS dmz_doc_link;
CREATE TABLE dmz_doc_link (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_spaceid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_sourcedocid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_sourcesectionid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_type NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_targetdocid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_targetid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_externalid NVARCHAR(1000) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_orphan BIT NOT NULL DEFAULT '0',
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
DROP TABLE IF EXISTS dmz_doc_share;
CREATE TABLE dmz_doc_share (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_docid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS DEFAULT '',
c_email NVARCHAR(250) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_message NVARCHAR(500) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_viewed NVARCHAR(500) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_secret NVARCHAR(250) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_expires NVARCHAR(20) COLLATE Latin1_General_CS_AS DEFAULT '',
c_active BIT NOT NULL DEFAULT '1',
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
DROP TABLE IF EXISTS dmz_doc_vote;
CREATE TABLE dmz_doc_vote (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_docid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_voter NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_vote INT NOT NULL DEFAULT '0',
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_doc_vote_1 ON dmz_doc_vote (c_refid);
CREATE INDEX idx_doc_vote_2 ON dmz_doc_vote (c_docid);
CREATE INDEX idx_doc_vote_3 ON dmz_doc_vote (c_orgid);
CREATE INDEX idx_doc_vote_4 ON dmz_doc_vote (c_orgid,c_docid);
DROP TABLE IF EXISTS dmz_group;
CREATE TABLE dmz_group (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_name NVARCHAR(50) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_desc NVARCHAR(100) COLLATE Latin1_General_CS_AS DEFAULT '',
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_group_1 ON dmz_group (c_refid);
CREATE INDEX idx_group_2 ON dmz_group (c_orgid);
DROP TABLE IF EXISTS dmz_group_member;
CREATE TABLE dmz_group_member (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_groupid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL
);
CREATE INDEX idx_group_member_1 ON dmz_group_member (c_groupid,c_userid);
CREATE INDEX idx_group_member_2 ON dmz_group_member (c_orgid,c_groupid,c_userid);
DROP TABLE IF EXISTS dmz_org;
CREATE TABLE dmz_org (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_company NVARCHAR(500) COLLATE Latin1_General_CS_AS NOT NULL,
c_title NVARCHAR(500) COLLATE Latin1_General_CS_AS NOT NULL,
c_message NVARCHAR(500) COLLATE Latin1_General_CS_AS NOT NULL,
c_domain NVARCHAR(200) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_service NVARCHAR(200) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_email NVARCHAR(500) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_anonaccess BIT NOT NULL DEFAULT '0',
c_authprovider NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT 'documize',
c_authconfig NVARCHAR(MAX) DEFAULT NULL,
c_maxtags INT NOT NULL DEFAULT '3',
c_sub NVARCHAR(MAX) NULL,
c_theme NVARCHAR(20) NOT NULL DEFAULT '',
c_logo VARBINARY(MAX),
c_verified BIT NOT NULL DEFAULT '0',
c_serial NVARCHAR(50) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_active BIT NOT NULL DEFAULT '1',
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
);
CREATE INDEX idx_org_1 ON dmz_org (id);
CREATE INDEX idx_org_2 ON dmz_org (c_domain);
DROP TABLE IF EXISTS dmz_permission;
CREATE TABLE dmz_permission (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_who NVARCHAR(30) COLLATE Latin1_General_CS_AS NOT NULL,
c_whoid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_action NVARCHAR(30) COLLATE Latin1_General_CS_AS NOT NULL,
c_scope NVARCHAR(30) COLLATE Latin1_General_CS_AS NOT NULL,
c_location NVARCHAR(100) COLLATE Latin1_General_CS_AS NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_permission_1 ON dmz_permission (c_orgid);
CREATE INDEX idx_permission_2 ON dmz_permission (c_orgid,c_who,c_whoid,c_location);
CREATE INDEX idx_permission_3 ON dmz_permission (c_orgid,c_who,c_whoid,c_location,c_action);
CREATE INDEX idx_permission_4 ON dmz_permission (c_orgid,c_location,c_refid);
CREATE INDEX idx_permission_5 ON dmz_permission (c_orgid,c_who,c_location,c_action);
DROP TABLE IF EXISTS dmz_pin;
CREATE TABLE dmz_pin (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS DEFAULT '',
c_spaceid NVARCHAR(20) COLLATE Latin1_General_CS_AS DEFAULT '',
c_docid NVARCHAR(20) COLLATE Latin1_General_CS_AS DEFAULT '',
c_sequence BIGINT NOT NULL DEFAULT '99',
c_name NVARCHAR(100) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_pin_1 ON dmz_pin (c_userid);
DROP TABLE IF EXISTS dmz_search;
CREATE TABLE dmz_search (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_docid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_itemid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_itemtype NVARCHAR(10) COLLATE Latin1_General_CS_AS NOT NULL,
c_content NVARCHAR(MAX) COLLATE Latin1_General_CS_AS,
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_search_1 ON dmz_search (c_orgid);
CREATE INDEX idx_search_2 ON dmz_search (c_docid);
DROP TABLE IF EXISTS dmz_section;
CREATE TABLE dmz_section (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_docid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_contenttype NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT 'wysiwyg',
c_type NVARCHAR(10) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT 'section',
c_templateid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_level bigint NOT NULL,
c_sequence double precision NOT NULL,
c_name NVARCHAR(2000) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_body NVARCHAR(MAX) COLLATE Latin1_General_CS_AS,
c_revisions bigint NOT NULL,
c_status INT NOT NULL DEFAULT '0',
c_relativeid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_section_1 ON dmz_section (id);
CREATE INDEX idx_section_2 ON dmz_section (c_orgid);
CREATE INDEX idx_section_3 ON dmz_section (c_docid);
DROP TABLE IF EXISTS dmz_section_meta;
CREATE TABLE dmz_section_meta (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_sectionid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_docid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_rawbody NVARCHAR(MAX),
c_config NVARCHAR(MAX) DEFAULT NULL,
c_external BIT DEFAULT '0',
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_section_meta_1 ON dmz_section_meta (id);
CREATE INDEX idx_section_meta_2 ON dmz_section_meta (c_sectionid);
CREATE INDEX idx_section_meta_3 ON dmz_section_meta (c_orgid);
CREATE INDEX idx_section_meta_4 ON dmz_section_meta (c_docid);
DROP TABLE IF EXISTS dmz_section_revision;
CREATE TABLE dmz_section_revision (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_docid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_ownerid NVARCHAR(20) COLLATE Latin1_General_CS_AS DEFAULT '',
c_sectionid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_contenttype NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT 'wysiwyg',
c_type NVARCHAR(10) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT 'section',
c_name NVARCHAR(2000) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_body NVARCHAR(MAX) COLLATE Latin1_General_CS_AS,
c_rawbody NVARCHAR(MAX),
c_config NVARCHAR(MAX) DEFAULT NULL,
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_section_revision_1 ON dmz_section_revision (id);
CREATE INDEX idx_section_revision_2 ON dmz_section_revision (c_orgid);
CREATE INDEX idx_section_revision_3 ON dmz_section_revision (c_docid);
CREATE INDEX idx_section_revision_4 ON dmz_section_revision (c_sectionid);
DROP TABLE IF EXISTS dmz_section_template;
CREATE TABLE dmz_section_template (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_spaceid NVARCHAR(20) COLLATE Latin1_General_CS_AS DEFAULT '',
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS DEFAULT '',
c_contenttype NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT 'wysiwyg',
c_type NVARCHAR(10) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT 'section',
c_name NVARCHAR(2000) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_body NVARCHAR(MAX) COLLATE Latin1_General_CS_AS,
c_desc NVARCHAR(2000) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_used INT NOT NULL,
c_rawbody NVARCHAR(MAX),
c_config NVARCHAR(MAX) DEFAULT NULL,
c_external BIT DEFAULT '0',
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_section_template_1 ON dmz_section_template (c_refid);
CREATE INDEX idx_section_template_2 ON dmz_section_template (c_spaceid);
DROP TABLE IF EXISTS dmz_space;
CREATE TABLE dmz_space (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_name NVARCHAR(300) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_type INT NOT NULL DEFAULT '1',
c_lifecycle INT NOT NULL DEFAULT '1',
c_desc NVARCHAR(200) NOT NULL DEFAULT '',
c_labelid NVARCHAR(20) NOT NULL DEFAULT '' COLLATE Latin1_General_CS_AS,
c_likes NVARCHAR(1000) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_icon NVARCHAR(50) NOT NULL DEFAULT '',
c_count_category INT NOT NULL DEFAULT 0,
c_count_content INT NOT NULL DEFAULT 0,
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_space_1 ON dmz_space (id);
CREATE INDEX idx_space_2 ON dmz_space (c_userid);
CREATE INDEX idx_space_3 ON dmz_space (c_orgid);
DROP TABLE IF EXISTS dmz_space_label;
CREATE TABLE dmz_space_label (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_name NVARCHAR(50) NOT NULL DEFAULT '',
c_color NVARCHAR(10) NOT NULL DEFAULT '',
c_created DATETIME2 DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_space_label_1 ON dmz_space_label (id);
CREATE INDEX idx_space_label_2 ON dmz_space_label (c_orgid);
DROP TABLE IF EXISTS dmz_user;
CREATE TABLE dmz_user (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_firstname NVARCHAR(500) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_lastname NVARCHAR(500) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_email NVARCHAR(500) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_initials NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_globaladmin BIT NOT NULL DEFAULT '0',
c_password NVARCHAR(500) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_salt NVARCHAR(500) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_reset NVARCHAR(500) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_active BIT NOT NULL DEFAULT '1',
c_lastversion NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_user_1 ON dmz_user (id);
CREATE INDEX idx_user_2 ON dmz_user (c_email);
DROP TABLE IF EXISTS dmz_user_account;
CREATE TABLE dmz_user_account (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_refid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_editor BIT NOT NULL DEFAULT '0',
c_admin BIT NOT NULL DEFAULT '0',
c_users BIT NOT NULL DEFAULT '1',
c_analytics BIT NOT NULL DEFAULT '0',
c_active BIT NOT NULL DEFAULT '1',
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
c_revised DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_user_account_1 ON dmz_user_account (id);
CREATE INDEX idx_user_account_2 ON dmz_user_account (c_userid);
CREATE INDEX idx_user_account_3 ON dmz_user_account (c_orgid);
DROP TABLE IF EXISTS dmz_user_activity;
CREATE TABLE dmz_user_activity (
id BIGINT PRIMARY KEY IDENTITY (1, 1) NOT NULL,
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_spaceid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_docid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_sectionid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_sourcetype INT NOT NULL DEFAULT '0',
c_activitytype INT NOT NULL DEFAULT '0',
c_metadata NVARCHAR(1000) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '',
c_created DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_user_activity_1 ON dmz_user_activity (c_orgid);
CREATE INDEX idx_user_activity_2 ON dmz_user_activity (c_userid);
CREATE INDEX idx_user_activity_3 ON dmz_user_activity (c_activitytype);
CREATE INDEX idx_user_activity_4 ON dmz_user_activity (c_orgid,c_docid,c_sourcetype);
CREATE INDEX idx_user_activity_5 ON dmz_user_activity (c_orgid,c_docid,c_userid,c_sourcetype);
DROP TABLE IF EXISTS dmz_user_config;
CREATE TABLE dmz_user_config (
c_orgid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_userid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL,
c_key NVARCHAR(200) COLLATE Latin1_General_CS_AS NOT NULL,
c_config NVARCHAR(MAX) DEFAULT NULL
);
INSERT INTO dmz_config VALUES ('SMTP','{"userid": "","password": "","host": "","port": "","sender": ""}');
INSERT INTO dmz_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 dmz_config VALUES ('SECTION-TRELLO','{"appKey": ""}');
INSERT INTO dmz_config VALUES ('META','{"database": "0"}');

View file

@ -1,4 +0,0 @@
/* Community Edition */
-- Support per section attachments
ALTER TABLE dmz_doc_attachment ADD c_sectionid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '';

View file

@ -1,5 +0,0 @@
/* Enterprise edition */
-- Feedback feature: support threaded comments and section references
ALTER TABLE dmz_doc_comment ADD c_replyto NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '';
ALTER TABLE dmz_doc_comment ADD c_sectionid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '';

View file

@ -1,16 +0,0 @@
/* Community edition */
-- Fulltext search support
IF EXISTS (SELECT * FROM sysfulltextcatalogs ftc WHERE ftc.name = N'dmz_search_catalog')
DROP FULLTEXT CATALOG dmz_search_catalog;
CREATE FULLTEXT CATALOG dmz_search_catalog;
CREATE UNIQUE INDEX idx_doc_4 ON dmz_doc(c_refid);
CREATE UNIQUE INDEX idx_section_4 ON dmz_section(c_refid);
CREATE FULLTEXT INDEX ON dmz_doc (c_name, c_desc) KEY INDEX idx_doc_4 ON dmz_search_catalog
WITH CHANGE_TRACKING AUTO;
CREATE FULLTEXT INDEX ON dmz_section (c_name, c_body) KEY INDEX idx_section_4 ON dmz_search_catalog
WITH CHANGE_TRACKING AUTO;

View file

@ -1,7 +0,0 @@
/* Community edition */
-- Increase column sizes to support rich text data entry
ALTER TABLE dmz_org ALTER COLUMN c_message NVARCHAR(2000);
ALTER TABLE dmz_space ALTER COLUMN c_desc NVARCHAR(2000);
ALTER TABLE dmz_category ALTER COLUMN c_name NVARCHAR(200);
ALTER TABLE dmz_category ADD c_default BIT NOT NULL DEFAULT '0';

View file

@ -1,4 +0,0 @@
/* Community edition */
-- Allow for pinned documents per space.
ALTER TABLE dmz_doc ADD c_seq INT NOT NULL DEFAULT '99999';

View file

@ -1,5 +0,0 @@
/* Community edition */
-- Local aware.
ALTER TABLE dmz_org ADD c_locale NVARCHAR(20) NOT NULL DEFAULT 'en-US';
ALTER TABLE dmz_user ADD c_locale NVARCHAR(20) NOT NULL DEFAULT 'en-US';

View file

@ -1,4 +0,0 @@
/* Community edition */
-- Performance indexes
CREATE INDEX idx_action_5 ON dmz_action (c_orgid,c_userid,c_docid,c_actiontype,c_iscomplete,c_reftype,c_reftypeid);

View file

@ -1,8 +0,0 @@
/* Community edition */
-- Performance indexes
CREATE INDEX idx_action_6 ON dmz_action (c_orgid,c_reftypeid,c_reftype);
CREATE INDEX idx_action_7 ON dmz_action (c_orgid,c_refid);
CREATE INDEX idx_section_5 ON dmz_section (c_orgid,c_refid);

View file

@ -1,6 +0,0 @@
/* Community edition */
-- Performance indexes
CREATE INDEX idx_action_8 ON dmz_action (c_orgid,c_docid);
CREATE INDEX idx_user_3 ON dmz_user (c_refid);

View file

@ -1,207 +0,0 @@
// 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 (
"encoding/json"
"encoding/xml"
"errors"
"net/http"
"time"
"github.com/documize/community/core/api/plugins"
"github.com/documize/community/core/env"
"github.com/documize/community/core/secrets"
"github.com/documize/community/core/stringutil"
"github.com/documize/community/core/uniqueid"
"github.com/documize/community/domain"
"github.com/documize/community/domain/store"
"github.com/documize/community/server/web"
)
// Handler contains the runtime information such as logging and database.
type Handler struct {
Runtime *env.Runtime
Store *store.Store
}
// Setup the tables in a blank database
func (h *Handler) Setup(w http.ResponseWriter, r *http.Request) {
defer func() {
target := "/setup"
status := http.StatusBadRequest
if h.Runtime.Flags.SiteMode == env.SiteModeNormal {
target = "/"
status = http.StatusOK
}
req, err := http.NewRequest("GET", target, nil)
if err != nil {
h.Runtime.Log.Error("database.Setup error in defer ", err)
}
http.Redirect(w, req, target, status)
}()
err := r.ParseForm()
if err != nil {
h.Runtime.Log.Error("database.Setup r.ParseForm()", err)
return
}
dbname := r.Form.Get("dbname")
dbhash := r.Form.Get("dbhash")
if dbname != web.SiteInfo.DBname || dbhash != web.SiteInfo.DBhash {
h.Runtime.Log.Error("database.Setup 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"),
ActivationKey: r.Form.Get("activationKey"),
Revised: time.Now().UTC(),
}
if details.Company == "" ||
details.CompanyLong == "" ||
details.Message == "" ||
details.Email == "" ||
details.Password == "" ||
details.Firstname == "" ||
details.Lastname == "" {
h.Runtime.Log.Error("database.Setup error ", errors.New("required field in database set-up form blank"))
return
}
if err = InstallUpgrade(h.Runtime, false); err != nil {
h.Runtime.Log.Error("database.Setup migrate", err)
return
}
err = setupAccount(h.Runtime, details, secrets.GenerateSalt())
if err != nil {
h.Runtime.Log.Error("database.Setup setup account ", err)
return
}
h.Runtime.Flags.SiteMode = env.SiteModeNormal
err = plugins.Setup(h.Store)
if err != nil {
h.Runtime.Log.Error("database.Setup plugin setup failed", err)
}
}
// 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
ActivationKey string
Revised time.Time
}
// setupAccount prepares the database for a newly onboard customer.
// Once done, they can then login and use Documize.
func setupAccount(rt *env.Runtime, completion onboardRequest, serial string) (err error) {
tx, err := rt.Db.Beginx()
if err != nil {
rt.Log.Error("setup - failed to get transaction", err)
return
}
salt := secrets.GenerateSalt()
password := secrets.GeneratePassword(completion.Password, salt)
// Process activation key if we have one.
activationKey := processActivationKey(rt, completion)
// Allocate organization to the user.
orgID := uniqueid.Generate()
_, err = tx.Exec(RebindParams("INSERT INTO dmz_org (c_refid, c_company, c_title, c_message, c_domain, c_email, c_serial, c_sub) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
rt.StoreProvider.Type()),
orgID, completion.Company, completion.CompanyLong, completion.Message, completion.URL, completion.Email, serial, activationKey)
if err != nil {
rt.Log.Error("INSERT INTO dmz_org failed", err)
rt.Rollback(tx)
return
}
// Create user.
userID := uniqueid.Generate()
_, err = tx.Exec(RebindParams("INSERT INTO dmz_user (c_refid, c_firstname, c_lastname, c_email, c_initials, c_salt, c_password, c_globaladmin) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", rt.StoreProvider.Type()),
userID, completion.Firstname, completion.Lastname, completion.Email, stringutil.MakeInitials(completion.Firstname, completion.Lastname), salt, password, true)
if err != nil {
rt.Log.Error("INSERT INTO dmz_user failed", err)
rt.Rollback(tx)
return
}
// Link user to organization.
accountID := uniqueid.Generate()
_, err = tx.Exec(RebindParams("INSERT INTO dmz_user_account (c_refid, c_userid, c_orgid, c_admin, c_editor, c_users, c_analytics) VALUES (?, ?, ?, ?, ?, ?, ?)", rt.StoreProvider.Type()),
accountID, userID, orgID, true, true, true, true)
if err != nil {
rt.Log.Error("INSERT INTO dmz_user_account failed", err)
rt.Rollback(tx)
return
}
// Finish up.
if err = tx.Commit(); err != nil {
rt.Log.Error("setup - unable to commit sql", err)
return
}
return
}
func processActivationKey(rt *env.Runtime, or onboardRequest) (key string) {
key = "{}"
if len(or.ActivationKey) == 0 {
return
}
j := domain.SubscriptionData{}
x := domain.SubscriptionXML{Key: "", Signature: ""}
err1 := xml.Unmarshal([]byte(or.ActivationKey), &x)
if err1 == nil {
j.Key = x.Key
j.Signature = x.Signature
} else {
rt.Log.Error("failed to XML unmarshal subscription XML", err1)
}
d, err2 := json.Marshal(j)
if err2 == nil {
key = string(d)
} else {
rt.Log.Error("failed to JSON marshal subscription XML", err2)
}
return
}

View file

@ -14,7 +14,7 @@
html {
-webkit-font-smoothing: antialiased;
}
body {
font-family: 'Open Sans', sans-serif;
background-color: #1b75bb;
@ -22,54 +22,54 @@
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;
@ -102,7 +102,7 @@
<body>
<div class="container">
<div class="logo">
<img src="/assets/img/setup/logo.png" alt="Documize Community">
<img src="/assets/img/setup/logo.png" alt="Documize">
</div>
<div class="content clearfix">
<div class="image">
@ -110,11 +110,11 @@
</div>
<div class="text">
<h1>Database Error</h1>
<p>There seems to be a problem with the Documize Community database: <strong>{{.DBname}}</strong></p>
<p>There seems to be a problem with the Documize database: <strong>{{.DBname}}</strong></p>
<p><em>{{.Issue}}</em></p>
</div>
</div>
</div>
</body>
</html>
</html>

File diff suppressed because one or more lines are too long

View file

@ -1,108 +0,0 @@
// 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 env provides runtime, server level setup and configuration
package env
import (
"flag"
"fmt"
"os"
"sort"
"strings"
"sync"
)
// prefix provides the prefix for all environment variables
const prefix = "DOCUMIZE"
const goInit = "(default)"
var flagList progFlags
var cliMutex sync.Mutex
type flagItem struct {
target *string
name, setter, value string
required bool
}
type progFlags struct {
items []flagItem
}
// Len is part of sort.Interface.
func (v *progFlags) Len() int {
return len(v.items)
}
// Swap is part of sort.Interface.
func (v *progFlags) Swap(i, j int) {
v.items[i], v.items[j] = v.items[j], v.items[i]
}
// Less is part of sort.Interface.
func (v *progFlags) Less(i, j int) bool {
return v.items[i].name < v.items[j].name
}
// register prepares flag for subsequent parsing
func register(target *string, name string, required bool, usage string) {
cliMutex.Lock()
defer cliMutex.Unlock()
name = strings.ToLower(strings.TrimSpace(name))
setter := prefix + strings.ToUpper(name)
value := os.Getenv(setter)
if value == "" {
value = *target // use the Go initialized value
setter = goInit
}
flag.StringVar(target, name, value, usage)
flagList.items = append(flagList.items, flagItem{target: target, name: name, required: required, value: value, setter: setter})
}
// parse loads flags from OS environment and command line switches
func parse(doFirst string) (ok bool) {
cliMutex.Lock()
defer cliMutex.Unlock()
flag.Parse()
sort.Sort(&flagList)
for pass := 1; pass <= 2; pass++ {
for vi, v := range flagList.items {
if (pass == 1 && v.name == doFirst) || (pass == 2 && v.name != doFirst) {
if v.value != *(v.target) || (v.value != "" && *(v.target) == "") {
flagList.items[vi].setter = "-" + v.name // v is a local copy, not the underlying data
}
if v.required {
if *(v.target) == "" {
fmt.Fprintln(os.Stderr)
fmt.Fprintln(os.Stderr, "In order to run", os.Args[0], "the following must be provided:")
for _, vv := range flagList.items {
if vv.required {
fmt.Fprintf(os.Stderr, "* setting from environment variable '%s' or flag '-%s' or an application setting '%s', current value: '%s' set by '%s'\n",
prefix+strings.ToUpper(vv.name), vv.name, vv.name, *(vv.target), vv.setter)
}
}
fmt.Fprintln(os.Stderr)
flag.Usage()
return false
}
}
}
}
}
return true
}

138
core/env/flags.go vendored
View file

@ -12,19 +12,25 @@
// Package env provides runtime, server level setup and configuration
package env
import (
"flag"
"fmt"
"os"
"sort"
"strings"
"sync"
)
// Flags provides access to environment and command line switches for this program.
type Flags struct {
DBType string // database type
DBConn string // database connection string
Salt string // the salt string used to encode JWT tokens
HTTPPort string // (optional) HTTP or HTTPS port
ForceHTTPPort2SSL string // (optional) HTTP that should be redirected to HTTPS
DBType string // (optional) database type
SSLCertFile string // (optional) name of SSL certificate PEM file
SSLKeyFile string // (optional) name of SSL key PEM file
TLSVersion string // (optional) minimum TLS version for SSL connections
HTTPPort string // (optional) HTTP or HTTPS port
ForceHTTPPort2SSL string // (optional) HTTP that should be redirected to HTTPS
SiteMode string // (optional) if 1 then serve offline web page
Location string // reserved
ConfigSource string // tells us if configuration info was obtained from command line or config file
}
// SSLEnabled returns true if both cert and key were provided at runtime.
@ -32,27 +38,113 @@ func (f *Flags) SSLEnabled() bool {
return f.SSLCertFile != "" && f.SSLKeyFile != ""
}
// ConfigToml represents configuration file that contains all flags as per above.
type ConfigToml struct {
HTTP httpConfig `toml:"http"`
Database databaseConfig `toml:"database"`
Install installConfig `toml:"install"`
type flagItem struct {
target *string
name, setter, value string
required bool
}
type httpConfig struct {
Port int
ForceSSLPort int
Cert string
Key string
TLSVersion string
type progFlags struct {
items []flagItem
}
type databaseConfig struct {
Type string
Connection string
Salt string
// Len is part of sort.Interface.
func (v *progFlags) Len() int {
return len(v.items)
}
type installConfig struct {
Location string
// Swap is part of sort.Interface.
func (v *progFlags) Swap(i, j int) {
v.items[i], v.items[j] = v.items[j], v.items[i]
}
// Less is part of sort.Interface.
func (v *progFlags) Less(i, j int) bool {
return v.items[i].name < v.items[j].name
}
// prefix provides the prefix for all environment variables
const prefix = "DOCUMIZE"
const goInit = "(default)"
var flagList progFlags
var loadMutex sync.Mutex
// ParseFlags loads command line and OS environment variables required by the program to function.
func ParseFlags() (f Flags) {
var dbConn, dbType, jwtKey, siteMode, port, certFile, keyFile, forcePort2SSL string
register(&jwtKey, "salt", false, "the salt string used to encode JWT tokens, if not set a random value will be generated")
register(&certFile, "cert", false, "the cert.pem file used for https")
register(&keyFile, "key", false, "the key.pem file used for https")
register(&port, "port", false, "http/https port number")
register(&forcePort2SSL, "forcesslport", false, "redirect given http port number to TLS")
register(&siteMode, "offline", false, "set to '1' for OFFLINE mode")
register(&dbType, "dbtype", false, "set to database type mysql|percona|mariadb")
register(&dbConn, "db", true, `'username:password@protocol(hostname:port)/databasename" for example "fred:bloggs@tcp(localhost:3306)/documize"`)
parse("db")
f.DBConn = dbConn
f.ForceHTTPPort2SSL = forcePort2SSL
f.HTTPPort = port
f.Salt = jwtKey
f.SiteMode = siteMode
f.SSLCertFile = certFile
f.SSLKeyFile = keyFile
f.DBType = dbType
return f
}
// register prepares flag for subsequent parsing
func register(target *string, name string, required bool, usage string) {
loadMutex.Lock()
defer loadMutex.Unlock()
name = strings.ToLower(strings.TrimSpace(name))
setter := prefix + strings.ToUpper(name)
value := os.Getenv(setter)
if value == "" {
value = *target // use the Go initialized value
setter = goInit
}
flag.StringVar(target, name, value, usage)
flagList.items = append(flagList.items, flagItem{target: target, name: name, required: required, value: value, setter: setter})
}
// parse loads flags from OS environment and command line switches
func parse(doFirst string) {
loadMutex.Lock()
defer loadMutex.Unlock()
flag.Parse()
sort.Sort(&flagList)
for pass := 1; pass <= 2; pass++ {
for vi, v := range flagList.items {
if (pass == 1 && v.name == doFirst) || (pass == 2 && v.name != doFirst) {
if v.value != *(v.target) || (v.value != "" && *(v.target) == "") {
flagList.items[vi].setter = "-" + v.name // v is a local copy, not the underlying data
}
if v.required {
if *(v.target) == "" {
fmt.Fprintln(os.Stderr)
fmt.Fprintln(os.Stderr, "In order to run", os.Args[0], "the following must be provided:")
for _, vv := range flagList.items {
if vv.required {
fmt.Fprintf(os.Stderr, "* setting from environment variable '%s' or flag '-%s' or an application setting '%s', current value: '%s' set by '%s'\n",
prefix+strings.ToUpper(vv.name), vv.name, vv.name, *(vv.target), vv.setter)
}
}
fmt.Fprintln(os.Stderr)
flag.Usage()
return
}
}
}
}
}
}

1
core/env/logger.go vendored
View file

@ -15,7 +15,6 @@ 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

145
core/env/parser.go vendored
View file

@ -1,145 +0,0 @@
// 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 env provides runtime, server level setup and configuration
package env
import (
"fmt"
"os"
"strconv"
"strings"
"github.com/BurntSushi/toml"
)
// LoadConfig loads runtime parameters like port numbers and DB connections.
// We first check for -config switch that would point us towards a .CONF file.
// If not found, we then read parameters from command line and environment vars.
func LoadConfig() (f Flags, ok bool) {
// Check and process config file
f, ok = configFile()
// If not OK then get parameters from command line and environment variables.
if !ok {
f, ok = commandLineEnv()
}
// reserved
if len(f.Location) == 0 {
f.Location = "selfhost"
}
return
}
// configFile checks for the presence of zero or one command argument.
// If no arguments are provided then we look for and load documize.conf file.
// If one argument is provided then we load the specified config file.
// If more than one argument is provided then we exit as flags as have passed.
// checks to see if it is a TOML format config file.
func configFile() (f Flags, ok bool) {
ok = false
var configFile string
// First argument is always program being executed.
// No additional arguments means check for documize.conf file.
if len(os.Args) == 1 {
// No arguments, so we default to default config filename.
configFile = "documize.conf"
} else if len(os.Args) == 2 {
// Config filename passed in, so we use it.
configFile = os.Args[1]
} else {
// Too many arguments means flags passed in so we return.
return
}
// Does file exist?
if len(configFile) == 0 || !configFileExists(configFile) {
return
}
// Tell caller where the config came from.
f.ConfigSource = configFile
// We parse the TOML format config file.
var ct ConfigToml
if _, err := toml.DecodeFile(configFile, &ct); err != nil {
fmt.Println(err)
return
}
f.DBType = strings.ToLower(ct.Database.Type)
f.DBConn = ct.Database.Connection
f.Salt = ct.Database.Salt
f.HTTPPort = strconv.Itoa(ct.HTTP.Port)
f.ForceHTTPPort2SSL = strconv.Itoa(ct.HTTP.ForceSSLPort)
f.SSLCertFile = ct.HTTP.Cert
f.SSLKeyFile = ct.HTTP.Key
f.TLSVersion = ct.HTTP.TLSVersion
f.Location = strings.ToLower(ct.Install.Location)
if len(f.TLSVersion) == 0 {
f.TLSVersion = "1.3"
}
ok = true
return
}
// commandLineEnv loads command line and OS environment variables required by the program to function.
func commandLineEnv() (f Flags, ok bool) {
ok = true
var dbConn, dbType, jwtKey, siteMode, port, certFile, keyFile, forcePort2SSL, TLSVersion, location string
// register(&configFile, "salt", false, "the salt string used to encode JWT tokens, if not set a random value will be generated")
register(&jwtKey, "salt", false, "the salt string used to encode JWT tokens, if not set a random value will be generated")
register(&certFile, "cert", false, "the cert.pem file used for https")
register(&keyFile, "key", false, "the key.pem file used for https")
register(&port, "port", false, "http/https port number")
register(&forcePort2SSL, "forcesslport", false, "redirect given http port number to TLS")
register(&TLSVersion, "tlsversion", false, "select minimum TLS: 1.0, 1.1, 1.2, 1.3")
register(&siteMode, "offline", false, "set to '1' for OFFLINE mode")
register(&dbType, "dbtype", true, "specify the database provider: mysql|percona|mariadb|postgresql|sqlserver")
register(&dbConn, "db", true, `'database specific connection string for example "user:password@tcp(localhost:3306)/dbname"`)
register(&location, "location", false, `reserved`)
if !parse("db") {
ok = false
}
f.DBType = strings.ToLower(dbType)
f.DBConn = dbConn
f.ForceHTTPPort2SSL = forcePort2SSL
f.HTTPPort = port
f.Salt = jwtKey
f.SiteMode = siteMode
f.SSLCertFile = certFile
f.SSLKeyFile = keyFile
f.TLSVersion = TLSVersion
f.Location = strings.ToLower(location)
f.ConfigSource = "flags/environment"
if len(f.TLSVersion) == 0 {
f.TLSVersion = "1.3"
}
return f, ok
}
func configFileExists(fn string) bool {
info, err := os.Stat(fn)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}

70
core/env/product.go vendored Normal file
View file

@ -0,0 +1,70 @@
// 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 env
import (
"fmt"
"time"
)
// ProdInfo describes a product
type ProdInfo struct {
Edition string
Title string
Version string
Major string
Minor string
Patch string
License License
}
// License holds details of product license.
type License struct {
Name string `json:"name"`
Email string `json:"email"`
Edition string `json:"edition"`
Start time.Time `json:"start"`
End time.Time `json:"end"`
Seats int `json:"seats"`
Trial bool `json:"trial"`
Valid bool
}
// IsEmpty determines if we have a license.
func (l *License) IsEmpty() bool {
return l.Seats == 0 && len(l.Name) == 0 && len(l.Email) == 0 && l.Start.Year() == 1 && l.End.Year() == 1
}
// Status returns formatted message stating if license is empty/populated and invalid/valid.
func (l *License) Status() string {
lp := "populated"
if l.IsEmpty() {
lp = "empty"
}
lv := "invalid"
if l.Valid {
lv = "valid"
}
return fmt.Sprintf("License is %s and %s", lp, lv)
}
// IsValid returns if license is valid
func (l *License) IsValid() bool {
return l.Valid == true
}
// LicenseData holds encrypted data and is unpacked into License.
type LicenseData struct {
Key string `json:"key"`
Signature string `json:"signature"`
}

117
core/env/provider.go vendored
View file

@ -1,117 +0,0 @@
// 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 env provides runtime, server level setup and configuration
package env
// StoreType represents name of database system
type StoreType string
const (
// StoreTypeMySQL is MySQL
StoreTypeMySQL StoreType = "MySQL"
// StoreTypePercona is Percona
StoreTypePercona StoreType = "Percona"
// StoreTypeMariaDB is MariaDB
StoreTypeMariaDB StoreType = "MariaDB"
// StoreTypePostgreSQL is PostgreSQL
StoreTypePostgreSQL StoreType = "PostgreSQL"
// StoreTypeSQLServer is Microsoft SQL Server
StoreTypeSQLServer StoreType = "SQLServer"
)
// StoreProvider defines a database provider.
type StoreProvider interface {
// Name of provider
Type() StoreType
// TypeVariant returns flavor of database provider.
TypeVariant() StoreType
// SQL driver name used to open DB connection.
DriverName() string
// Database connection string parameters that must be present before connecting to DB.
Params() map[string]string
// Example holds storage provider specific connection string format.
// used in error messages
Example() string
// DatabaseName holds the SQL database name where Documize tables live.
DatabaseName() string
// Make connection string with default parameters.
MakeConnectionString() string
// QueryMeta is how to extract version number, collation, character set from database provider.
QueryMeta() string
// QueryRecordVersionUpgrade returns database specific insert statement
// that records the database version number.
QueryRecordVersionUpgrade(version int) string
// QueryRecordVersionUpgrade returns database specific insert statement
// that records the database version number.
// For use on databases before The Great Schema Migration (v25, MySQL).
QueryRecordVersionUpgradeLegacy(version int) string
// QueryGetDatabaseVersion returns the schema version number.
QueryGetDatabaseVersion() string
// QueryGetDatabaseVersionLegacy returns the schema version number before The Great Schema Migration (v25, MySQL).
QueryGetDatabaseVersionLegacy() string
// QueryTableList returns a list tables in Documize database.
QueryTableList() string
// QueryDateInterval returns provider specific
// interval style date SQL.
QueryDateInterval(days int64) string
// JSONEmpty returns empty SQL JSON object.
// Typically used as 2nd parameter to COALESCE().
JSONEmpty() string
// JSONGetValue returns JSON attribute selection syntax.
// Typically used in SELECT <my_json_field> query.
JSONGetValue(column, attribute string) string
// VerfiyVersion checks to see if actual database meets
// minimum version requirements.
VerfiyVersion(dbVersion string) (versionOK bool, minVerRequired string)
// VerfiyCharacterCollation checks to see if actual database
// has correct character set and collation settings.
VerfiyCharacterCollation(charset, collation string) (charOK bool, requirements string)
// ConvertTimestamp returns SQL function to correctly convert
// ISO 8601 format (e.g. '2016-09-08T06:37:23Z') to SQL specific
// timestamp value (e.g. 2016-09-08 06:37:23).
// Must use ? for parameter placeholder character as DB layer
// will convert to database specific parameter placeholder character.
ConvertTimestamp() (statement string)
// IsTrue returns storage provider boolean TRUE:
// MySQL is 1, PostgresSQL is TRUE, SQL Server is 1
IsTrue() string
// IsFalse returns storage provider boolean FALSE:
// MySQL is 0, PostgresSQL is FALSE, SQL Server is 0
IsFalse() string
// RowLimit returns SQL for limited number of returned rows
RowLimit(max int) string
}

94
core/env/runtime.go vendored
View file

@ -12,70 +12,48 @@
// Package env provides runtime, server level setup and configuration
package env
import (
"context"
"database/sql"
"embed"
"github.com/documize/community/domain"
"github.com/jmoiron/sqlx"
)
const (
// SiteModeNormal serves app
SiteModeNormal = ""
// SiteModeOffline serves offline.html
SiteModeOffline = "1"
// SiteModeSetup tells Ember to serve setup route
SiteModeSetup = "2"
// SiteModeBadDB redirects to db-error.html page
SiteModeBadDB = "3"
)
import "github.com/jmoiron/sqlx"
// Runtime provides access to database, logger and other server-level scoped objects.
// Use Context for per-request values.
type Runtime struct {
Flags Flags
Db *sqlx.DB
StoreProvider StoreProvider
Log Logger
Product domain.Product
Assets embed.FS
Flags Flags
Db *sqlx.DB
DbVariant DbVariant
Log Logger
Product ProdInfo
}
// StartTx begins database transaction with given transaction isolation level.
// Any error encountered during this operation is logged to runtime logger.
func (r *Runtime) StartTx(i sql.IsolationLevel) (tx *sqlx.Tx, ok bool) {
tx, err := r.Db.BeginTxx(context.Background(), &sql.TxOptions{Isolation: i})
if err != nil {
r.Log.Error("unable to start database transaction", err)
return nil, false
}
const (
// SiteModeNormal serves app
SiteModeNormal = ""
// SiteModeOffline serves offline.html
SiteModeOffline = "1"
// SiteModeSetup tells Ember to serve setup route
SiteModeSetup = "2"
// SiteModeBadDB redirects to db-error.html page
SiteModeBadDB = "3"
)
return tx, true
}
// DbVariant details SQL database variant
type DbVariant string
// Rollback aborts active database transaction.
// Any error encountered during this operation is logged to runtime logger.
func (r *Runtime) Rollback(tx *sqlx.Tx) bool {
if err := tx.Commit(); err != nil {
r.Log.Error("unable to commit database transaction", err)
return false
}
const (
// DbVariantMySQL is MySQL
DbVariantMySQL DbVariant = "MySQL"
// DBVariantPercona is Percona
DBVariantPercona DbVariant = "Percona"
// DBVariantMariaDB is MariaDB
DBVariantMariaDB DbVariant = "MariaDB"
// DBVariantMSSQL is Microsoft SQL Server
DBVariantMSSQL DbVariant = "MSSQL"
// DBVariantPostgreSQL is PostgreSQL
DBVariantPostgreSQL DbVariant = "PostgreSQL"
)
return true
}
// Commit flushes pending changes to database.
// Any error encountered during this operation is logged to runtime logger.
func (r *Runtime) Commit(tx *sqlx.Tx) bool {
if err := tx.Commit(); err != nil {
r.Log.Error("unable to commit database transaction", err)
return false
}
return true
}
const (
// CommunityEdition is AGPL product variant
CommunityEdition = "Community"
// EnterpriseEdition is commercial licensed product variant
EnterpriseEdition = "Enterprise"
)

View file

@ -1,91 +0,0 @@
package i18n
import (
"embed"
"encoding/json"
"fmt"
"strings"
"github.com/documize/community/core/asset"
"github.com/pkg/errors"
)
const (
DefaultLocale = "en-US"
)
var localeMap map[string]map[string]string
// SupportedLocales returns array of locales.
func SupportedLocales() (locales []string) {
locales = append(locales, "en-US")
locales = append(locales, "de-DE")
locales = append(locales, "zh-CN")
locales = append(locales, "pt-BR")
locales = append(locales, "fr-FR")
locales = append(locales, "ja-JP")
locales = append(locales, "it-IT")
locales = append(locales, "es-AR")
return
}
// Intialize will load language files
func Initialize(e embed.FS) (err error) {
localeMap = make(map[string]map[string]string)
locales := SupportedLocales()
for i := range locales {
content, _, err := asset.FetchStatic(e, "i18n/"+locales[i]+".json")
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("missing locale %s", locales[i]))
return err
}
var payload interface{}
json.Unmarshal([]byte(content), &payload)
m := payload.(map[string]interface{})
translations := make(map[string]string)
for j := range m {
translations[j] = m[j].(string)
}
localeMap[locales[i]] = translations
}
return nil
}
// Localize will returns string value for given key using specified locale).
// e.g. locale = "en-US", key = "admin_billing"
//
// Replacements are for replacing string placeholders ({1} {2} {3}) with
// replacement text.
// e.g. "This is {1} example" --> replacements[0] will replace {1}
func Localize(locale string, key string, replacements ...string) (s string) {
l, ok := localeMap[locale]
if !ok {
// fallback
l = localeMap[DefaultLocale]
}
s, ok = l[key]
if !ok {
// missing translation key is echo'ed back
s = fmt.Sprintf("!! %s !!", key)
}
// placeholders are one-based: {1} {2} {3}
// replacements array is zero-based hence the +1 below
if len(replacements) > 0 {
for i := range replacements {
s = strings.Replace(s, fmt.Sprintf("{%d}", i+1), replacements[i], 1)
}
}
return
}

View file

@ -14,9 +14,10 @@ package osutil
import (
"bytes"
"errors"
"fmt"
"os/exec"
"time"
"github.com/documize/community/core/log"
)
var errTimeout = errors.New("conversion timelimit exceeded")
@ -38,7 +39,7 @@ func CommandWithTimeout(command *exec.Cmd, timeout time.Duration) ([]byte, error
select {
case <-time.After(timeout):
if err := command.Process.Kill(); err != nil {
fmt.Printf("failed to kill: %s", err.Error())
log.Error("failed to kill: ", err)
}
<-done // prevent memory leak
//fmt.Println("DEBUG timeout")

View file

@ -1,29 +0,0 @@
// 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 request provides HTTP request parsing functions.
package request
import (
"net/http"
"strings"
)
// IsSSL returns true if Referer header contains "https".
// If Referer header is empty we look at r.TLS setting.
func IsSSL(r *http.Request) bool {
rf := r.Referer()
if len(rf) > 1 {
return strings.HasPrefix(rf, "https")
}
return r.TLS != nil
}

Some files were not shown because too many files have changed in this diff Show more