update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b third try 79/5479/2 v3.0.0rc2
authorJeremy Mordkoff <Jeremy.Mordkoff@riftio.com>
Sun, 1 Oct 2017 01:42:44 +0000 (21:42 -0400)
committerJeremy Mordkoff <Jeremy.Mordkoff@riftio.com>
Mon, 2 Oct 2017 21:43:41 +0000 (17:43 -0400)
Signed-off-by: Jeremy Mordkoff <Jeremy.Mordkoff@riftio.com>
Change-Id: Ib11aa03a2eff5a53c808342508a5d7bee7b202b8

380 files changed:
.gitignore
BUILD.sh [new file with mode: 0755]
CMakeLists.txt
Dockerfile
Jenkinsfile
manifest/LICENSE
postinst [new file with mode: 0755]
python-osmclient/.gitignore [deleted file]
python-osmclient/Makefile [deleted file]
python-osmclient/README.md [deleted file]
python-osmclient/osmclient/__init__.py [deleted file]
python-osmclient/osmclient/common/OsmAPI.py [deleted file]
python-osmclient/osmclient/common/__init__.py [deleted file]
python-osmclient/osmclient/scripts/__init__.py [deleted file]
python-osmclient/osmclient/scripts/osm.py [deleted file]
python-osmclient/setup.py [deleted file]
python-osmclient/stdeb.cfg [deleted file]
skyquake/.storybook/config.js
skyquake/framework/core/api_utils/auth.js [new file with mode: 0644]
skyquake/framework/core/api_utils/constants.js
skyquake/framework/core/api_utils/csrf.js [new file with mode: 0644]
skyquake/framework/core/api_utils/openidconnect_config.json [new file with mode: 0644]
skyquake/framework/core/api_utils/sockets.js
skyquake/framework/core/api_utils/utils.js
skyquake/framework/core/modules/api/appConfigAPI.js [new file with mode: 0644]
skyquake/framework/core/modules/api/configuration.js
skyquake/framework/core/modules/api/descriptorModelMetaAPI.js
skyquake/framework/core/modules/api/modelAPI.js [new file with mode: 0644]
skyquake/framework/core/modules/api/projectManagementAPI.js [new file with mode: 0644]
skyquake/framework/core/modules/api/restconf.js
skyquake/framework/core/modules/api/schemaAPI.js [new file with mode: 0644]
skyquake/framework/core/modules/api/sessions.js [new file with mode: 0644]
skyquake/framework/core/modules/api/userManagementAPI.js [new file with mode: 0644]
skyquake/framework/core/modules/navigation_manager.js
skyquake/framework/core/modules/routes/auth.js [new file with mode: 0644]
skyquake/framework/core/modules/routes/configuration.js
skyquake/framework/core/modules/routes/navigation.js
skyquake/framework/core/modules/routes/projectManagement.js [new file with mode: 0644]
skyquake/framework/core/modules/routes/sessions.js [new file with mode: 0644]
skyquake/framework/core/modules/routes/userManagement.js [new file with mode: 0644]
skyquake/framework/core/views/home.ejs [new file with mode: 0644]
skyquake/framework/core/views/idpconnectfail.ejs [new file with mode: 0644]
skyquake/framework/plugin-index.html [new file with mode: 0644]
skyquake/framework/source/SourceCache.js [new file with mode: 0644]
skyquake/framework/source/model/index.js [new file with mode: 0644]
skyquake/framework/source/model/modelActions.js [new file with mode: 0644]
skyquake/framework/source/model/modelSource.js [new file with mode: 0644]
skyquake/framework/source/schema/index.js [new file with mode: 0644]
skyquake/framework/source/schema/schemaActions.js [new file with mode: 0644]
skyquake/framework/source/schema/schemaSource.js [new file with mode: 0644]
skyquake/framework/style/_colors.scss
skyquake/framework/style/core.css
skyquake/framework/style/img/osm_header.png
skyquake/framework/style/img/osm_header_253x50.png
skyquake/framework/style/img/osm_header_506x100.png
skyquake/framework/utils/appConfiguration.js [new file with mode: 0644]
skyquake/framework/utils/roleConstants.js [new file with mode: 0644]
skyquake/framework/utils/utils.js
skyquake/framework/widgets/button/button.scss
skyquake/framework/widgets/button/sq-button.jsx
skyquake/framework/widgets/components.js
skyquake/framework/widgets/form_controls/formControls.jsx [new file with mode: 0644]
skyquake/framework/widgets/form_controls/formControls.scss
skyquake/framework/widgets/form_controls/input.jsx [new file with mode: 0644]
skyquake/framework/widgets/form_controls/selectOption.jsx
skyquake/framework/widgets/form_controls/textInput.jsx
skyquake/framework/widgets/header/header.scss
skyquake/framework/widgets/operational-status/launchpadOperationalStatus.jsx
skyquake/framework/widgets/panel/panel.jsx
skyquake/framework/widgets/panel/panel.scss
skyquake/framework/widgets/skyquake_container/eventCenter.jsx
skyquake/framework/widgets/skyquake_container/skyquakeApp.scss
skyquake/framework/widgets/skyquake_container/skyquakeComponent.jsx
skyquake/framework/widgets/skyquake_container/skyquakeContainer.jsx
skyquake/framework/widgets/skyquake_container/skyquakeContainerActions.js
skyquake/framework/widgets/skyquake_container/skyquakeContainerSource.js
skyquake/framework/widgets/skyquake_container/skyquakeContainerStore.js
skyquake/framework/widgets/skyquake_container/skyquakeNav.jsx [deleted file]
skyquake/framework/widgets/skyquake_container/skyquakeRouter.jsx
skyquake/framework/widgets/skyquake_nav/skyquakeNav.jsx [new file with mode: 0644]
skyquake/framework/widgets/skyquake_nav/skyquakeNav.scss [new file with mode: 0644]
skyquake/framework/widgets/skyquake_notification/netConfErrors.js [new file with mode: 0644]
skyquake/framework/widgets/skyquake_notification/skyquakeNotification.jsx [new file with mode: 0644]
skyquake/framework/widgets/skyquake_rbac/skyquakeRBAC.jsx [new file with mode: 0644]
skyquake/package.json
skyquake/plugins/CMakeLists.txt
skyquake/plugins/about/api/about.js
skyquake/plugins/about/config.json
skyquake/plugins/about/scripts/build.sh
skyquake/plugins/about/scripts/install.sh
skyquake/plugins/about/src/about.jsx
skyquake/plugins/about/webpack.production.config.js
skyquake/plugins/accounts/api/accounts.js
skyquake/plugins/accounts/api/cloud_account/cloudAccount.js
skyquake/plugins/accounts/api/config_agent/configAgent.js
skyquake/plugins/accounts/api/sdn_account/sdnAccount.js
skyquake/plugins/accounts/config.json
skyquake/plugins/accounts/config_routes.js [new file with mode: 0644]
skyquake/plugins/accounts/images/brocade.png [new file with mode: 0644]
skyquake/plugins/accounts/routes.js
skyquake/plugins/accounts/scripts/build.sh
skyquake/plugins/accounts/scripts/install.sh
skyquake/plugins/accounts/src/account/account.jsx
skyquake/plugins/accounts/src/account/accountActions.js
skyquake/plugins/accounts/src/account/accountSource.js
skyquake/plugins/accounts/src/account/accountStore.js
skyquake/plugins/accounts/src/account/accountsDashboard.jsx
skyquake/plugins/accounts/src/account_sidebar/accountSidebar.jsx
skyquake/plugins/accounts/src/account_sidebar/accountSidebar.scss
skyquake/plugins/accounts/webpack.production.config.js
skyquake/plugins/admin/CMakeLists.txt [new file with mode: 0644]
skyquake/plugins/admin/api/admin.js [new file with mode: 0644]
skyquake/plugins/admin/config.json [new file with mode: 0644]
skyquake/plugins/admin/package.json [new file with mode: 0644]
skyquake/plugins/admin/routes.js [new file with mode: 0644]
skyquake/plugins/admin/scripts/build.sh [new file with mode: 0755]
skyquake/plugins/admin/scripts/install.sh [new file with mode: 0755]
skyquake/plugins/admin/server.js [new file with mode: 0644]
skyquake/plugins/admin/src/AdminStore.js [new file with mode: 0644]
skyquake/plugins/admin/src/admin.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/admin.scss [new file with mode: 0644]
skyquake/plugins/admin/src/adminActions.js [new file with mode: 0644]
skyquake/plugins/admin/src/adminSource.js [new file with mode: 0644]
skyquake/plugins/admin/src/components/ActionBar.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/ChoiceCard.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/ChoiceColumn.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/ColumnCard.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/ContainerCard.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/ContainerColumn.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/EditorDialog.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/ExplorerColumn.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/LeafGroup.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/ListCard.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/ListColumn.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/ListEntryCard.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/ListEntryColumn.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/ListStack.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/LoadingCard.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/LoadingColumn.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/ModelExplorer.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/editor/LeafEditor.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/editor/LeafField.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/editor/Select.jsx [new file with mode: 0644]
skyquake/plugins/admin/src/components/editor/resolveLeafRef.js [new file with mode: 0644]
skyquake/plugins/admin/src/main.js [new file with mode: 0644]
skyquake/plugins/admin/src/store/ModelStore.js [new file with mode: 0644]
skyquake/plugins/admin/src/yang/leaf-utils.js [new file with mode: 0644]
skyquake/plugins/admin/src/yang/property-utils.js [new file with mode: 0644]
skyquake/plugins/admin/webpack.production.config.js [new file with mode: 0644]
skyquake/plugins/composer/api/composer.js
skyquake/plugins/composer/api/packageFileHandler.js
skyquake/plugins/composer/config.json
skyquake/plugins/composer/package.json
skyquake/plugins/composer/routes.js
skyquake/plugins/composer/scripts/build.sh
skyquake/plugins/composer/src/schemas/yang/confd2model.js
skyquake/plugins/composer/src/schemas/yang/mano-types.yang.src
skyquake/plugins/composer/src/src/actions/CatalogDataSourceActions.js
skyquake/plugins/composer/src/src/actions/ComposerAppActions.js
skyquake/plugins/composer/src/src/actions/DescriptorEditorActions.js [new file with mode: 0644]
skyquake/plugins/composer/src/src/actions/PanelResizeAction.js
skyquake/plugins/composer/src/src/alt.js
skyquake/plugins/composer/src/src/components/Button.js
skyquake/plugins/composer/src/src/components/CanvasPanel.js
skyquake/plugins/composer/src/src/components/CanvasPanelTray.js
skyquake/plugins/composer/src/src/components/CatalogItemCanvasEditor.js
skyquake/plugins/composer/src/src/components/CatalogItemDetailsEditor.js
skyquake/plugins/composer/src/src/components/CatalogItems.js
skyquake/plugins/composer/src/src/components/CatalogPanel.js
skyquake/plugins/composer/src/src/components/CatalogPanelToolbar.js
skyquake/plugins/composer/src/src/components/ComposerApp.js
skyquake/plugins/composer/src/src/components/ComposerAppToolbar.js
skyquake/plugins/composer/src/src/components/ConfigPrimitiveParameters/ConfigPrimitiveParameters.js [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/DetailsPanel.js
skyquake/plugins/composer/src/src/components/DetailsPanelToolbar.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/EditDescriptorModelProperties.js
skyquake/plugins/composer/src/src/components/EditorForwardingGraph/EditForwardingGraphPaths.js
skyquake/plugins/composer/src/src/components/NavigateDescriptorErrors.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/NavigateDescriptorModel.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/RiftHeader.js
skyquake/plugins/composer/src/src/components/filemanager/FileManager.jsx
skyquake/plugins/composer/src/src/components/filemanager/FileManagerSource.js
skyquake/plugins/composer/src/src/components/messages.js
skyquake/plugins/composer/src/src/components/model/Choice.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/model/Container.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/model/EditDescriptorUtils.js [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/model/LeafEditor.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/model/LeafField.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/model/List.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/model/ListItemAsLink.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/model/ModelBreadcrumb.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/model/PanelHeader.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/model/PropertyCrumb.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/model/PropertyNavigate.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/model/PropertyPanel.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/model/RemoveItemButton.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/components/model/Select.jsx [new file with mode: 0644]
skyquake/plugins/composer/src/src/libraries/FileManagerUploadDropZone.js
skyquake/plugins/composer/src/src/libraries/PackageManagerApi.js [deleted file]
skyquake/plugins/composer/src/src/libraries/TooltipManager.js
skyquake/plugins/composer/src/src/libraries/UniqueId.js
skyquake/plugins/composer/src/src/libraries/graph/DescriptorGraph.js
skyquake/plugins/composer/src/src/libraries/graph/layouts/RelationsAndNetworksLayout.js
skyquake/plugins/composer/src/src/libraries/model/DescriptorModel.js
skyquake/plugins/composer/src/src/libraries/model/DescriptorModelFactory.js
skyquake/plugins/composer/src/src/libraries/model/DescriptorModelFields.js
skyquake/plugins/composer/src/src/libraries/model/DescriptorModelMetaFactory.js
skyquake/plugins/composer/src/src/libraries/model/DescriptorModelMetaProperty.js
skyquake/plugins/composer/src/src/libraries/model/DescriptorModelSerializer.js
skyquake/plugins/composer/src/src/libraries/model/descriptors/ConnectionPoint.js
skyquake/plugins/composer/src/src/libraries/model/descriptors/ConstituentVnfdConnectionPoint.js
skyquake/plugins/composer/src/src/libraries/model/descriptors/InternalVirtualLink.js
skyquake/plugins/composer/src/src/libraries/model/descriptors/NetworkService.js
skyquake/plugins/composer/src/src/libraries/model/descriptors/VirtualNetworkFunction.js
skyquake/plugins/composer/src/src/libraries/model/descriptors/VirtualNetworkFunctionAccessPoint.js [new file with mode: 0644]
skyquake/plugins/composer/src/src/libraries/model/descriptors/VirtualNetworkFunctionAccessPointMap.js [new file with mode: 0644]
skyquake/plugins/composer/src/src/libraries/model/descriptors/VirtualNetworkFunctionReadOnlyWrapper.js
skyquake/plugins/composer/src/src/libraries/utils.js
skyquake/plugins/composer/src/src/sources/CatalogDataSource.js
skyquake/plugins/composer/src/src/sources/CatalogPackageManagerSource.js
skyquake/plugins/composer/src/src/stores/CatalogDataStore.js
skyquake/plugins/composer/src/src/stores/CatalogPackageManagerStore.js
skyquake/plugins/composer/src/src/stores/ComposerAppStore.js
skyquake/plugins/composer/src/src/styles/Button.scss
skyquake/plugins/composer/src/src/styles/CanvasPanel.scss
skyquake/plugins/composer/src/src/styles/CanvasPanelTray.scss
skyquake/plugins/composer/src/src/styles/CatalogItemDetailsEditor.scss [new file with mode: 0644]
skyquake/plugins/composer/src/src/styles/CatalogItems.scss
skyquake/plugins/composer/src/src/styles/DetailsPanel.scss
skyquake/plugins/composer/src/src/styles/DetailsPanelErrors.scss [new file with mode: 0644]
skyquake/plugins/composer/src/src/styles/DetailsPanelToolbar.scss [new file with mode: 0644]
skyquake/plugins/composer/src/src/styles/EditConfigParameterMap.scss [new file with mode: 0644]
skyquake/plugins/composer/src/src/styles/EditDescriptorModelProperties.scss
skyquake/plugins/composer/src/src/styles/_main.scss
skyquake/plugins/composer/webpack.production.config.js
skyquake/plugins/config/CMakeLists.txt [deleted file]
skyquake/plugins/config/api/ro.js [deleted file]
skyquake/plugins/config/config.json [deleted file]
skyquake/plugins/config/images/OpenDaylight_logo.png [deleted file]
skyquake/plugins/config/images/aws.png [deleted file]
skyquake/plugins/config/images/juju.svg [deleted file]
skyquake/plugins/config/images/openmano.png [deleted file]
skyquake/plugins/config/images/openstack-horizontal.png [deleted file]
skyquake/plugins/config/images/openstack.png [deleted file]
skyquake/plugins/config/images/riftio.png [deleted file]
skyquake/plugins/config/package.json [deleted file]
skyquake/plugins/config/routes.js [deleted file]
skyquake/plugins/config/scripts/build.sh [deleted file]
skyquake/plugins/config/scripts/install.sh [deleted file]
skyquake/plugins/config/server.js [deleted file]
skyquake/plugins/config/src/dashboard/config.scss [deleted file]
skyquake/plugins/config/src/dashboard/configActions.js [deleted file]
skyquake/plugins/config/src/dashboard/configSource.js [deleted file]
skyquake/plugins/config/src/dashboard/configStore.js [deleted file]
skyquake/plugins/config/src/dashboard/dashboard.jsx [deleted file]
skyquake/plugins/config/src/dashboard/inputs.jsx [deleted file]
skyquake/plugins/config/src/main.js [deleted file]
skyquake/plugins/config/webpack.production.config.js [deleted file]
skyquake/plugins/debug/api/debug.js
skyquake/plugins/debug/config.json
skyquake/plugins/debug/scripts/build.sh
skyquake/plugins/debug/scripts/install.sh
skyquake/plugins/debug/webpack.production.config.js
skyquake/plugins/goodbyeworld/scripts/build.sh
skyquake/plugins/goodbyeworld/webpack.production.config.js
skyquake/plugins/helloworld/scripts/build.sh
skyquake/plugins/helloworld/webpack.production.config.js
skyquake/plugins/launchpad/api/launchpad.js
skyquake/plugins/launchpad/config.json
skyquake/plugins/launchpad/package.json
skyquake/plugins/launchpad/routes.js
skyquake/plugins/launchpad/scripts/build.sh
skyquake/plugins/launchpad/scripts/install.sh
skyquake/plugins/launchpad/src/instantiate/instantiateDashboard.jsx
skyquake/plugins/launchpad/src/instantiate/instantiateDashboard.scss
skyquake/plugins/launchpad/src/instantiate/instantiateInputParams.jsx
skyquake/plugins/launchpad/src/instantiate/instantiateParameters.jsx
skyquake/plugins/launchpad/src/instantiate/instantiateSelectDescriptorPanel.jsx
skyquake/plugins/launchpad/src/instantiate/instantiateSelectDescriptorPanel.scss
skyquake/plugins/launchpad/src/instantiate/instantiateStore.js
skyquake/plugins/launchpad/src/instantiate/launchNetworkServiceActions.js
skyquake/plugins/launchpad/src/instantiate/launchNetworkServiceSource.js
skyquake/plugins/launchpad/src/launchpad-create.js [deleted file]
skyquake/plugins/launchpad/src/launchpad.jsx
skyquake/plugins/launchpad/src/launchpadFleetSource.js
skyquake/plugins/launchpad/src/launchpad_card/launchpad-card.js [deleted file]
skyquake/plugins/launchpad/src/launchpad_card/launchpadCard.jsx
skyquake/plugins/launchpad/src/launchpad_card/launchpadCardCloudAccount.jsx
skyquake/plugins/launchpad/src/launchpad_card/launchpadHeader.jsx
skyquake/plugins/launchpad/src/launchpad_card/launchpad_card.scss
skyquake/plugins/launchpad/src/launchpad_card/nsrConfigPrimitives.jsx
skyquake/plugins/launchpad/src/launchpad_card/nsrScalingGroups.jsx
skyquake/plugins/launchpad/src/launchpad_card/vnfrConfigPrimitives.jsx
skyquake/plugins/launchpad/src/monitoring_params/monitoringParamComponents.js
skyquake/plugins/launchpad/src/monitoring_params/monitoring_params.scss
skyquake/plugins/launchpad/src/nsCardPanel/nsCardPanel.jsx
skyquake/plugins/launchpad/src/nsListPanel/nsListPanel.jsx
skyquake/plugins/launchpad/src/recordViewer/recordCard.jsx
skyquake/plugins/launchpad/src/recordViewer/recordView.jsx
skyquake/plugins/launchpad/src/recordViewer/recordViewSource.js
skyquake/plugins/launchpad/src/recordViewer/recordViewStore.js
skyquake/plugins/launchpad/src/topologyL2View/topologyL2Source.js
skyquake/plugins/launchpad/src/topologyView/topologySource.js
skyquake/plugins/launchpad/src/virtual_links/nsVirtualLinkCreateSource.js
skyquake/plugins/launchpad/src/virtual_links/nsVirtualLinks.jsx
skyquake/plugins/launchpad/src/vnfr/vnfrSource.js
skyquake/plugins/launchpad/webpack.production.config.js
skyquake/plugins/logging/api/logging.js
skyquake/plugins/logging/api/transforms.js
skyquake/plugins/logging/config.json
skyquake/plugins/logging/package.json
skyquake/plugins/logging/scripts/build.sh
skyquake/plugins/logging/scripts/install.sh
skyquake/plugins/logging/src/loggingSource.js
skyquake/plugins/logging/src/loggingStore.js
skyquake/plugins/logging/webpack.production.config.js
skyquake/plugins/logging/yarn.lock
skyquake/plugins/project_management/CMakeLists.txt [new file with mode: 0644]
skyquake/plugins/project_management/config.json [new file with mode: 0644]
skyquake/plugins/project_management/package.json [new file with mode: 0644]
skyquake/plugins/project_management/routes.js [new file with mode: 0644]
skyquake/plugins/project_management/scripts/build.sh [new file with mode: 0755]
skyquake/plugins/project_management/scripts/install.sh [new file with mode: 0755]
skyquake/plugins/project_management/server.js [new file with mode: 0644]
skyquake/plugins/project_management/src/dashboard/dashboard.jsx [new file with mode: 0644]
skyquake/plugins/project_management/src/dashboard/projectMgmt.scss [new file with mode: 0644]
skyquake/plugins/project_management/src/dashboard/projectMgmtActions.js [new file with mode: 0644]
skyquake/plugins/project_management/src/dashboard/projectMgmtSource.js [new file with mode: 0644]
skyquake/plugins/project_management/src/dashboard/projectMgmtStore.js [new file with mode: 0644]
skyquake/plugins/project_management/src/main.js [new file with mode: 0644]
skyquake/plugins/project_management/webpack.production.config.js [new file with mode: 0644]
skyquake/plugins/redundancy/CMakeLists.txt [new file with mode: 0644]
skyquake/plugins/redundancy/api/redundancy.js [new file with mode: 0644]
skyquake/plugins/redundancy/config.json [new file with mode: 0644]
skyquake/plugins/redundancy/package.json [new file with mode: 0644]
skyquake/plugins/redundancy/routes.js [new file with mode: 0644]
skyquake/plugins/redundancy/scripts/build.sh [new file with mode: 0755]
skyquake/plugins/redundancy/scripts/install.sh [new file with mode: 0755]
skyquake/plugins/redundancy/server.js [new file with mode: 0644]
skyquake/plugins/redundancy/src/dashboard/config.jsx [new file with mode: 0644]
skyquake/plugins/redundancy/src/dashboard/dashboard.jsx [new file with mode: 0644]
skyquake/plugins/redundancy/src/dashboard/redundancy.scss [new file with mode: 0644]
skyquake/plugins/redundancy/src/dashboard/redundancyActions.js [new file with mode: 0644]
skyquake/plugins/redundancy/src/dashboard/redundancySource.js [new file with mode: 0644]
skyquake/plugins/redundancy/src/dashboard/redundancyStore.js [new file with mode: 0644]
skyquake/plugins/redundancy/src/dashboard/sites.jsx [new file with mode: 0644]
skyquake/plugins/redundancy/src/dashboard/status.jsx [new file with mode: 0644]
skyquake/plugins/redundancy/src/dashboard/utils/utils.js [new file with mode: 0644]
skyquake/plugins/redundancy/src/main.js [new file with mode: 0644]
skyquake/plugins/redundancy/webpack.production.config.js [new file with mode: 0644]
skyquake/plugins/user_management/CMakeLists.txt [new file with mode: 0644]
skyquake/plugins/user_management/config.json [new file with mode: 0644]
skyquake/plugins/user_management/package.json [new file with mode: 0644]
skyquake/plugins/user_management/routes.js [new file with mode: 0644]
skyquake/plugins/user_management/scripts/build.sh [new file with mode: 0755]
skyquake/plugins/user_management/scripts/install.sh [new file with mode: 0755]
skyquake/plugins/user_management/server.js [new file with mode: 0644]
skyquake/plugins/user_management/src/dashboard/dashboard.jsx [new file with mode: 0644]
skyquake/plugins/user_management/src/dashboard/userMgmt.scss [new file with mode: 0644]
skyquake/plugins/user_management/src/dashboard/userMgmtActions.js [new file with mode: 0644]
skyquake/plugins/user_management/src/dashboard/userMgmtSource.js [new file with mode: 0644]
skyquake/plugins/user_management/src/dashboard/userMgmtStore.js [new file with mode: 0644]
skyquake/plugins/user_management/src/main.js [new file with mode: 0644]
skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagement.jsx [new file with mode: 0644]
skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagement.scss [new file with mode: 0644]
skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagementActions.js [new file with mode: 0644]
skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagementSource.js [new file with mode: 0644]
skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagementStore.js [new file with mode: 0644]
skyquake/plugins/user_management/src/userProfile/userProfile.jsx [new file with mode: 0644]
skyquake/plugins/user_management/src/userProfile/userProfileActions.js [new file with mode: 0644]
skyquake/plugins/user_management/src/userProfile/userProfileSource.js [new file with mode: 0644]
skyquake/plugins/user_management/src/userProfile/userProfileStore.js [new file with mode: 0644]
skyquake/plugins/user_management/webpack.production.config.js [new file with mode: 0644]
skyquake/scripts/build-dev.sh [new file with mode: 0755]
skyquake/scripts/build-plugin.sh [new file with mode: 0644]
skyquake/scripts/build.sh
skyquake/scripts/handle_plugin_node_modules [new file with mode: 0755]
skyquake/scripts/launch_ui.sh
skyquake/skyquake.js
skyquake/tests/stories/FileManager.js [new file with mode: 0644]

index 40934df..6747eae 100644 (file)
@@ -1,8 +1,10 @@
 .DS_Store/
 .DS_Store
+._.DS_Store
 err.log
 out.log
 node_modules/
 npm-debug.log
 fixtures/
 .build
+.fuse_*
diff --git a/BUILD.sh b/BUILD.sh
new file mode 100755 (executable)
index 0000000..e244b7c
--- /dev/null
+++ b/BUILD.sh
@@ -0,0 +1,121 @@
+#!/usr/bin/env bash
+# 
+#   Copyright 2016,2017 RIFT.IO Inc
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+# Author(s): Jeremy Mordkoff, Lezz Giles
+# Creation Date: 08/29/2016
+# 
+#
+
+# BUILD.sh
+#
+# This is a top-level build script for OSM SO or UI
+#
+# Arguments and options: use -h or --help
+#
+# dependencies -- requires sudo rights
+
+MODULE=UI
+
+# Defensive bash programming flags
+set -o errexit    # Exit on any error
+trap 'echo ERROR: Command failed: \"$BASH_COMMAND\"' ERR
+set -o nounset    # Expanding an unset variable is an error.  Variables must be
+                  # set before they can be used.
+
+###############################################################################
+# Options and arguments
+
+# There 
+params="$(getopt -o h -l install,help --name "$0" -- "$@")"
+if [ $? != 0 ] ; then echo "Failed parsing options." >&2 ; exit 1 ; fi
+
+eval set -- $params
+
+installFromPackages=false
+
+while true; do
+    case "$1" in
+       --install) installFromPackages=true; shift;;
+       -h|--help)
+           echo
+           echo "NAME:"
+           echo "  $0"
+           echo
+           echo "SYNOPSIS:"
+           echo "  $0 -h|--help"
+           echo "  $0 [--install] [PLATFORM_REPOSITORY] [PLATFORM_VERSION]"
+           echo
+           echo "DESCRIPTION:"
+           echo "  Prepare current system to run $MODULE.  By default, the system"
+           echo "  is set up to support building $MODULE; optionally, "
+           echo "  $MODULE can be installed from a Debian package repository."
+           echo
+           echo "  --install:  install $MODULE from package"
+           echo "  PLATFORM_REPOSITORY (optional): name of the RIFT.ware repository."
+           echo "  PLATFORM_VERSION (optional): version of the platform packages to be installed."
+           echo
+           exit 0;;
+       --) shift; break;;
+       *) echo "Not implemented: $1" >&2; exit 1;;
+    esac
+done
+
+# Turn this on after handling options, so the output doesn't get cluttered.
+set -x             # Print commands before executing them
+
+###############################################################################
+# Set up repo and version
+
+PLATFORM_REPOSITORY=${1:-osm-rbac}
+PLATFORM_VERSION=${2:-5.1.3.9999.70283}
+
+###############################################################################
+# Main block
+
+# must be run from the top of a workspace
+cd $(dirname $0)
+
+# enable the right repos
+curl http://repos.riftio.com/public/xenial-riftware-public-key | sudo apt-key add -
+
+# always use the same file name so that updates will overwrite rather than enable a second repo
+sudo curl -o /etc/apt/sources.list.d/rift.list http://buildtracker.riftio.com/repo_file/ub16/${PLATFORM_REPOSITORY}/ 
+sudo apt-get update
+
+sudo apt install -y --allow-downgrades rw.tools-container-tools=${PLATFORM_VERSION} rw.tools-scripts=${PLATFORM_VERSION}
+
+if $installFromPackages; then
+    
+    # Install module and platform from packages
+    sudo -H /usr/rift/container_tools/mkcontainer --modes $MODULE --repo ${PLATFORM_REPOSITORY} --rw-version ${PLATFORM_VERSION}
+    
+else
+
+    # Install environment to build module
+    sudo -H /usr/rift/container_tools/mkcontainer --modes $MODULE-dev --repo ${PLATFORM_REPOSITORY} --rw-version ${PLATFORM_VERSION}
+
+    # Build  and install module
+    make -j16 
+    sudo make install
+
+fi
+
+if [[ $MODULE == SO ]]; then
+    echo "Creating Service ...."
+    sudo /usr/rift/bin/create_launchpad_service
+fi
+
+
index 1c9b576..8a21f2f 100644 (file)
@@ -31,7 +31,7 @@ cmake_minimum_required(VERSION 2.8)
 # DO NOT add any code before this and DO NOT
 # include this file anywhere else
 ##
-include(rift_submodule)
+include(rift_submodule NO_POLICY_SCOPE)
 
 ##
 # Submodule specific includes will go here,
@@ -53,6 +53,15 @@ rift_add_subdirs(
     ${subdirs}
   )
 
+##
+# Only skyquake package contains anything
+##
+rift_set_component_package_fields(
+  skyquake
+  DESCRIPTION "RIFT.ware UI"
+  POST_INSTALL_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/postinst"
+  )
+
 ##
 # This macro adds targets for documentaion, unittests, code coverage and packaging
 ##
index 40dc922..d576e2f 100644 (file)
@@ -1,24 +1,13 @@
 FROM ubuntu:16.04
 
-RUN apt-get update && apt-get -y install python3 curl build-essential
+RUN apt-get update && apt-get -y install python3 curl build-essential apt-transport-https sudo
 RUN curl http://repos.riftio.com/public/xenial-riftware-public-key | apt-key add - && \
-       curl -o /etc/apt/sources.list.d/OSM.list http://buildtracker.riftio.com/repo_file/ub16/OSM/ && \
+       curl -o /etc/apt/sources.list.d/rift.list http://buildtracker.riftio.com/repo_file/ub16/OSM/ && \
        apt-get update && \
-       apt-get -y install rw.toolchain-rwbase \
-               rw.toolchain-rwtoolchain \
-               rw.core.mgmt-mgmt \
-               rw.core.util-util \
-               rw.core.rwvx-rwvx \
-               rw.core.rwvx-rwdts \
-               rw.automation.core-RWAUTO \
-               rw.tools-container-tools \
-               rw.tools-scripts \
-               python-cinderclient \
-               libxml2-dev \
-               libxslt-dev
+       apt-get -y install \
+               rw.tools-container-tools=5.2.0.0.71033 \
+               rw.tools-scripts=5.2.0.0.71033
 
-RUN /usr/rift/container_tools/mkcontainer --modes build --modes ext --repo OSM
+RUN /usr/rift/container_tools/mkcontainer --modes UI-dev --repo OSM --rw-version 5.2.0.0.71033
 
-RUN chmod 777 /usr/rift /usr/rift/usr/share
-
-RUN rm -rf /tmp/npm-cache
+RUN chmod 777 /usr/rift
index 99cb405..ceb06c3 100644 (file)
@@ -29,4 +29,3 @@ node('docker') {
                            params.GERRIT_PATCHSET_REVISION,
                            params.TEST_INSTALL,
                            params.ARTIFACTORY_SERVER)
-}
index e69de29..ab4a981 100644 (file)
@@ -0,0 +1 @@
+ho
diff --git a/postinst b/postinst
new file mode 100755 (executable)
index 0000000..602b110
--- /dev/null
+++ b/postinst
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# 
+#   Copyright 2016 RIFT.IO Inc
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+
+# Post-install script for packaging
+
+/usr/rift/usr/share/rw.ui/skyquake/scripts/handle_plugin_node_modules
diff --git a/python-osmclient/.gitignore b/python-osmclient/.gitignore
deleted file mode 100644 (file)
index e09c6a0..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-env/
-build/
-develop-eggs/
-dist/
-deb_dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-*.egg-info/
-.installed.cfg
-*.egg
-
-# PyInstaller
-#  Usually these files are written by a python script from a template
-#  before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*,cover
-.hypothesis/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-target/
-
-# IPython Notebook
-.ipynb_checkpoints
-
-# pyenv
-.python-version
-
-# celery beat schedule file
-celerybeat-schedule
-
-# dotenv
-.env
-
-# virtualenv
-venv/
-ENV/
-
-# Spyder project settings
-.spyderproject
-
-# Rope project settings
-.ropeproject
diff --git a/python-osmclient/Makefile b/python-osmclient/Makefile
deleted file mode 100644 (file)
index 1a2e448..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-package:
-       @python setup.py --command-packages=stdeb.command bdist_deb > /dev/null 2>&1
diff --git a/python-osmclient/README.md b/python-osmclient/README.md
deleted file mode 100644 (file)
index 8d41f2f..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-# python-osmclient
-A python client for osm orchestration
-
-# Installation
-
-## Install dependencies
-```bash
-sudo apt-get install python-dev libcurl4-gnutls-dev python-pip libgnutls-dev python-prettytable   
-sudo pip install pycurl
-```
-
-# Setup
-Set the OSM_HOSTNAME variable to the host of the osm server.
-
-Example
-```bash
-localhost$ export OSM_HOSTNAME=<hostname>:8008
-```
-
-# Examples 
-
-## upload vnfd
-```bash
-localhost$ osm upload-package ubuntu_xenial_vnf.tar.gz
-{'transaction_id': 'ec12af77-1b91-4c84-b233-60f2c2c16d14'}
-localhost$ osm vnfd-list
-+--------------------+--------------------+
-| vnfd name          | id                 |
-+--------------------+--------------------+
-| ubuntu_xenial_vnfd | ubuntu_xenial_vnfd |
-+--------------------+--------------------+
-```
-
-## upload nsd
-```bash
-localhost$ osm upload-package ubuntu_xenial_ns.tar.gz
-{'transaction_id': 'b560c9cb-43e1-49ef-a2da-af7aab24ce9d'}
-localhost$ osm nsd-list
-+-------------------+-------------------+
-| nsd name          | id                |
-+-------------------+-------------------+
-| ubuntu_xenial_nsd | ubuntu_xenial_nsd |
-+-------------------+-------------------+
-```
-## vim-list
-
-```bash
-localhost$ osm vim-list
-+-------------+-----------------+--------------------------------------+
-| ro-account  | datacenter name | uuid                                 |
-+-------------+-----------------+--------------------------------------+
-| osmopenmano | openstack-site  | 2ea04690-0e4a-11e7-89bc-00163e59ff0c |
-+-------------+-----------------+--------------------------------------+
-```
-
-
-## instantiate ns
-```bash
-localhost$ osm ns-create ubuntu_xenial_nsd testns openstack-site
-{'success': ''}
-localhost$ osm ns-list
-+------------------+--------------------------------------+-------------------+--------------------+---------------+
-| ns instance name | id                                   | catalog name      | operational status | config status |
-+------------------+--------------------------------------+-------------------+--------------------+---------------+
-| testns           | 6b0d2906-13d4-11e7-aa01-b8ac6f7d0c77 | ubuntu_xenial_nsd | running            | configured    |
-+------------------+--------------------------------------+-------------------+--------------------+---------------+
-```
-
-# Bash Completion
-python-osmclient uses [click](http://click.pocoo.org/5/).  You can setup bash completion by putting this in your .bashrc:
-    
-    eval "$(_OSM_COMPLETE=source osm)"
-
diff --git a/python-osmclient/osmclient/__init__.py b/python-osmclient/osmclient/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/python-osmclient/osmclient/common/OsmAPI.py b/python-osmclient/osmclient/common/OsmAPI.py
deleted file mode 100644 (file)
index f85e872..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-from io import BytesIO 
-import pycurl
-import json
-import pprint
-import uuid
-from prettytable import PrettyTable
-import time
-
-class OsmAPI():
-    def __init__(self,host,upload_port=8443):
-        if host is None:
-            raise Exception('missing host specifier')
-         
-        self._user='admin'
-        self._password='admin'
-        self._host=host
-        self._upload_port=upload_port
-        self._url = 'https://{}/'.format(self._host)
-        self._upload_url = 'https://{}:{}/'.format(self._host.split(':')[0],self._upload_port)
-
-    def get_curl_cmd(self,url):
-        curl_cmd = pycurl.Curl()
-        curl_cmd.setopt(pycurl.HTTPGET,1)
-        curl_cmd.setopt(pycurl.URL, self._url + url )
-        curl_cmd.setopt(pycurl.SSL_VERIFYPEER,0)
-        curl_cmd.setopt(pycurl.SSL_VERIFYHOST,0)
-        curl_cmd.setopt(pycurl.USERPWD, '{}:{}'.format(self._user,self._password))
-        curl_cmd.setopt(pycurl.HTTPHEADER, ['Accept: application/vnd.yand.data+json','Content-Type": "application/vnd.yang.data+json'])
-        return curl_cmd
-
-    def get_curl_upload_cmd(self,filename):
-        curl_cmd = pycurl.Curl()
-        curl_cmd.setopt(pycurl.HTTPPOST,[(('package',(pycurl.FORM_FILE,filename)))])
-        curl_cmd.setopt(pycurl.URL, self._upload_url + 'composer/upload?api_server=https://localhost&upload_server=https://' + self._host.split(':')[0])
-        curl_cmd.setopt(pycurl.SSL_VERIFYPEER,0)
-        curl_cmd.setopt(pycurl.SSL_VERIFYHOST,0)
-        curl_cmd.setopt(pycurl.USERPWD, '{}:{}'.format(self._user,self._password))
-        return curl_cmd
-
-    def get_ns_opdata(self,id):
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('api/operational/ns-instance-opdata/nsr/{}?deep'.format(id))
-        curl_cmd.setopt(pycurl.HTTPGET,1)
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        if data.getvalue():
-           return json.loads(data.getvalue().decode())
-        return None 
-
-    def get_ns_catalog(self):
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('api/running/nsd-catalog/nsd')
-        curl_cmd.setopt(pycurl.HTTPGET,1)
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        if data.getvalue():
-          resp = json.loads(data.getvalue().decode())
-          return resp
-        return {'nsd:nsd': []}
-
-    def get_config_agents(self):
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('api/config/config-agent')
-        curl_cmd.setopt(pycurl.HTTPGET,1)
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        if data.getvalue():
-          resp = json.loads(data.getvalue().decode())
-          if 'rw-config-agent:config-agent' in resp:
-            return resp['rw-config-agent:config-agent']['account']
-        return list()
-
-    def delete_config_agent(self,name):
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('api/config/config-agent/account/'+name)
-        curl_cmd.setopt(pycurl.CUSTOMREQUEST, "DELETE")
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        resp = json.loads(data.getvalue().decode())
-        pprint.pprint(resp)
-
-    def add_config_agent(self,name,account_type,server,user,secret):
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('api/config/config-agent')
-        curl_cmd.setopt(pycurl.POST,1)
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-
-        postdata={}
-        postdata['account'] = list()
-
-        account={}
-        account['name'] = name
-        account['account-type'] = account_type
-        account['juju'] = {}
-        account['juju']['user'] = user 
-        account['juju']['secret'] = secret
-        account['juju']['ip-address'] = server
-        postdata['account'].append(account)
-
-        jsondata=json.dumps(postdata)
-        curl_cmd.setopt(pycurl.POSTFIELDS,jsondata)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        resp = json.loads(data.getvalue().decode())
-        pprint.pprint(resp)
-
-    def get_ns_instance_list(self):
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('api/running/ns-instance-config')
-        curl_cmd.setopt(pycurl.HTTPGET,1)
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        resp = json.loads(data.getvalue().decode())
-        return resp['nsr:ns-instance-config']
-
-    def get_vnf_catalog(self):
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('api/running/vnfd-catalog/vnfd')
-        curl_cmd.setopt(pycurl.HTTPGET,1)
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        if data.getvalue():
-          resp = json.loads(data.getvalue().decode())
-          return resp
-        return {'vnfd:vnfd': []}
-
-    def get_vcs_info(self):
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('api/operational/vcs/info')
-        curl_cmd.setopt(pycurl.HTTPGET,1)
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        if data.getvalue():
-          resp = json.loads(data.getvalue().decode())
-          return resp['rw-base:info']['components']['component_info']
-        return list()
-
-    def get_vnfr_catalog(self):
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('v1/api/operational/vnfr-catalog/vnfr')
-        curl_cmd.setopt(pycurl.HTTPGET,1)
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        if data.getvalue():
-          resp = json.loads(data.getvalue().decode())
-          return resp
-        return None 
-
-    def get_vnf(self,vnf_name):
-        vnfs=self.get_vnfr_catalog()
-        for vnf in vnfs['vnfr:vnfr']:
-            if vnf_name == vnf['name']:
-                return vnf
-        return None
-
-    def get_vnf_monitoring(self,vnf_name):
-        vnf=self.get_vnf(vnf_name)
-        if vnf is not None:
-            if 'monitoring-param' in vnf:
-                return vnf['monitoring-param'] 
-        return None
-
-    def get_ns_monitoring(self,ns_name):
-        ns=self.get_ns(ns_name)
-        if ns is None:
-            raise Exception('cannot find ns {}'.format(ns_name)) 
-
-        vnfs=self.get_vnfr_catalog()
-        if vnfs is None:
-            return None
-        mon_list={}
-        for vnf in vnfs['vnfr:vnfr']:
-            if ns['id'] == vnf['nsr-id-ref']:
-                if 'monitoring-param' in vnf:
-                    mon_list[vnf['name']] = vnf['monitoring-param']
-
-        return mon_list 
-
-    def list_key_pair(self):
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('v1/api/config/key-pair?deep')
-        curl_cmd.setopt(pycurl.HTTPGET,1)
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        resp = json.loads(data.getvalue().decode())
-        if 'nsr:key-pair' in resp:
-            return resp['nsr:key-pair']
-        return list()
-
-    def list_ns_catalog(self):
-        resp = self.get_ns_catalog()
-        table=PrettyTable(['nsd name','id'])
-        for ns in resp['nsd:nsd']:
-            table.add_row([ns['name'],ns['id']])
-        table.align='l'
-        print(table)
-
-    def list_ns_instance(self):
-        resp = self.get_ns_instance_list()
-        table=PrettyTable(['ns instance name','id','catalog name','operational status','config status'])
-        if 'nsr' in resp:
-            for ns in resp['nsr']:
-                nsopdata=self.get_ns_opdata(ns['id'])
-                nsr=nsopdata['nsr:nsr']
-                table.add_row([nsr['name-ref'],nsr['ns-instance-config-ref'],nsr['nsd-name-ref'],nsr['operational-status'],nsr['config-status']])
-        table.align='l'
-        print(table)
-
-    def get_nsd(self,name):
-        resp = self.get_ns_catalog()
-        for ns in resp['nsd:nsd']:
-           if name == ns['name']:
-               return ns
-        return None 
-
-    def get_vnfd(self,name):
-        resp = self.get_vnf_catalog()
-        for vnf in resp['vnfd:vnfd']:
-           if name == vnf['name']:
-               return vnf 
-        return None 
-
-    def get_ns(self,name):
-        resp=self.get_ns_instance_list()
-        for ns in resp['nsr']:
-           if name == ns['name']:
-               return ns
-        return None 
-    
-    def instantiate_ns(self,nsd_name,nsr_name,account,vim_network_prefix=None,ssh_keys=None,description='default description',admin_status='ENABLED'):
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('api/config/ns-instance-config/nsr')
-        curl_cmd.setopt(pycurl.POST,1)
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-
-        postdata={}
-        postdata['nsr'] = list()
-        nsr={}
-        nsr['id']=str(uuid.uuid1())
-
-        nsd=self.get_nsd(nsd_name)
-        if nsd is None:
-            raise Exception('cannot find nsd {}'.format(nsd_name)) 
-        
-        datacenter=self.get_datacenter(account)
-        if datacenter is None:
-            raise Exception('cannot find datacenter account {}'.format(account)) 
-
-        nsr['nsd']=nsd
-        nsr['name']=nsr_name
-        nsr['short-name']=nsr_name
-        nsr['description']=description
-        nsr['admin-status']=admin_status
-        nsr['om-datacenter']=datacenter['uuid']
-
-        if ssh_keys is not None:
-            # ssh_keys is comma separate list
-            ssh_keys_format=[]
-            for key in ssh_keys.split(','):
-                ssh_keys_format.append({'key-pair-ref':key})
-
-            nsr['ssh-authorized-key']=ssh_keys_format
-
-        if vim_network_prefix is not None:
-            for index,vld in enumerate(nsr['nsd']['vld']):
-                network_name = vld['name']
-                nsr['nsd']['vld'][index]['vim-network-name'] = '{}-{}'.format(vim_network_prefix,network_name)
-
-        postdata['nsr'].append(nsr)
-        jsondata=json.dumps(postdata)
-        curl_cmd.setopt(pycurl.POSTFIELDS,jsondata)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        resp = json.loads(data.getvalue().decode())
-        pprint.pprint(resp)
-
-    def delete_nsd(self,nsd_name):
-        nsd=self.get_nsd(nsd_name)
-        if nsd is None:
-            raise Exception('cannot find nsd {}'.format(nsd_name)) 
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('api/running/nsd-catalog/nsd/'+nsd['id'])
-        curl_cmd.setopt(pycurl.CUSTOMREQUEST, "DELETE")
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        resp = json.loads(data.getvalue().decode())
-        pprint.pprint(resp)
-
-    def delete_vnfd(self,vnfd_name):
-        vnfd=self.get_vnfd(vnfd_name)
-        if vnfd is None:
-            raise Exception('cannot find vnfd {}'.format(vnfd_name)) 
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('api/running/vnfd-catalog/vnfd/'+vnfd['id'])
-        curl_cmd.setopt(pycurl.CUSTOMREQUEST, "DELETE")
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        resp = json.loads(data.getvalue().decode())
-        pprint.pprint(resp)
-
-    def terminate_ns(self,ns_name):
-        ns=self.get_ns(ns_name)
-        if ns is None:
-            raise Exception('cannot find ns {}'.format(ns_name)) 
-  
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('api/config/ns-instance-config/nsr/'+ns['id'])
-        curl_cmd.setopt(pycurl.CUSTOMREQUEST, "DELETE")
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        resp = json.loads(data.getvalue().decode())
-        pprint.pprint(resp)
-
-    def upload_package(self,filename):
-        data = BytesIO()
-        curl_cmd=self.get_curl_upload_cmd(filename)
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        resp = json.loads(data.getvalue().decode())
-        pprint.pprint(resp)
-      
-    def add_vim_account(self,name,user_name,secret,auth_url,tenant,mgmt_network,float_ip_pool,account_type='openstack'):
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('api/config/cloud')
-        curl_cmd.setopt(pycurl.POST,1)
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        vim_account={}
-        vim_account['account']={}
-
-        vim_account['account']['name'] = name
-        vim_account['account']['account-type'] = account_type
-        vim_account['account'][account_type] = {}
-        vim_account['account'][account_type]['key'] = user_name
-        vim_account['account'][account_type]['secret'] = secret
-        vim_account['account'][account_type]['auth_url'] = auth_url
-        vim_account['account'][account_type]['tenant'] = tenant
-        vim_account['account'][account_type]['mgmt-network'] = mgmt_network
-        vim_account['account'][account_type]['floating-ip-pool'] = float_ip_pool
-
-        jsondata=json.dumps(vim_account)
-        curl_cmd.setopt(pycurl.POSTFIELDS,jsondata)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        resp = json.loads(data.getvalue().decode())
-        pprint.pprint(resp)
-
-    def list_vim_accounts(self):
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('v1/api/operational/datacenters')
-        curl_cmd.setopt(pycurl.HTTPGET,1)
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        resp = json.loads(data.getvalue().decode())
-        datacenters=resp['rw-launchpad:datacenters']
-        if 'ro-accounts' in datacenters:
-            return datacenters['ro-accounts']
-        return list()
-
-    def get_datacenter(self,name):
-        data = BytesIO()
-        curl_cmd=self.get_curl_cmd('v1/api/operational/datacenters')
-        curl_cmd.setopt(pycurl.HTTPGET,1)
-        curl_cmd.setopt(pycurl.WRITEFUNCTION, data.write)
-        curl_cmd.perform() 
-        curl_cmd.close()
-        resp = json.loads(data.getvalue().decode())
-        datacenters=resp['rw-launchpad:datacenters']
-        if 'ro-accounts' in datacenters:
-            for roaccount in datacenters['ro-accounts']:
-                if not 'datacenters' in roaccount:
-                    continue
-                for datacenter in roaccount['datacenters']:
-                    if datacenter['name'] == name:
-                        return datacenter
-        return None
-
-    def show_ns(self,ns_name):
-        resp = self.get_ns_instance_list()
-        table=PrettyTable(['attribute','value'])
-
-        if 'nsr' in resp:
-            for ns in resp['nsr']:
-                if ns_name == ns['name']:
-                    # dump ns config
-                    for k,v in ns.items():
-                        table.add_row([k,json.dumps(v,indent=2)])
-
-                    nsopdata=self.get_ns_opdata(ns['id'])
-                    nsr_optdata=nsopdata['nsr:nsr']
-                    for k,v in nsr_optdata.items():
-                        table.add_row([k,json.dumps(v,indent=2)])
-        table.align='l'
-        print(table)
-
-    def show_ns_scaling(self,ns_name):
-        resp = self.get_ns_instance_list()
-
-        table=PrettyTable(['instance-id','operational status','create-time','vnfr ids'])
-
-        if 'nsr' in resp:
-            for ns in resp['nsr']:
-                if ns_name == ns['name']:
-                    nsopdata=self.get_ns_opdata(ns['id'])
-                    scaling_records=nsopdata['nsr:nsr']['scaling-group-record']
-                    for record in scaling_records:
-                        if 'instance' in record:
-                            instances=record['instance'] 
-                            for inst in instances:
-                                table.add_row([inst['instance-id'],inst['op-status'],time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(inst['create-time'])),inst['vnfrs']])
-        table.align='l'
-        print(table)
-
-    def list_vnfr(self):
-        return self.get_vnfr_catalog()
-
-    def list_vnf_catalog(self):
-        resp = self.get_vnf_catalog()
-        table=PrettyTable(['vnfd name','id'])
-        for ns in resp['vnfd:vnfd']:
-            table.add_row([ns['name'],ns['id']])
-        table.align='l'
-        print(table)
diff --git a/python-osmclient/osmclient/common/__init__.py b/python-osmclient/osmclient/common/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/python-osmclient/osmclient/scripts/__init__.py b/python-osmclient/osmclient/scripts/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/python-osmclient/osmclient/scripts/osm.py b/python-osmclient/osmclient/scripts/osm.py
deleted file mode 100755 (executable)
index d74580c..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-import click
-from osmclient.common import OsmAPI
-from prettytable import PrettyTable
-import pprint
-import textwrap
-
-@click.group()
-@click.option('--hostname',default=None,envvar='OSM_HOSTNAME',help='hostname of server.  Also can set OSM_HOSTNAME in environment')
-@click.pass_context
-def cli(ctx,hostname):
-    if hostname is None:
-        print("either hostname option or OSM_HOSTNAME environment variable needs to be specified") 
-        exit(1)
-    ctx.obj=OsmAPI.OsmAPI(hostname)
-
-@cli.command(name='ns-list')
-@click.pass_context
-def ns_list(ctx):
-    ctx.obj.list_ns_instance()
-
-@cli.command(name='nsd-list')
-@click.pass_context
-def nsd_list(ctx):
-    ctx.obj.list_ns_catalog()
-
-@cli.command(name='vnfd-list')
-@click.pass_context
-def vnfd_list(ctx):
-    ctx.obj.list_vnf_catalog()
-
-@cli.command(name='vnf-list')
-@click.pass_context
-def vnf_list(ctx):
-    resp=ctx.obj.list_vnfr()
-    table=PrettyTable(['vnf name','id','operational status','config Status','mgmt interface','nsr id'])
-    if resp is not None:
-        for vnfr in resp['vnfr:vnfr']:
-            if not 'mgmt-interface' in vnfr:
-                vnfr['mgmt-interface'] = {}
-                vnfr['mgmt-interface']['ip-address'] = None
-            table.add_row([vnfr['name'],vnfr['id'],vnfr['operational-status'],vnfr['config-status'],vnfr['mgmt-interface']['ip-address'],vnfr['nsr-id-ref']])
-        table.align='l'
-    print(table)
-
-@cli.command(name='vnf-monitoring-show')
-@click.argument('vnf_name')
-@click.pass_context
-def vnf_monitoring_show(ctx,vnf_name):
-    resp=ctx.obj.get_vnf_monitoring(vnf_name)
-    table=PrettyTable(['vnf name','monitoring name','value','units'])
-    if resp is not None:
-        for monitor in resp:
-            table.add_row([vnf_name,monitor['name'],monitor['value-integer'],monitor['units']])
-    table.align='l'
-    print(table)
-
-@cli.command(name='ns-monitoring-show')
-@click.argument('ns_name')
-@click.pass_context
-def ns_monitoring_show(ctx,ns_name):
-    resp=ctx.obj.get_ns_monitoring(ns_name)
-    table=PrettyTable(['vnf name','monitoring name','value','units'])
-    if resp is not None:
-        for key,val in resp.items():
-            for monitor in val:
-                table.add_row([key,monitor['name'],monitor['value-integer'],monitor['units']])
-    table.align='l'
-    print(table)
-
-@cli.command(name='ns-create')
-@click.argument('nsd_name')
-@click.argument('ns_name')
-@click.argument('vim_account')
-@click.option('--admin_status',default='ENABLED',help='administration status')
-@click.option('--ssh_keys',default=None,help='comma separated list of keys to inject to vnfs')
-@click.option('--vim_network_prefix',default=None,help='vim network name prefix')
-@click.pass_context
-def ns_create(ctx,nsd_name,ns_name,vim_account,admin_status,ssh_keys,vim_network_prefix):
-    ctx.obj.instantiate_ns(nsd_name,ns_name,vim_network_prefix=vim_network_prefix,ssh_keys=ssh_keys,account=vim_account)
-
-@cli.command(name='ns-delete')
-@click.argument('ns_name')
-@click.pass_context
-def ns_delete(ctx,ns_name):
-    ctx.obj.terminate_ns(ns_name)
-
-'''
-@cli.command(name='keypair-list')
-@click.pass_context
-def keypair_list(ctx):
-    resp=ctx.obj.list_key_pair()
-    table=PrettyTable(['key Name','key'])
-    for kp in resp:
-        table.add_row([kp['name'],kp['key']])
-    table.align='l'
-    print(table)
-'''
-
-@cli.command(name='upload-package')
-@click.argument('filename')
-@click.pass_context
-def upload_package(ctx,filename):
-    ctx.obj.upload_package(filename)
-
-@cli.command(name='ns-show')
-@click.argument('ns_name')
-@click.pass_context
-def ns_show(ctx,ns_name):
-    ctx.obj.show_ns(ns_name)
-
-@cli.command(name='ns-scaling-show')
-@click.argument('ns_name')
-@click.pass_context
-def show_ns_scaling(ctx,ns_name):
-    ctx.obj.show_ns_scaling(ns_name)
-
-@cli.command(name='nsd-delete')
-@click.argument('nsd_name')
-@click.pass_context
-def nsd_delete(ctx,nsd_name):
-    ctx.obj.delete_nsd(nsd_name)
-
-@cli.command(name='vnfd-delete')
-@click.argument('vnfd_name')
-@click.pass_context
-def nsd_delete(ctx,vnfd_name):
-    ctx.obj.delete_vnfd(vnfd_name)
-
-@cli.command(name='config-agent-list')
-@click.pass_context
-def config_agent_list(ctx):
-    table=PrettyTable(['name','account-type','details'])
-    for account in ctx.obj.get_config_agents():
-      table.add_row([account['name'],account['account-type'],account['juju']])
-    table.align='l'
-    print(table)
-
-@cli.command(name='config-agent-delete')
-@click.argument('name')
-@click.pass_context
-def config_agent_delete(ctx,name):
-    ctx.obj.delete_config_agent(name)
-
-@cli.command(name='config-agent-add')
-@click.argument('name')
-@click.argument('account_type')
-@click.argument('server')
-@click.argument('user')
-@click.argument('secret')
-@click.pass_context
-def config_agent_add(ctx,name,account_type,server,user,secret):
-    ctx.obj.add_config_agent(name,account_type,server,user,secret)
-
-'''
-@cli.command(name='vim-create')
-@click.argument('name')
-@click.argument('user')
-@click.argument('password')
-@click.argument('auth_url')
-@click.argument('tenant')
-@click.argument('mgmt_network')
-@click.argument('floating_ip_pool')
-@click.option('--account_type',default='openstack')
-@click.pass_context
-def vim_create(ctx,name,user,password,auth_url,tenant,mgmt_network,floating_ip_pool,account_type):
-    ctx.obj.add_vim_account(name,user,password,auth_url,tenant,mgmt_network,floating_ip_pool,account_type)
-'''
-
-@cli.command(name='vim-list')
-@click.pass_context
-def vim_list(ctx):
-    resp=ctx.obj.list_vim_accounts()
-    table=PrettyTable(['ro-account','datacenter name','uuid'])
-    for roaccount in resp:
-        for datacenter in roaccount['datacenters']:
-            table.add_row([roaccount['name'],datacenter['name'],datacenter['uuid']])
-    table.align='l'
-    print(table)
-
-@cli.command(name='vcs-list')
-@click.pass_context
-def vcs_list(ctx):
-    resp=ctx.obj.get_vcs_info()
-    table=PrettyTable(['component name','state'])
-    for component in resp:
-        table.add_row([component['component_name'],component['state']])
-    table.align='l'
-    print(table)
-
-if __name__ == '__main__':
-    cli()
diff --git a/python-osmclient/setup.py b/python-osmclient/setup.py
deleted file mode 100644 (file)
index 13b1771..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-from setuptools import setup,find_packages
-
-setup(
-    name='osmclient',
-    version='0.1',
-    author='Mike Marchetti',
-    author_email='mmarchetti@sandvine.com',
-    packages=find_packages(),
-    include_package_data=True,
-    install_requires=[
-        'Click','prettytable'
-    ],
-    entry_points='''
-        [console_scripts]
-        osm=osmclient.scripts.osm:cli
-        ''',
-)
diff --git a/python-osmclient/stdeb.cfg b/python-osmclient/stdeb.cfg
deleted file mode 100644 (file)
index eadf0fa..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-[DEFAULT]
-Depends: python-setuptools, python-pycurl, python-click, python-prettytable
index 42edf3c..d7168a9 100644 (file)
@@ -6,8 +6,12 @@ function loadStories() {
   // require('../tests/stories/sshKeyCard');
   // require('../tests/stories/button');
   // require('../tests/stories/sq-input-slider');
-  require('../tests/stories/catalogCard');
+  // require('../tests/stories/catalogCard');
+  require('../tests/stories/FileManager');
+  require('../tests/stories/inputs');
   // require as many stories as you need.
 }
 
 configure(loadStories, module);
+
+
diff --git a/skyquake/framework/core/api_utils/auth.js b/skyquake/framework/core/api_utils/auth.js
new file mode 100644 (file)
index 0000000..7249ac7
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ *
+ *   Copyright 2017 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+/**
+ * Auth util for use across the api_server.
+ * @module framework/core/api_utils/auth
+ * @author Kiran Kashalkar <kiran.kashalkar@riftio.com>
+ */
+
+var jsonLoader = require('require-json');
+var passport = require('passport');
+var OpenIdConnectStrategy = require('passport-openidconnect').Strategy;
+var BearerStrategy = require('passport-http-bearer').Strategy;
+var OAuth2Strategy = require('passport-oauth2');
+var OAuth2RefreshTokenStrategy = require('passport-oauth2-middleware').Strategy;
+var openidConnectConfig = require('./openidconnect_config.json');
+var _ = require('lodash');
+var constants = require('./constants');
+var utils = require('./utils');
+var request = utils.request;
+var rp = require('request-promise');
+var nodeutil = require('util');
+
+
+var Authorization = function(openidConfig) {
+
+    var self = this;
+
+    self.passport = passport;
+
+    self.openidConnectConfig = openidConnectConfig;
+
+    var refreshStrategy = new OAuth2RefreshTokenStrategy({
+        refreshWindow: constants.REFRESH_WINDOW, // Time in seconds to perform a token refresh before it expires
+        userProperty: 'user', // Active user property name to store OAuth tokens
+        authenticationURL: '/login', // URL to redirect unauthorized users to
+        callbackParameter: 'callback' //URL query parameter name to pass a return URL
+    });
+
+    self.passport.use('main', refreshStrategy);
+
+    var openidConfigPrefix = openidConfig.idpServerProtocol + '://' + openidConfig.idpServerAddress + ':' + openidConfig.idpServerPortNumber;
+
+    self.openidConnectConfig.authorizationURL = openidConfigPrefix + self.openidConnectConfig.authorizationURL;
+    self.openidConnectConfig.tokenURL = openidConfigPrefix + self.openidConnectConfig.tokenURL;
+    self.openidConnectConfig.callbackURL = openidConfig.callbackServerProtocol + '://' + openidConfig.callbackAddress + ':' + openidConfig.callbackPortNumber + self.openidConnectConfig.callbackURL;
+
+    var userInfoURL = openidConfigPrefix + self.openidConnectConfig.userInfoURL;
+
+    function SkyquakeOAuth2Strategy(options, verify) {
+        OAuth2Strategy.call(this, options, verify);
+    }
+    nodeutil.inherits(SkyquakeOAuth2Strategy, OAuth2Strategy);
+
+    SkyquakeOAuth2Strategy.prototype.userProfile = function(access_token, done) {
+
+        var requestHeaders = {
+            'Authorization': 'Bearer ' + access_token
+        };
+
+        request({
+            url: userInfoURL,
+            type: 'GET',
+            headers: requestHeaders,
+            forever: constants.FOREVER_ON,
+            rejectUnauthorized: constants.REJECT_UNAUTHORIZED
+        }, function(err, response, body) {
+            if (err) {
+                console.log('Error obtaining userinfo: ', err);
+                return done(null, {
+                    username: '',
+                    subject: ''
+                });
+            } else {
+                if (response.statusCode == constants.HTTP_RESPONSE_CODES.SUCCESS.OK) {
+                    try {
+                        var data = JSON.parse(response.body);
+                        var username = data['preferred_username'];
+                        var subject = data['sub'];
+                        var domain = data['user_domain'] || 'system';
+                        return done(null, {
+                            username: username,
+                            subject: subject,
+                            domain: domain
+                        })
+                    } catch (ex) {
+                        console.log('Error parsing userinfo data');
+                        return done(null, {
+                            username: '',
+                            subject: ''
+                        });
+                    }
+                }
+            }
+        })
+    };
+
+    var oauthStrategy = new SkyquakeOAuth2Strategy(self.openidConnectConfig,
+        refreshStrategy.getOAuth2StrategyCallback());
+
+    self.passport.use('oauth2', oauthStrategy);
+    refreshStrategy.useOAuth2Strategy(oauthStrategy);
+
+    self.passport.serializeUser(function(user, done) {
+        done(null, user);
+    });
+
+    self.passport.deserializeUser(function(obj, done) {
+        done(null, obj);
+    });
+
+};
+
+Authorization.prototype.configure = function(config) {
+       this.config = config;
+       // Initialize Passport and restore authentication state, if any, from the
+    // session.
+    if (this.config.app) {
+       this.config.app.use(this.passport.initialize());
+       this.config.app.use(this.passport.session());
+    } else {
+       console.log('FATAL error. Bad config passed into authorization module');
+    }
+};
+
+Authorization.prototype.invalidate_token = function(token) {
+
+};
+
+module.exports = Authorization;
index 0aac7d2..b27e7da 100644 (file)
@@ -73,11 +73,21 @@ constants.SOCKET_BASE_PORT = 3500;
 constants.SOCKET_POOL_LENGTH = 20;
 constants.SERVER_PORT = process.env.SERVER_PORT || 8000;
 constants.SECURE_SERVER_PORT = process.env.SECURE_SERVER_PORT || 8443;
+constants.REJECT_UNAUTHORIZED = false;
 
-constants.BASE_PACKAGE_UPLOAD_DESTINATION = 'upload/packages/';
+constants.BASE_PACKAGE_UPLOAD_DESTINATION = 'upload';
 constants.PACKAGE_MANAGER_SERVER_PORT = 4567;
 constants.PACKAGE_FILE_DELETE_DELAY_MILLISECONDS = 3 * 1000 * 60; //5 minutes
 constants.PACKAGE_FILE_ONBOARD_TRANSACTION_STATUS_CHECK_DELAY_MILLISECONDS = 2 * 1000; //2 seconds
 
+constants.REFRESH_WINDOW = 10; //Time in seconds to perform a token refresh before it expires
+constants.LAUNCHPAD_ADDRESS = 'localhost';
+constants.LAUNCHPAD_PORT = 8008;
+constants.IDP_SERVER_PROTOCOL = 'https';
+constants.IDP_PORT_NUMBER = 8009;
+constants.CALLBACK_SERVER_PROTOCOL = 'https';
+constants.CALLBACK_PORT_NUMBER = 8443;
+constants.CALLBACK_ADDRESS = 'localhost';
+constants.END_SESSION_PATH = 'end_session';
 
 module.exports = constants;
\ No newline at end of file
diff --git a/skyquake/framework/core/api_utils/csrf.js b/skyquake/framework/core/api_utils/csrf.js
new file mode 100644 (file)
index 0000000..62855f2
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *
+ *   Copyright 2017 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+/**
+ * CSRF util for use across the api_server.
+ * @module framework/core/api_utils/csrf
+ * @author Kiran Kashalkar <kiran.kashalkar@riftio.com>
+ */
+
+var constants = require('./constants.js');
+var utils = require('./utils.js');
+
+var target = null;
+
+function configure(config) {
+       target = config.target;
+}
+
+function csrfCheck(req, res, next) {
+       var host = null;
+
+       if (req.headers.origin != 'null') {
+               host = utils.getHostNameFromURL(req.headers.origin);
+       } else if (req.headers.referer) {
+               host = utils.getHostNameFromURL(req.headers.referer);
+       } else {
+               var msg = 'Request did not contain an origin or referer header. Request terminated.';
+               var error = {};
+               error.statusCode = constants.HTTP_RESPONSE_CODES.ERROR.METHOD_NOT_ALLOWED;
+               error.errorMessage = {
+                       error: msg
+               }
+               return utils.sendErrorResponse(error, res);
+       }
+
+       if (!host || host != target) {
+               var msg = 'Request did not originate from authorized source (Potential CSRF attempt). Request terminated.';
+               var error = {};
+               error.statusCode = constants.HTTP_RESPONSE_CODES.ERROR.METHOD_NOT_ALLOWED;
+               error.errorMessage = {
+                       error: msg
+               }
+               return utils.sendErrorResponse(error, res);
+       } else {
+               return next();
+       }
+}
+
+module.exports = {
+       configure: configure,
+       csrfCheck: csrfCheck
+};
\ No newline at end of file
diff --git a/skyquake/framework/core/api_utils/openidconnect_config.json b/skyquake/framework/core/api_utils/openidconnect_config.json
new file mode 100644 (file)
index 0000000..63c4a1d
--- /dev/null
@@ -0,0 +1,9 @@
+{
+       "scope": "openid",
+    "clientID": "cncudWkub3BlbmlkY2xpZW50",
+    "clientSecret": "riftiorocks",
+    "authorizationURL": "/authorization",
+    "tokenURL": "/token",
+    "userInfoURL": "/userinfo",
+    "callbackURL": "/callback"
+}
\ No newline at end of file
index 5e0b25b..a86f5ed 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,6 +33,7 @@ var url = require('url');
 var sockjs = require('sockjs');
 var websocket_multiplex = require('websocket-multiplex');
 var utils = require('./utils.js');
+var configurationAPI = require('../modules/api/configuration.js');
 
 
 var Subscriptions = function() {
@@ -182,7 +183,7 @@ Subscriptions.prototype.socketInstance = function(url, req, wss, Type, channelId
       if (Type == PollingSocket) {
         Socket = new Type(url, req, 1000, req.body);
       } else {
-        Socket = new Type(url);
+        Socket = new Type(url, ['Bearer', req.session.passport.user.user['access_token']]);
       }
       console.log('Socket assigned for url', url);
     }
@@ -278,12 +279,12 @@ function PollingSocket(url, req, interval, config) {
   self.isClosed = false;
   var requestHeaders = {};
   _.extend(requestHeaders, {
-    'Authorization': req.get('Authorization')
+    Cookie: req.get('Cookie')
   });
 
   var pollServer = function() {
     Request({
-      url: url,
+      url: utils.projectContextUrl(req, url),
       method: config.method || 'GET',
       headers: requestHeaders,
       json: config.payload,
@@ -294,7 +295,11 @@ function PollingSocket(url, req, interval, config) {
         console.log('Error polling: ' + url);
       } else {
         if (!self.isClosed) {
-          self.poll = setTimeout(pollServer, 1000 || interval);
+          if(process.env.DISABLE_POLLING != "TRUE") {
+            self.poll = setTimeout(pollServer, 1000 || interval);
+          } else {
+            console.log('Polling is disabled. Finishing request.')
+          }
           var data = response.body;
           if (self.onmessage) {
             self.onmessage(data);
index 5b17279..cdf12fc 100644 (file)
@@ -49,6 +49,41 @@ var confdPort = function(api_server) {
        return api_server + ':' + CONFD_PORT;
 };
 
+var projectContextUrl = function(req, url) {
+       //NOTE: We need to go into the sessionStore because express-session
+       // does not reliably update the session.
+       // See https://github.com/expressjs/session/issues/450
+       var projectId = (req.session &&
+                                        req.sessionStore &&
+                                        req.sessionStore.sessions &&
+                                        req.sessionStore.sessions[req.session.id] &&
+                                        JSON.parse(req.sessionStore.sessions[req.session.id])['projectId']) ||
+                                        (null);
+       if (projectId) {
+               projectId = encodeURIComponent(projectId);
+               return url.replace(/(\/api\/operational\/|\/api\/config\/)(.*)/, '$1project/' + projectId + '/$2');
+       }
+       return url;
+}
+
+var addProjectContextToRPCPayload = function(req, url, inputPayload) {
+       //NOTE: We need to go into the sessionStore because express-session
+       // does not reliably update the session.
+       // See https://github.com/expressjs/session/issues/450
+       var projectId = (req.session &&
+                                        req.sessionStore &&
+                                        req.sessionStore.sessions &&
+                                        req.sessionStore.sessions[req.session.id] &&
+                                        JSON.parse(req.sessionStore.sessions[req.session.id])['projectId']) ||
+                                        (null);
+       if (projectId) {
+               if (url.indexOf('/api/operations/')) {
+                       inputPayload['project-name'] = projectId;
+               }
+       }
+       return inputPayload;
+}
+
 
 var validateResponse = function(callerName, error, response, body, resolve, reject) {
        var res = {};
@@ -61,12 +96,12 @@ var validateResponse = function(callerName, error, response, body, resolve, reje
                };
                reject(res);
                return false;
-       } else if (response.statusCode >= 400) {
+       } else if (response.statusCode >= CONSTANTS.HTTP_RESPONSE_CODES.ERROR.BAD_REQUEST) {
                console.log('Problem with "', callerName, '": ', response.statusCode, ':', body);
                res.statusCode = response.statusCode;
 
                // auth specific
-               if (response.statusCode == 401) {
+               if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.ERROR.UNAUTHORIZED) {
                        res.errorMessage = {
                                error: 'Authentication needed' + body
                        };
@@ -81,7 +116,7 @@ var validateResponse = function(callerName, error, response, body, resolve, reje
 
                reject(res);
                return false;
-       } else if (response.statusCode == 204) {
+       } else if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.SUCCESS.NO_CONTENT) {
                resolve({
                        statusCode: response.statusCode,
                        data: {}
@@ -95,7 +130,7 @@ var validateResponse = function(callerName, error, response, body, resolve, reje
 
 var checkAuthorizationHeader = function(req) {
        return new Promise(function(resolve, reject) {
-               if (req.get('Authorization') == null) {
+               if (req.session && req.session.authorization == null) {
                        reject();
                } else {
                        resolve();
@@ -119,12 +154,12 @@ if (process.env.LOG_REQUESTS) {
                                reject(res);
                                fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Error: ' + error);
                                return false;
-                       } else if (response.statusCode >= 400) {
+                       } else if (response.statusCode >= CONSTANTS.HTTP_RESPONSE_CODES.ERROR.BAD_REQUEST) {
                                console.log('Problem with "', callerName, '": ', response.statusCode, ':', body);
                                res.statusCode = response.statusCode;
 
                                // auth specific
-                               if (response.statusCode == 401) {
+                               if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.ERROR.UNAUTHORIZED) {
                                        res.errorMessage = {
                                                error: 'Authentication needed' + body
                                        };
@@ -140,7 +175,7 @@ if (process.env.LOG_REQUESTS) {
                                reject(res);
                                fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Error Body: ' + body);
                                return false;
-                       } else if (response.statusCode == 204) {
+                       } else if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.SUCCESS.NO_CONTENT) {
                                resolve();
                                fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Response Body: ' + body);
                                return false;
@@ -162,6 +197,9 @@ if (process.env.LOG_REQUESTS) {
  * @param {Function} res - a handle to the express response function
  */
 var sendErrorResponse = function(error, res) {
+       if (!error.statusCode) {
+               console.error('Status Code has not been set in error object: ', error);
+       }
        res.status(error.statusCode);
        res.send(error);
 }
@@ -197,10 +235,10 @@ var passThroughConstructor = function(app) {
                }
                new Promise(function(resolve, reject) {
                        request({
-                               uri: uri,
+                               uri: projectContextUrl(req, uri),
                                method: 'GET',
                                headers: _.extend({}, CONSTANTS.HTTP_HEADERS.accept[type], {
-                                       'Authorization': req.get('Authorization'),
+                                       'Authorization': req.session && req.session.authorization,
                                        forever: CONSTANTS.FOREVER_ON,
                                        rejectUnauthorized: false,
                                })
@@ -226,6 +264,31 @@ var getPortForProtocol = function(protocol) {
   }
 }
 
+var buildRedirectURL = function(req, globalConfiguration, plugin, extra) {
+    var api_server = req.query['api_server'] || (req.protocol + '://' + globalConfiguration.get().api_server);
+    var download_server = req.query['dev_download_server'] || globalConfiguration.get().dev_download_server;
+       var url = '/';
+       url += plugin;
+       url += '/?api_server=' + api_server;
+       url += download_server ? '&dev_download_server=' + download_server : '';
+       url += extra || '';
+       return url;
+}
+
+var getHostNameFromURL = function(url) {
+    var match = url.match(/^(https?\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)([^?#]*)(\?[^#]*|)(#.*|)$/);
+    return match && match[3];
+}
+
+var dataToJsonSansPropNameNamespace = function(s) {
+       var a = JSON.parse(s);
+       var b = JSON.stringify(a);
+       var c = b.replace(/{"[-\w]+:/g, '{"');
+       var d = c.replace(/,"[-\w]+:/g, ',"');
+       var j = JSON.parse(d);
+       return j;
+}
+
 module.exports = {
        /**
         * Ensure confd port is on api_server variable.
@@ -244,5 +307,15 @@ module.exports = {
 
     passThroughConstructor: passThroughConstructor,
 
-    getPortForProtocol: getPortForProtocol
+    getPortForProtocol: getPortForProtocol,
+
+    projectContextUrl: projectContextUrl,
+
+       addProjectContextToRPCPayload: addProjectContextToRPCPayload,
+
+       buildRedirectURL: buildRedirectURL,
+
+       getHostNameFromURL: getHostNameFromURL,
+
+       dataToJsonSansPropNameNamespace: dataToJsonSansPropNameNamespace
 };
diff --git a/skyquake/framework/core/modules/api/appConfigAPI.js b/skyquake/framework/core/modules/api/appConfigAPI.js
new file mode 100644 (file)
index 0000000..ce93bdc
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+// DescriptorModelMeta API (NSD + VNFD)
+
+
+var Schema = {};
+var request = require('request');
+var Promise = require('promise');
+var constants = require('../../api_utils/constants');
+var utils = require('../../api_utils/utils');
+var _ = require('lodash');
+var cors = require('cors');
+var bodyParser = require('body-parser');
+var utils = require('../../api_utils/utils');
+var sessionAPI = require('./sessions.js');
+var configuration = require('./configuration');
+
+var router = require('express').Router();
+
+router.use(bodyParser.json());
+router.use(cors());
+router.use(bodyParser.urlencoded({
+    extended: true
+}));
+
+router.get('/app-config', cors(), function (req, res) {
+    getConfig(req).then(function (response) {
+        utils.sendSuccessResponse(response, res);
+    }, function (error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+
+var inactivityTimeout = process.env.UI_TIMEOUT_SECS || 600000;
+
+var versionPromise = null;
+
+var init = function () {
+    versionPromise = new Promise(
+        function (resolve, reject) {
+            sessionAPI.sessionPromise.then(
+                function (session) {
+                    request({
+                            url: configuration.getBackendURL() + '/api/operational/version',
+                            type: 'GET',
+                            headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                                'Authorization': session.authorization
+                            }),
+                            forever: constants.FOREVER_ON,
+                            rejectUnauthorized: false
+                        },
+                        function (error, response, body) {
+                            var data;
+                            if (utils.validateResponse('schema/version.get', error, response, body, resolve, reject)) {
+                                try {
+                                    data = JSON.parse(response.body)['rw-base:version'];
+                                    resolve(data.version);
+                                } catch (e) {
+                                    return reject({});
+                                }
+                            } else {
+                                console.log(error);
+                            }
+                        });
+                });
+        });
+}
+
+var getConfig = function (req) {
+    var api_server = req.query['api_server'];
+
+    var requests = [versionPromise];
+
+    return new Promise(function (resolve, reject) {
+        Promise.all(requests).then(
+            function (results) {
+                var data = {
+                    version: results[0],
+                    'api-server': configuration.getBackendURL,
+                    'inactivity-timeout': process.env.UI_TIMEOUT_SECS || 600000 
+                }
+                resolve({
+                    data: data,
+                    statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+                });
+            }).catch(
+            function (error) {
+                var response = {};
+                console.log('Problem with config.get', error);
+                response.statusCode = error.statusCode || 500;
+                response.errorMessage = {
+                    error: 'Failed to get config' + error
+                };
+                reject(response);
+            });
+    });
+};
+
+module.exports = {
+    getRouter: function () {
+        return router;
+    },
+    init: init
+};
\ No newline at end of file
index 3762643..d1fca27 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,7 +30,11 @@ var configurationAPI = {};
 var _ = require('lodash');
 var GLOBAL_CONFIGURATION = {
     api_server: 'localhost',
-    ssl_enabled: true
+    ssl_enabled: true,
+    api_server_port_number: constants.SECURE_SERVER_PORT,
+    idp_server_address: constants.LAUNCHPAD_ADDRESS,
+    idp_server_protocol: constants.IDP_SERVER_PROTOCOL,
+    idp_server_port_number: constants.IDP_PORT_NUMBER
 };
 
 /**
@@ -92,4 +96,18 @@ configurationAPI.globalConfiguration.get = function() {
     return GLOBAL_CONFIGURATION;
 };
 
+var backendURL = null;
+configurationAPI.getBackendURL = function () {
+       if (!backendURL) {
+               backendURL = GLOBAL_CONFIGURATION.api_server_protocol + '://' + GLOBAL_CONFIGURATION.api_server + ':' + GLOBAL_CONFIGURATION.api_server_port_number;
+       }
+       return backendURL;
+}
+
+configurationAPI.getBackendAPI = function () {
+       return configurationAPI.getBackendURL() + '/v2/api';
+}
+
+
+
 module.exports = configurationAPI;
index b0223b2..34d30b3 100644 (file)
@@ -36,7 +36,7 @@ ModelMeta.get = function(req) {
                 uri: utils.confdPort(api_server) + '/api/schema/nsd-catalog/nsd',
                 method: 'GET',
                 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
-                    'Authorization': req.get('Authorization')
+                    'Authorization': req.session && req.session.authorization
                 }),
                 forever: constants.FOREVER_ON,
                 rejectUnauthorized: false,
@@ -46,7 +46,7 @@ ModelMeta.get = function(req) {
                 uri: utils.confdPort(api_server) + '/api/schema/vnfd-catalog/vnfd',
                 method: 'GET',
                 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
-                    'Authorization': req.get('Authorization')
+                    'Authorization': req.session && req.session.authorization
                 }),
                 forever: constants.FOREVER_ON,
                 rejectUnauthorized: false,
diff --git a/skyquake/framework/core/modules/api/modelAPI.js b/skyquake/framework/core/modules/api/modelAPI.js
new file mode 100644 (file)
index 0000000..1f14cb7
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * 
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+// DescriptorModelMeta API (NSD + VNFD)
+
+
+var Schema = {};
+var rp = require('request-promise');
+var Promise = require('promise');
+var constants = require('../../api_utils/constants');
+var utils = require('../../api_utils/utils');
+var _ = require('lodash');
+var cors = require('cors');
+var bodyParser = require('body-parser');
+var utils = require('../../api_utils/utils');
+var configuration = require('./configuration');
+
+var router = require('express').Router();
+
+
+router.use(bodyParser.json());
+router.use(cors());
+router.use(bodyParser.urlencoded({
+    extended: true
+}));
+
+router.get('/model', cors(), function (req, res) {
+    get(req).then(function (response) {
+        utils.sendSuccessResponse(response, res);
+    }, function (error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+
+router.patch('/model', cors(), function (req, res) {
+    update(req).then(function (response) {
+        utils.sendSuccessResponse(response, res);
+    }, function (error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+
+router.put('/model', cors(), function (req, res) {
+    add(req).then(function (response) {
+        utils.sendSuccessResponse(response, res);
+    }, function (error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+
+router.delete('/model', cors(), function (req, res) {
+    remove(req).then(function (response) {
+        utils.sendSuccessResponse(response, res);
+    }, function (error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+
+module.exports = {
+    getRouter: function () {
+        return router;
+    },
+    init: function () {}
+};
+
+get = function (req) {
+    var backend = configuration.getBackendAPI();
+    var modelPath = req.query['path'];
+    var requestHeaders = _.extend({}, constants.HTTP_HEADERS.accept.collection, {
+        'Authorization': req.session && req.session.authorization
+    })
+    return new Promise(function (resolve, reject) {
+        Promise.all([
+            rp({
+                uri: backend + '/config' + modelPath,
+                method: 'GET',
+                headers: requestHeaders,
+                forever: constants.FOREVER_ON,
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+                // }),
+                // rp({
+                //     uri: utils.projectContextUrl(req, backend + '/api/operational' + modelPath),
+                //     method: 'GET',
+                //     headers: requestHeaders,
+                //     forever: constants.FOREVER_ON,
+                //     rejectUnauthorized: false,
+                //     resolveWithFullResponse: true
+            })
+        ]).then(function (results) {
+            var response = {
+                statusCode: results[0].statusCode || 200,
+                data: [null]
+            }
+            if (results[0].body && !results[0].error) {
+                var result = JSON.parse(results[0].body);
+                if (result.collection) {
+                    result = result.collection[Object.keys(result.collection)[0]];
+                    if (!result.length) {
+                        result = null;
+                    } else if (result.length === 1) {
+                        result = result[0];
+                    }
+                }
+                response.data = result;
+            }
+            resolve(response);
+
+        }).catch(function (error) {
+            var res = {};
+            console.log('Problem with model get', error);
+            res.statusCode = error.statusCode || 500;
+            res.errorMessage = {
+                error: 'Failed to get model: ' + error
+            };
+            reject(res);
+        });
+    });
+};
+
+add = function (req) {
+    var backend = configuration.getBackendAPI();
+    var modelPath = req.query['path'];
+    var targetProperty = modelPath.split('/').pop();
+    var newElement = {};
+    var data = {};
+    console.log(req.body);
+    _.forIn(req.body, function (value, key) {
+        if (_.isObject(value)) {
+            if (value.type === 'leaf_empty') {
+                if (value.data) {
+                    data[key] = ' ';
+                }
+            } else if (value.type === 'leaf_list') {
+                data[key] = value.data.add;
+            }
+        } else {
+            data[key] = value;
+        }
+    });
+    newElement[targetProperty] = [data];
+    console.log(newElement);
+    var target = backend + '/config' + modelPath;
+    var method = 'POST'
+    var requestHeaders = _.extend({},
+        constants.HTTP_HEADERS.accept.data, {
+            'Authorization': req.session && req.session.authorization
+        });
+    return new Promise(function (resolve, reject) {
+        rp({
+            uri: target,
+            method: method,
+            headers: requestHeaders,
+            forever: constants.FOREVER_ON,
+            json: newElement,
+            rejectUnauthorized: false,
+            resolveWithFullResponse: true
+        }).then(function (results) {
+            var response = {};
+            response.data = {
+                path: modelPath,
+                data: data
+            };
+            response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK;
+            console.log(response);
+            resolve(response);
+        }).catch(function (result) {
+            var response = {};
+            var error = {};
+            if (result.error['rpc-reply']) {
+                error.type = result.error['rpc-reply']['rpc-error']['error-tag'];
+                error.message = result.error['rpc-reply']['rpc-error']['error-message'];
+                error.rpcError = result.error['rpc-reply']['rpc-error']
+            } else {
+                error.type = 'api-error';
+                error.message = 'invalid api call';
+            }
+            console.log('Problem with model update', error);
+            response.statusCode = error.statusCode || 500;
+            response.error = error;
+            reject(response);
+        });
+    });
+};
+
+update = function (req) {
+    var backend = configuration.getBackendAPI();
+    var modelPath = req.query['path'];
+    var requestHeaders = _.extend({},
+        constants.HTTP_HEADERS.accept.data, {
+            'Authorization': req.session && req.session.authorization
+        });
+    var base = backend + '/config' + modelPath + '/';
+
+    function getUpdatePromise(name, value) {
+        var data = {};
+        data[name] = value;
+        return new Promise(function (resolve, reject) {
+            rp({
+                uri: base + name,
+                method: value ? 'PATCH' : 'DELETE',
+                headers: requestHeaders,
+                forever: constants.FOREVER_ON,
+                json: data,
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+            }).then(function (result) {
+                resolve({
+                    element: name,
+                    success: true,
+                    value: value
+                });
+            }).catch(function (result) {
+                var error = {};
+                if (result.error['rpc-reply']) {
+                    error.type = result.error['rpc-reply']['rpc-error']['error-tag'];
+                    error.message = result.error['rpc-reply']['rpc-error']['error-message'];
+                    error.rpcError = result.error['rpc-reply']['rpc-error']
+                } else {
+                    error.type = 'api-error';
+                    error.message = 'invalid api call';
+                }
+                resolve({
+                    element: name,
+                    success: false,
+                    error: error,
+                    value: value
+                });
+            })
+        })
+    }
+
+    function getDeletePromise(targetProp, item) {
+        if (item) {
+            targetProp = targetProp + '/' + item;
+        }
+        return getUpdatePromise(targetProp, '');
+    }
+
+    var updates = [];
+    _.forIn(req.body, function (value, key) {
+        var data = {};
+        if (_.isObject(value)) {
+            if (value.type === 'leaf_list') {
+                _.forEach(value.data.remove, function (v) {
+                    updates.push(getDeletePromise(key))
+                })
+                _.forEach(value.data.add, function (v) {
+                    updates.push(getUpdatePromise(key, v))
+                })
+            } else if (value.type === 'leaf_empty') {
+                if (value.data) {
+                    updates.push(getUpdatePromise(key, ' '))
+                } else {
+                    updates.push(getDeletePromise(key))
+                }
+            }
+        } else {
+            updates.push(getUpdatePromise(key, value))
+        }
+    })
+
+    return new Promise(function (resolve, reject) {
+        Promise.all(updates).then(function (results) {
+            var response = {};
+            var output = {};
+            var hasError = false;
+            _.forEach(results, function (result) {
+                var record = {};
+                if (output[result.element]) {
+                    if (_.isArray(output[result.element].value)) {
+                        output[result.element].value.push(result.value);
+                    } else {
+                        output[result.element].value = [output[result.element].value, result.value];
+                    }
+                } else {
+                    output[result.element] = result;
+                }
+                hasError = hasError || !result.success
+            })
+            response.data = {
+                result: output,
+                hasError: hasError
+            };
+            response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK;
+            console.log(response);
+            resolve(response);
+        }).catch(function (result) {
+            var response = {};
+            var error = {};
+            if (result.error['rpc-reply']) {
+                error.type = result.error['rpc-reply']['rpc-error']['error-tag'];
+                error.message = result.error['rpc-reply']['rpc-error']['error-message'];
+                error.rpcError = result.error['rpc-reply']['rpc-error']
+            } else {
+                error.type = 'api-error';
+                error.message = 'invalid api call';
+            }
+            console.log('Problem with model update', error);
+            response.statusCode = error.statusCode || 500;
+            response.error = error;
+            reject(response);
+        });
+    });
+};
+
+remove = function (req) {
+    var backend = configuration.getBackendAPI();
+    var modelPath = req.query['path'];
+    var target = backend + '/config' + modelPath;
+    var requestHeaders = _.extend({},
+        constants.HTTP_HEADERS.accept.data,
+        constants.HTTP_HEADERS.content_type.data, {
+            'Authorization': req.session && req.session.authorization
+        })
+    return new Promise(function (resolve, reject) {
+        rp({
+            url: target,
+            method: 'DELETE',
+            headers: requestHeaders,
+            forever: constants.FOREVER_ON,
+            rejectUnauthorized: false,
+        }).then(function (response) {
+            return resolve({
+                statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.OK,
+                data: modelPath
+            });
+        }).catch(function (result) {
+            var response = {};
+            var error = {};
+            if (result.error['rpc-reply']) {
+                error.type = result.error['rpc-reply']['rpc-error']['error-tag'];
+                error.message = result.error['rpc-reply']['rpc-error']['error-message'];
+                error.rpcError = result.error['rpc-reply']['rpc-error']
+            } else {
+                error.type = 'api-error';
+                error.message = 'invalid api call';
+            }
+            console.log('Problem with model update', error);
+            response.statusCode = error.statusCode || 500;
+            response.error = error;
+            reject(response);
+        });
+    })
+}
\ No newline at end of file
diff --git a/skyquake/framework/core/modules/api/projectManagementAPI.js b/skyquake/framework/core/modules/api/projectManagementAPI.js
new file mode 100644 (file)
index 0000000..d65e890
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ *
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+// DescriptorModelMeta API (NSD + VNFD)
+
+
+var ProjectManagement = {};
+var Promise = require('bluebird');
+var rp = require('request-promise');
+var Promise = require('promise');
+var constants = require('../../api_utils/constants');
+var utils = require('../../api_utils/utils');
+var _ = require('lodash');
+var API_VERSION = 'v2';
+ProjectManagement.get = function(req, fields) {
+    var self = this;
+    var api_server = req.query['api_server'];
+    // by default just load basic info as this request is expensive
+    fields = fields || ['name', 'description', 'project-config'];
+    var select = fields.length ? '?fields=' + fields.join(';') : '';
+
+    return new Promise(function(resolve, reject) {
+        Promise.all([
+            rp({
+                uri: `${utils.confdPort(api_server)}/${API_VERSION}/api/operational/project` + select,
+                method: 'GET',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': req.session && req.session.authorization
+                }),
+                forever: constants.FOREVER_ON,
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+            })
+        ]).then(function(result) {
+            var response = {};
+            response['data'] = {};
+            if (result[0].body) {
+                response['data']['project'] = JSON.parse(result[0].body)['rw-project:project'];
+            }
+            response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+            resolve(response);
+        }).catch(function(error) {
+            var response = {};
+            console.log('Problem with ProjectManagement.get', error);
+            response.statusCode = error.statusCode || 500;
+            response.errorMessage = {
+                error: 'Failed to get ProjectManagement' + error
+            };
+            reject(response);
+        });
+    });
+};
+
+ProjectManagement.create = function(req) {
+    var self = this;
+    var api_server = req.query['api_server'];
+    var data = req.body;
+    data = {
+        "project":[data]
+    }
+    return new Promise(function(resolve, reject) {
+        Promise.all([
+            rp({
+                uri: utils.confdPort(api_server) + '/' + API_VERSION  + '/api/config/project',
+                method: 'POST',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': req.session && req.session.authorization
+                }),
+                forever: constants.FOREVER_ON,
+                json: data,
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+            })
+        ]).then(function(result) {
+            var response = {};
+            response['data'] = {};
+            if (result[0].body) {
+                response['data'] = result[0].body;
+            }
+            response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+            resolve(response);
+        }).catch(function(error) {
+            var response = {};
+            console.log('Problem with ProjectManagement.create', error);
+            response.statusCode = error.statusCode || 500;
+            response.errorMessage = {
+                error: 'Failed to create user' + error
+            };
+            reject(response);
+        });
+    });
+};
+ProjectManagement.update = function(req) {
+    //"rw-project:project"
+    var self = this;
+    var api_server = req.query['api_server'];
+    var bodyData = req.body;
+    // oddly enough, if we do not encode this here letting the request below does so incorrectly
+    var projectName = encodeURIComponent(bodyData.name);
+    var descriptionData = {
+        "rw-project:project" : {
+            "name": bodyData.name,
+            "description": bodyData.description
+        }
+    }
+    var updateTasks = [];
+    var baseUrl = utils.confdPort(api_server) + '/' + API_VERSION  + '/api/config/project/' + projectName
+    var updateProjectConfig = rp({
+                uri: baseUrl + '/project-config',
+                method: 'PUT',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': req.session && req.session.authorization
+                }),
+                forever: constants.FOREVER_ON,
+                json: {
+                    "project-config": bodyData['project-config']
+                },
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+            });
+    updateTasks.push(updateProjectConfig);
+
+    var updateProjectDescription = rp({
+                uri: baseUrl + '/description',
+                method: 'PATCH',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': req.session && req.session.authorization
+                }),
+                forever: constants.FOREVER_ON,
+                json: {"description": bodyData.description},
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+            });
+    updateTasks.push(updateProjectDescription)
+    return new Promise(function(resolve, reject) {
+        Promise.all(
+            updateTasks
+        ).then(function(result) {
+            var response = {};
+            response['data'] = {};
+            if (result[0].body) {
+                response['data'] = result[0].body;
+            }
+            response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+            resolve(response);
+        }).catch(function(error) {
+            var response = {};
+            console.log('Problem with ProjectManagement.update', error);
+            response.statusCode = error.statusCode || 500;
+            response.errorMessage = {
+                error: 'Failed to update project - ' + error
+            };
+            reject(response);
+        });
+    });
+};
+
+ProjectManagement.delete = function(req) {
+    var self = this;
+    var projectname = encodeURIComponent(req.params.projectname);
+    var api_server = req.query["api_server"];
+    var requestHeaders = {};
+    var url = utils.confdPort(api_server) + '/' + API_VERSION  + '/api/config/project/' + projectname
+    return new Promise(function(resolve, reject) {
+        _.extend(requestHeaders,
+            constants.HTTP_HEADERS.accept.data,
+            constants.HTTP_HEADERS.content_type.data, {
+                'Authorization': req.session && req.session.authorization
+            });
+        rp({
+            url: url,
+            method: 'DELETE',
+            headers: requestHeaders,
+            forever: constants.FOREVER_ON,
+            rejectUnauthorized: false,
+        }, function(error, response, body) {
+            if (utils.validateResponse('ProjectManagement.DELETE', error, response, body, resolve, reject)) {
+                return resolve({
+                    statusCode: response.statusCode,
+                    data: JSON.stringify(response.body)
+                });
+            };
+        });
+    })
+}
+
+
+ProjectManagement.getPlatform = function(req, userId) {
+    var self = this;
+    var api_server = req.query['api_server'];
+    var user = req.params['userId'] || userId;
+    return new Promise(function(resolve, reject) {
+        var url = utils.confdPort(api_server) +  '/' + API_VERSION  + '/api/operational/rbac-platform-config';
+        if(user) {
+            url = url + '/user/' + encodeURIComponent(user);
+        }
+        Promise.all([
+            rp({
+                uri: url,
+                method: 'GET',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': req.session && req.session.authorization
+                }),
+                forever: constants.FOREVER_ON,
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+            })
+        ]).then(function(result) {
+            var response = {};
+            response['data'] = {};
+            if (result[0].body) {
+                if(user) {
+                    response['data']['platform'] = JSON.parse(result[0].body)['rw-rbac-platform:user'];
+                } else {
+                    response['data']['platform'] = JSON.parse(result[0].body)['rw-rbac-platform:rbac-platform-config'];
+                }
+            }
+            response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+            resolve(response);
+        }).catch(function(error) {
+            var response = {};
+            console.log('Problem with ProjectManagement.getPlatform', error);
+            response.statusCode = error.statusCode || 500;
+            response.errorMessage = {
+                error: 'Failed to get ProjectManagement.getPlatform' + error
+            };
+            reject(response);
+        });
+    });
+};
+
+ProjectManagement.updatePlatform = function(req) {
+    var self = this;
+    var api_server = req.query['api_server'];
+    var bodyData = req.body;
+    data = bodyData;
+    data.user = JSON.parse(data.user)
+    var updateTasks = [];
+
+    var updatePlatform = rp({
+                uri: utils.confdPort(api_server) +   '/' + API_VERSION  + '/api/config/rbac-platform-config',
+                method: 'PUT',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': req.session && req.session.authorization
+                }),
+                forever: constants.FOREVER_ON,
+                json: {
+                    "rw-rbac-platform:rbac-platform-config": data
+                },
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+            });
+    updateTasks.push(updatePlatform)
+    return new Promise(function(resolve, reject) {
+        Promise.all([
+            updateTasks
+        ]).then(function(result) {
+            var response = {};
+            response['data'] = {};
+            if (result[0].body) {
+                response['data'] = result[0].body;
+            }
+            response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+            resolve(response);
+        }).catch(function(error) {
+            var response = {};
+            console.log('Problem with ProjectManagement.updatePlatform', error);
+            response.statusCode = error.statusCode || 500;
+            response.errorMessage = {
+                error: 'Failed to update platform - ' + error
+            };
+            reject(response);
+        });
+    });
+};
+
+
+module.exports = ProjectManagement;
index 5ba0eb5..03f2721 100644 (file)
@@ -45,7 +45,7 @@ restconfAPI['streams'].get = function(req) {
             url: uri + url + '?deep',
             method: 'GET',
             headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
-                'Authorization': req.get('Authorization')
+                'Authorization': req.session && req.session.authorization
             }),
             forever: constants.FOREVER_ON,
             rejectUnauthorized: false,
diff --git a/skyquake/framework/core/modules/api/schemaAPI.js b/skyquake/framework/core/modules/api/schemaAPI.js
new file mode 100644 (file)
index 0000000..34c83be
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * 
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+// DescriptorModelMeta API (NSD + VNFD)
+
+
+var Schema = {};
+var rp = require('request-promise');
+var Promise = require('promise');
+var constants = require('../../api_utils/constants');
+var utils = require('../../api_utils/utils');
+var _ = require('lodash');
+var cors = require('cors');
+var bodyParser = require('body-parser');
+var utils = require('../../api_utils/utils');
+var configuration = require('./configuration');
+
+var router = require('express').Router();
+
+
+router.use(bodyParser.json());
+router.use(cors());
+router.use(bodyParser.urlencoded({
+    extended: true
+}));
+
+router.get('/schema', cors(), function (req, res) {
+    getSchema(req).then(function (response) {
+        utils.sendSuccessResponse(response, res);
+    }, function (error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+
+module.exports = {
+    getRouter: function () {
+        return router;
+    },
+    init: function () {}
+};
+
+getSchema = function (req) {
+    var schemaURI = configuration.getBackendURL() + '/api/schema/';
+    var schemaPaths = req.query['request'];
+    var paths = schemaPaths.split(',');
+
+    function getSchemaRequest(path) {
+        return rp({
+            uri: schemaURI + path,
+            method: 'GET',
+            headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
+                'Authorization': req.session && req.session.authorization
+            }),
+            forever: constants.FOREVER_ON,
+            rejectUnauthorized: false,
+            resolveWithFullResponse: true
+        })
+    }
+
+    var requests = _.map(paths, getSchemaRequest);
+
+    return new Promise(function (resolve, reject) {
+        Promise.all(requests).then(
+            function (results) {
+                var data = {
+                    schema: {}
+                }
+                _.forEach(results, function (result, index) {
+                    data.schema[paths[index]] = JSON.parse(result.body);
+                });
+                resolve({
+                    data: data,
+                    statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+                });
+            }).catch(
+            function (error) {
+                var response = {};
+                console.log('Problem with schema.get', error);
+                response.statusCode = error.statusCode || 500;
+                response.errorMessage = {
+                    error: 'Failed to get schema' + error
+                };
+                reject(response);
+            });
+    });
+};
\ No newline at end of file
diff --git a/skyquake/framework/core/modules/api/sessions.js b/skyquake/framework/core/modules/api/sessions.js
new file mode 100644 (file)
index 0000000..f168724
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ *
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+/**
+ * sessions api module. Provides API functions for sessions
+ * @module framework/core/modules/api/sessions
+ * @author Kiran Kashalkar <kiran.kashalkar@riftio.com>
+ */
+"use strict"
+var Promise = require('promise');
+var constants = require('../../api_utils/constants');
+var utils = require('../../api_utils/utils');
+var request = utils.request;
+var rp = require('request-promise');
+var sessionsAPI = {};
+var _ = require('lodash');
+var base64 = require('base-64');
+var APIVersion = '/v2';
+var configurationAPI = require('./configuration');
+var UserManagement = require('./userManagementAPI.js');
+var URL = require('url');
+
+// Used for determining what page a user should first go to.
+var Application = {
+    order: [
+        "rw-rbac-platform:super-admin",
+        "rw-rbac-platform:platform-admin",
+        "rw-rbac-platform:platform-oper",
+        "rw-project:project-admin",
+        "rw-project:project-oper",
+        "rw-project-mano:lcm-admin",
+        "rw-project-mano:lcm-oper",
+        "rw-project-mano:catalog-admin",
+        "rw-project-mano:catalog-oper",
+        "rw-project-mano:account-admin",
+        "rw-project-mano:account-oper"
+    ],
+    key: {
+        "rw-rbac-platform:super-admin": "user_management",
+        "rw-rbac-platform:platform-admin": "user_management",
+        "rw-rbac-platform:platform-oper": "user_management",
+        "rw-project:project-admin": "project_management",
+        "rw-project:project-oper": "project_management",
+        "rw-project-mano:catalog-admin": "composer",
+        "rw-project-mano:catalog-oper": "composer",
+        "rw-project-mano:lcm-admin": "launchpad",
+        "rw-project-mano:lcm-oper": "launchpad",
+        "rw-project-mano:account-admin": "accounts",
+        "rw-project-mano:account-oper": "accounts"
+    }
+};
+
+function logAndReject(mesg, reject, errCode) {
+    var res = {};
+    res.errorMessage = {
+        error: mesg
+    }
+    res.statusCode = errCode || constants.HTTP_RESPONSE_CODES.ERROR.BAD_REQUEST;
+    console.log(mesg);
+    reject(res);
+}
+
+function logAndRedirectToLogin(mesg, res, req, invalid) {
+    console.log(mesg);
+    if (!invalid) {
+        res.redirect(utils.buildRedirectURL(req, configurationAPI.globalConfiguration, 'login', '&referer=' + encodeURIComponent(req.headers.referer)));
+    }
+    res.end();
+}
+
+function logAndRedirectToEndSession(mesg, res, authorization, url) {
+    console.log(mesg);
+    res.set({
+        'Authorization': authorization
+    });
+    res.redirect(url);
+    res.end();
+}
+var sessionPromiseResolve = null;
+sessionsAPI.sessionPromise = new Promise(function(resolve, reject) {
+    sessionPromiseResolve = resolve;
+});
+
+sessionsAPI.create = function (req, res) {
+    if (!req.session.passport){
+        logAndRedirectToLogin("lost session", res, req);
+        return new Promise(function (resolve, reject){reject("lost session")});
+    }
+    var api_server = req.query['api_server'] || (req.protocol + '://' + configurationAPI.globalConfiguration.get().api_server);
+    var uri = utils.confdPort(api_server);
+    var username = req.session.passport.user['username'];
+    var authorization_header_string = 'Bearer ' + req.session.passport.user.user.access_token;
+    return new Promise(function (resolve, reject) {
+        req.session.authorization = authorization_header_string;
+        req.session.api_server = api_server;
+        req.session.api_protocal = req.protocol;
+        req.session.loggedIn = true;
+        req.session.userdata = {
+            username: username,
+        };
+        UserManagement.getUserInfo(req, req.session.passport.user.username).then(function (results) {
+            var project_list_for_user = null;
+            if (!req.session.projectId && results.data.project) {
+                project_list_for_user = Object.keys(results.data.project);
+                if (project_list_for_user.length > 0) {
+                    req.session.projectId = project_list_for_user.sort() && project_list_for_user[0];
+                }
+            }
+            sessionsAPI.setTopApplication(req);
+            req.session.isLCM = results.data.isLCM;
+
+            req.session['ui-state'] = results.data['ui-state'];
+            var lastActiveProject = req.session['ui-state'] && req.session['ui-state']['last-active-project'];
+            if (lastActiveProject) {
+                if (results.data.project.hasOwnProperty(lastActiveProject)) {
+                    req.session.projectId = lastActiveProject;
+                }
+
+            }
+
+            var successMsg = 'User => ' + username + ' successfully logged in.';
+            successMsg += req.session.projectId ? 'Project => ' + req.session.projectId + ' set as default.' : '';
+
+            console.log(successMsg);
+
+            req.session.save(function (err) {
+                if (err) {
+                    console.log('Error saving session to store', err);
+                }
+                // no response data, just redirect now that session data is set
+                if (req.session['ui-state'] && req.session['ui-state']['last-active-uri']) {
+                    var url = URL.parse(req.session['ui-state']['last-active-uri']);
+                    var host = req.headers.host;
+                    var path = url.path;
+                    var hash = url.hash;
+                    var protocol = url.protocol;
+                    var newUrl = protocol + '//' + host + path + (hash?hash:'');
+                    console.log('Redirecting to: ' + newUrl)
+                    res.redirect(newUrl)
+                } else {
+                    if(req.session.topApplication) {
+                        res.redirect(utils.buildRedirectURL(req, configurationAPI.globalConfiguration, req.session.topApplication));
+                    } else {
+                        res.redirect(utils.buildRedirectURL(req, configurationAPI.globalConfiguration, 'user_management', '#/user-profile'));
+                    }
+                }
+            })
+
+            sessionPromiseResolve(req.session);
+
+        }).catch(function (error) {
+            // Something went wrong - Redirect to /login
+            var errorMsg = 'Error logging in or getting list of projects. Error: ' + error;
+            console.log(errorMsg);
+            logAndRedirectToLogin(errorMsg, res, req);
+        });
+    })
+};
+
+sessionsAPI.addProjectToSession = function (req, res) {
+    return new Promise(function (resolve, reject) {
+        if (req.session && req.session.loggedIn == true) {
+            Promise.all([UserManagement.getProfile(req), UserManagement.updateActiveProject(req)]).then(function () {
+                req.session.projectId = req.params.projectId;
+                req.session.topApplication = null;
+                sessionsAPI.setTopApplication(req, req.query.app);
+                req.session.save(function (err) {
+                    if (err) {
+                        console.log('Error saving session to store', err);
+                        var errorMsg = 'Session does not exist or not logged in';
+                        logAndReject(errorMsg, reject, constants.HTTP_RESPONSE_CODES.ERROR.NOT_FOUND);
+                    } else {
+                        var successMsg = 'Added project ' + req.session.projectId + ' to session ' + req.sessionID;
+                        console.log(successMsg);
+                        var response = {
+                            statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.OK,
+                            data: JSON.stringify({
+                                status: successMsg
+                            })
+                        }
+                        return resolve(response);
+                    }
+                    // res.redirect('/');
+                });
+
+            })
+
+        }
+    });
+}
+
+sessionsAPI.delete = function (req, res) {
+    var idpServerAddress = configurationAPI.globalConfiguration.get().idp_server_address;
+    var idpServerProtocol = configurationAPI.globalConfiguration.get().idp_server_protocol;
+    var idpServerPortNumber = configurationAPI.globalConfiguration.get().idp_server_port_number;
+    var idpEndSessionPath = constants.END_SESSION_PATH;
+    var url = idpServerProtocol + '://' +
+        idpServerAddress + ':' +
+        idpServerPortNumber + '/' +
+        idpEndSessionPath;
+    var authorization = req.session.authorization;
+    return new Promise(function (resolve, reject) {
+        Promise.all([
+            UserManagement.updateActiveUri(req),
+            new Promise(function (success, failure) {
+                req.session.destroy(function (err) {
+                    if (err) {
+                        var errorMsg = 'Error deleting session. Error: ' + err;
+                        console.log(errorMsg);
+                        success({
+                            status: 'error',
+                            message: errorMsg
+                        });
+                    }
+
+                    var successMsg = 'Success deleting session';
+                    console.log(successMsg);
+
+                    success({
+                        status: 'success',
+                        message: successMsg
+                    });
+                });
+            })
+        ]).then(function (result) {
+            // assume the session was deleted!
+            var message = 'Session was deleted. Redirecting to end_session';
+            resolve({
+                statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.OK,
+                data: {
+                    url: url,
+                    message: message
+                }
+            });
+
+        }).catch(function (error) {
+            var message = "An error occured while deleting session";
+            resolve({
+                statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.OK,
+                data: {
+                    url: url,
+                    message: message
+                }
+            });
+        });
+    });
+}
+
+sessionsAPI.setTopApplication = function (req, suggestedPlugin) {
+    var selectedProject = req.session.projectId;
+    var userProject = selectedProject ? req.session.projectMap[selectedProject] : null;
+    if (userProject) {
+        if (suggestedPlugin) {
+            if (req.session.platformMap['rw-rbac-platform:super-admin']) {
+                topApplication = suggestedPlugin;
+            } else {
+                var roles = _.reduce(Object.keys(Application.key), function (accumulator, role) {
+                    if (Application.key[role] === suggestedPlugin) {
+                        accumulator.push(role);
+                    }
+                    return accumulator;
+                }, []);
+                if (_.some(roles, function (role){return userProject.role[role]})) {
+                    req.session.topApplication = suggestedPlugin;
+                    return;
+                }
+            }
+        }
+        _.some(Application.order, function (role) {
+            if (userProject.role[role] || req.session.platformMap.role[role]) {
+                req.session.topApplication = Application.key[role];
+                return true;
+            }
+            return false;
+        })
+    }
+}
+
+module.exports = sessionsAPI;
diff --git a/skyquake/framework/core/modules/api/userManagementAPI.js b/skyquake/framework/core/modules/api/userManagementAPI.js
new file mode 100644 (file)
index 0000000..834df7e
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+ *
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+// DescriptorModelMeta API (NSD + VNFD)
+
+
+var UserManagement = {};
+var Promise = require('bluebird');
+var rp = require('request-promise');
+var Promise = require('promise');
+var constants = require('../../api_utils/constants');
+var utils = require('../../api_utils/utils');
+var _ = require('lodash');
+var ProjectManagementAPI = require('./projectManagementAPI.js');
+var API_VERSION = 'v2';
+
+UserManagement.get = function(req) {
+    var self = this;
+    var api_server = req.query['api_server'];
+
+    return new Promise(function(resolve, reject) {
+        var userConfig = rp({
+                uri: utils.confdPort(api_server) +  '/' + API_VERSION  + '/api/operational/user-config/user',
+                method: 'GET',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': req.session && req.session.authorization
+                }),
+                forever: constants.FOREVER_ON,
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+            });
+        var userOp = rp({
+                uri: utils.confdPort(api_server) +  '/' + API_VERSION  + '/api/operational/user-state/user',
+                method: 'GET',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': req.session && req.session.authorization
+                }),
+                forever: constants.FOREVER_ON,
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+            })
+        Promise.all([
+            userConfig,
+            userOp
+        ]).then(function(result) {
+            var response = {};
+            var userConfig = [];
+            var userOpData = {};
+            response['data'] = {};
+            if (result[0].body) {
+                userConfig = JSON.parse(result[0].body)['rw-user:user'];
+            }
+            if (result[1].body) {
+                JSON.parse(result[1].body)['rw-user:user'].map(function(u) {
+                    userOpData[u['user-domain'] + ',' + u['user-name']] = u;
+                })
+            }
+            response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+            response['data']['user'] = userConfig.map(function(u,i) {
+                var mergedData = _.merge(u, userOpData[u['user-domain'] + ',' + u['user-name']]);
+                mergedData.projects = {
+                    ids: [],
+                    data: {}
+                };
+                var projects = mergedData.projects;
+                mergedData.role && mergedData.role.map(function(r) {
+                    if ((r.role != "rw-project:user-self" )&& (r.role != "rw-rbac-platform:user-self")) {
+                        var projectId = r.keys.split(';')[0];
+                        if (projectId == "") {
+                            projectId = "platform"
+                        }
+                        if (!projects.data[projectId]) {
+                            projects.ids.push(projectId);
+                            projects.data[projectId] = [];
+                        }
+                        projects.data[projectId].push(r.role);
+                    }
+                })
+                return mergedData;
+            })
+            resolve(response);
+        }).catch(function(error) {
+            var response = {};
+            console.log('Problem with UserManagement.get', error);
+            response.statusCode = error.statusCode || constants.HTTP_RESPONSE_CODES.ERROR.INTERNAL_SERVER_ERROR;
+            response.errorMessage = {
+                error: 'Failed to get UserManagement' + error
+            };
+            reject(response);
+        });
+    });
+};
+
+
+UserManagement.getProfile = function(req) {
+    var self = this;
+    var api_server = req.query['api_server'];
+    return new Promise(function(resolve, reject) {
+        var response = {};
+        try {
+            var userId = req.session.userdata.username
+            response['data'] = {
+                userId: userId,
+                projectId: req.session.projectId,
+                domain: req.session.passport.user.domain
+            };
+            UserManagement.getUserInfo(req, userId).then(function(result) {
+                response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK;
+                response.data.data = result.data
+                resolve(response);
+            }, function(error) {
+                console.log('Error retrieving getUserInfo');
+                response.statusCode = constants.HTTP_RESPONSE_CODES.ERROR.INTERNAL_SERVER_ERROR;
+                reject(response);
+            })
+        } catch (e) {
+            var response = {};
+            console.log('Problem with UserManagement.get', error);
+            response.statusCode = error.statusCode || 500;
+            response.errorMessage = {
+                error: 'Failed to get UserManagement' + error
+            };
+            reject(response);
+        }
+    });
+};
+UserManagement.getUserInfo = function(req, userId, domain) {
+    var self = this;
+    var api_server = req.query['api_server'];
+    var id = req.params['userId'] || userId;
+    var domain = req.params['domainId'] || domain;
+    var response = {};
+    return new Promise(function(resolve, reject) {
+        if (id) {
+            var getProjects = ProjectManagementAPI.get(req, ['name', 'project-config']);
+            var getPlatformUser = ProjectManagementAPI.getPlatform(req, id);
+            var getUserUiState = UserManagement.getUserUiState(req);
+            Promise.all([
+                getProjects,
+                getPlatformUser,
+                getUserUiState
+            ]).then(function(result) {
+                var userData = {
+                    platform: {
+                        role: {
+
+                        }
+                    },
+                    //id/key values for each project
+                    projectId:[],
+                    project: {
+                        /**
+                         *  [projectId] : {
+                         *      data: [project object],
+                         *      role: {
+                         *          [roleId]: true
+                         *      }
+                         *  }
+                         */
+                    }
+                }
+                //Build UI state
+                var uiState = result[2].data && result[2].data['rw-user:user'];
+                userData['ui-state'] = uiState['ui-state'];
+                //Build platform roles
+                var platformRoles = result[1].data.platform && result[1].data.platform.role;
+                platformRoles && platformRoles.map(function(r) {
+                    userData.platform.role[r.role] = true
+                });
+                //Build project roles
+                var projects = result[0].data.project;
+                var userProjects = [];
+                projects && projects.map(function(p, i) {
+                    userData.project[p.name] = {
+                        data: p,
+                        role: {}
+                    }
+                    userData.projectId.push(p.name);
+                    if (userData.platform.role['rw-rbac-platform:super-admin']) {
+                        userData.project[p.name] = {
+                            data: p,
+                            role: {
+                                "rw-project:project-admin": true,
+                                "rw-project:project-oper": true,
+                                "rw-project-mano:account-admin": true,
+                                "rw-project-mano:account-oper": true,
+                                "rw-project-mano:catalog-admin": true,
+                                "rw-project-mano:catalog-oper": true,
+                                "rw-project-mano:lcm-admin": true,
+                                "rw-project-mano:lcm-oper": true
+                            }
+                        }
+                    } else {
+                        var users = p['project-config'] && p['project-config'].user;
+                        users && users.map(function(u) {
+                            if(u['user-name'] == id) {
+                                u.role && u.role.map(function(r) {
+                                    userData.project[p.name].role[r.role] = true;
+                                    if (r.role === 'rw-project:project-admin') {
+                                        userData.project[p.name].role["rw-project-mano:account-admin"] = true;
+                                        userData.project[p.name].role["rw-project-mano:catalog-admin"] = true;
+                                        userData.project[p.name].role["rw-project-mano:lcm-admin"] = true;
+                                        userData.isLCM = true;
+                                    } else if (r.role === 'rw-project:project-oper') {
+                                        userData.project[p.name].role["rw-project-mano:account-oper"] = true;
+                                        userData.project[p.name].role["rw-project-mano:catalog-oper"] = true;
+                                        userData.project[p.name].role["rw-project-mano:lcm-oper"] = true;
+                                        userData.isLCM = true;
+                                    }
+                                });
+                                u["rw-project-mano:mano-role"] && u["rw-project-mano:mano-role"] .map(function(r) {
+                                    userData.project[p.name].role[r.role] = true;
+                                    if (r.role.indexOf('rw-project-mano:lcm') > -1) {
+                                        userData.isLCM = true;
+                                    }
+                                });
+                            }
+                        })
+                    }
+                });
+                response.data = userData;
+                response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK;
+
+                req.session.projectMap = userData.project;
+                req.session.platformMap = userData.platform;
+                resolve(response);
+            })
+        } else {
+            var errorMsg = 'userId not specified in UserManagement.getUserInfo';
+            console.error(errorMsg);
+            response.statusCode = constants.HTTP_RESPONSE_CODES.ERROR.BAD_REQUEST;
+            response.error = errorMsg;
+            reject(response)
+        }
+
+    })
+}
+UserManagement.create = function(req) {
+    var self = this;
+    var api_server = req.query['api_server'];
+    var data = req.body;
+    data = {
+        "user":[data]
+    }
+    return new Promise(function(resolve, reject) {
+        Promise.all([
+            rp({
+                uri: utils.confdPort(api_server) +  '/' + API_VERSION  + '/api/config/user-config',
+                method: 'POST',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': req.session && req.session.authorization
+                }),
+                forever: constants.FOREVER_ON,
+                json: data,
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+            })
+        ]).then(function(result) {
+            var response = {};
+            response['data'] = {};
+            if (result[0].body) {
+                response['data'] = result[0].body;
+            }
+            response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+            resolve(response);
+        }).catch(function(error) {
+            var response = {};
+            console.log('Problem with UserManagement.create', error);
+            response.statusCode = error.statusCode || 500;
+            response.errorMessage = {
+                error: 'Failed to create user' + error
+            };
+            reject(response);
+        });
+    });
+};
+UserManagement.update = function(req) {
+    var self = this;
+    var api_server = req.query['api_server'];
+    var bodyData = req.body;
+    data = {
+        "rw-user:user": bodyData
+    }
+    var updateTasks = [];
+    if(bodyData.hasOwnProperty('old-password')) {
+        var changePW = rp({
+            uri: utils.confdPort(api_server) +  '/' + API_VERSION  + '/api/operations/change-password',
+            method: 'POST',
+            headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                'Authorization': req.session && req.session.authorization
+            }),
+            forever: constants.FOREVER_ON,
+            json: {
+                "input": {
+                    'user-name' : bodyData['user-name'],
+                    'user-domain' : bodyData['user-domain'],
+                    'old-password' : bodyData['old-password'],
+                    'new-password' : bodyData['new-password'],
+                    'confirm-password' : bodyData['confirm-password'],
+                }
+            },
+            rejectUnauthorized: false,
+            resolveWithFullResponse: true
+        });
+        updateTasks.push(changePW);
+    };
+    var updateUser = rp({
+                uri: utils.confdPort(api_server) +  '/' + API_VERSION  + '/api/config/user-config/user/' + encodeURIComponent(bodyData['user-name']) + ',' +  encodeURIComponent(bodyData['user-domain']),
+                method: 'PUT',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': req.session && req.session.authorization
+                }),
+                forever: constants.FOREVER_ON,
+                json: data,
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+            });
+    updateTasks.push(updateUser)
+    return new Promise(function(resolve, reject) {
+        Promise.all([
+            updateTasks
+        ]).then(function(result) {
+            var response = {};
+            response['data'] = {};
+            if (result[0].body) {
+                response['data'] = result[0].body;
+            }
+            response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+            resolve(response);
+        }).catch(function(error) {
+            var response = {};
+            console.log('Problem with UserManagement.passwordChange', error);
+            response.statusCode = error.statusCode || 500;
+            response.errorMessage = {
+                error: 'Failed to passwordChange user' + error
+            };
+            reject(response);
+        });
+    });
+};
+
+UserManagement.delete = function(req) {
+    var self = this;
+    var username = req.params.username;
+    var domain = req.params.domain;
+    var api_server = req.query["api_server"];
+    var requestHeaders = {};
+    var url = `${utils.confdPort(api_server)}/${API_VERSION}/api/config/user-config/user/${encodeURIComponent(username)},${encodeURIComponent(domain)}`
+    return new Promise(function(resolve, reject) {
+        _.extend(requestHeaders,
+            constants.HTTP_HEADERS.accept.data,
+            constants.HTTP_HEADERS.content_type.data, {
+                'Authorization': req.session && req.session.authorization
+            });
+        rp({
+            url: url,
+            method: 'DELETE',
+            headers: requestHeaders,
+            forever: constants.FOREVER_ON,
+            rejectUnauthorized: false,
+        }, function(error, response, body) {
+            if (utils.validateResponse('UserManagement.DELETE', error, response, body, resolve, reject)) {
+                return resolve({
+                    statusCode: response.statusCode,
+                    data: JSON.stringify(response.body)
+                });
+            };
+        });
+    })
+};
+UserManagement.getUserUiState = function(req) {
+    var self = this;
+    var api_server = req.query['api_server'];
+    var user = req.session.passport.user;
+    return new Promise(function(resolve, reject) {
+        Promise.all([
+            rp({
+                uri: utils.confdPort(api_server) +  '/' + API_VERSION  + '/api/config/user-config/user/'+encodeURIComponent(user.username) + ',' + encodeURIComponent(user.domain),
+                method: 'GET',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': req.session && req.session.authorization
+                }),
+                forever: constants.FOREVER_ON,
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+            })
+        ]).then(function(result) {
+            var response = {};
+            response['data'] = {};
+            if (result[0].body) {
+                response['data'] = JSON.parse(result[0].body);
+            }
+            response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+            resolve(response);
+        }).catch(function(error) {
+            var response = {};
+            console.log('Problem with UserManagement.getUserUiState', error);
+            response.statusCode = error.statusCode || 500;
+            response.errorMessage = {
+                error: 'Failed to create user' + error
+            };
+            reject(response);
+        });
+    });
+};
+UserManagement.updateActiveProject = function(req) {
+    var self = this;
+    var api_server = req.query['api_server'];
+    var user = req.session.passport.user;
+    var data = {
+        "rw-user:user-config": {
+            "user":{
+                "user-name" : user.username,
+                "user-domain": user.domain,
+                "ui-state": {
+                     "last-active-project" : req.params.projectId
+                }
+            }
+        }
+    }
+    return new Promise(function(resolve, reject) {
+        Promise.all([
+            rp({
+                uri: utils.confdPort(api_server) +  '/' + API_VERSION  + '/api/config/user-config',
+                method: 'PATCH',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': req.session && req.session.authorization
+                }),
+                forever: constants.FOREVER_ON,
+                json: data,
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+            })
+        ]).then(function(result) {
+            var response = {};
+            response['data'] = {};
+            if (result[0].body) {
+                response['data'] = result[0].body;
+            }
+            response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+            resolve(response);
+        }).catch(function(error) {
+            var response = {};
+            console.log('Problem with UserManagement.updateActiveProject', error);
+            response.statusCode = error.statusCode || 500;
+            response.errorMessage = {
+                error: 'Failed to create user' + error
+            };
+            reject(response);
+        });
+    });
+};
+UserManagement.updateActiveUri = function(req) {
+    if (!req.session.passport) {
+        console.debug("passport gone before we got the save the active uri");
+        var response = {
+            statusCode: 500,
+            errorMessage: {
+                error: 'Failed to save active uri'
+            }};
+        return Promise.resolve(response);
+    }
+    var self = this;
+    var api_server = req.query['api_server'];
+    var user = req.session.passport.user;
+    var ref = req.headers.referer;
+    var hash = req.query.hash;
+    var data = {
+        "rw-user:user-config": {
+            "user":{
+                "user-name" : user.username,
+                "user-domain": user.domain,
+                "ui-state": {
+                     "last-active-uri" : ref + decodeURIComponent(hash)
+                }
+            }
+        }
+    }
+    return new Promise(function(resolve, reject) {
+        Promise.all([
+            rp({
+                uri: utils.confdPort(api_server) +  '/' + API_VERSION  + '/api/config/user-config',
+                method: 'PATCH',
+                headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+                    'Authorization': req.session && req.session.authorization
+                }),
+                forever: constants.FOREVER_ON,
+                json: data,
+                rejectUnauthorized: false,
+                resolveWithFullResponse: true
+            })
+        ]).then(function(result) {
+            var response = {};
+            response['data'] = {};
+            if (result[0].body) {
+                response['data'] = result[0].body;
+            }
+            response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+            resolve(response);
+        }).catch(function(error) {
+            var response = {};
+            console.log('Problem with UserManagement.updateActiveProject', error);
+            response.statusCode = error.statusCode || 500;
+            response.errorMessage = {
+                error: 'Failed to create user' + error
+            };
+            reject(response);
+        });
+    });
+};
+module.exports = UserManagement;
index c85eba6..7d22394 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -42,7 +42,6 @@ function addNavigation(plugin_name, routes) {
        if (!NAVIGATION[plugin_name]) {
                NAVIGATION[plugin_name] = {};
        }
-
        if (!NAVIGATION[plugin_name].routes) {
                NAVIGATION[plugin_name].routes = routes;
        } else {
@@ -69,6 +68,20 @@ function addLabel(plugin_name, label) {
        NAVIGATION[plugin_name].label = label || 'RW.UI Plugin';
 }
 
+function addAllow(plugin_name, allow) {
+       if (!NAVIGATION[plugin_name]) {
+               NAVIGATION[plugin_name] = {};
+       }
+       NAVIGATION[plugin_name].allow = allow || '*';
+}
+
+function addAdminFlag(plugin_name, admin_link) {
+       if (!NAVIGATION[plugin_name]) {
+               NAVIGATION[plugin_name] = {};
+       }
+       NAVIGATION[plugin_name].admin_link = admin_link || false;
+}
+
 function getNavigation() {
        return NAVIGATION;
 }
@@ -82,6 +95,8 @@ function onNavigationDiscovered(plugin_name, plugin) {
        addOrder(plugin_name, plugin.order);
        addPriority(plugin_name, plugin.priority);
        addLabel(plugin_name, plugin.name);
+       addAllow(plugin_name, plugin.allow);
+       addAdminFlag(plugin_name, plugin.admin_link);
 }
 
 function init() {
diff --git a/skyquake/framework/core/modules/routes/auth.js b/skyquake/framework/core/modules/routes/auth.js
new file mode 100644 (file)
index 0000000..c1df55a
--- /dev/null
@@ -0,0 +1,99 @@
+
+/*
+ *
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+/**
+ * auth routes module. Provides a RESTful API for this
+ * skyquake instance's auth state.
+ * @module framework/core/modules/routes/auth
+ * @author Kiran Kashalkar <kiran.kashalkar@riftio.com>
+ */
+
+var cors = require('cors');
+var bodyParser = require('body-parser');
+var Router = require('express').Router();
+var utils = require('../../api_utils/utils');
+var configurationAPI = require('../api/configuration');
+
+var auth = {};
+
+auth.routes = function(authManager) {
+       console.log('Configuring auth routes');
+       Router.use(bodyParser.json());
+       Router.use(cors());
+       Router.use(bodyParser.urlencoded({
+           extended: true
+       }));
+
+       // Define routes.
+    Router.get('/', function(req, res) {
+       var default_page = null;
+       var api_server = req.query['api_server'] || (req.protocol + '://' + configurationAPI.globalConfiguration.get().api_server);
+        if (req.session && req.session.topApplication) {
+            default_page = utils.buildRedirectURL(req, configurationAPI.globalConfiguration, req.session.topApplication);
+        } else {
+            default_page = utils.buildRedirectURL(req, configurationAPI.globalConfiguration, 'user_management', '#/user-profile');
+        }
+        if (!req.user) {
+            res.redirect('/login');
+        } else {
+            res.redirect(default_page);
+        }
+    });
+
+    Router.get('/login', cors(), function(req, res) {
+        // res.render('login.html');
+        res.redirect('/login/idp');
+    });
+
+    Router.get('/login/idp',
+        authManager.passport.authenticate('oauth2')
+    );
+
+    Router.get('/callback', function(req, res, next) {
+        authManager.passport.authenticate('oauth2', function(err, user, info) {
+            if (err) {
+                // Catch some errors specific to deployments (e.g. IDP unavailable)
+                if (err.oauthError && err.oauthError.code == 'ENOTFOUND') {
+                    return res.render('idpconnectfail.ejs', {
+                        callback_url: req.url
+                    });
+                }
+                return res.redirect('/login');
+            }
+            if (!user) {
+                return res.redirect('/login');
+            }
+            req.logIn(user, function(err) {
+                if (err) {
+                    return next(err);
+                }
+                return res.redirect('/session?redirectParams=' + req.url);
+            });
+        })(req, res, next);
+    });
+
+
+    Router.get('/login.html', cors(), function(req, res) {
+        res.render('login.html');
+    });
+}
+
+auth.router = Router;
+
+module.exports = auth;
index b789ff0..93bb88a 100644 (file)
@@ -56,38 +56,5 @@ Router.get('/server-configuration', cors(), function(req, res) {
     });
 });
 
-Router.get('/check-auth', function(req, res) {
-    console.log('testing auth')
-    var api_server = req.query["api_server"];
-    var uri = utils.confdPort(api_server) + '/api/config/';
-
-    checkAuth(uri, req).then(function(data) {
-        utils.sendSuccessResponse(data, res);
-    }, function(error) {
-        utils.sendErrorResponse(error, res);
-    });
-});
-
-function checkAuth(uri, req){
-    return new Promise(function(resolve, reject) {
-        request({
-            uri: uri,
-            method: 'GET',
-            headers: _.extend({}, {
-                'Authorization': req.get('Authorization'),
-                forever: CONSTANTS.FOREVER_ON,
-                rejectUnauthorized: false,
-            })
-        }, function(error, response, body) {
-            console.log(arguments)
-            if( response.statusCode == 401) {
-                reject({statusCode: 401, error: response.body});
-            } else {
-                resolve({statusCode:200, data:response.body})
-            }
-        });
-    });
-}
-
 
 module.exports = Router;
index 82c7ec5..37e86e4 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,6 +30,7 @@ var navAPI = require('../api/navigation');
 var Router = require('express').Router();
 var utils = require('../../api_utils/utils');
 var configurationAPI = require('../api/configuration');
+var csrfCheck = require('../../api_utils/csrf').csrfCheck;
 
 Router.use(bodyParser.json());
 Router.use(cors());
@@ -37,48 +38,64 @@ Router.use(bodyParser.urlencoded({
     extended: true
 }));
 
-Router.get('/', cors(), function(req, res, next) {
-       res.redirect('/launchpad/?api_server=' + req.protocol + '://' + configurationAPI.globalConfiguration.get().api_server + '&upload_server=' + req.protocol + '://' + (configurationAPI.globalConfiguration.get().upload_server || req.hostname));
+//Should have a way of adding excluded routes to this via plugin registry, instead of hard coding
+Router.use(/^(?!.*(login\/idp|session|composer\/upload|composer\/update)).*/, function(req, res, next) {
+    var api_server = req.query['api_server'] || (req.protocol + '://' + configurationAPI.globalConfiguration.get().api_server);
+    if (req.session && req.session.loggedIn) {
+        switch (req.method) {
+            case 'POST':
+            case 'PUT':
+                csrfCheck(req, res, next);
+                break;
+            default:
+                next();
+                break;
+        }
+    } else {
+        console.log('Redirect to login.html');
+        res.redirect(utils.buildRedirectURL(req, configurationAPI.globalConfiguration, 'login', '&referer=' + encodeURIComponent(req.headers.referer)));
+    }
 });
 
+
 Router.get('/nav', cors(), function(req, res) {
-       navAPI.get(req).then(function(data) {
-               utils.sendSuccessResponse(data, res);
-       }, function(error) {
-               utils.sendErrorResponse(error, res);
-       });
+    navAPI.get(req).then(function(data) {
+        utils.sendSuccessResponse(data, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
 });
 
 Router.get('/nav/:plugin_id', cors(), function(req, res) {
-       navAPI.get(req).then(function(data) {
-               utils.sendSuccessResponse(data, res);
-       }, function(error) {
-               utils.sendErrorResponse(error, res);
-       });
+    navAPI.get(req).then(function(data) {
+        utils.sendSuccessResponse(data, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
 });
 
 Router.post('/nav/:plugin_id', cors(), function(req, res) {
-       navAPI.create(req).then(function(data) {
-               utils.sendSuccessResponse(data, res);
-       }, function(error) {
-               utils.sendErrorResponse(error, res);
-       });
+    navAPI.create(req).then(function(data) {
+        utils.sendSuccessResponse(data, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
 });
 
 Router.put('/nav/:plugin_id/:route_id', cors(), function(req, res) {
-       navAPI.update(req).then(function(data) {
-               utils.sendSuccessResponse(data, res);
-       }, function(error) {
-               utils.sendErrorResponse(error, res);
-       });
+    navAPI.update(req).then(function(data) {
+        utils.sendSuccessResponse(data, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
 });
 
 Router.delete('/nav/:plugin_id/:route_id', cors(), function(req, res) {
-       navAPI.delete(req).then(function(data) {
-               utils.sendSuccessResponse(data, res);
-       }, function(error) {
-               utils.sendErrorResponse(error, res);
-       });
+    navAPI.delete(req).then(function(data) {
+        utils.sendSuccessResponse(data, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
 });
 
 
diff --git a/skyquake/framework/core/modules/routes/projectManagement.js b/skyquake/framework/core/modules/routes/projectManagement.js
new file mode 100644 (file)
index 0000000..c106f30
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ *
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+/**
+ * inactivity routes module. Provides a RESTful API for this
+ * skyquake instance's inactivity state.
+ * @module framework/core/modules/routes/inactivity
+ * @author Laurence Maultsby <laurence.maultsby@riftio.com>
+ */
+
+var cors = require('cors');
+var bodyParser = require('body-parser');
+var Router = require('express').Router();
+var utils = require('../../api_utils/utils');
+var ProjectManagementAPI = require('../api/projectManagementAPI.js');
+
+Router.use(bodyParser.json());
+Router.use(cors());
+Router.use(bodyParser.urlencoded({
+    extended: true
+}));
+
+Router.get('/project', cors(), function(req, res) {
+    ProjectManagementAPI.get(req).then(function(response) {
+        utils.sendSuccessResponse(response, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+Router.post('/project', cors(), function(req, res) {
+    ProjectManagementAPI.create(req).then(function(response) {
+        utils.sendSuccessResponse(response, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+Router.put('/project', cors(), function(req, res) {
+    ProjectManagementAPI.update(req).then(function(response) {
+        utils.sendSuccessResponse(response, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+Router.delete('/project/:projectname', cors(), function(req, res) {
+    ProjectManagementAPI.delete(req).then(function(response) {
+        utils.sendSuccessResponse(response, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+
+Router.put('/platform', cors(), function(req, res) {
+    ProjectManagementAPI.updatePlatform(req).then(function(response) {
+        utils.sendSuccessResponse(response, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+
+Router.get('/platform', cors(), function(req, res) {
+    ProjectManagementAPI.getPlatform(req).then(function(response) {
+        utils.sendSuccessResponse(response, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+module.exports = Router;
+
+
+
diff --git a/skyquake/framework/core/modules/routes/sessions.js b/skyquake/framework/core/modules/routes/sessions.js
new file mode 100644 (file)
index 0000000..f84ca11
--- /dev/null
@@ -0,0 +1,74 @@
+
+/*
+ *
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+/**
+ * Node sessions routes module.
+ * Provides a RESTful API to manage sessions.
+ * @module framework/core/modules/routes/sessions
+ * @author Kiran Kashalkar <kiran.kashalkar@riftio.com>
+ */
+
+var cors = require('cors');
+var bodyParser = require('body-parser');
+var sessionsAPI = require('../api/sessions');
+var Router = require('express').Router();
+var utils = require('../../api_utils/utils');
+var CONSTANTS = require('../../api_utils/constants.js');
+var request = require('request');
+var _ = require('lodash');
+
+var sessions = {};
+
+sessions.routes = function(sessionsConfig) {
+    Router.use(bodyParser.json());
+    Router.use(cors());
+    Router.use(bodyParser.urlencoded({
+        extended: true
+    }));
+
+    // Overloaded get method to handle OpenIDConnect redirect to establish a session.
+    Router.get('/session*', cors(), /*sessionsConfig.authManager.passport.authenticate('main', {
+        noredirect: false
+    }), */function(req, res) {
+        req.query['api_server'] = sessionsConfig.api_server_protocol + '://' + sessionsConfig.api_server;
+        sessionsAPI.create(req, res).then(function(data) {
+            utils.sendSuccessResponse(data, res);
+        });
+    });
+
+    // For project switcher UI
+    Router.put('/session/:projectId', cors(), function(req, res) {
+        sessionsAPI.addProjectToSession(req, res).then(function(data) {
+            utils.sendSuccessResponse(data, res);
+        }, function(error) {
+            utils.sendErrorResponse(error, res);
+        });
+    });
+
+    Router.delete('/session', cors(), function(req, res) {
+        sessionsAPI.delete(req, res).then(function(data) {
+            utils.sendSuccessResponse(data, res);
+        });
+    });
+}
+
+sessions.router = Router;
+
+
+module.exports = sessions;
diff --git a/skyquake/framework/core/modules/routes/userManagement.js b/skyquake/framework/core/modules/routes/userManagement.js
new file mode 100644 (file)
index 0000000..22a2d74
--- /dev/null
@@ -0,0 +1,85 @@
+
+/*
+ *
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+/**
+ * inactivity routes module. Provides a RESTful API for this
+ * skyquake instance's inactivity state.
+ * @module framework/core/modules/routes/inactivity
+ * @author Laurence Maultsby <laurence.maultsby@riftio.com>
+ */
+
+var cors = require('cors');
+var bodyParser = require('body-parser');
+var Router = require('express').Router();
+var utils = require('../../api_utils/utils');
+var UserManagementAPI = require('../api/userManagementAPI.js');
+
+Router.use(bodyParser.json());
+Router.use(cors());
+Router.use(bodyParser.urlencoded({
+    extended: true
+}));
+
+Router.get('/user', cors(), function(req, res) {
+    UserManagementAPI.get(req).then(function(response) {
+        utils.sendSuccessResponse(response, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+Router.get('/user-profile', cors(), function(req, res) {
+    UserManagementAPI.getProfile(req).then(function(response) {
+        utils.sendSuccessResponse(response, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+Router.get('/user-data/:userId/:domain?', cors(), function(req, res) {
+    UserManagementAPI.getUserInfo(req).then(function(response) {
+        utils.sendSuccessResponse(response, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+Router.post('/user', cors(), function(req, res) {
+    UserManagementAPI.create(req).then(function(response) {
+        utils.sendSuccessResponse(response, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+Router.put('/user', cors(), function(req, res) {
+    UserManagementAPI.update(req).then(function(response) {
+        utils.sendSuccessResponse(response, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+Router.delete('/user/:username/:domain', cors(), function(req, res) {
+    UserManagementAPI.delete(req).then(function(response) {
+        utils.sendSuccessResponse(response, res);
+    }, function(error) {
+        utils.sendErrorResponse(error, res);
+    });
+});
+
+module.exports = Router;
+
+
+
diff --git a/skyquake/framework/core/views/home.ejs b/skyquake/framework/core/views/home.ejs
new file mode 100644 (file)
index 0000000..2cb2f80
--- /dev/null
@@ -0,0 +1,5 @@
+<% if (!user) { %>
+       <p>Welcome! Please <a href="/login">log in</a>.</p>
+<% } else { %>
+       <p>Hello, <%= user.username %>. View your <a href="<%= default_page %>">default page</a>. TODO: Update link to dashboard</p>
+<% } %>
\ No newline at end of file
diff --git a/skyquake/framework/core/views/idpconnectfail.ejs b/skyquake/framework/core/views/idpconnectfail.ejs
new file mode 100644 (file)
index 0000000..7847b3d
--- /dev/null
@@ -0,0 +1,43 @@
+<style type="text/css">
+       
+html {
+       background: #f1f1f1;
+}
+
+body {
+       background: #f1f1f1;
+}
+#idpfail {
+       display: flex;
+       flex-direction: column;
+       text-align: center;
+       align-items: center;
+}
+#idpfail .message {
+       display: flex;
+       margin-bottom: 20px;
+       font-size: 1.625rem;
+       font-weight: 400;
+       text-decoration: none;
+       text-transform: uppercase;
+       font-family: roboto-thin, Helvetica, Arial, sans-serif;
+       color: #CD5C5C;
+}
+#retrylink {
+       margin-top:40px;
+       font-family: roboto-thin, Helvetica, Arial, sans-serif;
+}
+
+
+</style>
+<div id="idpfail">
+       <p class="message">
+               We are having trouble connecting to the Identity Provider.
+       </p>
+       <p class="message">
+               Please check that it is running and reachable.
+       </p>
+       <p id="retrylink">
+               Once you have resolved the connectivity issues, <a href="<%= callback_url %>">please click here to retry.</a>
+       </p>
+</div>
\ No newline at end of file
diff --git a/skyquake/framework/plugin-index.html b/skyquake/framework/plugin-index.html
new file mode 100644 (file)
index 0000000..b704a3c
--- /dev/null
@@ -0,0 +1,13 @@
+<style>
+    html {
+        display: none;
+    }
+</style>
+<script>
+    if (self == top) {
+        document.documentElement.style.display = 'block';
+    } else {
+        top.location = self.location;
+    }
+</script>
+<div id="app"></div>
\ No newline at end of file
diff --git a/skyquake/framework/source/SourceCache.js b/skyquake/framework/source/SourceCache.js
new file mode 100644 (file)
index 0000000..ded3c9d
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 
+ *   Copyright 2017 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+import appConfiguration from '../utils/appConfiguration'
+
+let versionKeyPrefix = null;
+
+const localCache = new class {
+    get(key) {
+        let valueAsString = localStorage.getItem(key);
+        return valueAsString ? JSON.parse(valueAsString) : undefined;
+    }
+    set(key, val) {
+        localStorage.setItem(key, typeof val === 'string' ? val : JSON.stringify(val));
+    }
+}();
+
+let objCache = new Map();
+
+const storeCache = new class {
+    get(key) {
+        if (objCache[key]) {
+            objCache[key].timerId && clearTimeout(objCache[key].timerId)
+            objCache[key].timerId = setTimeout((key) => delete objCache[key], 2000)
+            return objCache[key].value;
+        } 
+        const obj = localCache.get(key);
+        if (obj) {
+            objCache[key] = {
+                value: obj,
+                timerId: setTimeout((key) => delete objCache[key], 2000)
+            }
+            return obj;
+        }
+    }
+    set(key, obj) {
+        setTimeout(localCache.set, 100, key, obj);
+        objCache[key] = {
+            value: obj,
+            timerId: setTimeout((key) => delete objCache[key], 2000)
+        }
+    }
+    init(version) {
+        versionKeyPrefix = 's-v-' + version;
+        const currentStoreVersion = localStorage.getItem('store-version');
+        if (currentStoreVersion !== version) {
+            let removeItems = [];
+            for (let i = 0; i < localStorage.length; ++i) {
+                let key = localStorage.key(i);
+                if (key.startsWith('s-v-')) {
+                    removeItems.push(key);
+                }
+            }
+            removeItems.forEach((key) => localStorage.removeItem(key));
+            localStorage.setItem('store-version', version);
+        }
+    }
+}();
+
+class StoreCache {
+    constructor(name) {
+        this.name = 's-v-' + name;
+    }
+    get(key) {
+        return storeCache.get(this.name + key);
+    }
+    set(key, obj) {
+        storeCache.set(this.name + key, obj);
+    }
+    init() {
+        return versionKeyPrefix ? Promise.resolve() : new Promise(
+            (resolve, reject) => {
+                appConfiguration.get().then((config) => {
+                    storeCache.init(config.version);
+                    resolve();
+                })
+            }
+        )
+    }
+}
+
+module.exports = StoreCache;
\ No newline at end of file
diff --git a/skyquake/framework/source/model/index.js b/skyquake/framework/source/model/index.js
new file mode 100644 (file)
index 0000000..019ada0
--- /dev/null
@@ -0,0 +1,7 @@
+import modelActions from './modelActions'
+import modelSource from './modelSource'
+
+export {
+    modelSource,
+    modelActions
+}
\ No newline at end of file
diff --git a/skyquake/framework/source/model/modelActions.js b/skyquake/framework/source/model/modelActions.js
new file mode 100644 (file)
index 0000000..41dbc00
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 
+ *   Copyright 2017 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+import Alt from 'widgets/skyquake_container/skyquakeAltInstance';
+
+class Actions {
+
+       constructor() {
+               this.generateActions(
+            'loadModel',
+            'processRequestSuccess',
+            'processRequestInitiated',
+            'processRequestFailure');
+       }
+}
+
+export default Alt.createActions(Actions);
diff --git a/skyquake/framework/source/model/modelSource.js b/skyquake/framework/source/model/modelSource.js
new file mode 100644 (file)
index 0000000..3779aa5
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 
+ *   Copyright 2017 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+import rw from 'utils/rw'
+import modelActions from './modelActions'
+import Utils from 'utils/utils'
+import $ from 'jquery';
+
+const source = {
+    loadModel: function () {
+        return {
+            remote: function (state, path) {
+                return new Promise(function (resolve, reject) {
+                    $.ajax({
+                        url: '/model?path=' + path,
+                        type: 'GET',
+                        success: function (result) {
+                            resolve(result);
+                        },
+                        error: function (xhr, errorType, errorMessage) {
+                            console.log("There was an error updating the model: ", errorType, errorMessage, xhr);
+                            reject({response: xhr.responseJSON, errorType, errorMessage});
+                        }
+                    });
+                })
+            },
+            success: modelActions.processRequestSuccess,
+            loading: modelActions.processRequestInitiated,
+            error: modelActions.processRequestFailure
+        }
+    },
+    updateModel: function () {
+        return {
+            remote: function (state, path, data) {
+                const url = path.reduce((url, node) => {
+                    url += node[0] !== '[' ? '/' : '';
+                    return url + node
+                }, `/model?path=/${state.path}`);                
+                return new Promise(function (resolve, reject) {
+                    $.ajax({
+                        url: url,
+                        type: 'PATCH',
+                        data: data,
+                        success: function (result) {
+                            resolve(result);
+                        },
+                        error: function (xhr, errorType, errorMessage) {
+                            console.log("There was an error updating the model: ", errorType, errorMessage, xhr);
+                            reject({response: xhr.responseJSON, errorType, errorMessage});
+                        }
+                    });
+                })
+            },
+            success: modelActions.processRequestSuccess,
+            loading: modelActions.processRequestInitiated,
+            error: modelActions.processRequestFailure
+        }
+    },
+    createModel: function () {
+        return {
+            remote: function (state, path, data) {
+                const url = path.reduce((url, node) => {
+                    url += node[0] !== '[' ? '/' : '';
+                    return url + node
+                }, `/model?path=/${state.path}`);                
+                return new Promise(function (resolve, reject) {
+                    $.ajax({
+                        url: url,
+                        type: 'PUT',
+                        data: data,
+                        success: function (result) {
+                            resolve(result);
+                        },
+                        error: function (xhr, errorType, errorMessage) {
+                            console.log("There was an error updating the model: ", errorType, errorMessage, xhr);
+                            reject({response: xhr.responseJSON, errorType, errorMessage});
+                        }
+                    });
+                })
+            },
+            success: modelActions.processRequestSuccess,
+            loading: modelActions.processRequestInitiated,
+            error: modelActions.processRequestFailure
+        }
+    },
+
+    deleteModel: function () {
+        return {
+            remote: function (state, path) {
+                const url = path.reduce((url, node) => {
+                    url += node[0] !== '[' ? '/' : '';
+                    return url + node
+                }, `/model?path=/${state.path}`);                
+                return new Promise(function (resolve, reject) {
+                    $.ajax({
+                        url: url,
+                        type: 'DELETE',
+                        success: function (result) {
+                            resolve(result);
+                        },
+                        error: function (xhr, errorType, errorMessage) {
+                            console.log("There was an error updating the model: ", errorType, errorMessage, xhr);
+                            reject({response: xhr.responseJSON, errorType, errorMessage});
+                        }
+                    });
+                })
+            },
+            success: modelActions.processRequestSuccess,
+            loading: modelActions.processRequestInitiated,
+            error: modelActions.processRequestFailure
+        }
+    }
+}
+module.exports = source;
\ No newline at end of file
diff --git a/skyquake/framework/source/schema/index.js b/skyquake/framework/source/schema/index.js
new file mode 100644 (file)
index 0000000..95b152e
--- /dev/null
@@ -0,0 +1,7 @@
+import schemaActions from './schemaActions'
+import schemaSource from './schemaSource'
+
+export {
+    schemaSource,
+    schemaActions
+}
\ No newline at end of file
diff --git a/skyquake/framework/source/schema/schemaActions.js b/skyquake/framework/source/schema/schemaActions.js
new file mode 100644 (file)
index 0000000..7e36cca
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 
+ *   Copyright 2017 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+import Alt from 'widgets/skyquake_container/skyquakeAltInstance';
+
+class Actions {
+
+       constructor() {
+               this.generateActions(
+            'loadSchema',
+            'loadSchemaSuccess',
+            'loadSchemaLoading',
+            'loadSchemaFail');
+       }
+}
+
+export default Alt.createActions(Actions);
diff --git a/skyquake/framework/source/schema/schemaSource.js b/skyquake/framework/source/schema/schemaSource.js
new file mode 100644 (file)
index 0000000..2c7bd5b
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 
+ *   Copyright 2017 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+import rw from 'utils/rw'
+import schemaActions from './schemaActions'
+import Utils from 'utils/utils'
+import $ from 'jquery';
+import StoreCache from '../SourceCache'
+
+const storeCache = new StoreCache('schema');
+storeCache.init(); // get the ball rolling
+
+function getCachedSchema(request) {
+    const cachedSchema = {};
+    const requestSchema = [];
+    request.forEach((path) => {
+        let schema = storeCache.get(path);
+        if (schema) {
+            cachedSchema[path] = schema
+        } else {
+            requestSchema.push(path);
+        }
+    });
+    return {
+        cachedSchema,
+        requestSchema
+    };
+}
+
+const schemaSource = {
+    loadSchema: function () {
+        return {
+            local: function (state, request) {
+                request = Array.isArray(request) ? request : [request];
+                const results = getCachedSchema(request);
+                if (!results.requestSchema.length) {
+                    return(Promise.resolve(results.cachedSchema));
+                }
+            }, 
+
+            remote: function (state, request) {
+                return new Promise(function (resolve, reject) {
+                    storeCache.init().then(() => {
+                        request = Array.isArray(request) ? request : [request];
+                        const results = getCachedSchema(request);
+                        if (!results.requestSchema.length) {
+                            resolve({
+                                schema: results.cachedSchema
+                            });
+                        } else {
+                            $.ajax({
+                                url: '/schema?request=' + results.requestSchema.join(','),
+                                type: 'GET',
+                                success: function ({
+                                    schema
+                                }) {
+                                    for (let path in schema) {
+                                        storeCache.set(path, schema[path]);
+                                    }
+                                    resolve(getCachedSchema(request).cachedSchema);
+                                },
+                                error: function (error) {
+                                    console.log("There was an error getting the schema: ", error);
+                                    reject(error);
+                                }
+                            }).fail(function (xhr) {
+                                console.log("There was an error getting the schema: ", xhr);
+                                Utils.checkAuthentication(xhr.status);
+                                reject("There was an error getting the schema.")
+                            });
+                        }
+                    })
+                })
+            },
+            success: schemaActions.loadSchemaSuccess,
+            loading: schemaActions.loadSchemaLoading,
+            error: schemaActions.loadSchemaFail
+        }
+    },
+}
+export default schemaSource;
\ No newline at end of file
index 9378984..a01c293 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,7 +31,7 @@ $body-color:$lightest-gray;
 
 $error-red:#FF5F5F;
 
-//PC
+/*PC*/
 
 $black: #000;
 $gray-lightest: #f1f1f1;
@@ -42,9 +42,9 @@ $gray-dark: #999;
 $gray-darker: #666;
 $gray-darkest: #333;
 $white: #FFF;
-//
-// Brand Colors
-//
+/**/
+/* Brand Colors*/
+/**/
 $brand-blue-light: #30baef;
 $brand-blue: #00acee;
 $brand-blue-dark: #147ca3;
@@ -66,11 +66,12 @@ $neutral-light-3: hsl(360, 100%, 50%);
 $neutral-light-4: hsl(360, 100%, 50%);
 $neutral-light-5: hsl(360, 100%, 50%);
 
-$neutral-dark-1: hsl(360, 100%, 50%);
-$neutral-dark-2: hsl(360, 100%, 50%);
-$neutral-dark-3: hsl(360, 100%, 50%);
-$neutral-dark-4: hsl(360, 100%, 50%);
-$neutral-dark-5: hsl(360, 100%, 50%);
+$neutral-dark-0: hsl(0, 0%, 80.7%);
+$neutral-dark-1: hsl(0, 0%, 63.7%);
+$neutral-dark-2: hsl(0, 0%, 56.7%);
+$neutral-dark-3: hsl(0, 0%, 49.7%);
+$neutral-dark-4: hsl(0, 0%, 42.7%);
+$neutral-dark-5: hsl(0, 0%, 35.7%);
 $netral-black: hsl(0, 100%, 0%);
 
 
index 01b728b..e9d5de9 100644 (file)
@@ -16,8 +16,6 @@
  *
  */
 /*@import "./vendor/css-reset-2.0/css-reset.css";*/
-@import "../../node_modules/reset-css/reset.css";
-
 .has-drop-shadow {
     box-shadow: 2px 2px rgba(0, 0, 0, .15)
 }
@@ -2023,7 +2021,7 @@ a[role=button] {
     margin-top: 150px;
     margin-bottom: 20px;
     background-size: 154px 102px;
-    /*background-image: url(./img/header-logo.png)*/
+       /*background-image: url(./img/header-logo.png)*/
     background-image: url(./img/svg/osm-logo_color_rgb.svg);
 }
 .login-cntnr .riftio {
index 53a9500..c67dca3 100644 (file)
Binary files a/skyquake/framework/style/img/osm_header.png and b/skyquake/framework/style/img/osm_header.png differ
index 1005431..3055122 100644 (file)
Binary files a/skyquake/framework/style/img/osm_header_253x50.png and b/skyquake/framework/style/img/osm_header_253x50.png differ
index 7ece845..4b7a344 100644 (file)
Binary files a/skyquake/framework/style/img/osm_header_506x100.png and b/skyquake/framework/style/img/osm_header_506x100.png differ
diff --git a/skyquake/framework/utils/appConfiguration.js b/skyquake/framework/utils/appConfiguration.js
new file mode 100644 (file)
index 0000000..2882309
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *
+ *   Copyright 2017 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+import $ from 'jquery';
+
+const configPromise = new Promise((resolve, reject) => {
+    $.ajax({
+        url: '/app-config',
+        type: 'GET',
+        success: function (data) {
+            if (data.version.endsWith('.1')){
+                data.version = '' + Date.now();
+            }
+            resolve(data);
+        },
+        error: function (error) {
+            console.log("There was an error getting config: ", error);
+            reject(error);
+        }
+    }).fail(function (xhr) {
+        console.log('There was an xhr error getting the config', xhr);
+        reject(xhr);
+    });
+});
+
+module.exports = {
+    get: () => configPromise
+};
\ No newline at end of file
diff --git a/skyquake/framework/utils/roleConstants.js b/skyquake/framework/utils/roleConstants.js
new file mode 100644 (file)
index 0000000..5ac4e64
--- /dev/null
@@ -0,0 +1,31 @@
+var c = {};
+
+c.PLATFORM = {
+  OPER: "rw-rbac-platform:platform-oper",
+  ADMIN: "rw-rbac-platform:platform-admin",
+  SUPER: "rw-rbac-platform:super-admin"
+}
+
+c.PROJECT = {
+    TYPE: {
+      "rw-project-mano:catalog-oper": "rw-project-mano",
+      "rw-project-mano:catalog-admin": "rw-project-mano",
+      "rw-project-mano:lcm-oper": "rw-project-mano",
+      "rw-project-mano:lcm-admin": "rw-project-mano",
+      "rw-project-mano:account-oper": "rw-project-mano",
+      "rw-project-mano:account-admin": "rw-project-mano",
+      "rw-project:project-oper": "rw-project",
+      "rw-project:project-admin": "rw-project"
+    },
+    CATALOG_OPER: "rw-project-mano:catalog-oper",
+    CATALOG_ADMIN: "rw-project-mano:catalog-admin",
+    LCM_OPER: "rw-project-mano:lcm-oper",
+    LCM_ADMIN: "rw-project-mano:lcm-admin",
+    ACCOUNT_OPER: "rw-project-mano:account-oper",
+    ACCOUNT_ADMIN: "rw-project-mano:account-admin",
+    PROJECT_OPER: "rw-project:project-oper",
+    PROJECT_ADMIN: "rw-project:project-admin"
+
+}
+
+module.exports = c;
index 7b93fd5..88ef939 100644 (file)
  *   limitations under the License.
  *
  */
-//Login needs to be refactored. Too many cross dependencies
-var AuthActions = require('../widgets/login/loginAuthActions.js');
-var $ = require('jquery');
-import rw from './rw.js';
+import AuthActions from '../widgets/login/loginAuthActions';
+import $ from 'jquery';
+import rw from './rw';
+import appConfiguration from './appConfiguration'
+import SockJS from 'sockjs-client';
+
 var API_SERVER = rw.getSearchParams(window.location).api_server;
 let NODE_PORT = rw.getSearchParams(window.location).api_port || ((window.location.protocol == 'https:') ? 8443 : 8000);
-var SockJS = require('sockjs-client');
 
 var Utils = {};
 
@@ -29,25 +30,6 @@ Utils.DescriptorModelMeta = null;
 
 var INACTIVITY_TIMEOUT = 600000;
 
-Utils.getInactivityTimeout = function() {
-    return new Promise(function(resolve, reject) {
-        $.ajax({
-            url: '/inactivity-timeout',
-            type: 'GET',
-            success: function(data) {
-                resolve(data);
-            },
-            error: function(error) {
-                console.log("There was an error getting the inactivity-timeout: ", error);
-                reject(error);
-            }
-        }).fail(function(xhr) {
-            console.log('There was an xhr error getting the inactivity-timeout', xhr);
-            reject(xhr);
-        });
-    });
-};
-
 Utils.isMultiplexerLoaded = function() {
     if (window.multiplexer) {
         return true;
@@ -75,14 +57,19 @@ Utils.setupMultiplexClient = function() {
     loadChecker();
 };
 
-Utils.checkAndResolveSocketRequest = function(data, resolve, reject) {
+Utils.checkAndResolveSocketRequest = function(data, resolve, reject, successCallback) {
     const checker = () => {
         if (!Utils.isMultiplexerLoaded()) {
             setTimeout(() => {
                 checker();
             }, 500);
         } else {
-            resolve(data.id);
+            if (!successCallback) {
+                resolve(data.id);
+            } else {
+                //resolve handled in callback
+                successCallback(data.id)
+            }
         }
     };
 
@@ -90,9 +77,8 @@ Utils.checkAndResolveSocketRequest = function(data, resolve, reject) {
 };
 
 Utils.bootstrapApplication = function() {
-    var self = this;
-    return new Promise(function(resolve, reject) {
-        Promise.all([self.getInactivityTimeout()]).then(function(results) {
+    return new Promise((resolve, reject) => {
+        Promise.all([appConfiguration.get()]).then(function(results) {
             INACTIVITY_TIMEOUT = results[0]['inactivity-timeout'];
             resolve();
         }, function(error) {
@@ -129,8 +115,9 @@ Utils.getDescriptorModelMeta = function() {
 }
 
 Utils.addAuthorizationStub = function(xhr) {
-    var Auth = window.sessionStorage.getItem("auth");
-    xhr.setRequestHeader('Authorization', 'Basic ' + Auth);
+    // NO-OP now that we are dealing with it on the server
+    // var Auth = window.sessionStorage.getItem("auth");
+    // xhr.setRequestHeader('Authorization', 'Basic ' + Auth);
 };
 
 Utils.getByteDataWithUnitPrefix = function(number, precision) {
@@ -183,36 +170,30 @@ Utils.getPacketDataWithUnitPrefix = function(number, precision) {
     }
 }
 Utils.loginHash = "#/login";
-Utils.setAuthentication = function(username, password, cb) {
-    var self = this;
-    var AuthBase64 = btoa(username + ":" + password);
-    window.sessionStorage.setItem("auth", AuthBase64);
-    self.detectInactivity();
-    $.ajax({
-            url: '//' + window.location.hostname + ':' + window.location.port + '/check-auth?api_server=' + API_SERVER,
-            type: 'GET',
-            beforeSend: Utils.addAuthorizationStub,
-            success: function(data) {
-              //console.log("LoggingSource.getLoggingConfig success call. data=", data);
-                if (cb) {
-                    cb();
-                };
-            },
-            error: function(data) {
-                Utils.clearAuthentication();
-            }
-          });
-}
-Utils.clearAuthentication = function(callback) {
+
+Utils.clearAuthentication = function() {
     var self = this;
     window.sessionStorage.removeItem("auth");
     AuthActions.notAuthenticated();
     window.sessionStorage.setItem("locationRefHash", window.location.hash);
-    if (callback) {
-        callback();
-    } else {
-        window.location.hash = Utils.loginHash;
-    }
+    var reloadURL = '';
+    $.ajax({
+        url: '//' + window.location.hostname + ':' + window.location.port + '/session?api_server=' + API_SERVER + '&hash=' + encodeURIComponent(window.location.hash),
+        type: 'DELETE',
+        success: function(data) {
+            console.log('User logged out');
+            reloadURL = data['url'] + '?post_logout_redirect_uri=' +
+                 window.location.protocol + '//' +
+                 window.location.hostname + ':' +
+                 window.location.port +
+                 '/?api_server=' + API_SERVER;
+
+            window.location.replace(reloadURL);
+        },
+        error: function(data) {
+            console.log('Problem logging user out');
+        }
+    });
 }
 Utils.isNotAuthenticated = function(windowLocation, callback) {
     var self = this;
@@ -322,4 +303,24 @@ Utils.parseError = (error) => {
     return displayMsg
 }
 
+Utils.rpcError = (rpcResult) => {
+    try {
+        let info = JSON.parse(rpcResult);
+        let rpcError = info.body || info.errorMessage.body || info.errorMessage.error;
+        if (rpcError) {
+            if (typeof rpcError === 'string') {
+                const index = rpcError.indexOf('{');
+                if (index >= 0) {
+                    return JSON.parse(rpcError.substr(index));
+                }
+            } else {
+                return rpcError;
+            }
+        }
+    } catch (e) {
+    }
+    console.log('invalid rpc error: ', rpcResult);
+    return null;
+}
+
 module.exports = Utils;
index c972e14..043a769 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -62,15 +62,18 @@ button{
 ############################################################################ */
 
 .SqButton {
-  align-items: center;
+  -ms-flex-align: center;
+      align-items: center;
   border-style: solid;
   border-radius: 3px;
   border-width: 0px;
   cursor: pointer;
+  display: -ms-inline-flexbox;
   display: inline-flex;
   font-size: 1rem;
   height: 50px;
-  justify-content: center;
+  -ms-flex-pack: center;
+      justify-content: center;
   margin: 0 10px;
   outline: none;
   padding: 0 15px;
@@ -107,8 +110,9 @@ button{
 
   /* Focus */
   &:focus {
-    // box-shadow: $focus-shadow;
-    border: 1px solid red;
+    /* box-shadow: $focus-shadow;*/
+    border: 1px solid;
+    border-color: darken($normalHoverBackground, 10%);
   }
 
   /* SIZES
@@ -256,11 +260,14 @@ button{
       fill: $primaryForeground;
     }
   }
-
-
 }
 
-
+.sqButtonGroup {
+  display: -ms-flexbox;
+  display: flex;
+  -ms-flex-pack: center;
+      justify-content: center;
+}
 
 
 
index ae93128..8d0ec77 100644 (file)
@@ -36,17 +36,35 @@ export default class SqButton extends React.Component {
             Class += " is-disabled";
         }
         return (
-                <div style={{display: 'flex'}}>
+        <div style={{display: 'flex'}} onClick={this.props.onClick}>
             <div className={Class} tabIndex="0">
-            {svgHTML}
-              <div className="SqButton-content">{label}</div>
+                {svgHTML}
+                <div className="SqButton-content">{label}</div>
             </div>
+        </div>
+        )
+    }
+}
+
+export class ButtonGroup extends React.Component {
+    render() {
+        let className = "sqButtonGroup";
+        if (this.props.className) {
+            className = `${className} ${this.props.className}`
+        }
+        return (
+            <div className={className} style={this.props.style}>
+                {this.props.children}
             </div>
         )
     }
 }
 
+
 SqButton.defaultProps = {
+    onClick: function(e) {
+        console.log('Clicked')
+    },
     icon: false,
     primary: false,
     disabled: false,
index f38719a..461a783 100644 (file)
@@ -26,355 +26,7 @@ export default {
 //  Histogram: Histogram,
   Multicomponent: require('./multicomponent/multicomponent.js'),
   Mixins: require('./mixins/ButtonEventListener.js'),
-  // Gauge: require('./gauge/gauge.js'),
+//  Gauge: require('./gauge/gauge.js'),
   Bullet: require('./bullet/bullet.js')
 };
 
-// require('../../assets/js/n3-line-chart.js');
-// var Gauge = require('../../assets/js/gauge-modified.js');
-// var bulletController = function($scope, $element) {
-//     this.$element = $element;
-//     this.vertical = false;
-//     this.value = 0;
-//     this.min = 0;
-//     this.max = 100;
-//     //this.range = this.max - this.min;
-//     //this.percent = (this.value - this.min) / this.range;
-//     this.displayValue = this.value;
-//     this.isPercent = (this.units == '')? true:false;
-//     this.bulletColor = "#6BB814";
-//     this.fontsize = 28;
-//     this.radius = 4;
-//     this.containerMarginX = 0;
-//     this.containerMarginY = 0;
-//     this.textMarginX = 5;
-//     this.textMarginY = 42;
-//     this.bulletMargin = 0;
-//     this.width = 512;
-//     this.height = 64;
-//     this.markerX = -100; // puts it off screen unless set
-//     var self = this;
-//     if (this.isPercent) {
-//         this.displayValue + "%";
-//     }
-//     $scope.$watch(
-//       function() {
-//         return self.value;
-//       },
-//       function() {
-//         self.valueChanged();
-//       }
-//     );
-
-//   }
-
-//   bulletController.prototype = {
-
-//     valueChanged: function() {
-//       var range = this.max - this.min;
-//       var normalizedValue = (this.value - this.min) / range;
-//       if (this.isPercent) {
-//         this.displayValue = String(Math.round(normalizedValue * 100)) + "%";
-//       } else {
-//         this.displayValue = this.value;
-//       }
-//       // All versions of IE as of Jan 2015 does not support inline CSS transforms on SVG
-//       if (platform.name == 'IE') {
-//         this.bulletWidth = Math.round(100 * normalizedValue) + '%';
-//       } else {
-//         this.bulletWidth = this.width - (2 * this.containerMarginX);
-//         var transform = 'scaleX(' + normalizedValue + ')';
-//         var bullet = $(this.$element).find('.bullet2');
-//         bullet.css('transform', transform);
-//         bullet.css('-webkit-transform', transform);
-//       }
-//     },
-
-//     markerChanged: function() {
-//       var range = this.max - this.min;
-//       var w = this.width - (2 * this.containerMarginX);
-//       this.markerX = this.containerMarginX + ((this.marker - this.min) / range ) * w;
-//       this.markerY1 = 7;
-//       this.markerY2 = this.width - 7;
-//     }
-//   }
-
-// angular.module('components', ['n3-line-chart'])
-//     .directive('rwBullet', function() {
-//       return {
-//         restrict : 'E',
-//         templateUrl: 'modules/views/rw.bullet.tmpl.html',
-//         bindToController: true,
-//         controllerAs: 'bullet',
-//         controller: bulletController,
-//         replace: true,
-//         scope: {
-//           min : '@?',
-//           max : '@?',
-//           value : '@',
-//           marker: '@?',
-//           units: '@?',
-//           bulletColor: '@?',
-//           label: '@?'
-//         }
-//       };
-//     })
-//     .directive('rwSlider', function() {
-//       var controller = function($scope, $element, $timeout) {
-//         // Q: is there a way to force attributes to be ints?
-//         $scope.min = $scope.min || "0";
-//         $scope.max = $scope.max || "100";
-//         $scope.step = $scope.step || "1";
-//         $scope.height = $scope.height || "30";
-//         $scope.orientation = $scope.orientation || 'horizontal';
-//         $scope.tooltipInvert = $scope.tooltipInvert || false;
-//         $scope.percent = $scope.percent || false;
-//         $scope.kvalue = $scope.kvalue || false;
-//         $scope.direction = $scope.direction || "ltr";
-//         $($element).noUiSlider({
-//           start: parseInt($scope.value),
-//           step: parseInt($scope.step),
-//           orientation: $scope.orientation,
-//           range: {
-//             min: parseInt($scope.min),
-//             max: parseInt($scope.max)
-//           },
-//           direction: $scope.direction
-//         });
-//         //$(".no-Ui-target").Link('upper').to('-inline-<div class="tooltip"></div>')
-//         var onSlide = function(e, value) {
-//           $timeout(function(){
-//             $scope.value = value;
-//           })
-
-//         };
-//         $($element).on({
-//           change: onSlide,
-//           slide: onSlide,
-//           set: $scope.onSet({value: $scope.value})
-//         });
-//         var val = String(Math.round($scope.value));
-//         if ($scope.percent) {
-//             val += "%"
-//         } else if ($scope.kvalue) {
-//             val += "k"
-//         }
-//         $($element).height($scope.height);
-//         if ($scope.tooltipInvert) {
-//             $($element).find('.noUi-handle').append("<div class='tooltip' style='position:relative;right:20px'>" + val + "</div>");
-//         } else {
-//             $($element).find('.noUi-handle').append("<div class='tooltip' style='position:relative;left:-20px'>" + val + "</div>");
-//         }
-//         $scope.$watch('value', function(value) {
-//         var val = String(Math.round($scope.value));
-//         if ($scope.percent) {
-//             val += "%"
-//         } else if($scope.kvalue) {
-//             val += "k"
-//         }
-//           $($element).val(value);
-//           $($element).find('.tooltip').html(val);
-//         if ($scope.tooltipInvert) {
-//             $($element).find('.tooltip').css('right', $($element).find('.tooltip').innerWidth() * -1);
-//         } else {
-//             $($element).find('.tooltip').css('left', $($element).find('.tooltip').innerWidth() * -1);
-//         }
-//         });
-//       };
-
-//       return {
-//         restrict : 'E',
-//         template: '<div></div>',
-//         controller : controller,
-//         replace: true,
-//         scope: {
-//           min : '@',
-//           max : '@',
-//           width: '@',
-//           height: '@',
-//           step : '@',
-//           orientation : '@',
-//           tooltipInvert: '@',
-//           percent: '@',
-//           kvalue: '@?',
-//           onSet:'&?',
-//           direction: '@?',
-//           value:'=?'
-//         }
-//       };
-//     })
-// .directive('rwGauge', function() {
-//     return {
-//         restrict: 'AE',
-//         template: '<canvas class="rwgauge" style="width:100%;height:100%;max-width:{{width}}px;max-height:240px;"></canvas>',
-//         replace: true,
-//         scope: {
-//             min: '@?',
-//             max: '@?',
-//             size: '@?',
-//             color: '@?',
-//             value: '@?',
-//             resize: '@?',
-//             isAggregate: '@?',
-//             units: '@?',
-//             valueFormat: '=?',
-//             width: '@?'
-//         },
-//         bindToController: true,
-//         controllerAs: 'gauge',
-//         controller: function($scope, $element) {
-//             var self = this;
-//             this.gauge = null;
-//             this.min = this.min || 0;
-//             this.max = this.max || 100;
-//             this.nSteps = 14;
-//             this.size = this.size || 300;
-//             this.units = this.units || '';
-//             $scope.width = this.width || 240;
-//             this.color = this.color || 'hsla(212, 57%, 50%, 1)';
-//             if (!this.valueFormat) {
-//                 if (this.max > 1000 || this.value) {
-//                     self.valueFormat = {
-//                         "int": 1,
-//                         "dec": 0
-//                     };
-//                 } else {
-//                     self.valueFormat = {
-//                         "int": 1,
-//                         "dec": 2
-//                     };
-//                 }
-//             }
-//             this.isAggregate = this.isAggregate || false;
-//             this.resize = this.resize || false;
-//             if (this.format == 'percent') {
-//                 self.valueFormat = {
-//                     "int": 3,
-//                     "dec": 0
-//                 };
-//             }
-//             $scope.$watch(function() {
-//                 return self.max;
-//             }, function(n, o) {
-//                 if(n !== o) {
-//                     renderGauge();
-//                 }
-//             });
-//             $scope.$watch(function() {
-//                 return self.valueFormat;
-//             }, function(n, o) {
-//                 if(n != 0) {
-//                     renderGauge();
-//                 }
-//             });
-//             $scope.$watch(function() {
-//                 return self.value;
-//             }, function() {
-//                 if (self.gauge) {
-//                     // w/o rounding gauge will unexplainably thrash round.
-//                     self.valueFormat = determineValueFormat(self.value);
-//                     self.gauge.setValue(Math.ceil(self.value * 100) / 100);
-//                     //self.gauge.setValue(Math.round(self.value));
-//                 }
-//             });
-//             angular.element($element).ready(function() {
-//                 console.log('rendering')
-//                 renderGauge();
-//             })
-//             window.testme = renderGauge;
-//             function determineValueFormat(value) {
-
-//                     if (value > 999 || self.units == "%") {
-//                         return {
-//                             "int": 1,
-//                             "dec": 0
-//                         }
-//                     }
-
-//                     return {
-//                         "int": 1,
-//                         "dec": 2
-//                     }
-//                 }
-//             function renderGauge(calcWidth) {
-//                 if (self.max == self.min) {
-//                     self.max = 14;
-//                 }
-//                 var range = self.max - self.min;
-//                 var step = Math.round(range / self.nSteps);
-//                 var majorTicks = [];
-//                 for (var i = 0; i <= self.nSteps; i++) {
-//                     majorTicks.push(self.min + (i * step));
-//                 };
-//                 var redLine = self.min + (range * 0.9);
-//                 var config = {
-//                     isAggregate: self.isAggregate,
-//                     renderTo: angular.element($element)[0],
-//                     width: calcWidth || self.size,
-//                     height: calcWidth || self.size,
-//                     glow: false,
-//                     units: self.units,
-//                     title: false,
-//                     minValue: self.min,
-//                     maxValue: self.max,
-//                     majorTicks: majorTicks,
-//                     valueFormat: determineValueFormat(self.value),
-//                     minorTicks: 0,
-//                     strokeTicks: false,
-//                     highlights: [],
-//                     colors: {
-//                         plate: 'rgba(0,0,0,0)',
-//                         majorTicks: 'rgba(15, 123, 182, .84)',
-//                         minorTicks: '#ccc',
-//                         title: 'rgba(50,50,50,100)',
-//                         units: 'rgba(50,50,50,100)',
-//                         numbers: '#fff',
-//                         needle: {
-//                             start: 'rgba(255, 255, 255, 1)',
-//                             end: 'rgba(255, 255, 255, 1)'
-//                         }
-//                     }
-//                 };
-//                 var min = config.minValue;
-//                 var max = config.maxValue;
-//                 var N = 1000;
-//                 var increment = (max - min) / N;
-//                 for (i = 0; i < N; i++) {
-//                     var temp_color = 'rgb(0, 172, 238)';
-//                     if (i > 0.5714 * N && i <= 0.6428 * N) {
-//                         temp_color = 'rgb(0,157,217)';
-//                     } else if (i >= 0.6428 * N && i < 0.7142 * N) {
-//                         temp_color = 'rgb(0,142,196)';
-//                     } else if (i >= 0.7142 * N && i < 0.7857 * N) {
-//                         temp_color = 'rgb(0,126,175)';
-//                     } else if (i >= 0.7857 * N && i < 0.8571 * N) {
-//                         temp_color = 'rgb(0,122,154)';
-//                     } else if (i >= 0.8571 * N && i < 0.9285 * N) {
-//                         temp_color = 'rgb(0,96,133)';
-//                     } else if (i >= 0.9285 * N) {
-//                         temp_color = 'rgb(0,80,112)';
-//                     }
-//                     config.highlights.push({
-//                         from: i * increment,
-//                         to: increment * (i + 2),
-//                         color: temp_color
-//                     })
-//                 }
-//                 var updateSize = _.debounce(function() {
-//                     config.maxValue = self.max;
-//                     var clientWidth = self.parentNode.parentNode.clientWidth / 2;
-//                     var calcWidth = (300 > clientWidth) ? clientWidth : 300;
-//                     self.gauge.config.width = self.gauge.config.height = calcWidth;
-//                     self.renderGauge(calcWidth);
-//                 }, 500);
-//                 if (self.resize) $(window).resize(updateSize)
-//                 if (self.gauge) {
-//                     self.gauge.updateConfig(config);
-//                 } else {
-//                     self.gauge = new Gauge(config);
-//                     self.gauge.draw();
-//                 }
-//             };
-//         },
-//     }
-// });
diff --git a/skyquake/framework/widgets/form_controls/formControls.jsx b/skyquake/framework/widgets/form_controls/formControls.jsx
new file mode 100644 (file)
index 0000000..e50fb7e
--- /dev/null
@@ -0,0 +1,113 @@
+import './formControls.jsx';
+
+import React from 'react'
+import SelectOption from 'widgets/form_controls/selectOption.jsx';
+import imgAdd from '../../../node_modules/open-iconic/svg/plus.svg'
+import imgRemove from '../../../node_modules/open-iconic/svg/trash.svg'
+import TextInput from 'widgets/form_controls/textInput.jsx';
+import Input from 'widgets/form_controls/input.jsx';
+
+export class FormSection extends React.Component {
+    render() {
+        let className = 'FormSection ' + this.props.className;
+        let html = (
+            <div
+                style={this.props.style}
+                className={className}
+            >
+                <div className="FormSection-title">
+                    {this.props.title}
+                </div>
+                <div className="FormSection-body">
+                    {this.props.children}
+                </div>
+            </div>
+        );
+        return html;
+    }
+}
+
+FormSection.defaultProps = {
+    className: ''
+}
+
+/**
+ * AddItemFn:
+ */
+export class InputCollection extends React.Component {
+    constructor(props) {
+        super(props);
+        this.collection = props.collection;
+    }
+    buildTextInput(onChange, v, i) {
+        return (
+            <Input
+                readonly={this.props.readonly}
+                style={{flex: '1 1'}}
+                key={i}
+                value={v}
+                onChange= {onChange.bind(null, i)}
+            />
+        )
+    }
+    buildSelectOption(initial, options, onChange, v, i) {
+        return (
+            <SelectOption
+                readonly={this.props.readonly}
+                key={`${i}-${v.replace(' ', '_')}`}
+                intial={initial}
+                defaultValue={v}
+                options={options}
+                onChange={onChange.bind(null, i)}
+            />
+        );
+    }
+    showInput() {
+
+    }
+    render() {
+        const props = this.props;
+        let inputType;
+        let className = "InputCollection";
+        if (props.className) {
+            className = `${className} ${props.className}`;
+        }
+        if (props.type == 'select') {
+            inputType = this.buildSelectOption.bind(this, props.initial, props.options, props.onChange);
+        } else {
+            inputType = this.buildTextInput.bind(this, props.onChange)
+        }
+        let html = (
+            <div className="InputCollection-wrapper">
+                {props.collection.map((v,i) => {
+                    return (
+                        <div key={i} className={className} >
+                            {inputType(v, i)}
+                            {
+                                props.readonly ? null : <span onClick={props.RemoveItemFn.bind(null, i)} className="removeInput"><img src={imgRemove} />Remove</span>}
+                        </div>
+                    )
+                })}
+                { props.readonly ? null : <span onClick={props.AddItemFn} className="addInput"><img src={imgAdd} />Add</span>}
+            </div>
+        );
+        return html;
+    }
+}
+
+InputCollection.defaultProps = {
+    input: Input,
+    collection: [],
+    onChange: function(i, e) {
+        console.log(`
+                        Updating with: ${e.target.value}
+                        At index of: ${i}
+                    `)
+    },
+    AddItemFn: function(e) {
+        console.log(`Adding a new item to collection`)
+    },
+    RemoveItemFn: function(i, e) {
+        console.log(`Removing item from collection at index of: ${i}`)
+    }
+}
index 4a88435..ad95add 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
  *   limitations under the License.
  *
  */
-@import 'style/_colors.scss';
+@import '../../style/_colors.scss';
 
 .sqTextInput {
     display: -ms-flexbox;
@@ -32,9 +32,9 @@
         color:$darker-gray;
         text-transform:uppercase;
     }
-    input, .readonly, textarea {
+    input, textarea {
         height: 35px;
-        box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.39), 0 -1px 1px #ffffff, 0 1px 0 #ffffff;
+        /* box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.39), 0 -1px 1px #ffffff, 0 1px 0 #ffffff;*/
         font-size: 1rem;
         display: block;
         background: white !important;
@@ -49,6 +49,7 @@
     .readonly {
         line-height: 35px;
         box-shadow:none;
+        background:none !important;
     }
     textarea {
         -ms-flex-align: stretch;
         border:0px;
         height: 100%;
     }
+    &.checkbox {
+        -ms-flex-direction:row;
+            flex-direction:row;
+            -ms-flex-align:center;
+                align-items:center;
+        margin-bottom:0;
+            >span {
+                -ms-flex-order: 1;
+                    order: 1;
+                    padding-left:1rem;
+            }
+            >input {
+                -ms-flex-order: 0;
+                    order: 0;
+
+                    box-shadow:none;
+                    height:25px;
+            }
+    }
+    .invalid {
+        color: red;
+        font-weight:strong;
+    }
+     input:invalid {
+        border: 2px solid red;
+        &:after {
+            content: 'Invalid Value'
+        }
+    }
+}
+
+.sqCheckBox {
+    display:-ms-flexbox;
+    display:flex;
+    label {
+        display:-ms-flexbox;
+        display:flex;
+        -ms-flex-align: center;
+        align-items: center;
+        input {
+            box-shadow: none;
+            height: auto;
+            margin: 0 0.25rem;
+        }
+    }
+}
+
+.FormSection {
+    &-title {
+        color: #000;
+        background: lightgray;
+        padding: 0.5rem;
+        border-top: 1px solid #f1f1f1;
+        border-bottom: 1px solid #f1f1f1;
+    }
+    &-body {
+        padding: 0.5rem 0.75rem;
+    }
+    label {
+        -ms-flex: 1 0;
+            flex: 1 0;
+    }
+    /* label {*/
+    /*     display: -ms-flexbox;*/
+    /*     display: flex;*/
+    /*     -ms-flex-direction: column;*/
+    /*     flex-direction: column;*/
+    /*     width: 100%;*/
+    /*     margin: 0.5rem 0;*/
+    /*     -ms-flex-align: start;*/
+    /*     align-items: flex-start;*/
+    /*     -ms-flex-pack: start;*/
+    /*     justify-content: flex-start;*/
+    /* }*/
+    select {
+        font-size: 1rem;
+        min-width: 75%;
+        height: 35px;
+    }
+}
+
+
+
+
+.InputCollection {
+    display:-ms-flexbox;
+    display:flex;
+    -ms-flex-wrap: nowrap;
+        flex-wrap: nowrap;
+    -ms-flex-align: center;
+        align-items: center;
+    button {
+        padding: 0.25rem;
+        height: 1.5rem;
+        font-size: 0.75rem;
+    }
+    select {
+        min-width: 100%;
+    }
+    margin-bottom:0.5rem;
+    &-wrapper {
+
+    }
 }
diff --git a/skyquake/framework/widgets/form_controls/input.jsx b/skyquake/framework/widgets/form_controls/input.jsx
new file mode 100644 (file)
index 0000000..ca31c13
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ *
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+import './formControls.scss';
+import SelectOption from 'widgets/form_controls/selectOption.jsx';
+import CheckSVG from '../../../node_modules/open-iconic/svg/check.svg'
+import React, {Component} from 'react';
+
+export default class Input extends Component {
+    render() {
+        let {label, value, defaultValue, ...props} = this.props;
+        let inputProperties = {
+            value: value
+        }
+        let isRequired;
+        let inputType;
+        let tester = null;
+        let className = `sqTextInput ${props.className}`;
+
+        if(this.props.required) {
+           isRequired = <span className="required">*</span>
+        }
+        if (defaultValue) {
+            inputProperties.defaultValue = defaultValue;
+        }
+        if (props.pattern) {
+            inputProperties.pattern = props.pattern;
+            tester = new RegExp(props.pattern);
+        }
+        if(props.hasOwnProperty('type') && (props.type.toLowerCase() == 'checkbox')) {
+            inputProperties.checked = props.checked;
+            className = `${className} checkbox`;
+        }
+        if (value == undefined) {
+            value = defaultValue;
+        }
+        switch(props.type) {
+            case 'textarea':
+                inputType = <textarea key={props.key} {...inputProperties} value={value} onChange={props.onChange} />
+                break;
+            case 'select':
+                inputType = <SelectOption
+                                key={props.key}
+                                initial={props.initial}
+                                defaultValue={defaultValue}
+                                options={props.options}
+                                onChange={props.onChange}
+                            />
+                break;
+            case 'radiogroup':
+                inputType = buildRadioButtons(this.props);
+                break;
+            default:
+                inputType = <input key={props.key} type={props.type} {...inputProperties} onChange={props.onChange} placeholder={props.placeholder}/>;
+        }
+        let displayedValue;
+        if(value === null) {
+            displayedValue = null;
+        } else {
+            displayedValue = value.toString();
+        }
+        if( props.readonly && props.type == "checkbox" && props.checked ) {
+            displayedValue = <img src={CheckSVG} />
+        }
+
+        if( props.readonly && props.type == "radiogroup" && props.readonlydisplay ) {
+            displayedValue = props.readonlydisplay
+        }
+
+        let html = (
+            <label className={className} style={props.style}>
+              <span> { label } {isRequired}</span>
+              {
+                !props.readonly ? inputType : <div className="readonly">{displayedValue}</div>
+              }
+              {
+                 !props.readonly && tester && value && !tester.test(value) ? <span className="invalid">The Value you entered is invalid</span> : null
+              }
+            </label>
+        );
+        return html;
+    }
+}
+
+
+function buildRadioButtons(props) {
+    let className = 'sqCheckBox';
+    return(
+       <div className={className}>
+            {
+                props.options.map((o,i) => {
+                    let label = o.label || o;
+                    let value = o.value || o;
+                    return (
+                        <label key={i}>
+                            {label}
+                            <input type="radio" checked={props.value == value} value={value} onChange={props.onChange} />
+                        </label>
+                    )
+                })
+            }
+       </div>
+
+    )
+}
+
+Input.defaultProps = {
+    onChange: function(e) {
+        console.log(e.target.value, e);
+        console.dir(e.target);
+    },
+    label: '',
+    defaultValue: null,
+    type: 'text',
+    readonly: false,
+    style:{},
+    className: ''
+
+}
+
index 41a8b13..067d1d5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,32 +28,65 @@ export default class SelectOption extends React.Component {
   render() {
     let html;
     let defaultValue = this.props.defaultValue;
-    let options =  this.props.options.map(function(op, i) {
-      let value = JSON.stringify(op.value);
-      return <option key={i} value={JSON.stringify(op.value)}>{op.label}</option>
-    });
+    let options =  this.props.options && this.props.options.map(function(op, i) {
+    let value;
+    let label;
+    if(typeof(op) == 'object') {
+      value = JSON.stringify(op.value);
+      label = op.label;
+    } else {
+      value = op;
+      label = op;
+    }
+
+      return <option key={i} value={JSON.stringify(value)}>{label}</option>
+    }) || [];
     if (this.props.initial) {
       options.unshift(<option key='blank' value={JSON.stringify(this.props.defaultValue)}></option>);
     }
     html = (
-        <label>
-            {this.props.label}
-            <select className={this.props.className} onChange={this.handleOnChange} defaultValue={JSON.stringify(defaultValue)} >
-                {
-                 options
-                }
-            </select>
+        <label key={this.props.key} className={this.props.className}>
+            <span>{this.props.label}</span>
+            {
+              this.props.readonly ? defaultValue
+              : (
+                  <select
+                    className={this.props.className}
+                    onChange={this.handleOnChange}
+                    value={JSON.stringify(this.props.value)}
+                    defaultValue={JSON.stringify(defaultValue)}>
+                      {
+                       options
+                      }
+                  </select>
+                )
+            }
         </label>
     );
     return html;
   }
 }
 SelectOption.defaultProps = {
+  /**
+   * [options description]
+   * @type {Array} - Expects items to contain objects with the properties 'label' and 'value' which are both string types. Hint: JSON.stringify()
+   */
   options: [],
   onChange: function(e) {
+    console.log(e.target.value)
     console.dir(e)
   },
-  defaultValue: false,
+  readonly: false,
+  /**
+   *  Selected or default value
+​
+   * @type {[type]}
+   */
+  defaultValue: null,
+  /**
+   * True if first entry in dropdown should be blank
+   * @type {Boolean}
+   */
   initial: false,
   label: null
 }
index 03dfa9c..000dcf7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
 import './formControls.scss';
 
 import React, {Component} from 'react';
-
-export default class TextInput extends Component {
-    render() {
-        let {label, onChange, value, defaultValue, ...props} = this.props;
-        let inputProperties = {
-            value: value,
-            onChange: onChange
-        }
-        let isRequired;
-        let inputType;
-        if(this.props.required) {
-           isRequired = <span className="required">*</span>
-        }
-        if (defaultValue) {
-            inputProperties.defaultValue = defaultValue;
-        }
-        if (props.pattern) {
-            inputProperties.pattern = props.pattern;
-        }
-        if (value == undefined) {
-            value = defaultValue;
-        }
-        switch(props.type) {
-            case 'textarea':
-                inputType = <textarea {...inputProperties} value={value}/>
-
-                break;
-            default:
-                inputType = <input type={props.type} {...inputProperties} placeholder={props.placeholder}/>;
-        }
-        let html = (
-            <label className={"sqTextInput " + props.className} style={props.style}>
-              <span> { label } {isRequired}</span>
-              {
-                !props.readonly ? inputType : <div className="readonly">{value}</div>
-              }
-
-            </label>
-        );
-        return html;
+import Input from './input.jsx';
+class TextInput extends Input {
+    constructor(props) {
+        super(props);
+        console.warn('TextInput is deprecated. Use Input component instead')
     }
 }
-
-TextInput.defaultProps = {
-    onChange: function(e) {
-        console.log(e.target.value);
-    },
-    label: '',
-    defaultValue: undefined,
-    type: 'text',
-    readonly: false,
-    style:{}
-
-}
+export default TextInput;
 
index 5e1e717..6a2e56c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
  */
 
 header.header-app-component {
-    padding: 20px 0px;
+    padding: 10px 0px;
+    display:-ms-flexbox;
     display:flex;
-    flex-direction:column;
+    -ms-flex-direction:column;
+        flex-direction:column;
     .header-app-main {
+        display:-ms-flexbox;
         display:flex;
-        flex-direction:row;
-        justify-content:space-between;
-        align-items:center;
+        -ms-flex-direction:row;
+            flex-direction:row;
+        -ms-flex-pack:justify;
+            justify-content:space-between;
+        -ms-flex-align:center;
+            align-items:center;
     }
     h1 {
         /*background: url('../../style/img/header-logo.png') no-repeat;*/
@@ -39,15 +45,19 @@ header.header-app-component {
         font-size: 1.625rem;
         font-weight: 400;
         position:relative;
-        flex: 1 0 auto;
+        -ms-flex: 1 0 auto;
+            flex: 1 0 auto;
 
     }
     ul {
+            display:-ms-flexbox;
             display:flex;
         }
         li {
+            display:-ms-flexbox;
             display:flex;
-             flex:1 1 auto;
+             -ms-flex:1 1 auto;
+                 flex:1 1 auto;
              border-right:1px solid #e5e5e5;
              padding: 0 1rem;
             &:last-child {
@@ -55,12 +65,13 @@ header.header-app-component {
             }
             a {
                 cursor:pointer;
-                // padding: 0.125rem;
-                // border-bottom:1px solid black;
+                /* padding: 0.125rem;*/
+                /* border-bottom:1px solid black;*/
                 text-decoration:underline;
             }
         }
     .header-app-nav {
+        display:-ms-flexbox;
         display:flex;
         margin-left: 0.25rem;
         a,span {
@@ -81,8 +92,11 @@ header.header-app-component {
         }
     }
     nav {
+        display:-ms-flexbox;
         display:flex;
-        flex:0 1 auto;
-        align-items:center;
+        -ms-flex:0 1 auto;
+            flex:0 1 auto;
+        -ms-flex-align:center;
+            align-items:center;
     }
 }
index ba77a79..0e12b6e 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * 
+ *
  *   Copyright 2016 RIFT.IO Inc
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
@@ -101,7 +101,7 @@ class ThrottledMessage extends React.Component {
   }
   render() {
     if(!this.props.hasFailed) {
-      return (<span className='throttledMessageText'>{this.state.displayMessage}</span>)
+      return (<span className='throttledMessageText' style={{margin:'1rem'}}>{this.state.displayMessage}</span>)
     } else {
       return (<span> </span>)
     }
index 4ef7c89..03877b0 100644 (file)
@@ -18,6 +18,7 @@
 import React, {Component} from 'react';
 import 'style/core.css';
 import './panel.scss';
+import circleXImage from '../../../node_modules/open-iconic/svg/circle-x.svg';
 export class Panel extends Component {
     constructor(props) {
         super(props)
@@ -28,8 +29,15 @@ export class Panel extends Component {
         let classRoot = className ? ' ' + className : ' ';
         let hasCorners = this.props['no-corners'];
         let titleTag = title ? <header className="skyquakePanel-title">{title}</header> : '';
+        let closeButton = (
+            <a onClick={self.props.hasCloseButton}
+              className={"close-btn"}>
+              <img src={circleXImage} title="Close card" />
+              </a>
+        );
         return (
             <section className={'skyquakePanel' + classRoot} style={props.style}>
+                {  self.props.hasCloseButton ? closeButton : null}
                 { !hasCorners ? <i className="corner-accent top left"></i> : null }
                 { !hasCorners ? <i className="corner-accent top right"></i> : null }
                 {titleTag}
@@ -51,13 +59,23 @@ Panel.defaultProps = {
 
 export class PanelWrapper extends Component {
     render() {
+        let wrapperClass = 'skyquakePanelWrapper';
+        let {className, column, style, ...props} = this.props;
+        if(className) {
+            wrapperClass = `${wrapperClass} ${className}`
+        }
+        if(column) {
+            style.flexDirection = 'column';
+        }
         return (
-        <div className={'skyquakePanelWrapper ' + this.props.className} style={this.props.style}>
+        <div className={wrapperClass} style={style} {...props}>
             {this.props.children}
         </div>)
     }
 }
-
+PanelWrapper.defaultProps = {
+    style: {}
+}
 export default Panel;
 
 
index 2a31b1c..75dc8ac 100644 (file)
             width:100%;
             height:100%;
         }
+    .close-btn {
+        cursor:pointer;
+        position: absolute;
+        right: -0.5rem;
+        top: -0.5rem;
+        img {
+            width: 1rem;
+        }
+    }
 }
 
 .skyquakePanelWrapper.column {
+    -ms-flex-direction:column;
+            flex-direction:column;
+        display:-ms-flexbox;
+        display:flex;
     .skyquakePanel-wrapper {
         height:auto;
     }
index 7df4e3e..471efd1 100644 (file)
  *
  */
 
- /**
 * EventCenter module to display a list of events from the system
 * @module framework/widgets/skyquake_container/EventCenter
 * @author Kiran Kashalkar <kiran.kashalkar@riftio.com>
 *
 */
+/**
+ * EventCenter module to display a list of events from the system
+ * @module framework/widgets/skyquake_container/EventCenter
+ * @author Kiran Kashalkar <kiran.kashalkar@riftio.com>
+ *
+ */
 
 import React from 'react';
 import { Link } from 'react-router';
@@ -31,6 +31,8 @@ import TreeView from 'react-treeview';
 import _isEqual from 'lodash/isEqual';
 import _merge from 'lodash/merge';
 import _indexOf from 'lodash/indexOf';
+import _isArray from 'lodash/isArray';
+import _sortBy from 'lodash/sortBy';
 import '../../../node_modules/react-treeview/react-treeview.css';
 import './eventCenter.scss';
 
@@ -44,7