diff --git a/solidui/entity/core.py b/solidui/entity/core.py index ee52d11..49345f7 100644 --- a/solidui/entity/core.py +++ b/solidui/entity/core.py @@ -19,6 +19,7 @@ Base = declarative_base() + class DataSourceType(Base): __tablename__ = 'solidui_datasource_type' @@ -30,6 +31,7 @@ class DataSourceType(Base): icon = Column(String(255), nullable=False, default='') layers = Column(Integer, nullable=False) + class DataSource(Base): __tablename__ = 'solidui_datasource' @@ -46,6 +48,7 @@ class DataSource(Base): # datasource_type = relationship("DataSourceType") + class DataSourceTypeKey(Base): __tablename__ = 'solidui_datasource_type_key' @@ -66,6 +69,7 @@ class DataSourceTypeKey(Base): # datasource_type = relationship("DataSourceType") + class JobElement(Base): __tablename__ = 'solidui_job_element' @@ -78,31 +82,37 @@ class JobElement(Base): update_time = Column(DateTime, nullable=False) # project = relationship("Project") + + class JobElementPage(Base): __tablename__ = 'solidui_job_element_page' id = Column(Integer, primary_key=True) job_page_id = Column(Integer, nullable=False) - job_element_id = Column(Integer, nullable=False) + job_element_id = Column(Integer, nullable=False) position = Column(String(255), nullable=False, default='') create_time = Column(DateTime, nullable=False) update_time = Column(DateTime, nullable=False) # job_page = relationship("JobPage") # job_element = relationship("JobElement") + + class JobPage(Base): __tablename__ = 'solidui_job_page' id = Column(Integer, primary_key=True) project_id = Column(Integer, nullable=False) name = Column(String(255), nullable=False, default='') - parent_id = Column(Integer) + parent_id = Column(Integer, default=0) layout = Column(Integer, nullable=False) orders = Column(Integer, nullable=False) create_time = Column(DateTime, nullable=False) update_time = Column(DateTime, nullable=False) # project = relationship("Project") + + class Project(Base): __tablename__ = 'solidui_project' @@ -130,6 +140,7 @@ class User(Base): def json_data(self) -> str: return json.dumps(self.data) + class ModelType(Base): __tablename__ = 'solidui_model_type' diff --git a/solidui/initialization/__init__.py b/solidui/initialization/__init__.py index f39510e..e3a2e65 100644 --- a/solidui/initialization/__init__.py +++ b/solidui/initialization/__init__.py @@ -139,7 +139,7 @@ def log_default_secret_key_warning() -> None: bottom_banner = 80 * "-" + "\n" + 80 * "-" logger.warning(top_banner) logger.warning( - "A Default SECRET_KEY was detected, please use superset_config.py " + "A Default SECRET_KEY was detected, please use solidui_config.py " "to override it.\n" "Use a strong complex alphanumeric string and use a tool to help" " you generate \n" diff --git a/solidui/stats_logger.py b/solidui/stats_logger.py index fc223f7..da4ca9a 100644 --- a/solidui/stats_logger.py +++ b/solidui/stats_logger.py @@ -25,7 +25,7 @@ class BaseStatsLogger: """Base class for logging realtime events""" - def __init__(self, prefix: str = "superset") -> None: + def __init__(self, prefix: str = "solidui") -> None: self.prefix = prefix def key(self, key: str) -> str: @@ -79,7 +79,7 @@ def __init__( # pylint: disable=super-init-not-called self, host: str = "localhost", port: int = 8125, - prefix: str = "superset", + prefix: str = "solidui", statsd_client: Optional[StatsClient] = None, ) -> None: """ diff --git a/solidui/utils/logging_configurator.py b/solidui/utils/logging_configurator.py index 51a222b..9d15e4a 100644 --- a/solidui/utils/logging_configurator.py +++ b/solidui/utils/logging_configurator.py @@ -41,14 +41,14 @@ def configure_logging( if app_config["SILENCE_FAB"]: logging.getLogger("flask_appbuilder").setLevel(logging.ERROR) - # configure superset app logger - superset_logger = logging.getLogger("solidui") + # configure solidui app logger + solidui_logger = logging.getLogger("solidui") if debug_mode: - superset_logger.setLevel(logging.DEBUG) + solidui_logger.setLevel(logging.DEBUG) else: # In production mode, add log handler to sys.stderr. - superset_logger.addHandler(logging.StreamHandler()) - superset_logger.setLevel(logging.INFO) + solidui_logger.addHandler(logging.StreamHandler()) + solidui_logger.setLevel(logging.INFO) logging.basicConfig(format=app_config["LOG_FORMAT"]) logging.getLogger().setLevel(app_config["LOG_LEVEL"]) diff --git a/solidui/views/base_schemas.py b/solidui/views/base_schemas.py index 799fa1b..ded69f1 100644 --- a/solidui/views/base_schemas.py +++ b/solidui/views/base_schemas.py @@ -17,6 +17,9 @@ from typing import Optional, Dict, List +from marshmallow_sqlalchemy.schema import Schema +from marshmallow_sqlalchemy.fields import fields + @dataclass class Position: top: str = None @@ -84,8 +87,9 @@ class JobElementPageVO: class JobPageDTO: - def __init__(self, id: int, project_id: int, name: str, parent_id: int, layout: int, - create_time: datetime, update_time: datetime, orders: int, children: List['JobPageDTO']): + def __init__(self, id: int = None, project_id: int = None, name: str = None, parent_id: int = 0, layout: int = None, + create_time: datetime = None, update_time: datetime = None, orders: int = None, + children: List['JobPageDTO'] = None): self.id = id self.project_id = project_id self.name = name @@ -112,4 +116,17 @@ def append(self, string): def get_string(self): result = ''.join(self.data) - return result[-self.maxlen:] \ No newline at end of file + return result[-self.maxlen:] + + +class JobPageDTOSchema(Schema): + id = fields.Int() + project_id = fields.Int() + name = fields.Str() + parent_id = fields.Int() + layout = fields.Int() + create_time = fields.DateTime() + update_time = fields.DateTime() + orders = fields.Int() + # Use a Nested field for children, with many=True to indicate it's a list + children = fields.Nested('self', many=True, exclude=('children',)) diff --git a/solidui/views/job/schemas.py b/solidui/views/job/schemas.py index 6aaae47..a9190ad 100644 --- a/solidui/views/job/schemas.py +++ b/solidui/views/job/schemas.py @@ -11,5 +11,5 @@ # 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. -from typing import Dict, Any + diff --git a/solidui/views/job_page/api.py b/solidui/views/job_page/api.py index 5bd759f..c41c1b3 100644 --- a/solidui/views/job_page/api.py +++ b/solidui/views/job_page/api.py @@ -28,6 +28,9 @@ from solidui.views.base_api import BaseSolidUIApi from flask_appbuilder.api import expose, safe +from solidui.views.base_schemas import JobPageDTOSchema +from solidui.views.job_page.schemas import JobPageVO, JobPageSchema + logger = logging.getLogger(__name__) @@ -39,7 +42,15 @@ class JobPageRestApi(BaseSolidUIApi): def create_job_page(self) -> FlaskResponse: # Extract data from request job_page_data = request.json - job_page = JobPage(**job_page_data) + job_page_vo = JobPageVO(**job_page_data) + + job_page = JobPage( + project_id=job_page_vo.projectId, + name=job_page_vo.name, + parent_id=job_page_vo.parentId, + layout=job_page_vo.layout, + orders=job_page_vo.orders + ) # Check if page name already exists existing_job_page = JobPageDAO.get_job_name(job_page.name, job_page.project_id) @@ -62,7 +73,8 @@ def create_job_page(self) -> FlaskResponse: # Insert job page try: JobPageDAO.create(item=job_page) - return self.response_format(data=job_page) + job_page_schema = JobPageSchema() + return self.response_format(data=job_page_schema.dump(job_page)) except DAOCreateFailedError as ex: logger.exception(ex) return self.handle_error(SolidUIErrorType.CREATE_JOB_PAGE_ERROR) @@ -74,15 +86,23 @@ def update_job_page(self, pk) -> FlaskResponse: update job page """ job_page_data = request.json - job_page = JobPage(**job_page_data) + job_page_vo = JobPageVO(**job_page_data) + + job_page = JobPage( + project_id=job_page_vo.projectId, + name=job_page_vo.name, + parent_id=job_page_vo.parentId, + layout=job_page_vo.layout, + orders=job_page_vo.orders + ) job_page.id = pk new_job_page = JobPageDAO.find_by_id(pk) - if new_job_page: + if not new_job_page: return self.handle_error(SolidUIErrorType.QUERY_JOB_PAGE_ERROR) - new_job_page.update_time = datetime.now() + job_page.update_time = datetime.now() try: - JobPageDAO.update(new_job_page) + JobPageDAO.update(job_page) except DAOCreateFailedError as ex: logger.exception(ex) return self.handle_error(SolidUIErrorType.UPDATE_JOB_PAGE_ERROR) @@ -111,7 +131,7 @@ def delete_job_page(self, pk) -> FlaskResponse: logger.exception(ex) return self.handle_error(SolidUIErrorType.DELETE_JOB_PAGE_ERROR) - @expose('/query/', methods=('GET',)) + @expose('/queryList/', methods=('GET',)) @safe def get_job_pages(self, project_id) -> FlaskResponse: """ @@ -124,7 +144,7 @@ def get_job_pages(self, project_id) -> FlaskResponse: # Convert JobPage to JobPageDTO and sort job_page_dtos = [convert_to_dto(job_page) for job_page in job_pages] - sorted_job_page_dtos = sorted(job_page_dtos, key=lambda x: (x.parent_id, x.orders)) + sorted_job_page_dtos = sorted(job_page_dtos, key=lambda x: (x.parent_id or 0, x.orders or 0)) # Group and nest job pages top_level_job_pages = [dto for dto in sorted_job_page_dtos if dto.layout == 1] @@ -133,4 +153,5 @@ def get_job_pages(self, project_id) -> FlaskResponse: for top_level in top_level_job_pages: top_level.children = [dto for dto in second_level_job_pages if dto.parent_id == top_level.id] - return self.response_format(data=top_level_job_pages) + schema = JobPageDTOSchema() + return self.response_format(data=schema.dump(top_level_job_pages, many=True)) diff --git a/solidui/views/job_page/schemas.py b/solidui/views/job_page/schemas.py new file mode 100644 index 0000000..49b96e1 --- /dev/null +++ b/solidui/views/job_page/schemas.py @@ -0,0 +1,32 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +from marshmallow_sqlalchemy import SQLAlchemyAutoSchema + +from solidui.entity.core import JobPage + + +class JobPageVO: + def __init__(self, id=None, projectId=None, name=None, parentId=None, layout=None, orders=None): + self.id = id + self.projectId = projectId + self.name = name + self.parentId = parentId + self.layout = layout + self.orders = orders + + +class JobPageSchema(SQLAlchemyAutoSchema): + class Meta: + model = JobPage + load_instance = True # Optional: if you also want to use it for deserialization