mirror of
https://github.com/documize/community.git
synced 2025-07-24 15:49:44 +02:00
Merge branch 'master' into github-tidy-up
# Conflicts: # embed/bindata_assetfs.go
This commit is contained in:
commit
6f0d503cb5
34 changed files with 792 additions and 449 deletions
5
.gitattributes
vendored
Normal file
5
.gitattributes
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text=auto
|
||||
|
||||
# These files are text and should be normalized (convert crlf > lf)
|
||||
*.hbs text
|
5
.gitconfig
Normal file
5
.gitconfig
Normal file
|
@ -0,0 +1,5 @@
|
|||
[core]
|
||||
whitespace = trailing-space,space-before-tab
|
||||
autocrlf = input
|
||||
[apply]
|
||||
whitespace = fix
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -61,3 +61,5 @@ debug
|
|||
Dockerfile
|
||||
container.sh
|
||||
make.sh
|
||||
|
||||
embed/bindata_assetfs.go
|
||||
|
|
|
@ -30,6 +30,12 @@ v0.15.0
|
|||
|
||||

|
||||
|
||||
## Auth0 Integration
|
||||
|
||||
Documize is compatible with Auth0 identity as a service.
|
||||
|
||||
<a width="150" height="50" href="https://auth0.com/?utm_source=oss&utm_medium=gp&utm_campaign=oss" target="_blank" alt="Single Sign On & Token Based Authentication - Auth0"><img width="150" height="50" alt="JWT Auth for open source projects" src="https://cdn.auth0.com/oss/badges/a0-badge-dark.png"/></a>
|
||||
|
||||
## Legal
|
||||
|
||||
https://documize.com
|
||||
|
|
71
app/app/components/documize-setup.js
Normal file
71
app/app/components/documize-setup.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
// 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';
|
||||
|
||||
const {
|
||||
isEmpty,
|
||||
computed,
|
||||
set
|
||||
|
||||
} = Ember;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
titleEmpty: computed.empty('model.title'),
|
||||
firstnameEmpty: computed.empty('model.firstname'),
|
||||
lastnameEmpty: computed.empty('model.lastname'),
|
||||
emailEmpty: computed.empty('model.email'),
|
||||
passwordEmpty: computed.empty('model.password'),
|
||||
hasEmptyTitleError: computed.and('titleEmpty', 'titleError'),
|
||||
hasEmptyFirstnameError: computed.and('firstnameEmpty', 'adminFirstnameError'),
|
||||
hasEmptyLastnameError: computed.and('lastnameEmpty', 'adminLastnameError'),
|
||||
hasEmptyEmailError: computed.and('emailEmpty', 'adminEmailError'),
|
||||
hasEmptyPasswordError: computed.and('passwordEmpty', 'adminPasswordError'),
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
if (isEmpty(this.get('model.title'))) {
|
||||
set(this, 'titleError', true);
|
||||
return $("#siteTitle").focus();
|
||||
}
|
||||
|
||||
if (isEmpty(this.get('model.firstname'))) {
|
||||
set(this, 'adminFirstnameError', true);
|
||||
return $("#adminFirstname").focus();
|
||||
}
|
||||
|
||||
if (isEmpty(this.get('model.lastname'))) {
|
||||
set(this, 'adminLastnameError', true);
|
||||
return $("#adminLastname").focus();
|
||||
}
|
||||
|
||||
if (isEmpty(this.get('model.email')) || !is.email(this.get('model.email'))) {
|
||||
set(this, 'adminEmailError', true);
|
||||
return $("#adminEmail").focus();
|
||||
}
|
||||
|
||||
if (isEmpty(this.get('model.password'))) {
|
||||
set(this, 'adminPasswordError', true);
|
||||
return $("#adminPassword").focus();
|
||||
}
|
||||
|
||||
this.model.allowAnonymousAccess = Ember.$("#allowAnonymousAccess").prop('checked');
|
||||
|
||||
this.get('save')().then(() => {
|
||||
set(this, 'titleError', false);
|
||||
set(this, 'adminFirstnameError', false);
|
||||
set(this, 'adminLastnameError', false);
|
||||
set(this, 'adminEmailError', false);
|
||||
set(this, 'adminPasswordError', false);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
41
app/app/components/forgot-password.js
Normal file
41
app/app/components/forgot-password.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 Ember from 'ember';
|
||||
|
||||
const {
|
||||
computed,
|
||||
isEmpty
|
||||
} = Ember;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
email: "",
|
||||
sayThanks: false,
|
||||
emailEmpty: computed.empty('email'),
|
||||
hasEmptyEmailError: computed.and('emailEmpty', 'emailIsEmpty'),
|
||||
|
||||
actions: {
|
||||
forgot() {
|
||||
let email = this.get('email');
|
||||
|
||||
if (isEmpty(email)) {
|
||||
Ember.set(this, 'emailIsEmpty', true);
|
||||
return $("#email").focus();
|
||||
}
|
||||
|
||||
this.get('forgot')(email).then(() => {
|
||||
Ember.set(this, 'sayThanks', true);
|
||||
Ember.set(this, 'email', '');
|
||||
Ember.set(this, 'emailIsEmpty', false);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
45
app/app/components/general-settings.js
Normal file
45
app/app/components/general-settings.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
// 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';
|
||||
|
||||
const {
|
||||
isEmpty,
|
||||
computed,
|
||||
set
|
||||
} = Ember;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
titleEmpty: computed.empty('model.title'),
|
||||
messageEmpty: computed.empty('model.message'),
|
||||
hasTitleInputError: computed.and('titleEmpty', 'titleError'),
|
||||
hasMessageInputError: computed.and('messageEmpty', 'messageError'),
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
if (isEmpty(this.get('model.title'))) {
|
||||
set(this, 'titleError', true);
|
||||
return $("#siteTitle").focus();
|
||||
}
|
||||
|
||||
if (isEmpty(this.get('model.message'))) {
|
||||
set(this, 'messageError', true);
|
||||
return $("#siteMessage").focus();
|
||||
}
|
||||
|
||||
this.model.set('allowAnonymousAccess', Ember.$("#allowAnonymousAccess").prop('checked'));
|
||||
this.get('save')().then(() => {
|
||||
set(this, 'titleError', false);
|
||||
set(this, 'messageError', false);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
59
app/app/components/password-reset.js
Normal file
59
app/app/components/password-reset.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// This software (Documize Community Edition) is licensed under
|
||||
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
//
|
||||
// You can operate outside the AGPL restrictions by purchasing
|
||||
// Documize Enterprise Edition and obtaining a commercial license
|
||||
// by contacting <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
import Ember from 'ember';
|
||||
|
||||
const {
|
||||
isEmpty,
|
||||
isEqual,
|
||||
computed,
|
||||
set
|
||||
|
||||
} = Ember;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
password: "",
|
||||
passwordConfirm: "",
|
||||
mustMatch: false,
|
||||
passwordEmpty: computed.empty('password'),
|
||||
confirmEmpty: computed.empty('passwordConfirm'),
|
||||
hasPasswordError: computed.and('passwordEmpty', 'passwordIsEmpty'),
|
||||
hasConfirmError: computed.and('confirmEmpty', 'passwordConfirmIsEmpty'),
|
||||
|
||||
actions: {
|
||||
reset() {
|
||||
let password = this.get('password');
|
||||
let passwordConfirm = this.get('passwordConfirm');
|
||||
|
||||
if (isEmpty(password)) {
|
||||
set(this, 'passwordIsEmpty', true);
|
||||
return $("#newPassword").focus();
|
||||
}
|
||||
|
||||
if (isEmpty(passwordConfirm)) {
|
||||
set(this, 'passwordConfirmIsEmpty', true);
|
||||
return $("#passwordConfirm").focus();
|
||||
}
|
||||
|
||||
if (!isEqual(password, passwordConfirm)) {
|
||||
set(this, 'hasPasswordError', true);
|
||||
set(this, 'hasConfirmError', true);
|
||||
set(this, 'mustMatch', true);
|
||||
return;
|
||||
}
|
||||
|
||||
this.get('reset')(password).then(() => {
|
||||
set(this, 'passwordIsEmpty', false);
|
||||
set(this, 'passwordConfirmIsEmpty', false);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
|
@ -12,103 +12,103 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
pageBody: "",
|
||||
appMeta: Ember.inject.service(),
|
||||
pageBody: "",
|
||||
appMeta: Ember.inject.service(),
|
||||
|
||||
didReceiveAttrs() {
|
||||
this.set('pageBody', this.get('meta.rawBody'));
|
||||
},
|
||||
didReceiveAttrs() {
|
||||
this.set('pageBody', this.get('meta.rawBody'));
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
let self = this;
|
||||
didInsertElement() {
|
||||
let self = this;
|
||||
|
||||
let options = {
|
||||
selector: "#rich-text-editor",
|
||||
relative_urls: false,
|
||||
cache_suffix: "?v=430",
|
||||
browser_spellcheck: false,
|
||||
gecko_spellcheck: false,
|
||||
theme: "modern",
|
||||
statusbar: false,
|
||||
height: $(document).height() - $(".document-editor > .toolbar").height() - 200,
|
||||
entity_encoding: "raw",
|
||||
paste_data_images: true,
|
||||
image_advtab: true,
|
||||
image_caption: true,
|
||||
media_live_embeds: true,
|
||||
fontsize_formats: "8pt 10pt 12pt 14pt 16pt 18pt 20pt 22pt 24pt 26pt 28pt 30pt 32pt 34pt 36pt",
|
||||
formats: {
|
||||
bold: {
|
||||
inline: 'b'
|
||||
},
|
||||
italic: {
|
||||
inline: 'i'
|
||||
}
|
||||
},
|
||||
extended_valid_elements: "b,i,b/strong,i/em",
|
||||
plugins: [
|
||||
'advlist autolink lists link image charmap print preview hr anchor pagebreak',
|
||||
'searchreplace wordcount visualblocks visualchars code codesample fullscreen',
|
||||
'insertdatetime media nonbreaking save table directionality',
|
||||
'emoticons template paste textcolor colorpicker textpattern imagetools'
|
||||
],
|
||||
menu: {
|
||||
edit: {
|
||||
title: 'Edit',
|
||||
items: 'undo redo | cut copy paste pastetext | selectall | searchreplace'
|
||||
},
|
||||
insert: {
|
||||
title: 'Insert',
|
||||
items: 'anchor link media | hr | charmap emoticons | blockquote'
|
||||
},
|
||||
format: {
|
||||
title: 'Format',
|
||||
items: 'bold italic underline strikethrough superscript subscript | formats fonts | removeformat'
|
||||
},
|
||||
table: {
|
||||
title: 'Table',
|
||||
items: 'inserttable tableprops deletetable | cell row column'
|
||||
}
|
||||
},
|
||||
toolbar1: "formatselect fontselect fontsizeselect | bold italic underline | link unlink | image media | codesample | outdent indent | alignleft aligncenter alignright alignjustify | bullist numlist | forecolor backcolor",
|
||||
save_onsavecallback: function() {
|
||||
self.send('onAction');
|
||||
}
|
||||
};
|
||||
let options = {
|
||||
selector: "#rich-text-editor",
|
||||
relative_urls: false,
|
||||
cache_suffix: "?v=430",
|
||||
browser_spellcheck: false,
|
||||
gecko_spellcheck: false,
|
||||
theme: "modern",
|
||||
statusbar: false,
|
||||
height: $(document).height() - $(".document-editor > .toolbar").height() - 200,
|
||||
entity_encoding: "raw",
|
||||
paste_data_images: true,
|
||||
image_advtab: true,
|
||||
image_caption: true,
|
||||
media_live_embeds: true,
|
||||
fontsize_formats: "8pt 10pt 12pt 14pt 16pt 18pt 20pt 22pt 24pt 26pt 28pt 30pt 32pt 34pt 36pt",
|
||||
formats: {
|
||||
bold: {
|
||||
inline: 'b'
|
||||
},
|
||||
italic: {
|
||||
inline: 'i'
|
||||
}
|
||||
},
|
||||
extended_valid_elements: "b,i,b/strong,i/em",
|
||||
plugins: [
|
||||
'advlist autolink lists link image charmap print preview hr anchor pagebreak',
|
||||
'searchreplace wordcount visualblocks visualchars code codesample fullscreen',
|
||||
'insertdatetime media nonbreaking save table directionality',
|
||||
'emoticons template paste textcolor colorpicker textpattern imagetools'
|
||||
],
|
||||
menu: {
|
||||
edit: {
|
||||
title: 'Edit',
|
||||
items: 'undo redo | cut copy paste pastetext | selectall | searchreplace'
|
||||
},
|
||||
insert: {
|
||||
title: 'Insert',
|
||||
items: 'anchor link media | hr | charmap emoticons | blockquote'
|
||||
},
|
||||
format: {
|
||||
title: 'Format',
|
||||
items: 'bold italic underline strikethrough superscript subscript | formats fonts | removeformat'
|
||||
},
|
||||
table: {
|
||||
title: 'Table',
|
||||
items: 'inserttable tableprops deletetable | cell row column'
|
||||
}
|
||||
},
|
||||
toolbar1: "formatselect fontselect fontsizeselect | bold italic underline | link unlink | image media | codesample | outdent indent | alignleft aligncenter alignright alignjustify | bullist numlist | forecolor backcolor",
|
||||
save_onsavecallback: function () {
|
||||
self.send('onAction');
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof tinymce === 'undefined') {
|
||||
$.getScript(this.get("appMeta").getBaseUrl("tinymce/tinymce.min.js?v=430"), function() {
|
||||
window.tinymce.dom.Event.domLoaded = true;
|
||||
tinymce.baseURL = "//" + window.location.host + "/tinymce";
|
||||
tinymce.suffix = ".min";
|
||||
tinymce.init(options);
|
||||
});
|
||||
} else {
|
||||
tinymce.init(options);
|
||||
}
|
||||
},
|
||||
if (typeof tinymce === 'undefined') {
|
||||
$.getScript("tinymce/tinymce.min.js?v=430", function () {
|
||||
window.tinymce.dom.Event.domLoaded = true;
|
||||
tinymce.baseURL = "//" + window.location.host + "/tinymce";
|
||||
tinymce.suffix = ".min";
|
||||
tinymce.init(options);
|
||||
});
|
||||
} else {
|
||||
tinymce.init(options);
|
||||
}
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
tinymce.remove();
|
||||
},
|
||||
willDestroyElement() {
|
||||
tinymce.remove();
|
||||
},
|
||||
|
||||
actions: {
|
||||
isDirty() {
|
||||
return is.not.undefined(tinymce) && is.not.undefined(tinymce.activeEditor) && tinymce.activeEditor.isDirty();
|
||||
},
|
||||
actions: {
|
||||
isDirty() {
|
||||
return is.not.undefined(tinymce) && is.not.undefined(tinymce.activeEditor) && tinymce.activeEditor.isDirty();
|
||||
},
|
||||
|
||||
onCancel() {
|
||||
this.attrs.onCancel();
|
||||
},
|
||||
onCancel() {
|
||||
this.attrs.onCancel();
|
||||
},
|
||||
|
||||
onAction(title) {
|
||||
let page = this.get('page');
|
||||
let meta = this.get('meta');
|
||||
onAction(title) {
|
||||
let page = this.get('page');
|
||||
let meta = this.get('meta');
|
||||
|
||||
page.set('title', title);
|
||||
meta.set('rawBody', tinymce.activeEditor.getContent());
|
||||
page.set('title', title);
|
||||
meta.set('rawBody', tinymce.activeEditor.getContent());
|
||||
|
||||
this.attrs.onAction(page, meta);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.attrs.onAction(page, meta);
|
||||
}
|
||||
}
|
||||
});
|
83
app/app/components/user-profile.js
Normal file
83
app/app/components/user-profile.js
Normal file
|
@ -0,0 +1,83 @@
|
|||
// 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';
|
||||
|
||||
const {
|
||||
computed,
|
||||
isEmpty,
|
||||
isEqual,
|
||||
isPresent
|
||||
} = Ember;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
password: { password: "", confirmation: "" },
|
||||
hasFirstnameError: computed.empty('model.firstname'),
|
||||
hasLastnameError: computed.empty('model.lastname'),
|
||||
hasEmailError: computed.empty('model.email'),
|
||||
hasPasswordError: computed('passwordError', 'password.password', {
|
||||
get() {
|
||||
if (isPresent(this.get('passwordError'))) {
|
||||
return `error`;
|
||||
}
|
||||
|
||||
if (isEmpty(this.get('password.password'))) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}),
|
||||
hasConfirmPasswordError: computed('confirmPasswordError', {
|
||||
get() {
|
||||
if (isPresent(this.get("confirmPasswordError"))) {
|
||||
return `error`;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}),
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
let password = this.get('password.password');
|
||||
let confirmation = this.get('password.confirmation');
|
||||
|
||||
if (isEmpty(this.get('model.firstname'))) {
|
||||
return $("#firstname").focus();
|
||||
}
|
||||
if (isEmpty(this.get('model.lastname'))) {
|
||||
return $("#lastname").focus();
|
||||
}
|
||||
if (isEmpty(this.get('model.email'))) {
|
||||
return $("#email").focus();
|
||||
}
|
||||
|
||||
if (isPresent(password) && isEmpty(confirmation)) {
|
||||
Ember.set(this, 'confirmPasswordError', 'error');
|
||||
return $("#confirmPassword").focus();
|
||||
}
|
||||
if (isEmpty(password) && isPresent(confirmation)) {
|
||||
Ember.set(this, 'passwordError', 'error');
|
||||
return $("#password").focus();
|
||||
}
|
||||
if (!isEqual(password, confirmation)) {
|
||||
Ember.set(this, 'passwordError', 'error');
|
||||
return $("#password").focus();
|
||||
}
|
||||
|
||||
let passwords = this.get('password');
|
||||
|
||||
this.get('save')(passwords).finally(() => {
|
||||
Ember.set(this, 'password.password', '');
|
||||
Ember.set(this, 'password.confirmation', '');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
56
app/app/components/user-settings.js
Normal file
56
app/app/components/user-settings.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
// 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';
|
||||
|
||||
const {
|
||||
isEmpty,
|
||||
computed,
|
||||
set,
|
||||
get
|
||||
} = Ember;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
newUser: { firstname: "", lastname: "", email: "", active: true },
|
||||
firstnameEmpty: computed.empty('newUser.firstname'),
|
||||
lastnameEmpty: computed.empty('newUser.lastname'),
|
||||
emailEmpty: computed.empty('newUser.email'),
|
||||
hasFirstnameEmptyError: computed.and('firstnameEmpty', 'firstnameError'),
|
||||
hasLastnameEmptyError: computed.and('lastnameEmpty', 'lastnameError'),
|
||||
hasEmailEmptyError: computed.and('emailEmpty', 'emailError'),
|
||||
|
||||
actions: {
|
||||
add() {
|
||||
if (isEmpty(this.get('newUser.firstname'))) {
|
||||
set(this, 'firstnameError', true);
|
||||
return $("#newUserFirstname").focus();
|
||||
}
|
||||
if (isEmpty(this.get('newUser.lastname'))) {
|
||||
set(this, 'lastnameError', true);
|
||||
return $("#newUserLastname").focus();
|
||||
}
|
||||
if (isEmpty(this.get('newUser.email')) || is.not.email(this.get('newUser.email'))) {
|
||||
set(this, 'emailError', true);
|
||||
return $("#newUserEmail").focus();
|
||||
}
|
||||
|
||||
let user = get(this, 'newUser');
|
||||
|
||||
get(this, 'add')(user).then(() => {
|
||||
this.set('newUser', { firstname: "", lastname: "", email: "", active: true });
|
||||
set(this, 'firstnameError', false);
|
||||
set(this, 'lastnameError', false);
|
||||
set(this, 'emailError', false);
|
||||
$("#newUserFirstname").focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
|
@ -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
|
||||
|
||||
|
@ -13,23 +13,10 @@ import Ember from 'ember';
|
|||
|
||||
export default Ember.Controller.extend({
|
||||
userService: Ember.inject.service('user'),
|
||||
email: "",
|
||||
sayThanks: false,
|
||||
|
||||
actions: {
|
||||
forgot: function () {
|
||||
var self = this;
|
||||
var email = this.get('email');
|
||||
|
||||
if (is.empty(email)) {
|
||||
$("#email").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
|
||||
self.set('sayThanks', true);
|
||||
this.set('email', '');
|
||||
|
||||
this.get('userService').forgotPassword(email);
|
||||
forgot: function (email) {
|
||||
return this.get('userService').forgotPassword(email);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,20 +3,6 @@
|
|||
<img src="assets/img/logo-color.png" title="Documize" alt="Documize" class="responsive-img" />
|
||||
</div>
|
||||
<div class="login-form">
|
||||
<form {{action 'forgot' on="submit"}}>
|
||||
{{#if sayThanks}}
|
||||
<div class="reset-thanks margin-bottom-30">Thanks. Check your email for instructions.</div>
|
||||
{{else}}
|
||||
<div class="input-control">
|
||||
<label>Email</label>
|
||||
{{focus-input type="email" value=email id="email"}}
|
||||
</div>
|
||||
<div class="clearfix" />
|
||||
<div class="margin-top-10 margin-bottom-20">
|
||||
<button type="submit" class="regular-button button-blue">Reset</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#link-to 'auth.login'}}Sign In{{/link-to}}
|
||||
</form>
|
||||
{{forgot-password forgot=(action 'forgot')}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -18,31 +18,10 @@ export default Ember.Controller.extend({
|
|||
mustMatch: false,
|
||||
|
||||
actions: {
|
||||
reset() {
|
||||
let self = this;
|
||||
let password = this.get('password');
|
||||
let passwordConfirm = this.get('passwordConfirm');
|
||||
|
||||
if (is.empty(password)) {
|
||||
$("#newPassword").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (is.empty(passwordConfirm)) {
|
||||
$("#passwordConfirm").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (is.not.equal(password, passwordConfirm)) {
|
||||
$("#newPassword").addClass("error").focus();
|
||||
$("#passwordConfirm").addClass("error");
|
||||
self.set('mustMatch', true);
|
||||
return;
|
||||
}
|
||||
|
||||
this.get('userService').resetPassword(self.model, password).then(function (response) { /* jshint ignore:line */
|
||||
self.transitionToRoute('auth.login');
|
||||
reset(password) {
|
||||
return this.get('userService').resetPassword(this.model, password).then(() => { /* jshint ignore:line */
|
||||
this.transitionToRoute('auth.login');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,23 +2,5 @@
|
|||
<div class="logo">
|
||||
<img src="assets/img/logo-color.png" title="Documize" alt="Documize" class="responsive-img" />
|
||||
</div>
|
||||
<div class="login-form">
|
||||
<form {{action 'reset' on="submit"}}>
|
||||
<div class="input-control">
|
||||
<label>New Password</label>
|
||||
<div class="tip">Choose a strong password</div>
|
||||
{{focus-input type="password" value=password id="newPassword"}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Confirm Password</label>
|
||||
<div class="tip">Please type your new password again</div>
|
||||
{{input type="password" value=passwordConfirm id="passwordConfirm"}}
|
||||
</div>
|
||||
<div class="clearfix" />
|
||||
<div class="margin-top-10 margin-bottom-20">
|
||||
<button type="submit" class="regular-button button-blue">Reset</button>
|
||||
<span class="{{unless mustMatch "hide"}} color-red margin-left-20">Passwords must match</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{password-reset reset=(action 'reset')}}
|
||||
</div>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -17,19 +17,9 @@ export default Ember.Controller.extend(NotifierMixin, {
|
|||
|
||||
actions: {
|
||||
save() {
|
||||
if (is.empty(this.model.get('title'))) {
|
||||
$("#siteTitle").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (is.empty(this.model.get('message'))) {
|
||||
$("#siteMessage").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
|
||||
this.model.set('allowAnonymousAccess', Ember.$("#allowAnonymousAccess").prop('checked'));
|
||||
this.get('orgService').save(this.model);
|
||||
this.showNotification('Saved');
|
||||
return this.get('orgService').save(this.model).then(() => {
|
||||
this.showNotification('Saved');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,29 +1,3 @@
|
|||
<div class="input-form form-borderless">
|
||||
<form>
|
||||
<div class="heading">
|
||||
<div class="title">General Settings</div>
|
||||
<div class="tip">Tell people about this Documize instance</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="input-control">
|
||||
<label>Title</label>
|
||||
<div class="tip">Describe the title of this Documize instance</div>
|
||||
{{focus-input id="siteTitle" type="text" value=model.title}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Message</label>
|
||||
<div class="tip">Describe the purpose of this Documize instance</div>
|
||||
{{textarea id="siteMessage" rows="3" value=model.message}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Anonymous Access</label>
|
||||
<div class="tip">Content within "Everyone" will be made available to anonymous users</div>
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="allowAnonymousAccess" checked= {{model.allowAnonymousAccess}} />
|
||||
<label for="allowAnonymousAccess">Allow anyone to access this Documize instance</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="regular-button button-blue" {{ action 'save' }}>save</div>
|
||||
</div>
|
||||
</form>
|
||||
{{general-settings model=model save=(action 'save')}}
|
||||
</div>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -17,30 +17,13 @@ export default Ember.Controller.extend(NotifierMixin, {
|
|||
newUser: { firstname: "", lastname: "", email: "", active: true },
|
||||
|
||||
actions: {
|
||||
add: function () {
|
||||
if (is.empty(this.newUser.firstname)) {
|
||||
$("#newUserFirstname").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
if (is.empty(this.newUser.lastname)) {
|
||||
$("#newUserLastname").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
if (is.empty(this.newUser.email) || is.not.email(this.newUser.email)) {
|
||||
$("#newUserEmail").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
add(user) {
|
||||
Ember.set(this, 'newUser', user);
|
||||
|
||||
$("#newUserFirstname").removeClass("error");
|
||||
$("#newUserLastname").removeClass("error");
|
||||
$("#newUserEmail").removeClass("error");
|
||||
|
||||
this.get('userService')
|
||||
return this.get('userService')
|
||||
.add(this.get('newUser'))
|
||||
.then((user) => {
|
||||
this.showNotification('Added');
|
||||
this.set('newUser', { firstname: "", lastname: "", email: "", active: true });
|
||||
$("#newUserFirstname").focus();
|
||||
this.get('model').pushObject(user);
|
||||
})
|
||||
.catch(function (error) {
|
||||
|
@ -76,4 +59,4 @@ export default Ember.Controller.extend(NotifierMixin, {
|
|||
this.showNotification('Password changed');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,23 +1,5 @@
|
|||
<div class="input-form form-borderless">
|
||||
<form>
|
||||
<div class="heading">
|
||||
<div class="title">Add User</div>
|
||||
<div class="tip">New users receive an invitation email with a random password</div>
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Firstname</label>
|
||||
{{focus-input id="newUserFirstname" type="text" value=newUser.firstname}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Lastname</label>
|
||||
{{input id="newUserLastname" type="text" value=newUser.lastname}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Email</label>
|
||||
{{input id="newUserEmail" type="text" value=newUser.email}}
|
||||
</div>
|
||||
<div class="regular-button button-blue" {{ action 'add' }}>Add</div>
|
||||
</form>
|
||||
{{user-settings add=(action 'add')}}
|
||||
</div>
|
||||
|
||||
<div class="clearfix" /> {{settings/user-list users=model onDelete=(action "onDelete") onSave=(action "onSave") onPassword=(action "onPassword")}}
|
||||
|
|
|
@ -1,62 +1,37 @@
|
|||
// 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
|
||||
|
||||
import Ember from 'ember';
|
||||
|
||||
const {
|
||||
isPresent
|
||||
} = Ember;
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
userService: Ember.inject.service('user'),
|
||||
password: { password: "", confirmation: "" },
|
||||
session: Ember.inject.service(),
|
||||
|
||||
actions: {
|
||||
save: function () {
|
||||
if (is.empty(this.model.get('firstname'))) {
|
||||
$("#firstname").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
if (is.empty(this.model.get('lastname'))) {
|
||||
$("#lastname").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
if (is.empty(this.model.get('email'))) {
|
||||
$("#email").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
if (is.not.empty(this.password.password) && is.empty(this.password.confirmation)) {
|
||||
$("#confirmPassword").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
if (is.empty(this.password.password) && is.not.empty(this.password.confirmation)) {
|
||||
$("#password").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
if (is.not.equal(this.password.password, this.password.confirmation)) {
|
||||
$("#password").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
save(passwords) {
|
||||
let password = passwords.password;
|
||||
let confirmation = passwords.confirmation;
|
||||
|
||||
let self = this;
|
||||
|
||||
this.get('userService').save(this.model).then(function () {
|
||||
if (is.not.empty(self.password.password) && is.not.empty(self.password.confirmation)) {
|
||||
self.get('userService').updatePassword(self.model.get('id'), self.password.password).then(function () {
|
||||
self.password.password = "";
|
||||
self.password.confirmation = "";
|
||||
});
|
||||
return this.get('userService').save(this.model).then(() => {
|
||||
if (isPresent(password) && isPresent(confirmation)) {
|
||||
this.get('userService').updatePassword(this.get('model.id'), password);
|
||||
}
|
||||
self.model.generateInitials();
|
||||
self.get('session').set('user', self.model);
|
||||
this.model.generateInitials();
|
||||
this.get('session').set('user', this.model);
|
||||
this.transitionToRoute('folders');
|
||||
});
|
||||
|
||||
this.transitionToRoute('folders');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,33 +13,7 @@
|
|||
{{/layout/zone-sidebar}}
|
||||
|
||||
{{#layout/zone-content}}
|
||||
<div class="input-form form-borderless">
|
||||
<form>
|
||||
<div class="input-control">
|
||||
<label>Firstname</label>
|
||||
{{focus-input id="firstname" type="text" value=model.firstname}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Lastname</label>
|
||||
{{input id="lastname" type="text" value=model.lastname}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Email</label>
|
||||
{{input id="email" type="text" value=model.email}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Password</label>
|
||||
<div class="tip">Optional change your password</div>
|
||||
{{input id="password" type="password" value=password.password}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Confirm Password</label>
|
||||
<div class="tip">Confirm your new password</div>
|
||||
{{input id="confirmPassword" type="password" value=password.confirmation}}
|
||||
</div>
|
||||
<div class="regular-button button-blue" {{ action 'save' }}>save</div>
|
||||
</form>
|
||||
</div>
|
||||
{{user-profile model=model save=(action 'save')}}
|
||||
{{/layout/zone-content}}
|
||||
|
||||
{{/layout/zone-container}}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -19,39 +19,7 @@ export default Ember.Controller.extend(NotifierMixin, {
|
|||
|
||||
actions: {
|
||||
save() {
|
||||
if (is.empty(this.model.title)) {
|
||||
$("#siteTitle").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (is.empty(this.model.firstname)) {
|
||||
$("#adminFirstname").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (is.empty(this.model.lastname)) {
|
||||
$("#adminLastname").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (is.empty(this.model.email)) {
|
||||
$("#adminEmail").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is.email(this.model.email)) {
|
||||
$("#adminEmail").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (is.empty(this.model.password)) {
|
||||
$("#adminPassword").addClass("error").focus();
|
||||
return;
|
||||
}
|
||||
|
||||
this.model.allowAnonymousAccess = Ember.$("#allowAnonymousAccess").prop('checked');
|
||||
|
||||
this.get('ajax').request("/setup", {
|
||||
return this.get('ajax').request("/setup", {
|
||||
method: 'POST',
|
||||
data: this.model,
|
||||
dataType: "text",
|
||||
|
@ -64,4 +32,4 @@ export default Ember.Controller.extend(NotifierMixin, {
|
|||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,46 +9,7 @@
|
|||
<img src="/assets/img/setup/cogs.png" width="157" height="187" alt="Setup new database" class="no-select no-outline" />
|
||||
</div>
|
||||
</div>
|
||||
{{documize-setup model=model save=(action 'save')}}
|
||||
|
||||
<div class="col-lg-9 col-md-9 col-sm-9">
|
||||
<div class="input-form">
|
||||
<form>
|
||||
<div class="heading">
|
||||
<div class="title">Let's setup Documize</div>
|
||||
<div class="tip">Database name is <em>{{model.dbname}}</em></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="input-control">
|
||||
<label>Team</label>
|
||||
<div class="tip">What's your tribe called?</div>
|
||||
{{focus-input id="siteTitle" type="text" value=model.title}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Firstname</label>
|
||||
<div class="tip">What do people call you?</div>
|
||||
{{input id="adminFirstname" type="text" value=model.firstname}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Lastname</label>
|
||||
<div class="tip">How the government refers to you.</div>
|
||||
{{input id="adminLastname" type="text" value=model.lastname}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Email</label>
|
||||
<div class="tip">No spam. Ever!</div>
|
||||
{{input id="adminEmail" type="email" value=model.email}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Password</label>
|
||||
<div class="tip">Something you can remember without writing it down.</div>
|
||||
{{input id="adminPassword" type="text" value=model.password}}
|
||||
</div>
|
||||
<div class="regular-button button-green" {{ action 'save' }}>Go Setup</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -126,4 +126,4 @@ export default Ember.Service.extend({
|
|||
data: password
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
38
app/app/templates/components/documize-setup.hbs
Normal file
38
app/app/templates/components/documize-setup.hbs
Normal file
|
@ -0,0 +1,38 @@
|
|||
<div class="col-lg-9 col-md-9 col-sm-9">
|
||||
<div class="input-form">
|
||||
<form>
|
||||
<div class="heading">
|
||||
<div class="title">Let's setup Documize</div>
|
||||
<div class="tip">Database name is <em>{{model.dbname}}</em></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="input-control">
|
||||
<label>Team</label>
|
||||
<div class="tip">What's your tribe called?</div>
|
||||
{{focus-input id="siteTitle" type="text" value=model.title class=(if hasEmptyTitleError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Firstname</label>
|
||||
<div class="tip">What do people call you?</div>
|
||||
{{input id="adminFirstname" type="text" value=model.firstname class=(if hasEmptyFirstnameError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Lastname</label>
|
||||
<div class="tip">How the government refers to you.</div>
|
||||
{{input id="adminLastname" type="text" value=model.lastname class=(if hasEmptyLastnameError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Email</label>
|
||||
<div class="tip">No spam. Ever!</div>
|
||||
{{input id="adminEmail" type="email" value=model.email class=(if hasEmptyEmailError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Password</label>
|
||||
<div class="tip">Something you can remember without writing it down.</div>
|
||||
{{input id="adminPassword" type="text" value=model.password class=(if hasEmptyPasswordError 'error')}}
|
||||
</div>
|
||||
<div class="regular-button button-green" {{ action 'save' }}>Go Setup</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
15
app/app/templates/components/forgot-password.hbs
Normal file
15
app/app/templates/components/forgot-password.hbs
Normal file
|
@ -0,0 +1,15 @@
|
|||
<form {{action 'forgot' on="submit"}}>
|
||||
{{#if sayThanks}}
|
||||
<div class="reset-thanks margin-bottom-30">Thanks. Check your email for instructions.</div>
|
||||
{{else}}
|
||||
<div class="input-control">
|
||||
<label>Email</label>
|
||||
{{focus-input type="email" value=email id="email" class=(if hasEmptyEmailError 'error')}}
|
||||
</div>
|
||||
<div class="clearfix" />
|
||||
<div class="margin-top-10 margin-bottom-20">
|
||||
<button type="submit" class="regular-button button-blue">Reset</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#link-to 'auth.login'}}Sign In{{/link-to}}
|
||||
</form>
|
27
app/app/templates/components/general-settings.hbs
Normal file
27
app/app/templates/components/general-settings.hbs
Normal file
|
@ -0,0 +1,27 @@
|
|||
<form>
|
||||
<div class="heading">
|
||||
<div class="title">General Settings</div>
|
||||
<div class="tip">Tell people about this Documize instance</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="input-control">
|
||||
<label>Title</label>
|
||||
<div class="tip">Describe the title of this Documize instance</div>
|
||||
{{focus-input id="siteTitle" type="text" value=model.title class=(if hasTitleInputError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Message</label>
|
||||
<div class="tip">Describe the purpose of this Documize instance</div>
|
||||
{{textarea id="siteMessage" rows="3" value=model.message class=(if hasMessageInputError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Anonymous Access</label>
|
||||
<div class="tip">Content within "Everyone" will be made available to anonymous users</div>
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="allowAnonymousAccess" checked= {{model.allowAnonymousAccess}} />
|
||||
<label for="allowAnonymousAccess">Allow anyone to access this Documize instance</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="regular-button button-blue" {{ action 'save' }}>save</div>
|
||||
</div>
|
||||
</form>
|
19
app/app/templates/components/password-reset.hbs
Normal file
19
app/app/templates/components/password-reset.hbs
Normal file
|
@ -0,0 +1,19 @@
|
|||
<div class="login-form">
|
||||
<form {{action 'reset' on="submit"}}>
|
||||
<div class="input-control">
|
||||
<label>New Password</label>
|
||||
<div class="tip">Choose a strong password</div>
|
||||
{{focus-input type="password" value=password id="newPassword" class=(if hasPasswordError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Confirm Password</label>
|
||||
<div class="tip">Please type your new password again</div>
|
||||
{{input type="password" value=passwordConfirm id="passwordConfirm" class=(if hasConfirmError 'error')}}
|
||||
</div>
|
||||
<div class="clearfix" />
|
||||
<div class="margin-top-10 margin-bottom-20">
|
||||
<button type="submit" class="regular-button button-blue">Reset</button>
|
||||
<span class="{{unless mustMatch "hide"}} color-red margin-left-20">Passwords must match</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
27
app/app/templates/components/user-profile.hbs
Normal file
27
app/app/templates/components/user-profile.hbs
Normal file
|
@ -0,0 +1,27 @@
|
|||
<div class="input-form form-borderless">
|
||||
<form>
|
||||
<div class="input-control">
|
||||
<label>Firstname</label>
|
||||
{{focus-input id="firstname" type="text" value=model.firstname class=(if hasFirstnameError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Lastname</label>
|
||||
{{input id="lastname" type="text" value=model.lastname class=(if hasLastnameError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Email</label>
|
||||
{{input id="email" type="text" value=model.email class=(if hasEmailError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Password</label>
|
||||
<div class="tip">Optional change your password</div>
|
||||
{{input id="password" type="password" value=password.password class=hasPasswordError}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Confirm Password</label>
|
||||
<div class="tip">Confirm your new password</div>
|
||||
{{input id="confirmPassword" type="password" value=password.confirmation class=hasConfirmPasswordError}}
|
||||
</div>
|
||||
<div class="regular-button button-blue" {{ action 'save' }}>save</div>
|
||||
</form>
|
||||
</div>
|
19
app/app/templates/components/user-settings.hbs
Normal file
19
app/app/templates/components/user-settings.hbs
Normal file
|
@ -0,0 +1,19 @@
|
|||
<form>
|
||||
<div class="heading">
|
||||
<div class="title">Add User</div>
|
||||
<div class="tip">New users receive an invitation email with a random password</div>
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Firstname</label>
|
||||
{{focus-input id="newUserFirstname" type="text" value=newUser.firstname class=(if hasFirstnameEmptyError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Lastname</label>
|
||||
{{input id="newUserLastname" type="text" value=newUser.lastname class=(if hasLastnameEmptyError 'error')}}
|
||||
</div>
|
||||
<div class="input-control">
|
||||
<label>Email</label>
|
||||
{{input id="newUserEmail" type="text" value=newUser.email class=(if hasEmailEmptyError 'error')}}
|
||||
</div>
|
||||
<div class="regular-button button-blue" {{ action 'add' }}>Add</div>
|
||||
</form>
|
|
@ -50,8 +50,9 @@ func init() {
|
|||
var err error
|
||||
|
||||
environment.GetString(&connectionString, "db", true,
|
||||
`"username:password@protocol(hostname:port)/databasename" for example "fred:bloggs@tcp(localhost:3306)/documize"`,
|
||||
`'username:password@protocol(hostname:port)/databasename" for example "fred:bloggs@tcp(localhost:3306)/documize"`,
|
||||
func(*string, string) bool {
|
||||
|
||||
Db, err = sqlx.Open("mysql", stdConn(connectionString))
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -19,9 +19,9 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/documize/community/core/api/util"
|
||||
"github.com/documize/community/core/web"
|
||||
"github.com/documize/community/core/log"
|
||||
"github.com/documize/community/core/utility"
|
||||
"github.com/documize/community/core/web"
|
||||
)
|
||||
|
||||
// runSQL creates a transaction per call
|
||||
|
|
|
@ -13,16 +13,20 @@ package database
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
||||
"github.com/documize/community/core/web"
|
||||
"github.com/documize/community/core/log"
|
||||
"github.com/documize/community/core/utility"
|
||||
"github.com/documize/community/core/web"
|
||||
)
|
||||
|
||||
const migrationsDir = "bindata/scripts"
|
||||
|
@ -69,97 +73,176 @@ func migrations(lastMigration string) (migrationsT, error) {
|
|||
func (m migrationsT) migrate(tx *sqlx.Tx) error {
|
||||
for _, v := range m {
|
||||
log.Info("Processing migration file: " + v)
|
||||
|
||||
buf, err := web.Asset(migrationsDir + "/" + v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//fmt.Println("DEBUG database.Migrate() ", v, ":\n", string(buf)) // TODO actually run the SQL
|
||||
|
||||
err = processSQLfile(tx, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
json := `{"database":"` + v + `"}`
|
||||
sql := "INSERT INTO `config` (`key`,`config`) " +
|
||||
"VALUES ('META','" + json +
|
||||
"') ON DUPLICATE KEY UPDATE `config`='" + json + "';"
|
||||
|
||||
_, err = tx.Exec(sql)
|
||||
_, err = tx.Exec(sql) // add a record in the config file to say we have done the upgrade
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//fmt.Println("DEBUG insert 10s wait for testing")
|
||||
//time.Sleep(10 * time.Second)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func migrateEnd(tx *sqlx.Tx, err error) error {
|
||||
if tx != nil {
|
||||
_, ulerr := tx.Exec("UNLOCK TABLES;")
|
||||
log.IfErr(ulerr)
|
||||
if err == nil {
|
||||
log.IfErr(tx.Commit())
|
||||
log.Info("Database checks: completed")
|
||||
return nil
|
||||
}
|
||||
log.IfErr(tx.Rollback())
|
||||
func lockDB() (bool, error) {
|
||||
b := make([]byte, 2)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
log.Error("Database checks: failed: ", err)
|
||||
return err
|
||||
wait := ((time.Duration(b[0]) << 8) | time.Duration(b[1])) * time.Millisecond / 10 // up to 6.5 secs wait
|
||||
time.Sleep(wait)
|
||||
|
||||
tx, err := (*dbPtr).Beginx()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
_, err = tx.Exec("LOCK TABLE `config` WRITE;")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_, err = tx.Exec("UNLOCK TABLES;")
|
||||
log.IfErr(err)
|
||||
log.IfErr(tx.Commit())
|
||||
}()
|
||||
|
||||
_, err = tx.Exec("INSERT INTO `config` (`key`,`config`) " +
|
||||
fmt.Sprintf(`VALUES ('DBLOCK','{"pid": "%d"}');`, os.Getpid()))
|
||||
if err != nil {
|
||||
// good error would be "Error 1062: Duplicate entry 'DBLOCK' for key 'idx_config_area'"
|
||||
if strings.HasPrefix(err.Error(), "Error 1062:") {
|
||||
log.Info("Database locked by annother Documize instance")
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
log.Info("Database locked by this Documize instance")
|
||||
return true, err // success!
|
||||
}
|
||||
|
||||
func unlockDB() error {
|
||||
tx, err := (*dbPtr).Beginx()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.Exec("DELETE FROM `config` WHERE `key`='DBLOCK';")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func migrateEnd(tx *sqlx.Tx, err error, amLeader bool) error {
|
||||
if amLeader {
|
||||
defer func() { log.IfErr(unlockDB()) }()
|
||||
if tx != nil {
|
||||
if err == nil {
|
||||
log.IfErr(tx.Commit())
|
||||
log.Info("Database checks: completed")
|
||||
return nil
|
||||
}
|
||||
log.IfErr(tx.Rollback())
|
||||
}
|
||||
log.Error("Database checks: failed: ", err)
|
||||
return err
|
||||
}
|
||||
return nil // not the leader, so ignore errors
|
||||
}
|
||||
|
||||
func getLastMigration(tx *sqlx.Tx) (lastMigration string, err error) {
|
||||
var stmt *sql.Stmt
|
||||
stmt, err = tx.Prepare("SELECT JSON_EXTRACT(`config`,'$.database') FROM `config` WHERE `key` = 'META';")
|
||||
if err == nil {
|
||||
defer utility.Close(stmt)
|
||||
var item = make([]uint8, 0)
|
||||
|
||||
row := stmt.QueryRow()
|
||||
|
||||
err = row.Scan(&item)
|
||||
if err == nil {
|
||||
if len(item) > 1 {
|
||||
q := []byte(`"`)
|
||||
lastMigration = string(bytes.TrimPrefix(bytes.TrimSuffix(item, q), q))
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Migrate the database as required, consolidated action.
|
||||
func Migrate(ConfigTableExists bool) error {
|
||||
|
||||
lastMigration := ""
|
||||
amLeader := false
|
||||
|
||||
if ConfigTableExists {
|
||||
var err error
|
||||
amLeader, err = lockDB()
|
||||
log.IfErr(err)
|
||||
} else {
|
||||
amLeader = true // what else can you do?
|
||||
}
|
||||
|
||||
tx, err := (*dbPtr).Beginx()
|
||||
if err != nil {
|
||||
return migrateEnd(tx, err)
|
||||
return migrateEnd(tx, err, amLeader)
|
||||
}
|
||||
|
||||
lastMigration := ""
|
||||
|
||||
if ConfigTableExists {
|
||||
_, err = tx.Exec("LOCK TABLE `config` WRITE;")
|
||||
lastMigration, err = getLastMigration(tx)
|
||||
if err != nil {
|
||||
return migrateEnd(tx, err)
|
||||
}
|
||||
|
||||
log.Info("Database checks: lock taken")
|
||||
|
||||
var stmt *sql.Stmt
|
||||
stmt, err = tx.Prepare("SELECT JSON_EXTRACT(`config`,'$.database') FROM `config` WHERE `key` = 'META';")
|
||||
if err == nil {
|
||||
defer utility.Close(stmt)
|
||||
var item = make([]uint8, 0)
|
||||
|
||||
row := stmt.QueryRow()
|
||||
|
||||
err = row.Scan(&item)
|
||||
if err != nil {
|
||||
return migrateEnd(tx, err)
|
||||
}
|
||||
|
||||
if len(item) > 1 {
|
||||
q := []byte(`"`)
|
||||
lastMigration = string(bytes.TrimPrefix(bytes.TrimSuffix(item, q), q))
|
||||
}
|
||||
return migrateEnd(tx, err, amLeader)
|
||||
}
|
||||
log.Info("Database checks: last previously applied file was " + lastMigration)
|
||||
}
|
||||
|
||||
mig, err := migrations(lastMigration)
|
||||
if err != nil {
|
||||
return migrateEnd(tx, err)
|
||||
return migrateEnd(tx, err, amLeader)
|
||||
}
|
||||
|
||||
if len(mig) == 0 {
|
||||
log.Info("Database checks: no updates to perform")
|
||||
return migrateEnd(tx, nil) // no migrations to perform
|
||||
return migrateEnd(tx, nil, amLeader) // no migrations to perform
|
||||
}
|
||||
log.Info("Database checks: will execute the following update files: " + strings.Join([]string(mig), ", "))
|
||||
|
||||
return migrateEnd(tx, mig.migrate(tx))
|
||||
if amLeader {
|
||||
log.Info("Database checks: will execute the following update files: " + strings.Join([]string(mig), ", "))
|
||||
return migrateEnd(tx, mig.migrate(tx), amLeader)
|
||||
}
|
||||
|
||||
// a follower instance
|
||||
targetMigration := string(mig[len(mig)-1])
|
||||
for targetMigration != lastMigration {
|
||||
time.Sleep(time.Second)
|
||||
log.Info("Waiting for database migration process to complete")
|
||||
tx.Rollback() // ignore error
|
||||
tx, err := (*dbPtr).Beginx() // need this in order to see the changed situation since last tx
|
||||
if err != nil {
|
||||
return migrateEnd(tx, err, amLeader)
|
||||
}
|
||||
lastMigration, _ = getLastMigration(tx)
|
||||
}
|
||||
|
||||
return migrateEnd(tx, nil, amLeader)
|
||||
}
|
||||
|
||||
func processSQLfile(tx *sqlx.Tx, buf []byte) error {
|
||||
|
|
|
@ -27,7 +27,7 @@ type ProdInfo struct {
|
|||
func Product() (p ProdInfo) {
|
||||
p.Major = "0"
|
||||
p.Minor = "16"
|
||||
p.Patch = "0"
|
||||
p.Patch = "1"
|
||||
p.Version = fmt.Sprintf("%s.%s.%s", p.Major, p.Minor, p.Patch)
|
||||
p.Edition = "Community"
|
||||
p.Title = fmt.Sprintf("%s Edition", p.Edition)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue