1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-21 14:19:43 +02:00

Merge pull request #89 from documize/pdf-print

Print view enhancements, bug fixes
This commit is contained in:
Harvey Kandola 2017-04-04 19:14:15 +01:00 committed by GitHub
commit e97b992fa9
21 changed files with 1070 additions and 800 deletions

View file

@ -49,7 +49,11 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
this.set('document.name', this.get('docName')); this.set('document.name', this.get('docName'));
this.set('document.excerpt', this.get('docExcerpt')); this.set('document.excerpt', this.get('docExcerpt'));
this.showNotification('Saved'); this.showNotification('Saved');
this.get('browser').setTitle(this.get('document.name'));
this.get('browser').setMetaDescription(this.get('document.excerpt'));
this.get('documentService').save(this.get('document')); this.get('documentService').save(this.get('document'));
this.set('editMode', false); this.set('editMode', false);

View file

@ -13,64 +13,12 @@ import Ember from 'ember';
export default Ember.Component.extend({ export default Ember.Component.extend({
documentService: Ember.inject.service('document'), documentService: Ember.inject.service('document'),
appMeta: Ember.inject.service(),
sortedItems: [],
didReceiveAttrs() { didReceiveAttrs() {
this._super(...arguments); this._super(...arguments);
this.get('documentService').getMeta(this.get('document.id')).then((activity) => { this.get('documentService').getActivity(this.get('document.id')).then((activity) => {
this.set('activity', activity); this.set('activity', activity);
let editors = this.get('activity.editors');
let viewers = this.get('activity.viewers');
let pages = this.get('pages');
let sorted = [];
if (is.null(editors)) {
editors = [];
}
if (is.null(viewers)) {
viewers = [];
}
viewers.forEach((item) => {
Ember.set(item, 'changeLabel', "viewed");
Ember.set(item, "viewed", true);
sorted.pushObject({ date: item.created, item: item });
});
editors.forEach(function (item) {
Ember.set(item, "added", item.action === "add-page");
Ember.set(item, "changed", item.action === "update-page");
Ember.set(item, "deleted", item.action === "remove-page");
let page = pages.findBy('id', item.pageId);
let title = "";
if (item.deleted || is.undefined(page)) {
title = "removed section";
} else {
if (item.added) {
title = "added " + page.get('title');
}
if (item.changed) {
title = "changed " + page.get('title');
}
}
Ember.set(item, 'changeLabel', title);
let exists = sorted.findBy('item.pageId', item.pageId);
if (is.undefined(exists)) {
sorted.pushObject({ date: item.created, item: item });
}
});
this.set('sortedItems', _.sortBy(sorted, 'date').reverse());
}); });
} }
}); });

View file

@ -123,7 +123,7 @@ export default Ember.Component.extend(NotifierMixin, {
this.audit.record('used-saved-template'); this.audit.record('used-saved-template');
this.send("showNotification", "Creating"); this.send("showNotification", "Creating");
this.get('templateService').importSavedTemplate(this.folder.get('id'), template.id).then((document) => { this.get('templateService').importSavedTemplate(this.folder.get('id'), template.id, this.get('newDocumentName')).then((document) => {
this.get('router').transitionTo('document', this.get('folder.id'), this.get('folder.slug'), document.get('id'), document.get('slug')); this.get('router').transitionTo('document', this.get('folder.id'), this.get('folder.slug'), document.get('id'), document.get('slug'));
}); });

View file

@ -0,0 +1,103 @@
// 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 Model from 'ember-data/model';
import attr from 'ember-data/attr';
import Ember from 'ember';
import constants from '../utils/constants';
export default Model.extend({
orgId: attr('string'),
folderId: attr('string'),
documentId: attr('string'),
userId: attr('string'),
firstname: attr('string'),
lastname: attr('string'),
activityType: attr('number'),
created: attr(),
activityLabel: Ember.computed('activityType', function() {
let label = '';
switch (this.get('activityType')) {
case constants.UserActivityType.Created:
label = 'Added';
break;
case constants.UserActivityType.Read:
label = 'Viewed';
break;
case constants.UserActivityType.Edited:
label = 'Edited';
break;
case constants.UserActivityType.Deleted:
label = 'Deleted';
break;
case constants.UserActivityType.Archived:
label = 'Archived';
break;
case constants.UserActivityType.Approved:
label = 'Approved';
break;
case constants.UserActivityType.Reverted:
label = 'Reverted';
break;
case constants.UserActivityType.PublishedTemplate:
label = 'Published Template';
break;
case constants.UserActivityType.PublishedBlock:
label = 'Published Block';
break;
default:
break;
}
return label;
}),
activityColor: Ember.computed('activityType', function() {
let color = '';
switch (this.get('activityType')) {
case constants.UserActivityType.Created:
color = 'color-blue';
break;
case constants.UserActivityType.Read:
color = 'color-black';
break;
case constants.UserActivityType.Edited:
color = 'color-green';
break;
case constants.UserActivityType.Deleted:
color = 'color-red';
break;
case constants.UserActivityType.Archived:
color = 'color-gray';
break;
case constants.UserActivityType.Approved:
color = 'color-green';
break;
case constants.UserActivityType.Reverted:
color = 'color-red';
break;
case constants.UserActivityType.PublishedTemplate:
color = 'color-blue';
break;
case constants.UserActivityType.PublishedBlock:
color = 'color-blue';
break;
default:
break;
}
return color;
})
});

View file

@ -23,6 +23,7 @@ export default Ember.Service.extend({
ajax: service(), ajax: service(),
localStorage: service(), localStorage: service(),
kcAuth: service(), kcAuth: service(),
apiHost: `${config.apiHost}`,
endpoint: `${config.apiHost}/${config.apiNamespace}`, endpoint: `${config.apiHost}/${config.apiNamespace}`,
orgId: '', orgId: '',
title: '', title: '',

View file

@ -208,12 +208,19 @@ export default Ember.Service.extend({
}, },
// document meta referes to number of views, edits, approvals, etc. // document meta referes to number of views, edits, approvals, etc.
getMeta(documentId) { getActivity(documentId) {
return this.get('ajax').request(`documents/${documentId}/meta`, { return this.get('ajax').request(`documents/${documentId}/activity`, {
method: "GET" method: "GET"
}).then((response) => { }).then((response) => {
return response; let data = [];
data = response.map((obj) => {
let data = this.get('store').normalize('documentActivity', obj);
return this.get('store').push(data);
});
return data;
}).catch(() => { }).catch(() => {
return [];
}); });
}, },

View file

@ -28,10 +28,13 @@ export default Ember.Service.extend({
}); });
}, },
importSavedTemplate: function (folderId, templateId) { importSavedTemplate: function (folderId, templateId, docName) {
let url = `templates/${templateId}/folder/${folderId}?type=saved`; let url = `templates/${templateId}/folder/${folderId}?type=saved`;
return this.get('ajax').post(url).then((doc) => { return this.get('ajax').request(url, {
method: 'POST',
data: docName
}).then((doc) => {
let data = this.get('store').normalize('document', doc); let data = this.get('store').normalize('document', doc);
return this.get('store').push(data); return this.get('store').push(data);
}); });

View file

@ -9,22 +9,57 @@
// //
// https://documize.com // https://documize.com
@media print { @media print {
.non-printable, @page {
.zone-navigation, size: 8.5in 11in;
.zone-sidebar, margin: 20mm;
#sidebar-wrapper,
.document-heading, @top-right {
.edit-document-heading, font-size: 12px;
#sidebar-toggle, content: string(doctitle);
.back-to-space, color: $color-off-black;
.start-section,
.new-section-wizard {
display: none !important;
} }
#page-content-wrapper, #wrapper { @bottom-left {
padding: 0 !important; font-size: 12px;
content: 'Exported from Documize';
color: $color-off-black;
}
@bottom-right {
content: counter(page);
font-size: 12px;
color: $color-off-black;
}
}
html, body {
background-color: transparent !important;
max-width: none !important;
float: none !important;
position: relative !important;
height: initial !important;
min-height: initial !important;
}
.non-printable,
.zone-navigation,
#sidebar-wrapper,
.sidebar-wrapper,
.sidebar-common,
.sidebar-toolbar,
.sidebar-panel,
.edit-document-heading,
.back-to-space,
.start-section,
.start-button,
.is-a-tab,
.new-section-wizard {
float: none !important;
display: none !important;
margin: 0 !important; margin: 0 !important;
padding: 0 !important;
width: 0 !important;
z-index: 0 !important;
} }
.non-printable-message, .non-printable-message,
@ -32,9 +67,86 @@
display: block !important; display: block !important;
} }
.is-a-tab, .is-a-page { #wrapper {
padding: 0 !important; padding: 0 !important;
margin: 0 !important; margin: 0 !important;
box-shadow: none !important; position: relative !important;
box-shadow: initial !important;
border-radius: initial !important;
float: none !important;
overflow-x: initial !important;
padding-left: 0 !important;
.page-container {
padding: 0 !important;
margin: 0 !important;
position: initial !important;
box-shadow: initial !important;
border-radius: initial !important;
width: initial !important;
max-width: initial !important;
float: initial !important;
overflow-x: initial !important;
#page-content-wrapper {
padding: 0 !important;
margin: 0 !important;
position: initial !important;
box-shadow: initial !important;
border-radius: initial !important;
width: initial !important;
max-width: initial !important;
float: initial !important;
overflow-x: initial !important;
#zone-document-content {
padding: 0 !important;
margin: 0 !important;
position: initial !important;
box-shadow: initial !important;
border-radius: initial !important;
width: initial !important;
max-width: initial !important;
float: initial !important;
overflow-x: initial !important;
.document-heading {
.doc-title {
margin: 0 0 10px 0 !important;
}
}
.document-view {
padding: 0 !important;
margin: 0 !important;
position: initial !important;
box-shadow: initial !important;
border-radius: initial !important;
width: initial !important;
max-width: initial !important;
float: initial !important;
overflow-x: initial !important;
.is-a-page /*, .is-a-tab */ {
padding: 0 !important;
margin: 30px 0 20px 0 !important;
position: initial !important;
box-shadow: initial !important;
border-radius: initial !important;
width: initial !important;
max-width: initial !important;
float: initial !important;
overflow-x: initial !important;
}
}
}
}
}
}
.wysiwyg {
font-size: 15px;
line-height: 25px;
color: $color-black;
} }
} }

View file

@ -7,7 +7,6 @@ $sidebar-width: 400px;
-moz-transition: all 0.5s ease; -moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease; -o-transition: all 0.5s ease;
transition: all 0.5s ease; transition: all 0.5s ease;
background-color: $color-off-white;
} }
#sidebar-wrapper { #sidebar-wrapper {
@ -20,7 +19,6 @@ $sidebar-width: 400px;
height: 100%; height: 100%;
margin-left: -$sidebar-width; margin-left: -$sidebar-width;
border-right: 1px solid $color-stroke; border-right: 1px solid $color-stroke;
background: $color-off-white;
overflow-y: auto; overflow-y: auto;
-webkit-transition: all 0.5s ease; -webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease; -moz-transition: all 0.5s ease;
@ -28,10 +26,6 @@ $sidebar-width: 400px;
transition: all 0.5s ease; transition: all 0.5s ease;
} }
#wrapper.toggled #sidebar-wrapper {
width: $sidebar-width;
}
.page-container { .page-container {
margin-right: auto; margin-right: auto;
margin-left: auto; margin-left: auto;
@ -42,7 +36,8 @@ $sidebar-width: 400px;
#page-content-wrapper { #page-content-wrapper {
width: 100%; width: 100%;
position: absolute; position: relative;
// position: absolute;
padding: 30px; padding: 30px;
margin: 0 auto; margin: 0 auto;
margin-top: 30px; margin-top: 30px;
@ -54,42 +49,19 @@ $sidebar-width: 400px;
} }
} }
#wrapper.toggled #page-content-wrapper {
position: absolute;
margin-right: -$sidebar-width;
}
@media(min-width:768px) { @media(min-width:768px) {
#wrapper { #wrapper {
padding-left: $sidebar-width; padding-left: $sidebar-width;
} }
#wrapper.toggled {
padding-left: 0;
padding-right: 0;
}
#sidebar-wrapper { #sidebar-wrapper {
width: $sidebar-width; width: $sidebar-width;
} }
#wrapper.toggled #sidebar-wrapper { // #page-content-wrapper {
width: 0; // padding: 30px;
// position: relative;
.sidebar-toolbar { // }
position: relative;
}
}
#page-content-wrapper {
padding: 30px;
position: relative;
}
#wrapper.toggled #page-content-wrapper {
position: relative;
margin-left: 0;
}
} }
.sidebar-toolbar { .sidebar-toolbar {

View file

@ -1,4 +1,4 @@
<div id="page-{{ page.id }}" class="is-a-tab wysiwyg {{if expanded 'tab-max' 'tab-min'}}" data-id="{{ page.id }}" data-type="{{ page.contentType }}"> <div id="page-{{ page.id }}" class="is-a-tab wysiwyg non-printable {{if expanded 'tab-max' 'tab-min'}}" data-id="{{ page.id }}" data-type="{{ page.contentType }}">
{{document/tab-heading tagName=page.tagName document=document folder=folder page=page isEditor=isEditor {{document/tab-heading tagName=page.tagName document=document folder=folder page=page isEditor=isEditor
onExpand=(action 'onExpand') onSavePageAsBlock=(action 'onSavePageAsBlock') onCopyPage=(action 'onCopyPage') onMovePage=(action 'onMovePage') onDeletePage=(action 'onDeletePage')}} onExpand=(action 'onExpand') onSavePageAsBlock=(action 'onSavePageAsBlock') onCopyPage=(action 'onCopyPage') onMovePage=(action 'onMovePage') onDeletePage=(action 'onDeletePage')}}
{{#if expanded}} {{#if expanded}}

View file

@ -2,26 +2,13 @@
<div class="title">Activity</div> <div class="title">Activity</div>
<div class="document-sidebar-view-activity"> <div class="document-sidebar-view-activity">
<ul class="items"> <ul class="items">
{{#each sortedItems as |e|}} {{#each activity as |a|}}
<li class="item"> <li class="item">
<div class="avatar-box"> <div class="avatar-box">
<div class="avatar">{{user-initials e.item.firstname e.item.lastname}}</div> <div class="avatar">{{user-initials a.firstname a.lastname}}</div>
</div>
<div class="name">{{e.item.firstname}} {{e.item.lastname}}, {{time-ago e.date}}</div>
<div class="detail">
{{#if e.item.deleted}}
<div class="deleted">{{e.item.changeLabel}}</div>
{{/if}}
{{#if e.item.changed}}
<div class="changed">{{e.item.changeLabel}}</div>
{{/if}}
{{#if e.item.added}}
<div class="added">{{e.item.changeLabel}}</div>
{{/if}}
{{#if e.item.viewed}}
<div class="viewed">{{e.item.changeLabel}}</div>
{{/if}}
</div> </div>
<div class="name">{{a.firstname}} {{a.lastname}}</div>
<div class="detail {{a.activityColor}}">{{a.activityLabel}}, {{time-ago a.created}}</div>
</li> </li>
{{/each}} {{/each}}
</ul> </ul>

View file

@ -26,5 +26,18 @@ export default {
Feedback: 2, Feedback: 2,
Contribute: 3, Contribute: 3,
Approve: 4 Approve: 4
},
UserActivityType: {
Created: 1,
Read: 2,
Edited: 3,
Deleted: 4,
Archived: 5,
Approved: 6,
Reverted: 7,
PublishedTemplate: 8,
PublishedBlock: 9,
Feedback: 10
} }
}; };

View file

@ -227,16 +227,16 @@ textarea {
font-size: inherit; font-size: inherit;
line-height: inherit; line-height: inherit;
} }
a { /*a {
/*color: #337ab7;*/ color: #337ab7;
/*text-decoration: none;*/ text-decoration: none;
} }
/*a:hover, a:hover,
a:focus {*/ a:focus {
/*color: #23527c;*/ color: #23527c;
/*text-decoration: underline;*/ text-decoration: underline;
} }
/*a:focus { a:focus {
outline: thin dotted; outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color; outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px; outline-offset: -2px;
@ -1155,7 +1155,7 @@ hr {
display: none !important; display: none !important;
} }
} }
.visible-print { /*.visible-print {
display: none !important; display: none !important;
} }
@media print { @media print {
@ -1201,4 +1201,4 @@ hr {
.hidden-print { .hidden-print {
display: none !important; display: none !important;
} }
} }*/

View file

@ -227,6 +227,93 @@ func Authorize(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
} }
} }
// ValidToken finds and validates authentication token.
func ValidToken(r *http.Request) (context request.Context, valid bool) {
valid = false
token := findJWT(r)
hasToken := len(token) > 1
context, _, tokenErr := decodeJWT(token)
var org = entity.Organization{}
var err = errors.New("")
p := request.GetPersister(r)
// We always grab the org record regardless of token status.
// Why? If bad token we might be OK to alow anonymous access
// depending upon the domain in question.
if len(context.OrgID) == 0 {
org, err = p.GetOrganizationByDomain(request.GetRequestSubdomain(r))
} else {
org, err = p.GetOrganization(context.OrgID)
}
context.Subdomain = org.Domain
// Inability to find org record spells the end of this request.
if err != nil {
return
}
// If we have bad auth token and the domain does not allow anon access
if !org.AllowAnonymousAccess && tokenErr != nil {
return
}
domain := request.GetSubdomainFromHost(r)
domain2 := request.GetRequestSubdomain(r)
if org.Domain != domain && org.Domain != domain2 {
return
}
// If we have bad auth token and the domain allows anon access
// then we generate guest context.
if org.AllowAnonymousAccess {
// So you have a bad token
if hasToken {
if tokenErr != nil {
return
}
} else {
// Just grant anon user guest access
context.UserID = "0"
context.OrgID = org.RefID
context.Authenticated = false
context.Guest = true
}
}
// Refresh context and persister
request.SetContext(r, context)
p = request.GetPersister(r)
context.AllowAnonymousAccess = org.AllowAnonymousAccess
context.OrgName = org.Title
context.Administrator = false
context.Editor = false
context.Global = false
// Fetch user permissions for this org
if context.Authenticated {
user, err := getSecuredUser(p, org.RefID, context.UserID)
if err != nil {
return
}
context.Administrator = user.Admin
context.Editor = user.Editor
context.Global = user.Global
}
request.SetContext(r, context)
p = request.GetPersister(r)
valid = context.Authenticated || org.AllowAnonymousAccess
return
}
// Certain assets/URL do not require authentication. // Certain assets/URL do not require authentication.
// Just stops the log files being clogged up with failed auth errors. // Just stops the log files being clogged up with failed auth errors.
func preAuthorizeStaticAssets(r *http.Request) bool { func preAuthorizeStaticAssets(r *http.Request) bool {

View file

@ -26,6 +26,7 @@ import (
"github.com/documize/community/core/log" "github.com/documize/community/core/log"
"github.com/documize/community/core/utility" "github.com/documize/community/core/utility"
"github.com/documize/community/core/api/util"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
@ -126,39 +127,25 @@ func GetDocument(w http.ResponseWriter, r *http.Request) {
writeSuccessBytes(w, json) writeSuccessBytes(w, json)
} }
// GetDocumentMeta is an endpoint returning the metadata for a document. // GetDocumentActivity is an endpoint returning the activity logs for specified document.
func GetDocumentMeta(w http.ResponseWriter, r *http.Request) { func GetDocumentActivity(w http.ResponseWriter, r *http.Request) {
method := "GetDocumentMeta" method := "GetDocumentActivity"
p := request.GetPersister(r) p := request.GetPersister(r)
params := mux.Vars(r) params := mux.Vars(r)
id := params["documentID"]
id := params["documentID"]
if len(id) == 0 { if len(id) == 0 {
writeMissingDataError(w, method, "documentID") writeMissingDataError(w, method, "documentID")
return return
} }
meta, err := p.GetDocumentMeta(id) a, err := p.GetDocumentActivity(id)
if err != nil && err != sql.ErrNoRows {
if err == sql.ErrNoRows {
writeNotFoundError(w, method, id)
return
}
if err != nil {
writeGeneralSQLError(w, method, err) writeGeneralSQLError(w, method, err)
return return
} }
json, err := json.Marshal(meta) util.WriteJSON(w, a)
if err != nil {
writeJSONMarshalError(w, method, "document", err)
return
}
writeSuccessBytes(w, json)
} }
// GetDocumentLinks is an endpoint returning the links for a document. // GetDocumentLinks is an endpoint returning the links for a document.

View file

@ -16,6 +16,7 @@ package models
import ( import (
"github.com/documize/community/core/api/entity" "github.com/documize/community/core/api/entity"
"time"
) )
// PageSequenceRequestModel details a page ID and its sequence within the document. // PageSequenceRequestModel details a page ID and its sequence within the document.
@ -66,3 +67,16 @@ type PageModel struct {
Page entity.Page `json:"page"` Page entity.Page `json:"page"`
Meta entity.PageMeta `json:"meta"` Meta entity.PageMeta `json:"meta"`
} }
// DocumentActivity represents an activity taken against a document.
type DocumentActivity struct {
ID int `json:"id"`
OrgID string `json:"orgId"`
LabelID string `json:"folderId"`
DocumentID string `json:"documentId"`
UserID string `json:"userId"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
ActivityType int `json:"activityType"`
Created time.Time `json:"created"`
}

View file

@ -155,7 +155,7 @@ func init() {
log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}", []string{"GET", "OPTIONS"}, nil, GetDocument)) log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}", []string{"GET", "OPTIONS"}, nil, GetDocument))
log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}", []string{"PUT", "OPTIONS"}, nil, UpdateDocument)) log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}", []string{"PUT", "OPTIONS"}, nil, UpdateDocument))
log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}", []string{"DELETE", "OPTIONS"}, nil, DeleteDocument)) log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}", []string{"DELETE", "OPTIONS"}, nil, DeleteDocument))
log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/meta", []string{"GET", "OPTIONS"}, nil, GetDocumentMeta)) log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/activity", []string{"GET", "OPTIONS"}, nil, GetDocumentActivity))
// Document Page // Document Page
log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/pages/level", []string{"POST", "OPTIONS"}, nil, ChangeDocumentPageLevel)) log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/pages/level", []string{"POST", "OPTIONS"}, nil, ChangeDocumentPageLevel))

View file

@ -33,9 +33,9 @@ var port, certFile, keyFile, forcePort2SSL string
var Product core.ProdInfo var Product core.ProdInfo
func init() { func init() {
Product.Major = "0" Product.Major = "1"
Product.Minor = "44" Product.Minor = "0"
Product.Patch = "1" Product.Patch = "0"
Product.Version = fmt.Sprintf("%s.%s.%s", Product.Major, Product.Minor, Product.Patch) Product.Version = fmt.Sprintf("%s.%s.%s", Product.Major, Product.Minor, Product.Patch)
Product.Edition = "Community" Product.Edition = "Community"
Product.Title = fmt.Sprintf("%s Edition", Product.Edition) Product.Title = fmt.Sprintf("%s Edition", Product.Edition)
@ -175,7 +175,6 @@ func cors(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
} }
func metrics(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { func metrics(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
w.Header().Add("X-Documize-Version", Product.Version) w.Header().Add("X-Documize-Version", Product.Version)
w.Header().Add("Cache-Control", "no-cache") w.Header().Add("Cache-Control", "no-cache")

View file

@ -315,27 +315,32 @@ func StartDocumentFromStockTemplate(w http.ResponseWriter, r *http.Request) {
func StartDocumentFromSavedTemplate(w http.ResponseWriter, r *http.Request) { func StartDocumentFromSavedTemplate(w http.ResponseWriter, r *http.Request) {
method := "StartDocumentFromSavedTemplate" method := "StartDocumentFromSavedTemplate"
p := request.GetPersister(r) p := request.GetPersister(r)
params := mux.Vars(r) params := mux.Vars(r)
folderID := params["folderID"]
folderID := params["folderID"]
if len(folderID) == 0 { if len(folderID) == 0 {
writeMissingDataError(w, method, "folderID") writeMissingDataError(w, method, "folderID")
return return
} }
templateID := params["templateID"] templateID := params["templateID"]
// We are OK with zero valued template ID because it signals 'give me empty document'
if len(templateID) == 0 { if len(templateID) == 0 {
writeMissingDataError(w, method, "templateID") writeMissingDataError(w, method, "templateID")
return return
} }
defer utility.Close(r.Body)
body, err := ioutil.ReadAll(r.Body)
if err != nil {
writeBadRequestError(w, method, "Bad payload")
return
}
docTitle := string(body)
// Define an empty document just in case user wanted one. // Define an empty document just in case user wanted one.
var err error
var d = entity.Document{} var d = entity.Document{}
d.Title = "New Document" d.Title = docTitle
d.Location = fmt.Sprintf("template-%s", templateID) d.Location = fmt.Sprintf("template-%s", templateID)
d.Excerpt = "A new document" d.Excerpt = "A new document"
d.Slug = utility.MakeSlug(d.Title) d.Slug = utility.MakeSlug(d.Title)
@ -381,6 +386,7 @@ func StartDocumentFromSavedTemplate(w http.ResponseWriter, r *http.Request) {
d.Template = false d.Template = false
d.LabelID = folderID d.LabelID = folderID
d.UserID = p.Context.UserID d.UserID = p.Context.UserID
d.Title = docTitle
err = p.AddDocument(d) err = p.AddDocument(d)

View file

@ -12,8 +12,11 @@
package request package request
import ( import (
"database/sql"
"fmt"
"time" "time"
"github.com/documize/community/core/api/endpoint/models"
"github.com/documize/community/core/api/entity" "github.com/documize/community/core/api/entity"
"github.com/documize/community/core/log" "github.com/documize/community/core/log"
"github.com/documize/community/core/utility" "github.com/documize/community/core/utility"
@ -42,3 +45,27 @@ func (p *Persister) RecordUserActivity(activity entity.UserActivity) (err error)
return return
} }
// GetDocumentActivity returns the metadata for a specified document.
func (p *Persister) GetDocumentActivity(id string) (a []models.DocumentActivity, err error) {
s := `SELECT a.id, a.created, a.orgid, IFNULL(a.userid, '') AS userid, a.labelid, a.sourceid as documentid, a.activitytype,
IFNULL(u.firstname, 'Anonymous') AS firstname, IFNULL(u.lastname, 'Viewer') AS lastname
FROM useractivity a
LEFT JOIN user u ON a.userid=u.refid
WHERE a.orgid=? AND a.sourceid=? AND a.sourcetype=2
AND a.userid != '0' AND a.userid != ''
ORDER BY a.created DESC`
err = Db.Select(&a, s, p.Context.OrgID, id)
if len(a) == 0 {
a = []models.DocumentActivity{}
}
if err != nil && err != sql.ErrNoRows {
log.Error(fmt.Sprintf("Unable to execute GetDocumentActivity %s", id), err)
return
}
return
}

File diff suppressed because one or more lines are too long