????

Your IP : 216.73.216.157


Current Path : C:/opt/pgsql/pgAdmin 4/web/pgadmin/misc/cloud/static/js/
Upload File :
Current File : C:/opt/pgsql/pgAdmin 4/web/pgadmin/misc/cloud/static/js/google.js

/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import React from 'react';
import {GoogleCredSchema, GoogleClusterSchema, GoogleDatabaseSchema} from './google_schema.ui';
import pgAdmin from 'sources/pgadmin';
import { getNodeAjaxOptions, getNodeListById } from 'pgbrowser/node_ajax';
import SchemaView from '../../../../static/js/SchemaView';
import url_for from 'sources/url_for';
import { isEmptyString } from 'sources/validators';
import PropTypes from 'prop-types';
import getApiInstance from '../../../../static/js/api_instance';
import { CloudWizardEventsContext } from './CloudWizard';
import {MESSAGE_TYPE } from '../../../../static/js/components/FormComponents';
import gettext from 'sources/gettext';
import { makeStyles } from '@mui/styles';

const useStyles = makeStyles(() =>
  ({
    formClass: {
      overflow: 'auto',
    }
  }),
);


export function GoogleCredentials(props) {
  const [cloudDBCredInstance, setCloudDBCredInstance] = React.useState();

  let _eventBus = React.useContext(CloudWizardEventsContext);
  let child = null;
  React.useMemo(() => {
    const googleCredSchema = new GoogleCredSchema({
      authenticateGoogle:(client_secret_file) => {
        let loading_icon_url = url_for(
          'static', { 'filename': 'img/loading.gif'}
        );
        const axiosApi = getApiInstance();
        _eventBus.fireEvent('SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD', [MESSAGE_TYPE.INFO, 'Google authentication process is in progress..<img src="' + loading_icon_url + '" alt="' + gettext('Loading...') + '">']);
        let _url = url_for('google.verify_credentials');
        const post_data = {
          cloud: 'google',
          secret: {'client_secret_file':client_secret_file}
        };
        return new Promise((resolve, reject)=>{axiosApi.post(_url, post_data)
          .then((res) => {
            if (res.data && res.data.success == 1 ) {
              let params = 'scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no, width=550,height=650,left=600,top=150';
              child = window.open(res.data.data.auth_url, 'google_authentication', params);
              resolve(true);
            }
            else if (res.data && res.data.success == 0) {
              _eventBus.fireEvent('SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD',[MESSAGE_TYPE.ERROR, res.data.errormsg]);
              _eventBus.fireEvent('SET_CRED_VERIFICATION_INITIATED',false);
              resolve(false);
            }
          })
          .catch((error) => {
            _eventBus.fireEvent('SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD',[MESSAGE_TYPE.ERROR, gettext(`Error while authentication: ${error}`)]);
            reject(new Error(gettext(`Error while authentication: ${error}`)));
          });
        });
      },
      verification_ack:()=>{
        let auth_url = url_for('google.verification_ack');
        let countdown = 90;
        const axiosApi = getApiInstance();
        return new Promise((resolve, reject)=>{
          const interval = setInterval(()=>{
            axiosApi.get(auth_url)
              .then((res)=>{
                if (res.data.success && res.data.success == 1 ){
                  _eventBus.fireEvent('SET_CRED_VERIFICATION_INITIATED',true);
                  _eventBus.fireEvent('SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD',[MESSAGE_TYPE.SUCCESS, gettext('Authentication completed successfully. Click the Next button to proceed.')]);
                  clearInterval(interval);
                  if(child){
                    // close authentication window
                    child.close();
                  }
                  resolve();
                } else if (res.data && res.data.success == 0 && res.data.errormsg ){
                  _eventBus.fireEvent('SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD',[MESSAGE_TYPE.ERROR, res.data.errormsg]);
                  _eventBus.fireEvent('SET_CRED_VERIFICATION_INITIATED',false);
                  clearInterval(interval);
                  resolve(false);
                } else if (child?.closed || countdown <= 0) {
                  _eventBus.fireEvent('SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD',[MESSAGE_TYPE.ERROR, 'Authentication is aborted.']);
                  _eventBus.fireEvent('SET_CRED_VERIFICATION_INITIATED',false);
                  clearInterval(interval);
                }
              })
              .catch((error)=>{
                clearInterval(interval);
                reject(error);
              });
            countdown = countdown - 1;
          }, 1000);
        });
      }
    }, {}, _eventBus);
    setCloudDBCredInstance(googleCredSchema);
  }, [props.cloudProvider]);

  return  <SchemaView
    formType={'dialog'}
    getInitData={() => { /*This is intentional (SonarQube)*/ }}
    viewHelperProps={{ mode: 'create' }}
    schema={cloudDBCredInstance}
    showFooter={false}
    isTabView={false}
    onDataChange={(isChanged, changedData) => {
      props.setGoogleCredData(changedData);
    }}
  />;
}
GoogleCredentials.propTypes = {
  cloudProvider: PropTypes.string,
  setGoogleCredData: PropTypes.func
};

// Google Instance
export function GoogleInstanceDetails(props) {
  const [googleInstanceSchema, setGoogleInstanceSchema] = React.useState();
  const classes = useStyles();

  React.useMemo(() => {
    const GoogleClusterSchemaObj = new GoogleClusterSchema({
      projects: () => getNodeAjaxOptions('get_projects', {}, {}, {},{
        useCache:false,
        cacheNode: 'server',
        customGenerateUrl: ()=>{
          return url_for('google.projects');
        }
      }),
      regions: (project)=>getNodeAjaxOptions('get_regions', pgAdmin.Browser.Nodes['server'], props.nodeInfo, props.nodeData,{
        useCache:false,
        cacheNode: 'server',
        customGenerateUrl: ()=>{
          return url_for('google.regions', {'project_id': project});
        }
      }),
      availabilityZones: (region)=>getNodeAjaxOptions('get_availability_zones', pgAdmin.Browser.Nodes['server'], props.nodeInfo, props.nodeData, {
        useCache:false,
        cacheNode: 'server',
        customGenerateUrl: ()=>{
          return url_for('google.availability_zones', {'region': region});
        }
      }),
      dbVersions: ()=>getNodeAjaxOptions('get_db_versions', pgAdmin.Browser.Nodes['server'], props.nodeInfo, props.nodeData, {
        useCache:false,
        cacheNode: 'server',
        customGenerateUrl: ()=>{
          return url_for('google.database_versions');
        }
      }),
      instanceTypes: (project, region, instanceClass)=>{
        if (isEmptyString(project) || isEmptyString(region) || isEmptyString(instanceClass)) return [];
        return getNodeAjaxOptions('get_instance_types', pgAdmin.Browser.Nodes['server'], props.nodeInfo, props.nodeData, {
          useCache:false,
          cacheNode: 'server',
          customGenerateUrl: ()=>{
            return url_for('google.instance_types', {'project_id':project, 'region': region, 'instance_class': instanceClass});
          }
        });},
    }, {
      nodeInfo: props.nodeInfo,
      nodeData: props.nodeData,
      hostIP: props.hostIP,
      ...props.googleInstanceData
    });
    setGoogleInstanceSchema(GoogleClusterSchemaObj);
  }, [props.cloudProvider]);

  return  <SchemaView
    formType={'dialog'}
    getInitData={() => { /*This is intentional (SonarQube)*/ }}
    viewHelperProps={{ mode: 'create' }}
    schema={googleInstanceSchema}
    showFooter={false}
    isTabView={false}
    onDataChange={(isChanged, changedData) => {
      props.setGoogleInstanceData(changedData);
    }}
    formClassName={classes.formClass}
  />;
}
GoogleInstanceDetails.propTypes = {
  nodeInfo: PropTypes.object,
  nodeData: PropTypes.object,
  cloudProvider: PropTypes.string,
  setGoogleInstanceData: PropTypes.func,
  hostIP: PropTypes.string,
  googleInstanceData: PropTypes.object
};


// Google Database Details
export function GoogleDatabaseDetails(props) {
  const [googleDBInstance, setGoogleDBInstance] = React.useState();
  const classes = useStyles();

  React.useMemo(() => {
    const googleDBSchema = new GoogleDatabaseSchema({
      server_groups: ()=>getNodeListById(pgAdmin.Browser.Nodes['server_group'], props.nodeInfo, props.nodeData),
    },
    {
      gid: props.nodeInfo['server_group']._id,
    }
    );
    setGoogleDBInstance(googleDBSchema);

  }, [props.cloudProvider]);

  return <SchemaView
    formType={'dialog'}
    getInitData={() => { /*This is intentional (SonarQube)*/ }}
    viewHelperProps={{ mode: 'create' }}
    schema={googleDBInstance}
    showFooter={false}
    isTabView={false}
    onDataChange={(isChanged, changedData) => {
      props.setGoogleDatabaseData(changedData);
    }}
    formClassName={classes.formClass}
  />;
}
GoogleDatabaseDetails.propTypes = {
  nodeInfo: PropTypes.object,
  nodeData: PropTypes.object,
  cloudProvider: PropTypes.string,
  setGoogleDatabaseData: PropTypes.func,
};

// Validation functions
export function validateGoogleStep2(cloudInstanceDetails) {
  let isError = false;
  if ((isEmptyString(cloudInstanceDetails.name) || (!/^(?=[a-z])[a-z0-9\-]*$/.test(cloudInstanceDetails.name) ||
      cloudInstanceDetails.name.length > 97) || isEmptyString(cloudInstanceDetails.project) ||
      isEmptyString(cloudInstanceDetails.region) || isEmptyString(cloudInstanceDetails.availability_zone) ||
      isEmptyString(cloudInstanceDetails.db_version) || isEmptyString(cloudInstanceDetails.instance_type) ||
      isEmptyString(cloudInstanceDetails.instance_class) || isEmptyString(cloudInstanceDetails.storage_type)||
      isEmptyString(cloudInstanceDetails.storage_size) || isEmptyString(cloudInstanceDetails.public_ips)) ||
      (cloudInstanceDetails.high_availability && (isEmptyString(cloudInstanceDetails.secondary_availability_zone) ||
      cloudInstanceDetails.secondary_availability_zone == cloudInstanceDetails.availability_zone))) {
    isError = true;
  }
  return isError;
}

export function validateGoogleStep3(cloudDBDetails, nodeInfo) {
  let isError = false;
  if (isEmptyString(cloudDBDetails.db_username) || isEmptyString(cloudDBDetails.db_password)) {
    isError = true;
  }

  if (cloudDBDetails.db_password != cloudDBDetails.db_confirm_password) {
    isError = true;
  }

  if (isEmptyString(cloudDBDetails.gid)) cloudDBDetails.gid = nodeInfo['server_group']._id;
  return isError;
}

// Summary creation
function createData(name, value) {
  if (typeof(value) == 'boolean') {
    value = (value === true) ? 'True' : 'False';
  }
  return { name, value };
}

// Summary section
export function getGoogleSummary(cloud, cloudInstanceDetails, cloudDBDetails) {
  let db_version = cloudInstanceDetails.db_version;
  db_version  = db_version.charAt(0) + db_version.slice(1,7).toLowerCase() + 'SQL ' + db_version.split('_')[1];
  let storageType = cloudInstanceDetails.storage_type.split('_')[1];
  let instance_class = cloudInstanceDetails.instance_class.charAt(0).toUpperCase() + cloudInstanceDetails.instance_class.slice(1);
  let instance_type = cloudInstanceDetails.instance_type;
  if (instance_class =='Standard' || instance_class =='Highmem' ){
    instance_type =  instance_type.split('-')[2] + ' vCPU ' + Math.round((parseInt(instance_type.split('-')[3]))/1024) + ' GB';
  }else{
    const instance_type_mapping = {'db-f1-micro':'1 vCPU, 0.6 GB', 'db-g1-small': '1 vCPU, 1.7 GB'};
    instance_type = instance_type_mapping[instance_type];
  }

  const rows1 = [
    createData(gettext('Cloud'), cloud),
    createData(gettext('Instance name'), cloudInstanceDetails.name),
    createData(gettext('Project'), cloudInstanceDetails.project),
    createData(gettext('Region'), cloudInstanceDetails.region),
    createData(gettext('Availability zone'), cloudInstanceDetails.availability_zone),
  ];

  const rows2 = [
    createData(gettext('PostgreSQL version'), db_version),
    createData(gettext('Instance class'), instance_class),
    createData(gettext('Instance type'), instance_type),
  ];

  const rows3 = [
    createData(gettext('Storage type'), storageType),
    createData(gettext('Allocated storage'), cloudInstanceDetails.storage_size + ' GB'),
  ];

  const rows4 = [
    createData(gettext('Username'), cloudDBDetails.db_username),
    createData(gettext('Password'), 'xxxxxxx'),
  ];

  const rows5 = [
    createData(gettext('Public IP'), cloudInstanceDetails.public_ips),
  ];

  const rows6 = [
    createData(gettext('High availability'), cloudInstanceDetails.high_availability),
    createData(gettext('Secondary availability zone'), cloudInstanceDetails.secondary_availability_zone),
  ];

  return [rows1, rows2, rows3, rows4, rows5, rows6];
}