import { getRolesFromRights , Role } from '@energyweb/origin-backend-core' ; import { DatabaseService } from '@energyweb/origin-backend-utils' ; import { recoverTypedSignatureAddress , signTypedMessagePrivateKey } from '@energyweb/utils-general' ; import { HttpStatus , INestApplication } from '@nestjs/common' ; import { expect } from 'chai' ; import crypto from 'crypto' ; import { utils , Wallet } from 'ethers' ; import request from 'supertest' ; import { InvitationDTO } from '../src/pods/invitation/invitation.dto' ; import { NewOrganizationDTO , Organization } from '../src/pods/organization' ; import { PublicOrganizationInfoDTO } from '../src/pods/organization/dto/public-organization-info.dto' ; import { OrganizationService } from '../src/pods/organization/organization.service' ; import { TUserBaseEntity , UserService } from '../src/pods/user' ; import { bootstrapTestInstance , getExampleOrganization , loginUser , registerAndLogin } from './origin-backend' ; import { userToRegister } from './user.e2e-spec' ; describe ( 'Organization e2e tests' , ( ) => { let app ; let databaseService ; let organizationService ; let userService ; before ( async ( ) => { try { ( { app , databaseService , organizationService , userService } = await bootstrapTestInstance ( ) ) ; await app . init ( ) ; } catch ( e ) { console . error ( e ) ; } } ) ; beforeEach ( async ( ) => { await databaseService . truncate ( 'user' , 'platform_organization' ) ; } ) ; after ( async ( ) => { await app . close ( ) ; } ) ; it ( 'should allow platform owner to read all organizations' , async ( ) => { const { accessToken , organization } = await registerAndLogin ( app , userService , organizationService , [ Role . Admin ] ) ; await request ( app . getHttpServer ( ) ) . get ( '/organization' ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . OK ) . expect ( ( res ) => { const [ org ] = res . body as PublicOrganizationInfoDTO [ ] ; expect ( org . id ) . to . be . equal ( organization . id ) ; } ) ; } ) ; it ( 'should be able to remove organization member when organization admin' , async ( ) => { const { accessToken : adminAccessToken , organization } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationAdmin ] ) ; const { user : member , accessToken : memberAccessToken } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationUser ] , 'member' ) ; await request ( app . getHttpServer ( ) ) . put ( `/organization/${ organization . id }/remove-member/${ member . id }` ) . set ( 'Authorization' , `Bearer ${ adminAccessToken }` ) . expect ( HttpStatus . OK ) ; await request ( app . getHttpServer ( ) ) . get ( `/user/me` ) . set ( 'Authorization' , `Bearer ${ memberAccessToken }` ) . expect ( HttpStatus . OK ) . expect ( ( res ) => { const { organization : memberOrganization } = res . body as TUserBaseEntity ; expect ( memberOrganization ) . to . be . null ; } ) ; } ) ; it ( 'should be able to get invitations for organization' , async ( ) => { const { accessToken , organization } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationAdmin ] ) ; const newUserEmail = 'newuser@example.com' ; await request ( app . getHttpServer ( ) ) . post ( '/invitation' ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . send ( { email : newUserEmail , role : Role . OrganizationUser } ) . expect ( HttpStatus . CREATED ) ; await request ( app . getHttpServer ( ) ) . get ( `/organization/${ organization . id }/invitations` ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . OK ) . expect ( ( res ) => { const [ invitation ] = res . body as InvitationDTO [ ] ; expect ( invitation . email ) . to . equal ( newUserEmail ) ; expect ( invitation . role ) . to . equal ( Role . OrganizationUser ) ; } ) ; } ) ; it ( 'should fail to get invitations for different organization' , async ( ) => { const { accessToken , organization } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationAdmin ] ) ; await request ( app . getHttpServer ( ) ) . get ( `/organization/${ organization . id + 1 }/invitations` ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . FORBIDDEN ) ; } ) ; it ( 'should be able to change role for organization member when organization admin' , async ( ) => { const { accessToken : adminAccessToken , organization } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationAdmin ] ) ; const { user : member , accessToken : memberAccessToken } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationUser ] , 'member' ) ; await request ( app . getHttpServer ( ) ) . put ( `/organization/${ organization . id }/change-role/${ member . id }` ) . set ( 'Authorization' , `Bearer ${ adminAccessToken }` ) . send ( { role : Role . OrganizationDeviceManager } ) . expect ( HttpStatus . OK ) ; await request ( app . getHttpServer ( ) ) . get ( `/user/me` ) . set ( 'Authorization' , `Bearer ${ memberAccessToken }` ) . expect ( HttpStatus . OK ) . expect ( ( res ) => { const { rights } = res . body as TUserBaseEntity ; expect ( getRolesFromRights ( rights ) ) . contain ( Role . OrganizationDeviceManager ) ; } ) ; } ) ; it ( 'should not be able to change role for admin or support when organization admin' , async ( ) => { const { accessToken : adminAccessToken , organization } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationAdmin ] ) ; const { user : member } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationUser ] , 'member' ) ; await request ( app . getHttpServer ( ) ) . put ( `/organization/${ organization . id }/change-role/${ member . id }` ) . set ( 'Authorization' , `Bearer ${ adminAccessToken }` ) . send ( { role : Role . Admin } ) . expect ( HttpStatus . FORBIDDEN ) ; await request ( app . getHttpServer ( ) ) . put ( `/organization/${ organization . id }/change-role/${ member . id }` ) . set ( 'Authorization' , `Bearer ${ adminAccessToken }` ) . send ( { role : Role . SupportAgent } ) . expect ( HttpStatus . FORBIDDEN ) ; await request ( app . getHttpServer ( ) ) . put ( `/organization/${ organization . id }/change-role/${ member . id }` ) . set ( 'Authorization' , `Bearer ${ adminAccessToken }` ) . send ( { role : Role . Issuer } ) . expect ( HttpStatus . FORBIDDEN ) ; } ) ; it ( 'should be able to see information about own organization' , async ( ) => { const { accessToken , organization } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationUser ] ) ; await request ( app . getHttpServer ( ) ) . get ( `/organization/${ organization . id }` ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . OK ) ; } ) ; it ( 'should be not able to see information about a different organization' , async ( ) => { const { accessToken } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationUser ] ) ; const { organization : org2 } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationUser ] , 'org2' , 'org2' ) ; await request ( app . getHttpServer ( ) ) . get ( `/organization/${ org2 . id }` ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . FORBIDDEN ) ; } ) ; it ( 'should return all organizations if Admin or Support Agent' , async ( ) => { const { accessToken } = await registerAndLogin ( app , userService , organizationService , [ Role . Admin ] ) ; await request ( app . getHttpServer ( ) ) . get ( `/organization` ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . OK ) ; const { accessToken : accessToken2 } = await registerAndLogin ( app , userService , organizationService , [ Role . SupportAgent ] ) ; await request ( app . getHttpServer ( ) ) . get ( `/organization` ) . set ( 'Authorization' , `Bearer ${ accessToken2 }` ) . expect ( HttpStatus . OK ) ; } ) ; it ( 'should not return all organizations if not Admin or Support Agent' , async ( ) => { const { accessToken } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationUser , Role . OrganizationDeviceManager , Role . OrganizationAdmin ] ) ; await request ( app . getHttpServer ( ) ) . get ( `/organization` ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . FORBIDDEN ) ; } ) ; it ( 'should be able to register organization before being approved user' , async ( ) => { await request ( app . getHttpServer ( ) ) . post ( `/user/register` ) . send ( userToRegister ) . expect ( HttpStatus . CREATED ) ; const accessToken = await loginUser ( app , userToRegister . email , userToRegister . password ) ; const organization = getExampleOrganization ( ) ; await request ( app . getHttpServer ( ) ) . post ( `/organization` ) . send ( organization ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . CREATED ) ; } ) ; it ( 'should not be able to register organization where name was already taken' , async ( ) => { await request ( app . getHttpServer ( ) ) . post ( `/user/register` ) . send ( userToRegister ) . expect ( HttpStatus . CREATED ) ; const accessToken = await loginUser ( app , userToRegister . email , userToRegister . password ) ; const organization = getExampleOrganization ( ) ; await request ( app . getHttpServer ( ) ) . post ( `/organization` ) . send ( organization ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . CREATED ) ; const otherUser = { ... userToRegister , email : 'other@example.com' } ; await request ( app . getHttpServer ( ) ) . post ( `/user/register` ) . send ( otherUser ) . expect ( HttpStatus . CREATED ) ; const otherUserAccessToken = await loginUser ( app , otherUser . email , otherUser . password ) ; await request ( app . getHttpServer ( ) ) . post ( `/organization` ) . send ( organization ) . set ( 'Authorization' , `Bearer ${ otherUserAccessToken }` ) . expect ( HttpStatus . BAD_REQUEST ) ; } ) ; it ( 'should be able to register organization if already part of an organization' , async ( ) => { const { accessToken } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationAdmin ] ) ; const organization = getExampleOrganization ( ) ; await request ( app . getHttpServer ( ) ) . post ( `/organization` ) . send ( { ... organization , name : 'Other organization name' } ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . FORBIDDEN ) ; } ) ; it ( 'should be able to register organization with documents' , async ( ) => { await request ( app . getHttpServer ( ) ) . post ( `/user/register` ) . send ( userToRegister ) . expect ( HttpStatus . CREATED ) ; const accessToken = await loginUser ( app , userToRegister . email , userToRegister . password ) ; const blob = crypto . randomBytes ( 16 ) ; let fileId1 ; let fileId2 ; await request ( app . getHttpServer ( ) ) . post ( '/file' ) . attach ( 'files' , blob , { filename : 'blob.pdf' , contentType : 'application/pdf' } ) . attach ( 'files' , blob , { filename : 'blob2.pdf' , contentType : 'application/pdf' } ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( ( res ) => { [ fileId1 , fileId2 ] = res . body as string [ ] ; } ) ; const organization = getExampleOrganization ( ) ; await request ( app . getHttpServer ( ) ) . post ( `/organization` ) . send ( { ... organization , documentIds : [ fileId1 ] , signatoryDocumentIds : [ fileId2 ] } as NewOrganizationDTO ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . CREATED ) . expect ( ( res ) => { const org = res . body as Organization ; expect ( org . name ) . to . be . equal ( organization . name ) ; expect ( org . documentIds ) . to . be . deep . equal ( [ fileId1 ] ) ; expect ( org . signatoryDocumentIds ) . to . be . deep . equal ( [ fileId2 ] ) ; } ) ; } ) ; it ( 'should not be able to register organization with non existing documents' , async ( ) => { await request ( app . getHttpServer ( ) ) . post ( `/user/register` ) . send ( userToRegister ) . expect ( HttpStatus . CREATED ) ; const accessToken = await loginUser ( app , userToRegister . email , userToRegister . password ) ; const organization = getExampleOrganization ( ) ; await request ( app . getHttpServer ( ) ) . post ( `/organization` ) . send ( { ... organization , documentIds : [ '6ae855ca-8115-476e-9dfe-f6a23ede7959' ] } as NewOrganizationDTO ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . FORBIDDEN ) ; await request ( app . getHttpServer ( ) ) . post ( `/organization` ) . send ( { ... organization , signatoryDocumentIds : [ '6ae855ca-8115-476e-9dfe-f6a23ede7959' ] } as NewOrganizationDTO ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . FORBIDDEN ) ; } ) ; it ( 'should not be able to register organization with documents that belong to other user' , async ( ) => { await request ( app . getHttpServer ( ) ) . post ( `/user/register` ) . send ( userToRegister ) . expect ( HttpStatus . CREATED ) ; const accessToken = await loginUser ( app , userToRegister . email , userToRegister . password ) ; const blob = crypto . randomBytes ( 16 ) ; let fileId ; await request ( app . getHttpServer ( ) ) . post ( '/file' ) . attach ( 'files' , blob , { filename : 'blob.pdf' , contentType : 'application/pdf' } ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( ( res ) => { [ fileId ] = res . body as string [ ] ; } ) ; const otherUserEmail = 'other@example.com' ; await request ( app . getHttpServer ( ) ) . post ( `/user/register` ) . send ( { ... userToRegister , email : otherUserEmail } ) . expect ( HttpStatus . CREATED ) ; const otherUserAccessToken = await loginUser ( app , otherUserEmail , userToRegister . password ) ; const organization = getExampleOrganization ( ) ; await request ( app . getHttpServer ( ) ) . post ( `/organization` ) . send ( { ... organization , documentIds : [ fileId ] } as NewOrganizationDTO ) . set ( 'Authorization' , `Bearer ${ otherUserAccessToken }` ) . expect ( HttpStatus . FORBIDDEN ) ; } ) ; it ( 'should be able to set blockchain address before being approved user' , async ( ) => { const { accessToken } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationUser ] ) ; const wallet = Wallet . createRandom ( ) ; const signedMessage = await signTypedMessagePrivateKey ( wallet . privateKey . substring ( 2 ) , process . env . REGISTRATION_MESSAGE_TO_SIGN ) ; await request ( app . getHttpServer ( ) ) . post ( `/organization/chain-address` ) . send ( { signedMessage } ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . CREATED ) ; } ) ; it ( 'metamask blockchain address should match' , async ( ) => { const wallet = Wallet . createRandom ( ) ; const signedMessage = await signTypedMessagePrivateKey ( wallet . privateKey . substring ( 2 ) , process . env . REGISTRATION_MESSAGE_TO_SIGN ) ; const originatingAddress = await recoverTypedSignatureAddress ( process . env . REGISTRATION_MESSAGE_TO_SIGN , signedMessage ) ; const checksummedOriginatingAddress = utils . getAddress ( originatingAddress ) ; expect ( checksummedOriginatingAddress ) . to . equal ( wallet . address ) ; } ) ; it ( 'should not be able to set blockchain address before user is a part of an organization' , async ( ) => { await request ( app . getHttpServer ( ) ) . post ( `/user/register` ) . send ( userToRegister ) . expect ( HttpStatus . CREATED ) ; const accessToken = await loginUser ( app , userToRegister . email , userToRegister . password ) ; const wallet = Wallet . createRandom ( ) ; const signedMessage = await signTypedMessagePrivateKey ( wallet . privateKey . substring ( 2 ) , process . env . REGISTRATION_MESSAGE_TO_SIGN ) ; await request ( app . getHttpServer ( ) ) . post ( `/organization/chain-address` ) . send ( { signedMessage } ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . NOT_FOUND ) ; } ) ; it ( 'should not be able to change blockchain address' , async ( ) => { const { accessToken } = await registerAndLogin ( app , userService , organizationService , [ Role . OrganizationUser ] ) ; const wallet = Wallet . createRandom ( ) ; const signedMessage = await signTypedMessagePrivateKey ( wallet . privateKey . substring ( 2 ) , process . env . REGISTRATION_MESSAGE_TO_SIGN ) ; await request ( app . getHttpServer ( ) ) . post ( `/organization/chain-address` ) . send ( { signedMessage } ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . CREATED ) ; await request ( app . getHttpServer ( ) ) . post ( `/organization/chain-address` ) . send ( { signedMessage } ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . CONFLICT ) ; } ) ; it ( 'admin should be able to change blockchain address' , async ( ) => { const { organization , accessToken } = await registerAndLogin ( app , userService , organizationService , [ Role . Admin ] ) ; const wallet = Wallet . createRandom ( ) ; const signedMessage = await signTypedMessagePrivateKey ( wallet . privateKey . substring ( 2 ) , process . env . REGISTRATION_MESSAGE_TO_SIGN ) ; await request ( app . getHttpServer ( ) ) . post ( `/organization/chain-address` ) . send ( { signedMessage } ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . CREATED ) ; await request ( app . getHttpServer ( ) ) . put ( `/admin/organization/${ organization . id }/chain-address` ) . send ( { address : wallet . address } ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . CONFLICT ) ; await request ( app . getHttpServer ( ) ) . put ( `/admin/organization/${ organization . id }/chain-address` ) . send ( { address : Wallet . createRandom ( ) . address } ) . set ( 'Authorization' , `Bearer ${ accessToken }` ) . expect ( HttpStatus . OK ) ; } ) ; } ) ;