aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package.json2
-rw-r--r--src/client/util/SearchUtil.ts27
-rw-r--r--src/client/views/collections/CollectionSubView.tsx8
-rw-r--r--src/client/views/linking/LinkMenuItem.tsx1
-rw-r--r--src/client/views/pdf/Page.scss36
-rw-r--r--src/client/views/pdf/Page.tsx293
-rw-r--r--src/client/views/search/SearchBox.tsx15
-rw-r--r--src/client/views/search/SearchItem.tsx3
-rw-r--r--src/server/authentication/config/passport.ts2
-rw-r--r--src/server/index.ts43
10 files changed, 84 insertions, 346 deletions
diff --git a/package.json b/package.json
index 7a9e29f50..fa722a6ae 100644
--- a/package.json
+++ b/package.json
@@ -137,6 +137,7 @@
"express-session": "^1.15.6",
"express-validator": "^5.3.1",
"expressjs": "^1.0.1",
+ "find-in-files": "^0.5.0",
"flexlayout-react": "^0.3.3",
"font-awesome": "^4.7.0",
"formidable": "^1.2.1",
@@ -171,6 +172,7 @@
"passport": "^0.4.0",
"passport-google-oauth20": "^2.0.0",
"passport-local": "^1.0.0",
+ "pdf-parse": "^1.1.1",
"pdfjs-dist": "^2.0.943",
"probe-image-size": "^4.0.0",
"prosemirror-commands": "^1.0.8",
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index ee5a83710..d8b9dbec6 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -3,18 +3,22 @@ import { DocServer } from '../DocServer';
import { Doc } from '../../new_fields/Doc';
import { Id } from '../../new_fields/FieldSymbols';
import { Utils } from '../../Utils';
+import { ResultParameters } from '../northstar/model/idea/idea';
+import { DocumentType } from '../documents/DocumentTypes';
export namespace SearchUtil {
export type HighlightingResult = { [id: string]: { [key: string]: string[] } };
export interface IdSearchResult {
ids: string[];
+ lines: string[][];
numFound: number;
highlighting: HighlightingResult | undefined;
}
export interface DocSearchResult {
docs: Doc[];
+ lines: string[][];
numFound: number;
highlighting: HighlightingResult | undefined;
}
@@ -30,16 +34,31 @@ export namespace SearchUtil {
export function Search(query: string, returnDocs: false, options?: SearchParams): Promise<IdSearchResult>;
export async function Search(query: string, returnDocs: boolean, options: SearchParams = {}) {
query = query || "*"; //If we just have a filter query, search for * as the query
- const result: IdSearchResult = JSON.parse(await rp.get(Utils.prepend("/search"), {
+ let result: IdSearchResult = JSON.parse(await rp.get(Utils.prepend("/search"), {
qs: { ...options, q: query },
}));
if (!returnDocs) {
return result;
}
- const { ids, numFound, highlighting } = result;
+
+ let { ids, numFound, highlighting } = result;
+ let lines: string[][] = ids.map(i => []);
+
+ let txtresult = query !== "*" && JSON.parse(await rp.get(Utils.prepend("/textsearch"), {
+ qs: { ...options, q: query },
+ }));
+ let fileids = txtresult ? txtresult.ids : [];
+ await Promise.all(fileids.map(async (tr: string, i: number) => {
+ let docQuery = "fileUpload_t:" + tr.substr(0, 7); //If we just have a filter query, search for * as the query
+ let docResult = JSON.parse(await rp.get(Utils.prepend("/search"), { qs: { ...options, q: docQuery } }));
+ ids.push(...docResult.ids);
+ lines.push(...docResult.ids.map((dr: any) => txtresult.lines[i]));
+ numFound += docResult.numFound;
+ }));
+
const docMap = await DocServer.GetRefFields(ids);
- const docs = ids.map((id: string) => docMap[id]).filter((doc: any) => doc instanceof Doc);
- return { docs, numFound, highlighting };
+ const docs = ids.map((id: string) => docMap[id]).filter((doc: any) => doc instanceof Doc && doc.type !== DocumentType.KVP);
+ return { docs, numFound, highlighting, lines };
}
export async function GetAliasesOfDocument(doc: Doc): Promise<Doc[]>;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 13cf5e35a..155f2718b 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -22,6 +22,7 @@ import { CollectionPDFView } from "./CollectionPDFView";
import { CollectionVideoView } from "./CollectionVideoView";
import { CollectionView } from "./CollectionView";
import React = require("react");
+var path = require('path');
import { GooglePhotos } from "../../apis/google_docs/GooglePhotosClientUtils";
export interface CollectionViewProps extends FieldViewProps {
@@ -271,8 +272,11 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
}).then(async (res: Response) => {
(await res.json()).map(action((file: any) => {
let full = { ...options, nativeWidth: type.indexOf("video") !== -1 ? 600 : 300, width: 300, title: dropFileName };
- let path = Utils.prepend(file.path);
- Docs.Get.DocumentFromType(type, path, full).then(doc => doc && this.props.addDocument(doc));
+ let pathname = Utils.prepend(file.path);
+ Docs.Get.DocumentFromType(type, pathname, full).then(doc => {
+ doc && (doc.fileUpload = path.basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, ""));
+ doc && this.props.addDocument(doc);
+ });
}));
});
promises.push(prom);
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 835554ac0..77fa063f3 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -104,7 +104,6 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
async openLinkFollower() {
if (LinkFollowBox.Instance !== undefined) {
LinkFollowBox.Instance.props.Document.isMinimized = false;
- MainView.Instance.toggleLinkFollowBox(false);
LinkFollowBox.Instance.setLinkDocs(this.props.linkDoc, this.props.sourceDoc, this.props.destinationDoc);
}
}
diff --git a/src/client/views/pdf/Page.scss b/src/client/views/pdf/Page.scss
deleted file mode 100644
index d8034b4b4..000000000
--- a/src/client/views/pdf/Page.scss
+++ /dev/null
@@ -1,36 +0,0 @@
-
-.pdfViewer-text {
- .page {
- position: relative;
- }
-}
-.pdfPage-cont {
- position: relative;
-
- .pdfPage-canvasContainer {
- position: absolute;
- }
-
- .pdfPage-dragAnnotationBox {
- position: absolute;
- background-color: transparent;
- opacity: 0.1;
- }
-
- .pdfPage-textLayer {
- position: absolute;
- width: 100%;
- height: 100%;
- div {
- user-select: text;
- }
- span {
- color: transparent;
- position: absolute;
- white-space: pre;
- cursor: text;
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- }
- }
-} \ No newline at end of file
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
deleted file mode 100644
index 533247170..000000000
--- a/src/client/views/pdf/Page.tsx
+++ /dev/null
@@ -1,293 +0,0 @@
-import { action, IReactionDisposer, observable } from "mobx";
-import { observer } from "mobx-react";
-import * as Pdfjs from "pdfjs-dist";
-import "pdfjs-dist/web/pdf_viewer.css";
-import { Doc, DocListCastAsync, Opt, WidthSym } from "../../../new_fields/Doc";
-import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { Docs, DocUtils } from "../../documents/Documents";
-import { DragManager } from "../../util/DragManager";
-import PDFMenu from "./PDFMenu";
-import { scale } from "./PDFViewer";
-import "./Page.scss";
-import React = require("react");
-
-
-interface IPageProps {
- size: { width: number, height: number };
- pdf: Pdfjs.PDFDocumentProxy;
- name: string;
- numPages: number;
- page: number;
- pageLoaded: (page: Pdfjs.PDFPageViewport) => void;
- fieldExtensionDoc: Doc;
- Document: Doc;
- renderAnnotations: (annotations: Doc[], removeOld: boolean) => void;
- sendAnnotations: (annotations: HTMLDivElement[], page: number) => void;
- createAnnotation: (div: HTMLDivElement, page: number) => void;
- makeAnnotationDocuments: (doc: Doc | undefined, color: string, linkTo: boolean) => Doc;
- getScrollFromPage: (page: number) => number;
- setSelectionText: (text: string) => void;
-}
-
-@observer
-export default class Page extends React.Component<IPageProps> {
- @observable private _state: "N/A" | "rendering" = "N/A";
- @observable private _width: number = this.props.size.width;
- @observable private _height: number = this.props.size.height;
- @observable private _page: Opt<Pdfjs.PDFPageProxy>;
- @observable private _currPage: number = this.props.page + 1;
- @observable private _marqueeX: number = 0;
- @observable private _marqueeY: number = 0;
- @observable private _marqueeWidth: number = 0;
- @observable private _marqueeHeight: number = 0;
-
- private _canvas: React.RefObject<HTMLCanvasElement> = React.createRef();
- private _textLayer: React.RefObject<HTMLDivElement> = React.createRef();
- private _marquee: React.RefObject<HTMLDivElement> = React.createRef();
- private _marqueeing: boolean = false;
- private _reactionDisposer?: IReactionDisposer;
- private _startY: number = 0;
- private _startX: number = 0;
-
- componentDidMount = (): void => this.loadPage(this.props.pdf);
-
- componentDidUpdate = (): void => this.loadPage(this.props.pdf);
-
- componentWillUnmount = (): void => this._reactionDisposer && this._reactionDisposer();
-
- loadPage = (pdf: Pdfjs.PDFDocumentProxy): void => {
- pdf.getPage(this._currPage).then(page => this.renderPage(page));
- }
-
- @action
- renderPage = (page: Pdfjs.PDFPageProxy): void => {
- // lower scale = easier to read at small sizes, higher scale = easier to read at large sizes
- if (this._state !== "rendering" && !this._page && this._canvas.current && this._textLayer.current) {
- this._state = "rendering";
- let viewport = page.getViewport(scale);
- this._canvas.current.width = this._width = viewport.width;
- this._canvas.current.height = this._height = viewport.height;
- this.props.pageLoaded(viewport);
- let ctx = this._canvas.current.getContext("2d");
- if (ctx) {
- //@ts-ignore
- page.render({ canvasContext: ctx, viewport: viewport, enableWebGL: true }); // renders the page onto the canvas context
- page.getTextContent().then(res => // renders text onto the text container
- //@ts-ignore
- Pdfjs.renderTextLayer({
- textContent: res,
- container: this._textLayer.current,
- viewport: viewport
- }));
-
- this._page = page;
- }
- }
- }
-
- @action
- highlight = (targetDoc: Doc | undefined, color: string) => {
- // creates annotation documents for current highlights
- let annotationDoc = this.props.makeAnnotationDocuments(targetDoc, color, false);
- Doc.AddDocToList(this.props.fieldExtensionDoc, "annotations", annotationDoc);
- return annotationDoc;
- }
-
- /**
- * This is temporary for creating annotations from highlights. It will
- * start a drag event and create or put the necessary info into the drag event.
- */
- @action
- startDrag = (e: PointerEvent, ele: HTMLElement): void => {
- e.preventDefault();
- e.stopPropagation();
- if (this._textLayer.current) {
- let targetDoc = Docs.Create.TextDocument({ width: 200, height: 200, title: "New Annotation" });
- targetDoc.targetPage = this.props.page;
- let annotationDoc = this.highlight(undefined, "red");
- annotationDoc.linkedToDoc = false;
- let dragData = new DragManager.AnnotationDragData(this.props.Document, annotationDoc, targetDoc);
- DragManager.StartAnnotationDrag([ele], dragData, e.pageX, e.pageY, {
- handlers: {
- dragComplete: async () => {
- if (!BoolCast(annotationDoc.linkedToDoc)) {
- let annotations = await DocListCastAsync(annotationDoc.annotations);
- annotations && annotations.forEach(anno => anno.target = targetDoc);
- DocUtils.MakeLink(annotationDoc, targetDoc, dragData.targetContext, `Annotation from ${StrCast(this.props.Document.title)}`);
- }
- }
- },
- hideSource: false
- });
- }
- }
-
- // cleans up events and boolean
- endDrag = (e: PointerEvent): void => {
- e.stopPropagation();
- }
-
- createSnippet = (marquee: { left: number, top: number, width: number, height: number }): void => {
- let view = Doc.MakeAlias(this.props.Document);
- let data = Doc.MakeDelegate(Doc.GetProto(this.props.Document));
- data.title = StrCast(data.title) + "_snippet";
- view.proto = data;
- view.nativeHeight = marquee.height;
- view.height = (this.props.Document[WidthSym]() / NumCast(this.props.Document.nativeWidth)) * marquee.height;
- view.nativeWidth = this.props.Document.nativeWidth;
- view.startY = marquee.top + this.props.getScrollFromPage(this.props.page);
- view.width = this.props.Document[WidthSym]();
- DragManager.StartDocumentDrag([], new DragManager.DocumentDragData([view]), 0, 0);
- }
-
- @action
- onPointerDown = (e: React.PointerEvent): void => {
- // if alt+left click, drag and annotate
- if (NumCast(this.props.Document.scale, 1) !== 1) return;
- if (!e.altKey && e.button === 0) {
- PDFMenu.Instance.StartDrag = this.startDrag;
- PDFMenu.Instance.Highlight = this.highlight;
- PDFMenu.Instance.Snippet = this.createSnippet;
- PDFMenu.Instance.Status = "pdf";
- PDFMenu.Instance.fadeOut(true);
- if (e.target && (e.target as any).parentElement === this._textLayer.current) {
- e.stopPropagation();
- if (!e.ctrlKey) {
- this.props.sendAnnotations([], -1);
- }
- }
- else {
- // set marquee x and y positions to the spatially transformed position
- if (this._textLayer.current) {
- let boundingRect = this._textLayer.current.getBoundingClientRect();
- this._startX = this._marqueeX = (e.clientX - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width);
- this._startY = this._marqueeY = (e.clientY - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height);
- }
- this._marqueeing = true;
- this._marquee.current && (this._marquee.current.style.opacity = "0.2");
- this.props.sendAnnotations([], -1);
- }
- document.removeEventListener("pointermove", this.onSelectStart);
- document.addEventListener("pointermove", this.onSelectStart);
- document.removeEventListener("pointerup", this.onSelectEnd);
- document.addEventListener("pointerup", this.onSelectEnd);
- }
- }
-
- @action
- onSelectStart = (e: PointerEvent): void => {
- if (this._marqueeing && this._textLayer.current) {
- // transform positions and find the width and height to set the marquee to
- let boundingRect = this._textLayer.current.getBoundingClientRect();
- this._marqueeWidth = ((e.clientX - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width)) - this._startX;
- this._marqueeHeight = ((e.clientY - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height)) - this._startY;
- this._marqueeX = Math.min(this._startX, this._startX + this._marqueeWidth);
- this._marqueeY = Math.min(this._startY, this._startY + this._marqueeHeight);
- this._marqueeWidth = Math.abs(this._marqueeWidth);
- e.stopPropagation();
- e.preventDefault();
- }
- else if (e.target && (e.target as any).parentElement === this._textLayer.current) {
- e.stopPropagation();
- }
- }
-
- @action
- onSelectEnd = (e: PointerEvent): void => {
- if (this._marqueeing) {
- this._marqueeing = false;
- if (this._marqueeWidth > 10 || this._marqueeHeight > 10) {
- if (this._marquee.current) { // make a copy of the marquee
- let copy = document.createElement("div");
- let style = this._marquee.current.style;
- copy.style.left = style.left;
- copy.style.top = style.top;
- copy.style.width = style.width;
- copy.style.height = style.height;
- copy.style.border = style.border;
- copy.style.opacity = style.opacity;
- copy.className = "pdfPage-annotationBox";
- this.props.createAnnotation(copy, this.props.page);
- this._marquee.current.style.opacity = "0";
- }
-
- if (!e.ctrlKey) {
- PDFMenu.Instance.Status = "snippet";
- PDFMenu.Instance.Marquee = { left: this._marqueeX, top: this._marqueeY, width: this._marqueeWidth, height: this._marqueeHeight };
- }
- PDFMenu.Instance.jumpTo(e.clientX, e.clientY);
- }
-
- this._marqueeHeight = this._marqueeWidth = 0;
- }
- else {
- let sel = window.getSelection();
- if (sel && sel.type === "Range") {
- let selRange = sel.getRangeAt(0);
- this.createTextAnnotation(sel, selRange);
- PDFMenu.Instance.jumpTo(e.clientX, e.clientY);
- }
- }
-
- if (PDFMenu.Instance.Highlighting) {
- this.highlight(undefined, "goldenrod");
- }
- else {
- PDFMenu.Instance.StartDrag = this.startDrag;
- PDFMenu.Instance.Highlight = this.highlight;
- }
- document.removeEventListener("pointermove", this.onSelectStart);
- document.removeEventListener("pointerup", this.onSelectEnd);
- }
-
- @action
- createTextAnnotation = (sel: Selection, selRange: Range) => {
- if (this._textLayer.current) {
- let boundingRect = this._textLayer.current.getBoundingClientRect();
- let clientRects = selRange.getClientRects();
- for (let i = 0; i < clientRects.length; i++) {
- let rect = clientRects.item(i);
- if (rect && rect.width !== this._textLayer.current.getBoundingClientRect().width && rect.height !== this._textLayer.current.getBoundingClientRect().height) {
- let annoBox = document.createElement("div");
- annoBox.className = "pdfPage-annotationBox";
- // transforms the positions from screen onto the pdf div
- annoBox.style.top = ((rect.top - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height)).toString();
- annoBox.style.left = ((rect.left - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width)).toString();
- annoBox.style.width = (rect.width * this._textLayer.current.offsetWidth / boundingRect.width).toString();
- annoBox.style.height = (rect.height * this._textLayer.current.offsetHeight / boundingRect.height).toString();
- this.props.createAnnotation(annoBox, this.props.page);
- }
- }
- }
- let text = selRange.cloneContents().textContent;
- text && this.props.setSelectionText(text);
-
- // clear selection
- if (sel.empty) { // Chrome
- sel.empty();
- } else if (sel.removeAllRanges) { // Firefox
- sel.removeAllRanges();
- }
- }
-
- doubleClick = (e: React.MouseEvent) => {
- if (e.target && (e.target as any).parentElement === this._textLayer.current) {
- // do something to select the paragraph ideally
- }
- }
-
- render() {
- return (
- <div className={"pdfPage-cont"} onPointerDown={this.onPointerDown} onDoubleClick={this.doubleClick} style={{ "width": this._width, "height": this._height }}>
- <canvas className="PdfPage-canvasContainer" ref={this._canvas} />
- <div className="pdfPage-dragAnnotationBox" ref={this._marquee}
- style={{
- left: `${this._marqueeX}px`, top: `${this._marqueeY}px`,
- width: `${this._marqueeWidth}px`, height: `${this._marqueeHeight}px`,
- border: `${this._marqueeWidth === 0 ? "" : "10px dashed black"}`
- }}>
- </div>
- <div className="pdfPage-textlayer" ref={this._textLayer} />
- </div>);
- }
-} \ No newline at end of file
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 0d50124dd..f53270c64 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -18,6 +18,7 @@ import { FilterBox } from './FilterBox';
import "./FilterBox.scss";
import "./SearchBox.scss";
import { SearchItem } from './SearchItem';
+import { string } from 'prop-types';
library.add(faTimes);
@@ -27,7 +28,7 @@ export class SearchBox extends React.Component {
@observable private _searchString: string = "";
@observable private _resultsOpen: boolean = false;
@observable private _searchbarOpen: boolean = false;
- @observable private _results: [Doc, string[]][] = [];
+ @observable private _results: [Doc, string[], string[]][] = [];
private _resultsSet = new Map<Doc, number>();
@observable private _openNoResults: boolean = false;
@observable private _visibleElements: JSX.Element[] = [];
@@ -159,6 +160,8 @@ export class SearchBox extends React.Component {
const highlighting = res.highlighting || {};
const highlightList = res.docs.map(doc => highlighting[doc[Id]]);
+ const lines = new Map<string, string[]>();
+ res.docs.map((doc, i) => lines.set(doc[Id], res.lines[i]));
const docs = await Promise.all(res.docs.map(async doc => (await Cast(doc.extendsDoc, Doc)) || doc));
const highlights: typeof res.highlighting = {};
docs.forEach((doc, index) => highlights[doc[Id]] = highlightList[index]);
@@ -168,12 +171,14 @@ export class SearchBox extends React.Component {
filteredDocs.forEach(doc => {
const index = this._resultsSet.get(doc);
const highlight = highlights[doc[Id]];
+ const line = lines.get(doc[Id]) || [];
const hlights = highlight ? Object.keys(highlight).map(key => key.substring(0, key.length - 2)) : [];
if (index === undefined) {
this._resultsSet.set(doc, this._results.length);
- this._results.push([doc, hlights]);
+ this._results.push([doc, hlights, line]);
} else {
this._results[index][1].push(...hlights);
+ this._results[index][2].push(...line);
}
});
});
@@ -296,13 +301,13 @@ export class SearchBox extends React.Component {
}
else {
if (this._isSearch[i] !== "search") {
- let result: [Doc, string[]] | undefined = undefined;
+ let result: [Doc, string[], string[]] | undefined = undefined;
if (i >= this._results.length) {
this.getResults(this._searchString);
if (i < this._results.length) result = this._results[i];
if (result) {
let highlights = Array.from([...Array.from(new Set(result[1]).values())]).filter(v => v !== "search_string");
- this._visibleElements[i] = <SearchItem doc={result[0]} query={this._searchString} key={result[0][Id]} highlighting={highlights} />;
+ this._visibleElements[i] = <SearchItem doc={result[0]} query={this._searchString} key={result[0][Id]} lines={result[2]} highlighting={highlights} />;
this._isSearch[i] = "search";
}
}
@@ -310,7 +315,7 @@ export class SearchBox extends React.Component {
result = this._results[i];
if (result) {
let highlights = Array.from([...Array.from(new Set(result[1]).values())]).filter(v => v !== "search_string");
- this._visibleElements[i] = <SearchItem doc={result[0]} query={this._searchString} key={result[0][Id]} highlighting={highlights} />;
+ this._visibleElements[i] = <SearchItem doc={result[0]} query={this._searchString} key={result[0][Id]} lines={result[2]} highlighting={highlights} />;
this._isSearch[i] = "search";
}
}
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 96eefacc2..4d021216d 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -30,6 +30,7 @@ export interface SearchItemProps {
doc: Doc;
query: string;
highlighting: string[];
+ lines: string[];
}
library.add(faCaretUp);
@@ -288,7 +289,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
<div title="Drag as document" onPointerDown={this.onPointerDown} style={{ marginRight: "7px" }}> <FontAwesomeIcon icon="file" size="lg" /> </div>
<div className="search-title-container">
<div className="search-title">{StrCast(this.props.doc.title)}</div>
- <div className="search-highlighting">Matched fields: {this.props.highlighting.join(", ")}</div>
+ <div className="search-highlighting">{this.props.highlighting.length ? "Matched fields:" + this.props.highlighting.join(", ") : this.props.lines.length ? "Text:" + this.props.lines[0] : ""}</div>
</div>
<div className="search-info" style={{ width: this._useIcons ? "15%" : "400px" }}>
<div className={`icon-${this._useIcons ? "icons" : "live"}`}>
diff --git a/src/server/authentication/config/passport.ts b/src/server/authentication/config/passport.ts
index f69b274d3..8b20d29b1 100644
--- a/src/server/authentication/config/passport.ts
+++ b/src/server/authentication/config/passport.ts
@@ -42,7 +42,7 @@ export let isAuthorized = (req: Request, res: Response, next: NextFunction) => {
const provider = req.path.split("/").slice(-1)[0];
if (req.user) {
- if (_.find(req.user.tokens, { kind: provider })) {
+ if (_.find((req.user as any).tokens, { kind: provider })) {
next();
} else {
res.redirect(`/auth/${provider}`);
diff --git a/src/server/index.ts b/src/server/index.ts
index 7ebb374e9..0ee00f516 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -41,10 +41,12 @@ var AdmZip = require('adm-zip');
import * as YoutubeApi from "./apis/youtube/youtubeApiSample";
import { Response } from 'express-serve-static-core';
import { GoogleApiServerUtils } from "./apis/google/GoogleApiServerUtils";
-import { GooglePhotosUploadUtils } from './apis/google/GooglePhotosUploadUtils';
const MongoStore = require('connect-mongo')(session);
const mongoose = require('mongoose');
const probe = require("probe-image-size");
+const pdf = require('pdf-parse');
+var findInFiles = require('find-in-files');
+import { GooglePhotosUploadUtils } from './apis/google/GooglePhotosUploadUtils';
import * as qs from 'query-string';
import { Opt } from '../new_fields/Doc';
import { DashUploadUtils } from './DashUploadUtils';
@@ -118,7 +120,7 @@ function addSecureRoute(method: Method,
let sharing = qs.parse(qs.extract(req.originalUrl), { sort: false }).sharing === "true";
sharing = sharing && req.originalUrl.startsWith("/doc/");
if (req.user || sharing) {
- handler(req.user, res, req);
+ handler(req.user as any, res, req);
} else {
req.session!.target = req.originalUrl;
onRejection(res, req);
@@ -205,6 +207,23 @@ const solrURL = "http://localhost:8983/solr/#/dash";
// GETTERS
+app.get("/textsearch", async (req, res) => {
+ let q = req.query.q;
+ console.log("TEXTSEARCH " + q);
+ if (q === undefined) {
+ res.send([]);
+ return;
+ }
+ let results = await findInFiles.find({ 'term': q, 'flags': 'ig' }, uploadDirectory + "text", ".txt$");
+ let resObj: { ids: string[], numFound: number, lines: string[] } = { ids: [], numFound: 0, lines: [] };
+ for (var result in results) {
+ resObj.ids.push(path.basename(result, ".txt").replace(/upload_/, ""));
+ resObj.lines.push(results[result].line);
+ resObj.numFound++;
+ }
+ res.send(resObj);
+});
+
app.get("/search", async (req, res) => {
const solrQuery: any = {};
["q", "fq", "start", "rows", "hl", "hl.fl"].forEach(key => solrQuery[key] = req.query[key]);
@@ -583,8 +602,26 @@ app.post(
for (const key in files) {
const { type, path: location, name } = files[key];
const filename = path.basename(location);
- await DashUploadUtils.UploadImage(uploadDirectory + filename, filename).catch(() => console.log(`Unable to process ${filename}`));
+ if (filename.endsWith(".pdf")) {
+
+ var filePath = uploadDirectory + filename;
+
+ let dataBuffer = fs.readFileSync(filePath);
+
+ pdf(dataBuffer).then(async function (data: any) {
+ // // number of pages - data.numpages
+ // // number of rendered pages - data.numrender
+ // // PDF info - data.info
+ // // PDF metadata - data.metadata
+ // // PDF.js version - data.version // check https://mozilla.github.io/pdf.js/getting_started/
+ // // PDF text - data.text
+ fs.createWriteStream(uploadDirectory + "text/" + filename.substring(0, filename.length - ".pdf".length) + ".txt").write(data.text);
+ });
+ } else {
+ await DashUploadUtils.UploadImage(uploadDirectory + filename, filename).catch(() => console.log(`Unable to process ${filename}`));
+ }
results.push({ name, type, path: `/files/${filename}` });
+
}
_success(res, results);
});