mirror of
https://github.com/documize/community.git
synced 2025-08-09 07:25:23 +02:00
Merge branch 'master' into github-extension
This commit is contained in:
commit
5ace3850a6
10 changed files with 207 additions and 29 deletions
|
@ -22,6 +22,11 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
||||||
description: ""
|
description: ""
|
||||||
},
|
},
|
||||||
|
|
||||||
|
didReceiveAttrs() {
|
||||||
|
this.set('saveTemplate.name', this.get('document.name'));
|
||||||
|
this.set('saveTemplate.description', this.get('document.excerpt'));
|
||||||
|
},
|
||||||
|
|
||||||
didRender() {
|
didRender() {
|
||||||
if (this.get('isEditor')) {
|
if (this.get('isEditor')) {
|
||||||
this.addTooltip(document.getElementById("attachment-button"));
|
this.addTooltip(document.getElementById("attachment-button"));
|
||||||
|
@ -99,30 +104,21 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
||||||
},
|
},
|
||||||
|
|
||||||
saveTemplate() {
|
saveTemplate() {
|
||||||
var templateName = this.get('saveTemplate.name');
|
var name = this.get('saveTemplate.name');
|
||||||
var templateDescription = this.get('saveTemplate.description');
|
var excerpt = this.get('saveTemplate.description');
|
||||||
|
|
||||||
if (is.empty(templateName)) {
|
if (is.empty(name)) {
|
||||||
$("#new-template-name").addClass("error").focus();
|
$("#new-template-name").addClass("error").focus();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is.empty(templateDescription)) {
|
if (is.empty(excerpt)) {
|
||||||
$("#new-template-desc").addClass("error").focus();
|
$("#new-template-desc").addClass("error").focus();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.showNotification('Template saved');
|
||||||
let doc = this.get('document');
|
this.attrs.onSaveTemplate(name, excerpt);
|
||||||
doc.set('template', true);
|
|
||||||
doc.set('name', templateName);
|
|
||||||
doc.set('excerpt', templateDescription);
|
|
||||||
|
|
||||||
this.set('saveTemplate.name', "");
|
|
||||||
this.set('saveTemplate.description', "");
|
|
||||||
|
|
||||||
this.showNotification('Templated');
|
|
||||||
this.attrs.onSaveTemplate(doc);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,7 @@ import NotifierMixin from '../../../mixins/notifier';
|
||||||
|
|
||||||
export default Ember.Controller.extend(NotifierMixin, {
|
export default Ember.Controller.extend(NotifierMixin, {
|
||||||
documentService: Ember.inject.service('document'),
|
documentService: Ember.inject.service('document'),
|
||||||
|
templateService: Ember.inject.service('template'),
|
||||||
|
|
||||||
queryParams: ['page'],
|
queryParams: ['page'],
|
||||||
page: null,
|
page: null,
|
||||||
|
@ -170,6 +171,11 @@ export default Ember.Controller.extend(NotifierMixin, {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onSaveTemplate(name, desc) {
|
||||||
|
this.get('templateService').saveAsTemplate(this.model.get('id'), name, desc).then(function() {
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
onDocumentChange(doc) {
|
onDocumentChange(doc) {
|
||||||
let self = this;
|
let self = this;
|
||||||
this.get('documentService').save(doc).then(function() {
|
this.get('documentService').save(doc).then(function() {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{{header/message-box message=model.excerpt}}
|
{{header/message-box message=model.excerpt}}
|
||||||
{{/header/page-navigation}}
|
{{/header/page-navigation}}
|
||||||
|
|
||||||
{{document/document-toolbar document=model pages=pages meta=meta folder=folder isEditor=isEditor users=users owner=owner onSaveTemplate=(action 'onDocumentChange') onDocumentChange=(action 'onDocumentChange') onAttachmentUpload=(action
|
{{document/document-toolbar document=model pages=pages meta=meta folder=folder isEditor=isEditor users=users owner=owner onSaveTemplate=(action 'onSaveTemplate') onDocumentChange=(action 'onDocumentChange') onAttachmentUpload=(action
|
||||||
'onAttachmentUpload') onDocumentDelete=(action 'onDocumentDelete')}}
|
'onAttachmentUpload') onDocumentDelete=(action 'onDocumentDelete')}}
|
||||||
|
|
||||||
<div class="container-fluid background-color-white">
|
<div class="container-fluid background-color-white">
|
||||||
|
|
|
@ -62,5 +62,20 @@ export default Ember.Service.extend({
|
||||||
return this.get('ajax').request(url, {
|
return this.get('ajax').request(url, {
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
|
saveAsTemplate(documentId, name, excerpt) {
|
||||||
|
let url = this.get('sessionService').appMeta.getUrl("templates");
|
||||||
|
let payload = {
|
||||||
|
DocumentID: documentId,
|
||||||
|
Name: name,
|
||||||
|
Excerpt: excerpt
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.get('ajax').request(url, {
|
||||||
|
method: 'POST',
|
||||||
|
data: JSON.stringify(payload)
|
||||||
|
}).then(() => {
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -69,10 +69,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-template {
|
.is-template {
|
||||||
color: $color-green;
|
color: $color-gray;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 1.3em;
|
font-size: 1.5em;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 50px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
@include border-bottom(1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
> .pages {
|
> .pages {
|
||||||
|
|
|
@ -77,15 +77,15 @@
|
||||||
<p>Are you sure you want to delete this document?</p>
|
<p>Are you sure you want to delete this document?</p>
|
||||||
<p>There is no undo!</p>
|
<p>There is no undo!</p>
|
||||||
{{/dropdown-dialog}}
|
{{/dropdown-dialog}}
|
||||||
{{#dropdown-dialog target="save-template-button" position="bottom right" button="Save" color="flat-green" onAction=(action 'saveTemplate') focusOn="new-template-name"}}
|
{{#dropdown-dialog target="save-template-button" position="bottom right" button="Save as Template" color="flat-green" onAction=(action 'saveTemplate') focusOn="new-template-name"}}
|
||||||
<div>
|
<div>
|
||||||
<div class="input-control">
|
<div class="input-control">
|
||||||
<label>Template Name</label>
|
<label>Name</label>
|
||||||
<div class="tip">Short title for this type of document</div>
|
<div class="tip">Short name for this type of document</div>
|
||||||
{{input type='text' id="new-template-name" value=saveTemplate.name}}
|
{{input type='text' id="new-template-name" value=saveTemplate.name}}
|
||||||
</div>
|
</div>
|
||||||
<div class="input-control">
|
<div class="input-control">
|
||||||
<label>Description</label>
|
<label>Excerpt</label>
|
||||||
<div class="tip">Explain use case for this template</div>
|
<div class="tip">Explain use case for this template</div>
|
||||||
{{textarea value=saveTemplate.description rows="3" id="new-template-desc"}}
|
{{textarea value=saveTemplate.description rows="3" id="new-template-desc"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,6 +11,14 @@
|
||||||
<meta property="dbhash" content="{{.DBhash}}" />
|
<meta property="dbhash" content="{{.DBhash}}" />
|
||||||
<meta name="author" content="Documize" />
|
<meta name="author" content="Documize" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#ember-testing-container {
|
||||||
|
/* Set position static to short-circuit Hubspot Tether's positioning */
|
||||||
|
/* https://github.com/HubSpot/tether/pull/98/ */
|
||||||
|
position: static !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
{{content-for "head"}}
|
{{content-for "head"}}
|
||||||
{{content-for "test-head"}}
|
{{content-for "test-head"}}
|
||||||
|
|
||||||
|
|
|
@ -145,8 +145,8 @@ func buildSecureRoutes() *mux.Router {
|
||||||
router.HandleFunc("/api/documents/{documentID}", GetDocument).Methods("GET", "OPTIONS")
|
router.HandleFunc("/api/documents/{documentID}", GetDocument).Methods("GET", "OPTIONS")
|
||||||
router.HandleFunc("/api/documents/{documentID}", UpdateDocument).Methods("PUT", "OPTIONS")
|
router.HandleFunc("/api/documents/{documentID}", UpdateDocument).Methods("PUT", "OPTIONS")
|
||||||
router.HandleFunc("/api/documents/{documentID}", DeleteDocument).Methods("DELETE", "OPTIONS")
|
router.HandleFunc("/api/documents/{documentID}", DeleteDocument).Methods("DELETE", "OPTIONS")
|
||||||
// Document Meta
|
|
||||||
|
|
||||||
|
// Document Meta
|
||||||
router.HandleFunc("/api/documents/{documentID}/meta", GetDocumentMeta).Methods("GET", "OPTIONS")
|
router.HandleFunc("/api/documents/{documentID}/meta", GetDocumentMeta).Methods("GET", "OPTIONS")
|
||||||
|
|
||||||
// Document Page
|
// Document Page
|
||||||
|
@ -198,6 +198,7 @@ func buildSecureRoutes() *mux.Router {
|
||||||
router.HandleFunc("/api/search", SearchDocuments).Methods("GET", "OPTIONS")
|
router.HandleFunc("/api/search", SearchDocuments).Methods("GET", "OPTIONS")
|
||||||
|
|
||||||
// Templates
|
// Templates
|
||||||
|
router.HandleFunc("/api/templates", SaveAsTemplate).Methods("POST", "OPTIONS")
|
||||||
router.HandleFunc("/api/templates", GetSavedTemplates).Methods("GET", "OPTIONS")
|
router.HandleFunc("/api/templates", GetSavedTemplates).Methods("GET", "OPTIONS")
|
||||||
router.HandleFunc("/api/templates/stock", GetStockTemplates).Methods("GET", "OPTIONS")
|
router.HandleFunc("/api/templates/stock", GetStockTemplates).Methods("GET", "OPTIONS")
|
||||||
router.HandleFunc("/api/templates/{templateID}/folder/{folderID}", StartDocumentFromStockTemplate).Methods("POST", "OPTIONS").Queries("type", "stock")
|
router.HandleFunc("/api/templates/{templateID}/folder/{folderID}", StartDocumentFromStockTemplate).Methods("POST", "OPTIONS").Queries("type", "stock")
|
||||||
|
|
|
@ -34,6 +34,156 @@ import (
|
||||||
uuid "github.com/nu7hatch/gouuid"
|
uuid "github.com/nu7hatch/gouuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SaveAsTemplate saves existing document as a template.
|
||||||
|
func SaveAsTemplate(w http.ResponseWriter, r *http.Request) {
|
||||||
|
method := "SaveAsTemplate"
|
||||||
|
p := request.GetPersister(r)
|
||||||
|
|
||||||
|
var model struct {
|
||||||
|
DocumentID string
|
||||||
|
Name string
|
||||||
|
Excerpt string
|
||||||
|
}
|
||||||
|
|
||||||
|
defer utility.Close(r.Body)
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
writeBadRequestError(w, method, "Bad payload")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(body, &model)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
writePayloadError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.CanChangeDocument(model.DocumentID) {
|
||||||
|
writeForbiddenError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DB transaction
|
||||||
|
tx, err := request.Db.Beginx()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
writeTransactionError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Context.Transaction = tx
|
||||||
|
|
||||||
|
// Duplicate document
|
||||||
|
doc, err := p.GetDocument(model.DocumentID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
writeServerError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
docID := util.UniqueID()
|
||||||
|
doc.Template = true
|
||||||
|
doc.Title = model.Name
|
||||||
|
doc.Excerpt = model.Excerpt
|
||||||
|
doc.RefID = docID
|
||||||
|
doc.ID = 0
|
||||||
|
doc.Template = true
|
||||||
|
|
||||||
|
// Duplicate pages and associated meta
|
||||||
|
pages, err := p.GetPages(model.DocumentID)
|
||||||
|
var pageModel []models.PageModel
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
writeServerError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, page := range pages {
|
||||||
|
page.DocumentID = docID
|
||||||
|
page.ID = 0
|
||||||
|
|
||||||
|
meta, err2 := p.GetPageMeta(page.RefID)
|
||||||
|
|
||||||
|
if err2 != nil {
|
||||||
|
writeServerError(w, method, err2)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pageID := util.UniqueID()
|
||||||
|
page.RefID = pageID
|
||||||
|
|
||||||
|
meta.PageID = pageID
|
||||||
|
meta.DocumentID = docID
|
||||||
|
|
||||||
|
m := models.PageModel{}
|
||||||
|
|
||||||
|
m.Page = page
|
||||||
|
m.Meta = meta
|
||||||
|
|
||||||
|
pageModel = append(pageModel, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplicate attachments
|
||||||
|
attachments, err := p.GetAttachments(model.DocumentID)
|
||||||
|
|
||||||
|
for i, a := range attachments {
|
||||||
|
a.DocumentID = docID
|
||||||
|
a.RefID = util.UniqueID()
|
||||||
|
a.ID = 0
|
||||||
|
attachments[i] = a
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now create the template: document, attachments, pages and their meta
|
||||||
|
err = p.AddDocument(doc)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.IfErr(tx.Rollback())
|
||||||
|
writeGeneralSQLError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, a := range attachments {
|
||||||
|
err = p.AddAttachment(a)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.IfErr(tx.Rollback())
|
||||||
|
writeGeneralSQLError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range pageModel {
|
||||||
|
err = p.AddPage(m)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.IfErr(tx.Rollback())
|
||||||
|
writeGeneralSQLError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit and return new document template
|
||||||
|
log.IfErr(tx.Commit())
|
||||||
|
|
||||||
|
doc, err = p.GetDocument(docID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
writeGeneralSQLError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
d, err := json.Marshal(doc)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
writeJSONMarshalError(w, method, "document", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
writeSuccessBytes(w, d)
|
||||||
|
}
|
||||||
|
|
||||||
// GetSavedTemplates returns all templates saved by the user
|
// GetSavedTemplates returns all templates saved by the user
|
||||||
func GetSavedTemplates(w http.ResponseWriter, r *http.Request) {
|
func GetSavedTemplates(w http.ResponseWriter, r *http.Request) {
|
||||||
method := "GetSavedTemplates"
|
method := "GetSavedTemplates"
|
||||||
|
|
|
@ -29,7 +29,7 @@ func (p *Persister) AddDocument(document entity.Document) (err error) {
|
||||||
document.Created = time.Now().UTC()
|
document.Created = time.Now().UTC()
|
||||||
document.Revised = document.Created // put same time in both fields
|
document.Revised = document.Created // put same time in both fields
|
||||||
|
|
||||||
stmt, err := p.Context.Transaction.Preparex("INSERT INTO document (refId, orgid, labelid, userid, job, location, title, excerpt, slug, tags, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
stmt, err := p.Context.Transaction.Preparex("INSERT INTO document (refId, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||||
defer utility.Close(stmt)
|
defer utility.Close(stmt)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -37,7 +37,7 @@ func (p *Persister) AddDocument(document entity.Document) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = stmt.Exec(document.RefID, document.OrgID, document.LabelID, document.UserID, document.Job, document.Location, document.Title, document.Excerpt, document.Slug, document.Tags, document.Created, document.Revised)
|
_, err = stmt.Exec(document.RefID, document.OrgID, document.LabelID, document.UserID, document.Job, document.Location, document.Title, document.Excerpt, document.Slug, document.Tags, document.Template, document.Created, document.Revised)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to execute insert for document", err)
|
log.Error("Unable to execute insert for document", err)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue