move getTemplateOrg method; enable template org in docker tests (#602)

* move getTemplateOrg method; enable template org in docker tests

This moves the `getTemplateOrg` method to a neutral venue for the
convenience of `grist-static`, otherwise a lot of awkward dependencies
get pulled in needlessly in new parts of the app.

This also fixes docker tests using the template org.
This commit is contained in:
Paul Fitzpatrick 2023-07-31 21:10:59 +01:00 committed by GitHub
parent e1df6039c2
commit 61f954ff05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 57 additions and 32 deletions

View File

@ -11,10 +11,10 @@ import {getAuthorizedUserId, getUserId, getUserProfiles, RequestWithLogin} from
import {getSessionUser, linkOrgWithEmail} from 'app/server/lib/BrowserSession'; import {getSessionUser, linkOrgWithEmail} from 'app/server/lib/BrowserSession';
import {expressWrap} from 'app/server/lib/expressWrap'; import {expressWrap} from 'app/server/lib/expressWrap';
import {RequestWithOrg} from 'app/server/lib/extractOrg'; import {RequestWithOrg} from 'app/server/lib/extractOrg';
import {getTemplateOrg} from 'app/server/lib/gristSettings';
import log from 'app/server/lib/log'; import log from 'app/server/lib/log';
import {addPermit, clearSessionCacheIfNeeded, getDocScope, getScope, integerParam, import {addPermit, clearSessionCacheIfNeeded, getDocScope, getScope, integerParam,
isParameterOn, optStringParam, sendOkReply, sendReply, stringParam} from 'app/server/lib/requestUtils'; isParameterOn, optStringParam, sendOkReply, sendReply, stringParam} from 'app/server/lib/requestUtils';
import {getTemplateOrg} from 'app/server/lib/sendAppPage';
import {IWidgetRepository} from 'app/server/lib/WidgetRepository'; import {IWidgetRepository} from 'app/server/lib/WidgetRepository';
import {User} from './entity/User'; import {User} from './entity/User';

View File

@ -89,6 +89,7 @@ import {Authorizer} from 'app/server/lib/Authorizer';
import {checksumFile} from 'app/server/lib/checksumFile'; import {checksumFile} from 'app/server/lib/checksumFile';
import {Client} from 'app/server/lib/Client'; import {Client} from 'app/server/lib/Client';
import {DEFAULT_CACHE_TTL, DocManager} from 'app/server/lib/DocManager'; import {DEFAULT_CACHE_TTL, DocManager} from 'app/server/lib/DocManager';
import {getTemplateOrg} from 'app/server/lib/gristSettings';
import {ICreateActiveDocOptions} from 'app/server/lib/ICreate'; import {ICreateActiveDocOptions} from 'app/server/lib/ICreate';
import {makeForkIds} from 'app/server/lib/idUtils'; import {makeForkIds} from 'app/server/lib/idUtils';
import {GRIST_DOC_SQL, GRIST_DOC_WITH_TABLE1_SQL} from 'app/server/lib/initialDocSql'; import {GRIST_DOC_SQL, GRIST_DOC_WITH_TABLE1_SQL} from 'app/server/lib/initialDocSql';
@ -97,7 +98,6 @@ import log from 'app/server/lib/log';
import {LogMethods} from "app/server/lib/LogMethods"; import {LogMethods} from "app/server/lib/LogMethods";
import {NullSandbox, UnavailableSandboxMethodError} from 'app/server/lib/NullSandbox'; import {NullSandbox, UnavailableSandboxMethodError} from 'app/server/lib/NullSandbox';
import {DocRequests} from 'app/server/lib/Requests'; import {DocRequests} from 'app/server/lib/Requests';
import {getTemplateOrg} from 'app/server/lib/sendAppPage';
import {shortDesc} from 'app/server/lib/shortDesc'; import {shortDesc} from 'app/server/lib/shortDesc';
import {TableMetadataLoader} from 'app/server/lib/TableMetadataLoader'; import {TableMetadataLoader} from 'app/server/lib/TableMetadataLoader';
import {DocTriggers} from "app/server/lib/Triggers"; import {DocTriggers} from "app/server/lib/Triggers";

View File

@ -20,10 +20,11 @@ import {DocStatus, IDocWorkerMap} from 'app/server/lib/DocWorkerMap';
import {expressWrap} from 'app/server/lib/expressWrap'; import {expressWrap} from 'app/server/lib/expressWrap';
import {DocTemplate, GristServer} from 'app/server/lib/GristServer'; import {DocTemplate, GristServer} from 'app/server/lib/GristServer';
import {getCookieDomain} from 'app/server/lib/gristSessions'; import {getCookieDomain} from 'app/server/lib/gristSessions';
import {getTemplateOrg} from 'app/server/lib/gristSettings';
import {getAssignmentId} from 'app/server/lib/idUtils'; import {getAssignmentId} from 'app/server/lib/idUtils';
import log from 'app/server/lib/log'; import log from 'app/server/lib/log';
import {adaptServerUrl, addOrgToPathIfNeeded, pruneAPIResult, trustOrigin} from 'app/server/lib/requestUtils'; import {adaptServerUrl, addOrgToPathIfNeeded, pruneAPIResult, trustOrigin} from 'app/server/lib/requestUtils';
import {getTemplateOrg, ISendAppPageOptions} from 'app/server/lib/sendAppPage'; import {ISendAppPageOptions} from 'app/server/lib/sendAppPage';
export interface AttachOptions { export interface AttachOptions {
app: express.Application; // Express app to which to add endpoints app: express.Application; // Express app to which to add endpoints

View File

@ -0,0 +1,13 @@
import {appSettings} from 'app/server/lib/AppSettings';
export function getTemplateOrg() {
let org = appSettings.section('templates').flag('org').readString({
envVar: 'GRIST_TEMPLATE_ORG',
});
if (!org) { return null; }
if (process.env.GRIST_ID_PREFIX) {
org += `-${process.env.GRIST_ID_PREFIX}`;
}
return org;
}

View File

@ -3,10 +3,10 @@ import {isAffirmative} from 'app/common/gutil';
import {getTagManagerSnippet} from 'app/common/tagManager'; import {getTagManagerSnippet} from 'app/common/tagManager';
import {Document} from 'app/common/UserAPI'; import {Document} from 'app/common/UserAPI';
import {SUPPORT_EMAIL} from 'app/gen-server/lib/HomeDBManager'; import {SUPPORT_EMAIL} from 'app/gen-server/lib/HomeDBManager';
import {appSettings} from 'app/server/lib/AppSettings';
import {isAnonymousUser, isSingleUserMode, RequestWithLogin} from 'app/server/lib/Authorizer'; import {isAnonymousUser, isSingleUserMode, RequestWithLogin} from 'app/server/lib/Authorizer';
import {RequestWithOrg} from 'app/server/lib/extractOrg'; import {RequestWithOrg} from 'app/server/lib/extractOrg';
import {GristServer} from 'app/server/lib/GristServer'; import {GristServer} from 'app/server/lib/GristServer';
import {getTemplateOrg} from 'app/server/lib/gristSettings';
import {getSupportedEngineChoices} from 'app/server/lib/serverUtils'; import {getSupportedEngineChoices} from 'app/server/lib/serverUtils';
import {readLoadedLngs, readLoadedNamespaces} from 'app/server/localization'; import {readLoadedLngs, readLoadedNamespaces} from 'app/server/localization';
import * as express from 'express'; import * as express from 'express';
@ -154,18 +154,6 @@ export function makeSendAppPage(opts: {
}; };
} }
export function getTemplateOrg() {
let org = appSettings.section('templates').flag('org').readString({
envVar: 'GRIST_TEMPLATE_ORG',
});
if (!org) { return null; }
if (process.env.GRIST_ID_PREFIX) {
org += `-${process.env.GRIST_ID_PREFIX}`;
}
return org;
}
function shouldSupportAnon() { function shouldSupportAnon() {
// Enable UI for anonymous access if a flag is explicitly set in the environment // Enable UI for anonymous access if a flag is explicitly set in the environment
return process.env.GRIST_SUPPORT_ANON === "true"; return process.env.GRIST_SUPPORT_ANON === "true";

View File

@ -306,6 +306,7 @@ describe('CellColor', function() {
// Empty cell to clear error from converting toggle to date // Empty cell to clear error from converting toggle to date
await cell.click(); await cell.click();
await driver.sendKeys(Key.DELETE); await driver.sendKeys(Key.DELETE);
await gu.waitAppFocus(true);
const clip = cell.find('.field_clip'); const clip = cell.find('.field_clip');

View File

@ -232,7 +232,7 @@ async function checkSelectingRecords(selectBy: string, sourceData: string[][], n
for (let rowNum = 1; rowNum <= 3; rowNum++) { for (let rowNum = 1; rowNum <= 3; rowNum++) {
// Click an anchor link // Click an anchor link
const anchorCell = gu.getCell({section: "Anchors", rowNum, col: 1}); const anchorCell = gu.getCell({section: "Anchors", rowNum, col: 1});
await anchorCell.find('.test-tb-link').click(); await driver.withActions(a => a.click(anchorCell.find('.test-tb-link')));
// Check that navigation to the link target worked // Check that navigation to the link target worked
assert.equal(await gu.getActiveSectionTitle(), "LINKTARGET"); assert.equal(await gu.getActiveSectionTitle(), "LINKTARGET");

View File

@ -1,25 +1,26 @@
import * as _ from 'lodash'; import * as _ from 'lodash';
import {addToRepl, assert, driver} from 'mocha-webdriver'; import {assert, driver} from 'mocha-webdriver';
import {enterRulePart, findDefaultRuleSet} from 'test/nbrowser/aclTestUtils'; import {enterRulePart, findDefaultRuleSet} from 'test/nbrowser/aclTestUtils';
import * as gu from 'test/nbrowser/gristUtils'; import * as gu from 'test/nbrowser/gristUtils';
import {server, setupTestSuite} from 'test/nbrowser/testUtils'; import {setupTestSuite} from 'test/nbrowser/testUtils';
describe('SelectBySummary', function() { describe('SelectBySummary', function() {
this.timeout(50000); this.timeout(50000);
setupTestSuite(); const cleanup = setupTestSuite();
addToRepl('gu2', gu); let headers: Record<string, string>;
gu.bigScreen(); gu.bigScreen();
before(async function() { before(async function() {
await server.simulateLogin("Chimpy", "chimpy@getgrist.com", 'nasa'); const session = await gu.session().teamSite.login();
const doc = await gu.importFixturesDoc('chimpy', 'nasa', 'Horizon', await session.tempDoc(cleanup, 'SelectBySummary.grist');
'SelectBySummary.grist', false); headers = {
await driver.get(`${server.getHost()}/o/nasa/doc/${doc.id}`); Authorization: `Bearer ${session.getApiKey()}`
await gu.waitForDocToLoad(); };
}); });
it('should filter a source table selected by a summary table', async function() { it('should filter a source table selected by a summary table (first option)', async function() {
await checkSelectingRecords( await checkSelectingRecords(
headers,
['onetwo'], ['onetwo'],
[ [
'1', '16', '1', '16',
@ -40,8 +41,11 @@ describe('SelectBySummary', function() {
], ],
], ],
); );
});
it('should filter a source table selected by a summary table (second option)', async function() {
await checkSelectingRecords( await checkSelectingRecords(
headers,
['choices'], ['choices'],
[ [
'a', '14', 'a', '14',
@ -67,9 +71,11 @@ describe('SelectBySummary', function() {
], ],
], ],
); );
});
it('should filter a source table selected by a summary table (both options)', async function() {
await checkSelectingRecords( await checkSelectingRecords(
headers,
['onetwo', 'choices'], ['onetwo', 'choices'],
[ [
'1', 'a', '6', '1', 'a', '6',
@ -104,7 +110,6 @@ describe('SelectBySummary', function() {
], ],
], ],
); );
}); });
it('should create new rows in the source table (link target) with correct default values', it('should create new rows in the source table (link target) with correct default values',
@ -153,6 +158,7 @@ describe('SelectBySummary', function() {
// selecting by the two less detailed summaries. // selecting by the two less detailed summaries.
// There was a bug previously that this would not work while the summary source table (Table1) was hidden. // There was a bug previously that this would not work while the summary source table (Table1) was hidden.
await checkSelectingRecords( await checkSelectingRecords(
headers,
['onetwo'], ['onetwo'],
[ [
'1', '16', '1', '16',
@ -175,6 +181,7 @@ describe('SelectBySummary', function() {
); );
await checkSelectingRecords( await checkSelectingRecords(
headers,
['choices'], ['choices'],
[ [
'a', '14', 'a', '14',
@ -208,6 +215,7 @@ describe('SelectBySummary', function() {
* to the corresponding subarray of `targetData`. * to the corresponding subarray of `targetData`.
*/ */
async function checkSelectingRecords( async function checkSelectingRecords(
headers: Record<string, string>,
groubyColumns: string[], groubyColumns: string[],
summaryData: string[], summaryData: string[],
targetData: string[][], targetData: string[][],
@ -243,7 +251,7 @@ async function checkSelectingRecords(
); );
if (targetSection === 'TABLE1') { if (targetSection === 'TABLE1') {
assert.equal(await countCell.getText(), numTargetRows.toString()); assert.equal(await countCell.getText(), numTargetRows.toString());
const csvCells = await gu.downloadSectionCsvGridCells(targetSection); const csvCells = await gu.downloadSectionCsvGridCells(targetSection, headers);
// visible cells text uses newlines to separate list items, CSV export uses commas // visible cells text uses newlines to separate list items, CSV export uses commas
const expectedCsvCells = targetGroup.map(s => s.replace("\n", ", ")); const expectedCsvCells = targetGroup.map(s => s.replace("\n", ", "));
assert.deepEqual(csvCells, expectedCsvCells); assert.deepEqual(csvCells, expectedCsvCells);
@ -259,7 +267,7 @@ async function checkSelectingRecords(
for (let rowNum = 1; rowNum <= 8; rowNum++) { for (let rowNum = 1; rowNum <= 8; rowNum++) {
// Click an anchor link // Click an anchor link
const anchorCell = gu.getCell({section: "Anchors", rowNum, col: 1}); const anchorCell = gu.getCell({section: "Anchors", rowNum, col: 1});
await anchorCell.find('.test-tb-link').click(); await driver.withActions(a => a.click(anchorCell.find('.test-tb-link')));
// Check that navigation to the link target worked // Check that navigation to the link target worked
assert.equal(await gu.getActiveSectionTitle(), "TABLE1"); assert.equal(await gu.getActiveSectionTitle(), "TABLE1");

View File

@ -61,6 +61,7 @@ export const uploadFixtureDoc = homeUtil.uploadFixtureDoc.bind(homeUtil);
export const getWorkspaceId = homeUtil.getWorkspaceId.bind(homeUtil); export const getWorkspaceId = homeUtil.getWorkspaceId.bind(homeUtil);
export const listDocs = homeUtil.listDocs.bind(homeUtil); export const listDocs = homeUtil.listDocs.bind(homeUtil);
export const createHomeApi = homeUtil.createHomeApi.bind(homeUtil); export const createHomeApi = homeUtil.createHomeApi.bind(homeUtil);
export const getApiKey = homeUtil.getApiKey.bind(homeUtil);
export const simulateLogin = homeUtil.simulateLogin.bind(homeUtil); export const simulateLogin = homeUtil.simulateLogin.bind(homeUtil);
export const removeLogin = homeUtil.removeLogin.bind(homeUtil); export const removeLogin = homeUtil.removeLogin.bind(homeUtil);
export const enableTips = homeUtil.enableTips.bind(homeUtil); export const enableTips = homeUtil.enableTips.bind(homeUtil);
@ -2047,6 +2048,13 @@ export class Session {
return createHomeApi(this.settings.name, this.settings.orgDomain, this.settings.email); return createHomeApi(this.settings.name, this.settings.orgDomain, this.settings.email);
} }
public getApiKey(): string|null {
if (this.settings.email === 'anon@getgrist.com') {
return getApiKey(null);
}
return getApiKey(this.settings.name, this.settings.email);
}
// Get the id of this user. // Get the id of this user.
public async getUserId(): Promise<number> { public async getUserId(): Promise<number> {
await this.login(); await this.login();

View File

@ -316,9 +316,14 @@ export class HomeUtil {
// A helper to create a UserAPI instance for a given useranme and org, that targets the home server // A helper to create a UserAPI instance for a given useranme and org, that targets the home server
// Username can be null for anonymous access. // Username can be null for anonymous access.
public createHomeApi(username: string|null, org: string, email?: string): UserAPIImpl { public createHomeApi(username: string|null, org: string, email?: string): UserAPIImpl {
const apiKey = this.getApiKey(username, email);
return this._createHomeApiUsingApiKey(apiKey, org);
}
public getApiKey(username: string|null, email?: string): string | null {
const name = (username || '').toLowerCase(); const name = (username || '').toLowerCase();
const apiKey = username && ((email && this._apiKey.get(email)) || `api_key_for_${name}`); const apiKey = username && ((email && this._apiKey.get(email)) || `api_key_for_${name}`);
return this._createHomeApiUsingApiKey(apiKey, org); return apiKey;
} }
/** /**

View File

@ -41,6 +41,7 @@ docker run --name $DOCKER_CONTAINER --rm \
--env GRIST_LOG_LEVEL=$GRIST_LOG_LEVEL \ --env GRIST_LOG_LEVEL=$GRIST_LOG_LEVEL \
--env GRIST_LOG_SKIP_HTTP=${DEBUG:-false} \ --env GRIST_LOG_SKIP_HTTP=${DEBUG:-false} \
--env TEST_SUPPORT_API_KEY=api_key_for_support \ --env TEST_SUPPORT_API_KEY=api_key_for_support \
--env GRIST_TEMPLATE_ORG=templates \
${TEST_IMAGE:-gristlabs/grist} & ${TEST_IMAGE:-gristlabs/grist} &
DOCKER_PID="$!" DOCKER_PID="$!"