aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/ApiManagers/ApiManager.ts2
-rw-r--r--src/server/ApiManagers/DeleteManager.ts87
-rw-r--r--src/server/ApiManagers/GeneralGoogleManager.ts19
-rw-r--r--src/server/ApiManagers/GooglePhotosManager.ts4
-rw-r--r--src/server/ApiManagers/SessionManager.ts2
-rw-r--r--src/server/ApiManagers/UploadManager.ts2
-rw-r--r--src/server/ApiManagers/UserManager.ts4
-rw-r--r--src/server/DashSession/DashSessionAgent.ts4
-rw-r--r--src/server/DashUploadUtils.ts2
-rw-r--r--src/server/GarbageCollector.ts6
-rw-r--r--src/server/IDatabase.ts4
-rw-r--r--src/server/MemoryDatabase.ts23
-rw-r--r--src/server/Message.ts2
-rw-r--r--src/server/Recommender.ts6
-rw-r--r--src/server/RouteManager.ts2
-rw-r--r--src/server/apis/google/CredentialsLoader.ts (renamed from src/server/credentials/CredentialsLoader.ts)0
-rw-r--r--src/server/apis/google/GoogleApiServerUtils.ts57
-rw-r--r--src/server/apis/google/google_project_credentials.json (renamed from src/server/credentials/google_project_credentials.json)0
-rw-r--r--src/server/apis/youtube/youtubeApiSample.js22
-rw-r--r--src/server/authentication/AuthenticationManager.ts (renamed from src/server/authentication/controllers/user_controller.ts)8
-rw-r--r--src/server/authentication/DashUserModel.ts (renamed from src/server/authentication/models/user_model.ts)8
-rw-r--r--src/server/authentication/Passport.ts (renamed from src/server/authentication/config/passport.ts)2
-rw-r--r--src/server/authentication/models/current_user_utils.ts691
-rw-r--r--src/server/database.ts188
-rw-r--r--src/server/index.ts7
-rw-r--r--src/server/remapUrl.ts4
-rw-r--r--src/server/server_Initialization.ts4
-rw-r--r--src/server/websocket.ts (renamed from src/server/Websocket/Websocket.ts)67
28 files changed, 267 insertions, 960 deletions
diff --git a/src/server/ApiManagers/ApiManager.ts b/src/server/ApiManagers/ApiManager.ts
index e2b01d585..27e9de065 100644
--- a/src/server/ApiManagers/ApiManager.ts
+++ b/src/server/ApiManagers/ApiManager.ts
@@ -1,4 +1,4 @@
-import RouteManager, { RouteInitializer } from "../RouteManager";
+import { RouteInitializer } from "../RouteManager";
export type Registration = (initializer: RouteInitializer) => void;
diff --git a/src/server/ApiManagers/DeleteManager.ts b/src/server/ApiManagers/DeleteManager.ts
index 9e70af2eb..7fbb37658 100644
--- a/src/server/ApiManagers/DeleteManager.ts
+++ b/src/server/ApiManagers/DeleteManager.ts
@@ -1,12 +1,12 @@
import ApiManager, { Registration } from "./ApiManager";
-import { Method, _permission_denied, PublicHandler } from "../RouteManager";
-import { WebSocket } from "../Websocket/Websocket";
+import { Method, _permission_denied } from "../RouteManager";
+import { WebSocket } from "../websocket";
import { Database } from "../database";
import rimraf = require("rimraf");
-import { pathToDirectory, Directory } from "./UploadManager";
import { filesDirectory } from "..";
import { DashUploadUtils } from "../DashUploadUtils";
import { mkdirSync } from "fs";
+import RouteSubscriber from "../RouteSubscriber";
export default class DeleteManager extends ApiManager {
@@ -14,68 +14,39 @@ export default class DeleteManager extends ApiManager {
register({
method: Method.GET,
- subscription: "/delete",
- secureHandler: async ({ res, isRelease }) => {
+ subscription: new RouteSubscriber("delete").add("target?"),
+ secureHandler: async ({ req, res, isRelease }) => {
if (isRelease) {
- return _permission_denied(res, deletionPermissionError);
+ return _permission_denied(res, "Cannot perform a delete operation outside of the development environment!");
}
- await WebSocket.deleteFields();
- res.redirect("/home");
- }
- });
- register({
- method: Method.GET,
- subscription: "/deleteAll",
- secureHandler: async ({ res, isRelease }) => {
- if (isRelease) {
- return _permission_denied(res, deletionPermissionError);
+ const { target } = req.params;
+ const { doDelete } = WebSocket;
+
+ if (!target) {
+ await doDelete();
+ } else {
+ let all = false;
+ switch (target) {
+ case "all":
+ all = true;
+ case "database":
+ await doDelete(false);
+ if (!all) break;
+ case "files":
+ rimraf.sync(filesDirectory);
+ mkdirSync(filesDirectory);
+ await DashUploadUtils.buildFileDirectories();
+ break;
+ default:
+ await Database.Instance.dropSchema(target);
+ }
}
- await WebSocket.deleteAll();
- res.redirect("/home");
- }
- });
- register({
- method: Method.GET,
- subscription: "/deleteAssets",
- secureHandler: async ({ res, isRelease }) => {
- if (isRelease) {
- return _permission_denied(res, deletionPermissionError);
- }
- rimraf.sync(filesDirectory);
- mkdirSync(filesDirectory);
- await DashUploadUtils.buildFileDirectories();
- res.redirect("/delete");
- }
- });
-
- register({
- method: Method.GET,
- subscription: "/deleteWithAux",
- secureHandler: async ({ res, isRelease }) => {
- if (isRelease) {
- return _permission_denied(res, deletionPermissionError);
- }
- await Database.Auxiliary.DeleteAll();
- res.redirect("/delete");
- }
- });
-
- register({
- method: Method.GET,
- subscription: "/deleteWithGoogleCredentials",
- secureHandler: async ({ res, isRelease }) => {
- if (isRelease) {
- return _permission_denied(res, deletionPermissionError);
- }
- await Database.Auxiliary.GoogleAuthenticationToken.DeleteAll();
- res.redirect("/delete");
+ res.redirect("/home");
}
});
}
-}
-
-const deletionPermissionError = "Cannot perform a delete operation outside of the development environment!";
+} \ No newline at end of file
diff --git a/src/server/ApiManagers/GeneralGoogleManager.ts b/src/server/ApiManagers/GeneralGoogleManager.ts
index a5240edbc..f94b77cac 100644
--- a/src/server/ApiManagers/GeneralGoogleManager.ts
+++ b/src/server/ApiManagers/GeneralGoogleManager.ts
@@ -1,10 +1,8 @@
import ApiManager, { Registration } from "./ApiManager";
import { Method, _permission_denied } from "../RouteManager";
import { GoogleApiServerUtils } from "../apis/google/GoogleApiServerUtils";
-import { Database } from "../database";
import RouteSubscriber from "../RouteSubscriber";
-
-const deletionPermissionError = "Cannot perform specialized delete outside of the development environment!";
+import { Database } from "../database";
const EndpointHandlerMap = new Map<GoogleApiServerUtils.Action, GoogleApiServerUtils.ApiRouter>([
["create", (api, params) => api.create(params)],
@@ -20,11 +18,11 @@ export default class GeneralGoogleManager extends ApiManager {
method: Method.GET,
subscription: "/readGoogleAccessToken",
secureHandler: async ({ user, res }) => {
- const token = await GoogleApiServerUtils.retrieveAccessToken(user.id);
- if (!token) {
+ const { credentials } = (await GoogleApiServerUtils.retrieveCredentials(user.id));
+ if (!credentials?.access_token) {
return res.send(GoogleApiServerUtils.generateAuthenticationUrl());
}
- return res.send(token);
+ return res.send(credentials);
}
});
@@ -37,6 +35,15 @@ export default class GeneralGoogleManager extends ApiManager {
});
register({
+ method: Method.GET,
+ subscription: "/revokeGoogleAccessToken",
+ secureHandler: async ({ user, res }) => {
+ await Database.Auxiliary.GoogleAccessToken.Revoke(user.id);
+ res.send();
+ }
+ });
+
+ register({
method: Method.POST,
subscription: new RouteSubscriber("googleDocs").add("sector", "action"),
secureHandler: async ({ req, res, user }) => {
diff --git a/src/server/ApiManagers/GooglePhotosManager.ts b/src/server/ApiManagers/GooglePhotosManager.ts
index 88219423d..be17b698e 100644
--- a/src/server/ApiManagers/GooglePhotosManager.ts
+++ b/src/server/ApiManagers/GooglePhotosManager.ts
@@ -3,7 +3,7 @@ import { Method, _error, _success, _invalid } from "../RouteManager";
import * as path from "path";
import { GoogleApiServerUtils } from "../apis/google/GoogleApiServerUtils";
import { BatchedArray, TimeUnit } from "array-batcher";
-import { Opt } from "../../new_fields/Doc";
+import { Opt } from "../../fields/Doc";
import { DashUploadUtils, InjectSize, SizeSuffix } from "../DashUploadUtils";
import { Database } from "../database";
import { red } from "colors";
@@ -56,7 +56,7 @@ export default class GooglePhotosManager extends ApiManager {
const { media } = req.body;
// first we need to ensure that we know the google account to which these photos will be uploaded
- const token = await GoogleApiServerUtils.retrieveAccessToken(user.id);
+ const token = (await GoogleApiServerUtils.retrieveCredentials(user.id))?.credentials?.access_token;
if (!token) {
return _error(res, authenticationError);
}
diff --git a/src/server/ApiManagers/SessionManager.ts b/src/server/ApiManagers/SessionManager.ts
index bcaa6598f..fa2f6002a 100644
--- a/src/server/ApiManagers/SessionManager.ts
+++ b/src/server/ApiManagers/SessionManager.ts
@@ -55,7 +55,7 @@ export default class SessionManager extends ApiManager {
register({
method: Method.GET,
- subscription: this.secureSubscriber("delete"),
+ subscription: this.secureSubscriber("deleteSession"),
secureHandler: this.authorizedAction(async ({ res }) => {
const { error } = await sessionAgent.serverWorker.emit("delete");
res.send(error ? error.message : "Your request was successful: the server successfully deleted the database. Return to /home.");
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index 98f029c7d..b185d3b55 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -171,7 +171,7 @@ export default class UploadManager extends ApiManager {
await Promise.all(docs.map((doc: any) => new Promise(res => Database.Instance.replace(doc.id, doc, (err, r) => {
err && console.log(err);
res();
- }, true, "newDocuments"))));
+ }, true))));
} catch (e) { console.log(e); }
unlink(path_2, () => { });
}
diff --git a/src/server/ApiManagers/UserManager.ts b/src/server/ApiManagers/UserManager.ts
index d9d346cc1..0d1d8f218 100644
--- a/src/server/ApiManagers/UserManager.ts
+++ b/src/server/ApiManagers/UserManager.ts
@@ -3,7 +3,7 @@ import { Method } from "../RouteManager";
import { Database } from "../database";
import { msToTime } from "../ActionUtilities";
import * as bcrypt from "bcrypt-nodejs";
-import { Opt } from "../../new_fields/Doc";
+import { Opt } from "../../fields/Doc";
export const timeMap: { [id: string]: number } = {};
interface ActivityUnit {
@@ -89,8 +89,6 @@ export default class UserManager extends ApiManager {
}
});
-
-
register({
method: Method.GET,
subscription: "/activity",
diff --git a/src/server/DashSession/DashSessionAgent.ts b/src/server/DashSession/DashSessionAgent.ts
index 5cbba13de..ab3dfffcc 100644
--- a/src/server/DashSession/DashSessionAgent.ts
+++ b/src/server/DashSession/DashSessionAgent.ts
@@ -2,7 +2,7 @@ import { Email, pathFromRoot } from "../ActionUtilities";
import { red, yellow, green, cyan } from "colors";
import { get } from "request-promise";
import { Utils } from "../../Utils";
-import { WebSocket } from "../Websocket/Websocket";
+import { WebSocket } from "../websocket";
import { MessageStore } from "../Message";
import { launchServer, onWindows } from "..";
import { readdirSync, statSync, createWriteStream, readFileSync, unlinkSync } from "fs";
@@ -37,7 +37,7 @@ export class DashSessionAgent extends AppliedSessionAgent {
monitor.addReplCommand("debug", [/\S+\@\S+/], async ([to]) => this.dispatchZippedDebugBackup(to));
monitor.on("backup", this.backup);
monitor.on("debug", async ({ to }) => this.dispatchZippedDebugBackup(to));
- monitor.on("delete", WebSocket.deleteFields);
+ monitor.on("delete", WebSocket.doDelete);
monitor.coreHooks.onCrashDetected(this.dispatchCrashReport);
return sessionKey;
}
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 8567631cd..b74904ada 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -4,7 +4,7 @@ import * as path from 'path';
import * as sharp from 'sharp';
import request = require('request-promise');
import { ExifImage } from 'exif';
-import { Opt } from '../new_fields/Doc';
+import { Opt } from '../fields/Doc';
import { AcceptibleMedia, Upload } from './SharedMediaTypes';
import { filesDirectory, publicDirectory } from '.';
import { File } from 'formidable';
diff --git a/src/server/GarbageCollector.ts b/src/server/GarbageCollector.ts
index 5729c3ee5..24745cbb4 100644
--- a/src/server/GarbageCollector.ts
+++ b/src/server/GarbageCollector.ts
@@ -76,7 +76,7 @@ async function GarbageCollect(full: boolean = true) {
if (!fetchIds.length) {
continue;
}
- const docs = await new Promise<{ [key: string]: any }[]>(res => Database.Instance.getDocuments(fetchIds, res, "newDocuments"));
+ const docs = await new Promise<{ [key: string]: any }[]>(res => Database.Instance.getDocuments(fetchIds, res));
for (const doc of docs) {
const id = doc.id;
if (doc === undefined) {
@@ -116,10 +116,10 @@ async function GarbageCollect(full: boolean = true) {
const count = Math.min(toDelete.length, 5000);
const toDeleteDocs = toDelete.slice(i, i + count);
i += count;
- const result = await Database.Instance.delete({ _id: { $in: toDeleteDocs } }, "newDocuments");
+ const result = await Database.Instance.delete({ _id: { $in: toDeleteDocs } });
deleted += result.deletedCount || 0;
}
- // const result = await Database.Instance.delete({ _id: { $in: toDelete } }, "newDocuments");
+ // const result = await Database.Instance.delete({ _id: { $in: toDelete } });
console.log(`${deleted} documents deleted`);
await Search.deleteDocuments(toDelete);
diff --git a/src/server/IDatabase.ts b/src/server/IDatabase.ts
index 6a63df485..dd4968579 100644
--- a/src/server/IDatabase.ts
+++ b/src/server/IDatabase.ts
@@ -2,7 +2,6 @@ import * as mongodb from 'mongodb';
import { Transferable } from './Message';
export const DocumentsCollection = 'documents';
-export const NewDocumentsCollection = 'newDocuments';
export interface IDatabase {
update(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, upsert?: boolean, collectionName?: string): Promise<void>;
updateMany(query: any, update: any, collectionName?: string): Promise<mongodb.WriteOpResult>;
@@ -12,12 +11,13 @@ export interface IDatabase {
delete(query: any, collectionName?: string): Promise<mongodb.DeleteWriteOpResultObject>;
delete(id: string, collectionName?: string): Promise<mongodb.DeleteWriteOpResultObject>;
- deleteAll(collectionName?: string, persist?: boolean): Promise<any>;
+ dropSchema(...schemaNames: string[]): Promise<any>;
insert(value: any, collectionName?: string): Promise<void>;
getDocument(id: string, fn: (result?: Transferable) => void, collectionName?: string): void;
getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName?: string): void;
+ getCollectionNames(): Promise<string[]>;
visit(ids: string[], fn: (result: any) => string[] | Promise<string[]>, collectionName?: string): Promise<void>;
query(query: { [key: string]: any }, projection?: { [key: string]: 0 | 1 }, collectionName?: string): Promise<mongodb.Cursor>;
diff --git a/src/server/MemoryDatabase.ts b/src/server/MemoryDatabase.ts
index 543f96e7f..1f1d702d9 100644
--- a/src/server/MemoryDatabase.ts
+++ b/src/server/MemoryDatabase.ts
@@ -1,4 +1,4 @@
-import { IDatabase, DocumentsCollection, NewDocumentsCollection } from './IDatabase';
+import { IDatabase, DocumentsCollection } from './IDatabase';
import { Transferable } from './Message';
import * as mongodb from 'mongodb';
@@ -15,6 +15,10 @@ export class MemoryDatabase implements IDatabase {
}
}
+ public getCollectionNames() {
+ return Promise.resolve(Object.keys(this.db));
+ }
+
public update(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, _upsert?: boolean, collectionName = DocumentsCollection): Promise<void> {
const collection = this.getCollection(collectionName);
const set = "$set";
@@ -41,7 +45,7 @@ export class MemoryDatabase implements IDatabase {
return Promise.resolve(undefined);
}
- public updateMany(query: any, update: any, collectionName = NewDocumentsCollection): Promise<mongodb.WriteOpResult> {
+ public updateMany(query: any, update: any, collectionName = DocumentsCollection): Promise<mongodb.WriteOpResult> {
throw new Error("Can't updateMany a MemoryDatabase");
}
@@ -58,8 +62,15 @@ export class MemoryDatabase implements IDatabase {
return Promise.resolve({} as any);
}
- public deleteAll(collectionName = DocumentsCollection, _persist = true): Promise<any> {
- delete this.db[collectionName];
+ public async dropSchema(...schemaNames: string[]): Promise<any> {
+ const existing = await this.getCollectionNames();
+ let valid: string[];
+ if (schemaNames.length) {
+ valid = schemaNames.filter(collection => existing.includes(collection));
+ } else {
+ valid = existing;
+ }
+ valid.forEach(schemaName => delete this.db[schemaName]);
return Promise.resolve();
}
@@ -69,14 +80,14 @@ export class MemoryDatabase implements IDatabase {
return Promise.resolve();
}
- public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = NewDocumentsCollection): void {
+ public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = DocumentsCollection): void {
fn(this.getCollection(collectionName)[id]);
}
public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = DocumentsCollection): void {
fn(ids.map(id => this.getCollection(collectionName)[id]));
}
- public async visit(ids: string[], fn: (result: any) => string[] | Promise<string[]>, collectionName = NewDocumentsCollection): Promise<void> {
+ public async visit(ids: string[], fn: (result: any) => string[] | Promise<string[]>, collectionName = DocumentsCollection): Promise<void> {
const visited = new Set<string>();
while (ids.length) {
const count = Math.min(ids.length, 1000);
diff --git a/src/server/Message.ts b/src/server/Message.ts
index 01aae5de7..80f372733 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -1,6 +1,6 @@
import { Utils } from "../Utils";
import { Point } from "../pen-gestures/ndollar";
-import { Doc } from "../new_fields/Doc";
+import { Doc } from "../fields/Doc";
import { Image } from "canvas";
import { AnalysisResult, ImportResults } from "../scraping/buxton/final/BuxtonImporter";
diff --git a/src/server/Recommender.ts b/src/server/Recommender.ts
index aacdb4053..423ce9b46 100644
--- a/src/server/Recommender.ts
+++ b/src/server/Recommender.ts
@@ -1,6 +1,6 @@
-// //import { Doc } from "../new_fields/Doc";
-// //import { StrCast } from "../new_fields/Types";
-// //import { List } from "../new_fields/List";
+// //import { Doc } from "../fields/Doc";
+// //import { StrCast } from "../fields/Types";
+// //import { List } from "../fields/List";
// //import { CognitiveServices } from "../client/cognitive_services/CognitiveServices";
// // var w2v = require('word2vec');
diff --git a/src/server/RouteManager.ts b/src/server/RouteManager.ts
index 80e4a6741..b23215996 100644
--- a/src/server/RouteManager.ts
+++ b/src/server/RouteManager.ts
@@ -1,5 +1,5 @@
import RouteSubscriber from "./RouteSubscriber";
-import { DashUserModel } from "./authentication/models/user_model";
+import { DashUserModel } from "./authentication/DashUserModel";
import { Request, Response, Express } from 'express';
import { cyan, red, green } from 'colors';
diff --git a/src/server/credentials/CredentialsLoader.ts b/src/server/apis/google/CredentialsLoader.ts
index e3f4d167b..e3f4d167b 100644
--- a/src/server/credentials/CredentialsLoader.ts
+++ b/src/server/apis/google/CredentialsLoader.ts
diff --git a/src/server/apis/google/GoogleApiServerUtils.ts b/src/server/apis/google/GoogleApiServerUtils.ts
index 0f75833ee..20f96f432 100644
--- a/src/server/apis/google/GoogleApiServerUtils.ts
+++ b/src/server/apis/google/GoogleApiServerUtils.ts
@@ -1,11 +1,11 @@
import { google } from "googleapis";
import { OAuth2Client, Credentials, OAuth2ClientOptions } from "google-auth-library";
-import { Opt } from "../../../new_fields/Doc";
+import { Opt } from "../../../fields/Doc";
import { GaxiosResponse } from "gaxios";
import request = require('request-promise');
-import * as qs from 'query-string';
+import * as qs from "query-string";
import { Database } from "../../database";
-import { GoogleCredentialsLoader } from "../../credentials/CredentialsLoader";
+import { GoogleCredentialsLoader } from "./CredentialsLoader";
/**
* Scopes give Google users fine granularity of control
@@ -149,26 +149,6 @@ export namespace GoogleApiServerUtils {
}
/**
- * Returns the lengthy string or access token that can be passed into
- * the headers of an API request or into the constructor of the Photos
- * client API wrapper.
- * @param userId the Dash user id of the user requesting his/her associated
- * access_token
- * @returns the current access_token associated with the requesting
- * Dash user. The access_token is valid for only an hour, and
- * is then refreshed.
- */
- export async function retrieveAccessToken(userId: string): Promise<string> {
- return new Promise(async resolve => {
- const { credentials } = await retrieveCredentials(userId);
- if (!credentials) {
- return resolve();
- }
- resolve(credentials.access_token!);
- });
- }
-
- /**
* Manipulates a mapping such that, in the limit, each Dash user has
* an associated authenticated OAuth2 client at their disposal. This
* function ensures that the client's credentials always remain up to date
@@ -217,18 +197,6 @@ export namespace GoogleApiServerUtils {
}
/**
- * This is what we return to the server in processNewUser(), after the
- * worker OAuth2Client has used the user-pasted authentication code
- * to retrieve an access token and an info token. The avatar is the
- * URL to the Google-hosted mono-color, single white letter profile 'image'.
- */
- export interface GoogleAuthenticationResult {
- access_token: string;
- avatar: string;
- name: string;
- }
-
- /**
* This method receives the authentication code that the
* user pasted into the overlay in the client side and uses the worker
* and the authentication code to fetch the full set of credentials that
@@ -245,7 +213,7 @@ export namespace GoogleApiServerUtils {
* and display basic user information in the overlay on successful authentication.
* This can be expanded as needed by adding properties to the interface GoogleAuthenticationResult.
*/
- export async function processNewUser(userId: string, authenticationCode: string): Promise<GoogleAuthenticationResult> {
+ export async function processNewUser(userId: string, authenticationCode: string): Promise<EnrichedCredentials> {
const credentials = await new Promise<Credentials>((resolve, reject) => {
worker.getToken(authenticationCode, async (err, credentials) => {
if (err || !credentials) {
@@ -256,13 +224,8 @@ export namespace GoogleApiServerUtils {
});
});
const enriched = injectUserInfo(credentials);
- await Database.Auxiliary.GoogleAuthenticationToken.Write(userId, enriched);
- const { given_name, picture } = enriched.userInfo;
- return {
- access_token: enriched.access_token!,
- avatar: picture,
- name: given_name
- };
+ await Database.Auxiliary.GoogleAccessToken.Write(userId, enriched);
+ return enriched;
}
/**
@@ -316,15 +279,15 @@ export namespace GoogleApiServerUtils {
* @returns the credentials, or undefined if the user has no stored associated credentials,
* and a flag indicating whether or not they were refreshed during retrieval
*/
- async function retrieveCredentials(userId: string): Promise<{ credentials: Opt<Credentials>, refreshed: boolean }> {
- let credentials: Opt<Credentials> = await Database.Auxiliary.GoogleAuthenticationToken.Fetch(userId);
+ export async function retrieveCredentials(userId: string): Promise<{ credentials: Opt<EnrichedCredentials>, refreshed: boolean }> {
+ let credentials = await Database.Auxiliary.GoogleAccessToken.Fetch(userId);
let refreshed = false;
if (!credentials) {
return { credentials: undefined, refreshed };
}
// check for token expiry
if (credentials.expiry_date! <= new Date().getTime()) {
- credentials = await refreshAccessToken(credentials, userId);
+ credentials = { ...credentials, ...(await refreshAccessToken(credentials, userId)) };
refreshed = true;
}
return { credentials, refreshed };
@@ -355,7 +318,7 @@ export namespace GoogleApiServerUtils {
});
// expires_in is in seconds, but we're building the new expiry date in milliseconds
const expiry_date = new Date().getTime() + (expires_in * 1000);
- await Database.Auxiliary.GoogleAuthenticationToken.Update(userId, access_token, expiry_date);
+ await Database.Auxiliary.GoogleAccessToken.Update(userId, access_token, expiry_date);
// update the relevant properties
credentials.access_token = access_token;
credentials.expiry_date = expiry_date;
diff --git a/src/server/credentials/google_project_credentials.json b/src/server/apis/google/google_project_credentials.json
index 955c5a3c1..955c5a3c1 100644
--- a/src/server/credentials/google_project_credentials.json
+++ b/src/server/apis/google/google_project_credentials.json
diff --git a/src/server/apis/youtube/youtubeApiSample.js b/src/server/apis/youtube/youtubeApiSample.js
index 50b3c7b38..d535bd9ff 100644
--- a/src/server/apis/youtube/youtubeApiSample.js
+++ b/src/server/apis/youtube/youtubeApiSample.js
@@ -1,6 +1,8 @@
const fs = require('fs');
const readline = require('readline');
-const { google } = require('googleapis');
+const {
+ google
+} = require('googleapis');
const OAuth2 = google.auth.OAuth2;
@@ -19,21 +21,27 @@ module.exports.readApiKey = (callback) => {
}
callback(content);
});
-}
+};
module.exports.authorizedGetChannel = (apiKey) => {
//this didnt get called
// Authorize a client with the loaded credentials, then call the YouTube API.
authorize(JSON.parse(apiKey), getChannel);
-}
+};
module.exports.authorizedGetVideos = (apiKey, userInput, callBack) => {
- authorize(JSON.parse(apiKey), getVideos, { userInput: userInput, callBack: callBack });
-}
+ authorize(JSON.parse(apiKey), getVideos, {
+ userInput: userInput,
+ callBack: callBack
+ });
+};
module.exports.authorizedGetVideoDetails = (apiKey, videoIds, callBack) => {
- authorize(JSON.parse(apiKey), getVideoDetails, { videoIds: videoIds, callBack: callBack });
-}
+ authorize(JSON.parse(apiKey), getVideoDetails, {
+ videoIds: videoIds,
+ callBack: callBack
+ });
+};
/**
diff --git a/src/server/authentication/controllers/user_controller.ts b/src/server/authentication/AuthenticationManager.ts
index f0086d4ea..00f1fe44e 100644
--- a/src/server/authentication/controllers/user_controller.ts
+++ b/src/server/authentication/AuthenticationManager.ts
@@ -1,13 +1,13 @@
-import { default as User, DashUserModel, AuthToken } from "../models/user_model";
+import { default as User, DashUserModel } from "./DashUserModel";
import { Request, Response, NextFunction } from "express";
import * as passport from "passport";
import { IVerifyOptions } from "passport-local";
-import "../config/passport";
+import "./Passport";
import flash = require("express-flash");
import * as async from 'async';
import * as nodemailer from 'nodemailer';
import c = require("crypto");
-import { Utils } from "../../../Utils";
+import { Utils } from "../../Utils";
import { MailOptions } from "nodemailer/lib/stream-transport";
/**
@@ -111,7 +111,7 @@ export let postLogin = (req: Request, res: Response, next: NextFunction) => {
return res.redirect("/signup");
}
- passport.authenticate("local", (err: Error, user: DashUserModel, info: IVerifyOptions) => {
+ passport.authenticate("local", (err: Error, user: DashUserModel, _info: IVerifyOptions) => {
if (err) { next(err); return; }
if (!user) {
return res.redirect("/signup");
diff --git a/src/server/authentication/models/user_model.ts b/src/server/authentication/DashUserModel.ts
index 78e39dbc1..51d920a8f 100644
--- a/src/server/authentication/models/user_model.ts
+++ b/src/server/authentication/DashUserModel.ts
@@ -58,11 +58,11 @@ userSchema.pre("save", function save(next) {
if (!user.isModified("password")) {
return next();
}
- bcrypt.genSalt(10, (err, salt) => {
+ bcrypt.genSalt(10, (err: any, salt: string) => {
if (err) {
return next(err);
}
- bcrypt.hash(user.password, salt, () => void {}, (err: mongoose.Error, hash) => {
+ bcrypt.hash(user.password, salt, () => void {}, (err: mongoose.Error, hash: string) => {
if (err) {
return next(err);
}
@@ -74,9 +74,9 @@ userSchema.pre("save", function save(next) {
const comparePassword: comparePasswordFunction = function (this: DashUserModel, candidatePassword, cb) {
// Choose one of the following bodies for authentication logic.
- // secure
+ // secure (expected, default)
bcrypt.compare(candidatePassword, this.password, cb);
- // bypass password
+ // bypass password (debugging)
// cb(undefined, true);
};
diff --git a/src/server/authentication/config/passport.ts b/src/server/authentication/Passport.ts
index 286209b20..9b0069414 100644
--- a/src/server/authentication/config/passport.ts
+++ b/src/server/authentication/Passport.ts
@@ -1,6 +1,6 @@
import * as passport from 'passport';
import * as passportLocal from 'passport-local';
-import { default as User } from '../models/user_model';
+import { default as User } from './DashUserModel';
const LocalStrategy = passportLocal.Strategy;
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
deleted file mode 100644
index bf99f449f..000000000
--- a/src/server/authentication/models/current_user_utils.ts
+++ /dev/null
@@ -1,691 +0,0 @@
-import { action, computed, observable, reaction } from "mobx";
-import * as rp from 'request-promise';
-import { Utils } from "../../../Utils";
-import { DocServer } from "../../../client/DocServer";
-import { Docs, DocumentOptions } from "../../../client/documents/Documents";
-import { UndoManager } from "../../../client/util/UndoManager";
-import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc";
-import { List } from "../../../new_fields/List";
-import { listSpec } from "../../../new_fields/Schema";
-import { ScriptField, ComputedField } from "../../../new_fields/ScriptField";
-import { Cast, PromiseValue, StrCast, NumCast } from "../../../new_fields/Types";
-import { nullAudio, ImageField } from "../../../new_fields/URLField";
-import { DragManager } from "../../../client/util/DragManager";
-import { InkingControl } from "../../../client/views/InkingControl";
-import { Scripting, CompileScript } from "../../../client/util/Scripting";
-import { CollectionViewType } from "../../../client/views/collections/CollectionView";
-import { makeTemplate } from "../../../client/util/DropConverter";
-import { RichTextField } from "../../../new_fields/RichTextField";
-import { PrefetchProxy } from "../../../new_fields/Proxy";
-import { FormattedTextBox } from "../../../client/views/nodes/formattedText/FormattedTextBox";
-import { MainView } from "../../../client/views/MainView";
-import { DocumentType } from "../../../client/documents/DocumentTypes";
-import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
-
-export class CurrentUserUtils {
- private static curr_id: string;
- //TODO tfs: these should be temporary...
- private static mainDocId: string | undefined;
-
- public static get id() { return this.curr_id; }
- public static get MainDocId() { return this.mainDocId; }
- public static set MainDocId(id: string | undefined) { this.mainDocId = id; }
- @computed public static get UserDocument() { return Doc.UserDoc(); }
- @computed public static get ActivePen() { return Doc.UserDoc().activePen instanceof Doc && (Doc.UserDoc().activePen as Doc).inkPen as Doc; }
-
- @observable public static GuestTarget: Doc | undefined;
- @observable public static GuestWorkspace: Doc | undefined;
- @observable public static GuestMobile: Doc | undefined;
-
- // sets up the default User Templates - slideView, queryView, descriptionView
- static setupUserTemplateButtons(doc: Doc) {
- if (doc["template-button-query"] === undefined) {
- const queryTemplate = Docs.Create.MulticolumnDocument(
- [
- Docs.Create.QueryDocument({ title: "query", _height: 200 }),
- Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true })
- ],
- { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true }
- );
- queryTemplate.isTemplateDoc = makeTemplate(queryTemplate);
- doc["template-button-query"] = CurrentUserUtils.ficon({
- onDragStart: ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)'),
- dragFactory: new PrefetchProxy(queryTemplate) as any as Doc,
- removeDropProperties: new List<string>(["dropAction"]), title: "query view", icon: "question-circle"
- });
- }
-
- if (doc["template-button-slides"] === undefined) {
- const slideTemplate = Docs.Create.MultirowDocument(
- [
- Docs.Create.MulticolumnDocument([], { title: "data", _height: 200 }),
- Docs.Create.TextDocument("", { title: "text", _height: 100 })
- ],
- { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true }
- );
- slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
- doc["template-button-slides"] = CurrentUserUtils.ficon({
- onDragStart: ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)'),
- dragFactory: new PrefetchProxy(slideTemplate) as any as Doc,
- removeDropProperties: new List<string>(["dropAction"]), title: "presentation slide", icon: "address-card"
- });
- }
-
- if (doc["template-button-description"] === undefined) {
- const descriptionTemplate = Docs.Create.TextDocument(" ", { title: "header", _height: 100 }, "header"); // text needs to be a space to allow templateText to be created
- Doc.GetProto(descriptionTemplate).layout =
- "<div><FormattedTextBox {...props} height='{this._headerHeight||75}px' background='{this._headerColor||`orange`}' fieldKey={'header'}/>" +
- "<FormattedTextBox {...props} height='calc(100% - {this._headerHeight||75}px)' fieldKey={'text'}/></div>";
- descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView");
-
- doc["template-button-description"] = CurrentUserUtils.ficon({
- onDragStart: ScriptField.MakeFunction('makeDelegate(this.dragFactory)'),
- dragFactory: new PrefetchProxy(descriptionTemplate) as any as Doc,
- removeDropProperties: new List<string>(["dropAction"]), title: "description view", icon: "window-maximize"
- });
- }
-
- if (doc["template-button-detail"] === undefined) {
- const { TextDocument, MasonryDocument, CarouselDocument } = Docs.Create;
-
- const openInTarget = ScriptField.MakeScript("openOnRight(self.doubleClickView)");
- const carousel = CarouselDocument([], {
- title: "data", _height: 350, _itemIndex: 0, "_carousel-caption-xMargin": 10, "_carousel-caption-yMargin": 10,
- onChildDoubleClick: openInTarget, backgroundColor: "#9b9b9b3F"
- });
-
- const details = TextDocument("", { title: "details", _height: 350, _autoHeight: true });
- const short = TextDocument("", { title: "shortDescription", treeViewOpen: true, treeViewExpandedView: "layout", _height: 100, _autoHeight: true });
- const long = TextDocument("", { title: "longDescription", treeViewOpen: false, treeViewExpandedView: "layout", _height: 350, _autoHeight: true });
-
- const buxtonFieldKeys = ["year", "originalPrice", "degreesOfFreedom", "company", "attribute", "primaryKey", "secondaryKey", "dimensions"];
- const detailedTemplate = {
- doc: {
- type: "doc", content: buxtonFieldKeys.map(fieldKey => ({
- type: "paragraph",
- content: [{ type: "dashField", attrs: { fieldKey } }]
- }))
- },
- selection: { type: "text", anchor: 1, head: 1 },
- storedMarks: []
- };
- details.text = new RichTextField(JSON.stringify(detailedTemplate), buxtonFieldKeys.join(" "));
-
- const shared = { _chromeStatus: "disabled", _autoHeight: true, _xMargin: 0 };
- const detailViewOpts = { title: "detailView", _width: 300, _fontFamily: "Arial", _fontSize: 12 };
- const descriptionWrapperOpts = { title: "descriptions", _height: 300, columnWidth: -1, treeViewHideTitle: true, _pivotField: "title" };
-
- const descriptionWrapper = MasonryDocument([details, short, long], { ...shared, ...descriptionWrapperOpts });
- descriptionWrapper.sectionHeaders = new List<SchemaHeaderField>([
- new SchemaHeaderField("[A Short Description]", "dimGray", undefined, undefined, undefined, false),
- new SchemaHeaderField("[Long Description]", "dimGray", undefined, undefined, undefined, true),
- new SchemaHeaderField("[Details]", "dimGray", undefined, undefined, undefined, true),
- ]);
- const detailView = Docs.Create.StackingDocument([carousel, descriptionWrapper], { ...shared, ...detailViewOpts });
- detailView.isTemplateDoc = makeTemplate(detailView);
-
- details.title = "Details";
- short.title = "A Short Description";
- long.title = "Long Description";
-
- doc["template-button-detail"] = CurrentUserUtils.ficon({
- onDragStart: ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)'),
- dragFactory: new PrefetchProxy(detailView) as any as Doc,
- removeDropProperties: new List<string>(["dropAction"]), title: "detail view", icon: "window-maximize"
- });
- }
-
- if (doc["template-buttons"] === undefined) {
- doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument([doc["template-button-slides"] as Doc, doc["template-button-description"] as Doc,
- doc["template-button-query"] as Doc, doc["template-button-detail"] as Doc], {
- title: "Document Prototypes", _xMargin: 0, _showTitle: "title",
- _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled",
- dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
- }));
- } else {
- DocListCast(Cast(doc["template-buttons"], Doc, null)?.data); // prefetch templates
- }
- return doc["template-buttons"] as Doc;
- }
-
- // setup the different note type skins
- static setupNoteTemplates(doc: Doc) {
- if (doc["template-note-Note"] === undefined) {
- const noteView = Docs.Create.TextDocument("", { title: "text", style: "Note", isTemplateDoc: true, backgroundColor: "yellow" });
- noteView.isTemplateDoc = makeTemplate(noteView, true, "Note");
- doc["template-note-Note"] = new PrefetchProxy(noteView);
- }
- if (doc["template-note-Idea"] === undefined) {
- const noteView = Docs.Create.TextDocument("", { title: "text", style: "Idea", backgroundColor: "pink" });
- noteView.isTemplateDoc = makeTemplate(noteView, true, "Idea");
- doc["template-note-Idea"] = new PrefetchProxy(noteView);
- }
- if (doc["template-note-Topic"] === undefined) {
- const noteView = Docs.Create.TextDocument("", { title: "text", style: "Topic", backgroundColor: "lightBlue" });
- noteView.isTemplateDoc = makeTemplate(noteView, true, "Topic");
- doc["template-note-Topic"] = new PrefetchProxy(noteView);
- }
- if (doc["template-note-Todo"] === undefined) {
- const noteView = Docs.Create.TextDocument("", {
- title: "text", style: "Todo", backgroundColor: "orange", _autoHeight: false, _height: 100, _showCaption: "caption",
- layout: FormattedTextBox.LayoutString("Todo"), caption: RichTextField.DashField("taskStatus")
- });
- noteView.isTemplateDoc = makeTemplate(noteView, true, "Todo");
- doc["template-note-Todo"] = new PrefetchProxy(noteView);
- }
- const taskStatusValues = [
- { title: "todo", _backgroundColor: "blue", color: "white" },
- { title: "in progress", _backgroundColor: "yellow", color: "black" },
- { title: "completed", _backgroundColor: "green", color: "white" }
- ];
- if (doc.fieldTypes === undefined) {
- doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" });
- Doc.addFieldEnumerations(Doc.GetProto(doc["template-note-Todo"] as any as Doc), "taskStatus", taskStatusValues);
- }
-
- if (doc["template-notes"] === undefined) {
- doc["template-notes"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-note-Note"] as any as Doc,
- doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc, doc["template-note-Todo"] as any as Doc],
- { title: "Note Layouts", _height: 75 }));
- } else {
- const curNoteTypes = Cast(doc["template-notes"], Doc, null);
- const requiredTypes = [doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc,
- doc["template-note-Topic"] as any as Doc, doc["template-note-Todo"] as any as Doc];
- DocListCastAsync(curNoteTypes.data).then(async curNotes => {
- await Promise.all(curNotes!);
- requiredTypes.map(ntype => Doc.AddDocToList(curNoteTypes, "data", ntype));
- });
- }
-
- return doc["template-notes"] as Doc;
- }
-
- // creates Note templates, and initial "user" templates
- static setupDocTemplates(doc: Doc) {
- const noteTemplates = CurrentUserUtils.setupNoteTemplates(doc);
- const userTemplateBtns = CurrentUserUtils.setupUserTemplateButtons(doc);
- const clickTemplates = CurrentUserUtils.setupClickEditorTemplates(doc);
- if (doc.templateDocs === undefined) {
- doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([noteTemplates, userTemplateBtns, clickTemplates], {
- title: "template layouts", _xPadding: 0,
- dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
- }));
- }
- }
-
- // setup templates for different document types when they are iconified from Document Decorations
- static setupDefaultIconTemplates(doc: Doc) {
- if (doc["template-icon-view"] === undefined) {
- const iconView = Docs.Create.TextDocument("", {
- title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)")
- });
- Doc.GetProto(iconView).icon = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', "");
- iconView.isTemplateDoc = makeTemplate(iconView);
- doc["template-icon-view"] = new PrefetchProxy(iconView);
- }
- if (doc["template-icon-view-rtf"] === undefined) {
- const iconRtfView = Docs.Create.LabelDocument({
- title: "icon_" + DocumentType.RTF, textTransform: "unset", letterSpacing: "unset",
- _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)")
- });
- iconRtfView.isTemplateDoc = makeTemplate(iconRtfView, true, "icon_" + DocumentType.RTF);
- doc["template-icon-view-rtf"] = new PrefetchProxy(iconRtfView);
- }
- if (doc["template-icon-view-img"] === undefined) {
- const iconImageView = Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", {
- title: "data", _width: 50, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)")
- });
- iconImageView.isTemplateDoc = makeTemplate(iconImageView, true, "icon_" + DocumentType.IMG);
- doc["template-icon-view-img"] = new PrefetchProxy(iconImageView);
- }
- if (doc["template-icon-view-col"] === undefined) {
- const iconColView = Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)") });
- iconColView.isTemplateDoc = makeTemplate(iconColView, true, "icon_" + DocumentType.COL);
- doc["template-icon-view-col"] = new PrefetchProxy(iconColView);
- }
- if (doc["template-icons"] === undefined) {
- doc["template-icons"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc,
- doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc], { title: "icon templates", _height: 75 }));
- } else {
- const templateIconsDoc = Cast(doc["template-icons"], Doc, null);
- DocListCastAsync(templateIconsDoc).then(list => templateIconsDoc.data = new List<Doc>([doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc,
- doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc]));
- }
- return doc["template-icons"] as Doc;
- }
-
- static creatorBtnDescriptors(doc: Doc): {
- title: string, label: string, icon: string, drag?: string, ignoreClick?: boolean,
- click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc
- }[] {
- if (doc.emptyPresentation === undefined) {
- doc.emptyPresentation = Docs.Create.PresDocument(new List<Doc>(),
- { title: "Presentation", _viewType: CollectionViewType.Stacking, targetDropAction: "alias", _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" });
- }
- if (doc.emptyCollection === undefined) {
- doc.emptyCollection = Docs.Create.FreeformDocument([],
- { _nativeWidth: undefined, _nativeHeight: undefined, _LODdisable: true, _width: 150, _height: 100, title: "freeform" });
- }
- if (doc.emptyDocHolder === undefined) {
- doc.emptyDocHolder = Docs.Create.DocumentDocument(
- ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]") as any,
- { _width: 250, _height: 250, title: "container" });
- }
- if (doc.emptyWebpage === undefined) {
- doc.emptyWebpage = Docs.Create.WebDocument("", { title: "New Webpage", _width: 600 })
- }
- return [
- { title: "Drag a collection", label: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc },
- { title: "Drag a web page", label: "Web", icon: "globe-asia", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyWebpage as Doc },
- { title: "Drag a cat image", label: "Img", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 250, _nativeWidth:250, title: "an image of a cat" })' },
- { title: "Drag a screenshot", label: "Grab", icon: "photo-video", ignoreClick: true, drag: 'Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot" })' },
- { title: "Drag a webcam", label: "Cam", icon: "video", ignoreClick: true, drag: 'Docs.Create.WebCamDocument("", { _width: 400, _height: 400, title: "a test cam" })' },
- { title: "Drag a audio recorder", label: "Audio", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` },
- { title: "Drag a clickable button", label: "Btn", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, _xPadding:10, _yPadding: 10, title: "Button" })' },
- { title: "Drag a presentation view", label: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().activePresentation = getCopy(this.dragFactory,true)`, dragFactory: doc.emptyPresentation as Doc },
- { title: "Drag a search box", label: "Query", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' },
- { title: "Drag a scripting box", label: "Script", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250 title: "untitled script" })' },
- { title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' },
- { title: "Drag a mobile view", label: "Phone", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' },
- { title: "Drag an instance of the device collection", label: "Buxton", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.Buxton()' },
- // { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
- // { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
- // { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
- // { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "pink", activePen: doc },
- // { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.inkPen = this;', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "white", activePen: doc },
- { title: "Drag a document previewer", label: "Prev", icon: "expand", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory,true)', dragFactory: doc.emptyDocHolder as Doc },
- { title: "Drag a Calculator REPL", label: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' },
- ];
-
- }
-
- // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools
- static async setupCreatorButtons(doc: Doc) {
- let alreadyCreatedButtons: string[] = [];
- const dragCreatorSet = await Cast(doc.myItemCreators, Doc, null);
- if (dragCreatorSet) {
- const dragCreators = await Cast(dragCreatorSet.data, listSpec(Doc));
- if (dragCreators) {
- const dragDocs = await Promise.all(dragCreators);
- alreadyCreatedButtons = dragDocs.map(d => StrCast(d.title));
- }
- }
- const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title)).
- map(data => Docs.Create.FontIconDocument({
- _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100,
- icon: data.icon,
- title: data.title,
- label: data.label,
- ignoreClick: data.ignoreClick,
- dropAction: "copy",
- onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined,
- onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,
- ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined,
- activePen: data.activePen,
- backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]),
- dragFactory: data.dragFactory,
- }));
-
- if (dragCreatorSet === undefined) {
- doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, {
- title: "Basic Item Creators", _showTitle: "title", _xMargin: 0,
- _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled",
- dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
- }));
- } else {
- creatorBtns.forEach(nb => Doc.AddDocToList(doc.myItemCreators as Doc, "data", nb));
- }
- return doc.myItemCreators as Doc;
- }
-
- static setupMobileButtons(doc: Doc, buttons?: string[]) {
- const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [
- { title: "record", icon: "microphone", ignoreClick: true, click: "FILL" },
- { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
- { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
- { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "pink", activePen: doc },
- { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.inkPen = this;', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "white", activePen: doc },
- // { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "red", activePen: doc },
- { title: "upload", icon: "upload", click: 'switchMobileView(setupMobileUploadDoc, renderMobileUpload, onSwitchMobileUpload);', backgroundColor: "orange" },
- // { title: "upload", icon: "upload", click: 'uploadImageMobile();', backgroundColor: "cyan" },
- ];
- return docProtoData.filter(d => !buttons || !buttons.includes(d.title)).map(data => Docs.Create.FontIconDocument({
- _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: data.click ? "copy" : undefined, title: data.title, icon: data.icon, ignoreClick: data.ignoreClick,
- onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,
- ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, activePen: data.activePen,
- backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]), dragFactory: data.dragFactory,
- }));
- }
-
- static setupThumbButtons(doc: Doc) {
- const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, pointerDown?: string, pointerUp?: string, ischecked?: string, clipboard?: Doc, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [
- { title: "use pen", icon: "pen-nib", pointerUp: "resetPen()", pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
- { title: "use highlighter", icon: "highlighter", pointerUp: "resetPen()", pointerDown: 'setPen(20, this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
- { title: "notepad", icon: "clipboard", pointerUp: "GestureOverlay.Instance.closeFloatingDoc()", pointerDown: 'GestureOverlay.Instance.openFloatingDoc(this.clipboard)', clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300 }), backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
- { title: "interpret text", icon: "font", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('inktotext')", backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
- { title: "ignore gestures", icon: "signature", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('ignoregesture')", backgroundColor: "green", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
- ];
- return docProtoData.map(data => Docs.Create.FontIconDocument({
- _nativeWidth: 10, _nativeHeight: 10, _width: 10, _height: 10, title: data.title, icon: data.icon,
- dropAction: data.pointerDown ? "copy" : undefined, ignoreClick: data.ignoreClick,
- onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined,
- clipboard: data.clipboard,
- onPointerUp: data.pointerUp ? ScriptField.MakeScript(data.pointerUp) : undefined, onPointerDown: data.pointerDown ? ScriptField.MakeScript(data.pointerDown) : undefined,
- ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, activePen: data.activePen, pointerHack: true,
- backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]), dragFactory: data.dragFactory,
- }));
- }
-
- static setupThumbDoc(userDoc: Doc) {
- if (!userDoc.thumbDoc) {
- const thumbDoc = Docs.Create.LinearDocument(CurrentUserUtils.setupThumbButtons(userDoc), {
- _width: 100, _height: 50, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons",
- _autoHeight: true, _yMargin: 5, linearViewIsExpanded: true, backgroundColor: "white"
- });
- thumbDoc.inkToTextDoc = Docs.Create.LinearDocument([], {
- _width: 300, _height: 25, _autoHeight: true, _chromeStatus: "disabled", linearViewIsExpanded: true, flexDirection: "column"
- });
- userDoc.thumbDoc = thumbDoc;
- }
- return Cast(userDoc.thumbDoc, Doc);
- }
-
- static setupMobileDoc(userDoc: Doc) {
- return userDoc.activeMoble ?? Docs.Create.MasonryDocument(CurrentUserUtils.setupMobileButtons(userDoc), {
- columnWidth: 100, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", _autoHeight: true, _yMargin: 5
- });
- }
-
- static setupMobileInkingDoc(userDoc: Doc) {
- return Docs.Create.FreeformDocument([], { title: "Mobile Inking", backgroundColor: "white" });
- }
-
- static setupMobileUploadDoc(userDoc: Doc) {
- // const addButton = Docs.Create.FontIconDocument({ onDragStart: ScriptField.MakeScript('addWebToMobileUpload()'), title: "Add Web Doc to Upload Collection", icon: "plus", backgroundColor: "black" })
- const webDoc = Docs.Create.WebDocument("https://www.britannica.com/biography/Miles-Davis", {
- title: "Upload Images From the Web", _chromeStatus: "enabled", lockedPosition: true
- });
- const uploadDoc = Docs.Create.StackingDocument([], {
- title: "Mobile Upload Collection", backgroundColor: "white", lockedPosition: true
- });
- return Docs.Create.StackingDocument([webDoc, uploadDoc], {
- _width: screen.width, lockedPosition: true, _chromeStatus: "disabled", title: "Upload", _autoHeight: true, _yMargin: 80, backgroundColor: "lightgray"
- });
- }
-
- // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker.
- // when clicked, this panel will be displayed in the target container (ie, sidebarContainer)
- static async setupToolsBtnPanel(doc: Doc, sidebarContainer: Doc) {
- // setup a masonry view of all he creators
- const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc);
- const templateBtns = CurrentUserUtils.setupUserTemplateButtons(doc);
-
- if (doc.myCreators === undefined) {
- doc.myCreators = new PrefetchProxy(Docs.Create.StackingDocument([creatorBtns, templateBtns], {
- title: "all Creators", _yMargin: 0, _autoHeight: true, _xMargin: 0,
- _width: 500, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled",
- }));
- }
- // setup a color picker
- if (doc.myColorPicker === undefined) {
- const color = Docs.Create.ColorDocument({
- title: "color picker", _width: 300, dropAction: "alias", forceActive: true, removeDropProperties: new List<string>(["dropAction", "forceActive"])
- });
- doc.myColorPicker = new PrefetchProxy(color);
- }
-
- if (doc["tabs-button-tools"] === undefined) {
- doc["tabs-button-tools"] = new PrefetchProxy(Docs.Create.ButtonDocument({
- _width: 35, _height: 25, title: "Tools", _fontSize: 10,
- letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
- sourcePanel: new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], {
- _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true
- })) as any as Doc,
- targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc,
- onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"),
- }));
- }
- (doc["tabs-button-tools"] as Doc).sourcePanel; // prefetch sourcePanel
- return doc["tabs-button-tools"] as Doc;
- }
-
- static setupWorkspaces(doc: Doc) {
- // setup workspaces library item
- if (doc.myWorkspaces === undefined) {
- doc.myWorkspaces = new PrefetchProxy(Docs.Create.TreeDocument([], {
- title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true,
- }));
- }
- const newWorkspace = ScriptField.MakeScript(`createNewWorkspace()`);
- (doc.myWorkspaces as Doc).contextMenuScripts = new List<ScriptField>([newWorkspace!]);
- (doc.myWorkspaces as Doc).contextMenuLabels = new List<string>(["Create New Workspace"]);
-
- return doc.myWorkspaces as Doc;
- }
- static setupDocumentCollection(doc: Doc) {
- if (doc.myDocuments === undefined) {
- doc.myDocuments = new PrefetchProxy(Docs.Create.TreeDocument([], {
- title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true,
- }));
- }
- return doc.myDocuments as Doc;
- }
- static setupRecentlyClosed(doc: Doc) {
- // setup Recently Closed library item
- if (doc.myRecentlyClosed === undefined) {
- doc.myRecentlyClosed = new PrefetchProxy(Docs.Create.TreeDocument([], {
- title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true,
- }));
- }
- // this is equivalent to using PrefetchProxies to make sure the recentlyClosed doc is ready
- PromiseValue(Cast(doc.myRecentlyClosed, Doc)).then(recent => recent && PromiseValue(recent.data).then(DocListCast));
- const clearAll = ScriptField.MakeScript(`self.data = new List([])`);
- (doc.myRecentlyClosed as Doc).contextMenuScripts = new List<ScriptField>([clearAll!]);
- (doc.myRecentlyClosed as Doc).contextMenuLabels = new List<string>(["Clear All"]);
-
- return doc.myRecentlyClosed as Doc;
- }
- // setup the Library button which will display the library panel. This panel includes a collection of workspaces, documents, and recently closed views
- static setupLibraryPanel(doc: Doc, sidebarContainer: Doc) {
- const workspaces = CurrentUserUtils.setupWorkspaces(doc);
- const documents = CurrentUserUtils.setupDocumentCollection(doc);
- const recentlyClosed = CurrentUserUtils.setupRecentlyClosed(doc);
-
- if (doc["tabs-button-library"] === undefined) {
- doc["tabs-button-library"] = new PrefetchProxy(Docs.Create.ButtonDocument({
- _width: 50, _height: 25, title: "Library", _fontSize: 10,
- letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
- sourcePanel: new PrefetchProxy(Docs.Create.TreeDocument([workspaces, documents, recentlyClosed, doc], {
- title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "move", lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true
- })) as any as Doc,
- targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc,
- onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;")
- }));
- }
- return doc["tabs-button-library"] as Doc;
- }
-
- // setup the Search button which will display the search panel.
- static setupSearchBtnPanel(doc: Doc, sidebarContainer: Doc) {
- if (doc["tabs-button-search"] === undefined) {
- doc["tabs-button-search"] = new PrefetchProxy(Docs.Create.ButtonDocument({
- _width: 50, _height: 25, title: "Search", _fontSize: 10,
- letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
- sourcePanel: new PrefetchProxy(Docs.Create.QueryDocument({ title: "search stack", })) as any as Doc,
- searchFileTypes: new List<string>([DocumentType.RTF, DocumentType.IMG, DocumentType.PDF, DocumentType.VID, DocumentType.WEB, DocumentType.SCRIPTING]),
- targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc,
- lockedPosition: true,
- onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel")
- }));
- }
- return doc["tabs-button-search"] as Doc;
- }
-
- static setupSidebarContainer(doc: Doc) {
- if (doc["tabs-panelContainer"] === undefined) {
- const sidebarContainer = new Doc();
- sidebarContainer._chromeStatus = "disabled";
- sidebarContainer.onClick = ScriptField.MakeScript("freezeSidebar()");
- doc["tabs-panelContainer"] = new PrefetchProxy(sidebarContainer);
- }
- return doc["tabs-panelContainer"] as Doc;
- }
-
- // setup the list of sidebar mode buttons which determine what is displayed in the sidebar
- static async setupSidebarButtons(doc: Doc) {
- const sidebarContainer = CurrentUserUtils.setupSidebarContainer(doc);
- const toolsBtn = await CurrentUserUtils.setupToolsBtnPanel(doc, sidebarContainer);
- const libraryBtn = CurrentUserUtils.setupLibraryPanel(doc, sidebarContainer);
- const searchBtn = CurrentUserUtils.setupSearchBtnPanel(doc, sidebarContainer);
-
- // Finally, setup the list of buttons to display in the sidebar
- if (doc["tabs-buttons"] === undefined) {
- doc["tabs-buttons"] = new PrefetchProxy(Docs.Create.StackingDocument([searchBtn, libraryBtn, toolsBtn], {
- _width: 500, _height: 80, boxShadow: "0 0", _pivotField: "title", hideHeadings: true, ignoreClick: true, _chromeStatus: "view-mode",
- title: "sidebar btn row stack", backgroundColor: "dimGray",
- }));
- (toolsBtn.onClick as ScriptField).script.run({ this: toolsBtn });
- }
- }
-
- static blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, {
- ...opts,
- _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", forceActive: true,
- dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
- backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true
- })) as any as Doc
-
- static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({
- ...opts,
- dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100
- })) as any as Doc
-
- /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window
- static setupDockedButtons(doc: Doc) {
- if (doc["dockedBtn-pen"] === undefined) {
- doc["dockedBtn-pen"] = CurrentUserUtils.ficon({
- onClick: ScriptField.MakeScript("activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)"),
- author: "systemTemplates", title: "ink mode", icon: "pen-nib", ischecked: ComputedField.MakeFunction(`sameDocs(this.activePen.inkPen, this)`), activePen: doc
- });
- }
- if (doc["dockedBtn-undo"] === undefined) {
- doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" });
- }
- if (doc["dockedBtn-redo"] === undefined) {
- doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" });
- }
- if (doc.dockedBtns === undefined) {
- doc.dockedBtns = CurrentUserUtils.blist({ title: "docked buttons", ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc, doc["dockedBtn-pen"] as Doc]);
- }
- }
- // sets up the default set of documents to be shown in the Overlay layer
- static setupOverlays(doc: Doc) {
- if (doc.myOverlayDocuments === undefined) {
- doc.myOverlayDocuments = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "overlay documents", backgroundColor: "#aca3a6" }));
- }
- }
-
- // the initial presentation Doc to use
- static setupDefaultPresentation(doc: Doc) {
- if (doc.activePresentation === undefined) {
- doc.activePresentation = Docs.Create.PresDocument(new List<Doc>(), {
- title: "Presentation", _viewType: CollectionViewType.Stacking, targetDropAction: "alias",
- _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0"
- });
- }
- }
-
- static setupRightSidebar(doc: Doc) {
- if (doc.rightSidebarCollection === undefined) {
- doc.rightSidebarCollection = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Right Sidebar" }));
- }
- }
-
- static setupClickEditorTemplates(doc: Doc) {
- if (doc["clickFuncs-child"] === undefined) {
- const openInTarget = Docs.Create.ScriptingDocument(ScriptField.MakeScript(
- "docCast(thisContainer.target).then((target) => {" +
- " target && docCast(this.source).then((source) => { " +
- " target.proto.data = new List([source || this]); " +
- " }); " +
- "})",
- { target: Doc.name }), { title: "Click to open in target", _width: 300, _height: 200, targetScriptKey: "onChildClick" });
-
- const openDetail = Docs.Create.ScriptingDocument(ScriptField.MakeScript(
- "openOnRight(self.doubleClickView)",
- { target: Doc.name }), { title: "Double click to open doubleClickView", _width: 300, _height: 200, targetScriptKey: "onChildDoubleClick" });
-
- doc["clickFuncs-child"] = Docs.Create.TreeDocument([openInTarget, openDetail], { title: "on Child Click function templates" });
- }
- // this is equivalent to using PrefetchProxies to make sure all the childClickFuncs have been retrieved.
- PromiseValue(Cast(doc["clickFuncs-child"], Doc)).then(func => func && PromiseValue(func.data).then(DocListCast));
-
- if (doc.clickFuncs === undefined) {
- const onClick = Docs.Create.ScriptingDocument(undefined, {
- title: "onClick", "onClick-rawScript": "console.log('click')",
- isTemplateDoc: true, isTemplateForField: "onClick", _width: 300, _height: 200
- }, "onClick");
- const onDoubleClick = Docs.Create.ScriptingDocument(undefined, {
- title: "onDoubleClick", "onDoubleClick-rawScript": "console.log('double click')",
- isTemplateDoc: true, isTemplateForField: "onDoubleClick", _width: 300, _height: 200
- }, "onDoubleClick");
- const onCheckedClick = Docs.Create.ScriptingDocument(undefined, {
- title: "onCheckedClick", "onCheckedClick-rawScript": "console.log(heading + checked + containingTreeView)", "onCheckedClick-params": new List<string>(["heading", "checked", "containingTreeView"]), isTemplateDoc: true, isTemplateForField: "onCheckedClick", _width: 300, _height: 200
- }, "onCheckedClick");
- doc.clickFuncs = Docs.Create.TreeDocument([onClick, onDoubleClick, onCheckedClick], { title: "onClick funcs" });
- }
- PromiseValue(Cast(doc.clickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast));
-
- return doc.clickFuncs as Doc;
- }
-
- static async updateUserDocument(doc: Doc) {
- new InkingControl();
- doc.title = Doc.CurrentUserEmail;
- doc.activePen = doc;
- doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); //
- doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); //
- Utils.DRAG_THRESHOLD = NumCast(doc["constants-dragThreshold"]);
- this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon
- this.setupDocTemplates(doc); // sets up the template menu of templates
- this.setupRightSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing
- this.setupOverlays(doc); // documents in overlay layer
- this.setupDockedButtons(doc); // the bottom bar of font icons
- this.setupDefaultPresentation(doc); // presentation that's initially triggered
- await this.setupSidebarButtons(doc); // the pop-out left sidebar of tools/panels
- doc.globalLinkDatabase = Docs.Prototypes.MainLinkDocument();
-
- // setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet
- doc["dockedBtn-undo"] && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc["dockedBtn-undo"] as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true });
- doc["dockedBtn-redo"] && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc["dockedBtn-redo"] as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true });
-
- return doc;
- }
- public static async loadCurrentUser() {
- return rp.get(Utils.prepend("/getCurrentUser")).then(response => {
- if (response) {
- const result: { id: string, email: string } = JSON.parse(response);
- return result;
- } else {
- throw new Error("There should be a user! Why does Dash think there isn't one?");
- }
- });
- }
-
- public static async loadUserDocument({ id, email }: { id: string, email: string }) {
- this.curr_id = id;
- Doc.CurrentUserEmail = email;
- await rp.get(Utils.prepend("/getUserDocumentId")).then(id => {
- if (id && id !== "guest") {
- return DocServer.GetRefField(id).then(async field =>
- Doc.SetUserDoc(await this.updateUserDocument(field instanceof Doc ? field : new Doc(id, true))));
- } else {
- throw new Error("There should be a user id! Why does Dash think there isn't one?");
- }
- });
- }
-}
-
-Scripting.addGlobal(function setupMobileInkingDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileInkingDoc(userDoc); });
-Scripting.addGlobal(function setupMobileUploadDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileUploadDoc(userDoc); });
-Scripting.addGlobal(function createNewWorkspace() { return MainView.Instance.createNewWorkspace(); }); \ No newline at end of file
diff --git a/src/server/database.ts b/src/server/database.ts
index ad285765b..a5f23c4b1 100644
--- a/src/server/database.ts
+++ b/src/server/database.ts
@@ -1,10 +1,10 @@
import * as mongodb from 'mongodb';
import { Transferable } from './Message';
-import { Opt } from '../new_fields/Doc';
+import { Opt } from '../fields/Doc';
import { Utils, emptyFunction } from '../Utils';
import { Credentials } from 'google-auth-library';
import { GoogleApiServerUtils } from './apis/google/GoogleApiServerUtils';
-import { IDatabase } from './IDatabase';
+import { IDatabase, DocumentsCollection } from './IDatabase';
import { MemoryDatabase } from './MemoryDatabase';
import * as mongoose from 'mongoose';
import { Upload } from './SharedMediaTypes';
@@ -14,7 +14,7 @@ export namespace Database {
export let disconnect: Function;
const schema = 'Dash';
const port = 27017;
- export const url = `mongodb://localhost:${port}/`;
+ export const url = `mongodb://localhost:${port}/${schema}`;
enum ConnectionStates {
disconnected = 0,
@@ -47,28 +47,29 @@ export namespace Database {
}
export class Database implements IDatabase {
- public static DocumentsCollection = 'documents';
private MongoClient = mongodb.MongoClient;
private currentWrites: { [id: string]: Promise<void> } = {};
private db?: mongodb.Db;
private onConnect: (() => void)[] = [];
- doConnect() {
+ async doConnect() {
console.error(`\nConnecting to Mongo with URL : ${url}\n`);
- this.MongoClient.connect(url, { connectTimeoutMS: 30000, socketTimeoutMS: 30000, useUnifiedTopology: true }, (_err, client) => {
- console.error("mongo connect response\n");
- if (!client) {
- console.error("\nMongo connect failed with the error:\n");
- console.log(_err);
- process.exit(0);
- }
- this.db = client.db();
- this.onConnect.forEach(fn => fn());
+ return new Promise<void>(resolve => {
+ this.MongoClient.connect(url, { connectTimeoutMS: 30000, socketTimeoutMS: 30000, useUnifiedTopology: true }, (_err, client) => {
+ console.error("mongo connect response\n");
+ if (!client) {
+ console.error("\nMongo connect failed with the error:\n");
+ console.log(_err);
+ process.exit(0);
+ }
+ this.db = client.db();
+ this.onConnect.forEach(fn => fn());
+ resolve();
+ });
});
}
- public async update(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, upsert = true, collectionName = Database.DocumentsCollection) {
-
+ public async update(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, upsert = true, collectionName = DocumentsCollection) {
if (this.db) {
const collection = this.db.collection(collectionName);
const prom = this.currentWrites[id];
@@ -93,7 +94,7 @@ export namespace Database {
}
}
- public replace(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, upsert = true, collectionName = Database.DocumentsCollection) {
+ public replace(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, upsert = true, collectionName = DocumentsCollection) {
if (this.db) {
const collection = this.db.collection(collectionName);
const prom = this.currentWrites[id];
@@ -117,9 +118,21 @@ export namespace Database {
}
}
+ public async getCollectionNames() {
+ const cursor = this.db?.listCollections();
+ const collectionNames: string[] = [];
+ if (cursor) {
+ while (await cursor.hasNext()) {
+ const collection: any = await cursor.next();
+ collection && collectionNames.push(collection.name);
+ }
+ }
+ return collectionNames;
+ }
+
public delete(query: any, collectionName?: string): Promise<mongodb.DeleteWriteOpResultObject>;
public delete(id: string, collectionName?: string): Promise<mongodb.DeleteWriteOpResultObject>;
- public delete(id: any, collectionName = Database.DocumentsCollection) {
+ public delete(id: any, collectionName = DocumentsCollection) {
if (typeof id === "string") {
id = { _id: id };
}
@@ -131,25 +144,26 @@ export namespace Database {
}
}
- public async deleteAll(collectionName = Database.DocumentsCollection, persist = true): Promise<any> {
- return new Promise(resolve => {
- const executor = async (database: mongodb.Db) => {
- if (persist) {
- await database.collection(collectionName).deleteMany({});
- } else {
- await database.dropCollection(collectionName);
- }
- resolve();
- };
- if (this.db) {
- executor(this.db);
+ public async dropSchema(...targetSchemas: string[]): Promise<any> {
+ const executor = async (database: mongodb.Db) => {
+ const existing = await Instance.getCollectionNames();
+ let valid: string[];
+ if (targetSchemas.length) {
+ valid = targetSchemas.filter(collection => existing.includes(collection));
} else {
- this.onConnect.push(() => this.db && executor(this.db));
+ valid = existing;
}
- });
+ const pending = Promise.all(valid.map(schemaName => database.dropCollection(schemaName)));
+ return (await pending).every(dropOutcome => dropOutcome);
+ };
+ if (this.db) {
+ return executor(this.db);
+ } else {
+ this.onConnect.push(() => this.db && executor(this.db));
+ }
}
- public async insert(value: any, collectionName = Database.DocumentsCollection) {
+ public async insert(value: any, collectionName = DocumentsCollection) {
if (this.db) {
if ("id" in value) {
value._id = value.id;
@@ -177,7 +191,7 @@ export namespace Database {
}
}
- public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = "newDocuments") {
+ public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = DocumentsCollection) {
if (this.db) {
this.db.collection(collectionName).findOne({ _id: id }, (err, result) => {
if (result) {
@@ -193,7 +207,7 @@ export namespace Database {
}
}
- public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = Database.DocumentsCollection) {
+ public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = DocumentsCollection) {
if (this.db) {
this.db.collection(collectionName).find({ _id: { "$in": ids } }).toArray((err, docs) => {
if (err) {
@@ -211,7 +225,7 @@ export namespace Database {
}
}
- public async visit(ids: string[], fn: (result: any) => string[] | Promise<string[]>, collectionName = "newDocuments"): Promise<void> {
+ public async visit(ids: string[], fn: (result: any) => string[] | Promise<string[]>, collectionName = DocumentsCollection): Promise<void> {
if (this.db) {
const visited = new Set<string>();
while (ids.length) {
@@ -238,7 +252,7 @@ export namespace Database {
}
}
- public query(query: { [key: string]: any }, projection?: { [key: string]: 0 | 1 }, collectionName = "newDocuments"): Promise<mongodb.Cursor> {
+ public query(query: { [key: string]: any }, projection?: { [key: string]: 0 | 1 }, collectionName = DocumentsCollection): Promise<mongodb.Cursor> {
if (this.db) {
let cursor = this.db.collection(collectionName).find(query);
if (projection) {
@@ -252,7 +266,7 @@ export namespace Database {
}
}
- public updateMany(query: any, update: any, collectionName = "newDocuments") {
+ public updateMany(query: any, update: any, collectionName = DocumentsCollection) {
if (this.db) {
const db = this.db;
return new Promise<mongodb.WriteOpResult>(res => db.collection(collectionName).update(query, update, (_, result) => res(result)));
@@ -277,14 +291,28 @@ export namespace Database {
}
}
- export const Instance: IDatabase = getDatabase();
+ export const Instance = getDatabase();
+ /**
+ * Provides definitions and apis for working with
+ * portions of the database not dedicated to storing documents
+ * or Dash-internal user data.
+ */
export namespace Auxiliary {
+ /**
+ * All the auxiliary MongoDB collections (schemas)
+ */
export enum AuxiliaryCollections {
- GooglePhotosUploadHistory = "uploadedFromGooglePhotos"
+ GooglePhotosUploadHistory = "uploadedFromGooglePhotos",
+ GoogleAccess = "googleAuthentication"
}
+ /**
+ * Searches for the @param query in the specified @param collection,
+ * and returns at most the first @param cap results. If @param removeId is true,
+ * as it is by default, each object will be stripped of its database id.
+ */
const SanitizedCappedQuery = async (query: { [key: string]: any }, collection: string, cap: number, removeId = true) => {
const cursor = await Instance.query(query, undefined, collection);
const results = await cursor.toArray();
@@ -295,54 +323,88 @@ export namespace Database {
}) : slice;
};
+ /**
+ * Searches for the @param query in the specified @param collection,
+ * and returns at most the first result. If @param removeId is true,
+ * as it is by default, each object will be stripped of its database id.
+ * Worth the special case since it converts the Array return type to a single
+ * object of the specified type.
+ */
const SanitizedSingletonQuery = async <T>(query: { [key: string]: any }, collection: string, removeId = true): Promise<Opt<T>> => {
const results = await SanitizedCappedQuery(query, collection, 1, removeId);
return results.length ? results[0] : undefined;
};
+ /**
+ * Checks to see if an image with the given @param contentSize
+ * already exists in the aux database, i.e. has already been downloaded from Google Photos.
+ */
export const QueryUploadHistory = async (contentSize: number) => {
return SanitizedSingletonQuery<Upload.ImageInformation>({ contentSize }, AuxiliaryCollections.GooglePhotosUploadHistory);
};
- export namespace GoogleAuthenticationToken {
-
- const GoogleAuthentication = "googleAuthentication";
-
- export type StoredCredentials = Credentials & { _id: string };
+ /**
+ * Records the uploading of the image with the given @param information,
+ * using the given content size as a seed for the database id.
+ */
+ export const LogUpload = async (information: Upload.ImageInformation) => {
+ const bundle = {
+ _id: Utils.GenerateDeterministicGuid(String(information.contentSize)),
+ ...information
+ };
+ return Instance.insert(bundle, AuxiliaryCollections.GooglePhotosUploadHistory);
+ };
+ /**
+ * Manages the storage, retrieval and updating of the access token that
+ * facilitates interactions with all their APIs for a given account.
+ */
+ export namespace GoogleAccessToken {
+
+ /**
+ * Format stored in database.
+ */
+ type StoredCredentials = GoogleApiServerUtils.EnrichedCredentials & { _id: string };
+
+ /**
+ * Retrieves the credentials associaed with @param userId
+ * and optionally removes their database id according to @param removeId.
+ */
export const Fetch = async (userId: string, removeId = true): Promise<Opt<StoredCredentials>> => {
- return SanitizedSingletonQuery<StoredCredentials>({ userId }, GoogleAuthentication, removeId);
+ return SanitizedSingletonQuery<StoredCredentials>({ userId }, AuxiliaryCollections.GoogleAccess, removeId);
};
+ /**
+ * Writes the @param enrichedCredentials to the database, associated
+ * with @param userId for later retrieval and updating.
+ */
export const Write = async (userId: string, enrichedCredentials: GoogleApiServerUtils.EnrichedCredentials) => {
- return Instance.insert({ userId, canAccess: [], ...enrichedCredentials }, GoogleAuthentication);
+ return Instance.insert({ userId, canAccess: [], ...enrichedCredentials }, AuxiliaryCollections.GoogleAccess);
};
+ /**
+ * Updates the @param access_token and @param expiry_date fields
+ * in the stored credentials associated with @param userId.
+ */
export const Update = async (userId: string, access_token: string, expiry_date: number) => {
const entry = await Fetch(userId, false);
if (entry) {
const parameters = { $set: { access_token, expiry_date } };
- return Instance.update(entry._id, parameters, emptyFunction, true, GoogleAuthentication);
+ return Instance.update(entry._id, parameters, emptyFunction, true, AuxiliaryCollections.GoogleAccess);
}
};
- export const DeleteAll = () => Instance.deleteAll(GoogleAuthentication, false);
-
- }
-
- export const LogUpload = async (information: Upload.ImageInformation) => {
- const bundle = {
- _id: Utils.GenerateDeterministicGuid(String(information.contentSize)),
- ...information
+ /**
+ * Revokes the credentials associated with @param userId.
+ */
+ export const Revoke = async (userId: string) => {
+ const entry = await Fetch(userId, false);
+ if (entry) {
+ Instance.delete({ _id: entry._id }, AuxiliaryCollections.GoogleAccess);
+ }
};
- return Instance.insert(bundle, AuxiliaryCollections.GooglePhotosUploadHistory);
- };
- export const DeleteAll = async (persist = false) => {
- const collectionNames = Object.values(AuxiliaryCollections);
- const pendingDeletions = collectionNames.map(name => Instance.deleteAll(name, persist));
- return Promise.all(pendingDeletions);
- };
+ }
}
diff --git a/src/server/index.ts b/src/server/index.ts
index f26c8a6ab..af8f95a5e 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -11,9 +11,9 @@ import * as qs from 'query-string';
import UtilManager from './ApiManagers/UtilManager';
import { SearchManager } from './ApiManagers/SearchManager';
import UserManager from './ApiManagers/UserManager';
-import { WebSocket } from './Websocket/Websocket';
+import { WebSocket } from './websocket';
import DownloadManager from './ApiManagers/DownloadManager';
-import { GoogleCredentialsLoader } from './credentials/CredentialsLoader';
+import { GoogleCredentialsLoader } from './apis/google/CredentialsLoader';
import DeleteManager from "./ApiManagers/DeleteManager";
import PDFManager from "./ApiManagers/PDFManager";
import UploadManager from "./ApiManagers/UploadManager";
@@ -25,7 +25,6 @@ import { yellow } from "colors";
import { DashSessionAgent } from "./DashSession/DashSessionAgent";
import SessionManager from "./ApiManagers/SessionManager";
import { AppliedSessionAgent } from "./DashSession/Session/agents/applied_session_agent";
-import { Utils } from "../Utils";
export const onWindows = process.platform === "win32";
export let sessionAgent: AppliedSessionAgent;
@@ -125,7 +124,7 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }:
// initialize the web socket (bidirectional communication: if a user changes
// a field on one client, that change must be broadcast to all other clients)
- WebSocket.start(isRelease);
+ WebSocket.initialize(isRelease);
}
diff --git a/src/server/remapUrl.ts b/src/server/remapUrl.ts
index 45d2fdd33..91a3cb6bf 100644
--- a/src/server/remapUrl.ts
+++ b/src/server/remapUrl.ts
@@ -1,6 +1,4 @@
import { Database } from "./database";
-import { Search } from "./Search";
-import * as path from 'path';
//npx ts-node src/server/remapUrl.ts
@@ -50,7 +48,7 @@ async function update() {
return new Promise(res => Database.Instance.update(doc[0], doc[1], () => {
console.log("wrote " + JSON.stringify(doc[1]));
res();
- }, false, "newDocuments"));
+ }, false));
}));
console.log("Done");
// await Promise.all(updates.map(update => {
diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts
index add607761..4b3094616 100644
--- a/src/server/server_Initialization.ts
+++ b/src/server/server_Initialization.ts
@@ -7,7 +7,7 @@ import * as cookieParser from 'cookie-parser';
import expressFlash = require('express-flash');
import flash = require('connect-flash');
import { Database } from './database';
-import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLogin, postReset, postSignup } from './authentication/controllers/user_controller';
+import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLogin, postReset, postSignup } from './authentication/AuthenticationManager';
const MongoStore = require('connect-mongo')(session);
import RouteManager from './RouteManager';
import * as webpack from 'webpack';
@@ -94,6 +94,8 @@ function determineEnvironment() {
const label = isRelease ? "release" : "development";
console.log(`\nrunning server in ${color(label)} mode`);
+ // swilkins: I don't think we need to read from ClientUtils.RELEASE anymore. Should be able to invoke process.env.RELEASE
+ // on the client side, thanks to dotenv in webpack.config.js
let clientUtils = fs.readFileSync("./src/client/util/ClientUtils.ts.temp", "utf8");
clientUtils = `//AUTO-GENERATED FILE: DO NOT EDIT\n${clientUtils.replace('"mode"', String(isRelease))}`;
fs.writeFileSync("./src/client/util/ClientUtils.ts", clientUtils, "utf8");
diff --git a/src/server/Websocket/Websocket.ts b/src/server/websocket.ts
index be895c4bc..7278bdc32 100644
--- a/src/server/Websocket/Websocket.ts
+++ b/src/server/websocket.ts
@@ -1,17 +1,18 @@
-import { Utils } from "../../Utils";
-import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent, RoomMessage } from "../Message";
-import { Client } from "../Client";
+import { Utils } from "../Utils";
+import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent, RoomMessage } from "./Message";
+import { Client } from "./Client";
import { Socket } from "socket.io";
-import { Database } from "../database";
-import { Search } from "../Search";
+import { Database } from "./database";
+import { Search } from "./Search";
import * as io from 'socket.io';
-import YoutubeApi from "../apis/youtube/youtubeApiSample";
-import { GoogleCredentialsLoader } from "../credentials/CredentialsLoader";
-import { logPort } from "../ActionUtilities";
-import { timeMap } from "../ApiManagers/UserManager";
+import YoutubeApi from "./apis/youtube/youtubeApiSample";
+import { GoogleCredentialsLoader } from "./apis/google/CredentialsLoader";
+import { logPort } from "./ActionUtilities";
+import { timeMap } from "./ApiManagers/UserManager";
import { green } from "colors";
import { networkInterfaces } from "os";
-import executeImport from "../../scraping/buxton/final/BuxtonImporter";
+import executeImport from "../scraping/buxton/final/BuxtonImporter";
+import { DocumentsCollection } from "./IDatabase";
export namespace WebSocket {
@@ -20,15 +21,7 @@ export namespace WebSocket {
export const socketMap = new Map<SocketIO.Socket, string>();
export let disconnect: Function;
-
- export async function start(isRelease: boolean) {
- await preliminaryFunctions();
- initialize(isRelease);
- }
-
- async function preliminaryFunctions() {
- }
- function initialize(isRelease: boolean) {
+ export function initialize(isRelease: boolean) {
const endpoint = io();
endpoint.on("connection", function (socket: Socket) {
_socket = socket;
@@ -96,7 +89,7 @@ export namespace WebSocket {
Utils.AddServerHandlerCallback(socket, MessageStore.GetField, getField);
Utils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields);
if (isRelease) {
- Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields);
+ Utils.AddServerHandler(socket, MessageStore.DeleteAll, () => doDelete(false));
}
Utils.AddServerHandler(socket, MessageStore.CreateField, CreateField);
@@ -163,24 +156,10 @@ export namespace WebSocket {
}
}
- export async function deleteFields() {
- await Database.Instance.deleteAll();
- if (process.env.DISABLE_SEARCH !== "true") {
- await Search.clear();
- }
- await Database.Instance.deleteAll('newDocuments');
- }
-
- // export async function deleteUserDocuments() {
- // await Database.Instance.deleteAll();
- // await Database.Instance.deleteAll('newDocuments');
- // }
-
- export async function deleteAll() {
- await Database.Instance.deleteAll();
- await Database.Instance.deleteAll('newDocuments');
- await Database.Instance.deleteAll('sessions');
- await Database.Instance.deleteAll('users');
+ export async function doDelete(onlyFields = true) {
+ const target: string[] = [];
+ onlyFields && target.push(DocumentsCollection);
+ await Database.Instance.dropSchema(...target);
if (process.env.DISABLE_SEARCH !== "true") {
await Search.clear();
}
@@ -210,11 +189,11 @@ export namespace WebSocket {
}
function GetRefField([id, callback]: [string, (result?: Transferable) => void]) {
- Database.Instance.getDocument(id, callback, "newDocuments");
+ Database.Instance.getDocument(id, callback);
}
function GetRefFields([ids, callback]: [string[], (result?: Transferable[]) => void]) {
- Database.Instance.getDocuments(ids, callback, "newDocuments");
+ Database.Instance.getDocuments(ids, callback);
}
const suffixMap: { [type: string]: (string | [string, string | ((json: any) => any)]) } = {
@@ -271,7 +250,7 @@ export namespace WebSocket {
function UpdateField(socket: Socket, diff: Diff) {
Database.Instance.update(diff.id, diff.diff,
- () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false, "newDocuments");
+ () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false);
const docfield = diff.diff.$set || diff.diff.$unset;
if (!docfield) {
return;
@@ -296,7 +275,7 @@ export namespace WebSocket {
}
function DeleteField(socket: Socket, id: string) {
- Database.Instance.delete({ _id: id }, "newDocuments").then(() => {
+ Database.Instance.delete({ _id: id }).then(() => {
socket.broadcast.emit(MessageStore.DeleteField.Message, id);
});
@@ -304,14 +283,14 @@ export namespace WebSocket {
}
function DeleteFields(socket: Socket, ids: string[]) {
- Database.Instance.delete({ _id: { $in: ids } }, "newDocuments").then(() => {
+ Database.Instance.delete({ _id: { $in: ids } }).then(() => {
socket.broadcast.emit(MessageStore.DeleteFields.Message, ids);
});
Search.deleteDocuments(ids);
}
function CreateField(newValue: any) {
- Database.Instance.insert(newValue, "newDocuments");
+ Database.Instance.insert(newValue);
}
}