mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Move Notifier to /ext
Summary: This makes it possible to configure a SendGrid-based Notifier instance via a JSON configuration file. Test Plan: Tested manually. Reviewers: alexmojaki Reviewed By: alexmojaki Subscribers: paulfitz Differential Revision: https://phab.getgrist.com/D3432
This commit is contained in:
@@ -6,7 +6,6 @@ import {encodeUrl, getSlugIfNeeded, GristLoadConfig, IGristUrlState, isOrgInPath
|
||||
import {getOrgUrlInfo} from 'app/common/gristUrls';
|
||||
import {UserProfile} from 'app/common/LoginSessionAPI';
|
||||
import {tbind} from 'app/common/tbind';
|
||||
import {UserConfig} from 'app/common/UserConfig';
|
||||
import * as version from 'app/common/version';
|
||||
import {ApiServer} from 'app/gen-server/ApiServer';
|
||||
import {Document} from "app/gen-server/entity/Document";
|
||||
@@ -103,7 +102,7 @@ export class FlexServer implements GristServer {
|
||||
public housekeeper: Housekeeper;
|
||||
public server: http.Server;
|
||||
public httpsServer?: https.Server;
|
||||
public settings: any;
|
||||
public settings?: Readonly<Record<string, unknown>>;
|
||||
public worker: DocWorkerInfo;
|
||||
public electronServerMethods: ElectronServerMethods;
|
||||
public readonly docsRoot: string;
|
||||
@@ -802,22 +801,24 @@ export class FlexServer implements GristServer {
|
||||
});
|
||||
}
|
||||
|
||||
// Load user config file from standard location. Alternatively, a config object
|
||||
// can be supplied, in which case no file is needed. The notion of a user config
|
||||
// file doesn't mean much in hosted grist, so it is convenient to be able to skip it.
|
||||
public async loadConfig(settings?: UserConfig) {
|
||||
/**
|
||||
* Load user config file from standard location (if present).
|
||||
*
|
||||
* Note that the user config file doesn't do anything today, but may be useful in
|
||||
* the future for configuring things that don't fit well into environment variables.
|
||||
*
|
||||
* TODO: Revisit this, and update `GristServer.settings` type to match the expected shape
|
||||
* of config.json. (ts-interface-checker could be useful here for runtime validation.)
|
||||
*/
|
||||
public async loadConfig() {
|
||||
if (this._check('config')) { return; }
|
||||
if (!settings) {
|
||||
const settingsPath = path.join(this.instanceRoot, 'config.json');
|
||||
if (await fse.pathExists(settingsPath)) {
|
||||
log.info(`Loading config from ${settingsPath}`);
|
||||
this.settings = JSON.parse(await fse.readFile(settingsPath, 'utf8'));
|
||||
} else {
|
||||
log.info(`Loading empty config because ${settingsPath} missing`);
|
||||
this.settings = {};
|
||||
}
|
||||
const settingsPath = path.join(this.instanceRoot, 'config.json');
|
||||
if (await fse.pathExists(settingsPath)) {
|
||||
log.info(`Loading config from ${settingsPath}`);
|
||||
this.settings = JSON.parse(await fse.readFile(settingsPath, 'utf8'));
|
||||
} else {
|
||||
this.settings = settings;
|
||||
log.info(`Loading empty config because ${settingsPath} missing`);
|
||||
this.settings = {};
|
||||
}
|
||||
|
||||
// TODO: We could include a third mock provider of login/logout URLs for better tests. Or we
|
||||
|
||||
@@ -16,7 +16,7 @@ import { ErrorWithCode } from 'app/common/ErrorWithCode';
|
||||
import { AclMatchInput, InfoEditor, InfoView } from 'app/common/GranularAccessClause';
|
||||
import { UserInfo } from 'app/common/GranularAccessClause';
|
||||
import { isCensored } from 'app/common/gristTypes';
|
||||
import { getSetMapValue, isObject, pruneArray } from 'app/common/gutil';
|
||||
import { getSetMapValue, isNonNullish, pruneArray } from 'app/common/gutil';
|
||||
import { canEdit, canView, isValidRole, Role } from 'app/common/roles';
|
||||
import { FullUser, UserAccessData } from 'app/common/UserAPI';
|
||||
import { HomeDBManager } from 'app/gen-server/lib/HomeDBManager';
|
||||
@@ -1039,7 +1039,7 @@ export class GranularAccess implements GranularAccessForBundle {
|
||||
this._makeAdditions(rowsAfter, forceAdds),
|
||||
this._removeRows(action, removals),
|
||||
this._makeRemovals(rowsAfter, forceRemoves),
|
||||
].filter(isObject);
|
||||
].filter(isNonNullish);
|
||||
|
||||
// Check whether there are column rules for this table, and if so whether they are row
|
||||
// dependent. If so, we may need to update visibility of cells not mentioned in the
|
||||
|
||||
@@ -22,6 +22,7 @@ import * as express from 'express';
|
||||
*/
|
||||
export interface GristServer {
|
||||
readonly create: ICreate;
|
||||
settings?: Readonly<Record<string, unknown>>;
|
||||
getHost(): string;
|
||||
getHomeUrl(req: express.Request, relPath?: string): string;
|
||||
getHomeUrlByDocId(docId: string, relPath?: string): Promise<string>;
|
||||
|
||||
@@ -46,10 +46,15 @@ export interface ICreateStorageOptions {
|
||||
create(purpose: 'doc'|'meta', extraPrefix: string): ExternalStorage|undefined;
|
||||
}
|
||||
|
||||
export interface ICreateNotifierOptions {
|
||||
create(dbManager: HomeDBManager, gristConfig: GristServer): INotifier|undefined;
|
||||
}
|
||||
|
||||
export function makeSimpleCreator(opts: {
|
||||
sessionSecret?: string,
|
||||
storage?: ICreateStorageOptions[],
|
||||
activationMiddleware?: (db: HomeDBManager, app: express.Express) => Promise<void>,
|
||||
notifier?: ICreateNotifierOptions,
|
||||
}): ICreate {
|
||||
return {
|
||||
Billing(db) {
|
||||
@@ -63,8 +68,9 @@ export function makeSimpleCreator(opts: {
|
||||
}
|
||||
};
|
||||
},
|
||||
Notifier() {
|
||||
return {
|
||||
Notifier(dbManager, gristConfig) {
|
||||
const {notifier} = opts;
|
||||
return notifier?.create(dbManager, gristConfig) ?? {
|
||||
get testPending() { return false; },
|
||||
deleteUser() { throw new Error('deleteUser unavailable'); },
|
||||
};
|
||||
|
||||
@@ -40,3 +40,10 @@ export function makeForkIds(options: { userId: number|null, isAnonymous: boolean
|
||||
export function getAssignmentId(docWorkerMap: IDocWorkerMap, docId: string): string {
|
||||
return docId;
|
||||
}
|
||||
|
||||
// Get the externalId to use for an AppSumo user. AppSumo identifies users by
|
||||
// an activation email, so we just use that (with an appsumo/ prefix it allow
|
||||
// for other families of id in the future).
|
||||
export function getExternalIdForAppSumoUser(email: string) {
|
||||
return `appsumo/${email}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user