1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-22 14:49:42 +02:00

moved document meta

This commit is contained in:
Harvey Kandola 2016-11-20 13:41:43 -08:00
parent 877a6b5096
commit 39fcb04604
28 changed files with 859 additions and 836 deletions

View file

@ -8,7 +8,7 @@ The mission is to bring software dev inspired features (refactoring, testing, li
## Latest version
v0.31.0
v0.32.0
## OS Support

View file

@ -1,47 +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 Ember from 'ember';
import NotifierMixin from '../../mixins/notifier';
import TooltipMixin from '../../mixins/tooltip';
export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
appMeta: Ember.inject.service(),
didReceiveAttrs() {
// setup document owner
let owner = this.get('users').findBy('id', this.get('document.userId'));
// no document owner? You are the owner!
if (is.undefined(owner)) {
owner = this.session.user;
}
this.set('owner', owner);
},
actions: {
onSave() {
let doc = this.get('document');
if (is.empty(doc.get('excerpt'))) {
$("meta-excerpt").addClass("error").focus();
return false;
}
doc.set('excerpt', doc.get('excerpt').substring(0, 250));
doc.set('userId', this.get('owner.id'));
this.attrs.onSave(doc);
return true;
},
}
});

View file

@ -71,6 +71,25 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
this.attrs.onSaveTemplate(name, excerpt);
return true;
}
},
saveMeta() {
let doc = this.get('document');
if (is.empty(doc.get('name'))) {
$("#meta-name").addClass("error").focus();
return false;
}
if (is.empty(doc.get('excerpt'))) {
$("#meta-excerpt").addClass("error").focus();
return false;
}
doc.set('excerpt', doc.get('excerpt').substring(0, 250));
this.attrs.onSaveMeta(doc);
return true;
},
}
});
});

View file

@ -12,5 +12,11 @@
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'span'
tagName: 'span',
actions: {
onCheck() {
this.set('selected', !this.get('selected'));
}
}
});

View file

@ -1,11 +1,11 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// 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>.
// by contacting <sales@documize.com>.
//
// https://documize.com
@ -14,7 +14,13 @@ import dateUtil from '../utils/date';
// {{time-ago createdAt}}
export function timeAgo(params) {
return dateUtil.timeAgo(params[0]);
let d = dateUtil.timeAgo(params[0]);
if (d === 'Invalid date'){
d = '';
}
return d;
}
export default Ember.Helper.helper(timeAgo);
export default Ember.Helper.helper(timeAgo);

View file

@ -55,7 +55,7 @@ export default Ember.Controller.extend(NotifierMixin, {
},
onPassword(user, password) {
this.get('userService').updatePassword(user.get('id'), password);
this.get('userService').updatePassword(user.id, password);
this.showNotification('Password changed');
}
}

View file

@ -92,6 +92,12 @@ export default Ember.Controller.extend(NotifierMixin, {
this.get('templateService').saveAsTemplate(this.get('model.document.id'), name, desc).then(function () {});
},
onSaveMeta(doc) {
this.get('documentService').save(doc).then(() => {
this.transitionToRoute('document.index');
});
},
onAddSection(section) {
this.audit.record("added-section-" + section.get('contentType'));

View file

@ -1,24 +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 Ember from 'ember';
export default Ember.Controller.extend({
documentService: Ember.inject.service('document'),
actions: {
onSave(doc) {
this.get('documentService').save(doc).then(() => {
this.transitionToRoute('document.index');
});
}
}
});

View file

@ -1,33 +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 Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
userService: Ember.inject.service('user'),
model() {
this.audit.record("viewed-document-meta");
let folderId = this.modelFor('document').folder.get('id');
return Ember.RSVP.hash({
folders: this.modelFor('document').folders,
folder: this.modelFor('document').folder,
document: this.modelFor('document').document,
isEditor: this.modelFor('document').isEditor,
pages: this.modelFor('document').allPages,
tabs: this.modelFor('document').tabs,
users: this.get('userService').getFolderUsers(folderId)
});
}
});

View file

@ -1 +0,0 @@
{{document/document-meta document=model.document folders=model.folders folder=model.folder users=model.users isEditor=model.isEditor onSave=(action 'onSave')}}

View file

@ -23,20 +23,24 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
this.set('documentId', this.paramsFor('document').document_id);
return new Ember.RSVP.Promise((resolve) => {
this.get('folderService').getAll().then((folders) => {
this.set('folders', folders);
this.get('documentService').getDocument(this.get('documentId')).then((document) => {
this.set('document', document);
this.get('folderService').getFolder(this.get('folderId')).then((folder) => {
this.set('folder', folder);
this.get('folderService').getAll().then((folders) => {
this.set('folders', folders);
this.get('folderService').setCurrentFolder(folder).then(() => {
this.set('isEditor', this.get('folderService').get('canEditCurrentFolder'));
this.get('folderService').getFolder(this.get('folderId')).then((folder) => {
this.set('folder', folder);
this.get('documentService').getPages(this.get('documentId')).then((pages) => {
this.set('allPages', pages);
this.set('pages', pages.filterBy('pageType', 'section'));
this.set('tabs', pages.filterBy('pageType', 'tab'));
resolve();
this.get('folderService').setCurrentFolder(folder).then(() => {
this.set('isEditor', this.get('folderService').get('canEditCurrentFolder'));
this.get('documentService').getPages(this.get('documentId')).then((pages) => {
this.set('allPages', pages);
this.set('pages', pages.filterBy('pageType', 'section'));
this.set('tabs', pages.filterBy('pageType', 'tab'));
resolve();
});
});
});
});
@ -48,9 +52,7 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
return Ember.RSVP.hash({
folders: this.get('folders'),
folder: this.get('folder'),
document: this.get('documentService').getDocument(this.get('documentId')).then((document) => {
return document;
}),
document: this.get('document'),
page: this.get('pageId'),
isEditor: this.get('isEditor'),
allPages: this.get('allPages'),
@ -65,7 +67,7 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
actions: {
error(error /*, transition*/ ) {
console.log(error);
console.log(error.stack);
if (error) {
this.transitionTo('/not-found');
return false;

View file

@ -7,7 +7,7 @@
{{#layout/zone-content}}
{{document/document-toolbar document=model.document pages=model.pages tabs=model.tabs folder=model.folder isEditor=model.isEditor
onSaveTemplate=(action 'onSaveTemplate') onDocumentDelete=(action 'onDocumentDelete')}}
onSaveTemplate=(action 'onSaveTemplate') onSaveMeta=(action 'onSaveMeta') onDocumentDelete=(action 'onDocumentDelete')}}
{{outlet}}
{{/layout/zone-content}}

View file

@ -35,9 +35,6 @@ export default Router.map(function () {
this.route('files', {
path: 'files'
});
this.route('meta', {
path: 'meta'
});
this.route('activity', {
path: 'activity'
});

View file

@ -27,6 +27,9 @@ export default Ember.Service.extend({
}).then((response) => {
let data = this.get('store').normalize('document', response);
return this.get('store').push(data);
}).catch((error) => {
this.get('router').transitionTo('/not-found');
return error;
});
},

View file

@ -2,18 +2,19 @@
color: $color-white;
background-color: $color-gray;
@include border-radius(20px);
@include ease-in();
padding: 7px 0 0 0;
letter-spacing: 1px;
text-align: center;
height: 35px;
width: 35px;
cursor: crosshair;
}
.avatar-large {
color: $color-white;
background-color: $color-gray;
@include border-radius(100px);
@include ease-in();
height: 100px;
width: 100px;
font-size: 30px;
@ -21,5 +22,36 @@
letter-spacing: 1px;
text-align: center;
margin: 0 auto;
cursor: crosshair;
}
.avatar-picker {
background-color: $color-off-white;
@include border-radius(20px);
@include ease-in();
padding: 7px 0 0 0;
letter-spacing: 1px;
text-align: center;
height: 35px;
width: 35px;
cursor: pointer;
&:hover {
> i {
color: $color-link;
}
}
> i {
color: $color-gray;
font-size: 1.4rem;
@include ease-in();
}
}
.avatar-remover {
&:hover {
color: $color-white;
background-color: $color-red;
cursor: pointer;
}
}

View file

@ -1,21 +1,27 @@
.checkbox-option {
.ui-checkbox {
vertical-align: bottom;
cursor: pointer;
font-size: 0.9rem;
font-size: 1.1rem;
overflow: hidden;
white-space: nowrap;
margin: 0 0 5px 0;
> .material-icons {
font-size: 0.9rem;
font-size: 1.4rem;
color: $color-gray;
vertical-align: top;
margin-right: 5px;
}
> .selected {
color: $color-link;
}
&:hover {
color: $color-link;
}
}
.checkbox-option-selected {
.ui-checkbox-selected {
color: $color-link;
}

View file

@ -1,27 +0,0 @@
<div class="form-bordered">
<div class="form-header">
<div class="title">Meta Information</div>
<div class="tip">Name, owner, excerpt</div>
</div>
<div class="input-control">
<label>Owner</label>
<div class="tip">Set the document owner</div>
{{ui-select id="document-owner"
content=users
action=(action (mut owner))
optionValuePath="id"
optionLabelPath="fullname"
selection=owner}}
</div>
<div class="input-control">
<label>Name</label>
<div class="tip">Short title for this document</div>
{{focus-input type='text' id="document-name" value=document.name}}
</div>
<div class="input-control">
<label>Excerpt</label>
<div class="tip">Provide short summary of the document (max. 250)</div>
{{textarea value=document.excerpt rows="5" id="meta-excerpt"}}
</div>
<div class="regular-button button-blue" {{ action 'onSave' }}>Save</div>
</div>

View file

@ -7,11 +7,6 @@
<li class="tab">
{{#link-to 'document.files'}}Files{{/link-to}}
</li>
{{#if isEditor}}
<li class="tab">
{{#link-to 'document.meta'}}Meta{{/link-to}}
</li>
{{/if}}
{{#if session.authenticated}}
<li class="tab">
{{#link-to 'document.activity'}}Activity{{/link-to}}
@ -35,6 +30,7 @@
<ul class="options">
{{#if isEditor}}
<li class="option" id="set-meta-button"><i class="material-icons">settings</i></li>
<li class="option" id="save-template-button"><i class="material-icons">content_copy</i></li>
{{/if}}
<li class="option" id="document-toolbar-menu"><i class="material-icons">more_horiz</i></li>
@ -44,7 +40,6 @@
<ul class="menu">
<li class="item" id="print-document-button" {{action 'printDocument'}}>Print</li>
{{#if isEditor}}
<li class="item" id="save-template-button">Save as template</li>
<li class="divider"></li>
<li class="item" id="delete-document-button">Delete</li>
{{/if}}
@ -73,6 +68,19 @@
</div>
</div>
{{/dropdown-dialog}}
{{#dropdown-dialog target="set-meta-button" position="bottom right" button="Save" color="flat-green" onAction=(action 'saveMeta') focusOn="meta-name" }}
<div class="input-control">
<label>Name</label>
<div class="tip">Short title for this document</div>
{{focus-input type='text' id="meta-name" value=document.name}}
</div>
<div class="input-control">
<label>Excerpt</label>
<div class="tip">Provide short summary of the document (max. 250)</div>
{{textarea value=document.excerpt rows="5" id="meta-excerpt"}}
</div>
{{/dropdown-dialog}}
{{/if}}
</div>

View file

@ -1,8 +1,8 @@
<div class="checkbox-option {{if selected 'checkbox-option-selected'}}">
<div class="ui-checkbox {{if selected 'ui-checkbox-selected'}}" {{action 'onCheck'}}>
{{#if selected}}
<i class="material-icons checkbox-option-selected">radio_button_checked</i>
<i class="material-icons selected">check_box</i>
{{else}}
<i class="material-icons">radio_button_unchecked</i>
<i class="material-icons">check_box_outline_blank</i>
{{/if}}
{{yield}}
</div>

View file

@ -51,8 +51,21 @@ function isAjaxAccessError(reason) {
return false;
}
function isAjaxNotFoundError(reason) {
if (typeof reason === "undefined" || typeof reason.errors === "undefined") {
return false;
}
if (reason.errors.length > 0 && (reason.errors[0].status === "404")) {
return true;
}
return false;
}
export default {
getSubdomain,
getAppUrl,
isAjaxAccessError,
};
isAjaxNotFoundError,
};

View file

@ -1,6 +1,6 @@
{
"name": "documize",
"version": "0.31.0",
"version": "0.32.0",
"description": "The Document IDE",
"private": true,
"directories": {

142
app/vendor/dragula.js vendored
View file

@ -323,7 +323,9 @@ function dragula (initialContainers, options) {
var initial = isInitialPlacement(parent);
if (initial === false && reverts) {
if (_copy) {
parent.removeChild(_copy);
if (parent) {
parent.removeChild(_copy);
}
} else {
_source.insertBefore(item, _initialSibling);
}
@ -644,7 +646,10 @@ module.exports = dragula;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./classes":1,"contra/emitter":4,"crossvent":8}],3:[function(require,module,exports){
},{"./classes":1,"contra/emitter":5,"crossvent":6}],3:[function(require,module,exports){
module.exports = function atoa (a, n) { return Array.prototype.slice.call(a, n); }
},{}],4:[function(require,module,exports){
'use strict';
var ticky = require('ticky');
@ -656,7 +661,7 @@ module.exports = function debounce (fn, args, ctx) {
});
};
},{"ticky":6}],4:[function(require,module,exports){
},{"ticky":9}],5:[function(require,module,exports){
'use strict';
var atoa = require('atoa');
@ -712,72 +717,7 @@ module.exports = function emitter (thing, options) {
return thing;
};
},{"./debounce":3,"atoa":5}],5:[function(require,module,exports){
module.exports = function atoa (a, n) { return Array.prototype.slice.call(a, n); }
},{}],6:[function(require,module,exports){
var si = typeof setImmediate === 'function', tick;
if (si) {
tick = function (fn) { setImmediate(fn); };
} else {
tick = function (fn) { setTimeout(fn, 0); };
}
module.exports = tick;
},{}],7:[function(require,module,exports){
(function (global){
var NativeCustomEvent = global.CustomEvent;
function useNative () {
try {
var p = new NativeCustomEvent('cat', { detail: { foo: 'bar' } });
return 'cat' === p.type && 'bar' === p.detail.foo;
} catch (e) {
}
return false;
}
/**
* Cross-browser `CustomEvent` constructor.
*
* https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent.CustomEvent
*
* @public
*/
module.exports = useNative() ? NativeCustomEvent :
// IE >= 9
'function' === typeof document.createEvent ? function CustomEvent (type, params) {
var e = document.createEvent('CustomEvent');
if (params) {
e.initCustomEvent(type, params.bubbles, params.cancelable, params.detail);
} else {
e.initCustomEvent(type, false, false, void 0);
}
return e;
} :
// IE <= 8
function CustomEvent (type, params) {
var e = document.createEventObject();
e.type = type;
if (params) {
e.bubbles = Boolean(params.bubbles);
e.cancelable = Boolean(params.cancelable);
e.detail = params.detail;
} else {
e.bubbles = false;
e.cancelable = false;
e.detail = void 0;
}
return e;
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],8:[function(require,module,exports){
},{"./debounce":4,"atoa":3}],6:[function(require,module,exports){
(function (global){
'use strict';
@ -883,7 +823,7 @@ function find (el, type, fn) {
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./eventmap":9,"custom-event":7}],9:[function(require,module,exports){
},{"./eventmap":7,"custom-event":8}],7:[function(require,module,exports){
(function (global){
'use strict';
@ -901,5 +841,67 @@ module.exports = eventmap;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],8:[function(require,module,exports){
(function (global){
var NativeCustomEvent = global.CustomEvent;
function useNative () {
try {
var p = new NativeCustomEvent('cat', { detail: { foo: 'bar' } });
return 'cat' === p.type && 'bar' === p.detail.foo;
} catch (e) {
}
return false;
}
/**
* Cross-browser `CustomEvent` constructor.
*
* https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent.CustomEvent
*
* @public
*/
module.exports = useNative() ? NativeCustomEvent :
// IE >= 9
'function' === typeof document.createEvent ? function CustomEvent (type, params) {
var e = document.createEvent('CustomEvent');
if (params) {
e.initCustomEvent(type, params.bubbles, params.cancelable, params.detail);
} else {
e.initCustomEvent(type, false, false, void 0);
}
return e;
} :
// IE <= 8
function CustomEvent (type, params) {
var e = document.createEventObject();
e.type = type;
if (params) {
e.bubbles = Boolean(params.bubbles);
e.cancelable = Boolean(params.cancelable);
e.detail = params.detail;
} else {
e.bubbles = false;
e.cancelable = false;
e.detail = void 0;
}
return e;
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],9:[function(require,module,exports){
var si = typeof setImmediate === 'function', tick;
if (si) {
tick = function (fn) { setImmediate(fn); };
} else {
tick = function (fn) { setTimeout(fn, 0); };
}
module.exports = tick;
},{}]},{},[2])(2)
});

View file

@ -206,7 +206,7 @@ func (m *baseManager) DeleteWhere(tx *sqlx.Tx, statement string) (rows int64, er
// Audit inserts a record into the audit table.
func (m *baseManager) Audit(c Context, action, document, page string) {
_, err := Db.Exec("INSERT INTO audit (orgid, userid, documentid, pageid, action) VALUES (?,?,?,?,?)", c.OrgID, c.UserID, document, page, action)
_, err := Db.Exec("INSERT INTO audit (orgid, userid, documentid, pageid, action, created) VALUES (?, ?, ?, ?, ?, ?)", c.OrgID, c.UserID, document, page, action, time.Now().UTC())
if err != nil {
log.Error(fmt.Sprintf("Unable record audit for action %s, user %s, customer %s", action, c.UserID, c.OrgID), err)

View file

@ -101,7 +101,7 @@ func Create(w http.ResponseWriter, r *http.Request) {
Password: r.Form.Get("password"),
Firstname: r.Form.Get("firstname"),
Lastname: r.Form.Get("lastname"),
Revised: time.Now(),
Revised: time.Now().UTC(),
}
if details.Company == "" ||

View file

@ -240,7 +240,7 @@ CREATE TABLE IF NOT EXISTS `revision` (
`pageid` CHAR(16) NOT NULL COLLATE utf8_bin,
`userid` CHAR(16) NOT NULL COLLATE utf8_bin,
`contenttype` CHAR(20) NOT NULL DEFAULT 'wysiwyg',
`pagetype` CHAR(10) NOT NULL DEFAULT 'section',
`pagetype` CHAR(10) NOT NULL DEFAULT 'section',
`title` NVARCHAR(2000) NOT NULL,
`body` LONGTEXT,
`rawbody` LONGBLOB,
@ -334,3 +334,19 @@ CREATE TABLE IF NOT EXISTS `link` (
CONSTRAINT pk_id PRIMARY KEY (id))
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
ENGINE = InnoDB;
DROP TABLE IF EXISTS `participant`;
CREATE TABLE IF NOT EXISTS `participant` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`refid` CHAR(16) NOT NULL COLLATE utf8_bin,
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
`documentid` CHAR(16) NOT NULL COLLATE utf8_bin,
`userid` CHAR(16) DEFAULT '' COLLATE utf8_bin,
`roletype` CHAR(1) NOT NULL DEFAULT 'I' COLLATE utf8_bin,
`lastviewed` TIMESTAMP NULL,
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT pk_id PRIMARY KEY (id),
INDEX `idx_participant_documentid` (`documentid` ASC))
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
ENGINE = InnoDB;

View file

@ -0,0 +1,16 @@
/* enterprise edition */
DROP TABLE IF EXISTS `participant`;
CREATE TABLE IF NOT EXISTS `participant` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`refid` CHAR(16) NOT NULL COLLATE utf8_bin,
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
`documentid` CHAR(16) NOT NULL COLLATE utf8_bin,
`userid` CHAR(16) DEFAULT '' COLLATE utf8_bin,
`roletype` CHAR(1) NOT NULL DEFAULT 'I' COLLATE utf8_bin,
`lastviewed` TIMESTAMP NULL,
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT pk_id PRIMARY KEY (id),
INDEX `idx_participant_documentid` (`documentid` ASC))
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
ENGINE = InnoDB;

View file

@ -26,7 +26,7 @@ type ProdInfo struct {
// Product returns product edition details
func Product() (p ProdInfo) {
p.Major = "0"
p.Minor = "31"
p.Minor = "32"
p.Patch = "0"
p.Version = fmt.Sprintf("%s.%s.%s", p.Major, p.Minor, p.Patch)
p.Edition = "Community"

File diff suppressed because one or more lines are too long