Skip to content

Commit

Permalink
Merge pull request #4383 from alkem-io/develop
Browse files Browse the repository at this point in the history
Release: Account, Space Atomic Creation
  • Loading branch information
valentinyanakiev authored Aug 9, 2024
2 parents e55f3d1 + eeaca74 commit 30da775
Show file tree
Hide file tree
Showing 136 changed files with 1,560 additions and 1,361 deletions.
3 changes: 3 additions & 0 deletions alkemio.yml
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,9 @@ communications:
## storage ##
# Alkemio uses multiple types of persistent storage, including SQL database and IPFS.
storage:
file:
# 20MB
max_file_size: 2097152
# MySQL database configuration for usage by the Alkemio Server.
# The authentication method used by Alkemio Server is MySQL Native Password.
# Note: both schema / database name are used for configuration and they need to have the same value.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "alkemio-server",
"version": "0.86.1",
"version": "0.87.0",
"description": "Alkemio server, responsible for managing the shared Alkemio platform",
"author": "Alkemio Foundation",
"private": false,
Expand Down
234 changes: 116 additions & 118 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { GraphQLModule } from '@nestjs/graphql';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { CloseCode } from 'graphql-ws';
import { ConfigurationTypes } from '@common/enums';
import { ValidationPipe } from '@common/pipes/validation.pipe';
import configuration from '@config/configuration';
import {
Expand All @@ -32,6 +31,7 @@ import { print } from 'graphql/language/printer';
import { WinstonModule } from 'nest-winston';
import { join } from 'path';
import {
AlkemioConfig,
ConnectionContext,
SubscriptionsTransportWsWebsocket,
WebsocketContext,
Expand Down Expand Up @@ -90,41 +90,42 @@ import { LookupByNameModule } from '@services/api/lookup-by-name';
CacheModule.registerAsync({
isGlobal: true,
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
store: redisStore,
host: configService.get(ConfigurationTypes.STORAGE)?.redis?.host,
port: configService.get(ConfigurationTypes.STORAGE)?.redis?.port,
redisOptions: {
connectTimeout:
configService.get(ConfigurationTypes.STORAGE)?.redis?.timeout *
1000, // Connection timeout in milliseconds
},
}),
useFactory: async (configService: ConfigService<AlkemioConfig, true>) => {
const { host, port, timeout } = configService.get('storage.redis', {
infer: true,
});
return {
store: redisStore,
host,
port,
redisOptions: { connectTimeout: timeout * 1000 }, // Connection timeout in milliseconds
};
},
inject: [ConfigService],
}),
TypeOrmModule.forRootAsync({
name: 'default',
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
type: 'mysql',
insecureAuth: true,
synchronize: false,
cache: true,
entities: [join(__dirname, '**', '*.entity.{ts,js}')],
host: configService.get(ConfigurationTypes.STORAGE)?.database?.host,
port: configService.get(ConfigurationTypes.STORAGE)?.database?.port,
charset: configService.get(ConfigurationTypes.STORAGE)?.database
?.charset,
username: configService.get(ConfigurationTypes.STORAGE)?.database
?.username,
password: configService.get(ConfigurationTypes.STORAGE)?.database
?.password,
database: configService.get(ConfigurationTypes.STORAGE)?.database
?.schema,
logging: configService.get(ConfigurationTypes.STORAGE)?.database
?.logging,
}),
useFactory: async (configService: ConfigService<AlkemioConfig, true>) => {
const dbOptions = configService.get('storage.database', {
infer: true,
});
return {
type: 'mysql',
insecureAuth: true,
synchronize: false,
cache: true,
entities: [join(__dirname, '**', '*.entity.{ts,js}')],
host: dbOptions.host,
port: dbOptions.port,
charset: dbOptions.charset,
username: dbOptions.username,
password: dbOptions.password,
database: dbOptions.database,
logging: dbOptions.logging,
};
},
}),
WinstonModule.forRootAsync({
useClass: WinstonConfigService,
Expand All @@ -133,102 +134,99 @@ import { LookupByNameModule } from '@services/api/lookup-by-name';
driver: ApolloDriver,
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
cors: false, // this is to avoid a duplicate cors origin header being created when behind the oathkeeper reverse proxy
uploads: false,
autoSchemaFile: true,
introspection: true,
playground: {
settings: {
'request.credentials': 'include',
},
tabs: [
{
name: 'Me',
endpoint: `${
configService.get(ConfigurationTypes.HOSTING)?.endpoint_cluster
}/api/private/graphql`,
query: print(meQuery),
},
{
name: 'Spaces',
endpoint: `${
configService.get(ConfigurationTypes.HOSTING)?.endpoint_cluster
}/api/private/graphql`,
query: print(spacesQuery),
},
{
name: 'Configuration',
endpoint: `${
configService.get(ConfigurationTypes.HOSTING)?.endpoint_cluster
}/api/public/graphql`,
query: print(configQuery),
},
{
name: 'Server Metadata',
endpoint: `${
configService.get(ConfigurationTypes.HOSTING)?.endpoint_cluster
}/api/public/graphql`,
query: print(platformMetadataQuery),
useFactory: async (configService: ConfigService<AlkemioConfig, true>) => {
const endpointCluster = configService.get('hosting.endpoint_cluster', {
infer: true,
});
return {
cors: false, // this is to avoid a duplicate cors origin header being created when behind the oathkeeper reverse proxy
uploads: false,
autoSchemaFile: true,
introspection: true,
playground: {
settings: {
'request.credentials': 'include',
},
],
},
fieldResolverEnhancers: ['guards', 'filters'],
sortSchema: true,
persistedQueries: false,
/***
* graphql-ws requires passing the request object through the context method
* !!! this is graphql-ws ONLY
*/
context: (ctx: ConnectionContext) => {
if (isWebsocketContext(ctx)) {
return {
req: {
...ctx.extra.request,
headers: {
...ctx.extra.request.headers,
...ctx.connectionParams?.headers,
},
connectionParams: ctx.connectionParams,
tabs: [
{
name: 'Me',
endpoint: `${endpointCluster}/api/private/graphql`,
query: print(meQuery),
},
};
}

return { req: ctx.req };
},
subscriptions: {
'subscriptions-transport-ws': {
/***
* subscriptions-transport-ws required passing the request object
* through the onConnect method
*/
onConnect: (
connectionParams: Record<string, any>,
websocket: SubscriptionsTransportWsWebsocket // couldn't find a better type
) => {
{
name: 'Spaces',
endpoint: `${endpointCluster}/api/private/graphql`,
query: print(spacesQuery),
},
{
name: 'Configuration',
endpoint: `${endpointCluster}/api/public/graphql`,
query: print(configQuery),
},
{
name: 'Server Metadata',
endpoint: `${endpointCluster}/api/public/graphql`,
query: print(platformMetadataQuery),
},
],
},
fieldResolverEnhancers: ['guards', 'filters'],
sortSchema: true,
persistedQueries: false,
/***
* graphql-ws requires passing the request object through the context method
* !!! this is graphql-ws ONLY
*/
context: (ctx: ConnectionContext) => {
if (isWebsocketContext(ctx)) {
return {
req: { headers: websocket?.upgradeReq?.headers },
req: {
...ctx.extra.request,
headers: {
...ctx.extra.request.headers,
...ctx.connectionParams?.headers,
},
connectionParams: ctx.connectionParams,
},
};
},
}

return { req: ctx.req };
},
'graphql-ws': {
onNext: (ctx, message, args, result) => {
const context = args.contextValue as IGraphQLContext;
const expiry = context.req.user.expiry;
// if the session has expired, close the socket
if (expiry && expiry < Date.now()) {
(ctx as WebsocketContext).extra.socket.close(
CloseCode.Unauthorized,
'Session expired'
);
return;
}
subscriptions: {
'subscriptions-transport-ws': {
/***
* subscriptions-transport-ws required passing the request object
* through the onConnect method
*/
onConnect: (
connectionParams: Record<string, any>,
websocket: SubscriptionsTransportWsWebsocket // couldn't find a better type
) => {
return {
req: { headers: websocket?.upgradeReq?.headers },
};
},
},
'graphql-ws': {
onNext: (ctx, message, args, result) => {
const context = args.contextValue as IGraphQLContext;
const expiry = context.req.user.expiry;
// if the session has expired, close the socket
if (expiry && expiry < Date.now()) {
(ctx as WebsocketContext).extra.socket.close(
CloseCode.Unauthorized,
'Session expired'
);
return;
}

return result;
return result;
},
},
},
},
}),
};
},
}),
ScalarsModule,
AuthenticationModule,
Expand Down
17 changes: 0 additions & 17 deletions src/common/enums/configuration.type.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/common/enums/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export * from './logging.context';
export * from './alkemio.error.status';
export * from './authentication.provider';
export * from './configuration.type';
export * from './authorization.credential';
export * from './authorization.credential.global';
export * from './authorization.privilege';
Expand Down
11 changes: 6 additions & 5 deletions src/common/interceptors/innovation.hub.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import { ConfigService } from '@nestjs/config';
import { GqlExecutionContext } from '@nestjs/graphql';
import { INNOVATION_HUB_INJECT_TOKEN } from '@common/constants';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
import { ConfigurationTypes, LogContext } from '@common/enums';
import { LogContext } from '@common/enums';
import { InnovationHubService } from '@domain/innovation-hub';
import { DOMAIN_PATTERN, SUBDOMAIN_PATTERN } from '@core/validation';
import { AlkemioConfig } from '@src/types';

const SUBDOMAIN_GROUP = 'subdomain';

Expand All @@ -37,13 +38,13 @@ export class InnovationHubInterceptor implements NestInterceptor {

constructor(
private readonly innovationHubService: InnovationHubService,
private readonly configService: ConfigService,
private readonly configService: ConfigService<AlkemioConfig, true>,
@Inject(WINSTON_MODULE_NEST_PROVIDER)
private readonly logger: LoggerService
) {
this.innovationHubHeader = this.configService.get(
ConfigurationTypes.INNOVATION_HUB
)?.header;
this.innovationHubHeader = this.configService.get('innovation_hub.header', {
infer: true,
});
}

async intercept(context: ExecutionContext, next: CallHandler) {
Expand Down
Loading

0 comments on commit 30da775

Please sign in to comment.