mirror of
https://github.com/documize/community.git
synced 2025-07-25 16:19:46 +02:00
commit
7cc0b9c9b8
847 changed files with 47330 additions and 43756 deletions
14
README.md
14
README.md
|
@ -48,19 +48,13 @@ Integrations for embedding SaaS data within documents, zero add-on/marketplace f
|
||||||
|
|
||||||
## What does it look like?
|
## What does it look like?
|
||||||
|
|
||||||
All spaces.
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Space view.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Latest Release
|
## Latest Release
|
||||||
|
|
||||||
[Community Edition: v1.76.2](https://github.com/documize/community/releases)
|
[Community Edition: v2.0.0](https://github.com/documize/community/releases)
|
||||||
|
|
||||||
[Enterprise Edition: v1.76.2](https://documize.com/downloads)
|
[Enterprise Edition: v2.0.0](https://documize.com/downloads)
|
||||||
|
|
||||||
## OS support
|
## OS support
|
||||||
|
|
||||||
|
@ -99,8 +93,8 @@ Documize supports the following (evergreen) browsers:
|
||||||
|
|
||||||
Documize is built with the following technologies:
|
Documize is built with the following technologies:
|
||||||
|
|
||||||
- EmberJS (v3.1.2)
|
- EmberJS (v3.5.1)
|
||||||
- Go (v1.11.2)
|
- Go (v1.11.4)
|
||||||
|
|
||||||
## Authentication Options
|
## Authentication Options
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,15 @@ call ember b -o dist-prod/ --environment=production
|
||||||
|
|
||||||
echo "Copying Ember assets..."
|
echo "Copying Ember assets..."
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
rd /s /q embed\bindata\public
|
rd /s /q embed\bindata\public
|
||||||
mkdir embed\bindata\public
|
mkdir embed\bindata\public
|
||||||
echo "Copying Ember assets folder"
|
echo "Copying Ember assets folder"
|
||||||
robocopy /e /NFL /NDL /NJH gui\dist-prod\assets embed\bindata\public\assets
|
robocopy /e /NFL /NDL /NJH gui\dist-prod\assets embed\bindata\public\assets
|
||||||
echo "Copying Ember codemirror folder"
|
echo "Copying Ember codemirror folder"
|
||||||
robocopy /e /NFL /NDL /NJH gui\dist-prod\codemirror embed\bindata\public\codemirror
|
robocopy /e /NFL /NDL /NJH gui\dist-prod\codemirror embed\bindata\public\codemirror
|
||||||
|
echo "Copying Ember prism folder"
|
||||||
|
robocopy /e /NFL /NDL /NJH gui\dist-prod\prism embed\bindata\public\prism
|
||||||
echo "Copying Ember tinymce folder"
|
echo "Copying Ember tinymce folder"
|
||||||
robocopy /e /NFL /NDL /NJH gui\dist-prod\tinymce embed\bindata\public\tinymce
|
robocopy /e /NFL /NDL /NJH gui\dist-prod\tinymce embed\bindata\public\tinymce
|
||||||
echo "Copying Ember sections folder"
|
echo "Copying Ember sections folder"
|
||||||
|
|
9
build.sh
9
build.sh
|
@ -8,23 +8,26 @@ echo "Build process started $NOW"
|
||||||
|
|
||||||
echo "Building Ember assets..."
|
echo "Building Ember assets..."
|
||||||
cd gui
|
cd gui
|
||||||
ember b -o dist-prod/ --environment=production
|
ember build ---environment=production --output-path dist-prod --suppress-sizes true
|
||||||
|
cd ..
|
||||||
|
|
||||||
echo "Copying Ember assets..."
|
echo "Copying Ember assets..."
|
||||||
cd ..
|
|
||||||
rm -rf embed/bindata/public
|
rm -rf embed/bindata/public
|
||||||
mkdir -p embed/bindata/public
|
mkdir -p embed/bindata/public
|
||||||
cp -r gui/dist-prod/assets 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/codemirror embed/bindata/public/codemirror
|
||||||
cp -r gui/dist-prod/tinymce embed/bindata/public/tinymce
|
cp -r gui/dist-prod/prism embed/bindata/public/prism
|
||||||
cp -r gui/dist-prod/sections embed/bindata/public/sections
|
cp -r gui/dist-prod/sections embed/bindata/public/sections
|
||||||
|
cp -r gui/dist-prod/tinymce embed/bindata/public/tinymce
|
||||||
cp gui/dist-prod/*.* embed/bindata
|
cp gui/dist-prod/*.* embed/bindata
|
||||||
cp gui/dist-prod/favicon.ico embed/bindata/public
|
cp gui/dist-prod/favicon.ico embed/bindata/public
|
||||||
cp gui/dist-prod/manifest.json embed/bindata/public
|
cp gui/dist-prod/manifest.json embed/bindata/public
|
||||||
|
|
||||||
rm -rf embed/bindata/mail
|
rm -rf embed/bindata/mail
|
||||||
mkdir -p embed/bindata/mail
|
mkdir -p embed/bindata/mail
|
||||||
cp domain/mail/*.html embed/bindata/mail
|
cp domain/mail/*.html embed/bindata/mail
|
||||||
cp core/database/templates/*.html embed/bindata
|
cp core/database/templates/*.html embed/bindata
|
||||||
|
|
||||||
rm -rf embed/bindata/scripts
|
rm -rf embed/bindata/scripts
|
||||||
mkdir -p embed/bindata/scripts
|
mkdir -p embed/bindata/scripts
|
||||||
mkdir -p embed/bindata/scripts/mysql
|
mkdir -p embed/bindata/scripts/mysql
|
||||||
|
|
37
core/database/scripts/mysql/db_00027.sql
Normal file
37
core/database/scripts/mysql/db_00027.sql
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/* 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
|
36
core/database/scripts/postgresql/db_00003.sql
Normal file
36
core/database/scripts/postgresql/db_00003.sql
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/* 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 labelling, 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
|
|
@ -14,10 +14,9 @@ package osutil
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/documize/community/core/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var errTimeout = errors.New("conversion timelimit exceeded")
|
var errTimeout = errors.New("conversion timelimit exceeded")
|
||||||
|
@ -39,7 +38,7 @@ func CommandWithTimeout(command *exec.Cmd, timeout time.Duration) ([]byte, error
|
||||||
select {
|
select {
|
||||||
case <-time.After(timeout):
|
case <-time.After(timeout):
|
||||||
if err := command.Process.Kill(); err != nil {
|
if err := command.Process.Kill(); err != nil {
|
||||||
log.Error("failed to kill: ", err)
|
fmt.Errorf("failed to kill: ", err)
|
||||||
}
|
}
|
||||||
<-done // prevent memory leak
|
<-done // prevent memory leak
|
||||||
//fmt.Println("DEBUG timeout")
|
//fmt.Println("DEBUG timeout")
|
||||||
|
|
|
@ -15,9 +15,12 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/documize/community/domain/auth"
|
||||||
|
"github.com/documize/community/model/space"
|
||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/documize/community/core/env"
|
"github.com/documize/community/core/env"
|
||||||
"github.com/documize/community/core/request"
|
"github.com/documize/community/core/request"
|
||||||
|
@ -47,9 +50,22 @@ func (h *Handler) Download(w http.ResponseWriter, r *http.Request) {
|
||||||
method := "attachment.Download"
|
method := "attachment.Download"
|
||||||
ctx := domain.GetRequestContext(r)
|
ctx := domain.GetRequestContext(r)
|
||||||
ctx.Subdomain = organization.GetSubdomainFromHost(r)
|
ctx.Subdomain = organization.GetSubdomainFromHost(r)
|
||||||
|
ctx.OrgID = request.Param(r, "orgID")
|
||||||
|
|
||||||
a, err := h.Store.Attachment.GetAttachment(ctx, request.Param(r, "orgID"), request.Param(r, "attachmentID"))
|
// Is caller permitted to download this attachment?
|
||||||
|
canDownload := false
|
||||||
|
|
||||||
|
// Do e have user authentication token?
|
||||||
|
authToken := strings.TrimSpace(request.Query(r, "token"))
|
||||||
|
|
||||||
|
// Do we have secure sharing token (for external users)?
|
||||||
|
secureToken := strings.TrimSpace(request.Query(r, "secure"))
|
||||||
|
|
||||||
|
// We now fetch attachment, the document and space it lives inside.
|
||||||
|
// Any data loading issue spells the end of this request.
|
||||||
|
|
||||||
|
// Get attachment being requested.
|
||||||
|
a, err := h.Store.Attachment.GetAttachment(ctx, ctx.OrgID, request.Param(r, "attachmentID"))
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
response.WriteNotFoundError(w, method, request.Param(r, "fileID"))
|
response.WriteNotFoundError(w, method, request.Param(r, "fileID"))
|
||||||
return
|
return
|
||||||
|
@ -60,6 +76,99 @@ func (h *Handler) Download(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the document for this attachment
|
||||||
|
doc, err := h.Store.Document.Get(ctx, a.DocumentID)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
response.WriteNotFoundError(w, method, a.DocumentID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
h.Runtime.Log.Error("get attachment document", err)
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the space for this attachment
|
||||||
|
sp, err := h.Store.Space.Get(ctx, doc.SpaceID)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
response.WriteNotFoundError(w, method, a.DocumentID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
h.Runtime.Log.Error("get attachment document", err)
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the organization for this request
|
||||||
|
// Get the space for this attachment
|
||||||
|
org, err := h.Store.Organization.GetOrganization(ctx, ctx.OrgID)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
response.WriteNotFoundError(w, method, a.DocumentID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
h.Runtime.Log.Error("get attachment org", err)
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point, all data associated data is loaded.
|
||||||
|
// We now begin security checks based upon the request.
|
||||||
|
|
||||||
|
// If attachment is in public space then anyone can download
|
||||||
|
if org.AllowAnonymousAccess && sp.Type == space.ScopePublic {
|
||||||
|
canDownload = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// External users can be sent secure document viewing links.
|
||||||
|
// Those documents may contain attachments that external viewers
|
||||||
|
// can download as required.
|
||||||
|
// Such secure document viewing links can have expiry dates.
|
||||||
|
if !canDownload && len(secureToken) > 0 {
|
||||||
|
canDownload = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an user authentication token was provided we check to see
|
||||||
|
// if user can view document.
|
||||||
|
// This check only applies to attachments NOT in public spaces.
|
||||||
|
if !canDownload && len(authToken) > 0 {
|
||||||
|
// Decode and check incoming token.
|
||||||
|
creds, _, err := auth.DecodeJWT(h.Runtime, authToken)
|
||||||
|
if err != nil {
|
||||||
|
h.Runtime.Log.Error("get attachment decode auth token", err)
|
||||||
|
response.WriteForbiddenError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Check for tampering.
|
||||||
|
if ctx.OrgID != creds.OrgID {
|
||||||
|
h.Runtime.Log.Error("get attachment org ID mismatch", err)
|
||||||
|
response.WriteForbiddenError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use token-based user ID for subsequent processing.
|
||||||
|
ctx.UserID = creds.UserID
|
||||||
|
|
||||||
|
// Check to see if user can view BOTH space and document.
|
||||||
|
if !permission.CanViewSpace(ctx, *h.Store, sp.RefID) || !permission.CanViewDocument(ctx, *h.Store, a.DocumentID) {
|
||||||
|
h.Runtime.Log.Error("get attachment cannot view document", err)
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authenticated user can view attachment.
|
||||||
|
canDownload = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send back error if caller unable view attachment
|
||||||
|
if !canDownload {
|
||||||
|
h.Runtime.Log.Error("get attachment refused", err)
|
||||||
|
response.WriteForbiddenError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point, user can view attachment so we send it back!
|
||||||
typ := mime.TypeByExtension("." + a.Extension)
|
typ := mime.TypeByExtension("." + a.Extension)
|
||||||
if typ == "" {
|
if typ == "" {
|
||||||
typ = "application/octet-stream"
|
typ = "application/octet-stream"
|
||||||
|
|
|
@ -46,7 +46,6 @@ import (
|
||||||
"github.com/documize/community/model/doc"
|
"github.com/documize/community/model/doc"
|
||||||
"github.com/documize/community/model/group"
|
"github.com/documize/community/model/group"
|
||||||
"github.com/documize/community/model/link"
|
"github.com/documize/community/model/link"
|
||||||
"github.com/documize/community/model/org"
|
|
||||||
"github.com/documize/community/model/page"
|
"github.com/documize/community/model/page"
|
||||||
"github.com/documize/community/model/permission"
|
"github.com/documize/community/model/permission"
|
||||||
"github.com/documize/community/model/pin"
|
"github.com/documize/community/model/pin"
|
||||||
|
@ -231,14 +230,14 @@ func (b backerHandler) dmzOrg(files *[]backupItem) (err error) {
|
||||||
w = fmt.Sprintf(" WHERE c_refid='%s' ", b.Spec.OrgID)
|
w = fmt.Sprintf(" WHERE c_refid='%s' ", b.Spec.OrgID)
|
||||||
}
|
}
|
||||||
|
|
||||||
o := []org.Organization{}
|
o := []orgExtended{}
|
||||||
err = b.Runtime.Db.Select(&o, `SELECT id, c_refid AS refid,
|
err = b.Runtime.Db.Select(&o, `SELECT id, c_refid AS refid,
|
||||||
c_title AS title, c_message AS message, c_domain AS domain,
|
c_title AS title, c_message AS message, c_domain AS domain,
|
||||||
c_service AS conversionendpoint, c_email AS email, c_serial AS serial, c_active AS active,
|
c_service AS conversionendpoint, c_email AS email, c_serial AS serial, c_active AS active,
|
||||||
c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider,
|
c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider,
|
||||||
coalesce(c_sub,`+b.Runtime.StoreProvider.JSONEmpty()+`) AS subscription,
|
coalesce(c_sub,`+b.Runtime.StoreProvider.JSONEmpty()+`) AS subscription,
|
||||||
coalesce(c_authconfig,`+b.Runtime.StoreProvider.JSONEmpty()+`) AS authconfig, c_maxtags AS maxtags,
|
coalesce(c_authconfig,`+b.Runtime.StoreProvider.JSONEmpty()+`) AS authconfig, c_maxtags AS maxtags,
|
||||||
c_created AS created, c_revised AS revised
|
c_theme AS theme, c_logo AS logo, c_created AS created, c_revised AS revised
|
||||||
FROM dmz_org`+w)
|
FROM dmz_org`+w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -255,10 +254,6 @@ func (b backerHandler) dmzOrg(files *[]backupItem) (err error) {
|
||||||
|
|
||||||
// Config, User Config.
|
// Config, User Config.
|
||||||
func (b backerHandler) dmzConfig(files *[]backupItem) (err error) {
|
func (b backerHandler) dmzConfig(files *[]backupItem) (err error) {
|
||||||
type config struct {
|
|
||||||
ConfigKey string `json:"key"`
|
|
||||||
ConfigValue string `json:"config"`
|
|
||||||
}
|
|
||||||
c := []config{}
|
c := []config{}
|
||||||
err = b.Runtime.Db.Select(&c, `SELECT c_key AS configkey, c_config AS configvalue FROM dmz_config`)
|
err = b.Runtime.Db.Select(&c, `SELECT c_key AS configkey, c_config AS configvalue FROM dmz_config`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -279,14 +274,7 @@ func (b backerHandler) dmzConfig(files *[]backupItem) (err error) {
|
||||||
w = fmt.Sprintf(" where c_orgid='%s' ", b.Spec.OrgID)
|
w = fmt.Sprintf(" where c_orgid='%s' ", b.Spec.OrgID)
|
||||||
}
|
}
|
||||||
|
|
||||||
type userConfig struct {
|
|
||||||
OrgID string `json:"orgId"`
|
|
||||||
UserID string `json:"userId"`
|
|
||||||
ConfigKey string `json:"key"`
|
|
||||||
ConfigValue string `json:"config"`
|
|
||||||
}
|
|
||||||
uc := []userConfig{}
|
uc := []userConfig{}
|
||||||
|
|
||||||
err = b.Runtime.Db.Select(&uc, `select c_orgid AS orgid, c_userid AS userid,
|
err = b.Runtime.Db.Select(&uc, `select c_orgid AS orgid, c_userid AS userid,
|
||||||
c_key AS configkey, c_config AS configvalue FROM dmz_user_config`+w)
|
c_key AS configkey, c_config AS configvalue FROM dmz_user_config`+w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -475,6 +463,8 @@ func (b backerHandler) dmzSpace(files *[]backupItem) (err error) {
|
||||||
err = b.Runtime.Db.Select(&sp, `SELECT id, c_refid AS refid,
|
err = b.Runtime.Db.Select(&sp, `SELECT id, c_refid AS refid,
|
||||||
c_name AS name, c_orgid AS orgid, c_userid AS userid,
|
c_name AS name, c_orgid AS orgid, c_userid AS userid,
|
||||||
c_type AS type, c_lifecycle AS lifecycle, c_likes AS likes,
|
c_type AS type, c_lifecycle AS lifecycle, c_likes AS likes,
|
||||||
|
c_icon AS icon, c_labelid AS labelid, c_desc AS description,
|
||||||
|
c_count_category As countcategory, c_count_content AS countcontent,
|
||||||
c_created AS created, c_revised AS revised
|
c_created AS created, c_revised AS revised
|
||||||
FROM dmz_space`+w)
|
FROM dmz_space`+w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -671,16 +661,6 @@ func (b backerHandler) dmzDocument(files *[]backupItem) (err error) {
|
||||||
*files = append(*files, backupItem{Filename: "dmz_doc.json", Content: content})
|
*files = append(*files, backupItem{Filename: "dmz_doc.json", Content: content})
|
||||||
|
|
||||||
// Vote
|
// Vote
|
||||||
type vote struct {
|
|
||||||
RefID string `json:"refId"`
|
|
||||||
OrgID string `json:"orgId"`
|
|
||||||
DocumentID string `json:"documentId"`
|
|
||||||
VoterID string `json:"voterId"`
|
|
||||||
Vote int `json:"vote"`
|
|
||||||
Created time.Time `json:"created"`
|
|
||||||
Revised time.Time `json:"revised"`
|
|
||||||
}
|
|
||||||
|
|
||||||
vt := []vote{}
|
vt := []vote{}
|
||||||
err = b.Runtime.Db.Select(&vt, `
|
err = b.Runtime.Db.Select(&vt, `
|
||||||
SELECT c_refid AS refid, c_orgid AS orgid,
|
SELECT c_refid AS refid, c_orgid AS orgid,
|
||||||
|
@ -716,16 +696,6 @@ func (b backerHandler) dmzDocument(files *[]backupItem) (err error) {
|
||||||
*files = append(*files, backupItem{Filename: "dmz_doc_link.json", Content: content})
|
*files = append(*files, backupItem{Filename: "dmz_doc_link.json", Content: content})
|
||||||
|
|
||||||
// Comment
|
// Comment
|
||||||
type comment struct {
|
|
||||||
RefID string `json:"feedbackId"`
|
|
||||||
OrgID string `json:"orgId"`
|
|
||||||
DocumentID string `json:"documentId"`
|
|
||||||
UserID string `json:"userId"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
Feedback string `json:"feedback"`
|
|
||||||
Created time.Time `json:"created"`
|
|
||||||
}
|
|
||||||
|
|
||||||
cm := []comment{}
|
cm := []comment{}
|
||||||
err = b.Runtime.Db.Select(&cm, `
|
err = b.Runtime.Db.Select(&cm, `
|
||||||
SELECT c_refid AS refid, c_orgid AS orgid, c_docid AS documentid,
|
SELECT c_refid AS refid, c_orgid AS orgid, c_docid AS documentid,
|
||||||
|
@ -743,20 +713,6 @@ func (b backerHandler) dmzDocument(files *[]backupItem) (err error) {
|
||||||
*files = append(*files, backupItem{Filename: "dmz_doc_comment.json", Content: content})
|
*files = append(*files, backupItem{Filename: "dmz_doc_comment.json", Content: content})
|
||||||
|
|
||||||
// Share
|
// Share
|
||||||
type share struct {
|
|
||||||
ID uint64 `json:"id"`
|
|
||||||
OrgID string `json:"orgId"`
|
|
||||||
UserID string `json:"userId"`
|
|
||||||
DocumentID string `json:"documentId"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
Viewed string `json:"viewed"` // recording each view as |date-viewed|date-viewed|
|
|
||||||
Secret string `json:"secret"` // secure token used to access document
|
|
||||||
Expires string `json:"expires"` // number of days from creation, value of 0 means never
|
|
||||||
Active bool `json:"active"`
|
|
||||||
Created time.Time `json:"created"`
|
|
||||||
}
|
|
||||||
|
|
||||||
sh := []share{}
|
sh := []share{}
|
||||||
err = b.Runtime.Db.Select(&sh, `
|
err = b.Runtime.Db.Select(&sh, `
|
||||||
SELECT id AS id, c_orgid AS orgid, c_docid AS documentid,
|
SELECT id AS id, c_orgid AS orgid, c_docid AS documentid,
|
||||||
|
|
78
domain/backup/models.go
Normal file
78
domain/backup/models.go
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||||
|
//
|
||||||
|
// This software (Documize Community Edition) is licensed under
|
||||||
|
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||||
|
//
|
||||||
|
// You can operate outside the AGPL restrictions by purchasing
|
||||||
|
// Documize Enterprise Edition and obtaining a commercial license
|
||||||
|
// by contacting <sales@documize.com>.
|
||||||
|
//
|
||||||
|
// https://documize.com
|
||||||
|
|
||||||
|
// Package backup handle data backup/restore to/from ZIP format.
|
||||||
|
package backup
|
||||||
|
|
||||||
|
// Existing data models do not necessarily have fields to hold
|
||||||
|
// all data when loaded from the database.
|
||||||
|
// So we extend the existing models to hold additional fields
|
||||||
|
// for a complete backup and restore process.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/documize/community/model/org"
|
||||||
|
)
|
||||||
|
|
||||||
|
type orgExtended struct {
|
||||||
|
org.Organization
|
||||||
|
Logo []byte `json:"logo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type config struct {
|
||||||
|
ConfigKey string `json:"key"`
|
||||||
|
ConfigValue string `json:"config"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type userConfig struct {
|
||||||
|
OrgID string `json:"orgId"`
|
||||||
|
UserID string `json:"userId"`
|
||||||
|
ConfigKey string `json:"key"`
|
||||||
|
ConfigValue string `json:"config"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vote
|
||||||
|
type vote struct {
|
||||||
|
RefID string `json:"refId"`
|
||||||
|
OrgID string `json:"orgId"`
|
||||||
|
DocumentID string `json:"documentId"`
|
||||||
|
VoterID string `json:"voterId"`
|
||||||
|
Vote int `json:"vote"`
|
||||||
|
Created time.Time `json:"created"`
|
||||||
|
Revised time.Time `json:"revised"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comment
|
||||||
|
type comment struct {
|
||||||
|
RefID string `json:"feedbackId"`
|
||||||
|
OrgID string `json:"orgId"`
|
||||||
|
DocumentID string `json:"documentId"`
|
||||||
|
UserID string `json:"userId"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Feedback string `json:"feedback"`
|
||||||
|
Created time.Time `json:"created"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Share
|
||||||
|
type share struct {
|
||||||
|
ID uint64 `json:"id"`
|
||||||
|
OrgID string `json:"orgId"`
|
||||||
|
UserID string `json:"userId"`
|
||||||
|
DocumentID string `json:"documentId"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Viewed string `json:"viewed"` // recording each view as |date-viewed|date-viewed|
|
||||||
|
Secret string `json:"secret"` // secure token used to access document
|
||||||
|
Expires string `json:"expires"` // number of days from creation, value of 0 means never
|
||||||
|
Active bool `json:"active"`
|
||||||
|
Created time.Time `json:"created"`
|
||||||
|
}
|
|
@ -39,7 +39,6 @@ import (
|
||||||
"github.com/documize/community/model/doc"
|
"github.com/documize/community/model/doc"
|
||||||
"github.com/documize/community/model/group"
|
"github.com/documize/community/model/group"
|
||||||
"github.com/documize/community/model/link"
|
"github.com/documize/community/model/link"
|
||||||
"github.com/documize/community/model/org"
|
|
||||||
"github.com/documize/community/model/page"
|
"github.com/documize/community/model/page"
|
||||||
"github.com/documize/community/model/permission"
|
"github.com/documize/community/model/permission"
|
||||||
"github.com/documize/community/model/pin"
|
"github.com/documize/community/model/pin"
|
||||||
|
@ -332,7 +331,7 @@ func (r *restoreHandler) readZip(filename string) (found bool, b []byte, err err
|
||||||
func (r *restoreHandler) dmzOrg() (err error) {
|
func (r *restoreHandler) dmzOrg() (err error) {
|
||||||
filename := "dmz_org.json"
|
filename := "dmz_org.json"
|
||||||
|
|
||||||
org := []org.Organization{}
|
org := []orgExtended{}
|
||||||
err = r.fileJSON(filename, &org)
|
err = r.fileJSON(filename, &org)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, fmt.Sprintf("failed to load %s", filename))
|
err = errors.Wrap(err, fmt.Sprintf("failed to load %s", filename))
|
||||||
|
@ -363,12 +362,14 @@ func (r *restoreHandler) dmzOrg() (err error) {
|
||||||
_, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind(`
|
_, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind(`
|
||||||
INSERT INTO dmz_org (c_refid, c_company, c_title, c_message,
|
INSERT INTO dmz_org (c_refid, c_company, c_title, c_message,
|
||||||
c_domain, c_service, c_email, c_anonaccess, c_authprovider, c_authconfig,
|
c_domain, c_service, c_email, c_anonaccess, c_authprovider, c_authconfig,
|
||||||
c_maxtags, c_verified, c_serial, c_sub, c_active, c_created, c_revised)
|
c_maxtags, c_verified, c_serial, c_sub, c_active,
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
|
c_theme, c_logo, c_created, c_revised)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
|
||||||
org[i].RefID, org[i].Company, org[i].Title, org[i].Message,
|
org[i].RefID, org[i].Company, org[i].Title, org[i].Message,
|
||||||
strings.ToLower(org[i].Domain), org[i].ConversionEndpoint, strings.ToLower(org[i].Email),
|
strings.ToLower(org[i].Domain), org[i].ConversionEndpoint, strings.ToLower(org[i].Email),
|
||||||
org[i].AllowAnonymousAccess, org[i].AuthProvider, org[i].AuthConfig,
|
org[i].AllowAnonymousAccess, org[i].AuthProvider, org[i].AuthConfig,
|
||||||
org[i].MaxTags, true, org[i].Serial, org[i].Subscription,
|
org[i].MaxTags, true, org[i].Serial, org[i].Subscription,
|
||||||
|
org[i].Theme, org[i].Logo,
|
||||||
org[i].Active, org[i].Created, org[i].Revised)
|
org[i].Active, org[i].Created, org[i].Revised)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Context.Transaction.Rollback()
|
r.Context.Transaction.Rollback()
|
||||||
|
@ -402,6 +403,7 @@ func (r *restoreHandler) dmzOrg() (err error) {
|
||||||
org[0].Serial = r.Spec.Org.Serial
|
org[0].Serial = r.Spec.Org.Serial
|
||||||
org[0].Title = r.Spec.Org.Title
|
org[0].Title = r.Spec.Org.Title
|
||||||
org[0].Subscription = r.Spec.Org.Subscription
|
org[0].Subscription = r.Spec.Org.Subscription
|
||||||
|
org[0].Theme = r.Spec.Org.Theme
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = r.Context.Transaction.NamedExec(`UPDATE dmz_org SET
|
_, err = r.Context.Transaction.NamedExec(`UPDATE dmz_org SET
|
||||||
|
@ -612,8 +614,16 @@ func (r *restoreHandler) dmzSpace() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range sp {
|
for i := range sp {
|
||||||
_, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind("INSERT INTO dmz_space (c_refid, c_name, c_orgid, c_userid, c_type, c_lifecycle, c_likes, c_created, c_revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"),
|
_, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind(`
|
||||||
sp[i].RefID, sp[i].Name, r.remapOrg(sp[i].OrgID), r.remapUser(sp[i].UserID), sp[i].Type, sp[i].Lifecycle, sp[i].Likes, sp[i].Created, sp[i].Revised)
|
INSERT INTO dmz_space
|
||||||
|
(c_refid, c_name, c_orgid, c_userid, c_type, c_lifecycle,
|
||||||
|
c_likes, c_icon, c_desc, c_count_category, c_count_content,
|
||||||
|
c_labelid, c_created, c_revised)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
|
||||||
|
sp[i].RefID, sp[i].Name, r.remapOrg(sp[i].OrgID),
|
||||||
|
r.remapUser(sp[i].UserID), sp[i].Type, sp[i].Lifecycle,
|
||||||
|
sp[i].Likes, sp[i].Icon, sp[i].Description, sp[i].CountCategory,
|
||||||
|
sp[i].CountContent, sp[i].LabelID, sp[i].Created, sp[i].Revised)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Context.Transaction.Rollback()
|
r.Context.Transaction.Rollback()
|
||||||
|
|
|
@ -105,6 +105,14 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = h.Store.Space.IncrementCategoryCount(ctx, cat.SpaceID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Transaction.Rollback()
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Transaction.Commit()
|
ctx.Transaction.Commit()
|
||||||
|
|
||||||
cat, err = h.Store.Category.Get(ctx, cat.RefID)
|
cat, err = h.Store.Category.Get(ctx, cat.RefID)
|
||||||
|
@ -295,6 +303,14 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = h.Store.Space.DecrementCategoryCount(ctx, cat.SpaceID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Transaction.Rollback()
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Transaction.Commit()
|
ctx.Transaction.Commit()
|
||||||
|
|
||||||
h.Store.Audit.Record(ctx, audit.EventTypeCategoryDelete)
|
h.Store.Audit.Record(ctx, audit.EventTypeCategoryDelete)
|
||||||
|
|
|
@ -50,14 +50,17 @@ func (s Store) GetBySpace(ctx domain.RequestContext, spaceID string) (c []catego
|
||||||
SELECT id, c_refid AS refid, c_orgid AS orgid, c_spaceid AS spaceid, c_name AS name, c_created AS created, c_revised AS revised
|
SELECT id, c_refid AS refid, c_orgid AS orgid, c_spaceid AS spaceid, c_name AS name, c_created AS created, c_revised AS revised
|
||||||
FROM dmz_category
|
FROM dmz_category
|
||||||
WHERE c_orgid=? AND c_spaceid=? AND c_refid IN
|
WHERE c_orgid=? AND c_spaceid=? AND c_refid IN
|
||||||
(SELECT c_refid FROM dmz_permission WHERE c_orgid=? AND c_location='category' AND c_refid IN
|
(
|
||||||
(SELECT c_refid from dmz_permission WHERE c_orgid=? AND c_who='user' AND (c_whoid=? OR c_whoid='0') AND c_location='category'
|
SELECT c_refid
|
||||||
|
FROM dmz_permission
|
||||||
|
WHERE c_orgid=? AND c_who='user' AND (c_whoid=? OR c_whoid='0') AND c_location='category'
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT p.c_refid from dmz_permission p LEFT JOIN dmz_group_member r ON p.c_whoid=r.c_groupid
|
SELECT p.c_refid
|
||||||
WHERE p.c_orgid=? AND p.c_who='role' AND p.c_location='category' AND (r.c_userid=? OR r.c_userid='0')
|
FROM dmz_permission p LEFT JOIN dmz_group_member r ON p.c_whoid=r.c_groupid
|
||||||
))
|
WHERE p.c_orgid=? AND p.c_who='role' AND p.c_location='category' AND (r.c_userid=? OR r.c_userid='0')
|
||||||
|
)
|
||||||
ORDER BY name`),
|
ORDER BY name`),
|
||||||
ctx.OrgID, spaceID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
ctx.OrgID, spaceID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
|
@ -77,14 +80,17 @@ func (s Store) GetAllBySpace(ctx domain.RequestContext, spaceID string) (c []cat
|
||||||
SELECT id, c_refid AS refid, c_orgid AS orgid, c_spaceid AS spaceid, c_name AS name, c_created AS created, c_revised AS revised
|
SELECT id, c_refid AS refid, c_orgid AS orgid, c_spaceid AS spaceid, c_name AS name, c_created AS created, c_revised AS revised
|
||||||
FROM dmz_category
|
FROM dmz_category
|
||||||
WHERE c_orgid=? AND c_spaceid=? AND c_spaceid IN
|
WHERE c_orgid=? AND c_spaceid=? AND c_spaceid IN
|
||||||
(SELECT c_refid FROM dmz_permission WHERE c_orgid=? AND c_location='space' AND c_refid IN
|
(
|
||||||
(SELECT c_refid FROM dmz_permission WHERE c_orgid=? AND c_who='user' AND (c_whoid=? OR c_whoid='0') AND c_location='space' AND c_action='view'
|
SELECT c_refid
|
||||||
|
FROM dmz_permission
|
||||||
|
WHERE c_orgid=? AND c_who='user' AND (c_whoid=? OR c_whoid='0') AND c_location='space' AND c_action='view'
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT p.c_refid FROM dmz_permission p LEFT JOIN dmz_group_member r ON p.c_whoid=r.c_groupid
|
SELECT p.c_refid
|
||||||
|
FROM dmz_permission p LEFT JOIN dmz_group_member r ON p.c_whoid=r.c_groupid
|
||||||
WHERE p.c_orgid=? AND p.c_who='role' AND p.c_location='space' AND p.c_action='view' AND (r.c_userid=? OR r.c_userid='0')
|
WHERE p.c_orgid=? AND p.c_who='role' AND p.c_location='space' AND p.c_action='view' AND (r.c_userid=? OR r.c_userid='0')
|
||||||
))
|
)
|
||||||
ORDER BY c_name`),
|
ORDER BY c_name`),
|
||||||
ctx.OrgID, spaceID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
ctx.OrgID, spaceID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
|
@ -280,15 +286,19 @@ func (s Store) GetSpaceCategoryMembership(ctx domain.RequestContext, spaceID str
|
||||||
SELECT id, c_refid AS refid, c_orgid AS orgid, c_spaceid AS spaceid, c_categoryid AS categoryid, c_docid AS documentid, c_created AS created, c_revised AS revised
|
SELECT id, c_refid AS refid, c_orgid AS orgid, c_spaceid AS spaceid, c_categoryid AS categoryid, c_docid AS documentid, c_created AS created, c_revised AS revised
|
||||||
FROM dmz_category_member
|
FROM dmz_category_member
|
||||||
WHERE c_orgid=? AND c_spaceid=? AND c_spaceid IN
|
WHERE c_orgid=? AND c_spaceid=? AND c_spaceid IN
|
||||||
(SELECT c_refid FROM dmz_permission WHERE c_orgid=? AND c_location='space' AND c_refid IN
|
(
|
||||||
(SELECT c_refid FROM dmz_permission WHERE c_orgid=? AND c_who='user' AND (c_whoid=? OR c_whoid='0') AND c_location='space' AND c_action='view'
|
SELECT c_refid
|
||||||
|
FROM dmz_permission
|
||||||
|
WHERE c_orgid=? AND c_who='user'
|
||||||
|
AND (c_whoid=? OR c_whoid='0') AND c_location='space' AND c_action='view'
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT p.c_refid FROM dmz_permission p LEFT JOIN dmz_group_member r ON p.c_whoid=r.c_groupid
|
SELECT p.c_refid
|
||||||
|
FROM dmz_permission p LEFT JOIN dmz_group_member r ON p.c_whoid=r.c_groupid
|
||||||
WHERE p.c_orgid=? AND p.c_who='role' AND p.c_location='space'
|
WHERE p.c_orgid=? AND p.c_who='role' AND p.c_location='space'
|
||||||
AND p.c_action='view' AND (r.c_userid=? OR r.c_userid='0')
|
AND p.c_action='view' AND (r.c_userid=? OR r.c_userid='0')
|
||||||
))
|
)
|
||||||
ORDER BY documentid`),
|
ORDER BY documentid`),
|
||||||
ctx.OrgID, spaceID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
ctx.OrgID, spaceID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
|
@ -306,14 +316,17 @@ func (s Store) GetOrgCategoryMembership(ctx domain.RequestContext, userID string
|
||||||
SELECT id, c_refid AS refid, c_orgid AS orgid, c_spaceid AS spaceid, c_categoryid AS categoryid, c_docid AS documentid, c_created AS created, c_revised AS revised
|
SELECT id, c_refid AS refid, c_orgid AS orgid, c_spaceid AS spaceid, c_categoryid AS categoryid, c_docid AS documentid, c_created AS created, c_revised AS revised
|
||||||
FROM dmz_category_member
|
FROM dmz_category_member
|
||||||
WHERE c_orgid=? AND c_spaceid IN
|
WHERE c_orgid=? AND c_spaceid IN
|
||||||
(SELECT c_refid FROM dmz_permission WHERE c_orgid=? AND c_location='space' AND c_refid IN
|
(
|
||||||
(SELECT c_refid from dmz_permission WHERE c_orgid=? AND c_who='user' AND (c_whoid=? OR c_whoid='0') AND c_location='space' AND c_action='view'
|
SELECT c_refid
|
||||||
|
FROM dmz_permission
|
||||||
|
WHERE c_orgid=? AND c_who='user' AND (c_whoid=? OR c_whoid='0') AND c_location='space' AND c_action='view'
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT p.c_refid from dmz_permission p LEFT JOIN dmz_group_member r ON p.c_whoid=r.c_groupid WHERE p.c_orgid=? AND p.c_who='role' AND p.c_location='space'
|
SELECT p.c_refid
|
||||||
AND p.c_action='view' AND (r.c_userid=? OR r.c_userid='0')
|
FROM dmz_permission p LEFT JOIN dmz_group_member r ON p.c_whoid=r.c_groupid
|
||||||
))
|
WHERE p.c_orgid=? AND p.c_who='role' AND p.c_location='space' AND p.c_action='view' AND (r.c_userid=? OR r.c_userid='0')
|
||||||
|
)
|
||||||
ORDER BY documentid`),
|
ORDER BY documentid`),
|
||||||
ctx.OrgID, ctx.OrgID, ctx.OrgID, userID, ctx.OrgID, userID)
|
ctx.OrgID, ctx.OrgID, userID, ctx.OrgID, userID)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
|
|
|
@ -248,6 +248,12 @@ func processDocument(ctx domain.RequestContext, r *env.Runtime, store *store.Sto
|
||||||
SourceType: activity.SourceTypeDocument,
|
SourceType: activity.SourceTypeDocument,
|
||||||
ActivityType: activity.TypeCreated})
|
ActivityType: activity.TypeCreated})
|
||||||
|
|
||||||
|
err = store.Space.IncrementContentCount(ctx, newDocument.SpaceID)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "cannot increment space content count")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err = ctx.Transaction.Commit()
|
err = ctx.Transaction.Commit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "cannot commit new document import")
|
err = errors.Wrap(err, "cannot commit new document import")
|
||||||
|
|
|
@ -166,9 +166,6 @@ func (h *Handler) BySpace(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by title.
|
|
||||||
sort.Sort(doc.ByName(documents))
|
|
||||||
|
|
||||||
// Remove documents that cannot be seen due to lack of
|
// Remove documents that cannot be seen due to lack of
|
||||||
// category view/access permission.
|
// category view/access permission.
|
||||||
cats, err := h.Store.Category.GetBySpace(ctx, spaceID)
|
cats, err := h.Store.Category.GetBySpace(ctx, spaceID)
|
||||||
|
@ -178,6 +175,30 @@ func (h *Handler) BySpace(w http.ResponseWriter, r *http.Request) {
|
||||||
// Keep the latest version when faced with multiple versions.
|
// Keep the latest version when faced with multiple versions.
|
||||||
filtered = FilterLastVersion(filtered)
|
filtered = FilterLastVersion(filtered)
|
||||||
|
|
||||||
|
// Sort document list by ID.
|
||||||
|
sort.Sort(doc.ByID(filtered))
|
||||||
|
|
||||||
|
// Attach category membership to each document.
|
||||||
|
// Put category names into map for easier retrieval.
|
||||||
|
catNames := make(map[string]string)
|
||||||
|
for i := range cats {
|
||||||
|
catNames[cats[i].RefID] = cats[i].Name
|
||||||
|
}
|
||||||
|
// Loop the smaller list which is categories assigned to documents.
|
||||||
|
for i := range members {
|
||||||
|
// Get name of category
|
||||||
|
cn := catNames[members[i].CategoryID]
|
||||||
|
// Find document that is assigned this category.
|
||||||
|
j := sort.Search(len(filtered), func(k int) bool { return filtered[k].RefID <= members[i].DocumentID })
|
||||||
|
// Attach category name to document
|
||||||
|
if j < len(filtered) && filtered[j].RefID == members[i].DocumentID {
|
||||||
|
filtered[j].Category = append(filtered[j].Category, cn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort document list by title.
|
||||||
|
sort.Sort(doc.ByName(filtered))
|
||||||
|
|
||||||
response.WriteJSON(w, filtered)
|
response.WriteJSON(w, filtered)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,6 +417,14 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||||
ActivityType: activity.TypeDeleted})
|
ActivityType: activity.TypeDeleted})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = h.Store.Space.DecrementContentCount(ctx, doc.SpaceID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Transaction.Rollback()
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Transaction.Commit()
|
ctx.Transaction.Commit()
|
||||||
|
|
||||||
h.Store.Audit.Record(ctx, audit.EventTypeDocumentDelete)
|
h.Store.Audit.Record(ctx, audit.EventTypeDocumentDelete)
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -81,17 +81,15 @@ func (s Store) GetBySpace(ctx domain.RequestContext, spaceID string) (documents
|
||||||
c_versionorder AS versionorder, c_groupid AS groupid, c_created AS created, c_revised AS revised
|
c_versionorder AS versionorder, c_groupid AS groupid, c_created AS created, c_revised AS revised
|
||||||
FROM dmz_doc
|
FROM dmz_doc
|
||||||
WHERE c_orgid=? AND c_template=false AND c_spaceid IN
|
WHERE c_orgid=? AND c_template=false AND c_spaceid IN
|
||||||
(SELECT c_refid FROM dmz_space WHERE c_orgid=? AND c_refid IN
|
(SELECT c_refid FROM dmz_permission WHERE c_orgid=? AND c_location='space' AND c_refid=? AND c_refid IN
|
||||||
(SELECT c_refid FROM dmz_permission WHERE c_orgid=? AND c_location='space' AND c_refid=? AND c_refid IN
|
(SELECT c_refid from dmz_permission WHERE c_orgid=? AND c_who='user' AND (c_whoid=? OR c_whoid='0') AND c_location='space' AND c_action='view'
|
||||||
(SELECT c_refid from dmz_permission WHERE c_orgid=? AND c_who='user' AND (c_whoid=? OR c_whoid='0') AND c_location='space' AND c_action='view'
|
UNION ALL
|
||||||
UNION ALL
|
SELECT p.c_refid from dmz_permission p LEFT JOIN dmz_group_member r ON p.c_whoid=r.c_groupid WHERE p.c_orgid=?
|
||||||
SELECT p.c_refid from dmz_permission p LEFT JOIN dmz_group_member r ON p.c_whoid=r.c_groupid WHERE p.c_orgid=?
|
AND p.c_who='role' AND p.c_location='space' AND p.c_refid=? AND p.c_action='view' AND (r.c_userid=? OR r.c_userid='0')
|
||||||
AND p.c_who='role' AND p.c_location='space' AND p.c_refid=? AND p.c_action='view' AND (r.c_userid=? OR r.c_userid='0')
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
ORDER BY c_name, c_versionorder`),
|
ORDER BY c_name, c_versionorder`),
|
||||||
ctx.OrgID, ctx.OrgID, ctx.OrgID, spaceID, ctx.OrgID, ctx.UserID, ctx.OrgID, spaceID, ctx.UserID)
|
ctx.OrgID, ctx.OrgID, spaceID, ctx.OrgID, ctx.UserID, ctx.OrgID, spaceID, ctx.UserID)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
|
@ -100,6 +98,9 @@ func (s Store) GetBySpace(ctx domain.RequestContext, spaceID string) (documents
|
||||||
err = errors.Wrap(err, "select documents by space")
|
err = errors.Wrap(err, "select documents by space")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (SELECT c_refid FROM dmz_space WHERE c_orgid=? AND c_refid IN
|
||||||
|
// )
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -179,3 +179,19 @@ func (s Store) GetMembers(ctx domain.RequestContext) (r []group.Record, err erro
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveUserGroups remove user from all group.
|
||||||
|
func (s Store) RemoveUserGroups(ctx domain.RequestContext, userID string) (err error) {
|
||||||
|
_, err = s.DeleteWhere(ctx.Transaction,
|
||||||
|
fmt.Sprintf("DELETE FROM dmz_group_member WHERE c_orgid='%s' AND c_userid='%s'",
|
||||||
|
ctx.OrgID, userID))
|
||||||
|
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "RemoveUserGroups")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
201
domain/label/endpoint.go
Normal file
201
domain/label/endpoint.go
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
// 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 label
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/documize/community/core/env"
|
||||||
|
"github.com/documize/community/core/request"
|
||||||
|
"github.com/documize/community/core/response"
|
||||||
|
"github.com/documize/community/core/streamutil"
|
||||||
|
"github.com/documize/community/core/uniqueid"
|
||||||
|
"github.com/documize/community/domain"
|
||||||
|
"github.com/documize/community/domain/store"
|
||||||
|
"github.com/documize/community/model/audit"
|
||||||
|
"github.com/documize/community/model/label"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handler contains the runtime information such as logging and database.
|
||||||
|
type Handler struct {
|
||||||
|
Runtime *env.Runtime
|
||||||
|
Store *store.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add space label to the store.
|
||||||
|
func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
||||||
|
method := "label.Add"
|
||||||
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
|
if !h.Runtime.Product.IsValid(ctx) {
|
||||||
|
response.WriteBadLicense(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ctx.Administrator {
|
||||||
|
response.WriteForbiddenError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer streamutil.Close(r.Body)
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
response.WriteBadRequestError(w, method, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := label.Label{}
|
||||||
|
err = json.Unmarshal(body, &l)
|
||||||
|
if err != nil {
|
||||||
|
response.WriteBadRequestError(w, method, err.Error())
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l.RefID = uniqueid.Generate()
|
||||||
|
|
||||||
|
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||||
|
if err != nil {
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.Store.Label.Add(ctx, l)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Transaction.Rollback()
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Transaction.Commit()
|
||||||
|
|
||||||
|
h.Store.Audit.Record(ctx, audit.EventTypeLabelAdd)
|
||||||
|
|
||||||
|
response.WriteJSON(w, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns all space labels.
|
||||||
|
func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
|
||||||
|
method := "label.Get"
|
||||||
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
|
l, err := h.Store.Label.Get(ctx)
|
||||||
|
if err != nil {
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(l) == 0 {
|
||||||
|
l = []label.Label{}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteJSON(w, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update persists label name/color changes.
|
||||||
|
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
|
method := "label.Update"
|
||||||
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
|
if !ctx.Administrator {
|
||||||
|
response.WriteForbiddenError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
labelID := request.Param(r, "labelID")
|
||||||
|
if len(labelID) == 0 {
|
||||||
|
response.WriteMissingDataError(w, method, "labelID")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer streamutil.Close(r.Body)
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
response.WriteBadRequestError(w, method, "Bad payload")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := label.Label{}
|
||||||
|
err = json.Unmarshal(body, &l)
|
||||||
|
if err != nil {
|
||||||
|
response.WriteBadRequestError(w, method, "Bad payload")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l.RefID = labelID
|
||||||
|
|
||||||
|
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||||
|
if err != nil {
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.Store.Label.Update(ctx, l)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Transaction.Rollback()
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Transaction.Commit()
|
||||||
|
|
||||||
|
h.Store.Audit.Record(ctx, audit.EventTypeLabelUpdate)
|
||||||
|
|
||||||
|
response.WriteEmpty(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes space label from store and
|
||||||
|
// removes label association from spaces.
|
||||||
|
func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||||
|
method := "label.Delete"
|
||||||
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
|
labelID := request.Param(r, "labelID")
|
||||||
|
if len(labelID) == 0 {
|
||||||
|
response.WriteMissingDataError(w, method, "labelID")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||||
|
if err != nil {
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = h.Store.Label.Delete(ctx, labelID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Transaction.Rollback()
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.Store.Label.RemoveReference(ctx, labelID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Transaction.Rollback()
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Transaction.Commit()
|
||||||
|
|
||||||
|
h.Store.Audit.Record(ctx, audit.EventTypeLabelDelete)
|
||||||
|
|
||||||
|
response.WriteEmpty(w)
|
||||||
|
}
|
106
domain/label/store.go
Normal file
106
domain/label/store.go
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
// 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 label
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/documize/community/domain"
|
||||||
|
"github.com/documize/community/domain/store"
|
||||||
|
"github.com/documize/community/model/label"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Store provides data access to section template information.
|
||||||
|
type Store struct {
|
||||||
|
store.Context
|
||||||
|
store.LabelStorer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add saves space label to store.
|
||||||
|
func (s Store) Add(ctx domain.RequestContext, l label.Label) (err error) {
|
||||||
|
l.OrgID = ctx.OrgID
|
||||||
|
l.Created = time.Now().UTC()
|
||||||
|
l.Revised = time.Now().UTC()
|
||||||
|
|
||||||
|
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_space_label (c_refid, c_orgid, c_name, c_color, c_created, c_revised) VALUES (?, ?, ?, ?, ?, ?)"),
|
||||||
|
l.RefID, l.OrgID, l.Name, l.Color, l.Created, l.Revised)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "execute insert label")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns all space labels from store.
|
||||||
|
func (s Store) Get(ctx domain.RequestContext) (l []label.Label, err error) {
|
||||||
|
err = s.Runtime.Db.Select(&l, s.Bind(`
|
||||||
|
SELECT id, c_refid as refid,
|
||||||
|
c_orgid as orgid,
|
||||||
|
c_name AS name, c_color AS color,
|
||||||
|
c_created AS created, c_revised AS revised
|
||||||
|
FROM dmz_space_label
|
||||||
|
WHERE c_orgid=?`),
|
||||||
|
ctx.OrgID)
|
||||||
|
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "execute select label")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update persists space label changes to the store.
|
||||||
|
func (s Store) Update(ctx domain.RequestContext, l label.Label) (err error) {
|
||||||
|
l.Revised = time.Now().UTC()
|
||||||
|
|
||||||
|
_, err = ctx.Transaction.NamedExec(s.Bind(`UPDATE dmz_space_label SET
|
||||||
|
c_name=:name, c_color=:color, c_revised=:revised
|
||||||
|
WHERE c_orgid=:orgid AND c_refid=:refid`),
|
||||||
|
l)
|
||||||
|
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "execute update label")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes space label from the store.
|
||||||
|
func (s Store) Delete(ctx domain.RequestContext, id string) (rows int64, err error) {
|
||||||
|
return s.DeleteConstrained(ctx.Transaction, "dmz_space_label", ctx.OrgID, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveReference clears space.labelID for given label.
|
||||||
|
func (s Store) RemoveReference(ctx domain.RequestContext, spaceID string) (err error) {
|
||||||
|
_, err = ctx.Transaction.Exec(s.Bind(`UPDATE dmz_space SET
|
||||||
|
c_labelid='', c_revised=?
|
||||||
|
WHERE c_orgid=? AND c_refid=?`),
|
||||||
|
time.Now().UTC(), ctx.OrgID, spaceID)
|
||||||
|
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "execute remove space label reference")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -97,7 +97,6 @@ func (h *Handler) GetLinkCandidates(w http.ResponseWriter, r *http.Request) {
|
||||||
if len(files) == 0 {
|
if len(files) == 0 {
|
||||||
files = []attachment.Attachment{}
|
files = []attachment.Attachment{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
h.Runtime.Log.Error(method, err)
|
h.Runtime.Log.Error(method, err)
|
||||||
|
|
|
@ -76,7 +76,7 @@ background-color: #f6f6f6;
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
||||||
<td class="content-block" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
<td class="content-block" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
||||||
<a href="{{.URL}}" class="btn-primary" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background: #4ccb6a; margin: 0; padding: 0; border-color: #4ccb6a; border-style: solid; border-width: 10px 20px;">View document</a>
|
<a href="{{.URL}}" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background: #4ccb6a; margin: 0; padding: 0; border-color: #4ccb6a; border-style: solid; border-width: 10px 20px;">View document</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
||||||
|
|
|
@ -87,7 +87,7 @@ background-color: #f6f6f6;
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
||||||
<td class="content-block" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
<td class="content-block" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
||||||
<a href="{{.Url}}" class="btn-primary" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background: #4ccb6a; margin: 0; padding: 0; border-color: #4ccb6a; border-style: solid; border-width: 10px 20px;">Click here to access Documize</a>
|
<a href="{{.Url}}" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background: #4ccb6a; margin: 0; padding: 0; border-color: #4ccb6a; border-style: solid; border-width: 10px 20px;">Click here to access Documize</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
||||||
|
|
|
@ -72,7 +72,7 @@ background-color: #f6f6f6;
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
||||||
<td class="content-block" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
<td class="content-block" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
||||||
<a href="{{.URL}}" class="btn-primary" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background: #4ccb6a; margin: 0; padding: 0; border-color: #4ccb6a; border-style: solid; border-width: 10px 20px;">Click here to access Documize</a>
|
<a href="{{.URL}}" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background: #4ccb6a; margin: 0; padding: 0; border-color: #4ccb6a; border-style: solid; border-width: 10px 20px;">Click here to access Documize</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
||||||
|
|
|
@ -82,7 +82,7 @@ background-color: #f6f6f6;
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
||||||
<td class="content-block" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
<td class="content-block" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
||||||
<a href="{{.URL}}" class="btn-primary" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background: #4ccb6a; margin: 0; padding: 0; border-color: #4ccb6a; border-style: solid; border-width: 10px 20px;">Click here to access Documize</a>
|
<a href="{{.URL}}" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background: #4ccb6a; margin: 0; padding: 0; border-color: #4ccb6a; border-style: solid; border-width: 10px 20px;">Click here to access Documize</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
||||||
|
|
|
@ -79,7 +79,7 @@ background-color: #f6f6f6;
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
||||||
<td class="content-block" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
<td class="content-block" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
||||||
<a href="{{.URL}}" class="btn-primary" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background: #4ccb6a; margin: 0; padding: 0; border-color: #4ccb6a; border-style: solid; border-width: 10px 20px;">Click here to reset your password</a>
|
<a href="{{.URL}}" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background: #4ccb6a; margin: 0; padding: 0; border-color: #4ccb6a; border-style: solid; border-width: 10px 20px;">Click here to reset your password</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
||||||
|
|
|
@ -75,7 +75,7 @@ background-color: #f6f6f6;
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
||||||
<td class="content-block" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
<td class="content-block" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
||||||
<a href="{{.URL}}" class="btn-primary" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background: #4ccb6a; margin: 0; padding: 0; border-color: #4ccb6a; border-style: solid; border-width: 10px 20px;">Login to Documize</a>
|
<a href="{{.URL}}" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background: #4ccb6a; margin: 0; padding: 0; border-color: #4ccb6a; border-style: solid; border-width: 10px 20px;">Login to Documize</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
||||||
|
|
|
@ -81,7 +81,7 @@ background-color: #f6f6f6;
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
||||||
<td class="content-block" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
<td class="content-block" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
|
||||||
<a href="{{.URL}}" class="btn-primary" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background: #4ccb6a; margin: 0; padding: 0; border-color: #4ccb6a; border-style: solid; border-width: 10px 20px;">Go to Documize</a>
|
<a href="{{.URL}}" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background: #4ccb6a; margin: 0; padding: 0; border-color: #4ccb6a; border-style: solid; border-width: 10px 20px;">Go to Documize</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0; padding: 0;">
|
||||||
|
|
|
@ -13,6 +13,7 @@ package meta
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -57,6 +58,7 @@ func (h *Handler) Meta(w http.ResponseWriter, r *http.Request) {
|
||||||
data.AuthProvider = strings.TrimSpace(org.AuthProvider)
|
data.AuthProvider = strings.TrimSpace(org.AuthProvider)
|
||||||
data.AuthConfig = org.AuthConfig
|
data.AuthConfig = org.AuthConfig
|
||||||
data.MaxTags = org.MaxTags
|
data.MaxTags = org.MaxTags
|
||||||
|
data.Theme = org.Theme
|
||||||
data.Version = h.Runtime.Product.Version
|
data.Version = h.Runtime.Product.Version
|
||||||
data.Revision = h.Runtime.Product.Revision
|
data.Revision = h.Runtime.Product.Revision
|
||||||
data.Edition = h.Runtime.Product.Edition
|
data.Edition = h.Runtime.Product.Edition
|
||||||
|
@ -111,6 +113,10 @@ Disallow: /auth/*
|
||||||
Disallow: /auth/**
|
Disallow: /auth/**
|
||||||
Disallow: /share
|
Disallow: /share
|
||||||
Disallow: /share/*
|
Disallow: /share/*
|
||||||
|
Disallow: /attachments
|
||||||
|
Disallow: /attachments/*
|
||||||
|
Disallow: /attachment
|
||||||
|
Disallow: /attachment/*
|
||||||
Sitemap: %s`, sitemap)
|
Sitemap: %s`, sitemap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +196,7 @@ func (h *Handler) Reindex(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if !ctx.GlobalAdmin {
|
if !ctx.GlobalAdmin {
|
||||||
response.WriteForbiddenError(w)
|
response.WriteForbiddenError(w)
|
||||||
h.Runtime.Log.Info(fmt.Sprintf("%s attempted search reindex"))
|
h.Runtime.Log.Info(fmt.Sprintf("%s attempted search reindex", ctx.UserID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +259,7 @@ func (h *Handler) SearchStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if !ctx.GlobalAdmin {
|
if !ctx.GlobalAdmin {
|
||||||
response.WriteForbiddenError(w)
|
response.WriteForbiddenError(w)
|
||||||
h.Runtime.Log.Info(fmt.Sprintf("%s attempted get of search status"))
|
h.Runtime.Log.Info(fmt.Sprintf("%s attempted get of search status", ctx.UserID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,3 +283,72 @@ type sitemapItem struct {
|
||||||
type searchStatus struct {
|
type searchStatus struct {
|
||||||
Entries int `json:"entries"`
|
Entries int `json:"entries"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Themes returns list of installed UI themes.
|
||||||
|
func (h *Handler) Themes(w http.ResponseWriter, r *http.Request) {
|
||||||
|
type theme struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Primary string `json:"primary"`
|
||||||
|
}
|
||||||
|
|
||||||
|
th := []theme{}
|
||||||
|
th = append(th, theme{Name: "", Primary: "#280A42"})
|
||||||
|
th = append(th, theme{Name: "Brave", Primary: "#BF360C"})
|
||||||
|
th = append(th, theme{Name: "Conference", Primary: "#176091"})
|
||||||
|
th = append(th, theme{Name: "Forest", Primary: "#00695C"})
|
||||||
|
th = append(th, theme{Name: "Harvest", Primary: "#A65F20"})
|
||||||
|
th = append(th, theme{Name: "Silver", Primary: "#AEBECC"})
|
||||||
|
th = append(th, theme{Name: "Sunflower", Primary: "#D7B92F"})
|
||||||
|
|
||||||
|
response.WriteJSON(w, th)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logo returns site logo based upon request domain (e.g. acme.documize.com).
|
||||||
|
// The default Documize logo is returned if organization has not uploaded
|
||||||
|
// their own logo.
|
||||||
|
func (h *Handler) Logo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := domain.GetRequestContext(r)
|
||||||
|
d := organization.GetSubdomainFromHost(r)
|
||||||
|
|
||||||
|
// If organization has logo, send it back.
|
||||||
|
logo, err := h.Store.Organization.Logo(ctx, d)
|
||||||
|
if err == nil && len(logo) > 0 {
|
||||||
|
h.writeLogo(w, r, logo)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
h.Runtime.Log.Infof("unable to fetch logo for domain %s", d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we send back default logo.
|
||||||
|
h.DefaultLogo(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultLogo write the default Documize logo to the HTTP response.
|
||||||
|
func (h *Handler) DefaultLogo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
logo, err := base64.StdEncoding.DecodeString(defaultLogo)
|
||||||
|
if err != nil {
|
||||||
|
h.Runtime.Log.Error("unable to decode default logo", err)
|
||||||
|
response.WriteEmpty(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.writeLogo(w, r, logo)
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeLogo writes byte array as logo to HTTP response stream.
|
||||||
|
func (h *Handler) writeLogo(w http.ResponseWriter, r *http.Request, logo []byte) {
|
||||||
|
w.Header().Set("Content-Type", "application/octet-stream")
|
||||||
|
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(logo)))
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
_, err := w.Write(logo)
|
||||||
|
if err != nil {
|
||||||
|
h.Runtime.Log.Error("failed to write logo", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultLogo = `
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAAEIAAAA2CAYAAABz508/AAAAAXNSR0IArs4c6QAABuRJREFUaAXtW1tsFFUY/s/s7tBCkcpFH0gRfeBBDPCAKAqJJUYSY+DBQIwPRo2JCIZ2W1qiKzIVtkBb2lIlER/UB6KJGE2JCcaQABpNRBQ0QYWYaLxxlRZobbszc36/s9spu9uZ7drZC4WeZDtnzu3//m/+c/nPORWUFgzjnZJu6+L9zDSPiKelZRf8lVlYpPEVQaKHNflbiUY/NRkb/841EJHcYDjSusgmq5OZS4WgCcRUkpxfjDhwSHwUkwR+ihQCLmJbCHFYMHWSHvqw3Qh3+8U2RERVpGUts73bb4OFrS+ukuAQZB4kLWB0bNnw7Wjlx4mo2bRzvi2to2BeH21DxawH65BM1K8xf6LrFB5N1xGGwdqlWPNJIXgOiNCKqZBv2YJiaMPSBO0sD5Y1Gca6nmzb1LpjzQsE8cwxT4LSWFk000SWouaS2fNDbaTljqyJgA0sZkGBbCuMhXJMPAk4K0yWx8ORHQuzwRyEJUwDi6UehWFa8ZHaIzv/ybBWTBYUxB9g5Ow/GKMO8a0205FwpPnJtmhdZya0IAITlBLlHso0TVS6ZxUmFeuHIEueJUnMxKB4J0u5HM8pGByVophKRwwTbZYfY1Z8aFd0w+depdGYdwCIgfatdYe9SxQnJ7ypda6U1mp8xOdAxhSgUF0hUxBYGhxBvXvattScdCs4JmcJpcyuaP3mJQtmzyLSolCsFwuuPjcFnTQ1xdqW+dnG7XsUccPCmCTC0WL16tV2R2PdNl3X7hIsPsV41uvkpT+xWtZA1tT+q5c/QnzYUDCmiXCUbTHqzrdH6x7HuLGXsdR00l2eJchcWP1Ky7r0vBuCCKUUTJ9fb6xfg3GtAW8D6YoOvTPfgnGlwTA+SFlF3zBEOIqiqzRgbfQm3r27CbF+2fr9BaeOet5wRCillsybXYvx4HshNHfLYCqT0oZV7JmoyquQcfpMFMnub7XRVi4tc0Z2pXNTSguGLri54GoQNYzdy7tiPX9CkvtaA6vpLvNyNfIbFRrfRNREdlbYZL8rYyYWXsNHYyUkXwEyuSrSdChAgadbo7V/JMtRDld1pGkrMG3G6rksOU/FVRqWkk8hGifCV9dQnqvN9j5MR8sKTUJCMcZCiZcpDApLIu3a3/LQjDcwcCqP1DWg7uyqaPvtKnNYZdcaHomXqOVueAL3eWQXLFlhUFjSBRrGM/1YPmzETOI+cKpdrz7zMVXPFxFBKQs6JqQrmvyuWTQ9+d2J6zrvT/glTkrSE90DXeQJleKLCKnpxzE6/5vUdHGiCkMweMJNuFpsEclf3fLiaSyXGsahoC8iEiO2CKsNVk9Bec5IyBZht9nDEa1R4D2vRRbqmz3WsQrfs0ZHtP4t7H6fsDVzBSaN+MDjAMj7U/A5jUP726I1RzPJEhp/jW2NPvyGTaVYklumFHN8E6EADALJCCYT0LznieAZkjFY/zBfC6I5CIOu8NU18q5AjgSUlAbPYsBM8S2cpuG1huColN0URGx7ef0FgYMPR/nkJ6beEH43BxEJxdlrQFfGELopLCLZArzi40QMMjNOxCAROZk+w5ualkqbVqLNwq4jiM5hCOxs21L/hZfJZ5vum4iqSPOLts0dxfE+iWxb1ADD+l3ROniaow++ukbYaJ3KJJuLRUJCbbjiwKCwjJ4Gn06XkOZ8LFuLfplEYYhj8cGEL4tgDsGzuz6CXyy+iGh9LfwjNj2+LDYVCoPC4geHLyLUWYKg0Cq4sgfg0Nh+gIyursBdKjqQwJDxYGfE5n3PGu2N4TOQ8qjaGr9i9hT0Ft4tobJ/DOP5nGwM+SbCoXoQUE5AOW0W8umraxQSaL5ljRMxyPA4EeNEpHa2cYsY5COHs8busm6KuR6ypHKfu7dy0i/+n0ulmST7JgJb+TNxkf3tLrPnYZwaFdTCukRMro80HQxQ8FnspP+VSdGR8nwBVwevkq19OFp+pNAkKMXiMiFbYcCBrtte/Uj6D+X7ImLwEHjxUGtFimAXenFVQ8tcP+Jxf1v2w2lxvVkCAZ5H6kro9XQIPCIW4a4jzjQGcObRi4u12s+4iOZiVkgUdCqTyemlk0+AxD4/XyIXdRUGhcWrLaUDrjKfhmMInVMDUvoCJE5p6o4yypnDvUfs/GiBNcrDTK167W37S2u70PYGNwHXSuU7hg+mUW0ci4eouJcc0lel76Th68eg5WnFQdwSOjo6JvxydmAvLqeuwACk/l1Iw+3MB9sb67/zaDslGdeHHpBkrwRjt6Vk5PkF4M/jpLsT14a+ykZUzas7Km2L3gfOyTARHboem6ovwrWASiulS6h7Ar30zfRJNKNb3TbJpvGxVkb9814vXSifRPdiDVKpPno8/AeFjniebez5hgAAAABJRU5ErkJggg==
|
||||||
|
`
|
||||||
|
|
|
@ -12,8 +12,11 @@
|
||||||
package organization
|
package organization
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"github.com/documize/community/model/audit"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
@ -99,3 +102,50 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
response.WriteJSON(w, org)
|
response.WriteJSON(w, org)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UploadLogo stores log for organization.
|
||||||
|
func (h *Handler) UploadLogo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
method := "organization.UploadLogo"
|
||||||
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
|
if !ctx.Administrator {
|
||||||
|
response.WriteForbiddenError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// We use default logo if body is empty.
|
||||||
|
logo := []byte{}
|
||||||
|
|
||||||
|
filedata, _, err := r.FormFile("attachment")
|
||||||
|
if err == nil {
|
||||||
|
b := new(bytes.Buffer)
|
||||||
|
_, err = io.Copy(b, filedata)
|
||||||
|
if err != nil {
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
} else {
|
||||||
|
logo = b.Bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||||
|
if err != nil {
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.Store.Organization.UploadLogo(ctx, logo)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Transaction.Rollback()
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Transaction.Commit()
|
||||||
|
|
||||||
|
h.Store.Audit.Record(ctx, audit.EventTypeOrganizationLogo)
|
||||||
|
|
||||||
|
response.WriteEmpty(w)
|
||||||
|
}
|
||||||
|
|
|
@ -50,9 +50,9 @@ func (s Store) GetOrganization(ctx domain.RequestContext, id string) (org org.Or
|
||||||
c_title AS title, c_message AS message, c_domain AS domain,
|
c_title AS title, c_message AS message, c_domain AS domain,
|
||||||
c_service AS conversionendpoint, c_email AS email, c_serial AS serial, c_active AS active,
|
c_service AS conversionendpoint, c_email AS email, c_serial AS serial, c_active AS active,
|
||||||
c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider,
|
c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider,
|
||||||
coalesce(c_authconfig,`+s.EmptyJSON()+`) AS authconfig,
|
coalesce(c_authconfig,`+s.EmptyJSON()+`) AS authconfig,
|
||||||
coalesce(c_sub,`+s.EmptyJSON()+`) AS subscription,
|
coalesce(c_sub,`+s.EmptyJSON()+`) AS subscription,
|
||||||
c_maxtags AS maxtags, c_created AS created, c_revised AS revised
|
c_maxtags AS maxtags, c_theme AS theme, c_created AS created, c_revised AS revised
|
||||||
FROM dmz_org
|
FROM dmz_org
|
||||||
WHERE c_refid=?`),
|
WHERE c_refid=?`),
|
||||||
id)
|
id)
|
||||||
|
@ -82,9 +82,9 @@ func (s Store) GetOrganizationByDomain(subdomain string) (o org.Organization, er
|
||||||
c_title AS title, c_message AS message, c_domain AS domain,
|
c_title AS title, c_message AS message, c_domain AS domain,
|
||||||
c_service AS conversionendpoint, c_email AS email, c_serial AS serial, c_active AS active,
|
c_service AS conversionendpoint, c_email AS email, c_serial AS serial, c_active AS active,
|
||||||
c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider,
|
c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider,
|
||||||
coalesce(c_authconfig,`+s.EmptyJSON()+`) AS authconfig,
|
coalesce(c_authconfig,`+s.EmptyJSON()+`) AS authconfig,
|
||||||
coalesce(c_sub,`+s.EmptyJSON()+`) AS subscription,
|
coalesce(c_sub,`+s.EmptyJSON()+`) AS subscription,
|
||||||
c_maxtags AS maxtags, c_created AS created, c_revised AS revised
|
c_maxtags AS maxtags, c_created AS created, c_revised AS revised, c_theme AS theme
|
||||||
FROM dmz_org
|
FROM dmz_org
|
||||||
WHERE c_domain=? AND c_active=true`),
|
WHERE c_domain=? AND c_active=true`),
|
||||||
subdomain)
|
subdomain)
|
||||||
|
@ -97,9 +97,9 @@ func (s Store) GetOrganizationByDomain(subdomain string) (o org.Organization, er
|
||||||
c_title AS title, c_message AS message, c_domain AS domain,
|
c_title AS title, c_message AS message, c_domain AS domain,
|
||||||
c_service AS conversionendpoint, c_email AS email, c_serial AS serial, c_active AS active,
|
c_service AS conversionendpoint, c_email AS email, c_serial AS serial, c_active AS active,
|
||||||
c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider,
|
c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider,
|
||||||
coalesce(c_authconfig,`+s.EmptyJSON()+`) AS authconfig,
|
coalesce(c_authconfig,`+s.EmptyJSON()+`) AS authconfig,
|
||||||
coalesce(c_sub,`+s.EmptyJSON()+`) AS subscription,
|
coalesce(c_sub,`+s.EmptyJSON()+`) AS subscription,
|
||||||
c_maxtags AS maxtags, c_created AS created, c_revised AS revised
|
c_maxtags AS maxtags, c_created AS created, c_revised AS revised, c_theme AS theme
|
||||||
FROM dmz_org
|
FROM dmz_org
|
||||||
WHERE c_domain='' AND c_active=true`))
|
WHERE c_domain='' AND c_active=true`))
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ func (s Store) UpdateOrganization(ctx domain.RequestContext, org org.Organizatio
|
||||||
|
|
||||||
_, err = ctx.Transaction.NamedExec(`UPDATE dmz_org SET
|
_, err = ctx.Transaction.NamedExec(`UPDATE dmz_org SET
|
||||||
c_title=:title, c_message=:message, c_service=:conversionendpoint, c_email=:email,
|
c_title=:title, c_message=:message, c_service=:conversionendpoint, c_email=:email,
|
||||||
c_anonaccess=:allowanonymousaccess, c_maxtags=:maxtags, c_revised=:revised
|
c_anonaccess=:allowanonymousaccess, c_maxtags=:maxtags, c_theme=:theme, c_revised=:revised
|
||||||
WHERE c_refid=:refid`,
|
WHERE c_refid=:refid`,
|
||||||
&org)
|
&org)
|
||||||
|
|
||||||
|
@ -176,3 +176,31 @@ func (s Store) CheckDomain(ctx domain.RequestContext, domain string) string {
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Logo fetchs stored image from store or NULL.
|
||||||
|
func (s Store) Logo(ctx domain.RequestContext, domain string) (l []byte, err error) {
|
||||||
|
row := s.Runtime.Db.QueryRow(s.Bind("SELECT c_logo FROM dmz_org WHERE c_domain=? AND c_active=true"), domain)
|
||||||
|
|
||||||
|
err = row.Scan(&l)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
err = nil
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UploadLogo saves custom logo to the organization record.
|
||||||
|
func (s Store) UploadLogo(ctx domain.RequestContext, logo []byte) (err error) {
|
||||||
|
_, err = ctx.Transaction.Exec(s.Bind("UPDATE dmz_org SET c_logo=?, c_revised=? WHERE c_refid=?"),
|
||||||
|
logo, time.Now().UTC(), ctx.OrgID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, fmt.Sprintf("unable to save custom logo for org %s", ctx.OrgID))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -157,7 +157,6 @@ func (p *Provider) Refresh(ctx *provider.Context, config, data string) (newData
|
||||||
func auth(ctx *provider.Context, store *store.Store, w http.ResponseWriter, r *http.Request) {
|
func auth(ctx *provider.Context, store *store.Store, w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
provider.WriteMessage(w, "gemini", "Bad payload")
|
provider.WriteMessage(w, "gemini", "Bad payload")
|
||||||
return
|
return
|
||||||
|
@ -165,7 +164,6 @@ func auth(ctx *provider.Context, store *store.Store, w http.ResponseWriter, r *h
|
||||||
|
|
||||||
var config = geminiConfig{}
|
var config = geminiConfig{}
|
||||||
err = json.Unmarshal(body, &config)
|
err = json.Unmarshal(body, &config)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
provider.WriteMessage(w, "gemini", "Bad payload")
|
provider.WriteMessage(w, "gemini", "Bad payload")
|
||||||
return
|
return
|
||||||
|
@ -177,30 +175,26 @@ func auth(ctx *provider.Context, store *store.Store, w http.ResponseWriter, r *h
|
||||||
provider.WriteMessage(w, "gemini", "Missing URL value")
|
provider.WriteMessage(w, "gemini", "Missing URL value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(config.Username) == 0 {
|
if len(config.Username) == 0 {
|
||||||
provider.WriteMessage(w, "gemini", "Missing Username value")
|
provider.WriteMessage(w, "gemini", "Missing Username value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(config.APIKey) == 0 {
|
if len(config.APIKey) == 0 {
|
||||||
provider.WriteMessage(w, "gemini", "Missing APIKey value")
|
provider.WriteMessage(w, "gemini", "Missing APIKey value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
creds := []byte(fmt.Sprintf("%s:%s", config.Username, config.APIKey))
|
creds := []byte(fmt.Sprintf("%s:%s", config.Username, config.APIKey))
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/users/username/%s", config.URL, config.Username), nil)
|
req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/users/username/%s", config.URL, config.Username), nil)
|
||||||
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString(creds))
|
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString(creds))
|
||||||
|
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
res, err := client.Do(req)
|
res, err := client.Do(req)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
provider.WriteError(w, "gemini", err)
|
provider.WriteError(w, "gemini", err)
|
||||||
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
provider.WriteForbidden(w)
|
provider.WriteForbidden(w)
|
||||||
return
|
return
|
||||||
|
@ -213,9 +207,9 @@ func auth(ctx *provider.Context, store *store.Store, w http.ResponseWriter, r *h
|
||||||
|
|
||||||
dec := json.NewDecoder(res.Body)
|
dec := json.NewDecoder(res.Body)
|
||||||
err = dec.Decode(&g)
|
err = dec.Decode(&g)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
provider.WriteError(w, "gemini", err)
|
provider.WriteError(w, "gemini", err)
|
||||||
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -324,7 +324,7 @@ const renderTemplate = `
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bordered no-width"><a href="{{ $app }}/browse/{{ $item.Key }}">{{ $item.Key }} </a></td>
|
<td class="bordered no-width"><a href="{{ $app }}/browse/{{ $item.Key }}">{{ $item.Key }} </a></td>
|
||||||
<td class="bordered no-width"><img class="section-jira-icon" src='{{ $item.Fields.Type.IconURL }}' /></td>
|
<td class="bordered no-width"><img class="section-jira-icon" src='{{ $item.Fields.Type.IconURL }}' /></td>
|
||||||
<td class="bordered no-width"><span class="badge badge-warning">{{ $item.Fields.Status.Name }}</span> </td>
|
<td class="bordered no-width"><span class="seciton-jira-status">{{ $item.Fields.Status.Name }}</span> </td>
|
||||||
<td class="bordered no-width"><img class="section-jira-icon" src='{{ $item.Fields.Priority.IconURL }}' /></td>
|
<td class="bordered no-width"><img class="section-jira-icon" src='{{ $item.Fields.Priority.IconURL }}' /></td>
|
||||||
<td class="bordered no-width">
|
<td class="bordered no-width">
|
||||||
{{range $comp := $item.Fields.Components}}
|
{{range $comp := $item.Fields.Components}}
|
||||||
|
|
|
@ -28,7 +28,7 @@ const renderTemplate = `
|
||||||
<tbody>
|
<tbody>
|
||||||
{{range $item := .Events}}
|
{{range $item := .Events}}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="bordered no-width color-gray">{{ $item.Dated }}</td>
|
<td class="bordered no-width color-gray-600">{{ $item.Dated }}</td>
|
||||||
<td class="bordered no-width">{{ $item.Severity }}</td>
|
<td class="bordered no-width">{{ $item.Severity }}</td>
|
||||||
<td class="bordered width-90">{{ $item.Message }}</td>
|
<td class="bordered width-90">{{ $item.Message }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -99,6 +99,9 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
var sp space.Space
|
var sp space.Space
|
||||||
sp.Name = model.Name
|
sp.Name = model.Name
|
||||||
|
sp.Description = model.Description
|
||||||
|
sp.Icon = model.Icon
|
||||||
|
sp.LabelID = model.LabelID
|
||||||
sp.RefID = uniqueid.Generate()
|
sp.RefID = uniqueid.Generate()
|
||||||
sp.OrgID = ctx.OrgID
|
sp.OrgID = ctx.OrgID
|
||||||
sp.UserID = ctx.UserID
|
sp.UserID = ctx.UserID
|
||||||
|
@ -673,77 +676,84 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete the space first.
|
||||||
ok := true
|
ok := true
|
||||||
ctx.Transaction, ok = h.Runtime.StartTx()
|
ctx.Transaction, ok = h.Runtime.StartTx()
|
||||||
if !ok {
|
if !ok {
|
||||||
response.WriteError(w, method)
|
response.WriteError(w, method)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := h.Store.Document.DeleteBySpace(ctx, id)
|
_, err := h.Store.Space.Delete(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.Runtime.Rollback(ctx.Transaction)
|
h.Runtime.Rollback(ctx.Transaction)
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Runtime.Commit(ctx.Transaction)
|
||||||
|
|
||||||
|
// Delete data associated with this space.
|
||||||
|
ctx.Transaction, ok = h.Runtime.StartTx()
|
||||||
|
if !ok {
|
||||||
|
response.WriteError(w, method)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = h.Store.Document.DeleteBySpace(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
h.Runtime.Rollback(ctx.Transaction)
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = h.Store.Permission.DeleteSpacePermissions(ctx, id)
|
_, err = h.Store.Permission.DeleteSpacePermissions(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.Runtime.Rollback(ctx.Transaction)
|
h.Runtime.Rollback(ctx.Transaction)
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove category permissions
|
|
||||||
_, err = h.Store.Permission.DeleteSpaceCategoryPermissions(ctx, id)
|
_, err = h.Store.Permission.DeleteSpaceCategoryPermissions(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.Runtime.Rollback(ctx.Transaction)
|
h.Runtime.Rollback(ctx.Transaction)
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = h.Store.Category.DeleteBySpace(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
h.Runtime.Rollback(ctx.Transaction)
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = h.Store.Pin.DeletePinnedSpace(ctx, id)
|
_, err = h.Store.Pin.DeletePinnedSpace(ctx, id)
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
h.Runtime.Rollback(ctx.Transaction)
|
h.Runtime.Rollback(ctx.Transaction)
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove category and members for space
|
|
||||||
_, err = h.Store.Category.DeleteBySpace(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
h.Runtime.Rollback(ctx.Transaction)
|
|
||||||
response.WriteServerError(w, method, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = h.Store.Space.Delete(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
h.Runtime.Rollback(ctx.Transaction)
|
|
||||||
response.WriteServerError(w, method, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close out the delete process
|
|
||||||
h.Runtime.Commit(ctx.Transaction)
|
h.Runtime.Commit(ctx.Transaction)
|
||||||
|
|
||||||
// Record this action.
|
// Record this action.
|
||||||
ctx.Transaction, ok = h.Runtime.StartTx()
|
ctx.Transaction, ok = h.Runtime.StartTx()
|
||||||
if !ok {
|
if !ok {
|
||||||
response.WriteError(w, method)
|
response.WriteError(w, method)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
err = h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
||||||
SpaceID: id,
|
SpaceID: id,
|
||||||
SourceType: activity.SourceTypeSpace,
|
SourceType: activity.SourceTypeSpace,
|
||||||
ActivityType: activity.TypeDeleted})
|
ActivityType: activity.TypeDeleted})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.Runtime.Rollback(ctx.Transaction)
|
h.Runtime.Rollback(ctx.Transaction)
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
h.Runtime.Commit(ctx.Transaction)
|
h.Runtime.Commit(ctx.Transaction)
|
||||||
|
|
||||||
h.Store.Audit.Record(ctx, audit.EventTypeSpaceDelete)
|
h.Store.Audit.Record(ctx, audit.EventTypeSpaceDelete)
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,15 @@ type Store struct {
|
||||||
|
|
||||||
// Add adds new folder into the store.
|
// Add adds new folder into the store.
|
||||||
func (s Store) Add(ctx domain.RequestContext, sp space.Space) (err error) {
|
func (s Store) Add(ctx domain.RequestContext, sp space.Space) (err error) {
|
||||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_space (c_refid, c_name, c_orgid, c_userid, c_type, c_lifecycle, c_likes, c_created, c_revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"),
|
_, err = ctx.Transaction.Exec(s.Bind(`
|
||||||
sp.RefID, sp.Name, sp.OrgID, sp.UserID, sp.Type, sp.Lifecycle, sp.Likes, sp.Created, sp.Revised)
|
INSERT INTO dmz_space
|
||||||
|
(c_refid, c_name, c_orgid, c_userid, c_type, c_lifecycle,
|
||||||
|
c_likes, c_icon, c_desc, c_count_category, c_count_content,
|
||||||
|
c_labelid, c_created, c_revised)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
|
||||||
|
sp.RefID, sp.Name, sp.OrgID, sp.UserID, sp.Type, sp.Lifecycle, sp.Likes,
|
||||||
|
sp.Icon, sp.Description, sp.CountCategory, sp.CountContent, sp.LabelID,
|
||||||
|
sp.Created, sp.Revised)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "unable to execute insert for space")
|
err = errors.Wrap(err, "unable to execute insert for space")
|
||||||
|
@ -45,6 +52,8 @@ func (s Store) Get(ctx domain.RequestContext, id string) (sp space.Space, err er
|
||||||
err = s.Runtime.Db.Get(&sp, s.Bind(`SELECT id, c_refid AS refid,
|
err = s.Runtime.Db.Get(&sp, s.Bind(`SELECT id, c_refid AS refid,
|
||||||
c_name AS name, c_orgid AS orgid, c_userid AS userid,
|
c_name AS name, c_orgid AS orgid, c_userid AS userid,
|
||||||
c_type AS type, c_lifecycle AS lifecycle, c_likes AS likes,
|
c_type AS type, c_lifecycle AS lifecycle, c_likes AS likes,
|
||||||
|
c_icon AS icon, c_labelid AS labelid, c_desc AS description,
|
||||||
|
c_count_category As countcategory, c_count_content AS countcontent,
|
||||||
c_created AS created, c_revised AS revised
|
c_created AS created, c_revised AS revised
|
||||||
FROM dmz_space
|
FROM dmz_space
|
||||||
WHERE c_orgid=? and c_refid=?`),
|
WHERE c_orgid=? and c_refid=?`),
|
||||||
|
@ -62,6 +71,8 @@ func (s Store) PublicSpaces(ctx domain.RequestContext, orgID string) (sp []space
|
||||||
qry := s.Bind(`SELECT id, c_refid AS refid,
|
qry := s.Bind(`SELECT id, c_refid AS refid,
|
||||||
c_name AS name, c_orgid AS orgid, c_userid AS userid,
|
c_name AS name, c_orgid AS orgid, c_userid AS userid,
|
||||||
c_type AS type, c_lifecycle AS lifecycle, c_likes AS likes,
|
c_type AS type, c_lifecycle AS lifecycle, c_likes AS likes,
|
||||||
|
c_icon AS icon, c_labelid AS labelid, c_desc AS description,
|
||||||
|
c_count_category AS countcategory, c_count_content AS countcontent,
|
||||||
c_created AS created, c_revised AS revised
|
c_created AS created, c_revised AS revised
|
||||||
FROM dmz_space
|
FROM dmz_space
|
||||||
WHERE c_orgid=? AND c_type=1`)
|
WHERE c_orgid=? AND c_type=1`)
|
||||||
|
@ -85,6 +96,8 @@ func (s Store) GetViewable(ctx domain.RequestContext) (sp []space.Space, err err
|
||||||
q := s.Bind(`SELECT id, c_refid AS refid,
|
q := s.Bind(`SELECT id, c_refid AS refid,
|
||||||
c_name AS name, c_orgid AS orgid, c_userid AS userid,
|
c_name AS name, c_orgid AS orgid, c_userid AS userid,
|
||||||
c_type AS type, c_lifecycle AS lifecycle, c_likes AS likes,
|
c_type AS type, c_lifecycle AS lifecycle, c_likes AS likes,
|
||||||
|
c_icon AS icon, c_labelid AS labelid, c_desc AS description,
|
||||||
|
c_count_category AS countcategory, c_count_content AS countcontent,
|
||||||
c_created AS created, c_revised AS revised
|
c_created AS created, c_revised AS revised
|
||||||
FROM dmz_space
|
FROM dmz_space
|
||||||
WHERE c_orgid=? AND c_refid IN
|
WHERE c_orgid=? AND c_refid IN
|
||||||
|
@ -122,14 +135,18 @@ func (s Store) AdminList(ctx domain.RequestContext) (sp []space.Space, err error
|
||||||
SELECT id, c_refid AS refid,
|
SELECT id, c_refid AS refid,
|
||||||
c_name AS name, c_orgid AS orgid, c_userid AS userid,
|
c_name AS name, c_orgid AS orgid, c_userid AS userid,
|
||||||
c_type AS type, c_lifecycle AS lifecycle, c_likes AS likes,
|
c_type AS type, c_lifecycle AS lifecycle, c_likes AS likes,
|
||||||
c_created AS created, c_revised AS revised
|
c_created AS created, c_revised AS revised,
|
||||||
|
c_icon AS icon, c_labelid AS labelid, c_desc AS description,
|
||||||
|
c_count_category AS countcategory, c_count_content AS countcontent
|
||||||
FROM dmz_space
|
FROM dmz_space
|
||||||
WHERE c_orgid=? AND (c_type=? OR c_type=?)
|
WHERE c_orgid=? AND (c_type=? OR c_type=?)
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT id, c_refid AS refid,
|
SELECT id, c_refid AS refid,
|
||||||
c_name AS name, c_orgid AS orgid, c_userid AS userid,
|
c_name AS name, c_orgid AS orgid, c_userid AS userid,
|
||||||
c_type AS type, c_lifecycle AS lifecycle, c_likes AS likes,
|
c_type AS type, c_lifecycle AS lifecycle, c_likes AS likes,
|
||||||
c_created AS created, c_revised AS revised
|
c_created AS created, c_revised AS revised,
|
||||||
|
c_icon AS icon, c_labelid AS labelid, c_desc AS description,
|
||||||
|
c_count_category AS countcategory, c_count_content AS countcontent
|
||||||
FROM dmz_space
|
FROM dmz_space
|
||||||
WHERE c_orgid=? AND (c_type=? OR c_type=?) AND c_refid NOT IN
|
WHERE c_orgid=? AND (c_type=? OR c_type=?) AND c_refid NOT IN
|
||||||
(SELECT c_refid FROM dmz_permission WHERE c_orgid=? AND c_action='own')
|
(SELECT c_refid FROM dmz_permission WHERE c_orgid=? AND c_action='own')
|
||||||
|
@ -154,7 +171,13 @@ func (s Store) AdminList(ctx domain.RequestContext) (sp []space.Space, err error
|
||||||
func (s Store) Update(ctx domain.RequestContext, sp space.Space) (err error) {
|
func (s Store) Update(ctx domain.RequestContext, sp space.Space) (err error) {
|
||||||
sp.Revised = time.Now().UTC()
|
sp.Revised = time.Now().UTC()
|
||||||
|
|
||||||
_, err = ctx.Transaction.NamedExec("UPDATE dmz_space SET c_name=:name, c_type=:type, c_lifecycle=:lifecycle, c_userid=:userid, c_likes=:likes, c_revised=:revised WHERE c_orgid=:orgid AND c_refid=:refid", &sp)
|
_, err = ctx.Transaction.NamedExec(`
|
||||||
|
UPDATE dmz_space
|
||||||
|
SET c_name=:name, c_type=:type, c_lifecycle=:lifecycle, c_userid=:userid,
|
||||||
|
c_likes=:likes, c_desc=:description, c_labelid=:labelid, c_icon=:icon,
|
||||||
|
c_count_category=:countcategory, c_count_content=:countcontent,
|
||||||
|
c_revised=:revised
|
||||||
|
WHERE c_orgid=:orgid AND c_refid=:refid`, &sp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute update for space %s", sp.RefID))
|
err = errors.Wrap(err, fmt.Sprintf("unable to execute update for space %s", sp.RefID))
|
||||||
}
|
}
|
||||||
|
@ -166,3 +189,55 @@ func (s Store) Update(ctx domain.RequestContext, sp space.Space) (err error) {
|
||||||
func (s Store) Delete(ctx domain.RequestContext, id string) (rows int64, err error) {
|
func (s Store) Delete(ctx domain.RequestContext, id string) (rows int64, err error) {
|
||||||
return s.DeleteConstrained(ctx.Transaction, "dmz_space", ctx.OrgID, id)
|
return s.DeleteConstrained(ctx.Transaction, "dmz_space", ctx.OrgID, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IncrementCategoryCount increments usage counter for space category.
|
||||||
|
func (s Store) IncrementCategoryCount(ctx domain.RequestContext, spaceID string) (err error) {
|
||||||
|
_, err = ctx.Transaction.Exec(s.Bind(`UPDATE dmz_space SET
|
||||||
|
c_count_category=c_count_category+1, c_revised=? WHERE c_orgid=? AND c_refid=?`),
|
||||||
|
time.Now().UTC(), ctx.OrgID, spaceID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "execute increment category count")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecrementCategoryCount decrements usage counter for space category.
|
||||||
|
func (s Store) DecrementCategoryCount(ctx domain.RequestContext, spaceID string) (err error) {
|
||||||
|
_, err = ctx.Transaction.Exec(s.Bind(`UPDATE dmz_space SET
|
||||||
|
c_count_category=c_count_category-1, c_revised=? WHERE c_orgid=? AND c_refid=?`),
|
||||||
|
time.Now().UTC(), ctx.OrgID, spaceID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "execute decrement category count")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncrementContentCount increments usage counter for space category.
|
||||||
|
func (s Store) IncrementContentCount(ctx domain.RequestContext, spaceID string) (err error) {
|
||||||
|
_, err = ctx.Transaction.Exec(s.Bind(`UPDATE dmz_space SET
|
||||||
|
c_count_content=c_count_content+1, c_revised=? WHERE c_orgid=? AND c_refid=?`),
|
||||||
|
time.Now().UTC(), ctx.OrgID, spaceID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "execute increment content count")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecrementContentCount decrements usage counter for space category.
|
||||||
|
func (s Store) DecrementContentCount(ctx domain.RequestContext, spaceID string) (err error) {
|
||||||
|
_, err = ctx.Transaction.Exec(s.Bind(`UPDATE dmz_space SET
|
||||||
|
c_count_content=c_count_content-1, c_revised=? WHERE c_orgid=? AND c_refid=?`),
|
||||||
|
time.Now().UTC(), ctx.OrgID, spaceID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "execute decrement category count")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/documize/community/model/category"
|
"github.com/documize/community/model/category"
|
||||||
"github.com/documize/community/model/doc"
|
"github.com/documize/community/model/doc"
|
||||||
"github.com/documize/community/model/group"
|
"github.com/documize/community/model/group"
|
||||||
|
"github.com/documize/community/model/label"
|
||||||
"github.com/documize/community/model/link"
|
"github.com/documize/community/model/link"
|
||||||
"github.com/documize/community/model/org"
|
"github.com/documize/community/model/org"
|
||||||
"github.com/documize/community/model/page"
|
"github.com/documize/community/model/page"
|
||||||
|
@ -42,6 +43,7 @@ type Store struct {
|
||||||
Document DocumentStorer
|
Document DocumentStorer
|
||||||
Group GroupStorer
|
Group GroupStorer
|
||||||
Link LinkStorer
|
Link LinkStorer
|
||||||
|
Label LabelStorer
|
||||||
Meta MetaStorer
|
Meta MetaStorer
|
||||||
Organization OrganizationStorer
|
Organization OrganizationStorer
|
||||||
Page PageStorer
|
Page PageStorer
|
||||||
|
@ -62,6 +64,10 @@ type SpaceStorer interface {
|
||||||
Update(ctx domain.RequestContext, sp space.Space) (err error)
|
Update(ctx domain.RequestContext, sp space.Space) (err error)
|
||||||
Delete(ctx domain.RequestContext, id string) (rows int64, err error)
|
Delete(ctx domain.RequestContext, id string) (rows int64, err error)
|
||||||
AdminList(ctx domain.RequestContext) (sp []space.Space, err error)
|
AdminList(ctx domain.RequestContext) (sp []space.Space, err error)
|
||||||
|
IncrementCategoryCount(ctx domain.RequestContext, spaceID string) (err error)
|
||||||
|
DecrementCategoryCount(ctx domain.RequestContext, spaceID string) (err error)
|
||||||
|
IncrementContentCount(ctx domain.RequestContext, spaceID string) (err error)
|
||||||
|
DecrementContentCount(ctx domain.RequestContext, spaceID string) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CategoryStorer defines required methods for category and category membership management
|
// CategoryStorer defines required methods for category and category membership management
|
||||||
|
@ -148,6 +154,8 @@ type OrganizationStorer interface {
|
||||||
RemoveOrganization(ctx domain.RequestContext, orgID string) (err error)
|
RemoveOrganization(ctx domain.RequestContext, orgID string) (err error)
|
||||||
UpdateAuthConfig(ctx domain.RequestContext, org org.Organization) (err error)
|
UpdateAuthConfig(ctx domain.RequestContext, org org.Organization) (err error)
|
||||||
CheckDomain(ctx domain.RequestContext, domain string) string
|
CheckDomain(ctx domain.RequestContext, domain string) string
|
||||||
|
Logo(ctx domain.RequestContext, domain string) (l []byte, err error)
|
||||||
|
UploadLogo(ctx domain.RequestContext, l []byte) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PinStorer defines required methods for pin management
|
// PinStorer defines required methods for pin management
|
||||||
|
@ -285,6 +293,7 @@ type GroupStorer interface {
|
||||||
GetMembers(ctx domain.RequestContext) (r []group.Record, err error)
|
GetMembers(ctx domain.RequestContext) (r []group.Record, err error)
|
||||||
JoinGroup(ctx domain.RequestContext, groupID, userID string) (err error)
|
JoinGroup(ctx domain.RequestContext, groupID, userID string) (err error)
|
||||||
LeaveGroup(ctx domain.RequestContext, groupID, userID string) (err error)
|
LeaveGroup(ctx domain.RequestContext, groupID, userID string) (err error)
|
||||||
|
RemoveUserGroups(ctx domain.RequestContext, userID string) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetaStorer provide specialist methods for global administrators.
|
// MetaStorer provide specialist methods for global administrators.
|
||||||
|
@ -295,3 +304,12 @@ type MetaStorer interface {
|
||||||
Attachments(ctx domain.RequestContext, docID string) (a []attachment.Attachment, err error)
|
Attachments(ctx domain.RequestContext, docID string) (a []attachment.Attachment, err error)
|
||||||
SearchIndexCount(ctx domain.RequestContext) (c int, err error)
|
SearchIndexCount(ctx domain.RequestContext) (c int, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LabelStorer defines required methods for space label management
|
||||||
|
type LabelStorer interface {
|
||||||
|
Add(ctx domain.RequestContext, l label.Label) (err error)
|
||||||
|
Get(ctx domain.RequestContext) (l []label.Label, err error)
|
||||||
|
Update(ctx domain.RequestContext, l label.Label) (err error)
|
||||||
|
Delete(ctx domain.RequestContext, id string) (rows int64, err error)
|
||||||
|
RemoveReference(ctx domain.RequestContext, spaceID string) (err error)
|
||||||
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ import (
|
||||||
"github.com/documize/community/model/doc"
|
"github.com/documize/community/model/doc"
|
||||||
"github.com/documize/community/model/page"
|
"github.com/documize/community/model/page"
|
||||||
pm "github.com/documize/community/model/permission"
|
pm "github.com/documize/community/model/permission"
|
||||||
"github.com/documize/community/model/template"
|
// "github.com/documize/community/model/template"
|
||||||
"github.com/documize/community/model/workflow"
|
"github.com/documize/community/model/workflow"
|
||||||
uuid "github.com/nu7hatch/gouuid"
|
uuid "github.com/nu7hatch/gouuid"
|
||||||
)
|
)
|
||||||
|
@ -66,23 +66,23 @@ func (h *Handler) SavedList(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
templates := []template.Template{}
|
// templates := []template.Template{}
|
||||||
|
|
||||||
for _, d := range documents {
|
// for _, d := range documents {
|
||||||
var t = template.Template{}
|
// var t = template.Template{}
|
||||||
t.ID = d.RefID
|
// t.ID = d.RefID
|
||||||
t.Title = d.Name
|
// t.Title = d.Name
|
||||||
t.Description = d.Excerpt
|
// t.Description = d.Excerpt
|
||||||
t.Author = ""
|
// t.Author = ""
|
||||||
t.Dated = d.Created
|
// t.Dated = d.Created
|
||||||
t.Type = template.TypePrivate
|
// t.Type = template.TypePrivate
|
||||||
|
|
||||||
if d.SpaceID == spaceID {
|
// if d.SpaceID == spaceID {
|
||||||
templates = append(templates, t)
|
// templates = append(templates, t)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
response.WriteJSON(w, templates)
|
response.WriteJSON(w, documents)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveAs saves existing document as a template.
|
// SaveAs saves existing document as a template.
|
||||||
|
@ -245,6 +245,14 @@ func (h *Handler) SaveAs(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = h.Store.Space.IncrementContentCount(ctx, doc.SpaceID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Transaction.Rollback()
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Commit and return new document template
|
// Commit and return new document template
|
||||||
ctx.Transaction.Commit()
|
ctx.Transaction.Commit()
|
||||||
|
|
||||||
|
@ -430,6 +438,14 @@ func (h *Handler) Use(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = h.Store.Space.IncrementContentCount(ctx, d.SpaceID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Transaction.Rollback()
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Transaction.Commit()
|
ctx.Transaction.Commit()
|
||||||
|
|
||||||
h.Store.Audit.Record(ctx, audit.EventTypeTemplateUse)
|
h.Store.Audit.Record(ctx, audit.EventTypeTemplateUse)
|
||||||
|
|
|
@ -405,7 +405,7 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove all associated roles for this user
|
// Remove user's permissions
|
||||||
_, err = h.Store.Permission.DeleteUserPermissions(ctx, userID)
|
_, err = h.Store.Permission.DeleteUserPermissions(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
|
@ -414,6 +414,15 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove all user groups memberships
|
||||||
|
err = h.Store.Group.RemoveUserGroups(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Transaction.Rollback()
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Transaction.Commit()
|
ctx.Transaction.Commit()
|
||||||
|
|
||||||
h.Store.Audit.Record(ctx, audit.EventTypeUserDelete)
|
h.Store.Audit.Record(ctx, audit.EventTypeUserDelete)
|
||||||
|
|
|
@ -42,6 +42,7 @@ func AttachUserAccounts(ctx domain.RequestContext, s store.Store, orgID string,
|
||||||
u.Active = false
|
u.Active = false
|
||||||
u.ViewUsers = false
|
u.ViewUsers = false
|
||||||
u.Analytics = false
|
u.Analytics = false
|
||||||
|
u.Theme = ""
|
||||||
|
|
||||||
for _, account := range u.Accounts {
|
for _, account := range u.Accounts {
|
||||||
if account.OrgID == orgID {
|
if account.OrgID == orgID {
|
||||||
|
@ -50,6 +51,7 @@ func AttachUserAccounts(ctx domain.RequestContext, s store.Store, orgID string,
|
||||||
u.Active = account.Active
|
u.Active = account.Active
|
||||||
u.ViewUsers = account.Users
|
u.ViewUsers = account.Users
|
||||||
u.Analytics = account.Analytics
|
u.Analytics = account.Analytics
|
||||||
|
u.Theme = account.Theme
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
package boot
|
package boot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/documize/community/core/database"
|
"github.com/documize/community/core/database"
|
||||||
|
@ -57,28 +58,37 @@ func InitRuntime(r *env.Runtime, s *store.Store) bool {
|
||||||
storage.SetMySQLProvider(r, s)
|
storage.SetMySQLProvider(r, s)
|
||||||
case "postgresql":
|
case "postgresql":
|
||||||
storage.SetPostgreSQLProvider(r, s)
|
storage.SetPostgreSQLProvider(r, s)
|
||||||
case "mssql":
|
// case "mssql":
|
||||||
// storage.SetSQLServerProvider(r, s)
|
// storage.SetSQLServerProvider(r, s)
|
||||||
|
default:
|
||||||
|
r.Log.Infof("Unsupported database type: %s", r.Flags.DBType)
|
||||||
|
r.Log.Info("Documize supports the following database types: mysql | mariadb | percona | postgresql")
|
||||||
|
os.Exit(1)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open connection to database
|
// Open connection to database
|
||||||
db, err := sqlx.Open(r.StoreProvider.DriverName(), r.StoreProvider.MakeConnectionString()) //r.Flags.DBConn
|
db, err := sqlx.Open(r.StoreProvider.DriverName(), r.StoreProvider.MakeConnectionString()) //r.Flags.DBConn
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Log.Error("unable to open database", err)
|
r.Log.Error("Unable to open database", err)
|
||||||
|
os.Exit(1)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Database handle
|
// Set the database handle
|
||||||
r.Db = db
|
r.Db = db
|
||||||
|
|
||||||
// Database connection defaults
|
// Set connection defaults
|
||||||
r.Db.SetMaxIdleConns(30)
|
r.Db.SetMaxIdleConns(30)
|
||||||
r.Db.SetMaxOpenConns(100)
|
r.Db.SetMaxOpenConns(100)
|
||||||
r.Db.SetConnMaxLifetime(time.Second * 14400)
|
r.Db.SetConnMaxLifetime(time.Second * 14400)
|
||||||
|
|
||||||
// Database good?
|
// Ping verifies a connection to the database is still alive, establishing a connection if necessary.
|
||||||
err = r.Db.Ping()
|
err = r.Db.Ping()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Log.Error("unable to connect to database - "+r.StoreProvider.Example(), err)
|
r.Log.Error("Unable to connect to database", err)
|
||||||
|
r.Log.Info(r.StoreProvider.Example())
|
||||||
|
os.Exit(1)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,10 +39,10 @@ func main() {
|
||||||
|
|
||||||
// product details
|
// product details
|
||||||
rt.Product = domain.Product{}
|
rt.Product = domain.Product{}
|
||||||
rt.Product.Major = "1"
|
rt.Product.Major = "2"
|
||||||
rt.Product.Minor = "76"
|
rt.Product.Minor = "0"
|
||||||
rt.Product.Patch = "2"
|
rt.Product.Patch = "0"
|
||||||
rt.Product.Revision = 181121115333
|
rt.Product.Revision = 190115203818
|
||||||
rt.Product.Version = fmt.Sprintf("%s.%s.%s", rt.Product.Major, rt.Product.Minor, rt.Product.Patch)
|
rt.Product.Version = fmt.Sprintf("%s.%s.%s", rt.Product.Major, rt.Product.Minor, rt.Product.Patch)
|
||||||
rt.Product.Edition = domain.CommunityEdition
|
rt.Product.Edition = domain.CommunityEdition
|
||||||
rt.Product.Title = fmt.Sprintf("%s Edition", rt.Product.Edition)
|
rt.Product.Title = fmt.Sprintf("%s Edition", rt.Product.Edition)
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
category "github.com/documize/community/domain/category"
|
category "github.com/documize/community/domain/category"
|
||||||
document "github.com/documize/community/domain/document"
|
document "github.com/documize/community/domain/document"
|
||||||
group "github.com/documize/community/domain/group"
|
group "github.com/documize/community/domain/group"
|
||||||
|
label "github.com/documize/community/domain/label"
|
||||||
link "github.com/documize/community/domain/link"
|
link "github.com/documize/community/domain/link"
|
||||||
meta "github.com/documize/community/domain/meta"
|
meta "github.com/documize/community/domain/meta"
|
||||||
org "github.com/documize/community/domain/organization"
|
org "github.com/documize/community/domain/organization"
|
||||||
|
@ -149,6 +150,11 @@ func SetMySQLProvider(r *env.Runtime, s *store.Store) {
|
||||||
userStore := user.Store{}
|
userStore := user.Store{}
|
||||||
userStore.Runtime = r
|
userStore.Runtime = r
|
||||||
s.User = userStore
|
s.User = userStore
|
||||||
|
|
||||||
|
// Space Label
|
||||||
|
labelStore := label.Store{}
|
||||||
|
labelStore.Runtime = r
|
||||||
|
s.Label = labelStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// MySQLProvider supports MySQL 5.7.x and 8.0.x versions.
|
// MySQLProvider supports MySQL 5.7.x and 8.0.x versions.
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
category "github.com/documize/community/domain/category"
|
category "github.com/documize/community/domain/category"
|
||||||
document "github.com/documize/community/domain/document"
|
document "github.com/documize/community/domain/document"
|
||||||
group "github.com/documize/community/domain/group"
|
group "github.com/documize/community/domain/group"
|
||||||
|
label "github.com/documize/community/domain/label"
|
||||||
link "github.com/documize/community/domain/link"
|
link "github.com/documize/community/domain/link"
|
||||||
meta "github.com/documize/community/domain/meta"
|
meta "github.com/documize/community/domain/meta"
|
||||||
org "github.com/documize/community/domain/organization"
|
org "github.com/documize/community/domain/organization"
|
||||||
|
@ -147,6 +148,11 @@ func SetPostgreSQLProvider(r *env.Runtime, s *store.Store) {
|
||||||
userStore := user.Store{}
|
userStore := user.Store{}
|
||||||
userStore.Runtime = r
|
userStore.Runtime = r
|
||||||
s.User = userStore
|
s.User = userStore
|
||||||
|
|
||||||
|
// Space Label
|
||||||
|
labelStore := label.Store{}
|
||||||
|
labelStore.Runtime = r
|
||||||
|
s.Label = labelStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type returns name of provider
|
// Type returns name of provider
|
||||||
|
|
2923
embed/bindata.go
2923
embed/bindata.go
File diff suppressed because one or more lines are too long
|
@ -4,3 +4,25 @@ public/tinymce
|
||||||
public/codemirror/**
|
public/codemirror/**
|
||||||
public/codemirror/
|
public/codemirror/
|
||||||
public/codemirror
|
public/codemirror
|
||||||
|
|
||||||
|
# unconventional js
|
||||||
|
/blueprints/*/files/
|
||||||
|
/vendor/
|
||||||
|
|
||||||
|
# compiled output
|
||||||
|
/dist/
|
||||||
|
/dist-prod/
|
||||||
|
/tmp/
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/bower_components/
|
||||||
|
/node_modules/
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/coverage/
|
||||||
|
!.*
|
||||||
|
|
||||||
|
# ember-try
|
||||||
|
/.node_modules.ember-try/
|
||||||
|
/bower.json.ember-try
|
||||||
|
/package.json.ember-try
|
||||||
|
|
|
@ -20,8 +20,10 @@ module.exports = {
|
||||||
// node files
|
// node files
|
||||||
{
|
{
|
||||||
files: [
|
files: [
|
||||||
'testem.js',
|
'.eslintrc.js',
|
||||||
|
'.template-lintrc.js',
|
||||||
'ember-cli-build.js',
|
'ember-cli-build.js',
|
||||||
|
'testem.js',
|
||||||
'config/**/*.js'
|
'config/**/*.js'
|
||||||
],
|
],
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
|
@ -60,7 +62,6 @@ module.exports = {
|
||||||
"userLogin": true,
|
"userLogin": true,
|
||||||
"Keycloak": true,
|
"Keycloak": true,
|
||||||
"slug": true,
|
"slug": true,
|
||||||
"interact": true,
|
"iziToast": true
|
||||||
"velocity": true
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
22
gui/.gitignore
vendored
22
gui/.gitignore
vendored
|
@ -1,18 +1,24 @@
|
||||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
# compiled output
|
# compiled output
|
||||||
/dist
|
/dist/
|
||||||
/dist-prod
|
/tmp/
|
||||||
/tmp
|
/dist-prod/
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
/node_modules
|
/bower_components/
|
||||||
/bower_components
|
/node_modules/
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
/.sass-cache
|
/.sass-cache
|
||||||
/connect.lock
|
/connect.lock
|
||||||
/coverage/*
|
/coverage/
|
||||||
/libpeerconnection.log
|
/libpeerconnection.log
|
||||||
npm-debug.log*
|
/npm-debug.log*
|
||||||
testem.log
|
/testem.log
|
||||||
|
/yarn-error.log
|
||||||
|
|
||||||
|
# ember-try
|
||||||
|
/.node_modules.ember-try/
|
||||||
|
/bower.json.ember-try
|
||||||
|
/package.json.ember-try
|
||||||
|
|
19
gui/.template-lintrc.js
Normal file
19
gui/.template-lintrc.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
extends: 'recommended',
|
||||||
|
rules: {
|
||||||
|
'attribute-indentation': false,
|
||||||
|
'block-indentation': false,
|
||||||
|
'img-alt-attributes': false,
|
||||||
|
'link-rel-noopener': false,
|
||||||
|
'no-inline-styles': false,
|
||||||
|
'no-invalid-interactive': false,
|
||||||
|
'no-nested-interactive': false,
|
||||||
|
'no-triple-curlies': false,
|
||||||
|
'style-concatenation': false,
|
||||||
|
'simple-unless': false,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rules.md
|
|
@ -25,5 +25,6 @@ install:
|
||||||
- yarn install --non-interactive
|
- yarn install --non-interactive
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- yarn lint:js
|
- npm run lint:hbs
|
||||||
- yarn test
|
- npm run lint:js
|
||||||
|
- npm test
|
||||||
|
|
|
@ -34,6 +34,12 @@ Make use of the many generators for code, try `ember help generate` for more det
|
||||||
* `ember test`
|
* `ember test`
|
||||||
* `ember test --server`
|
* `ember test --server`
|
||||||
|
|
||||||
|
### Linting
|
||||||
|
|
||||||
|
* `npm run lint:hbs`
|
||||||
|
* `npm run lint:js`
|
||||||
|
* `npm run lint:js -- --fix`
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
* `ember build` (development)
|
* `ember build` (development)
|
||||||
|
|
|
@ -141,15 +141,13 @@ export default Component.extend(ModalMixin, Notifier, {
|
||||||
},
|
},
|
||||||
|
|
||||||
onLDAPPreview() {
|
onLDAPPreview() {
|
||||||
this.showWait();
|
|
||||||
|
|
||||||
let config = this.get('ldapConfig');
|
let config = this.get('ldapConfig');
|
||||||
config.serverPort = parseInt(this.get('ldapConfig.serverPort'));
|
config.serverPort = parseInt(this.get('ldapConfig.serverPort'));
|
||||||
|
|
||||||
this.get('globalSvc').previewLDAP(config).then((preview) => {
|
this.get('globalSvc').previewLDAP(config).then((preview) => {
|
||||||
this.set('ldapPreview', preview);
|
this.set('ldapPreview', preview);
|
||||||
this.modalOpen("#ldap-preview-modal", {"show": true});
|
this.modalOpen("#ldap-preview-modal", {"show": true});
|
||||||
this.showDone();
|
this.notifySuccess('Saved');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -231,8 +229,6 @@ export default Component.extend(ModalMixin, Notifier, {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showWait();
|
|
||||||
|
|
||||||
let data = { authProvider: provider, authConfig: JSON.stringify(config) };
|
let data = { authProvider: provider, authConfig: JSON.stringify(config) };
|
||||||
|
|
||||||
this.get('onSave')(data).then(() => {
|
this.get('onSave')(data).then(() => {
|
||||||
|
@ -274,7 +270,7 @@ export default Component.extend(ModalMixin, Notifier, {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showDone();
|
this.notifySuccess('Saved');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,6 @@ export default Component.extend(Notifier, Modal, {
|
||||||
},
|
},
|
||||||
|
|
||||||
doBackup() {
|
doBackup() {
|
||||||
this.showWait();
|
|
||||||
this.set('backupFilename', '');
|
this.set('backupFilename', '');
|
||||||
this.set('backupSuccess', false);
|
this.set('backupSuccess', false);
|
||||||
this.set('backupFailed', false);
|
this.set('backupFailed', false);
|
||||||
|
@ -69,13 +68,13 @@ export default Component.extend(Notifier, Modal, {
|
||||||
let spec = this.get('backupSpec');
|
let spec = this.get('backupSpec');
|
||||||
|
|
||||||
this.get('onBackup')(spec).then((filename) => {
|
this.get('onBackup')(spec).then((filename) => {
|
||||||
this.showDone();
|
this.notifySuccess('Completed');
|
||||||
this.set('backupLabel', 'Start Backup');
|
this.set('backupLabel', 'Start Backup');
|
||||||
this.set('backupSuccess', true);
|
this.set('backupSuccess', true);
|
||||||
this.set('backupFilename', filename);
|
this.set('backupFilename', filename);
|
||||||
this.set('backupRunning', false);
|
this.set('backupRunning', false);
|
||||||
}, ()=> {
|
}, ()=> {
|
||||||
this.showDone();
|
this.notifyError('Failed');
|
||||||
this.set('backupLabel', 'Run Backup');
|
this.set('backupLabel', 'Run Backup');
|
||||||
this.set('backupFailed', true);
|
this.set('backupFailed', true);
|
||||||
this.set('backupRunning', false);
|
this.set('backupRunning', false);
|
||||||
|
@ -134,7 +133,6 @@ export default Component.extend(Notifier, Modal, {
|
||||||
}
|
}
|
||||||
|
|
||||||
// start restore process
|
// start restore process
|
||||||
this.showWait();
|
|
||||||
this.set('restoreButtonLabel', 'Please wait, restore running...');
|
this.set('restoreButtonLabel', 'Please wait, restore running...');
|
||||||
this.set('restoreSuccess', false);
|
this.set('restoreSuccess', false);
|
||||||
this.set('restoreFailed', false);
|
this.set('restoreFailed', false);
|
||||||
|
@ -147,12 +145,12 @@ export default Component.extend(Notifier, Modal, {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.get('onRestore')(spec, filedata).then(() => {
|
this.get('onRestore')(spec, filedata).then(() => {
|
||||||
this.showDone();
|
this.notifySuccess('Completed');
|
||||||
this.set('backupLabel', 'Restore');
|
this.set('backupLabel', 'Restore');
|
||||||
this.set('restoreSuccess', true);
|
this.set('restoreSuccess', true);
|
||||||
this.get('router').transitionTo('auth.logout');
|
this.get('router').transitionTo('auth.logout');
|
||||||
}, ()=> {
|
}, ()=> {
|
||||||
this.showDone();
|
this.notifyError('Failed');
|
||||||
this.set('restorbackupLabel', 'Restore');
|
this.set('restorbackupLabel', 'Restore');
|
||||||
this.set('restoreFailed', true);
|
this.set('restoreFailed', true);
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,10 +13,12 @@ import $ from 'jquery';
|
||||||
import { empty, and } from '@ember/object/computed';
|
import { empty, and } from '@ember/object/computed';
|
||||||
import { isEmpty } from '@ember/utils';
|
import { isEmpty } from '@ember/utils';
|
||||||
import { set } from '@ember/object';
|
import { set } from '@ember/object';
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
import Notifier from '../../mixins/notifier';
|
import Notifier from '../../mixins/notifier';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(Notifier, {
|
export default Component.extend(Notifier, {
|
||||||
|
appMeta: service(),
|
||||||
maxTags: 3,
|
maxTags: 3,
|
||||||
titleEmpty: empty('model.general.title'),
|
titleEmpty: empty('model.general.title'),
|
||||||
messageEmpty: empty('model.general.message'),
|
messageEmpty: empty('model.general.message'),
|
||||||
|
@ -30,6 +32,51 @@ export default Component.extend(Notifier, {
|
||||||
this.set('maxTags', this.get('model.general.maxTags'));
|
this.set('maxTags', this.get('model.general.maxTags'));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
didInsertElement() {
|
||||||
|
this._super(...arguments);
|
||||||
|
|
||||||
|
let self = this;
|
||||||
|
let url = this.get('appMeta.endpoint');
|
||||||
|
let orgId = this.get('appMeta.orgId');
|
||||||
|
let uploadUrl = `${url}/organization/${orgId}/logo`;
|
||||||
|
|
||||||
|
let dzone = new Dropzone("#upload-logo > div", {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + self.get('session.authToken')
|
||||||
|
},
|
||||||
|
url: uploadUrl,
|
||||||
|
method: "post",
|
||||||
|
paramName: 'attachment',
|
||||||
|
clickable: true,
|
||||||
|
maxFilesize: 50,
|
||||||
|
parallelUploads: 1,
|
||||||
|
uploadMultiple: false,
|
||||||
|
addRemoveLinks: false,
|
||||||
|
autoProcessQueue: true,
|
||||||
|
createImageThumbnails: false,
|
||||||
|
|
||||||
|
init: function () {
|
||||||
|
this.on("success", function (/*file, response*/ ) {
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on("queuecomplete", function () {
|
||||||
|
self.notifySuccess('Logo uploaded');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on("error", function (error, msg) {
|
||||||
|
self.notifyError(msg);
|
||||||
|
self.notifyError(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dzone.on("complete", function (file) {
|
||||||
|
dzone.removeFile(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.set('drop', dzone);
|
||||||
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
change() {
|
change() {
|
||||||
const selectEl = this.$('#maxTags')[0];
|
const selectEl = this.$('#maxTags')[0];
|
||||||
|
@ -60,16 +107,23 @@ export default Component.extend(Notifier, {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.set('model.general.maxTags', this.get('maxTags'));
|
this.set('model.general.maxTags', this.get('maxTags'));
|
||||||
this.model.general.set('allowAnonymousAccess', $("#allowAnonymousAccess").prop('checked'));
|
|
||||||
|
|
||||||
this.showWait();
|
this.get('onUpdate')().then(() => {
|
||||||
|
this.notifySuccess('Saved');
|
||||||
this.get('save')().then(() => {
|
|
||||||
this.showDone();
|
|
||||||
set(this, 'titleError', false);
|
set(this, 'titleError', false);
|
||||||
set(this, 'messageError', false);
|
set(this, 'messageError', false);
|
||||||
set(this, 'conversionEndpointError', false);
|
set(this, 'conversionEndpointError', false);
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onThemeChange(theme) {
|
||||||
|
this.get('appMeta').setTheme(theme);
|
||||||
|
this.set('model.general.theme', theme);
|
||||||
|
},
|
||||||
|
|
||||||
|
onDefaultLogo() {
|
||||||
|
this.get('onDefaultLogo')(this.get('appMeta.orgId'));
|
||||||
|
this.notifySuccess('Using default logo');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -56,13 +56,12 @@ export default Component.extend(Notifier, {
|
||||||
this.set('jiraCreds.url', url.substring(0, url.length-1));
|
this.set('jiraCreds.url', url.substring(0, url.length-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showWait();
|
|
||||||
this.get('orgSvc').saveOrgSetting(orgId, 'jira', this.get('jiraCreds')).then(() => {
|
this.get('orgSvc').saveOrgSetting(orgId, 'jira', this.get('jiraCreds')).then(() => {
|
||||||
if (this.get('session.isGlobalAdmin')) {
|
if (this.get('session.isGlobalAdmin')) {
|
||||||
this.get('orgSvc').saveGlobalSetting('SECTION-TRELLO', this.get('trelloCreds'));
|
this.get('orgSvc').saveGlobalSetting('SECTION-TRELLO', this.get('trelloCreds'));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showDone();
|
this.notifySuccess('Saved');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,10 +40,8 @@ export default Component.extend(Notifier, Modals, {
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
saveLicense() {
|
saveLicense() {
|
||||||
this.showWait();
|
|
||||||
|
|
||||||
this.get('global').setLicense(this.get('license')).then(() => {
|
this.get('global').setLicense(this.get('license')).then(() => {
|
||||||
this.showDone();
|
this.notifySuccess('Saved');
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -57,7 +55,7 @@ export default Component.extend(Notifier, Modals, {
|
||||||
let comment = this.get('comment');
|
let comment = this.get('comment');
|
||||||
|
|
||||||
this.get('global').deactivate(comment).then(() => {
|
this.get('global').deactivate(comment).then(() => {
|
||||||
this.showDone();
|
this.notifySuccess('Saved');
|
||||||
this.modalOpen("#deactivation-confirmation-modal", {"show": true});
|
this.modalOpen("#deactivation-confirmation-modal", {"show": true});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,16 +10,20 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
|
import Notifier from '../../mixins/notifier';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend(Notifier, {
|
||||||
appMeta: service(),
|
appMeta: service(),
|
||||||
buttonLabel: 'Rebuild Search Index',
|
buttonLabel: 'Rebuild',
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
reindex() {
|
reindex() {
|
||||||
this.set('buttonLabel', 'Rebuilding search index...')
|
this.set('buttonLabel', 'Running...');
|
||||||
this.get('reindex')();
|
this.notifyInfo("Starting search re-index process");
|
||||||
|
this.get('reindex')(() => {
|
||||||
|
this.notifySuccess("Search re-indexing complete");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -48,13 +48,18 @@ export default Component.extend(Notifier, {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
this.showWait();
|
|
||||||
this.set('buttonText', 'Please wait...');
|
this.set('buttonText', 'Please wait...');
|
||||||
|
this.notifyInfo('Sending test email to you');
|
||||||
|
|
||||||
this.get('saveSMTP')().then((result) => {
|
this.get('saveSMTP')().then((result) => {
|
||||||
this.showDone();
|
|
||||||
this.set('buttonText', 'Save & Test');
|
this.set('buttonText', 'Save & Test');
|
||||||
this.set('testSMTP', result);
|
this.set('testSMTP', result);
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
this.notifySuccess(result.message);
|
||||||
|
} else {
|
||||||
|
this.notifyError(result.message);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,13 +33,11 @@ export default Component.extend(Notifier, Modals, {
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
this.loadData();
|
this.loadData();
|
||||||
},
|
},
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
this.deleteSpace = {
|
this.deleteSpace = {
|
||||||
id: '',
|
id: '',
|
||||||
name: ''
|
name: ''
|
||||||
|
@ -55,6 +53,7 @@ export default Component.extend(Notifier, Modals, {
|
||||||
actions: {
|
actions: {
|
||||||
onShow(id) {
|
onShow(id) {
|
||||||
this.set('deleteSpace.id', id);
|
this.set('deleteSpace.id', id);
|
||||||
|
this.modalOpen("#space-delete-modal", {"show": true}, '#delete-space-name');
|
||||||
},
|
},
|
||||||
|
|
||||||
onDelete() {
|
onDelete() {
|
||||||
|
@ -76,29 +75,28 @@ export default Component.extend(Notifier, Modals, {
|
||||||
this.set('deleteSpace.id', '');
|
this.set('deleteSpace.id', '');
|
||||||
this.set('deleteSpace.name', '');
|
this.set('deleteSpace.name', '');
|
||||||
this.loadData();
|
this.loadData();
|
||||||
|
this.notifySuccess('Deleted');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onExport() {
|
onExport() {
|
||||||
this.showWait();
|
|
||||||
|
|
||||||
let spec = {
|
let spec = {
|
||||||
spaceId: '',
|
spaceId: '',
|
||||||
data: _.pluck(this.get('folders'), 'id'),
|
data: _.pluck(this.get('folders'), 'id'),
|
||||||
filterType: 'space',
|
filterType: 'space',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.notifyInfo('Export running...');
|
||||||
|
|
||||||
this.get('documentSvc').export(spec).then((htmlExport) => {
|
this.get('documentSvc').export(spec).then((htmlExport) => {
|
||||||
this.get('browserSvc').downloadFile(htmlExport, 'documize.html');
|
this.get('browserSvc').downloadFile(htmlExport, 'documize.html');
|
||||||
this.showDone();
|
this.notifySuccess('Export completed');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onOwner(spaceId) {
|
onOwner(spaceId) {
|
||||||
this.showWait();
|
|
||||||
|
|
||||||
this.get('spaceSvc').grantOwnerPermission(spaceId).then(() => { /* jshint ignore:line */
|
this.get('spaceSvc').grantOwnerPermission(spaceId).then(() => { /* jshint ignore:line */
|
||||||
this.showDone();
|
this.notifySuccess('Added as owner');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
94
gui/app/components/customize/space-labels.js
Normal file
94
gui/app/components/customize/space-labels.js
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
import $ from 'jquery';
|
||||||
|
import Modals from '../../mixins/modal';
|
||||||
|
import Component from '@ember/component';
|
||||||
|
|
||||||
|
export default Component.extend(Modals, {
|
||||||
|
labelName: '',
|
||||||
|
labelColor: '',
|
||||||
|
editLabel: null,
|
||||||
|
deleetLabel: null,
|
||||||
|
showDeleteDialog: false,
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
onShowAddModal() {
|
||||||
|
this.set('labelName', '');
|
||||||
|
this.set('labelColor', '');
|
||||||
|
this.modalOpen("#add-label-modal", {"show": true}, '#add-label-name');
|
||||||
|
},
|
||||||
|
|
||||||
|
onShowDeleteModal(label) {
|
||||||
|
this.set('deleteLabel', label);
|
||||||
|
this.set('showDeleteDialog', !this.get('showDeleteDialog'));
|
||||||
|
},
|
||||||
|
|
||||||
|
onShowUpdateModal(label) {
|
||||||
|
this.set('editLabel', label);
|
||||||
|
this.set('labelName', label.get('name'));
|
||||||
|
this.set('labelColor', label.get('color'));
|
||||||
|
this.modalOpen("#edit-label-modal", {"show": true}, '#edit-label-name');
|
||||||
|
},
|
||||||
|
|
||||||
|
onSetColor(color) {
|
||||||
|
this.set('labelColor', color);
|
||||||
|
},
|
||||||
|
|
||||||
|
onAdd() {
|
||||||
|
let label = {
|
||||||
|
name: this.get('labelName').trim(),
|
||||||
|
color: this.get('labelColor').trim(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is.empty(label.name)) {
|
||||||
|
$('#add-label-name').addClass('is-invalid').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#add-label-name').removeClass('is-invalid');
|
||||||
|
this.modalClose('#add-label-modal');
|
||||||
|
|
||||||
|
this.get('onAdd')(label);
|
||||||
|
},
|
||||||
|
|
||||||
|
onUpdate() {
|
||||||
|
let name = this.get('labelName').trim();
|
||||||
|
let color = this.get('labelColor').trim();
|
||||||
|
let label = this.get('editLabel');
|
||||||
|
|
||||||
|
if (is.empty(name)) {
|
||||||
|
$('#edit-label-name').addClass('is-invalid').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#edit-label-name').removeClass('is-invalid');
|
||||||
|
this.modalClose('#edit-label-modal');
|
||||||
|
|
||||||
|
label.set('name', name);
|
||||||
|
label.set('color', color);
|
||||||
|
|
||||||
|
this.get('onUpdate')(label);
|
||||||
|
|
||||||
|
this.set('editLabel', null);
|
||||||
|
},
|
||||||
|
|
||||||
|
onDelete() {
|
||||||
|
let label = this.get('deleteLabel');
|
||||||
|
|
||||||
|
this.set('showDeleteDialog', false);
|
||||||
|
this.get('onDelete')(label.get('id'));
|
||||||
|
this.set('deleteLabel', null);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -12,9 +12,10 @@
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import AuthProvider from '../../mixins/auth';
|
import AuthProvider from '../../mixins/auth';
|
||||||
import ModalMixin from '../../mixins/modal';
|
import ModalMixin from '../../mixins/modal';
|
||||||
|
import Notifier from '../../mixins/notifier';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(AuthProvider, ModalMixin, {
|
export default Component.extend(AuthProvider, ModalMixin, Notifier, {
|
||||||
bulkUsers: '',
|
bulkUsers: '',
|
||||||
newUser: null,
|
newUser: null,
|
||||||
|
|
||||||
|
@ -51,6 +52,7 @@ export default Component.extend(AuthProvider, ModalMixin, {
|
||||||
|
|
||||||
this.get('onAddUser')(user).then(() => {
|
this.get('onAddUser')(user).then(() => {
|
||||||
this.set('newUser', { firstname: '', lastname: '', email: '', active: true });
|
this.set('newUser', { firstname: '', lastname: '', email: '', active: true });
|
||||||
|
this.notifySuccess('Added user');
|
||||||
});
|
});
|
||||||
|
|
||||||
this.modalClose("#add-user-modal");
|
this.modalClose("#add-user-modal");
|
||||||
|
@ -65,6 +67,7 @@ export default Component.extend(AuthProvider, ModalMixin, {
|
||||||
|
|
||||||
this.get('onAddUsers')(this.get('bulkUsers')).then(() => {
|
this.get('onAddUsers')(this.get('bulkUsers')).then(() => {
|
||||||
this.set('bulkUsers', '');
|
this.set('bulkUsers', '');
|
||||||
|
this.notifySuccess('Added users');
|
||||||
});
|
});
|
||||||
|
|
||||||
this.modalClose("#add-user-modal");
|
this.modalClose("#add-user-modal");
|
||||||
|
|
|
@ -24,7 +24,7 @@ export default Component.extend(AuthProvider, ModalMixin, {
|
||||||
searchText: '',
|
searchText: '',
|
||||||
users: null,
|
users: null,
|
||||||
members: null,
|
members: null,
|
||||||
userLimit: 100,
|
userLimit: 25,
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
|
@ -10,20 +10,22 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
import { observer } from '@ember/object';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import { schedule, debounce } from '@ember/runloop';
|
import { schedule, debounce } from '@ember/runloop';
|
||||||
import TooltipMixin from '../../mixins/tooltip';
|
|
||||||
import AuthProvider from '../../mixins/auth';
|
import AuthProvider from '../../mixins/auth';
|
||||||
import ModalMixin from '../../mixins/modal';
|
import ModalMixin from '../../mixins/modal';
|
||||||
|
import Notifier from '../../mixins/notifier';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(AuthProvider, ModalMixin, TooltipMixin, {
|
export default Component.extend(AuthProvider, ModalMixin, Notifier, {
|
||||||
groupSvc: service('group'),
|
groupSvc: service('group'),
|
||||||
editUser: null,
|
editUser: null,
|
||||||
deleteUser: null,
|
deleteUser: null,
|
||||||
filter: '',
|
filter: '',
|
||||||
hasSelectedUsers: false,
|
hasSelectedUsers: false,
|
||||||
showDeleteDialog: false,
|
showDeleteDialog: false,
|
||||||
|
showPermExplain: false,
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
@ -46,24 +48,27 @@ export default Component.extend(AuthProvider, ModalMixin, TooltipMixin, {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.set('users', users);
|
this.set('users', users);
|
||||||
|
|
||||||
this.renderTooltips();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
willDestroyElement() {
|
onKeywordChange: observer('filter', function() {
|
||||||
this._super(...arguments);
|
|
||||||
this.removeTooltips();
|
|
||||||
},
|
|
||||||
|
|
||||||
onKeywordChange: function () {
|
|
||||||
debounce(this, this.filterUsers, 350);
|
debounce(this, this.filterUsers, 350);
|
||||||
}.observes('filter'),
|
}),
|
||||||
|
|
||||||
filterUsers() {
|
filterUsers() {
|
||||||
this.get('onFilter')(this.get('filter'));
|
this.get('onFilter')(this.get('filter'));
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
togglePerms() {
|
||||||
|
this.set('showPermExplain', !this.get('showPermExplain'));
|
||||||
|
|
||||||
|
if (this.showPermExplain) {
|
||||||
|
this.$(".perms").show();
|
||||||
|
} else {
|
||||||
|
this.$(".perms").hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
toggleSelect(user) {
|
toggleSelect(user) {
|
||||||
user.set('selected', !user.get('selected'));
|
user.set('selected', !user.get('selected'));
|
||||||
|
|
||||||
|
@ -178,9 +183,15 @@ export default Component.extend(AuthProvider, ModalMixin, TooltipMixin, {
|
||||||
let cb = this.get('onDelete');
|
let cb = this.get('onDelete');
|
||||||
cb(this.get('deleteUser.id'));
|
cb(this.get('deleteUser.id'));
|
||||||
|
|
||||||
|
this.notifySuccess("Deleted user");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onShowDeleteBulk() {
|
||||||
|
this.modalOpen("#admin-user-delete-modal", {"show": true});
|
||||||
|
},
|
||||||
|
|
||||||
onBulkDelete() {
|
onBulkDelete() {
|
||||||
let su = this.get('selectedUsers');
|
let su = this.get('selectedUsers');
|
||||||
|
|
||||||
|
@ -192,6 +203,8 @@ export default Component.extend(AuthProvider, ModalMixin, TooltipMixin, {
|
||||||
this.set('selectedUsers', []);
|
this.set('selectedUsers', []);
|
||||||
this.set('hasSelectedUsers', false);
|
this.set('hasSelectedUsers', false);
|
||||||
|
|
||||||
|
this.notifySuccess("Deleted selected users");
|
||||||
|
|
||||||
this.modalClose('#admin-user-delete-modal');
|
this.modalClose('#admin-user-delete-modal');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,12 @@
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import { empty } from '@ember/object/computed';
|
import { empty } from '@ember/object/computed';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import { computed } from '@ember/object';
|
import { computed, observer } from '@ember/object';
|
||||||
import Tooltips from '../../mixins/tooltip';
|
|
||||||
import Notifier from '../../mixins/notifier';
|
import Notifier from '../../mixins/notifier';
|
||||||
import Modals from '../../mixins/modal';
|
import Modals from '../../mixins/modal';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(Tooltips, Notifier, Modals, {
|
export default Component.extend(Notifier, Modals, {
|
||||||
documentService: service('document'),
|
documentService: service('document'),
|
||||||
sectionService: service('section'),
|
sectionService: service('section'),
|
||||||
store: service(),
|
store: service(),
|
||||||
|
@ -34,7 +33,7 @@ export default Component.extend(Tooltips, Notifier, Modals, {
|
||||||
return this.get('blocks.length') > 0;
|
return this.get('blocks.length') > 0;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
onModalToggle: function () {
|
onModalToggle: observer('show', function() {
|
||||||
let modalId = this.get('modalId');
|
let modalId = this.get('modalId');
|
||||||
|
|
||||||
if (this.get('show')) {
|
if (this.get('show')) {
|
||||||
|
@ -49,7 +48,7 @@ export default Component.extend(Tooltips, Notifier, Modals, {
|
||||||
$(modalId).modal('hide');
|
$(modalId).modal('hide');
|
||||||
$(modalId).modal('dispose');
|
$(modalId).modal('dispose');
|
||||||
}
|
}
|
||||||
}.observes('show'),
|
}),
|
||||||
|
|
||||||
addSection(model) {
|
addSection(model) {
|
||||||
this.modalClose(this.get('modalId'));
|
this.modalClose(this.get('modalId'));
|
||||||
|
|
|
@ -10,14 +10,13 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
import { debounce } from '@ember/runloop';
|
import { debounce } from '@ember/runloop';
|
||||||
import { computed, set } from '@ember/object';
|
import { computed, set, observer } from '@ember/object';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import stringUtil from '../../utils/string';
|
import stringUtil from '../../utils/string';
|
||||||
import TooltipMixin from '../../mixins/tooltip';
|
|
||||||
import ModalMixin from '../../mixins/modal';
|
import ModalMixin from '../../mixins/modal';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(ModalMixin, TooltipMixin, {
|
export default Component.extend(ModalMixin, {
|
||||||
link: service(),
|
link: service(),
|
||||||
linkName: '',
|
linkName: '',
|
||||||
selection: null,
|
selection: null,
|
||||||
|
@ -36,7 +35,7 @@ export default Component.extend(ModalMixin, TooltipMixin, {
|
||||||
}),
|
}),
|
||||||
modalId: computed('page', function() { return '#content-linker-modal-' + this.get('page.id'); }),
|
modalId: computed('page', function() { return '#content-linker-modal-' + this.get('page.id'); }),
|
||||||
showModal: false,
|
showModal: false,
|
||||||
onToggle: function() {
|
onToggle: observer('showModal', function() {
|
||||||
let modalId = this.get('modalId');
|
let modalId = this.get('modalId');
|
||||||
|
|
||||||
if (!this.get('showModal')) {
|
if (!this.get('showModal')) {
|
||||||
|
@ -56,7 +55,7 @@ export default Component.extend(ModalMixin, TooltipMixin, {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.modalOpen(modalId, {show: true});
|
this.modalOpen(modalId, {show: true});
|
||||||
}.observes('showModal'),
|
}),
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
@ -71,18 +70,16 @@ export default Component.extend(ModalMixin, TooltipMixin, {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
this.$('#content-linker-networklocation').removeClass('is-invalid');
|
this.$('#content-linker-networklocation').removeClass('is-invalid');
|
||||||
this.renderTooltips();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.removeTooltips();
|
|
||||||
this.modalClose(this.get('modalId'));
|
this.modalClose(this.get('modalId'));
|
||||||
},
|
},
|
||||||
|
|
||||||
onKeywordChange: function() {
|
onKeywordChange: observer('keywords', function() {
|
||||||
debounce(this, this.fetch, 750);
|
debounce(this, this.fetch, 750);
|
||||||
}.observes('keywords'),
|
}),
|
||||||
|
|
||||||
fetch() {
|
fetch() {
|
||||||
let keywords = this.get('keywords');
|
let keywords = this.get('keywords');
|
||||||
|
|
|
@ -9,176 +9,30 @@
|
||||||
//
|
//
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
import $ from 'jquery';
|
|
||||||
import { A } from '@ember/array';
|
import { A } from '@ember/array';
|
||||||
import { computed } from '@ember/object';
|
import { computed } from '@ember/object';
|
||||||
import { notEmpty } from '@ember/object/computed';
|
import { notEmpty } from '@ember/object/computed';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import Modals from '../../mixins/modal';
|
import Modals from '../../mixins/modal';
|
||||||
import Tooltips from '../../mixins/tooltip';
|
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(Modals, Tooltips, {
|
export default Component.extend(Modals, {
|
||||||
documentService: service('document'),
|
documentService: service('document'),
|
||||||
sessionService: service('session'),
|
sessionService: service('session'),
|
||||||
categoryService: service('category'),
|
categoryService: service('category'),
|
||||||
router: service(),
|
router: service(),
|
||||||
|
selectedCategories: A([]),
|
||||||
contributorMsg: '',
|
tagz: A([]),
|
||||||
approverMsg: '',
|
|
||||||
userChanges: notEmpty('contributorMsg'),
|
userChanges: notEmpty('contributorMsg'),
|
||||||
isApprover: computed('permissions', function() {
|
unassigned: computed('selectedCategories', 'tagz', function() {
|
||||||
return this.get('permissions.documentApprove');
|
return this.get('selectedCategories').length === 0 && this.get('tagz').length === 0;
|
||||||
}),
|
|
||||||
isSpaceAdmin: computed('permissions', function() {
|
|
||||||
return this.get('permissions.spaceOwner') || this.get('permissions.spaceManage');
|
|
||||||
}),
|
|
||||||
changeControlMsg: computed('document.protection', function() {
|
|
||||||
let p = this.get('document.protection');
|
|
||||||
let constants = this.get('constants');
|
|
||||||
let msg = '';
|
|
||||||
|
|
||||||
switch (p) {
|
|
||||||
case constants.ProtectionType.None:
|
|
||||||
msg = constants.ProtectionType.NoneLabel;
|
|
||||||
break;
|
|
||||||
case constants.ProtectionType.Lock:
|
|
||||||
msg = constants.ProtectionType.LockLabel;
|
|
||||||
break;
|
|
||||||
case constants.ProtectionType.Review:
|
|
||||||
msg = constants.ProtectionType.ReviewLabel;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return msg;
|
|
||||||
}),
|
|
||||||
approvalMsg: computed('document.{protection,approval}', function() {
|
|
||||||
let p = this.get('document.protection');
|
|
||||||
let a = this.get('document.approval');
|
|
||||||
let constants = this.get('constants');
|
|
||||||
let msg = '';
|
|
||||||
|
|
||||||
if (p === constants.ProtectionType.Review) {
|
|
||||||
switch (a) {
|
|
||||||
case constants.ApprovalType.Anybody:
|
|
||||||
msg = constants.ApprovalType.AnybodyLabel;
|
|
||||||
break;
|
|
||||||
case constants.ApprovalType.Majority:
|
|
||||||
msg = constants.ApprovalType.MajorityLabel;
|
|
||||||
break;
|
|
||||||
case constants.ApprovalType.Unanimous:
|
|
||||||
msg = constants.ApprovalType.UnanimousLabel;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return msg;
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
this.workflowStatus();
|
|
||||||
this.popovers();
|
|
||||||
this.load();
|
this.load();
|
||||||
},
|
},
|
||||||
|
|
||||||
didInsertElement() {
|
|
||||||
this._super(...arguments);
|
|
||||||
|
|
||||||
this.popovers();
|
|
||||||
this.renderTooltips();
|
|
||||||
},
|
|
||||||
|
|
||||||
willDestroyElement() {
|
|
||||||
this._super(...arguments);
|
|
||||||
|
|
||||||
$('#document-lifecycle-popover').popover('dispose');
|
|
||||||
$('#document-protection-popover').popover('dispose');
|
|
||||||
this.removeTooltips();
|
|
||||||
},
|
|
||||||
|
|
||||||
popovers() {
|
|
||||||
let constants = this.get('constants');
|
|
||||||
|
|
||||||
if (this.get('permissions.documentLifecycle')) {
|
|
||||||
$('#document-lifecycle-popover').addClass('cursor-pointer');
|
|
||||||
} else {
|
|
||||||
$('#document-lifecycle-popover').popover('dispose');
|
|
||||||
$('#document-lifecycle-popover').removeClass('cursor-pointer');
|
|
||||||
|
|
||||||
$('#document-lifecycle-popover').popover({
|
|
||||||
html: true,
|
|
||||||
title: 'Lifecycle',
|
|
||||||
content: "<p>Draft — restricted visiblity and not searchable</p><p>Live — document visible to all</p><p>Archived — not visible or searchable</p>",
|
|
||||||
placement: 'top',
|
|
||||||
trigger: 'hover click'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.get('permissions.documentApprove')) {
|
|
||||||
$('#document-protection-popover').addClass('cursor-pointer');
|
|
||||||
} else {
|
|
||||||
$('#document-protection-popover').popover('dispose');
|
|
||||||
$('#document-protection-popover').removeClass('cursor-pointer');
|
|
||||||
|
|
||||||
let ccMsg = `<p>${this.changeControlMsg}</p>`;
|
|
||||||
|
|
||||||
if (this.get('document.protection') === constants.ProtectionType.Review) {
|
|
||||||
ccMsg += '<ul>'
|
|
||||||
ccMsg += `<li>${this.approvalMsg}</li>`;
|
|
||||||
if (this.get('userChanges')) ccMsg += `<li>Your contributions: ${this.contributorMsg}</li>`;
|
|
||||||
if (this.get('isApprover') && this.get('approverMsg.length') > 0) ccMsg += `<li>${this.approverMsg}</li>`;
|
|
||||||
ccMsg += '</ul>'
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#document-protection-popover').popover({
|
|
||||||
html: true,
|
|
||||||
title: 'Change Control',
|
|
||||||
content: ccMsg,
|
|
||||||
placement: 'top',
|
|
||||||
trigger: 'hover click'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
workflowStatus() {
|
|
||||||
let pages = this.get('pages');
|
|
||||||
let contributorMsg = '';
|
|
||||||
let userPendingCount = 0;
|
|
||||||
let userReviewCount = 0;
|
|
||||||
let userRejectedCount = 0;
|
|
||||||
let approverMsg = '';
|
|
||||||
let approverPendingCount = 0;
|
|
||||||
let approverReviewCount = 0;
|
|
||||||
let approverRejectedCount = 0;
|
|
||||||
|
|
||||||
pages.forEach((item) => {
|
|
||||||
if (item.get('userHasChangePending')) userPendingCount+=1;
|
|
||||||
if (item.get('userHasChangeAwaitingReview')) userReviewCount+=1;
|
|
||||||
if (item.get('userHasChangeRejected')) userRejectedCount+=1;
|
|
||||||
if (item.get('changePending')) approverPendingCount+=1;
|
|
||||||
if (item.get('changeAwaitingReview')) approverReviewCount+=1;
|
|
||||||
if (item.get('changeRejected')) approverRejectedCount+=1;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (userPendingCount > 0 || userReviewCount > 0 || userRejectedCount > 0) {
|
|
||||||
let label = userPendingCount === 1 ? 'change' : 'changes';
|
|
||||||
contributorMsg = `${userPendingCount} ${label} progressing, ${userReviewCount} awaiting review, ${userRejectedCount} rejected`;
|
|
||||||
}
|
|
||||||
this.set('contributorMsg', contributorMsg);
|
|
||||||
|
|
||||||
if (approverPendingCount > 0 || approverReviewCount > 0 || approverRejectedCount > 0) {
|
|
||||||
let label = approverPendingCount === 1 ? 'change' : 'changes';
|
|
||||||
approverMsg = `${approverPendingCount} ${label} progressing, ${approverReviewCount} awaiting review, ${approverRejectedCount} rejected`;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.set('approverMsg', approverMsg);
|
|
||||||
this.set('selectedVersion', this.get('versions').findBy('documentId', this.get('document.id')));
|
|
||||||
|
|
||||||
this.popovers();
|
|
||||||
},
|
|
||||||
|
|
||||||
load() {
|
load() {
|
||||||
this.get('categoryService').getDocumentCategories(this.get('document.id')).then((selected) => {
|
this.get('categoryService').getDocumentCategories(this.get('document.id')).then((selected) => {
|
||||||
this.set('selectedCategories', selected);
|
this.set('selectedCategories', selected);
|
||||||
|
@ -198,24 +52,10 @@ export default Component.extend(Modals, Tooltips, {
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
onSelectVersion(version) {
|
|
||||||
let space = this.get('folder');
|
|
||||||
|
|
||||||
this.get('router').transitionTo('document',
|
|
||||||
space.get('id'), space.get('slug'),
|
|
||||||
version.documentId, this.get('document.slug'));
|
|
||||||
},
|
|
||||||
|
|
||||||
onEditLifecycle() {
|
|
||||||
},
|
|
||||||
|
|
||||||
onEditProtection() {
|
|
||||||
},
|
|
||||||
|
|
||||||
onEditCategory() {
|
onEditCategory() {
|
||||||
if (!this.get('permissions.spaceManage')) return;
|
if (!this.get('permissions.documentEdit')) return;
|
||||||
|
|
||||||
this.get('router').transitionTo('document.settings', {queryParams: {tab: 'meta'}});
|
this.get('router').transitionTo('document.settings', {queryParams: {tab: 'category'}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,9 +11,8 @@
|
||||||
|
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
import TooltipMixin from '../../mixins/tooltip';
|
|
||||||
|
|
||||||
export default Component.extend(TooltipMixin, {
|
export default Component.extend({
|
||||||
documentService: service('document'),
|
documentService: service('document'),
|
||||||
sectionService: service('section'),
|
sectionService: service('section'),
|
||||||
editMode: false,
|
editMode: false,
|
||||||
|
|
|
@ -11,13 +11,13 @@
|
||||||
|
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
|
import { computed } from '@ember/object';
|
||||||
import AuthMixin from '../../mixins/auth';
|
import AuthMixin from '../../mixins/auth';
|
||||||
import TooltipMixin from '../../mixins/tooltip';
|
|
||||||
import ModalMixin from '../../mixins/modal';
|
import ModalMixin from '../../mixins/modal';
|
||||||
import Notifier from '../../mixins/notifier';
|
import Notifier from '../../mixins/notifier';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, Notifier, {
|
export default Component.extend(ModalMixin, AuthMixin, Notifier, {
|
||||||
store: service(),
|
store: service(),
|
||||||
spaceSvc: service('folder'),
|
spaceSvc: service('folder'),
|
||||||
session: service(),
|
session: service(),
|
||||||
|
@ -25,6 +25,29 @@ export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, Notifier, {
|
||||||
pinned: service(),
|
pinned: service(),
|
||||||
browserSvc: service('browser'),
|
browserSvc: service('browser'),
|
||||||
documentSvc: service('document'),
|
documentSvc: service('document'),
|
||||||
|
showRevisions: computed('permissions', 'document.protection', function() {
|
||||||
|
if (!this.get('session.authenticated')) return false;
|
||||||
|
if (!this.get('session.viewUsers')) return false;
|
||||||
|
if (this.get('document.protection') === this.get('constants').ProtectionType.None) return true;
|
||||||
|
if (this.get('document.protection') === this.get('constants').ProtectionType.Review && this.get('permissions.documentApprove')) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}),
|
||||||
|
showActivity: computed('permissions', function() {
|
||||||
|
if (this.get('appMeta.edition') !== this.get('constants').Product.EnterpriseEdition) return false;
|
||||||
|
if (!this.get('session.authenticated')) return false;
|
||||||
|
if (!this.get('session.viewUsers')) return false;
|
||||||
|
if (this.get('permissions.spaceView')) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}),
|
||||||
|
hasToolbar: computed('permissions', 'showRevisions', 'showActivity', function() {
|
||||||
|
if (this.get('showRevisions') || this.get('showActivity')) return true;
|
||||||
|
if (this.get('permissions.documentAdd') || this.get('permissions.documentDelete')) return true;
|
||||||
|
if (this.get('appMeta.edition') === this.get('constants').Product.EnterpriseEdition &&
|
||||||
|
this.get('permissions.documentEdit')) return true;
|
||||||
|
|
||||||
|
}),
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
@ -49,24 +72,25 @@ export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, Notifier, {
|
||||||
this.set('pinState.pinId', pinId);
|
this.set('pinState.pinId', pinId);
|
||||||
this.set('pinState.isPinned', pinId !== '');
|
this.set('pinState.isPinned', pinId !== '');
|
||||||
this.set('pinState.newName', doc.get('name'));
|
this.set('pinState.newName', doc.get('name'));
|
||||||
this.renderTooltips();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.set('saveTemplate.name', this.get('document.name'));
|
this.set('saveTemplate.name', this.get('document.name'));
|
||||||
this.set('saveTemplate.description', this.get('document.excerpt'));
|
this.set('saveTemplate.description', this.get('document.excerpt'));
|
||||||
},
|
},
|
||||||
|
|
||||||
didInsertElement() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.modalInputFocus('#document-template-modal', '#new-template-name');
|
|
||||||
},
|
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.removeTooltips();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
onShowTemplateModal() {
|
||||||
|
this.modalOpen("#document-template-modal", {show:true}, "#new-template-name");
|
||||||
|
},
|
||||||
|
|
||||||
|
onShowDeleteModal() {
|
||||||
|
this.modalOpen("#document-delete-modal", {show:true});
|
||||||
|
},
|
||||||
|
|
||||||
onDocumentDelete() {
|
onDocumentDelete() {
|
||||||
this.modalClose('#document-delete-modal');
|
this.modalClose('#document-delete-modal');
|
||||||
|
|
||||||
|
@ -80,11 +104,9 @@ export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, Notifier, {
|
||||||
|
|
||||||
onUnpin() {
|
onUnpin() {
|
||||||
this.get('pinned').unpinItem(this.get('pinState.pinId')).then(() => {
|
this.get('pinned').unpinItem(this.get('pinState.pinId')).then(() => {
|
||||||
$('#document-pin-button').tooltip('dispose');
|
|
||||||
this.set('pinState.isPinned', false);
|
this.set('pinState.isPinned', false);
|
||||||
this.set('pinState.pinId', '');
|
this.set('pinState.pinId', '');
|
||||||
this.eventBus.publish('pinChange');
|
this.eventBus.publish('pinChange');
|
||||||
this.renderTooltips();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -96,11 +118,9 @@ export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, Notifier, {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.get('pinned').pinItem(pin).then((pin) => {
|
this.get('pinned').pinItem(pin).then((pin) => {
|
||||||
$('#document-pin-button').tooltip('dispose');
|
|
||||||
this.set('pinState.isPinned', true);
|
this.set('pinState.isPinned', true);
|
||||||
this.set('pinState.pinId', pin.get('id'));
|
this.set('pinState.pinId', pin.get('id'));
|
||||||
this.eventBus.publish('pinChange');
|
this.eventBus.publish('pinChange');
|
||||||
this.renderTooltips();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -135,10 +155,8 @@ export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, Notifier, {
|
||||||
},
|
},
|
||||||
|
|
||||||
onExport() {
|
onExport() {
|
||||||
this.showWait();
|
|
||||||
|
|
||||||
let spec = {
|
let spec = {
|
||||||
spaceId: this.get('document.folderId'),
|
spaceId: this.get('document.spaceId'),
|
||||||
data: [],
|
data: [],
|
||||||
filterType: 'document',
|
filterType: 'document',
|
||||||
};
|
};
|
||||||
|
@ -147,7 +165,7 @@ export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, Notifier, {
|
||||||
|
|
||||||
this.get('documentSvc').export(spec).then((htmlExport) => {
|
this.get('documentSvc').export(spec).then((htmlExport) => {
|
||||||
this.get('browserSvc').downloadFile(htmlExport, this.get('document.slug') + '.html');
|
this.get('browserSvc').downloadFile(htmlExport, this.get('document.slug') + '.html');
|
||||||
this.showDone();
|
this.notifySuccess('Exported');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,15 +10,14 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import { computed } from '@ember/object';
|
import { computed, observer } from '@ember/object';
|
||||||
import { debounce } from '@ember/runloop';
|
import { debounce } from '@ember/runloop';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import Tooltips from '../../mixins/tooltip';
|
|
||||||
import ModalMixin from '../../mixins/modal';
|
import ModalMixin from '../../mixins/modal';
|
||||||
import tocUtil from '../../utils/toc';
|
import tocUtil from '../../utils/toc';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(ModalMixin, Tooltips, {
|
export default Component.extend(ModalMixin, {
|
||||||
documentService: service('document'),
|
documentService: service('document'),
|
||||||
searchService: service('search'),
|
searchService: service('search'),
|
||||||
router: service(),
|
router: service(),
|
||||||
|
@ -29,9 +28,9 @@ export default Component.extend(ModalMixin, Tooltips, {
|
||||||
canDelete: false,
|
canDelete: false,
|
||||||
canMove: false,
|
canMove: false,
|
||||||
docSearchFilter: '',
|
docSearchFilter: '',
|
||||||
onKeywordChange: function () {
|
onKeywordChange: observer('docSearchFilter', function() {
|
||||||
debounce(this, this.searchDocs, 750);
|
debounce(this, this.searchDocs, 750);
|
||||||
}.observes('docSearchFilter'),
|
}),
|
||||||
emptySearch: computed('docSearchResults', function() {
|
emptySearch: computed('docSearchResults', function() {
|
||||||
return this.get('docSearchResults.length') === 0;
|
return this.get('docSearchResults.length') === 0;
|
||||||
}),
|
}),
|
||||||
|
@ -78,14 +77,6 @@ export default Component.extend(ModalMixin, Tooltips, {
|
||||||
this.setState(this.get('page.id'));
|
this.setState(this.get('page.id'));
|
||||||
},
|
},
|
||||||
|
|
||||||
didInsertElement() {
|
|
||||||
this._super(...arguments);
|
|
||||||
|
|
||||||
if (this.get('session.authenticated')) {
|
|
||||||
this.renderTooltips();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
searchDocs() {
|
searchDocs() {
|
||||||
let payload = { keywords: this.get('docSearchFilter').trim(), doc: true };
|
let payload = { keywords: this.get('docSearchFilter').trim(), doc: true };
|
||||||
if (payload.keywords.length == 0) return;
|
if (payload.keywords.length == 0) return;
|
||||||
|
|
|
@ -125,8 +125,6 @@ export default Component.extend(Notifier, {
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
onSave() {
|
onSave() {
|
||||||
this.showWait();
|
|
||||||
|
|
||||||
let docId = this.get('document.id');
|
let docId = this.get('document.id');
|
||||||
let folderId = this.get('space.id');
|
let folderId = this.get('space.id');
|
||||||
let link = this.get('categories').filterBy('selected', true);
|
let link = this.get('categories').filterBy('selected', true);
|
||||||
|
@ -158,7 +156,6 @@ export default Component.extend(Notifier, {
|
||||||
|
|
||||||
this.get('categoryService').setCategoryMembership(toUnlink, 'unlink').then(() => {
|
this.get('categoryService').setCategoryMembership(toUnlink, 'unlink').then(() => {
|
||||||
this.get('categoryService').setCategoryMembership(toLink, 'link').then(() => {
|
this.get('categoryService').setCategoryMembership(toLink, 'link').then(() => {
|
||||||
this.showDone();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,7 +32,7 @@ export default Component.extend(Notifier, {
|
||||||
if (this.get('hasNameError')) return;
|
if (this.get('hasNameError')) return;
|
||||||
if (!this.get('permissions.documentEdit')) return;
|
if (!this.get('permissions.documentEdit')) return;
|
||||||
|
|
||||||
this.set('document.name', this.get('docName'));
|
this.set('document.name', this.get('docName').trim());
|
||||||
this.set('document.excerpt', this.get('docExcerpt').trim());
|
this.set('document.excerpt', this.get('docExcerpt').trim());
|
||||||
|
|
||||||
let cb = this.get('onSaveDocument');
|
let cb = this.get('onSaveDocument');
|
||||||
|
|
189
gui/app/components/document/settings-tag.js
Normal file
189
gui/app/components/document/settings-tag.js
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
import $ from 'jquery';
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
import { A } from '@ember/array';
|
||||||
|
import { computed } from '@ember/object';
|
||||||
|
import { schedule } from '@ember/runloop';
|
||||||
|
import Notifier from '../../mixins/notifier';
|
||||||
|
import Component from '@ember/component';
|
||||||
|
|
||||||
|
export default Component.extend(Notifier, {
|
||||||
|
appMeta: service(),
|
||||||
|
documentSvc: service('document'),
|
||||||
|
categoryService: service('category'),
|
||||||
|
|
||||||
|
tagz: A([]),
|
||||||
|
categories: A([]),
|
||||||
|
newCategory: '',
|
||||||
|
showCategoryModal: false,
|
||||||
|
hasCategories: computed('categories', function() {
|
||||||
|
return this.get('categories').length > 0;
|
||||||
|
}),
|
||||||
|
canSelectCategory: computed('categories', function() {
|
||||||
|
return (this.get('categories').length > 0 && this.get('permissions.documentEdit'));
|
||||||
|
}),
|
||||||
|
canAddCategory: computed('categories', function() {
|
||||||
|
return this.get('permissions.spaceOwner') || this.get('permissions.spaceManage');
|
||||||
|
}),
|
||||||
|
|
||||||
|
didReceiveAttrs() {
|
||||||
|
this._super(...arguments);
|
||||||
|
this.load();
|
||||||
|
},
|
||||||
|
|
||||||
|
didInsertElement() {
|
||||||
|
this._super(...arguments);
|
||||||
|
|
||||||
|
schedule('afterRender', () => {
|
||||||
|
$("#add-tag-field-1").focus();
|
||||||
|
|
||||||
|
$(".tag-input").off("keydown").on("keydown", function(e) {
|
||||||
|
if (e.shiftKey && e.which === 9) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.shiftKey) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.which === 9 ||
|
||||||
|
e.which === 13 ||
|
||||||
|
e.which === 16 ||
|
||||||
|
e.which === 37 ||
|
||||||
|
e.which === 38 ||
|
||||||
|
e.which === 39 ||
|
||||||
|
e.which === 40 ||
|
||||||
|
e.which === 45 ||
|
||||||
|
e.which === 189 ||
|
||||||
|
e.which === 8 ||
|
||||||
|
e.which === 127 ||
|
||||||
|
(e.which >= 65 && e.which <= 90) ||
|
||||||
|
(e.which >= 97 && e.which <= 122) ||
|
||||||
|
(e.which >= 48 && e.which <= 57)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
willDestroyElement() {
|
||||||
|
this._super(...arguments);
|
||||||
|
|
||||||
|
$(".tag-input").off("keydown");
|
||||||
|
},
|
||||||
|
|
||||||
|
load() {
|
||||||
|
this.get('categoryService').getUserVisible(this.get('space.id')).then((categories) => {
|
||||||
|
let cats = A(categories);
|
||||||
|
this.set('categories', cats);
|
||||||
|
this.get('categoryService').getDocumentCategories(this.get('document.id')).then((selected) => {
|
||||||
|
this.set('selectedCategories', selected);
|
||||||
|
selected.forEach((s) => {
|
||||||
|
let cat = cats.findBy('id', s.id);
|
||||||
|
if (is.not.undefined(cat)) {
|
||||||
|
cat.set('selected', true);
|
||||||
|
this.set('categories', cats);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let counter = 1;
|
||||||
|
let tagz = A([]);
|
||||||
|
let maxTags = this.get('appMeta.maxTags');
|
||||||
|
|
||||||
|
if (!_.isUndefined(this.get('document.tags')) && this.get('document.tags').length > 1) {
|
||||||
|
let tags = this.get('document.tags').split('#');
|
||||||
|
|
||||||
|
_.each(tags, (tag) => {
|
||||||
|
tag = tag.trim();
|
||||||
|
if (tag.length > 0 && counter <= maxTags) {
|
||||||
|
tagz.pushObject({number: counter, value: tag});
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let index = counter; index <= maxTags; index++) {
|
||||||
|
tagz.pushObject({number: index, value: ''});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set('tagz', tagz);
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
onSave() {
|
||||||
|
let docId = this.get('document.id');
|
||||||
|
let folderId = this.get('space.id');
|
||||||
|
let link = this.get('categories').filterBy('selected', true);
|
||||||
|
let unlink = this.get('categories').filterBy('selected', false);
|
||||||
|
let toLink = [];
|
||||||
|
let toUnlink = [];
|
||||||
|
|
||||||
|
// prepare links associated with document
|
||||||
|
link.forEach((l) => {
|
||||||
|
let t = {
|
||||||
|
spaceId: folderId,
|
||||||
|
documentId: docId,
|
||||||
|
categoryId: l.get('id')
|
||||||
|
};
|
||||||
|
|
||||||
|
toLink.push(t);
|
||||||
|
});
|
||||||
|
|
||||||
|
// prepare links no longer associated with document
|
||||||
|
unlink.forEach((l) => {
|
||||||
|
let t = {
|
||||||
|
spaceId: folderId,
|
||||||
|
documentId: docId,
|
||||||
|
categoryId: l.get('id')
|
||||||
|
};
|
||||||
|
|
||||||
|
toUnlink.pushObject(t);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.get('categoryService').setCategoryMembership(toUnlink, 'unlink').then(() => {
|
||||||
|
this.get('categoryService').setCategoryMembership(toLink, 'link').then(() => {
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let tagz = this.get('tagz');
|
||||||
|
let tagzToSave = [];
|
||||||
|
|
||||||
|
_.each(tagz, (t) => {
|
||||||
|
let tag = t.value.toLowerCase().trim();
|
||||||
|
if (tag.length> 0) {
|
||||||
|
if (!_.contains(tagzToSave, tag) && is.not.startWith(tag, '-')) {
|
||||||
|
tagzToSave.push(tag);
|
||||||
|
this.$('#add-tag-field-' + t.number).removeClass('is-invalid');
|
||||||
|
} else {
|
||||||
|
this.$('#add-tag-field-' + t.number).addClass('is-invalid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let save = "#";
|
||||||
|
_.each(tagzToSave, (t) => {
|
||||||
|
save += t;
|
||||||
|
save += '#';
|
||||||
|
});
|
||||||
|
|
||||||
|
let doc = this.get('document');
|
||||||
|
doc.set('tags', save);
|
||||||
|
|
||||||
|
this.get('onSaveDocument')(doc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -17,18 +17,17 @@ import Notifier from '../../mixins/notifier';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(Modals, Notifier, {
|
export default Component.extend(Modals, Notifier, {
|
||||||
|
classNames: ["section"],
|
||||||
documentService: service('document'),
|
documentService: service('document'),
|
||||||
|
browserSvc: service('browser'),
|
||||||
appMeta: service(),
|
appMeta: service(),
|
||||||
|
session: service(),
|
||||||
hasAttachments: notEmpty('files'),
|
hasAttachments: notEmpty('files'),
|
||||||
canEdit: computed('permissions.documentEdit', 'document.protection', function() {
|
canEdit: computed('permissions.documentEdit', 'document.protection', function() {
|
||||||
return this.get('document.protection') !== this.get('constants').ProtectionType.Lock && this.get('permissions.documentEdit');
|
return this.get('document.protection') !== this.get('constants').ProtectionType.Lock && this.get('permissions.documentEdit');
|
||||||
}),
|
}),
|
||||||
showDialog: false,
|
showDialog: false,
|
||||||
|
downloadQuery: '',
|
||||||
init() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.deleteAttachment = { id: '', name: '' };
|
|
||||||
},
|
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
@ -47,9 +46,9 @@ export default Component.extend(Modals, Notifier, {
|
||||||
let url = this.get('appMeta.endpoint');
|
let url = this.get('appMeta.endpoint');
|
||||||
let uploadUrl = `${url}/documents/${documentId}/attachments`;
|
let uploadUrl = `${url}/documents/${documentId}/attachments`;
|
||||||
|
|
||||||
let dzone = new Dropzone("#upload-document-files", {
|
let dzone = new Dropzone("#upload-document-files > div", {
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': 'Bearer ' + self.get('session.session.content.authenticated.token')
|
'Authorization': 'Bearer ' + self.get('session.authToken')
|
||||||
},
|
},
|
||||||
url: uploadUrl,
|
url: uploadUrl,
|
||||||
method: "post",
|
method: "post",
|
||||||
|
@ -66,17 +65,16 @@ export default Component.extend(Modals, Notifier, {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.on("queuecomplete", function () {
|
this.on("queuecomplete", function () {
|
||||||
self.showDone();
|
self.notifySuccess('Uploaded file');
|
||||||
self.getAttachments();
|
self.getAttachments();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.on("addedfile", function ( /*file*/ ) {
|
this.on("addedfile", function ( /*file*/ ) {
|
||||||
self.showWait();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.on("error", function (error, msg) { // // eslint-disable-line no-unused-vars
|
this.on("error", function (error, msg) {
|
||||||
self.showNotification(msg);
|
self.notifyError(msg);
|
||||||
console.log(msg); // eslint-disable-line no-console
|
self.notifyError(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -86,6 +84,15 @@ export default Component.extend(Modals, Notifier, {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.set('drop', dzone);
|
this.set('drop', dzone);
|
||||||
|
|
||||||
|
// For authenticated users we send server auth token.
|
||||||
|
let qry = '';
|
||||||
|
if (this.get('session.hasSecureToken')) {
|
||||||
|
qry = '?secure=' + this.get('session.secureToken');
|
||||||
|
} else if (this.get('session.authenticated')) {
|
||||||
|
qry = '?token=' + this.get('session.authToken');
|
||||||
|
}
|
||||||
|
this.set('downloadQuery', qry);
|
||||||
},
|
},
|
||||||
|
|
||||||
getAttachments() {
|
getAttachments() {
|
||||||
|
@ -95,26 +102,20 @@ export default Component.extend(Modals, Notifier, {
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
onShowDialog(id, name) {
|
onDelete(attachment) {
|
||||||
this.set('deleteAttachment', { id: id, name: name });
|
this.get('documentService').deleteAttachment(this.get('document.id'), attachment.id).then(() => {
|
||||||
|
this.notifySuccess('File deleted');
|
||||||
this.set('showDialog', true);
|
this.getAttachments();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onDelete() {
|
onExport() {
|
||||||
this.set('showDialog', false);
|
this.get('documentSvc').export({}).then((htmlExport) => {
|
||||||
|
this.get('browserSvc').downloadFile(htmlExport, this.get('space.slug') + '.html');
|
||||||
let attachment = this.get('deleteAttachment');
|
this.notifySuccess('Exported');
|
||||||
|
|
||||||
this.get('documentService').deleteAttachment(this.get('document.id'), attachment.id).then(() => {
|
|
||||||
this.getAttachments();
|
|
||||||
this.set('deleteAttachment', {
|
|
||||||
id: "",
|
|
||||||
name: ""
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
this.modalClose("#space-export-modal");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
41
gui/app/components/document/sidebar-meta.js
Normal file
41
gui/app/components/document/sidebar-meta.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
import { computed } from '@ember/object';
|
||||||
|
import { notEmpty } from '@ember/object/computed';
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
import Modals from '../../mixins/modal';
|
||||||
|
import Component from '@ember/component';
|
||||||
|
|
||||||
|
export default Component.extend(Modals, {
|
||||||
|
appMeta: service(),
|
||||||
|
documentService: service('document'),
|
||||||
|
sessionService: service('session'),
|
||||||
|
router: service(),
|
||||||
|
userChanges: notEmpty('contributorMsg'),
|
||||||
|
unassigned: computed('selectedCategories', 'tagz', function() {
|
||||||
|
return this.get('selectedCategories').length === 0 && this.get('tagz').length === 0;
|
||||||
|
}),
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
onEditStatus() {
|
||||||
|
if (!this.get('permissions.documentEdit')) return;
|
||||||
|
|
||||||
|
this.get('router').transitionTo('document.settings', {queryParams: {tab: 'general'}});
|
||||||
|
},
|
||||||
|
|
||||||
|
onSelectVersion(version) {
|
||||||
|
let space = this.get('space');
|
||||||
|
|
||||||
|
this.get('router').transitionTo('document', space.get('id'), space.get('slug'), version.documentId, this.get('document.slug'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -13,10 +13,10 @@ import { computed } from '@ember/object';
|
||||||
import { schedule } from '@ember/runloop';
|
import { schedule } from '@ember/runloop';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import tocUtil from '../../utils/toc';
|
import tocUtil from '../../utils/toc';
|
||||||
import TooltipMixin from '../../mixins/tooltip';
|
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(TooltipMixin, {
|
export default Component.extend({
|
||||||
|
classNames: ["section"],
|
||||||
documentService: service('document'),
|
documentService: service('document'),
|
||||||
emptyState: computed('pages', function () {
|
emptyState: computed('pages', function () {
|
||||||
return this.get('pages.length') === 0;
|
return this.get('pages.length') === 0;
|
||||||
|
@ -54,13 +54,11 @@ export default Component.extend(TooltipMixin, {
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.eventBus.subscribe('documentPageAdded', this, 'onDocumentPageAdded');
|
this.eventBus.subscribe('documentPageAdded', this, 'onDocumentPageAdded');
|
||||||
this.renderTooltips();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.eventBus.unsubscribe('documentPageAdded');
|
this.eventBus.unsubscribe('documentPageAdded');
|
||||||
this.removeTooltips();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onDocumentPageAdded(pageId) {
|
onDocumentPageAdded(pageId) {
|
|
@ -13,16 +13,15 @@ import $ from 'jquery';
|
||||||
import { notEmpty } from '@ember/object/computed';
|
import { notEmpty } from '@ember/object/computed';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import { computed } from '@ember/object';
|
import { computed } from '@ember/object';
|
||||||
import TooltipMixin from '../../mixins/tooltip';
|
|
||||||
import Notifier from '../../mixins/notifier';
|
import Notifier from '../../mixins/notifier';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(TooltipMixin, Notifier, {
|
export default Component.extend(Notifier, {
|
||||||
documentService: service('document'),
|
documentService: service('document'),
|
||||||
sectionService: service('section'),
|
sectionService: service('section'),
|
||||||
store: service(),
|
store: service(),
|
||||||
appMeta: service(),
|
appMeta: service(),
|
||||||
link: service(),
|
linkSvc: service('link'),
|
||||||
hasPages: notEmpty('pages'),
|
hasPages: notEmpty('pages'),
|
||||||
showInsertSectionModal: false,
|
showInsertSectionModal: false,
|
||||||
newSectionLocation: '',
|
newSectionLocation: '',
|
||||||
|
@ -41,36 +40,21 @@ export default Component.extend(TooltipMixin, Notifier, {
|
||||||
this.set('showLikes', this.get('folder.allowLikes') && this.get('document.isLive'));
|
this.set('showLikes', this.get('folder.allowLikes') && this.get('document.isLive'));
|
||||||
},
|
},
|
||||||
|
|
||||||
didRender() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.contentLinkHandler();
|
|
||||||
},
|
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
if (this.get('session.authenticated')) {
|
|
||||||
this.renderTooltips();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.jumpToSection(this.get('currentPageId'));
|
this.jumpToSection(this.get('currentPageId'));
|
||||||
},
|
|
||||||
|
|
||||||
willDestroyElement() {
|
this.contentLinkHandler();
|
||||||
this._super(...arguments);
|
|
||||||
|
|
||||||
if (this.get('session.authenticated')) {
|
|
||||||
this.removeTooltips();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
contentLinkHandler() {
|
contentLinkHandler() {
|
||||||
let links = this.get('link');
|
let linkSvc = this.get('linkSvc');
|
||||||
let doc = this.get('document');
|
let doc = this.get('document');
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
||||||
$("a[data-documize='true']").off('click').on('click', function (e) {
|
$("a[data-documize='true']").off('click').on('click', function (e) {
|
||||||
let link = links.getLinkObject(self.get('links'), this);
|
let link = linkSvc.getLinkObject(self.get('links'), this);
|
||||||
|
|
||||||
// local link? exists?
|
// local link? exists?
|
||||||
if ((link.linkType === "section" || link.linkType === "tab") && link.documentId === doc.get('id')) {
|
if ((link.linkType === "section" || link.linkType === "tab") && link.documentId === doc.get('id')) {
|
||||||
|
@ -92,7 +76,10 @@ export default Component.extend(TooltipMixin, Notifier, {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
links.linkClick(doc, link);
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
linkSvc.linkClick(doc, link);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,19 +9,15 @@
|
||||||
//
|
//
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
import { computed, set } from '@ember/object';
|
import { computed } from '@ember/object';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import ModalMixin from '../../mixins/modal';
|
import ModalMixin from '../../mixins/modal';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(ModalMixin, {
|
export default Component.extend(ModalMixin, {
|
||||||
documentService: service('document'),
|
documentService: service('document'),
|
||||||
revision: null,
|
|
||||||
revisions: null,
|
|
||||||
diff: '',
|
diff: '',
|
||||||
hasRevisions: computed('revisions', function() {
|
revision: null,
|
||||||
return this.get('revisions').length > 0;
|
|
||||||
}),
|
|
||||||
hasDiff: computed('diff', function() {
|
hasDiff: computed('diff', function() {
|
||||||
return this.get('diff').length > 0;
|
return this.get('diff').length > 0;
|
||||||
}),
|
}),
|
||||||
|
@ -34,32 +30,17 @@ export default Component.extend(ModalMixin, {
|
||||||
this.get('document.protection') === constants.ProtectionType.None;
|
this.get('document.protection') === constants.ProtectionType.None;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
init() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.revisions = [];
|
|
||||||
},
|
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.fetchRevisions();
|
|
||||||
},
|
|
||||||
|
|
||||||
fetchRevisions() {
|
let revision = this.get('revision');
|
||||||
this.get('documentService').getDocumentRevisions(this.get('document.id')).then((revisions) => {
|
|
||||||
revisions.forEach((r) => {
|
|
||||||
set(r, 'deleted', r.revisions === 0);
|
|
||||||
let date = moment(r.created).format('Do MMMM YYYY HH:mm');
|
|
||||||
let format = `${r.firstname} ${r.lastname} on ${date} changed ${r.title}`;
|
|
||||||
set(r, 'label', format);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.set('revisions', revisions);
|
if (is.not.null(revision)) {
|
||||||
|
if (!revision.deleted) {
|
||||||
if (revisions.length > 0 && is.null(this.get('revision'))) {
|
this.fetchDiff(revision.pageId, revision.id);
|
||||||
this.send('onSelectRevision', revisions[0]);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchDiff(pageId, revisionId) {
|
fetchDiff(pageId, revisionId) {
|
||||||
this.get('documentService').getPageRevisionDiff(this.get('document.id'), pageId, revisionId).then((revision) => {
|
this.get('documentService').getPageRevisionDiff(this.get('document.id'), pageId, revisionId).then((revision) => {
|
||||||
|
@ -68,12 +49,8 @@ export default Component.extend(ModalMixin, {
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
onSelectRevision(revision) {
|
onShowModal() {
|
||||||
this.set('revision', revision);
|
this.modalOpen('#document-rollback-modal', {show:true});
|
||||||
|
|
||||||
if (!revision.deleted) {
|
|
||||||
this.fetchDiff(revision.pageId, revision.id);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onRollback() {
|
onRollback() {
|
||||||
|
|
16
gui/app/components/folder/document-categories.js
Normal file
16
gui/app/components/folder/document-categories.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
import Component from '@ember/component';
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
classNames: ['categories'],
|
||||||
|
});
|
|
@ -12,6 +12,8 @@
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
|
classNames: ['hashtags'],
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
let tagz = [];
|
let tagz = [];
|
||||||
|
@ -20,7 +22,7 @@ export default Component.extend({
|
||||||
let tags = this.get('documentTags').split('#');
|
let tags = this.get('documentTags').split('#');
|
||||||
_.each(tags, function(tag) {
|
_.each(tags, function(tag) {
|
||||||
if (tag.length > 0) {
|
if (tag.length > 0) {
|
||||||
tagz.pushObject("#" + tag);
|
tagz.pushObject(tag);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,9 @@
|
||||||
|
|
||||||
import { computed } from '@ember/object';
|
import { computed } from '@ember/object';
|
||||||
import { A } from '@ember/array';
|
import { A } from '@ember/array';
|
||||||
import TooltipMixin from '../../mixins/tooltip';
|
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(TooltipMixin, {
|
export default Component.extend({
|
||||||
showDeleteDialog: false,
|
showDeleteDialog: false,
|
||||||
showMoveDialog: false,
|
showMoveDialog: false,
|
||||||
selectedDocuments: A([]),
|
selectedDocuments: A([]),
|
||||||
|
@ -105,7 +104,6 @@ export default Component.extend(TooltipMixin, {
|
||||||
|
|
||||||
this.set('selectedCaption', list.length > 1 ? 'documents' : 'document');
|
this.set('selectedCaption', list.length > 1 ? 'documents' : 'document');
|
||||||
this.set('selectedDocuments', A(list));
|
this.set('selectedDocuments', A(list));
|
||||||
this.renderTooltips();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -52,11 +52,9 @@ export default Component.extend(AuthMixin, Notifier, {
|
||||||
|
|
||||||
let id = this.get('deleteBlockId');
|
let id = this.get('deleteBlockId');
|
||||||
|
|
||||||
this.showWait();
|
|
||||||
|
|
||||||
this.get('sectionSvc').deleteBlock(id).then(() => {
|
this.get('sectionSvc').deleteBlock(id).then(() => {
|
||||||
this.set('deleteBlockId', '');
|
this.set('deleteBlockId', '');
|
||||||
this.showDone();
|
this.notifySuccess('Deleted');
|
||||||
|
|
||||||
this.get('sectionSvc').getSpaceBlocks(this.get('space.id')).then((blocks) => {
|
this.get('sectionSvc').getSpaceBlocks(this.get('space.id')).then((blocks) => {
|
||||||
this.set('blocks', blocks);
|
this.set('blocks', blocks);
|
||||||
|
|
|
@ -12,19 +12,19 @@
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import { A } from '@ember/array';
|
import { A } from '@ember/array';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import TooltipMixin from '../../mixins/tooltip';
|
|
||||||
import ModalMixin from '../../mixins/modal';
|
import ModalMixin from '../../mixins/modal';
|
||||||
import Notifer from '../../mixins/notifier';
|
import Notifer from '../../mixins/notifier';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(ModalMixin, TooltipMixin, Notifer, {
|
export default Component.extend(ModalMixin, Notifer, {
|
||||||
spaceSvc: service('folder'),
|
spaceSvc: service('folder'),
|
||||||
groupSvc: service('group'),
|
groupSvc: service('group'),
|
||||||
categorySvc: service('category'),
|
categorySvc: service('category'),
|
||||||
appMeta: service(),
|
appMeta: service(),
|
||||||
store: service(),
|
store: service(),
|
||||||
|
editId: '',
|
||||||
|
editName: '',
|
||||||
deleteId: '',
|
deleteId: '',
|
||||||
dropdown: null,
|
|
||||||
newCategory: '',
|
newCategory: '',
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
@ -34,13 +34,11 @@ export default Component.extend(ModalMixin, TooltipMixin, Notifer, {
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.renderTooltips();
|
|
||||||
this.load();
|
this.load();
|
||||||
},
|
},
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.removeTooltips();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
load() {
|
load() {
|
||||||
|
@ -120,13 +118,20 @@ export default Component.extend(ModalMixin, TooltipMixin, Notifer, {
|
||||||
spaceId: this.get('space.id')
|
spaceId: this.get('space.id')
|
||||||
};
|
};
|
||||||
|
|
||||||
this.showWait();
|
|
||||||
this.get('categorySvc').add(c).then(() => {
|
this.get('categorySvc').add(c).then(() => {
|
||||||
this.load();
|
this.load();
|
||||||
this.showDone();
|
this.notifySuccess('Category added');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onShowEdit(id) {
|
||||||
|
let cat = this.get('category').findBy('id', id);
|
||||||
|
this.set('editId', cat.get('id'));
|
||||||
|
this.set('editName', cat.get('category'));
|
||||||
|
|
||||||
|
this.modalOpen('#category-edit-modal', {show: true}, "#edit-category-id");
|
||||||
|
},
|
||||||
|
|
||||||
onShowDelete(id) {
|
onShowDelete(id) {
|
||||||
let cat = this.get('category').findBy('id', id);
|
let cat = this.get('category').findBy('id', id);
|
||||||
this.set('deleteId', cat.get('id'));
|
this.set('deleteId', cat.get('id'));
|
||||||
|
@ -142,32 +147,22 @@ export default Component.extend(ModalMixin, TooltipMixin, Notifer, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onEdit(id) {
|
onSave() {
|
||||||
this.setEdit(id, true);
|
let name = this.get('editName');
|
||||||
this.removeTooltips();
|
if (name === '') {
|
||||||
},
|
$('#edit-category-name').addClass('is-invalid').focus();
|
||||||
|
|
||||||
onEditCancel(id) {
|
|
||||||
this.setEdit(id, false);
|
|
||||||
this.load();
|
|
||||||
this.renderTooltips();
|
|
||||||
},
|
|
||||||
|
|
||||||
onSave(id) {
|
|
||||||
let cat = this.setEdit(id, true);
|
|
||||||
if (cat.get('category') === '') {
|
|
||||||
$('#edit-category-' + cat.get('id')).addClass('is-invalid').focus();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cat = this.setEdit(id, false);
|
let cat = this.get('category').findBy('id', this.get('editId'));
|
||||||
$('#edit-category-' + cat.get('id')).removeClass('is-invalid');
|
cat.set('category', name);
|
||||||
|
|
||||||
|
this.modalClose('#category-edit-modal');
|
||||||
|
$('#edit-category-name').removeClass('is-invalid');
|
||||||
|
|
||||||
this.get('categorySvc').save(cat).then(() => {
|
this.get('categorySvc').save(cat).then(() => {
|
||||||
this.load();
|
this.load();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.renderTooltips();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onShowAccessPicker(catId) {
|
onShowAccessPicker(catId) {
|
||||||
|
|
|
@ -36,9 +36,10 @@ export default Component.extend(AuthMixin, Notifier, {
|
||||||
$("#delete-space-name").removeClass("is-invalid");
|
$("#delete-space-name").removeClass("is-invalid");
|
||||||
|
|
||||||
this.get('spaceSvc').delete(this.get('space.id')).then(() => { /* jshint ignore:line */
|
this.get('spaceSvc').delete(this.get('space.id')).then(() => { /* jshint ignore:line */
|
||||||
this.get('localStorage').clearSessionItem('folder');
|
|
||||||
this.get('router').transitionTo('folders');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.get('localStorage').clearSessionItem('folder');
|
||||||
|
this.get('router').transitionTo('folders');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
import { A } from '@ember/array';
|
import { A } from '@ember/array';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import { schedule } from '@ember/runloop';
|
|
||||||
import { computed } from '@ember/object';
|
import { computed } from '@ember/object';
|
||||||
import { empty } from '@ember/object/computed';
|
import { empty } from '@ember/object/computed';
|
||||||
import AuthMixin from '../../mixins/auth';
|
import AuthMixin from '../../mixins/auth';
|
||||||
|
@ -21,18 +20,29 @@ import Component from '@ember/component';
|
||||||
export default Component.extend(AuthMixin, Notifier, {
|
export default Component.extend(AuthMixin, Notifier, {
|
||||||
router: service(),
|
router: service(),
|
||||||
spaceSvc: service('folder'),
|
spaceSvc: service('folder'),
|
||||||
|
iconSvc: service('icon'),
|
||||||
localStorage: service('localStorage'),
|
localStorage: service('localStorage'),
|
||||||
|
|
||||||
isSpaceAdmin: computed('permissions', function() {
|
isSpaceAdmin: computed('permissions', function() {
|
||||||
return this.get('permissions.spaceOwner') || this.get('permissions.spaceManage');
|
return this.get('permissions.spaceOwner') || this.get('permissions.spaceManage');
|
||||||
}),
|
}),
|
||||||
|
|
||||||
spaceName: '',
|
spaceName: '',
|
||||||
hasNameError: empty('spaceName'),
|
hasNameError: empty('spaceName'),
|
||||||
spaceTypeOptions: A([]),
|
spaceTypeOptions: A([]),
|
||||||
spaceType: 0,
|
spaceType: 0,
|
||||||
likes: '',
|
likes: '',
|
||||||
allowLikes: false,
|
allowLikes: false,
|
||||||
|
spaceLifecycleOptions: A([]),
|
||||||
|
spaceLifecycle: null,
|
||||||
|
iconList: A([]),
|
||||||
|
spaceIcon: '',
|
||||||
|
spaceDesc: '',
|
||||||
|
spaceLabel: '',
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this._super(...arguments);
|
||||||
|
|
||||||
|
this.set('iconList', this.get('iconSvc').getSpaceIconList());
|
||||||
|
},
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
@ -56,6 +66,15 @@ export default Component.extend(AuthMixin, Notifier, {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.set('spaceName', this.get('space.name'));
|
this.set('spaceName', this.get('space.name'));
|
||||||
|
this.set('spaceDesc', this.get('space.desc'));
|
||||||
|
this.set('spaceLabel', this.get('space.labelId'));
|
||||||
|
|
||||||
|
let icon = this.get('space.icon');
|
||||||
|
if (is.empty(icon)) {
|
||||||
|
icon = constants.IconMeta.Apps;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set('spaceIcon', icon);
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
@ -63,12 +82,16 @@ export default Component.extend(AuthMixin, Notifier, {
|
||||||
this.set('spaceType', t);
|
this.set('spaceType', t);
|
||||||
},
|
},
|
||||||
|
|
||||||
onSetLikes(l) {
|
onSetSpaceLifecycle(l) {
|
||||||
this.set('allowLikes', l);
|
this.set('spaceLifecycle', l);
|
||||||
|
},
|
||||||
|
|
||||||
schedule('afterRender', () => {
|
onSetIcon(icon) {
|
||||||
if (l) this.$('#space-likes-prompt').focus();
|
this.set('spaceIcon', icon);
|
||||||
});
|
},
|
||||||
|
|
||||||
|
onSetLabel(id) {
|
||||||
|
this.set('spaceLabel', id);
|
||||||
},
|
},
|
||||||
|
|
||||||
onSave() {
|
onSave() {
|
||||||
|
@ -84,10 +107,12 @@ export default Component.extend(AuthMixin, Notifier, {
|
||||||
if (spaceName.length === 0) return;
|
if (spaceName.length === 0) return;
|
||||||
space.set('name', spaceName);
|
space.set('name', spaceName);
|
||||||
|
|
||||||
this.showWait();
|
space.set('icon', this.get('spaceIcon'));
|
||||||
|
space.set('desc', this.get('spaceDesc'));
|
||||||
|
space.set('labelId', this.get('spaceLabel'));
|
||||||
|
|
||||||
this.get('spaceSvc').save(space).then(() => {
|
this.get('spaceSvc').save(space).then(() => {
|
||||||
this.showDone();
|
this.notifySuccess('Saved');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@ export default Component.extend(Notifier, Modals, {
|
||||||
searchText: '',
|
searchText: '',
|
||||||
inviteEmail: '',
|
inviteEmail: '',
|
||||||
inviteMessage: '',
|
inviteMessage: '',
|
||||||
|
showSpacePermExplain: false,
|
||||||
|
showDocumentPermExplain: false,
|
||||||
|
|
||||||
isSpaceAdmin: computed('permissions', function() {
|
isSpaceAdmin: computed('permissions', function() {
|
||||||
return this.get('permissions.spaceOwner') || this.get('permissions.spaceManage');
|
return this.get('permissions.spaceOwner') || this.get('permissions.spaceManage');
|
||||||
|
@ -132,8 +134,6 @@ export default Component.extend(Notifier, Modals, {
|
||||||
let spacePermissions = this.get('spacePermissions');
|
let spacePermissions = this.get('spacePermissions');
|
||||||
let filteredUsers = A([]);
|
let filteredUsers = A([]);
|
||||||
|
|
||||||
this.showWait();
|
|
||||||
|
|
||||||
this.get('userSvc').matchUsers(s).then((users) => {
|
this.get('userSvc').matchUsers(s).then((users) => {
|
||||||
users.forEach((user) => {
|
users.forEach((user) => {
|
||||||
let exists = spacePermissions.findBy('whoId', user.get('id'));
|
let exists = spacePermissions.findBy('whoId', user.get('id'));
|
||||||
|
@ -144,11 +144,30 @@ export default Component.extend(Notifier, Modals, {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.set('filteredUsers', filteredUsers);
|
this.set('filteredUsers', filteredUsers);
|
||||||
this.showDone();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
toggleSpacePerms() {
|
||||||
|
this.set('showSpacePermExplain', !this.get('showSpacePermExplain'));
|
||||||
|
|
||||||
|
if (this.showSpacePermExplain) {
|
||||||
|
this.$(".space-perms").show();
|
||||||
|
} else {
|
||||||
|
this.$(".space-perms").hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleDocumentPerms() {
|
||||||
|
this.set('showDocumentPermExplain', !this.get('showDocumentPermExplain'));
|
||||||
|
|
||||||
|
if (this.showDocumentPermExplain) {
|
||||||
|
this.$(".document-perms").show();
|
||||||
|
} else {
|
||||||
|
this.$(".document-perms").hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
onShowInviteModal() {
|
onShowInviteModal() {
|
||||||
this.modalOpen("#space-invite-user-modal", {"show": true}, '#space-invite-email');
|
this.modalOpen("#space-invite-user-modal", {"show": true}, '#space-invite-email');
|
||||||
},
|
},
|
||||||
|
@ -160,9 +179,7 @@ export default Component.extend(Notifier, Modals, {
|
||||||
onSave() {
|
onSave() {
|
||||||
if (!this.get('isSpaceAdmin')) return;
|
if (!this.get('isSpaceAdmin')) return;
|
||||||
|
|
||||||
this.showWait();
|
let message = this.getDefaultInvitationMessage();
|
||||||
|
|
||||||
let message = this.getDefaultInvitationMessage();
|
|
||||||
let permissions = this.get('spacePermissions');
|
let permissions = this.get('spacePermissions');
|
||||||
let folder = this.get('folder');
|
let folder = this.get('folder');
|
||||||
let payload = { Message: message, Permissions: permissions };
|
let payload = { Message: message, Permissions: permissions };
|
||||||
|
@ -197,7 +214,7 @@ export default Component.extend(Notifier, Modals, {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.get('spaceSvc').savePermissions(folder.get('id'), payload).then(() => {
|
this.get('spaceSvc').savePermissions(folder.get('id'), payload).then(() => {
|
||||||
this.showDone();
|
this.notifySuccess('Saved');
|
||||||
this.get('onRefresh')();
|
this.get('onRefresh')();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -219,17 +236,13 @@ export default Component.extend(Notifier, Modals, {
|
||||||
let spacePermissions = this.get('spacePermissions');
|
let spacePermissions = this.get('spacePermissions');
|
||||||
let constants = this.get('constants');
|
let constants = this.get('constants');
|
||||||
|
|
||||||
this.showWait();
|
let exists = spacePermissions.findBy('whoId', user.get('id'));
|
||||||
|
|
||||||
let exists = spacePermissions.findBy('whoId', user.get('id'));
|
|
||||||
|
|
||||||
if (is.undefined(exists)) {
|
if (is.undefined(exists)) {
|
||||||
spacePermissions.pushObject(this.permissionRecord(constants.WhoType.User, user.get('id'), user.get('fullname')));
|
spacePermissions.pushObject(this.permissionRecord(constants.WhoType.User, user.get('id'), user.get('fullname')));
|
||||||
this.set('spacePermissions', spacePermissions);
|
this.set('spacePermissions', spacePermissions);
|
||||||
this.send('onSearch');
|
this.send('onSearch');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showDone();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onSpaceInvite(e) {
|
onSpaceInvite(e) {
|
||||||
|
@ -248,9 +261,7 @@ export default Component.extend(Notifier, Modals, {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showWait();
|
var result = {
|
||||||
|
|
||||||
var result = {
|
|
||||||
Message: message,
|
Message: message,
|
||||||
Recipients: []
|
Recipients: []
|
||||||
};
|
};
|
||||||
|
@ -271,7 +282,7 @@ export default Component.extend(Notifier, Modals, {
|
||||||
this.set('inviteEmail', '');
|
this.set('inviteEmail', '');
|
||||||
|
|
||||||
this.get('spaceSvc').share(this.get('folder.id'), result).then(() => {
|
this.get('spaceSvc').share(this.get('folder.id'), result).then(() => {
|
||||||
this.showDone();
|
this.notifySuccess('Invites sent');
|
||||||
this.$('#space-invite-email').removeClass('is-invalid');
|
this.$('#space-invite-email').removeClass('is-invalid');
|
||||||
this.modalClose("#space-invite-user-modal");
|
this.modalClose("#space-invite-user-modal");
|
||||||
this.load();
|
this.load();
|
||||||
|
|
|
@ -1,37 +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
|
|
||||||
|
|
||||||
import { inject as service } from '@ember/service';
|
|
||||||
import { computed } from '@ember/object';
|
|
||||||
import stringUtil from '../../utils/string';
|
|
||||||
import AuthMixin from '../../mixins/auth';
|
|
||||||
import Notifier from '../../mixins/notifier';
|
|
||||||
import Component from '@ember/component';
|
|
||||||
|
|
||||||
export default Component.extend(AuthMixin, Notifier, {
|
|
||||||
spaceSvc: service('folder'),
|
|
||||||
|
|
||||||
isSpaceAdmin: computed('permissions', function() {
|
|
||||||
return this.get('permissions.spaceOwner') || this.get('permissions.spaceManage');
|
|
||||||
}),
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
onOpenTemplate(id) {
|
|
||||||
if (is.empty(id)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let template = this.get('templates').findBy('id', id)
|
|
||||||
|
|
||||||
let slug = stringUtil.makeSlug(template.get('title'));
|
|
||||||
this.get('router').transitionTo('document', this.get('space.id'), this.get('space.slug'), id, slug);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -17,6 +17,7 @@ import AuthMixin from '../../mixins/auth';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(AuthMixin, {
|
export default Component.extend(AuthMixin, {
|
||||||
|
classNames: ["section"],
|
||||||
router: service(),
|
router: service(),
|
||||||
documentService: service('document'),
|
documentService: service('document'),
|
||||||
folderService: service('folder'),
|
folderService: service('folder'),
|
||||||
|
@ -26,6 +27,8 @@ export default Component.extend(AuthMixin, {
|
||||||
spaceSettings: computed('permissions', function() {
|
spaceSettings: computed('permissions', function() {
|
||||||
return this.get('permissions.spaceOwner') || this.get('permissions.spaceManage');
|
return this.get('permissions.spaceOwner') || this.get('permissions.spaceManage');
|
||||||
}),
|
}),
|
||||||
|
selectedFilter: '',
|
||||||
|
spaceLabel: null,
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
@ -53,6 +56,7 @@ export default Component.extend(AuthMixin, {
|
||||||
|
|
||||||
this.set('categories', categories);
|
this.set('categories', categories);
|
||||||
this.set('categoryLinkName', categories.length > 0 ? 'Manage' : 'Add');
|
this.set('categoryLinkName', categories.length > 0 ? 'Manage' : 'Add');
|
||||||
|
this.set('spaceLabel', _.findWhere(this.get('labels'), {id: this.get('space.labelId')}));
|
||||||
|
|
||||||
schedule('afterRender', () => {
|
schedule('afterRender', () => {
|
||||||
if (this.get('categoryFilter') !== '') {
|
if (this.get('categoryFilter') !== '') {
|
||||||
|
@ -81,8 +85,6 @@ export default Component.extend(AuthMixin, {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.set('categoryFilter', id);
|
this.set('categoryFilter', id);
|
||||||
this.set('spaceSelected', false);
|
|
||||||
this.set('uncategorizedSelected', false);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'uncategorized':
|
case 'uncategorized':
|
||||||
|
@ -94,19 +96,29 @@ export default Component.extend(AuthMixin, {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.set('categoryFilter', '');
|
this.set('categoryFilter', '');
|
||||||
this.set('spaceSelected', false);
|
|
||||||
this.set('uncategorizedSelected', true);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'space':
|
case 'space':
|
||||||
allowed = _.pluck(categoryMembers, 'documentId');
|
|
||||||
docs.forEach((d) => {
|
docs.forEach((d) => {
|
||||||
filtered.pushObject(d);
|
filtered.pushObject(d);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.set('categoryFilter', '');
|
this.set('categoryFilter', '');
|
||||||
this.set('spaceSelected', true);
|
break;
|
||||||
this.set('uncategorizedSelected', false);
|
|
||||||
|
case 'template':
|
||||||
|
filtered.pushObjects(this.get('templates'));
|
||||||
|
this.set('categoryFilter', '');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'draft':
|
||||||
|
filtered = this.get('documentsDraft');
|
||||||
|
this.set('categoryFilter', '');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'live':
|
||||||
|
filtered = this.get('documentsLive');
|
||||||
|
this.set('categoryFilter', '');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +126,7 @@ export default Component.extend(AuthMixin, {
|
||||||
cat.set('selected', cat.get('id') === id);
|
cat.set('selected', cat.get('id') === id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.set('selectedFilter', filter);
|
||||||
this.set('categories', categories);
|
this.set('categories', categories);
|
||||||
this.get('onFiltered')(filtered);
|
this.get('onFiltered')(filtered);
|
||||||
}
|
}
|
|
@ -13,13 +13,13 @@ import $ from 'jquery';
|
||||||
import { computed } from '@ember/object';
|
import { computed } from '@ember/object';
|
||||||
import { schedule } from '@ember/runloop';
|
import { schedule } from '@ember/runloop';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import TooltipMixin from '../../mixins/tooltip';
|
|
||||||
import ModalMixin from '../../mixins/modal';
|
import ModalMixin from '../../mixins/modal';
|
||||||
import AuthMixin from '../../mixins/auth';
|
import AuthMixin from '../../mixins/auth';
|
||||||
import Notifier from '../../mixins/notifier';
|
import Notifier from '../../mixins/notifier';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, Notifier, {
|
export default Component.extend(ModalMixin, AuthMixin, Notifier, {
|
||||||
|
classNames: ["display-inline-block"],
|
||||||
spaceService: service('folder'),
|
spaceService: service('folder'),
|
||||||
localStorage: service(),
|
localStorage: service(),
|
||||||
templateService: service('template'),
|
templateService: service('template'),
|
||||||
|
@ -75,7 +75,6 @@ export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, Notifier, {
|
||||||
this.set('pinState.pinId', pinId);
|
this.set('pinState.pinId', pinId);
|
||||||
this.set('pinState.isPinned', pinId !== '');
|
this.set('pinState.isPinned', pinId !== '');
|
||||||
this.set('pinState.newName', folder.get('name'));
|
this.set('pinState.newName', folder.get('name'));
|
||||||
this.renderTooltips();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let cats = this.get('categories');
|
let cats = this.get('categories');
|
||||||
|
@ -92,7 +91,6 @@ export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, Notifier, {
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.removeTooltips();
|
|
||||||
|
|
||||||
if (is.not.null(this.get('dropzone'))) {
|
if (is.not.null(this.get('dropzone'))) {
|
||||||
this.get('dropzone').destroy();
|
this.get('dropzone').destroy();
|
||||||
|
@ -152,11 +150,9 @@ export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, Notifier, {
|
||||||
actions: {
|
actions: {
|
||||||
onUnpin() {
|
onUnpin() {
|
||||||
this.get('pinned').unpinItem(this.get('pinState.pinId')).then(() => {
|
this.get('pinned').unpinItem(this.get('pinState.pinId')).then(() => {
|
||||||
$('#space-pin-button').tooltip('dispose');
|
|
||||||
this.set('pinState.isPinned', false);
|
this.set('pinState.isPinned', false);
|
||||||
this.set('pinState.pinId', '');
|
this.set('pinState.pinId', '');
|
||||||
this.eventBus.publish('pinChange');
|
this.eventBus.publish('pinChange');
|
||||||
this.renderTooltips();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -168,11 +164,9 @@ export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, Notifier, {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.get('pinned').pinItem(pin).then((pin) => {
|
this.get('pinned').pinItem(pin).then((pin) => {
|
||||||
$('#space-pin-button').tooltip('dispose');
|
|
||||||
this.set('pinState.isPinned', true);
|
this.set('pinState.isPinned', true);
|
||||||
this.set('pinState.pinId', pin.get('id'));
|
this.set('pinState.pinId', pin.get('id'));
|
||||||
this.eventBus.publish('pinChange');
|
this.eventBus.publish('pinChange');
|
||||||
this.renderTooltips();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -288,8 +282,6 @@ export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, Notifier, {
|
||||||
},
|
},
|
||||||
|
|
||||||
onExport() {
|
onExport() {
|
||||||
this.showWait();
|
|
||||||
|
|
||||||
let spec = {
|
let spec = {
|
||||||
spaceId: this.get('space.id'),
|
spaceId: this.get('space.id'),
|
||||||
data: [],
|
data: [],
|
||||||
|
@ -310,7 +302,7 @@ export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, Notifier, {
|
||||||
|
|
||||||
this.get('documentSvc').export(spec).then((htmlExport) => {
|
this.get('documentSvc').export(spec).then((htmlExport) => {
|
||||||
this.get('browserSvc').downloadFile(htmlExport, this.get('space.slug') + '.html');
|
this.get('browserSvc').downloadFile(htmlExport, this.get('space.slug') + '.html');
|
||||||
this.showDone();
|
this.notifySuccess('Exported');
|
||||||
});
|
});
|
||||||
|
|
||||||
this.modalClose("#space-export-modal");
|
this.modalClose("#space-export-modal");
|
|
@ -1,62 +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
|
|
||||||
|
|
||||||
import $ from 'jquery';
|
|
||||||
import { inject as service } from '@ember/service';
|
|
||||||
import Component from '@ember/component';
|
|
||||||
|
|
||||||
export default Component.extend({
|
|
||||||
classNames: ['layout-footer', 'non-printable'],
|
|
||||||
tagName: 'footer',
|
|
||||||
appMeta: service(),
|
|
||||||
showWait: false,
|
|
||||||
showDone: false,
|
|
||||||
showMessage: false,
|
|
||||||
message: '',
|
|
||||||
|
|
||||||
init() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.eventBus.subscribe('notifyUser', this, 'processNotification');
|
|
||||||
},
|
|
||||||
|
|
||||||
processNotification(msg) {
|
|
||||||
if (this.get('isDestroyed') || this.get('isDestroying')) return;
|
|
||||||
|
|
||||||
if (msg === 'wait') {
|
|
||||||
this.set('showWait', true);
|
|
||||||
this.set('showMessage', false);
|
|
||||||
this.set('showDone', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg === 'done') {
|
|
||||||
$('.progress-done').removeClass('zoomOut').addClass('zoomIn');
|
|
||||||
this.set('showWait', false);
|
|
||||||
this.set('showMessage', false);
|
|
||||||
this.set('showDone', true);
|
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
$('.progress-done').removeClass('zoomIn').addClass('zoomOut');
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg !== 'done' && msg !== 'wait') {
|
|
||||||
$('.progress-notification').removeClass('zoomOut').addClass('zoomIn');
|
|
||||||
this.set('showWait', false);
|
|
||||||
this.set('showDone', false);
|
|
||||||
this.set('showMessage', true);
|
|
||||||
this.set('message', msg);
|
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
$('.progress-notification').removeClass('zoomIn').addClass('zoomOut');
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
28
gui/app/components/layout/logo-heading.js
Normal file
28
gui/app/components/layout/logo-heading.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
import Component from '@ember/component';
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
appMeta: service(),
|
||||||
|
icon: null,
|
||||||
|
meta: null,
|
||||||
|
logo: false,
|
||||||
|
|
||||||
|
didReceiveAttrs() {
|
||||||
|
this._super(...arguments);
|
||||||
|
if (this.get('logo')) {
|
||||||
|
let cb = + new Date();
|
||||||
|
this.set('cacheBuster', cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -12,21 +12,14 @@
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
tagName: 'nav',
|
tagName: 'div',
|
||||||
classNames: ['layout-sidebar', 'non-printable'],
|
classNames: ['master-container'],
|
||||||
classNameBindings: ['scrollable:sidebar-scroll'],
|
|
||||||
scrollable: false,
|
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
// let sb = this.$().overlayScrollbars({ scrollbars: { autoHide: 'leave' }});
|
|
||||||
// this.set('scrollbars', sb);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
// let sb = this.get('scrollbars');
|
|
||||||
// sb.destroy();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -11,14 +11,14 @@
|
||||||
|
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import { notEmpty } from '@ember/object/computed';
|
import { notEmpty } from '@ember/object/computed';
|
||||||
import { inject as service } from '@ember/service'
|
import { inject as service } from '@ember/service';
|
||||||
import ModalMixin from '../../mixins/modal';
|
import Modals from '../../mixins/modal';
|
||||||
import TooltipMixin from '../../mixins/tooltip';
|
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(ModalMixin, TooltipMixin, {
|
export default Component.extend(Modals, {
|
||||||
classNames: ['layout-header', 'non-printable'],
|
tagName: 'div',
|
||||||
tagName: 'header',
|
classNames: ['master-sidebar-container', 'non-printable'],
|
||||||
|
selectedItem: '',
|
||||||
folderService: service('folder'),
|
folderService: service('folder'),
|
||||||
appMeta: service(),
|
appMeta: service(),
|
||||||
session: service(),
|
session: service(),
|
||||||
|
@ -30,9 +30,11 @@ export default Component.extend(ModalMixin, TooltipMixin, {
|
||||||
hasDocumentPins: notEmpty('documentPins'),
|
hasDocumentPins: notEmpty('documentPins'),
|
||||||
hasWhatsNew: false,
|
hasWhatsNew: false,
|
||||||
newsContent: '',
|
newsContent: '',
|
||||||
|
hideNavigation: false,
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
let constants = this.get('constants');
|
let constants = this.get('constants');
|
||||||
|
|
||||||
this.pins = [];
|
this.pins = [];
|
||||||
|
@ -71,7 +73,15 @@ export default Component.extend(ModalMixin, TooltipMixin, {
|
||||||
this.setupPins();
|
this.setupPins();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.renderTooltips();
|
this.eventBus.subscribe('notifyUser', this, 'processNotification');
|
||||||
|
},
|
||||||
|
|
||||||
|
willDestroyElement() {
|
||||||
|
this._super(...arguments);
|
||||||
|
|
||||||
|
this.eventBus.unsubscribe('notifyUser');
|
||||||
|
this.eventBus.unsubscribe('pinChange');
|
||||||
|
iziToast.destroy();
|
||||||
},
|
},
|
||||||
|
|
||||||
setupPins() {
|
setupPins() {
|
||||||
|
@ -87,11 +97,39 @@ export default Component.extend(ModalMixin, TooltipMixin, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
willDestroyElement() {
|
processNotification(msg, type) {
|
||||||
this._super(...arguments);
|
if (this.get('isDestroyed') || this.get('isDestroying')) return;
|
||||||
|
|
||||||
this.removeTooltips();
|
if (is.not.undefined(type)) {
|
||||||
this.eventBus.unsubscribe('pinChange');
|
switch (type) {
|
||||||
|
case 'info':
|
||||||
|
iziToast.info({
|
||||||
|
title: '',
|
||||||
|
message: msg,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'success':
|
||||||
|
iziToast.success({
|
||||||
|
title: '',
|
||||||
|
message: msg,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'warn':
|
||||||
|
iziToast.warning({
|
||||||
|
title: '',
|
||||||
|
message: msg,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'error':
|
||||||
|
iziToast.error({
|
||||||
|
title: '',
|
||||||
|
message: msg,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
@ -110,12 +148,11 @@ export default Component.extend(ModalMixin, TooltipMixin, {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onShowWhatsNewModal() {
|
onNew() {
|
||||||
this.modalOpen("#whats-new-modal", { "show": true });
|
|
||||||
|
|
||||||
if (this.get('newsContent.length') > 0) {
|
if (this.get('newsContent.length') > 0) {
|
||||||
this.get('session').seenNewVersion();
|
this.get('session').seenNewVersion();
|
||||||
this.set('hasWhatsNew', false);
|
this.set('hasWhatsNew', false);
|
||||||
|
this.get('router').transitionTo('updates');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -13,6 +13,6 @@
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNames: ['layout-body'],
|
tagName: 'p',
|
||||||
tagName: 'main'
|
classNames: ['master-page-desc'],
|
||||||
});
|
});
|
|
@ -13,6 +13,6 @@
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNames: ['layout-content'],
|
tagName: 'h1',
|
||||||
tagName: 'article'
|
classNames: ['master-page-heading'],
|
||||||
});
|
});
|
|
@ -95,11 +95,14 @@ export default Component.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($("#stage-2-password-confirm").val() !== $("#stage-2-password").val()) {
|
if ($("#stage-2-password-confirm").val() !== $("#stage-2-password").val()) {
|
||||||
$(".mismatch").show();
|
$("#stage-2-password").addClass("is-invalid");
|
||||||
|
$("#stage-2-password-confirm").addClass("is-invalid");
|
||||||
|
// $(".mismatch").show();
|
||||||
// $(".password-status").attr("src", "/assets/img/onboard/lock-red.png");
|
// $(".password-status").attr("src", "/assets/img/onboard/lock-red.png");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$("#stage-2-password").removeClass("is-invalid");
|
||||||
$("#stage-2-password-confirm").removeClass("is-invalid");
|
$("#stage-2-password-confirm").removeClass("is-invalid");
|
||||||
|
|
||||||
self.set('processing', false);
|
self.set('processing', false);
|
||||||
|
@ -121,7 +124,7 @@ export default Component.extend({
|
||||||
let creds = { password: password, email: user.email };
|
let creds = { password: password, email: user.email };
|
||||||
|
|
||||||
self.get('session').authenticate('authenticator:documize', creds).then(() => {
|
self.get('session').authenticate('authenticator:documize', creds).then(() => {
|
||||||
window.location.href = 's/' + self.folderId + "/" + self.slug;
|
window.location.href = '//' + window.location.host + '/s/' + self.folderId + "/" + self.slug;
|
||||||
});
|
});
|
||||||
|
|
||||||
// var credentials = encodingUtil.Base64.encode(netUtil.getSubdomain() + ":" + user.email + ":" + password);
|
// var credentials = encodingUtil.Base64.encode(netUtil.getSubdomain() + ":" + user.email + ":" + password);
|
||||||
|
|
|
@ -12,11 +12,10 @@
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import { empty } from '@ember/object/computed';
|
import { empty } from '@ember/object/computed';
|
||||||
import { computed } from '@ember/object';
|
import { computed } from '@ember/object';
|
||||||
import TooltipMixin from '../../mixins/tooltip';
|
|
||||||
import ModalMixin from '../../mixins/modal';
|
import ModalMixin from '../../mixins/modal';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(TooltipMixin, ModalMixin, {
|
export default Component.extend(ModalMixin, {
|
||||||
busy: false,
|
busy: false,
|
||||||
mousetrap: null,
|
mousetrap: null,
|
||||||
showLinkModal: false,
|
showLinkModal: false,
|
||||||
|
@ -57,15 +56,11 @@ export default Component.extend(TooltipMixin, ModalMixin, {
|
||||||
$('#' + this.get('pageId')).focus(function() {
|
$('#' + this.get('pageId')).focus(function() {
|
||||||
$(this).select();
|
$(this).select();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.renderTooltips();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
this.removeTooltips();
|
|
||||||
|
|
||||||
let mousetrap = this.get('mousetrap');
|
let mousetrap = this.get('mousetrap');
|
||||||
if (is.not.null(mousetrap)) {
|
if (is.not.null(mousetrap)) {
|
||||||
mousetrap.unbind('esc');
|
mousetrap.unbind('esc');
|
||||||
|
|
|
@ -10,10 +10,9 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
import { computed } from '@ember/object';
|
import { computed } from '@ember/object';
|
||||||
import TooltipMixin from '../../../mixins/tooltip';
|
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(TooltipMixin, {
|
export default Component.extend({
|
||||||
isDirty: false,
|
isDirty: false,
|
||||||
pageBody: "",
|
pageBody: "",
|
||||||
codeSyntax: null,
|
codeSyntax: null,
|
||||||
|
@ -100,9 +99,6 @@ export default Component.extend(TooltipMixin, {
|
||||||
editor = null;
|
editor = null;
|
||||||
this.set('codeEditor', null);
|
this.set('codeEditor', null);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.removeTooltips();
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Wrap code in PRE tag with language identifier for subsequent rendering.
|
// Wrap code in PRE tag with language identifier for subsequent rendering.
|
||||||
|
|
|
@ -13,11 +13,10 @@ import $ from 'jquery';
|
||||||
import { set } from '@ember/object';
|
import { set } from '@ember/object';
|
||||||
import { schedule } from '@ember/runloop';
|
import { schedule } from '@ember/runloop';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import Component from '@ember/component';
|
|
||||||
import SectionMixin from '../../../mixins/section';
|
import SectionMixin from '../../../mixins/section';
|
||||||
import TooltipMixin from '../../../mixins/tooltip';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(SectionMixin, TooltipMixin, {
|
export default Component.extend(SectionMixin, {
|
||||||
sectionService: service('section'),
|
sectionService: service('section'),
|
||||||
isDirty: false,
|
isDirty: false,
|
||||||
waiting: false,
|
waiting: false,
|
||||||
|
@ -27,7 +26,7 @@ export default Component.extend(SectionMixin, TooltipMixin, {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.user = {};
|
this.user = {};
|
||||||
this.workspaces = [];
|
this.workspaces = [];
|
||||||
this.config = {};
|
this.config = {};
|
||||||
},
|
},
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
|
@ -92,7 +91,6 @@ export default Component.extend(SectionMixin, TooltipMixin, {
|
||||||
|
|
||||||
schedule('afterRender', () => {
|
schedule('afterRender', () => {
|
||||||
window.scrollTo(0, document.body.scrollHeight);
|
window.scrollTo(0, document.body.scrollHeight);
|
||||||
self.renderTooltips();
|
|
||||||
});
|
});
|
||||||
self.set('waiting', false);
|
self.set('waiting', false);
|
||||||
}, function (reason) { // eslint-disable-line no-unused-vars
|
}, function (reason) { // eslint-disable-line no-unused-vars
|
||||||
|
|
|
@ -10,11 +10,10 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import Component from '@ember/component';
|
|
||||||
import SectionMixin from '../../../mixins/section';
|
import SectionMixin from '../../../mixins/section';
|
||||||
import TooltipMixin from '../../../mixins/tooltip';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(SectionMixin, TooltipMixin, {
|
export default Component.extend(SectionMixin, {
|
||||||
sectionService: service('section'),
|
sectionService: service('section'),
|
||||||
isDirty: false,
|
isDirty: false,
|
||||||
waiting: false,
|
waiting: false,
|
||||||
|
|
|
@ -33,7 +33,7 @@ export default Component.extend({
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
let body = (is.not.undefined(this.get('meta'))) ? this.get('meta.rawBody').trim() : '';
|
let body = (is.not.undefined(this.get('meta'))) ? this.get('meta.rawBody').trim() : '';
|
||||||
this.set('pageBody', body);
|
this.set('pageBody', body);
|
||||||
},
|
},
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
|
@ -67,7 +67,7 @@ export default Component.extend({
|
||||||
dragDrop: false,
|
dragDrop: false,
|
||||||
extraKeys: {"Enter": "newlineAndIndentContinueMarkdownList"}
|
extraKeys: {"Enter": "newlineAndIndentContinueMarkdownList"}
|
||||||
});
|
});
|
||||||
|
|
||||||
CodeMirror.commands.save = function(/*instance*/){
|
CodeMirror.commands.save = function(/*instance*/){
|
||||||
Mousetrap.trigger('ctrl+s');
|
Mousetrap.trigger('ctrl+s');
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,12 +14,11 @@ import $ from 'jquery';
|
||||||
import { htmlSafe } from '@ember/string';
|
import { htmlSafe } from '@ember/string';
|
||||||
import { computed, set } from '@ember/object';
|
import { computed, set } from '@ember/object';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import Component from '@ember/component';
|
|
||||||
import NotifierMixin from '../../../mixins/notifier';
|
import NotifierMixin from '../../../mixins/notifier';
|
||||||
import TooltipMixin from '../../../mixins/tooltip';
|
|
||||||
import SectionMixin from '../../../mixins/section';
|
import SectionMixin from '../../../mixins/section';
|
||||||
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend(SectionMixin, NotifierMixin, TooltipMixin, {
|
export default Component.extend(SectionMixin, NotifierMixin, {
|
||||||
sectionService: service('section'),
|
sectionService: service('section'),
|
||||||
isDirty: false,
|
isDirty: false,
|
||||||
busy: false,
|
busy: false,
|
||||||
|
@ -93,10 +92,6 @@ export default Component.extend(SectionMixin, NotifierMixin, TooltipMixin, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
willDestroyElement() {
|
|
||||||
this.removeTooltips();
|
|
||||||
},
|
|
||||||
|
|
||||||
getBoardLists() {
|
getBoardLists() {
|
||||||
this.set('busy', true);
|
this.set('busy', true);
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue