mirror of
https://github.com/documize/community.git
synced 2025-07-20 05:39:42 +02:00
Allow doc/section/files links to open in tabs
Closes #233 and might help #236
This commit is contained in:
parent
92696c5181
commit
9e3eac19aa
12 changed files with 886 additions and 743 deletions
|
@ -49,7 +49,7 @@ Heck, Documize will probably run just fine on a Raspberry Pi.
|
||||||
|
|
||||||
## Technology Stack
|
## Technology Stack
|
||||||
|
|
||||||
- Go (v1.12.2)
|
- Go (v1.12.3)
|
||||||
- Ember JS (v3.8.0)
|
- Ember JS (v3.8.0)
|
||||||
|
|
||||||
## Authentication Options
|
## Authentication Options
|
||||||
|
|
|
@ -15,13 +15,14 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/documize/community/domain/auth"
|
|
||||||
"github.com/documize/community/model/space"
|
|
||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/documize/community/domain/auth"
|
||||||
|
"github.com/documize/community/model/space"
|
||||||
|
|
||||||
"github.com/documize/community/core/env"
|
"github.com/documize/community/core/env"
|
||||||
"github.com/documize/community/core/request"
|
"github.com/documize/community/core/request"
|
||||||
"github.com/documize/community/core/response"
|
"github.com/documize/community/core/response"
|
||||||
|
@ -161,7 +162,7 @@ func (h *Handler) Download(w http.ResponseWriter, r *http.Request) {
|
||||||
canDownload = true
|
canDownload = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(secureToken) == 0 && len(authToken) == 0 {
|
if !canDownload && len(secureToken) == 0 && len(authToken) == 0 {
|
||||||
h.Runtime.Log.Error("get attachment received no access token", err)
|
h.Runtime.Log.Error("get attachment received no access token", err)
|
||||||
response.WriteForbiddenError(w)
|
response.WriteForbiddenError(w)
|
||||||
return
|
return
|
||||||
|
|
|
@ -13,9 +13,12 @@ package link
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/documize/community/core/stringutil"
|
||||||
|
|
||||||
"github.com/documize/community/core/env"
|
"github.com/documize/community/core/env"
|
||||||
"github.com/documize/community/core/request"
|
"github.com/documize/community/core/request"
|
||||||
"github.com/documize/community/core/response"
|
"github.com/documize/community/core/response"
|
||||||
|
@ -160,3 +163,55 @@ func (h *Handler) SearchLinkCandidates(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
response.WriteJSON(w, payload)
|
response.WriteJSON(w, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLink returns link object for given ID.
|
||||||
|
func (h *Handler) GetLink(w http.ResponseWriter, r *http.Request) {
|
||||||
|
method := "link.GetLink"
|
||||||
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
|
// Param check.
|
||||||
|
linkID := request.Param(r, "linkID")
|
||||||
|
if len(linkID) == 0 {
|
||||||
|
response.WriteMissingDataError(w, method, "linkID")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load link record.
|
||||||
|
link, err := h.Store.Link.GetLink(ctx, linkID)
|
||||||
|
if err != nil {
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check document permissions.
|
||||||
|
if !permission.CanViewDocument(ctx, *h.Store, link.SourceDocumentID) {
|
||||||
|
response.WriteForbiddenError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build URL for link
|
||||||
|
url := ""
|
||||||
|
|
||||||
|
// Jump-to-document link type.
|
||||||
|
if link.LinkType == "document" {
|
||||||
|
doc, err := h.Store.Document.Get(ctx, link.TargetDocumentID)
|
||||||
|
if err != nil {
|
||||||
|
response.WriteString(w, url)
|
||||||
|
}
|
||||||
|
url = ctx.GetAppURL(fmt.Sprintf("s/%s/%s/d/%s/%s",
|
||||||
|
doc.SpaceID, doc.SpaceID, doc.RefID, stringutil.MakeSlug(doc.Name)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jump-to-section link type.
|
||||||
|
if link.LinkType == "section" || link.LinkType == "tab" {
|
||||||
|
doc, err := h.Store.Document.Get(ctx, link.TargetDocumentID)
|
||||||
|
if err != nil {
|
||||||
|
response.WriteString(w, url)
|
||||||
|
}
|
||||||
|
url = ctx.GetAppURL(fmt.Sprintf("s/%s/%s/d/%s/%s?currentPageId=%s",
|
||||||
|
doc.SpaceID, doc.SpaceID, doc.RefID,
|
||||||
|
stringutil.MakeSlug(doc.Name), link.TargetID))
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteString(w, url)
|
||||||
|
}
|
||||||
|
|
|
@ -46,6 +46,25 @@ func (s Store) Add(ctx domain.RequestContext, l link.Link) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLink returns specified link.
|
||||||
|
func (s Store) GetLink(ctx domain.RequestContext, linkID string) (l link.Link, err error) {
|
||||||
|
err = s.Runtime.Db.Get(&l, s.Bind(`
|
||||||
|
select c_refid AS refid, c_orgid AS orgid, c_spaceid AS spaceid, c_userid AS userid,
|
||||||
|
c_sourcedocid AS sourcedocumentid, c_sourcesectionid AS sourcesectionid,
|
||||||
|
c_targetdocid AS targetdocumentid, c_targetid AS targetid, c_externalid AS externalid,
|
||||||
|
c_type as linktype, c_orphan As orphan, c_created AS created, c_revised AS revised
|
||||||
|
FROM dmz_doc_link
|
||||||
|
WHERE c_orgid=? AND c_refid=?`),
|
||||||
|
ctx.OrgID, linkID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrapf(err, "select link %s", linkID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// GetDocumentOutboundLinks returns outbound links for specified document.
|
// GetDocumentOutboundLinks returns outbound links for specified document.
|
||||||
func (s Store) GetDocumentOutboundLinks(ctx domain.RequestContext, documentID string) (links []link.Link, err error) {
|
func (s Store) GetDocumentOutboundLinks(ctx domain.RequestContext, documentID string) (links []link.Link, err error) {
|
||||||
err = s.Runtime.Db.Select(&links, s.Bind(`
|
err = s.Runtime.Db.Select(&links, s.Bind(`
|
||||||
|
|
|
@ -215,6 +215,7 @@ type AttachmentStorer interface {
|
||||||
type LinkStorer interface {
|
type LinkStorer interface {
|
||||||
Add(ctx domain.RequestContext, l link.Link) (err error)
|
Add(ctx domain.RequestContext, l link.Link) (err error)
|
||||||
SearchCandidates(ctx domain.RequestContext, keywords string) (docs []link.Candidate, pages []link.Candidate, attachments []link.Candidate, err error)
|
SearchCandidates(ctx domain.RequestContext, keywords string) (docs []link.Candidate, pages []link.Candidate, attachments []link.Candidate, err error)
|
||||||
|
GetLink(ctx domain.RequestContext, linkID string) (l link.Link, err error)
|
||||||
GetDocumentOutboundLinks(ctx domain.RequestContext, documentID string) (links []link.Link, err error)
|
GetDocumentOutboundLinks(ctx domain.RequestContext, documentID string) (links []link.Link, err error)
|
||||||
GetPageLinks(ctx domain.RequestContext, documentID, pageID string) (links []link.Link, err error)
|
GetPageLinks(ctx domain.RequestContext, documentID, pageID string) (links []link.Link, err error)
|
||||||
MarkOrphanDocumentLink(ctx domain.RequestContext, documentID string) (err error)
|
MarkOrphanDocumentLink(ctx domain.RequestContext, documentID string) (err error)
|
||||||
|
|
1478
embed/bindata.go
1478
embed/bindata.go
File diff suppressed because one or more lines are too long
15
gui/app/pods/jumpto/controller.js
Normal file
15
gui/app/pods/jumpto/controller.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// 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 Controller from '@ember/controller';
|
||||||
|
|
||||||
|
export default Controller.extend({
|
||||||
|
});
|
37
gui/app/pods/jumpto/route.js
Normal file
37
gui/app/pods/jumpto/route.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||||
|
//
|
||||||
|
// This software (Documize Community Edition) is licensed under
|
||||||
|
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||||
|
//
|
||||||
|
// You can operate outside the AGPL restrictions by purchasing
|
||||||
|
// Documize Enterprise Edition and obtaining a commercial license
|
||||||
|
// by contacting <sales@documize.com>.
|
||||||
|
//
|
||||||
|
// https://documize.com
|
||||||
|
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
import { Promise } from 'rsvp';
|
||||||
|
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
|
||||||
|
import Route from '@ember/routing/route';
|
||||||
|
|
||||||
|
export default Route.extend(AuthenticatedRouteMixin, {
|
||||||
|
linkSvc: service('link'),
|
||||||
|
jumpToLink: '',
|
||||||
|
|
||||||
|
beforeModel: function () {
|
||||||
|
// let jumpType = this.paramsFor('jumpto').jump_type;
|
||||||
|
let jumpId = this.paramsFor('jumpto').jump_id;
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.get('linkSvc').fetchLinkUrl(jumpId).then((link) => {
|
||||||
|
this.set('jumpToLink', link);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
model: function () {
|
||||||
|
let link = this.get('jumpToLink');
|
||||||
|
window.location.href = link;
|
||||||
|
}
|
||||||
|
});
|
0
gui/app/pods/jumpto/template.hbs
Normal file
0
gui/app/pods/jumpto/template.hbs
Normal file
|
@ -129,6 +129,10 @@ export default Router.map(function () {
|
||||||
path: 'secure/:token'
|
path: 'secure/:token'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.route('jumpto', {
|
||||||
|
path: 'link/:jump_type/:jump_id'
|
||||||
|
});
|
||||||
|
|
||||||
this.route(
|
this.route(
|
||||||
'auth',
|
'auth',
|
||||||
{
|
{
|
||||||
|
|
|
@ -35,6 +35,16 @@ export default Service.extend(Notifier, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Returns link URL for specified link.
|
||||||
|
fetchLinkUrl(linkId) {
|
||||||
|
return this.get('ajax').request(`link/${linkId}`, {
|
||||||
|
method: 'GET',
|
||||||
|
dataType: 'text'
|
||||||
|
}).then((response) => {
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// Returns keyword-based candidates
|
// Returns keyword-based candidates
|
||||||
searchCandidates(keywords) {
|
searchCandidates(keywords) {
|
||||||
let url = "links?keywords=" + encodeURIComponent(keywords);
|
let url = "links?keywords=" + encodeURIComponent(keywords);
|
||||||
|
|
|
@ -187,6 +187,7 @@ func RegisterEndpoints(rt *env.Runtime, s *store.Store) {
|
||||||
|
|
||||||
AddPrivate(rt, "links/{spaceID}/{documentID}/{pageID}", []string{"GET", "OPTIONS"}, nil, link.GetLinkCandidates)
|
AddPrivate(rt, "links/{spaceID}/{documentID}/{pageID}", []string{"GET", "OPTIONS"}, nil, link.GetLinkCandidates)
|
||||||
AddPrivate(rt, "links", []string{"GET", "OPTIONS"}, nil, link.SearchLinkCandidates)
|
AddPrivate(rt, "links", []string{"GET", "OPTIONS"}, nil, link.SearchLinkCandidates)
|
||||||
|
AddPrivate(rt, "link/{linkID}", []string{"GET", "OPTIONS"}, nil, link.GetLink)
|
||||||
AddPrivate(rt, "documents/{documentID}/links", []string{"GET", "OPTIONS"}, nil, document.DocumentLinks)
|
AddPrivate(rt, "documents/{documentID}/links", []string{"GET", "OPTIONS"}, nil, document.DocumentLinks)
|
||||||
|
|
||||||
AddPrivate(rt, "pin/{userID}", []string{"POST", "OPTIONS"}, nil, pin.Add)
|
AddPrivate(rt, "pin/{userID}", []string{"POST", "OPTIONS"}, nil, pin.Add)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue