diff --git a/.eslintrc.json b/.eslintrc.json index d131be8c..eeca408f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,23 +1,17 @@ { - "env": { - "browser": true, - "es2021": true - }, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module" - }, - "plugins": [ - "@typescript-eslint" - ], - "rules": { - }, - "ignorePatterns": [ + "env": { + "browser": true, + "es2021": true + }, + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": ["@typescript-eslint"], + "rules": {}, + "ignorePatterns": [ "*-adapter.service.ts", "api.service.ts", "i-api-service.ts", @@ -27,6 +21,7 @@ "*.decorator.ts", "*.interceptor.ts", "*.directive.ts", - "i-any-object.ts"] + "i-any-object.ts", + "setenv.ts" + ] } - \ No newline at end of file diff --git a/Dockerfile.saas-ui b/Dockerfile.saas-ui new file mode 100644 index 00000000..ec183fff --- /dev/null +++ b/Dockerfile.saas-ui @@ -0,0 +1,39 @@ +# Using Node 10 Alpine image as the builder +FROM node:18-alpine as builder +ARG BASE_HREF + +#ARG ENV_CONFIG +# Setting Env Var Production as true +ENV PRODUCTION true + +RUN ls -la +# Creating a new dir for the app +RUN mkdir /ng-app +# Copying package.json (done to implement docker caching and speed up build) +COPY package.json package-lock.json ./ng-app/ +# Setting current working dir +WORKDIR /ng-app +# Setting npm config and cleaning cache +# RUN npm set progress=false && npm config set depth 0 && npm cache clean --force +# Installing node dependencies +RUN npm install +# Copying all files into the working dir +COPY . . + +# Creating a build version of the app for deployment +#RUN npm run build -- --configuration production +RUN npm run build saas-ui +# Using NGINX as the web server image +FROM sourcefuse/nginx:release-1.2.0 +# Replacing the defaut config of NGINX +COPY projects/saas-ui/nginx/default.conf /etc/nginx/conf.d/default.conf +# Removing unwanted files from the base NGINX folder +RUN rm -rf /usr/share/nginx/html/* +# Copying build files from the builder to the app's root dir +COPY --from=builder /ng-app/dist/saas-ui /usr/share/nginx/html +# Copying the startup script +COPY projects/saas-ui/docker/startup.sh /startup.sh +# Enabling executable rights on the script +RUN chmod +x startup.sh +# Running the startup script +CMD ["/bin/sh","-c","./startup.sh"] \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3fdfd55c..78e080c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "@nebular/theme": "^11.0.0", "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", - "@stripe/stripe-js": "^4.10.0", + "@stripe/stripe-js": "^4.9.0", "@types/lodash": "^4.14.194", "ag-grid-angular": "^31.3.1", "ag-grid-community": "^31.3.1", diff --git a/projects/arc-docs/src/app/docs/docs.module.ts b/projects/arc-docs/src/app/docs/docs.module.ts index 323a2dc7..095aa740 100644 --- a/projects/arc-docs/src/app/docs/docs.module.ts +++ b/projects/arc-docs/src/app/docs/docs.module.ts @@ -9,7 +9,7 @@ import {AuthService, CoreAuthModule} from '@project-lib/core/auth'; import {HttpClientModule} from '@angular/common/http'; import {NgxPermissionsService, NgxPermissionsStore} from 'ngx-permissions'; import {AuthModule} from '@project-lib/components/index'; -import {environment} from '@main-project/boiler/env/environment'; +import {environment} from '@project-lib/env/environment'; import {APP_CONFIG} from '@project-lib/app-config'; @NgModule({ diff --git a/projects/arc-lib/.env.example b/projects/arc-lib/.env.example new file mode 100644 index 00000000..01345aa6 --- /dev/null +++ b/projects/arc-lib/.env.example @@ -0,0 +1,15 @@ +LOG_LEVEL= +BASE_API_URL= +CLIENT_ID= +CLIENT_SECRET= +PUBLIC_KEY= +AUTH_SERVICE_URL= +USER_SERVICE_URL= +HOME_PATH= +HOME= +TENANT_MGMT_FACADE_URL= +TENANT_MGMT_SERVICE_URL= +SUBSCRIPTION_SERVICE_URL= +COGNITO_LOGOUT_URL= +STRIPE_PUBLIC_KEY= + diff --git a/projects/arc-lib/src/lib/assets/json/environment-template.json b/projects/arc-lib/src/lib/assets/json/environment-template.json index 4e2ab880..5e2ed37f 100644 --- a/projects/arc-lib/src/lib/assets/json/environment-template.json +++ b/projects/arc-lib/src/lib/assets/json/environment-template.json @@ -1,8 +1,17 @@ { + "production": "${PRODUCTION}", "baseApiUrl": "${BASE_API_URL}", "clientId": "${CLIENT_ID}", + "client_secret": "${CLIENT_SECRET_VALUE}", "publicKey": "${CLIENT_SECRET}", "cspApiUrl": "${CSP_API_URL}", "authServiceUrl": "${AUTH_SERVICE_URL}", - "userServiceUrl": "${USER_SERVICE_URL}" + "userServiceUrl": "${USER_SERVICE_URL}", + "homePath": "${HOME_PATH}", + "home": "${HOME_PATH}", + "tenantMgmtFacadeUrl": "${TENANT_MGMT_FACADE_URL}", + "tenantmgmtServiceUrl": "${TENANT_MGMT_SERVICE_URL}", + "subscriptionServiceUrl": "${SUBSCRIPTION_SERVICE_URL}", + "cognitoLogoutUrl": "${COGNITO_LOGOUT_URL}", + "stripePublicKey": "${STRIPE_PUBLIC_KEY}" } diff --git a/projects/arc-lib/src/lib/assets/json/environment.json b/projects/arc-lib/src/lib/assets/json/environment.json index 284b299b..5e2ed37f 100644 --- a/projects/arc-lib/src/lib/assets/json/environment.json +++ b/projects/arc-lib/src/lib/assets/json/environment.json @@ -1,8 +1,17 @@ { + "production": "${PRODUCTION}", "baseApiUrl": "${BASE_API_URL}", "clientId": "${CLIENT_ID}", + "client_secret": "${CLIENT_SECRET_VALUE}", "publicKey": "${CLIENT_SECRET}", "cspApiUrl": "${CSP_API_URL}", "authServiceUrl": "${AUTH_SERVICE_URL}", - "userServiceUrl": "${USER_SERVICE_URL}" -} \ No newline at end of file + "userServiceUrl": "${USER_SERVICE_URL}", + "homePath": "${HOME_PATH}", + "home": "${HOME_PATH}", + "tenantMgmtFacadeUrl": "${TENANT_MGMT_FACADE_URL}", + "tenantmgmtServiceUrl": "${TENANT_MGMT_SERVICE_URL}", + "subscriptionServiceUrl": "${SUBSCRIPTION_SERVICE_URL}", + "cognitoLogoutUrl": "${COGNITO_LOGOUT_URL}", + "stripePublicKey": "${STRIPE_PUBLIC_KEY}" +} diff --git a/projects/arc-lib/src/lib/core/auth/guards/logged-in.guard.ts b/projects/arc-lib/src/lib/core/auth/guards/logged-in.guard.ts index dc9e3e02..cfa90423 100644 --- a/projects/arc-lib/src/lib/core/auth/guards/logged-in.guard.ts +++ b/projects/arc-lib/src/lib/core/auth/guards/logged-in.guard.ts @@ -4,7 +4,7 @@ import {catchError, concatMap, Observable, of, tap} from 'rxjs'; import {AuthService} from '../auth.service'; import {SystemStoreFacadeService} from '@project-lib/core/store'; -import {environment} from '@main-project/boiler/env/environment'; +import {environment} from '@project-lib/env/environment'; @Injectable({ providedIn: 'root', diff --git a/projects/arc-lib/src/lib/core/store/adapters/env-adapter.service.ts b/projects/arc-lib/src/lib/core/store/adapters/env-adapter.service.ts index 772dfa98..efbc11ae 100644 --- a/projects/arc-lib/src/lib/core/store/adapters/env-adapter.service.ts +++ b/projects/arc-lib/src/lib/core/store/adapters/env-adapter.service.ts @@ -2,7 +2,7 @@ import {Injectable} from '@angular/core'; import {NgxLoggerLevel} from 'ngx-logger'; import {StoreModule} from '../store.module'; import {IAdapter} from '../../api'; -import {environment} from '@main-project/boiler/env/environment'; +import {environment} from '@project-lib/env/environment'; @Injectable({ providedIn: StoreModule, diff --git a/projects/arc-lib/src/lib/core/store/system-store-facade.service.ts b/projects/arc-lib/src/lib/core/store/system-store-facade.service.ts index 970509cb..b22af38b 100644 --- a/projects/arc-lib/src/lib/core/store/system-store-facade.service.ts +++ b/projects/arc-lib/src/lib/core/store/system-store-facade.service.ts @@ -11,7 +11,7 @@ import {GetEnvCommand} from './commands'; import {StoreKeys} from './store-keys.enum'; import {StoreModule} from './store.module'; import {ApiService} from '../api'; -import {environment} from '@main-project/boiler/env/environment.prod'; +import {environment} from '@project-lib/env/environment'; @Injectable({ providedIn: StoreModule, diff --git a/projects/arc-lib/src/lib/environment/environment.prod.ts b/projects/arc-lib/src/lib/environment/environment.prod.ts new file mode 100644 index 00000000..08555f26 --- /dev/null +++ b/projects/arc-lib/src/lib/environment/environment.prod.ts @@ -0,0 +1,17 @@ +export const environment = { + production: true, + clientId: '', + publicKey: '', + homePath: '/main/home', + baseApiUrl: '', + authServiceUrl: '', + userServiceUrl: '', + logLevel: 5, + client_secret: '', + home: '', + tenantMgmtFacadeUrl: '', + tenantmgmtServiceUrl: '', + subscriptionServiceUrl: '', + cognitoLogoutUrl: '', + stripePublicKey: '', +}; diff --git a/projects/arc-lib/src/lib/environment/environment.ts b/projects/arc-lib/src/lib/environment/environment.ts new file mode 100644 index 00000000..3b55ffda --- /dev/null +++ b/projects/arc-lib/src/lib/environment/environment.ts @@ -0,0 +1,17 @@ +export const environment = { + production: false, + clientId: '', + publicKey: '', + homePath: '/main/home', + baseApiUrl: '', + authServiceUrl: '', + userServiceUrl: '', + logLevel: 5, + client_secret: '', + home: '', + tenantMgmtFacadeUrl: '', + tenantmgmtServiceUrl: '', + subscriptionServiceUrl: '', + cognitoLogoutUrl: '', + stripePublicKey: '', +}; diff --git a/projects/saas-ui/docker/startup.sh b/projects/saas-ui/docker/startup.sh new file mode 100644 index 00000000..77d062b1 --- /dev/null +++ b/projects/saas-ui/docker/startup.sh @@ -0,0 +1,4 @@ +# Startup script to run when deploying the container +echo "Starting startup.sh script" +envsubst < "/usr/share/nginx/html/assets/json/environment-template.json" > "/usr/share/nginx/html/assets/json/environment.json" +nginx -g 'daemon off;' \ No newline at end of file diff --git a/projects/saas-ui/nginx/default.conf b/projects/saas-ui/nginx/default.conf new file mode 100644 index 00000000..ae9d3f3d --- /dev/null +++ b/projects/saas-ui/nginx/default.conf @@ -0,0 +1,47 @@ +# server { +# listen 80; +# listen [::]:80; +# sendfile on; +# default_type application/octet-stream; + +# gzip_static on; +# root /usr/share/nginx/html; + +# # Banner grabbing fix +# server_tokens off; + +# # Max File upload size +# client_max_body_size 250M; +# client_body_buffer_size 80k; +# client_header_buffer_size 80k; +# http2_max_field_size 80k; +# http2_max_header_size 80k; +# large_client_header_buffers 4 80k; +# proxy_buffers 4 160k; +# proxy_buffer_size 80k; +# proxy_busy_buffers_size 160k; + +# LOCATION_BLOCK_TO_REPLACE + +# location /status { +# vhost_traffic_status_display; +# vhost_traffic_status_display_format html; +# allow ::1; #only allow requests from localhost +# allow 127.0.0.1; #only allow requests from localhost +# deny all; #deny all other hosts +# } +# } + +server { + # Listen on port 80 for incoming HTTP requests. + listen 80; + # Define the location for serving static files. + location / { + # Set the root directory where NGINX will look for static files. + root /usr/share/nginx/html; + # Define the default files to serve if no specific file is requested. + index index.html index.htm; + # Define the behavior for handling URL requests. + try_files $uri $uri/ /index.html =404; + } +} \ No newline at end of file diff --git a/projects/saas-ui/scripts/setenv.ts b/projects/saas-ui/scripts/setenv.ts new file mode 100644 index 00000000..fbd7405c --- /dev/null +++ b/projects/saas-ui/scripts/setenv.ts @@ -0,0 +1,34 @@ +const {writeFile} = require('fs'); +const {argv} = require('yargs'); + +//reading env variables from .env file +require('dotenv').config(); + +const targetPath: string = + './projects/arc-lib/src/lib/assets/json/environment.json'; +//we can access the env variables +//in the process.env object + +const environmentFileContent = `{ + "logLevel": "${process.env['LOG_LEVEL'] ?? 5}", + "baseApiUrl": "${process.env['BASE_API_URL']}", + "clientId": "${process.env['CLIENT_ID']}", + "client_secret": "${process.env['CLIENT_SECRET']}", + "publicKey": "${process.env['PUBLIC_KEY']}", + "authServiceUrl": "${process.env['AUTH_SERVICE_URL']}", + "userServiceUrl": "${process.env['USER_SERVICE_URL']}", + "homePath": "${process.env['HOME_PATH']}", + "home": "${process.env['HOME']}", + "tenantMgmtFacadeUrl": "${process.env['TENANT_MGMT_FACADE_URL']}", + "tenantmgmtServiceUrl": "${process.env['TENANT_MGMT_SERVICE_URL']}", + "subscriptionServiceUrl": "${process.env['SUBSCRIPTION_SERVICE_URL']}", + "cognitoLogoutUrl": "${process.env['COGNITO_LOGOUT_URL']}", + "stripePublicKey": "${process.env['STRIPE_PUBLIC_KEY']}" +}`; +// writing content to the respective file +writeFile(targetPath, environmentFileContent, (err: unknown) => { + if (err) { + console.log(err); + } + console.log(`environment variables written to ${targetPath}`); +}); diff --git a/projects/saas-ui/src/app/app.module.ts b/projects/saas-ui/src/app/app.module.ts index e92ef668..eb2426c3 100644 --- a/projects/saas-ui/src/app/app.module.ts +++ b/projects/saas-ui/src/app/app.module.ts @@ -22,7 +22,7 @@ import {IconPacksManagerService} from '@project-lib/theme/services'; import {OnBoardingComponent} from './on-boarding/on-boarding.component'; import {NbLayoutModule, NbRadioModule} from '@nebular/theme'; import {AgGridModule} from 'ag-grid-angular'; -import {environment} from '../environment'; +import {environment} from '@project-lib/env/environment'; import {FeatureListService} from './shared/services/feature-list-service'; @NgModule({ diff --git a/projects/saas-ui/src/app/on-boarding/components/add-tenant/add-tenant.component.ts b/projects/saas-ui/src/app/on-boarding/components/add-tenant/add-tenant.component.ts index 581ffdc5..4e6a3c5f 100644 --- a/projects/saas-ui/src/app/on-boarding/components/add-tenant/add-tenant.component.ts +++ b/projects/saas-ui/src/app/on-boarding/components/add-tenant/add-tenant.component.ts @@ -3,6 +3,7 @@ import { AfterViewInit, Component, ElementRef, + Inject, OnInit, ViewChild, } from '@angular/core'; @@ -10,11 +11,12 @@ import {FormBuilder, FormGroup, Validators} from '@angular/forms'; import {ActivatedRoute, Router} from '@angular/router'; import {NbToastrService} from '@nebular/theme'; import {AnyObject} from '@project-lib/core/api'; -import {environment} from 'projects/saas-ui/src/environment'; import {Lead} from '../../../shared/models'; import {BillingPlanService} from '../../../shared/services/billing-plan-service'; import {OnBoardingService} from '../../../shared/services/on-boarding-service'; import {Stripe} from '@stripe/stripe-js'; +import {APP_CONFIG} from '@project-lib/app-config'; +import {IAnyObject} from '@project-lib/core/i-any-object'; declare let Stripe: (key: string) => Stripe; @Component({ @@ -40,6 +42,7 @@ export class AddTenantComponent implements OnInit, AfterViewInit { private fb: FormBuilder, private onboardingService: OnBoardingService, private billingPlanService: BillingPlanService, + @Inject(APP_CONFIG) private readonly appConfig: IAnyObject, ) { this.addTenantForm = this.fb.group({ key: [ @@ -68,7 +71,7 @@ export class AddTenantComponent implements OnInit, AfterViewInit { } ngAfterViewInit() { - this.stripe = Stripe(environment.stripePublicKey); // Initialize Stripe + this.stripe = Stripe(this.appConfig.stripePublicKey); // Initialize Stripe const elements = this.stripe.elements(); // Initialize the card element for payment details diff --git a/projects/saas-ui/src/app/on-boarding/guards/email-verify.guard.ts b/projects/saas-ui/src/app/on-boarding/guards/email-verify.guard.ts index 5f7faee6..8527aec0 100644 --- a/projects/saas-ui/src/app/on-boarding/guards/email-verify.guard.ts +++ b/projects/saas-ui/src/app/on-boarding/guards/email-verify.guard.ts @@ -4,8 +4,11 @@ import { CanActivate, RouterStateSnapshot, } from '@angular/router'; -import {UserSessionStoreService} from '@project-lib/core/index'; -import {Observable, catchError, map, of, tap} from 'rxjs'; +import { + SystemStoreFacadeService, + UserSessionStoreService, +} from '@project-lib/core/index'; +import {Observable, catchError, map, of, switchMap} from 'rxjs'; import {OnBoardingService} from '../../shared/services/on-boarding-service'; @Injectable({ @@ -15,6 +18,7 @@ export class EmailVerifyGuard implements CanActivate { constructor( private readonly onboardingService: OnBoardingService, private readonly store: UserSessionStoreService, + private readonly systemStore: SystemStoreFacadeService, ) {} canActivate( @@ -26,16 +30,21 @@ export class EmailVerifyGuard implements CanActivate { const leadId = route.params['leadId']; if (code) { - return this.onboardingService.validateEmail(code, leadId).pipe( - map(response => { - if (response.token) { - this.store.saveAccessToken(response.token); - return true; - } else return false; - }), - catchError(err => { - console.log(err); - throw err; + return this.systemStore.getEnvConfig().pipe( + switchMap(() => { + return this.onboardingService.validateEmail(code, leadId).pipe( + map(response => { + if (response.token) { + this.store.saveAccessToken(response.token); + return true; + } + return false; + }), + catchError(err => { + console.log(err); + return of(false); // guards must return boolean + }), + ); }), ); } diff --git a/projects/saas-ui/src/assets/json/environment-template.json b/projects/saas-ui/src/assets/json/environment-template.json new file mode 100644 index 00000000..5e2ed37f --- /dev/null +++ b/projects/saas-ui/src/assets/json/environment-template.json @@ -0,0 +1,17 @@ +{ + "production": "${PRODUCTION}", + "baseApiUrl": "${BASE_API_URL}", + "clientId": "${CLIENT_ID}", + "client_secret": "${CLIENT_SECRET_VALUE}", + "publicKey": "${CLIENT_SECRET}", + "cspApiUrl": "${CSP_API_URL}", + "authServiceUrl": "${AUTH_SERVICE_URL}", + "userServiceUrl": "${USER_SERVICE_URL}", + "homePath": "${HOME_PATH}", + "home": "${HOME_PATH}", + "tenantMgmtFacadeUrl": "${TENANT_MGMT_FACADE_URL}", + "tenantmgmtServiceUrl": "${TENANT_MGMT_SERVICE_URL}", + "subscriptionServiceUrl": "${SUBSCRIPTION_SERVICE_URL}", + "cognitoLogoutUrl": "${COGNITO_LOGOUT_URL}", + "stripePublicKey": "${STRIPE_PUBLIC_KEY}" +} diff --git a/projects/saas-ui/src/assets/json/environment.json b/projects/saas-ui/src/assets/json/environment.json new file mode 100644 index 00000000..5e2ed37f --- /dev/null +++ b/projects/saas-ui/src/assets/json/environment.json @@ -0,0 +1,17 @@ +{ + "production": "${PRODUCTION}", + "baseApiUrl": "${BASE_API_URL}", + "clientId": "${CLIENT_ID}", + "client_secret": "${CLIENT_SECRET_VALUE}", + "publicKey": "${CLIENT_SECRET}", + "cspApiUrl": "${CSP_API_URL}", + "authServiceUrl": "${AUTH_SERVICE_URL}", + "userServiceUrl": "${USER_SERVICE_URL}", + "homePath": "${HOME_PATH}", + "home": "${HOME_PATH}", + "tenantMgmtFacadeUrl": "${TENANT_MGMT_FACADE_URL}", + "tenantmgmtServiceUrl": "${TENANT_MGMT_SERVICE_URL}", + "subscriptionServiceUrl": "${SUBSCRIPTION_SERVICE_URL}", + "cognitoLogoutUrl": "${COGNITO_LOGOUT_URL}", + "stripePublicKey": "${STRIPE_PUBLIC_KEY}" +} diff --git a/projects/saas-ui/src/environment.ts b/projects/saas-ui/src/environment.ts index f5002606..487279a1 100644 --- a/projects/saas-ui/src/environment.ts +++ b/projects/saas-ui/src/environment.ts @@ -12,4 +12,5 @@ export const environment = { tenantmgmtServiceUrl: '', subscriptionServiceUrl: '', cognitoLogoutUrl: '', + stripePublicKey: '', }; diff --git a/tsconfig.json b/tsconfig.json index 5e4b0631..86947ae1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,7 @@ "lib": ["ES2019", "dom"], "useDefineForClassFields": false, "paths": { - "@main-project/boiler/env/*": ["projects/arc/src/environments/*"], + "@project-lib/env/*": ["projects/arc-lib/src/lib/environment/*"], "@main-project/boiler/*": ["projects/arc/src/app/*"], "@project-lib/core/*": ["projects/arc-lib/src/lib/core/*"], "@project-lib/components/*": ["projects/arc-lib/src/lib/components/*"],