From c77c7aa11e9fed512569f4127a4ffa8c9c0878c9 Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Tue, 12 Mar 2024 00:02:11 +0200 Subject: [PATCH] chore: migration for ckan v2.8 --- README.md | 3 ++ ckanext/files/command.py | 75 +++++++++++++++++++++++++++++++++++ ckanext/files/logic/action.py | 4 +- ckanext/files/model/file.py | 8 ++-- ckanext/files/model/owner.py | 2 + ckanext/files/views.py | 8 ++-- pyproject.toml | 5 ++- setup.cfg | 5 +++ 8 files changed, 101 insertions(+), 9 deletions(-) create mode 100644 ckanext/files/command.py diff --git a/README.md b/README.md index 77da124..bd43c92 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ Compatibility with core CKAN versions: | 2.9 | yes | | master | yes | + +alembic==1.4 + ## Installation To install ckanext-files: diff --git a/ckanext/files/command.py b/ckanext/files/command.py new file mode 100644 index 0000000..22ad153 --- /dev/null +++ b/ckanext/files/command.py @@ -0,0 +1,75 @@ +from __future__ import print_function + +import logging + +import paste.script + +from ckan import model +from ckan.lib.cli import CkanCommand + +from ckanext.files.model.base import metadata + +log = logging.getLogger(__name__) + + +def drop_tables(): + """Drop tables defined in model.""" + metadata.drop_all(model.meta.engine) + + +def create_tables(): + """Create tables defined in model.""" + metadata.create_all(model.meta.engine) + + +class FilesCommand(CkanCommand): + """ + ckanext-files management commands. + + Usage:: + paster --plugin=ckanext-files files -c ckan.ini initdb + paster --plugin=ckanext-files files -c ckan.ini dropdb + """ + + summary = __doc__.split("\n")[0] + usage = __doc__ + + parser = paste.script.command.Command.standard_parser(verbose=True) + parser.add_option( + "-c", + "--config", + dest="config", + default="ckan.ini", + help="Config file to use.", + ) + + def command(self): + """Command itself.""" + self._load_config() + + if not len(self.args): + print(self.usage) # noqa + + elif self.args[0] == "initdb": + self._init() + elif self.args[0] == "dropdb": + self._drop() + elif self.args[0] == "createdb": + self._create() + + def _init(self): + self._drop() + self._create() + log.info("DB tables are reinitialized") + + def _drop(self): + model.Session.rollback() + + drop_tables() + log.info("DB tables are removed") + + def _create(self): + model.Session.rollback() + + create_tables() + log.info("DB tables are setup") diff --git a/ckanext/files/logic/action.py b/ckanext/files/logic/action.py index c23199a..073a1f7 100644 --- a/ckanext/files/logic/action.py +++ b/ckanext/files/logic/action.py @@ -43,7 +43,9 @@ def files_file_search_by_user(context, data_dict): total = sess.scalar(sa.select(sa.func.count()).select_from(stmt)) - sort, *sort_path = data_dict["sort"].split(".") + parts = data_dict["sort"].split(".") + sort = parts[0] + sort_path = parts[1:] inspector = sa.inspect(File) # type: types.Any columns = inspector.columns diff --git a/ckanext/files/model/file.py b/ckanext/files/model/file.py index eb2160f..9c9a617 100644 --- a/ckanext/files/model/file.py +++ b/ckanext/files/model/file.py @@ -22,13 +22,13 @@ class File(Base): # type: ignore name = Column(UnicodeText, nullable=False) storage = Column(UnicodeText, nullable=False) - ctime = Column(DateTime, nullable=False, default=now) + ctime = Column(DateTime, nullable=False, default=now, server_default=sa.func.now()) mtime = Column(DateTime) atime = Column(DateTime) - storage_data = Column(JSONB, default=dict) - plugin_data = Column(JSONB, default=dict) - completed = Column(sa.Boolean, default=False) + storage_data = Column(JSONB, default=dict, server_default="{}") + plugin_data = Column(JSONB, default=dict, server_default="{}") + completed = Column(sa.Boolean, default=False, server_default="false") def __init__(self, **kwargs): # type: (**types.Any) -> None diff --git a/ckanext/files/model/owner.py b/ckanext/files/model/owner.py index 4568e9d..16d9062 100644 --- a/ckanext/files/model/owner.py +++ b/ckanext/files/model/owner.py @@ -21,6 +21,8 @@ class Owner(Base): # type: ignore owner_id = sa.Column(sa.Text, nullable=False) owner_type = sa.Column(sa.Text, nullable=False) + sa.UniqueConstraint(item_id, item_type, owner_id, owner_type) + def dictize(self, context): # type: (Any) -> dict[str, Any] return table_dictize(self, context) diff --git a/ckanext/files/views.py b/ckanext/files/views.py index 9a9f9d2..1cac939 100644 --- a/ckanext/files/views.py +++ b/ckanext/files/views.py @@ -13,14 +13,15 @@ bp = Blueprint("files", __name__) -def not_found_handler(error: tk.ObjectNotFound): +def not_found_handler(error): + # type: (tk.ObjectNotFound) -> tuple[str, int] """Generic handler for ObjectNotFound exception""" return ( tk.render( "error_document_template.html", { "code": 404, - "content": f"Object not found: {error.message}", + "content": "Object not found: {}".format(error.message), "name": "Not found", }, ), @@ -28,7 +29,8 @@ def not_found_handler(error: tk.ObjectNotFound): ) -def not_authorized_handler(error: tk.NotAuthorized): +def not_authorized_handler(error): + # type: (tk.NotAuthorized) -> tuple[str, int] """Generic handler for NotAuthorized exception""" return ( tk.render( diff --git a/pyproject.toml b/pyproject.toml index bb1bc6c..6ec44cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,6 +4,7 @@ [tool.ruff] target-version = "py38" +[tool.ruff.lint] select = [ "B", # likely bugs and design problems # "BLE", # do not catch blind exception @@ -29,15 +30,17 @@ select = [ # "TRY", # better exceptions # "UP", # upgrade syntax for newer versions of the language ] + ignore = [ "E712", # comparison to bool: violated by SQLAlchemy filters "PT004", # fixture does not return anything, add leading underscore: violated by clean_db "PLC1901", # simplify comparison to empty string: violated by SQLAlchemy filters ] -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "ckanext/files/tests*" = ["S", "PL"] + [tool.isort] known_ckan = "ckan" known_ckanext = "ckanext" diff --git a/setup.cfg b/setup.cfg index b8121fa..d4f92de 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,6 +25,7 @@ keywords = install_requires = six typing_extensions; python_version >= "3.6" + packages = find: namespace_packages = ckanext include_package_data = True @@ -48,6 +49,10 @@ ckan.plugins = file_manager = ckanext.file_manager.plugin:FileManagerPlugin babel.extractors = ckan = ckan.lib.extract:extract_ckan + +paste.paster_command = + files = ckanext.files.command:FilesCommand + [extract_messages] keywords = translate isPlural add_comments = TRANSLATORS: