Skip to content

Commit

Permalink
Merge pull request #189 from cloudblue/allow_web_for_hubs_plus_fixes
Browse files Browse the repository at this point in the history
Allow web app for hub ext; other fixes
  • Loading branch information
ffaraone authored Nov 24, 2022
2 parents fd7bffe + 44f10d8 commit e9b0b80
Show file tree
Hide file tree
Showing 17 changed files with 355 additions and 302 deletions.
8 changes: 4 additions & 4 deletions connect/cli/plugins/project/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def __init__(self, *args, **kwargs):
assert self.conflict_with, "'conflict_with' parameter required"

help_str = kwargs.get("help", "")
help_str += f' Option is mutually exclusive with {", ".join(self.conflict_with)}.'
help_str += f' This option is mutually exclusive with {", ".join(self.conflict_with)}.'
kwargs["help"] = help_str.strip()
super(Mutex, self).__init__(*args, **kwargs)

Expand All @@ -35,7 +35,7 @@ def handle_parse_result(self, ctx, opts, args):
if mutex_opt in opts:
if current_opt:
raise click.UsageError(
f'Illegal usage: {self.name} is mutually exclusive with {mutex_opt}.',
f'Illegal usage: options {self.name} and {mutex_opt} are mutually exclusive.',
)
else:
self.prompt = None
Expand Down Expand Up @@ -141,7 +141,7 @@ def grp_project_extension():
default=None,
type=click.Path(exists=False, file_okay=True, dir_okay=False),
required=False,
help='Directory or file where to entered save answers as json file.',
help='Path to JSON file where to save wizard answers.',
cls=Mutex,
conflict_with=['load_answers'],
)
Expand All @@ -150,7 +150,7 @@ def grp_project_extension():
default=None,
type=click.Path(exists=True, file_okay=True, dir_okay=False),
required=False,
help='Json file to load answers from.',
help='Path to JSON file from where load wizard answers.',
cls=Mutex,
conflict_with=['save_answers'],
)
Expand Down
6 changes: 4 additions & 2 deletions connect/cli/plugins/project/extension/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def bootstrap_extension_project( # noqa: CCR001
console.secho('Bootstraping extension project...\n', fg='blue')

if save_answers and os.path.exists(save_answers):
raise ClickException(f'Answers can not be saved, because {save_answers} already exists.')
raise ClickException(f'Answers cannot be saved, because {save_answers} already exists.')

statuses_by_event = collections.defaultdict(lambda: collections.defaultdict())

Expand Down Expand Up @@ -82,8 +82,10 @@ def bootstrap_extension_project( # noqa: CCR001

if save_answers:
with open(save_answers, 'w') as fp:
json.dump(answers, fp)
json.dump(answers, fp, indent=2)
console.echo()
console.secho(f'Answers saved to {save_answers}', fg='green')
console.echo()

exclude = []

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
from typing import List, Optional
# -*- coding: utf-8 -*-
#
# Copyright (c) {% now 'utc', '%Y' %}, {{ author }}
# All rights reserved.
#
from typing import {% if extension_type == 'multiaccount' %}List, {% endif %}Optional

from pydantic import BaseModel, validator

Expand All @@ -11,11 +16,9 @@ class Marketplace(BaseModel):

@validator('icon')
def set_icon(cls, icon):
return icon or (
'https://unpkg.com/@cloudblueconnect'
'/material-svg@latest/icons/google/language/baseline.svg'
)

return icon or '/static/images/mkp.svg'

{% if extension_type == 'multiaccount' %}
class Settings(BaseModel):
marketplaces: List[Marketplace] = []
{% endif -%}
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,36 @@
#
from typing import List

from connect.client import {% if use_asyncio == 'y' %}Async{% endif %}ConnectClient, R
from connect.client import {% if use_asyncio == 'y' %}Async{% endif %}ConnectClient{% if extension_type == 'multiaccount' %}, R{% endif %}
from connect.eaas.core.decorators import (
{%- if webapp_supports_ui == 'y' %}
account_settings_page,
module_pages,
{%- endif %}
router,
{%- if include_variables_example == 'y' %}
variables,
{%- endif %}
web_app,
)
from connect.eaas.core.extension import WebApplicationBase
{%- if use_asyncio == 'y' %}
{%- if use_asyncio == 'y' and extension_type == 'multiaccount' %}
from connect.eaas.core.inject.asynchronous import get_installation, get_installation_client
{%- elif use_asyncio == 'y' and extension_type != 'multiaccount' %}
from connect.eaas.core.inject.asynchronous import get_extension_client
{%- endif %}
{%- if extension_type == 'multiaccount' %}
from connect.eaas.core.inject.common import get_call_context
from connect.eaas.core.inject.models import Context
{%- if use_asyncio != 'y' %}
{%- endif %}
{%- if use_asyncio != 'y' and extension_type == 'multiaccount' %}
from connect.eaas.core.inject.synchronous import get_installation, get_installation_client
{%- elif use_asyncio != 'y' and extension_type != 'multiaccount' %}
from connect.eaas.core.inject.synchronous import get_extension_client
{%- endif %}
from fastapi import Depends

from {{ package_name }}.schemas import Marketplace, Settings
from {{ package_name }}.schemas import Marketplace{% if extension_type == 'multiaccount' %}, Settings{% endif %}


{% if include_variables_example == 'y' -%}
Expand All @@ -50,6 +58,23 @@ from {{ package_name }}.schemas import Marketplace, Settings
{% endif -%}
class {{ project_slug|replace("_", " ")|title|replace(" ", "") }}WebApplication(WebApplicationBase):

@router.get(
'/marketplaces',
summary='List all available marketplaces',
response_model=List[Marketplace],
)
{% if use_asyncio == 'y' %}async {% endif %}def list_marketplaces(
self,
client: {% if use_asyncio == 'y' %}Async{% endif %}ConnectClient = Depends(get_{% if extension_type == 'multiaccount' %}installation{% else %}extension{% endif %}_client),
):
return [
Marketplace(**marketplace)
{% if use_asyncio == 'y' %}async {% endif %}for marketplace in client.marketplaces.all().values_list(
'id', 'name', 'description', 'icon',
)
]

{% if extension_type == 'multiaccount' -%}
@router.get(
'/settings',
summary='Retrive charts settings',
Expand Down Expand Up @@ -79,22 +104,6 @@ class {{ project_slug|replace("_", " ")|title|replace(" ", "") }}WebApplication(
)
return settings

@router.get(
'/marketplaces',
summary='List all available marketplaces',
response_model=List[Marketplace],
)
{% if use_asyncio == 'y' %}async {% endif %}def list_marketplaces(
self,
client: {% if use_asyncio == 'y' %}Async{% endif %}ConnectClient = Depends(get_installation_client),
):
return [
Marketplace(**marketplace)
{% if use_asyncio == 'y' %}async {% endif %}for marketplace in client.marketplaces.all().values_list(
'id', 'name', 'description', 'icon',
)
]

@router.get(
'/chart',
summary='Generate chart data',
Expand Down Expand Up @@ -123,3 +132,4 @@ class {{ project_slug|replace("_", " ")|title|replace(" ", "") }}WebApplication(
],
},
}
{% endif %}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"mini-css-extract-plugin": "^2.6.1",
"style-loader": "^3.3.1",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
"webpack-cli": "^4.10.0",
"copy-webpack-plugin": "^11.0.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ readme = "./README.md"

[tool.poetry.dependencies]
python = ">=3.8,<4"
connect-eaas-core = ">=26.10,<27"
connect-eaas-core = ">=26.13,<27"
[tool.poetry.dev-dependencies]
pytest = ">=6.1.2,<8"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,66 @@
# Copyright (c) {% now 'utc', '%Y' %}, {{ author }}
# All rights reserved.
#
{% if extension_type == 'multiaccount' -%}
from connect.client import R

from {{ package_name }}.schemas import Marketplace, Settings
{% endif -%}
from {{ package_name }}.webapp import {{ project_slug|replace("_", " ")|title|replace(" ", "") }}WebApplication


def test_list_marketplaces(test_client_factory, {% if use_asyncio == 'y' %}async_{% endif %}client_mocker_factory):
marketplaces = [
{
'id': 'MP-000',
'name': 'MP 000',
'description': 'MP 000 description',
'icon': 'mp_000.png',
},
{
'id': 'MP-001',
'name': 'MP 001',
'description': 'MP 001 description',
'icon': 'mp_001.png',
},
]
client_mocker = {% if use_asyncio == 'y' %}async_{% endif %}client_mocker_factory()

client_mocker.marketplaces.all().mock(return_value=marketplaces)

client = test_client_factory({{ project_slug|replace("_", " ")|title|replace(" ", "") }}WebApplication)
response = client.get('/api/marketplaces')

assert response.status_code == 200

data = response.json()

assert data == marketplaces


def test_list_marketplaces_api_error(test_client_factory, {% if use_asyncio == 'y' %}async_{% endif %}client_mocker_factory):
client_mocker = {% if use_asyncio == 'y' %}async_{% endif %}client_mocker_factory()

error_data = {
'error_code': 'AUTH_001',
'errors': [
'API request is unauthorized.',
],
}

client_mocker.marketplaces.all().mock(
status_code=401,
return_value=error_data,
)

client = test_client_factory({{ project_slug|replace("_", " ")|title|replace(" ", "") }}WebApplication)
response = client.get('/api/marketplaces')

assert response.status_code == 401
assert response.json() == error_data


{% if extension_type == 'multiaccount' -%}
def test_retrieve_settings_empty(test_client_factory):
installation = {
'id': 'EIN-000',
Expand Down Expand Up @@ -68,64 +122,17 @@ def test_save_settings(test_client_factory, {% if use_asyncio == 'y' %}async_{%

client = test_client_factory({{ project_slug|replace("_", " ")|title|replace(" ", "") }}WebApplication)

response = client.post('/api/settings', json=settings.dict())
response = client.post(
'/api/settings',
json=settings.dict(),
context={'installation_id': 'EIN-000'},
)
assert response.status_code == 200

data = response.json()
assert data == settings.dict()


def test_list_marketplaces(test_client_factory, {% if use_asyncio == 'y' %}async_{% endif %}client_mocker_factory):
marketplaces = [
{
'id': 'MP-000',
'name': 'MP 000',
'description': 'MP 000 description',
'icon': 'mp_000.png',
},
{
'id': 'MP-001',
'name': 'MP 001',
'description': 'MP 001 description',
'icon': 'mp_001.png',
},
]
client_mocker = {% if use_asyncio == 'y' %}async_{% endif %}client_mocker_factory()

client_mocker.marketplaces.all().mock(return_value=marketplaces)

client = test_client_factory({{ project_slug|replace("_", " ")|title|replace(" ", "") }}WebApplication)
response = client.get('/api/marketplaces')

assert response.status_code == 200

data = response.json()

assert data == marketplaces


def test_list_marketplaces_api_error(test_client_factory, {% if use_asyncio == 'y' %}async_{% endif %}client_mocker_factory):
client_mocker = {% if use_asyncio == 'y' %}async_{% endif %}client_mocker_factory()

error_data = {
'error_code': 'AUTH_001',
'errors': [
'API request is unauthorized.',
],
}

client_mocker.marketplaces.all().mock(
status_code=401,
return_value=error_data,
)

client = test_client_factory({{ project_slug|replace("_", " ")|title|replace(" ", "") }}WebApplication)
response = client.get('/api/marketplaces')

assert response.status_code == 401
assert response.json() == error_data


def test_generate_chart_data(test_client_factory, {% if use_asyncio == 'y' %}async_{% endif %}client_mocker_factory):
marketplaces = [
{
Expand Down Expand Up @@ -172,3 +179,4 @@ def test_generate_chart_data(test_client_factory, {% if use_asyncio == 'y' %}asy
],
},
}
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm6.93 6h-2.95c-.32-1.25-.78-2.45-1.38-3.56 1.84.63 3.37 1.91 4.33 3.56zM12 4.04c.83 1.2 1.48 2.53 1.91 3.96h-3.82c.43-1.43 1.08-2.76 1.91-3.96zM4.26 14C4.1 13.36 4 12.69 4 12s.1-1.36.26-2h3.38c-.08.66-.14 1.32-.14 2 0 .68.06 1.34.14 2H4.26zm.82 2h2.95c.32 1.25.78 2.45 1.38 3.56-1.84-.63-3.37-1.9-4.33-3.56zm2.95-8H5.08c.96-1.66 2.49-2.93 4.33-3.56C8.81 5.55 8.35 6.75 8.03 8zM12 19.96c-.83-1.2-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.76-1.91 3.96zM14.34 14H9.66c-.09-.66-.16-1.32-.16-2 0-.68.07-1.35.16-2h4.68c.09.65.16 1.32.16 2 0 .68-.07 1.34-.16 2zm.25 5.56c.6-1.11 1.06-2.31 1.38-3.56h2.95c-.96 1.65-2.49 2.93-4.33 3.56zM16.36 14c.08-.66.14-1.32.14-2 0-.68-.06-1.34-.14-2h3.38c.16.64.26 1.31.26 2s-.1 1.36-.26 2h-3.38z"/></svg>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const htmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const ESLintPlugin = require('eslint-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

const generateHtmlPlugin = (title) => {
const moduleName = title.toLowerCase();
Expand Down Expand Up @@ -56,6 +57,11 @@ module.exports = {
},
plugins: [
...pages,
new CopyWebpackPlugin({
patterns: [
{ from: __dirname + "/ui/images", to: "images" },
],
}),
new MiniCssExtractPlugin({
filename: "index.css",
chunkFilename: "[id].css",
Expand Down
Loading

0 comments on commit e9b0b80

Please sign in to comment.