mirror of
https://github.com/dadosfera/maestro.git
synced 2026-10-09 15:19:09 +00:00
276 lines
8.3 KiB
TypeScript
276 lines
8.3 KiB
TypeScript
import DadosferaLogger from '@dadosfera/dadosfera-logs';
|
|
import {
|
|
ProtoServices,
|
|
ReadService,
|
|
} from '@dadosfera/protospack-v2/dist/lib/Catalog';
|
|
import {
|
|
ForbiddenException,
|
|
Inject,
|
|
NotFoundException,
|
|
OnModuleInit,
|
|
} from '@nestjs/common';
|
|
import { CatalogClientConfiguration } from '../catalog-client';
|
|
import { ClientGrpc } from '@nestjs/microservices';
|
|
import { UsersService } from 'src/modules/users/users.service';
|
|
import { RolesService } from 'src/modules/roles/roles.service';
|
|
import { RequestUser } from 'src/decorators/user.decorator';
|
|
import { PackTheMetadata } from 'src/utils/PackTheMetadata';
|
|
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
|
|
import { Metadata } from '@grpc/grpc-js';
|
|
import { lastValueFrom } from 'rxjs';
|
|
import { ShareMetadataService } from 'src/modules/share-metadata/share-metadata.service';
|
|
import { isJWT } from 'class-validator';
|
|
import { MixpanelService } from 'src/modules/mixpanel/mixpanel.service';
|
|
import { Request } from 'express';
|
|
import jwt from 'jsonwebtoken';
|
|
import { AuthClientService } from 'src/modules/auth/auth.service';
|
|
|
|
|
|
export class ShareService implements OnModuleInit {
|
|
catalogReadService: ReadService.CatalogReadServices;
|
|
logger: DadosferaLogger;
|
|
|
|
constructor(
|
|
@Inject(DadosferaLogger)
|
|
dadosferaLogger: DadosferaLogger,
|
|
@Inject(CatalogClientConfiguration.name)
|
|
private readonly grpcClient: ClientGrpc,
|
|
private readonly userService: UsersService,
|
|
private readonly roleService: RolesService,
|
|
private readonly shareMetadataService: ShareMetadataService,
|
|
private readonly mixpanelService: MixpanelService,
|
|
private authClient: AuthClientService,
|
|
) {
|
|
this.logger = dadosferaLogger.logger;
|
|
}
|
|
|
|
onModuleInit() {
|
|
this.catalogReadService =
|
|
this.grpcClient.getService<ReadService.CatalogReadServices>(
|
|
ProtoServices.CatalogReadServices,
|
|
);
|
|
}
|
|
|
|
async getDatasetColumnsMetadata(id: string, request: Request) {
|
|
const shareMetadata = await this.getShareMetadata(id, request);
|
|
const metadata = PackTheMetadata({
|
|
customer_id: shareMetadata.customerId,
|
|
customer_name: shareMetadata.customerName,
|
|
});
|
|
const { columns_metadata } = await lastValueFrom(
|
|
this.catalogReadService.GetDatasetColumnsMetadata(
|
|
{ id: shareMetadata.assetId, type: undefined },
|
|
metadata,
|
|
),
|
|
);
|
|
const result = JSON.parse(columns_metadata);
|
|
return result;
|
|
}
|
|
|
|
async getDatasetPreview(id: string, request: Request) {
|
|
const shareMetadata = await this.getShareMetadata(id, request);
|
|
const metadata = PackTheMetadata({
|
|
customer_id: shareMetadata.customerId,
|
|
customer_name: shareMetadata.customerName,
|
|
});
|
|
const { preview } = await lastValueFrom(
|
|
this.catalogReadService.GetDatasetPreview(
|
|
{ id: shareMetadata.assetId, type: undefined },
|
|
metadata,
|
|
),
|
|
);
|
|
const result = JSON.parse(preview);
|
|
return result;
|
|
}
|
|
|
|
async getOneDataAssetPublic(id: string, request: Request) {
|
|
this.logger.info("getOneDataAssetPublic: " + JSON.stringify({
|
|
id
|
|
}))
|
|
try {
|
|
const user = await this.getUserFromRequest(request);
|
|
|
|
const shareMetadata = await this.getShareMetadata(id, request);
|
|
|
|
const mixpanelTracker = {
|
|
asset: shareMetadata.assetId,
|
|
type: isJWT(id) ? 'assigned' : shareMetadata.type,
|
|
customer: shareMetadata.customerName
|
|
}
|
|
|
|
if (user) {
|
|
await this.mixpanelService.track("share_page", user, request, mixpanelTracker);
|
|
} else {
|
|
await this.mixpanelService.trackShare(request, mixpanelTracker);
|
|
}
|
|
|
|
this.logger.info("shareMetadata: " + JSON.stringify(shareMetadata))
|
|
const metadata = PackTheMetadata({
|
|
customer_id: shareMetadata.customerId,
|
|
customer_name: shareMetadata.customerName,
|
|
});
|
|
|
|
const { data_asset } = await this.getOneDataAsset({
|
|
customer_id: shareMetadata.customerId,
|
|
id: shareMetadata.assetId,
|
|
metadata,
|
|
});
|
|
this.logger.info('found asset: ' + JSON.stringify(data_asset));
|
|
delete data_asset.p_roles;
|
|
delete data_asset.p_users;
|
|
data_asset.share_type = 'public';
|
|
if (data_asset.share_type !== 'public') throw new NotFoundException();
|
|
|
|
return { data_asset };
|
|
} catch (error) {
|
|
this.logger.error(error);
|
|
throw error;
|
|
}
|
|
|
|
}
|
|
|
|
private async getOneDataAsset(data: {
|
|
id: string;
|
|
customer_id: string;
|
|
metadata: Metadata;
|
|
}) {
|
|
const { customer_id, id, metadata } = data;
|
|
const { data_asset } = await lastValueFrom(
|
|
this.catalogReadService.GetOneDataAsset(
|
|
{ id, type: undefined },
|
|
metadata,
|
|
),
|
|
);
|
|
let asset = JSON.parse(data_asset);
|
|
asset = {
|
|
...asset,
|
|
p_roles: asset.roles,
|
|
p_users: asset.users,
|
|
};
|
|
asset = await this.getAssetsUsersAndRoles([asset], customer_id);
|
|
|
|
return { data_asset: asset[0] };
|
|
}
|
|
|
|
async getDataDocs(id: string, request: Request) {
|
|
const shareMetadata = await this.getShareMetadata(id, request);
|
|
const metadata = PackTheMetadata({
|
|
customer_id: shareMetadata.customerId,
|
|
customer_name: shareMetadata.customerName,
|
|
});
|
|
|
|
const { documentation } = await lastValueFrom(
|
|
this.catalogReadService.GetDatasetDoc({ id }, metadata),
|
|
);
|
|
console.log(documentation);
|
|
const docs = JSON.parse(documentation);
|
|
return docs;
|
|
}
|
|
|
|
private async getAssetsUsersAndRoles(
|
|
data_assets: Array<any>,
|
|
customer_id: string,
|
|
) {
|
|
const { users: customer_users } =
|
|
await this.userService.findAllUsersByCustomerId(customer_id);
|
|
const { roles: customer_roles } = await this.roleService.roleSearch(
|
|
{},
|
|
{ customer_id },
|
|
);
|
|
return data_assets.map((data_asset) => {
|
|
const owner = customer_users.find(
|
|
(u) => u.id === data_asset.owner,
|
|
)?.email;
|
|
|
|
const roles = [];
|
|
const users = [];
|
|
for (const role_id of data_asset.roles) {
|
|
const role = customer_roles.find((r) => r.id === role_id);
|
|
if (role) roles.push({ id: role.id, name: role.name });
|
|
}
|
|
for (const user_id of data_asset.users) {
|
|
const user = customer_users.find((r) => r.id === user_id);
|
|
if (user) users.push({ id: user.id, email: user.email });
|
|
}
|
|
return {
|
|
...data_asset,
|
|
roles,
|
|
users,
|
|
owner,
|
|
} as typeof data_asset;
|
|
});
|
|
}
|
|
|
|
|
|
private async getShareMetadata(id: string, request: Request) {
|
|
const metadata = PackTheMetadata({});
|
|
this.logger.info('GET share metadata')
|
|
const info = await this.shareMetadataService.get(id, metadata);
|
|
if (isJWT(id) && info ){
|
|
return info;
|
|
}
|
|
|
|
const user = await this.getUserFromRequest(request);
|
|
|
|
if (info.type === 'private') {
|
|
if (!user) {
|
|
throw new ForbiddenException(
|
|
'You do not have permission to access this data asset.',
|
|
);
|
|
}
|
|
|
|
const is_data_manager = user.permissions.includes(
|
|
PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER.seqid,
|
|
);
|
|
|
|
const is_get = user.permissions.includes(
|
|
PERMISSIONS_GROUPS.CATALOG.permissions.GET.seqid,
|
|
);
|
|
|
|
if (is_data_manager || is_get) {
|
|
return info;
|
|
}
|
|
|
|
throw new ForbiddenException(
|
|
'You do not have permission to access this data asset.',
|
|
);
|
|
}
|
|
return info;
|
|
}
|
|
|
|
private async getUserFromRequest(request: Request): Promise<RequestUser | null> {
|
|
const accessToken = request.get('Authorization');
|
|
if (accessToken) {
|
|
const accessTokenDecoded: any = jwt.decode(accessToken, {
|
|
complete: true,
|
|
});
|
|
|
|
const { kid } = accessTokenDecoded.header;
|
|
|
|
const { keys } = await this.authClient.getPublicKeys();
|
|
|
|
const pemValue = keys.find((key) => key.kid === kid);
|
|
|
|
if (!pemValue) {
|
|
return null;
|
|
}
|
|
|
|
jwt.verify(accessToken, pemValue.pem);
|
|
const accessTokenPayload = accessTokenDecoded.payload;
|
|
|
|
return {
|
|
user_id: accessTokenPayload.user_id,
|
|
username: accessTokenPayload.username,
|
|
permissions: accessTokenPayload.permissions,
|
|
customer_id: accessTokenPayload.customer_id,
|
|
customer_name: accessTokenPayload.customer_name,
|
|
customer_tier: accessTokenPayload.customer_tier,
|
|
customer_modules: accessTokenPayload.customer_modules,
|
|
access_token: accessToken,
|
|
};
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|