aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package.json4
-rw-r--r--src/client/util/Import & Export/DirectoryImportBox.tsx12
-rw-r--r--src/client/util/SearchUtil.ts23
-rw-r--r--src/client/util/TooltipTextMenu.tsx42
-rw-r--r--src/client/views/MainView.tsx5
-rw-r--r--src/client/views/collections/ParentDocumentSelector.tsx4
-rw-r--r--src/client/views/globalCssVariables.scss13
-rw-r--r--src/client/views/nodes/DocumentView.tsx4
-rw-r--r--src/client/views/pdf/PDFViewer.tsx1
-rw-r--r--src/client/views/pdf/Page.tsx4
-rw-r--r--src/client/views/search/FilterBox.tsx4
-rw-r--r--src/client/views/search/SearchBox.tsx11
-rw-r--r--src/client/views/search/SearchItem.tsx4
-rw-r--r--src/server/Search.ts3
-rw-r--r--src/server/authentication/controllers/user_controller.ts25
-rw-r--r--src/server/authentication/models/user_model.ts2
-rw-r--r--src/server/index.ts6
17 files changed, 119 insertions, 48 deletions
diff --git a/package.json b/package.json
index 22b3a6b21..7407a719f 100644
--- a/package.json
+++ b/package.json
@@ -73,7 +73,7 @@
"@types/lodash": "^4.14.121",
"@types/mobile-detect": "^1.3.4",
"@types/mongodb": "^3.1.22",
- "@types/mongoose": "^5.3.21",
+ "@types/mongoose": "^5.5.8",
"@types/node": "^10.12.30",
"@types/nodemailer": "^4.6.6",
"@types/passport": "^1.0.0",
@@ -144,7 +144,7 @@
"mobx-react-devtools": "^6.1.1",
"mobx-utils": "^5.4.0",
"mongodb": "^3.1.13",
- "mongoose": "^5.4.18",
+ "mongoose": "^5.6.4",
"node-sass": "^4.12.0",
"nodemailer": "^5.1.1",
"nodemon": "^1.18.10",
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index a810db0fa..c096e9ceb 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx
@@ -8,7 +8,7 @@ import { FieldViewProps, FieldView } from "../../views/nodes/FieldView";
import Measure, { ContentRect } from "react-measure";
import { library } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faArrowUp, faTag, faPlus } from '@fortawesome/free-solid-svg-icons';
+import { faTag, faPlus, faCloudUploadAlt } from '@fortawesome/free-solid-svg-icons';
import { Docs, DocumentOptions } from "../../documents/Documents";
import { observer } from "mobx-react";
import ImportMetadataEntry, { keyPlaceholder, valuePlaceholder } from "./ImportMetadataEntry";
@@ -40,7 +40,7 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps>
constructor(props: FieldViewProps) {
super(props);
- library.add(faArrowUp, faTag, faPlus);
+ library.add(faTag, faPlus);
let doc = this.props.Document;
this.editingMetadata = this.editingMetadata || false;
this.persistent = this.persistent || false;
@@ -237,12 +237,12 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps>
}} />
<div style={{
position: "absolute",
- left: this.left + 12.6,
- top: this.top + 11,
+ left: this.left + 8,
+ top: this.top + 10,
opacity: uploading ? 0 : 1,
transition: "0.4s opacity ease"
}}>
- <FontAwesomeIcon icon={faArrowUp} color="#FFFFFF" size={"2x"} />
+ <FontAwesomeIcon icon={faCloudUploadAlt} color="#FFFFFF" size={"2x"} />
</div>
<img
style={{
@@ -318,7 +318,7 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps>
opacity: uploading ? 0 : 1,
transition: "0.4s opacity ease"
}}
- icon={isEditing ? faArrowUp : faTag}
+ icon={isEditing ? faCloudUploadAlt : faTag}
color="#FFFFFF"
size={"1x"}
/>
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 674eeb1a8..806746496 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -14,11 +14,12 @@ export namespace SearchUtil {
numFound: number;
}
- export function Search(query: string, returnDocs: true, start?: number, count?: number): Promise<DocSearchResult>;
- export function Search(query: string, returnDocs: false, start?: number, count?: number): Promise<IdSearchResult>;
- export async function Search(query: string, returnDocs: boolean, start?: number, rows?: number) {
+ export function Search(query: string, filterQuery: string | undefined, returnDocs: true, start?: number, count?: number): Promise<DocSearchResult>;
+ export function Search(query: string, filterQuery: string | undefined, returnDocs: false, start?: number, count?: number): Promise<IdSearchResult>;
+ export async function Search(query: string, filterQuery: string | undefined, returnDocs: boolean, start?: number, rows?: number) {
+ query = query || "*"; //If we just have a filter query, search for * as the query
const result: IdSearchResult = JSON.parse(await rp.get(DocServer.prepend("/search"), {
- qs: { query, start, rows }
+ qs: { query, filterQuery, start, rows },
}));
if (!returnDocs) {
return result;
@@ -35,31 +36,31 @@ export namespace SearchUtil {
const proto = Doc.GetProto(doc);
const protoId = proto[Id];
if (returnDocs) {
- return (await Search(`proto_i:"${protoId}"`, returnDocs)).docs;
+ return (await Search("", `proto_i:"${protoId}"`, returnDocs)).docs;
} else {
- return (await Search(`proto_i:"${protoId}"`, returnDocs)).ids;
+ return (await Search("", `proto_i:"${protoId}"`, returnDocs)).ids;
}
// return Search(`{!join from=id to=proto_i}id:${protoId}`, true);
}
export async function GetViewsOfDocument(doc: Doc): Promise<Doc[]> {
- const results = await Search(`proto_i:"${doc[Id]}"`, true);
+ const results = await Search("", `proto_i:"${doc[Id]}"`, true);
return results.docs;
}
export async function GetContextsOfDocument(doc: Doc): Promise<{ contexts: Doc[], aliasContexts: Doc[] }> {
- const docContexts = (await Search(`data_l:"${doc[Id]}"`, true)).docs;
+ const docContexts = (await Search("", `data_l:"${doc[Id]}"`, true)).docs;
const aliases = await GetAliasesOfDocument(doc, false);
- const aliasContexts = (await Promise.all(aliases.map(doc => Search(`data_l:"${doc}"`, true))));
+ const aliasContexts = (await Promise.all(aliases.map(doc => Search("", `data_l:"${doc}"`, true))));
const contexts = { contexts: docContexts, aliasContexts: [] as Doc[] };
aliasContexts.forEach(result => contexts.aliasContexts.push(...result.docs));
return contexts;
}
export async function GetContextIdsOfDocument(doc: Doc): Promise<{ contexts: string[], aliasContexts: string[] }> {
- const docContexts = (await Search(`data_l:"${doc[Id]}"`, false)).ids;
+ const docContexts = (await Search("", `data_l:"${doc[Id]}"`, false)).ids;
const aliases = await GetAliasesOfDocument(doc, false);
- const aliasContexts = (await Promise.all(aliases.map(doc => Search(`data_l:"${doc}"`, false))));
+ const aliasContexts = (await Promise.all(aliases.map(doc => Search("", `data_l:"${doc}"`, false))));
const contexts = { contexts: docContexts, aliasContexts: [] as string[] };
aliasContexts.forEach(result => contexts.aliasContexts.push(...result.ids));
return contexts;
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 9ba339285..fe7e0b97f 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -51,6 +51,7 @@ export class TooltipTextMenu {
this.tooltip = document.createElement("div");
this.tooltip.className = "tooltipMenu";
+ this.dragElement(this.tooltip);
// this.createCollapse();
// if (this._collapseBtn) {
// this.tooltip.appendChild(this._collapseBtn.render(this.view).dom);
@@ -269,6 +270,47 @@ export class TooltipTextMenu {
// this.tooltip.appendChild(this.linkEditor);
}
+ dragElement(elmnt: HTMLElement) {
+ var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
+ if (elmnt) {
+ // if present, the header is where you move the DIV from:
+ elmnt.onpointerdown = dragMouseDown;
+ }
+ const self = this;
+
+ function dragMouseDown(e: PointerEvent) {
+ e = e || window.event;
+ //e.preventDefault();
+ // get the mouse cursor position at startup:
+ pos3 = e.clientX;
+ pos4 = e.clientY;
+ document.onpointerup = closeDragElement;
+ // call a function whenever the cursor moves:
+ document.onpointermove = elementDrag;
+ }
+
+ function elementDrag(e: PointerEvent) {
+ e = e || window.event;
+ //e.preventDefault();
+ // calculate the new cursor position:
+ pos1 = pos3 - e.clientX;
+ pos2 = pos4 - e.clientY;
+ pos3 = e.clientX;
+ pos4 = e.clientY;
+ // set the element's new position:
+ elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
+ elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
+ }
+
+ function closeDragElement() {
+ // stop moving when mouse button is released:
+ document.onpointerup = null;
+ document.onpointermove = null;
+ //self.highlightSearchTerms(self.state, ["hello"]);
+ //FormattedTextBox.Instance.unhighlightSearchTerms();
+ }
+ }
+
makeLink = (target: string) => {
let node = this.view.state.selection.$from.nodeAfter;
let link = this.view.state.schema.mark(this.view.state.schema.marks.link, { href: target });
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 76cc7e6d3..ce7369220 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,5 +1,5 @@
import { IconName, library } from '@fortawesome/fontawesome-svg-core';
-import { faArrowDown, faArrowUp, faClone, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faPortrait, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt, faCat } from '@fortawesome/free-solid-svg-icons';
+import { faArrowDown, faCloudUploadAlt, faArrowUp, faClone, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faPortrait, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt, faCat } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, configure, observable, runInAction, reaction, trace } from 'mobx';
import { observer } from 'mobx-react';
@@ -130,6 +130,7 @@ export class MainView extends React.Component {
library.add(faCheck);
library.add(faArrowDown);
library.add(faArrowUp);
+ library.add(faCloudUploadAlt);
this.initEventListeners();
this.initAuthenticationRouters();
}
@@ -382,7 +383,7 @@ export class MainView extends React.Component {
let btns: [React.RefObject<HTMLDivElement>, IconName, string, () => Doc][] = [
[React.createRef<HTMLDivElement>(), "object-group", "Add Collection", addColNode],
// [React.createRef<HTMLDivElement>(), "clone", "Add Docking Frame", addDockingNode],
- [React.createRef<HTMLDivElement>(), "arrow-up", "Import Directory", addImportCollectionNode],
+ [React.createRef<HTMLDivElement>(), "cloud-upload-alt", "Import Directory", addImportCollectionNode],
];
if (!ClientUtils.RELEASE) btns.unshift([React.createRef<HTMLDivElement>(), "cat", "Add Cat Image", addImageNode]);
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index c0f489cd8..a97aa4f36 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -23,9 +23,9 @@ export class SelectorContextMenu extends React.Component<SelectorProps> {
async fetchDocuments() {
let aliases = (await SearchUtil.GetAliasesOfDocument(this.props.Document)).filter(doc => doc !== this.props.Document);
- const { docs } = await SearchUtil.Search(`data_l:"${this.props.Document[Id]}"`, true);
+ const { docs } = await SearchUtil.Search("", `data_l:"${this.props.Document[Id]}"`, true);
const map: Map<Doc, Doc> = new Map;
- const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search(`data_l:"${doc[Id]}"`, true).then(result => result.docs)));
+ const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search("", `data_l:"${doc[Id]}"`, true).then(result => result.docs)));
allDocs.forEach((docs, index) => docs.forEach(doc => map.set(doc, aliases[index])));
docs.forEach(doc => map.delete(doc));
runInAction(() => {
diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss
index fec105516..6dffee586 100644
--- a/src/client/views/globalCssVariables.scss
+++ b/src/client/views/globalCssVariables.scss
@@ -13,23 +13,26 @@ $darker-alt-accent: rgb(178, 206, 248);
$intermediate-color: #9c9396;
$dark-color: #121721;
// fonts
-$sans-serif: "Noto Sans", sans-serif;
+$sans-serif: "Noto Sans",
+sans-serif;
// $sans-serif: "Roboto Slab", sans-serif;
-$serif: "Crimson Text", serif;
+$serif: "Crimson Text",
+serif;
// misc values
$border-radius: 0.3em;
//
$search-thumnail-size: 175;
- // dragged items
-$contextMenu-zindex: 1000; // context menu shows up over everything
+// dragged items
+$contextMenu-zindex: 100000; // context menu shows up over everything
$mainTextInput-zindex: 999; // then text input overlay so that it's context menu will appear over decorations, etc
$docDecorations-zindex: 998; // then doc decorations appear over everything else
$remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right?
$COLLECTION_BORDER_WIDTH: 1;
$MINIMIZED_ICON_SIZE:25;
$MAX_ROW_HEIGHT: 44px;
-:export {
+
+:export {
contextMenuZindex: $contextMenu-zindex;
COLLECTION_BORDER_WIDTH: $COLLECTION_BORDER_WIDTH;
MINIMIZED_ICON_SIZE: $MINIMIZED_ICON_SIZE;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 2c1813482..f7a33466e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -432,6 +432,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
anno.target = targetDoc;
});
}
+ let pdfDoc = await Cast(annotationDoc.pdfDoc, Doc);
+ if (pdfDoc) {
+ DocUtils.MakeLink(annotationDoc, targetDoc, undefined, `Annotation from ${StrCast(pdfDoc.title)}`, "", StrCast(pdfDoc.title));
+ }
}
if (de.data instanceof DragManager.LinkDragData) {
let sourceDoc = de.data.linkSourceDocument;
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 01fd1c247..c560e581c 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -278,6 +278,7 @@ export class Viewer extends React.Component<IViewerProps> {
if (de.data instanceof DragManager.LinkDragData) {
let sourceDoc = de.data.linkSourceDocument;
let destDoc = this.makeAnnotationDocument(sourceDoc, 1, "red");
+ de.data.droppedDocuments.push(destDoc);
let targetAnnotations = DocListCast(this.props.parent.fieldExtensionDoc.annotations);
if (targetAnnotations) {
targetAnnotations.push(destDoc);
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 3d8973414..c9d442fe5 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -176,6 +176,10 @@ export default class Page extends React.Component<IPageProps> {
anno.target = targetDoc;
});
}
+ let pdfDoc = await Cast(annotationDoc.pdfDoc, Doc);
+ if (pdfDoc) {
+ DocUtils.MakeLink(annotationDoc, targetDoc, undefined, `Annotation from ${StrCast(pdfDoc.title)}`, "", StrCast(pdfDoc.title));
+ }
}
}
},
diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx
index 435ca86e3..f11fb008c 100644
--- a/src/client/views/search/FilterBox.tsx
+++ b/src/client/views/search/FilterBox.tsx
@@ -237,6 +237,10 @@ export class FilterBox extends React.Component {
return "+(" + finalColString + ")" + query;
}
+ get filterTypes() {
+ return this._icons.length === 9 ? undefined : this._icons;
+ }
+
@action
filterDocsByType(docs: Doc[]) {
if (this._icons.length === 9) {
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index dc1d35b1c..3830a6d16 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -67,7 +67,7 @@ export class SearchBox extends React.Component {
this._maxSearchIndex = 0;
}
- enter = (e: React.KeyboardEvent) => { if (e.key === "Enter") { this.submitSearch(); } }
+ enter = (e: React.KeyboardEvent) => { if (e.key === "Enter") { this.submitSearch(); } };
public static async convertDataUri(imageUri: string, returnedFilename: string) {
try {
@@ -113,7 +113,12 @@ export class SearchBox extends React.Component {
}
getAllResults = async (query: string) => {
- return SearchUtil.Search(query, true, 0, 10000000);
+ return SearchUtil.Search(query, this.filterQuery, true, 0, 10000000);
+ }
+
+ private get filterQuery() {
+ const types = FilterBox.Instance.filterTypes;
+ return "proto_i:*" + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})` : "");
}
@@ -124,7 +129,7 @@ export class SearchBox extends React.Component {
}
this.lockPromise = new Promise(async res => {
while (this._results.length <= this._endIndex && (this._numTotalResults === -1 || this._maxSearchIndex < this._numTotalResults)) {
- this._curRequest = SearchUtil.Search(query, true, this._maxSearchIndex, 10).then(action((res: SearchUtil.DocSearchResult) => {
+ this._curRequest = SearchUtil.Search(query, this.filterQuery, true, this._maxSearchIndex, 10).then(action((res: SearchUtil.DocSearchResult) => {
// happens at the beginning
if (res.numFound !== this._numTotalResults && this._numTotalResults === -1) {
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 16ad71d16..e34d101a8 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -51,9 +51,9 @@ export class SelectorContextMenu extends React.Component<SearchItemProps> {
async fetchDocuments() {
let aliases = (await SearchUtil.GetViewsOfDocument(this.props.doc)).filter(doc => doc !== this.props.doc);
- const { docs } = await SearchUtil.Search(`data_l:"${this.props.doc[Id]}"`, true);
+ const { docs } = await SearchUtil.Search("", `data_l:"${this.props.doc[Id]}"`, true);
const map: Map<Doc, Doc> = new Map;
- const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search(`data_l:"${doc[Id]}"`, true).then(result => result.docs)));
+ const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search("", `data_l:"${doc[Id]}"`, true).then(result => result.docs)));
allDocs.forEach((docs, index) => docs.forEach(doc => map.set(doc, aliases[index])));
docs.forEach(doc => map.delete(doc));
runInAction(() => {
diff --git a/src/server/Search.ts b/src/server/Search.ts
index 11092c5be..69e327d2d 100644
--- a/src/server/Search.ts
+++ b/src/server/Search.ts
@@ -30,11 +30,12 @@ export class Search {
}
}
- public async search(query: string, start: number = 0, rows: number = 10) {
+ public async search(query: string, filterQuery: string = "", start: number = 0, rows: number = 10) {
try {
const searchResults = JSON.parse(await rp.get(this.url + "dash/select", {
qs: {
q: query,
+ fq: filterQuery,
fl: "id",
start,
rows,
diff --git a/src/server/authentication/controllers/user_controller.ts b/src/server/authentication/controllers/user_controller.ts
index ca4fc171c..fa1cd647d 100644
--- a/src/server/authentication/controllers/user_controller.ts
+++ b/src/server/authentication/controllers/user_controller.ts
@@ -12,6 +12,9 @@ import * as nodemailer from 'nodemailer';
import c = require("crypto");
import { RouteStore } from "../../RouteStore";
import { Utils } from "../../../Utils";
+import { Schema } from "mongoose";
+import { Opt } from "../../../new_fields/Doc";
+import { MailOptions } from "nodemailer/lib/stream-transport";
/**
* GET /signup
@@ -45,21 +48,23 @@ export let postSignup = (req: Request, res: Response, next: NextFunction) => {
return res.redirect(RouteStore.signup);
}
- const email = req.body.email;
+ const email = req.body.email as String;
const password = req.body.password;
- const user = new User({
- email,
+ const model = {
+ email: { type: email, unique: true },
password,
userDocumentId: Utils.GenerateGuid()
- });
+ } as Partial<DashUserModel>;
+
+ const user = new User(model);
User.findOne({ email }, (err, existingUser) => {
if (err) { return next(err); }
if (existingUser) {
return res.redirect(RouteStore.login);
}
- user.save((err) => {
+ user.save((err: any) => {
if (err) { return next(err); }
req.logIn(user, (err) => {
if (err) { return next(err); }
@@ -181,15 +186,15 @@ export let postForgot = function (req: Request, res: Response, next: NextFunctio
}
});
const mailOptions = {
- to: user.email,
+ to: user.email.type,
from: 'brownptcdash@gmail.com',
subject: 'Dash Password Reset',
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
'http://' + req.headers.host + '/reset/' + token + '\n\n' +
'If you did not request this, please ignore this email and your password will remain unchanged.\n'
- };
- smtpTransport.sendMail(mailOptions, function (err) {
+ } as MailOptions;
+ smtpTransport.sendMail(mailOptions, function (err: Error | null) {
// req.flash('info', 'An e-mail has been sent to ' + user.email + ' with further instructions.');
done(null, err, 'done');
});
@@ -254,12 +259,12 @@ export let postReset = function (req: Request, res: Response) {
}
});
const mailOptions = {
- to: user.email,
+ to: user.email.type,
from: 'brownptcdash@gmail.com',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +
'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n'
- };
+ } as MailOptions;
smtpTransport.sendMail(mailOptions, function (err) {
done(null, err);
});
diff --git a/src/server/authentication/models/user_model.ts b/src/server/authentication/models/user_model.ts
index ee85e1c05..fb62de1c8 100644
--- a/src/server/authentication/models/user_model.ts
+++ b/src/server/authentication/models/user_model.ts
@@ -16,7 +16,7 @@ mongoose.connection.on('disconnected', function () {
console.log('connection closed');
});
export type DashUserModel = mongoose.Document & {
- email: string,
+ email: { type: String, unique: true },
password: string,
passwordResetToken?: string,
passwordResetExpires?: Date,
diff --git a/src/server/index.ts b/src/server/index.ts
index 58af074aa..06f8358e1 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -58,7 +58,7 @@ clientUtils = `//AUTO-GENERATED FILE: DO NOT EDIT\n${clientUtils.replace('"mode"
fs.writeFileSync("./src/client/util/ClientUtils.ts", clientUtils, "utf8");
const mongoUrl = 'mongodb://localhost:27017/Dash';
-mongoose.connect(mongoUrl);
+mongoose.connection.readyState === 0 && mongoose.connect(mongoUrl);
mongoose.connection.on('connected', () => console.log("connected"));
// SESSION MANAGEMENT AND AUTHENTICATION MIDDLEWARE
@@ -144,12 +144,12 @@ app.get("/pull", (req, res) =>
// GETTERS
app.get("/search", async (req, res) => {
- const { query, start, rows } = req.query;
+ const { query, filterQuery, start, rows } = req.query;
if (query === undefined) {
res.send([]);
return;
}
- let results = await Search.Instance.search(query, start, rows);
+ let results = await Search.Instance.search(query, filterQuery, start, rows);
res.send(results);
});