feat(build): Build auth providers and write plugin import file.

This commit is contained in:
Sam 2022-04-22 17:21:14 +02:00
parent f27cc6066e
commit 9eb34c8700
No known key found for this signature in database
GPG Key ID: D004126FCD1A6DF0
12 changed files with 231 additions and 55 deletions

View File

@ -16,43 +16,14 @@
limitations under the License.
*/
import { type } from '@lowdefy/helpers';
import getPageRoles from './getPageRoles.js';
import getProtectedPages from './getProtectedPages.js';
import buildAuthPlugins from './buildAuthPlugins.js';
import buildPageAuth from './buildPageAuth.js';
import validateAuthConfig from './validateAuthConfig.js';
function buildAuth({ components }) {
function buildAuth({ components, context }) {
validateAuthConfig({ components });
const protectedPages = getProtectedPages({ components });
const pageRoles = getPageRoles({ components });
let configPublicPages = [];
if (type.isArray(components.auth.pages.public)) {
configPublicPages = components.auth.pages.public;
}
(components.pages || []).forEach((page) => {
if (pageRoles[page.id]) {
if (configPublicPages.includes(page.id)) {
throw new Error(
`Page "${page.id}" is both protected by roles ${JSON.stringify(
pageRoles[page.id]
)} and public.`
);
}
page.auth = {
public: false,
roles: pageRoles[page.id],
};
} else if (protectedPages.includes(page.id)) {
page.auth = {
public: false,
};
} else {
page.auth = {
public: true,
};
}
});
buildPageAuth({ components });
buildAuthPlugins({ components, context });
return components;
}

View File

@ -0,0 +1,41 @@
/*
Copyright 2020-2022 Lowdefy, Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { type } from '@lowdefy/helpers';
function buildAuthPlugins({ components, context }) {
if (type.isArray(components.auth.providers)) {
components.auth.providers.forEach((provider) => {
if (type.isUndefined(provider.id)) {
throw new Error(`Connection id missing.`);
}
if (!type.isString(provider.id)) {
throw new Error(
`Auth provider id is not a string. Received ${JSON.stringify(provider.id)}.`
);
}
if (!type.isString(provider.type)) {
throw new Error(
`Auth provider type is not a string at provider "${
provider.id
}". Received ${JSON.stringify(provider.type)}.`
);
}
context.typeCounters.auth.providers.increment(provider.type);
});
}
}
export default buildAuthPlugins;

View File

@ -0,0 +1,58 @@
/* eslint-disable no-param-reassign */
/*
Copyright 2020-2022 Lowdefy, Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { type } from '@lowdefy/helpers';
import getPageRoles from './getPageRoles.js';
import getProtectedPages from './getProtectedPages.js';
function buildPageAuth({ components }) {
const protectedPages = getProtectedPages({ components });
const pageRoles = getPageRoles({ components });
let configPublicPages = [];
if (type.isArray(components.auth.pages.public)) {
configPublicPages = components.auth.pages.public;
}
(components.pages || []).forEach((page) => {
if (pageRoles[page.id]) {
if (configPublicPages.includes(page.id)) {
throw new Error(
`Page "${page.id}" is both protected by roles ${JSON.stringify(
pageRoles[page.id]
)} and public.`
);
}
page.auth = {
public: false,
roles: pageRoles[page.id],
};
} else if (protectedPages.includes(page.id)) {
page.auth = {
public: false,
};
} else {
page.auth = {
public: true,
};
}
});
return components;
}
export default buildPageAuth;

View File

@ -33,10 +33,17 @@ async function validateAuthConfig({ components }) {
if (type.isNone(components.auth.pages.roles)) {
components.auth.pages.roles = {};
}
validate({
const { valid } = validate({
schema: lowdefySchema.definitions.authConfig,
data: components.auth,
returnErrors: true,
});
if (!valid) {
throw new Error('lowdefy.auth does not match schema.'); // TODO: Better error message
}
if (
(components.auth.pages.protected === true && components.auth.pages.public === true) ||
(type.isArray(components.auth.pages.protected) && type.isArray(components.auth.pages.public))

View File

@ -52,6 +52,9 @@ function buildTypes({ components, context }) {
components.types = {
actions: {},
auth: {
providers: {},
},
blocks: {},
connections: {},
requests: {},
@ -68,6 +71,13 @@ function buildTypes({ components, context }) {
typeClass: 'Action',
});
buildTypeClass(context, {
counter: typeCounters.auth.providers,
definitions: context.typesMap.auth.providers,
store: components.types.auth.providers,
typeClass: 'Auth provider',
});
buildTypeClass(context, {
counter: typeCounters.blocks,
definitions: context.typesMap.blocks,

View File

@ -24,12 +24,12 @@ async function testSchema({ components, context }) {
data: components,
returnErrors: true,
});
if (!valid) {
await context.logger.warn('Schema not valid.');
const promises = errors.map((error) =>
context.logger.warn(formatErrorMessage({ error, components }))
await Promise.all(
errors.map((error) => context.logger.warn(formatErrorMessage({ error, components })))
);
await promises;
}
}

View File

@ -29,6 +29,7 @@ async function updateServerPackageJson({ components, context }) {
});
}
getPackages(components.types.actions);
getPackages(components.types.auth.providers);
getPackages(components.types.blocks);
getPackages(components.types.connections);
getPackages(components.types.requests);

View File

@ -0,0 +1,29 @@
/*
Copyright 2020-2022 Lowdefy, Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import generateImportFile from './generateImportFile.js';
async function writeAuthImports({ components, context }) {
await context.writeBuildArtifact(
'plugins/auth/providers.js',
generateImportFile({
types: components.types.auth.providers,
importPath: 'auth/providers',
})
);
}
export default writeAuthImports;

View File

@ -18,14 +18,14 @@ import generateImportFile from './generateImportFile.js';
async function writeOperatorImports({ components, context }) {
await context.writeBuildArtifact(
'plugins/operatorsClient.js',
'plugins/operators/client.js',
generateImportFile({
types: components.types.operators.client,
importPath: 'operators/client',
})
);
await context.writeBuildArtifact(
'plugins/operatorsServer.js',
'plugins/operators/server.js',
generateImportFile({
types: components.types.operators.server,
importPath: 'operators/server',

View File

@ -0,0 +1,35 @@
/*
Copyright 2020-2022 Lowdefy, Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import writeActionImports from './writeActionImports.js';
import writeAuthImports from './writeAuthImports.js';
import writeBlockImports from './writeBlockImports.js';
import writeConnectionImports from './writeConnectionImports.js';
import writeIconImports from './writeIconImports.js';
import writeOperatorImports from './writeOperatorImports.js';
import writeStyleImports from './writeStyleImports.js';
async function writePluginImports({ components, context }) {
await writeActionImports({ components, context });
await writeAuthImports({ components, context });
await writeBlockImports({ components, context });
await writeConnectionImports({ components, context });
await writeIconImports({ components, context });
await writeOperatorImports({ components, context });
await writeStyleImports({ components, context });
}
export default writePluginImports;

View File

@ -39,20 +39,15 @@ import testSchema from './build/testSchema.js';
import validateApp from './build/validateApp.js';
import validateConfig from './build/validateConfig.js';
import updateServerPackageJson from './build/updateServerPackageJson.js';
import writeActionImports from './build/writePluginImports/writeActionImports.js';
import writeApp from './build/writeApp.js';
import writeAuth from './build/writeAuth.js';
import writeBlockImports from './build/writePluginImports/writeBlockImports.js';
import writePluginImports from './build/writePluginImports/writePluginImports.js';
import writeConfig from './build/writeConfig.js';
import writeConnectionImports from './build/writePluginImports/writeConnectionImports.js';
import writeConnections from './build/writeConnections.js';
import writeGlobal from './build/writeGlobal.js';
import writeIconImports from './build/writePluginImports/writeIconImports.js';
import writeMenus from './build/writeMenus.js';
import writeOperatorImports from './build/writePluginImports/writeOperatorImports.js';
import writePages from './build/writePages.js';
import writeRequests from './build/writeRequests.js';
import writeStyleImports from './build/writePluginImports/writeStyleImports.js';
import writeTypes from './build/writeTypes.js';
async function createContext({ customTypesMap, directories, logger, refResolver }) {
@ -67,6 +62,9 @@ async function createContext({ customTypesMap, directories, logger, refResolver
refResolver,
typeCounters: {
actions: createCounter(),
auth: {
providers: createCounter(),
},
blocks: createCounter(),
connections: createCounter(),
requests: createCounter(),
@ -96,7 +94,6 @@ async function build(options) {
await buildIcons({ components, context });
await buildStyles({ components, context });
await cleanBuildDirectory({ context });
await writeActionImports({ components, context });
await writeApp({ components, context });
await writeAuth({ components, context });
await writeConnections({ components, context });
@ -106,11 +103,7 @@ async function build(options) {
await writeGlobal({ components, context });
await writeMenus({ components, context });
await writeTypes({ components, context });
await writeBlockImports({ components, context });
await writeConnectionImports({ components, context });
await writeOperatorImports({ components, context });
await writeStyleImports({ components, context });
await writeIconImports({ components, context });
await writePluginImports({ components, context });
await updateServerPackageJson({ components, context });
await copyPublicFolder({ components, context });
}

View File

@ -185,6 +185,37 @@ export default {
},
},
},
providers: {
type: 'array',
items: {
type: 'object',
required: ['id', 'type'],
properties: {
id: {
type: 'string',
errorMessage: {
type: 'Auth provider "id" should be a string.',
},
},
type: {
type: 'string',
errorMessage: {
type: 'Auth provider "type" should be a string.',
},
},
properties: {
type: 'object',
},
},
errorMessage: {
type: 'Auth provider should be an object.',
required: {
id: 'Auth provider should have required property "id".',
type: 'Auth provider should have required property "type".',
},
},
},
},
},
},
block: {
@ -615,6 +646,9 @@ export default {
app: {
$ref: '#/definitions/app',
},
auth: {
$ref: '#/definitions/authConfig',
},
cli: {
type: 'object',
errorMessage: {
@ -628,9 +662,6 @@ export default {
},
additionalProperties: false,
properties: {
auth: {
$ref: '#/definitions/authConfig',
},
basePath: {
type: 'string',
description: 'App base path to apply to all routes. Base path must start with "/".',