diff --git a/.github/workflows/CD-time-tracker-ui.yml b/.github/workflows/CD-time-tracker-ui.yml index 195572bed..2f2a7c666 100644 --- a/.github/workflows/CD-time-tracker-ui.yml +++ b/.github/workflows/CD-time-tracker-ui.yml @@ -29,7 +29,11 @@ jobs: SCOPES: ${{ secrets.scopes }} CLIENT_ID: ${{ secrets.client_id }} AUTHORITY: ${{ secrets.authority }} - run: sudo sh scripts/populate-keys.sh + STACK_EXCHANGE_ID: ${{ secrets.stack_exchange_id }} + STACK_EXCHANGE_ACCESS_TOKEN: ${{ secrets.stack_exchange_access_token }} + run: | + chmod +x ./scripts/populate-keys.sh + sh ./scripts/populate-keys.sh - name: 'run: npm install and build' run: | diff --git a/.github/workflows/CI-mutation-tests.yml b/.github/workflows/CI-mutation-tests.yml index c1ee543a6..264dfe2a5 100644 --- a/.github/workflows/CI-mutation-tests.yml +++ b/.github/workflows/CI-mutation-tests.yml @@ -26,6 +26,8 @@ jobs: SCOPES: ${{ secrets.scopes }} CLIENT_ID: ${{ secrets.client_id }} AUTHORITY: ${{ secrets.authority }} + STACK_EXCHANGE_ID: ${{ secrets.stack_exchange_id }} + STACK_EXCHANGE_ACCESS_TOKEN: ${{ secrets.stack_exchange_access_token }} run: sudo sh scripts/populate-keys.sh - name: Run the test diff --git a/.github/workflows/CI-time-tracker-ui.yml b/.github/workflows/CI-time-tracker-ui.yml index d6e26e465..df3f2c3fa 100644 --- a/.github/workflows/CI-time-tracker-ui.yml +++ b/.github/workflows/CI-time-tracker-ui.yml @@ -44,12 +44,14 @@ jobs: SCOPES: ${{ secrets.scopes }} CLIENT_ID: ${{ secrets.client_id }} AUTHORITY: ${{ secrets.authority }} + STACK_EXCHANGE_ID: ${{ secrets.stack_exchange_id }} + STACK_EXCHANGE_ACCESS_TOKEN: ${{ secrets.stack_exchange_access_token }} run: sudo sh scripts/populate-keys.sh - name: Run the test run: npm run ci-test --if-present - name: Generate coverage report - env: + env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} run: bash <(curl -s https://codecov.io/bash) diff --git a/README.md b/README.md index f1c637de0..7abe9e04a 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,8 @@ Create a file keys.ts with the content pinned in our slack channel: export const AUTHORITY = 'XXX'; export const CLIENT_ID = 'XXX'; export const SCOPES = ['XXX']; +export const STACK_EXCHANGE_ID = 'XXX'; +export const STACK_EXCHANGE_ACCESS_TOKEN = 'XXX'; ``` ### Prepare your environment for vscode diff --git a/package-lock.json b/package-lock.json index c590736d2..df0b73483 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "time-tracker", - "version": "1.0.7", + "version": "1.0.9", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6af4ef87a..7807817fa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "time-tracker", - "version": "1.0.7", + "version": "1.0.9", "scripts": { "ng": "ng", "start": "ng serve", diff --git a/scripts/populate-keys.sh b/scripts/populate-keys.sh index 66239f278..614ff3e38 100644 --- a/scripts/populate-keys.sh +++ b/scripts/populate-keys.sh @@ -4,3 +4,6 @@ echo 'export const AUTHORITY = "'$AUTHORITY'";' >> src/environments/keys.ts echo 'export const CLIENT_ID = "'$CLIENT_ID'";' >> src/environments/keys.ts echo 'export const SCOPES = ["'$SCOPES'"];' >> src/environments/keys.ts +echo 'export const STACK_EXCHANGE_ID = "'$STACK_EXCHANGE_ID'";' >> src/environments/keys.ts +echo 'export const STACK_EXCHANGE_ACCESS_TOKEN = "'$STACK_EXCHANGE_ACCESS_TOKEN'";' >> src/environments/keys.ts +cat src/environments/keys.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 1c8664b38..89e7d1029 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -32,6 +32,7 @@ import { HomeComponent } from './modules/home/home.component'; import { LoginComponent } from './modules/login/login.component'; import { ActivityEffects } from './modules/activities-management/store/activity-management.effects'; import { ProjectEffects } from './modules/project-management/store/project.effects'; +import { TechnologyEffects } from './modules/shared/store/technology.effects'; import { reducers, metaReducers } from './reducers'; import { environment } from '../environments/environment'; import { CustomerComponent } from './modules/customer-managment/pages/customer.component'; @@ -99,7 +100,7 @@ import { CreateProjectTypeComponent } from './modules/customer-managment/compone maxAge: 15, // Retains last 15 states }) : [], - EffectsModule.forRoot([ProjectEffects, ActivityEffects]), + EffectsModule.forRoot([ProjectEffects, ActivityEffects, TechnologyEffects]), ], providers: [], bootstrap: [AppComponent], diff --git a/src/app/modules/login/services/azure.ad.b2c.service.spec.ts b/src/app/modules/login/services/azure.ad.b2c.service.spec.ts index ed091da69..935d8dab6 100644 --- a/src/app/modules/login/services/azure.ad.b2c.service.spec.ts +++ b/src/app/modules/login/services/azure.ad.b2c.service.spec.ts @@ -5,6 +5,19 @@ import { UserAgentApplication, Account } from 'msal'; describe('AzureAdB2CService', () => { let service: AzureAdB2CService; + const account: Account = { + accountIdentifier: 'abc', + homeAccountIdentifier: 'abc', + userName: 'abc', + name: 'abc', + idToken: { + iss: ' http://hostname.com/12345/v0/', + }, + idTokenClaims: {}, + sid: 'abc', + environment: 'abc', + }; + beforeEach(() => { TestBed.configureTestingModule({ imports: [], @@ -33,16 +46,6 @@ describe('AzureAdB2CService', () => { }); it('should get Account name from UserAgentApplication', () => { - const account: Account = { - accountIdentifier: 'abc', - homeAccountIdentifier: 'abc', - userName: 'abc', - name: 'abc', - idToken: {}, - idTokenClaims: {}, - sid: 'abc', - environment: 'abc', - }; spyOn(UserAgentApplication.prototype, 'getAccount').and.returnValues(account); const name = service.getName(); @@ -52,16 +55,6 @@ describe('AzureAdB2CService', () => { }); it('isLogin returns true if UserAgentApplication has a defined Account', () => { - const account: Account = { - accountIdentifier: 'abc', - homeAccountIdentifier: 'abc', - userName: 'abc', - name: 'abc', - idToken: {}, - idTokenClaims: {}, - sid: 'abc', - environment: 'abc', - }; spyOn(UserAgentApplication.prototype, 'getAccount').and.returnValue(account); const isLogin = service.isLogin(); @@ -76,4 +69,45 @@ describe('AzureAdB2CService', () => { expect(UserAgentApplication.prototype.getAccount).toHaveBeenCalled(); expect(isLogin).toEqual(false); }); + + it('setTenantId should save a tenantId in session storage', () => { + spyOn(UserAgentApplication.prototype, 'getAccount').and.returnValue(account); + spyOn(sessionStorage, 'setItem').withArgs('tenant_id', '12345'); + + const isLogin = service.isLogin(); + service.setTenantId(); + + expect(UserAgentApplication.prototype.getAccount).toHaveBeenCalled(); + expect(isLogin).toEqual(true); + expect(sessionStorage.setItem).toHaveBeenCalledWith('tenant_id', '12345'); + }); + + it('setTenantId should not save tenantId if login is false ', () => { + spyOn(UserAgentApplication.prototype, 'getAccount').and.returnValue(null); + spyOn(sessionStorage, 'setItem'); + const isLogin = service.isLogin(); + expect(UserAgentApplication.prototype.getAccount).toHaveBeenCalled(); + expect(isLogin).toEqual(false); + expect(sessionStorage.setItem).not.toHaveBeenCalled(); + }); + + it('getTenantId should get the tenantId from session storage', () => { + const tenantId = '12345'; + spyOn(sessionStorage, 'getItem').and.returnValue(tenantId); + + const resp = service.getTenantId(); + + expect(sessionStorage.getItem).toHaveBeenCalled(); + expect(resp).toEqual(tenantId); + }); + + it('getBearerToken should get the bearer token from session storage', () => { + const token = '12345abc'; + spyOn(sessionStorage, 'getItem').and.returnValue(token); + + const resp = service.getBearerToken(); + + expect(sessionStorage.getItem).toHaveBeenCalled(); + expect(resp).toEqual(token); + }); }); diff --git a/src/app/modules/login/services/azure.ad.b2c.service.ts b/src/app/modules/login/services/azure.ad.b2c.service.ts index da0c4a9d7..3f2966682 100644 --- a/src/app/modules/login/services/azure.ad.b2c.service.ts +++ b/src/app/modules/login/services/azure.ad.b2c.service.ts @@ -4,21 +4,19 @@ import { CLIENT_ID, AUTHORITY, SCOPES } from '../../../../environments/environme import { UserAgentApplication } from 'msal'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) - export class AzureAdB2CService { - msalConfig = { auth: { clientId: CLIENT_ID, authority: AUTHORITY, - validateAuthority: false - } + validateAuthority: false, + }, }; tokenRequest = { - scopes: SCOPES + scopes: SCOPES, }; msal = new UserAgentApplication(this.msalConfig); @@ -38,4 +36,19 @@ export class AzureAdB2CService { isLogin() { return this.msal.getAccount() ? true : false; } + + setTenantId() { + if (this.msal.getAccount() && this.msal.getAccount().idToken) { + const pathArray = this.msal.getAccount().idToken.iss.split('/'); + const tenantId = pathArray[3]; + sessionStorage.setItem('tenant_id', tenantId); + } + } + + getTenantId(): string { + return sessionStorage.getItem('tenant_id'); + } + getBearerToken(): string { + return sessionStorage.getItem('msal.idtoken'); + } } diff --git a/src/app/modules/shared/components/details-fields/details-fields.component.html b/src/app/modules/shared/components/details-fields/details-fields.component.html index 66a747528..a1d5012ae 100644 --- a/src/app/modules/shared/components/details-fields/details-fields.component.html +++ b/src/app/modules/shared/components/details-fields/details-fields.component.html @@ -36,18 +36,38 @@ aria-describedby="inputGroup-sizing-sm" /> -