diff --git a/CMakeLists.txt b/CMakeLists.txt index ca7f81a..5238465 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ set(Sqlpp11_DIR "${CMAKE_BINARY_DIR}/local/lib/cmake/Sqlpp11") set(wt_DIR "${CMAKE_BINARY_DIR}/local/lib/cmake/wt") set(Sqlpp-connector-postgresql_DIR "${CMAKE_BINARY_DIR}/local/lib/cmake/sqlpp-connector-postgresql") + find_program( CLANG_TIDY_EXE NAMES "clang-tidy-5.0" diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 0c454be..ee1c4f6 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -8,4 +8,5 @@ target_link_libraries(eedb PRIVATE webapp PRIVATE postgres_connector PRIVATE dl + PRIVATE chaiscript_bindings ) diff --git a/src/app/main.cpp b/src/app/main.cpp index 49e7817..98224e8 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -10,6 +10,9 @@ #include +#include +#include + static auto _createSinks() { std::vector< spdlog::sink_ptr > sinks; auto stdout_sink = spdlog::sinks::stdout_sink_mt::instance(); @@ -48,9 +51,23 @@ std::unique_ptr< Wt::WApplication > createApplication(const Wt::WEnvironment & e }); auto factory = std::make_unique< eedb::pg::FactoryImpl >(std::move(connection)); - factory->init(); + chaiscript::ChaiScript chai; + auto module = std::make_shared< chaiscript::Module >(); + + eedb::script::chai_bootstrap(*module); + chai.add(module); + + chai.add_global(chaiscript::var(static_cast< eedb::Factory * >(factory.get())), "factory"); + chai.add(chaiscript::fun([](std::string_view str) { return std::string{str}; }), "toStdString"); + + try { + chai.eval_file("/home/wieczbar/chai_test.chai"); + } catch(chaiscript::exception::eval_error e) { + std::cout << e.pretty_print(); + } + return eedb::WebApplicationFactory{}.create(std::move(factory), env); } diff --git a/src/libs/CMakeLists.txt b/src/libs/CMakeLists.txt index b5a9f0c..ac02c5d 100644 --- a/src/libs/CMakeLists.txt +++ b/src/libs/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.9) add_subdirectory(eedb) +add_subdirectory(chaiscript_bindings) + add_subdirectory(db) add_subdirectory(auth) diff --git a/src/libs/chaiscript_bindings/CMakeLists.txt b/src/libs/chaiscript_bindings/CMakeLists.txt new file mode 100644 index 0000000..5a90a2b --- /dev/null +++ b/src/libs/chaiscript_bindings/CMakeLists.txt @@ -0,0 +1,24 @@ +set(LIB chaiscript_bindings) + +#set(chaiscript_DIR "${CMAKE_BINARY_DIR}/local/lib") + +find_package(PkgConfig) +set(${PKG_CONFIG_USE_CMAKE_PREFIX_PATH} ON) + +# find packages +pkg_check_modules(chaiscript REQUIRED) + +# create library +add_library(${LIB} src/chai_bindings.cpp ) + +# link all +target_include_directories(${LIB} + PUBLIC include +) + +target_link_libraries(${LIB} + PUBLIC eedb_api + PRIVATE Boost::system + PRIVATE Boost::filesystem +) + diff --git a/src/libs/chaiscript_bindings/include/eedb/chai/chai_bindings.hpp b/src/libs/chaiscript_bindings/include/eedb/chai/chai_bindings.hpp new file mode 100644 index 0000000..ff33214 --- /dev/null +++ b/src/libs/chaiscript_bindings/include/eedb/chai/chai_bindings.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace eedb::script { + +void chai_bootstrap(chaiscript::Module & module); +} diff --git a/src/libs/chaiscript_bindings/src/chai_bindings.cpp b/src/libs/chaiscript_bindings/src/chai_bindings.cpp new file mode 100644 index 0000000..cb05846 --- /dev/null +++ b/src/libs/chaiscript_bindings/src/chai_bindings.cpp @@ -0,0 +1,81 @@ +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +void eedb::script::chai_bootstrap(chaiscript::Module & module) { + using namespace chaiscript; + + chaiscript::bootstrap::standard_library::string_type< std::string >("string", module); + + /******************* + * CATEGORY + *******************/ + + module.add(user_type< CategoriesRepository >(), "CategoriesRepository"); + module.add(fun(&CategoriesRepository::create), "create"); + module.add(fun(&CategoriesRepository::root), "root"); + + module.add(user_type< exceptions::CategoryAddException >(), "CategoryAddException"); + // module.add(constructor< exceptions::CategoryAddException(std::unique_ptr< Category >) >(), "CategoryAddException"); + module.add(fun(&exceptions::CategoryAddException::what), "what"); + + chaiscript::utility::add_class< Category >(module, + "Category", + {}, + {// + {fun(&Category::addChild), "addChild"}, + {fun(&Category::attachTo), "attachTo"}, + {fun(&Category::children), "children"}, + {fun(&Category::detach), "detach"}, + {fun(&Category::displayName), "displayName"}, + {fun(&Category::parent), "parent"}}); + + + module.add(user_type< CategoriesChildren >(), "CategoriesChildren"); + bootstrap::standard_library::input_range_type< CategoriesChildren >("CategoriesChildren", module); + + /******************* + * USER + *******************/ + + chaiscript::utility::add_class< User >(module, + "User", + {}, + {// + {fun(&User::authIdentities), "authIdentities"}, + {fun(&User::authInfo), "authInfo"}, + {fun(&User::authTokens), "authTokens"}, + {fun(&User::config), "config"}}); + + chaiscript::utility::add_class< AuthIdentities >(module, + "AuthIdentities", + {}, + {// + {fun(&AuthIdentities::removeProvider), "removeProvider"}}); + + /******************** + * FACTORY + ********************/ + + chaiscript::utility::add_class< Factory >(module, + "Factory", + {}, + {// + {fun(&Factory::categoriesRepository), "categoriesRepository"}}); + + // module.add(fun(&Factory::itemsRepository), "itemsRepository"); +} diff --git a/src/libs/db/postgresql_connector/include/eedb/pg/Category.hpp b/src/libs/db/postgresql_connector/include/eedb/pg/Category.hpp index 3ddb6d4..4dffce4 100644 --- a/src/libs/db/postgresql_connector/include/eedb/pg/Category.hpp +++ b/src/libs/db/postgresql_connector/include/eedb/pg/Category.hpp @@ -52,7 +52,7 @@ class CategoryImpl : public impl::PgCategory { Category * parent() const override; - Category * addChild(std::unique_ptr< Category > category) noexcept(false) override; + Category * addChild(std::unique_ptr< Category > && category) noexcept(false) override; CategoriesChildren children() const override; diff --git a/src/libs/db/postgresql_connector/mock/include/eedb/mock/db/pg/CategoryMock.hpp b/src/libs/db/postgresql_connector/mock/include/eedb/mock/db/pg/CategoryMock.hpp index d8c9adf..bd873c9 100644 --- a/src/libs/db/postgresql_connector/mock/include/eedb/mock/db/pg/CategoryMock.hpp +++ b/src/libs/db/postgresql_connector/mock/include/eedb/mock/db/pg/CategoryMock.hpp @@ -36,7 +36,7 @@ class CategoryMock : public impl::PgCategory { MOCK_CONST_METHOD0(path, std::string_view()); MOCK_CONST_METHOD0(parent, Category *()); MOCK_METHOD1(doAddChild, Category *( Category * ) ); - Category * addChild(std::unique_ptr< Category > c) { + Category * addChild(std::unique_ptr< Category > &&c) { return doAddChild(c.get()); } MOCK_CONST_METHOD0(children, CategoriesChildren()); diff --git a/src/libs/db/postgresql_connector/src/Category.cpp b/src/libs/db/postgresql_connector/src/Category.cpp index 4bd0bb9..34aa249 100644 --- a/src/libs/db/postgresql_connector/src/Category.cpp +++ b/src/libs/db/postgresql_connector/src/Category.cpp @@ -177,7 +177,7 @@ struct CategoryImpl::CategoryImplPrivate { return _parent; } - auto displayName() const { + const auto & displayName() const { return _name; } @@ -217,7 +217,7 @@ Category * CategoryImpl::parent() const { return _priv->parent(); } -Category * CategoryImpl::addChild(std::unique_ptr< Category > category) noexcept(false) { +Category * CategoryImpl::addChild(std::unique_ptr< Category > && category) noexcept(false) { return _priv->addChild(std::move(category)); } diff --git a/src/libs/db/postgresql_connector/src/Factory.cpp b/src/libs/db/postgresql_connector/src/Factory.cpp index b93dcdb..58db9a0 100644 --- a/src/libs/db/postgresql_connector/src/Factory.cpp +++ b/src/libs/db/postgresql_connector/src/Factory.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -66,6 +67,44 @@ void FactoryImpl::init() { (*_connection)(insert_into(t_category).set(set_rootCategoryValues())); } details::session_set_user_id((*_connection), _global_root_uid); + +// CategoriesRepositoryImpl repo{(*_connection)}; + +// auto rootId = dynamic_cast< CategoryImpl * >(repo.root().get())->id(); + +// try{ +// auto cat1 = (*_connection)(sqlpp::postgresql::insert_into(t_category) +// .set(t_category.owner = app_root_id(), +// t_category.status = 0, +// t_category.parent_id = rootId, +// t_category.name = "cat123", +// t_category.description = "cat123") +// .returning(t_category.id)) +// .front() +// .id; + +// auto cat2 = (*_connection)(sqlpp::postgresql::insert_into(t_category) +// .set(t_category.owner = app_root_id(), +// t_category.status = 0, +// t_category.parent_id = rootId, +// t_category.name = "cat2123", +// t_category.description = "cat2123") +// .returning(t_category.id)) +// .front() +// .id; + +// auto cat3 = (*_connection)(sqlpp::postgresql::insert_into(t_category) +// .set(t_category.owner = app_root_id(), +// t_category.status = 0, +// t_category.parent_id = cat2, +// t_category.name = "cat3123", +// t_category.description = "cat3123") +// .returning(t_category.id)) +// .front() +// .id; +// } catch (const sqlpp::postgresql::failure &f){ +// std::cout << f.what() << '\n'; +// } } std::unique_ptr< Users > FactoryImpl::usersRepository() const { diff --git a/src/libs/eedb/include/eedb/Category.hpp b/src/libs/eedb/include/eedb/Category.hpp index c3539f3..5d1e5d7 100644 --- a/src/libs/eedb/include/eedb/Category.hpp +++ b/src/libs/eedb/include/eedb/Category.hpp @@ -29,7 +29,7 @@ class CategoriesRepository { }; namespace details { - using CategoryPtrIterator = IteratorTypeErasure::any_iterator< Category *, std::forward_iterator_tag, Category * >; + using CategoryPtrIterator = IteratorTypeErasure::any_iterator< Category *, std::bidirectional_iterator_tag, Category * >; using CategoryPtrIteratorRange = boost::iterator_range< CategoryPtrIterator >; } // namespace details @@ -90,7 +90,7 @@ class Category { * @throws CategoryAddException() * @return pointer to newely added category */ - virtual Category * addChild(std::unique_ptr< Category > category) = 0; + virtual Category * addChild(std::unique_ptr< Category > && category) = 0; /** * @brief children diff --git a/src/libs/webapp/include/widget/DefaultCategoryTree.hpp b/src/libs/webapp/include/widget/DefaultCategoryTree.hpp index 95bbdf0..43e044e 100644 --- a/src/libs/webapp/include/widget/DefaultCategoryTree.hpp +++ b/src/libs/webapp/include/widget/DefaultCategoryTree.hpp @@ -2,7 +2,11 @@ #include -#include +#include + +namespace Wt { +class WTreeNode; +} namespace eedb { @@ -20,8 +24,12 @@ class DefaultCategoriesTree final : public CategoriesTree { void registerOnCategoryChanged(std::function< void(const Category *) >) override; private: - std::unique_ptr< CategoriesRepository > _categories; + void handleTreeNodeSelect() ; + std::unique_ptr< Category > _root; + std::map< Wt::WTreeNode *, const Category * > _categories; Wt::Signal< const Category * > _categorySelected; + + std::function< void(Wt::WTreeNode *) > registerForUpdate; }; } // namespace eedb diff --git a/src/libs/webapp/mock/include/eedb/mock/CategoryMock.hpp b/src/libs/webapp/mock/include/eedb/mock/CategoryMock.hpp index 157afa2..ae49473 100644 --- a/src/libs/webapp/mock/include/eedb/mock/CategoryMock.hpp +++ b/src/libs/webapp/mock/include/eedb/mock/CategoryMock.hpp @@ -12,7 +12,7 @@ class CategoryMock : public Category { MOCK_CONST_METHOD0(displayName, string_view()); MOCK_CONST_METHOD0(parent, Category *()); MOCK_METHOD1(doAddChild, Category *( Category * ) ); - Category * addChild(std::unique_ptr< Category > c) { + Category * addChild(std::unique_ptr< Category > && c) { return doAddChild(c.get()); } MOCK_CONST_METHOD0(children, CategoriesChildren()); diff --git a/src/libs/webapp/src/DefaultCategoryTree.cpp b/src/libs/webapp/src/DefaultCategoryTree.cpp index d8c70d4..f0ab4ba 100644 --- a/src/libs/webapp/src/DefaultCategoryTree.cpp +++ b/src/libs/webapp/src/DefaultCategoryTree.cpp @@ -8,8 +8,7 @@ namespace eedb { -DefaultCategoriesTree::DefaultCategoriesTree(std::unique_ptr< CategoriesRepository > categories) - : _categories{std::move(categories)}, _root{_categories->root()} { +DefaultCategoriesTree::DefaultCategoriesTree(std::unique_ptr< CategoriesRepository > categories) : _root{categories->root()} { using namespace Wt; setObjectName(widget_name()); @@ -22,58 +21,53 @@ DefaultCategoriesTree::DefaultCategoriesTree(std::unique_ptr< CategoriesReposito treeRoot()->setChildCountPolicy(Wt::ChildCountPolicy::Disabled); treeRoot()->setLoadPolicy(ContentLoading::NextLevel); - treeRoot()->selected().connect([root = _root.get()](bool e) { - for(const auto child : root->children()) { - auto name = std::string{child->displayName()}; - /// TODO load image into WTreeNode - auto node = cpp14::make_unique< WTreeNode >(name); - node->selected().connect( [name](bool selected){ - if(selected){ - std::cout << "selected category: " << name; - } - } ); + itemSelectionChanged().connect(this, &DefaultCategoriesTree::handleTreeNodeSelect); + + auto saveCategory = [=](auto node, const auto child) { + if(_categories.find(node) == _categories.end()) { + assert(node); + assert(child); + _categories[node] = child; } - }); + }; - // treeRoot()->addChildNode(cpp14::make_unique< WTreeNode >("Table"))->selected().connect([](bool selected) { - // if(selected) - // std::cout << "selected Table\n"; - // }); + auto populate = [=](WTreeNode * parent, const Category * child) { + auto node = parent->addChildNode(cpp14::make_unique< WTreeNode >(std::string{child->displayName()})); + saveCategory(node, child); + return node; + }; - // treeRoot()->addChildNode(cpp14::make_unique< WTreeNode >("Cupboard"))->selected().connect([](bool selected) { - // if(selected) - // std::cout << "selected Cupboard\n"; - // }); + registerForUpdate = [=](WTreeNode * node) { + node->selected().connect([&, n=node](bool selected) { + if(selected) { + for(const auto child : _categories[n]->children()) { + populate(n, child); + registerForUpdate(n); + } + } + }); + }; - // auto subtree = cpp14::make_unique< WTreeNode >("Chair"); - // auto subtree_ = treeRoot()->addChildNode(std::move(subtree)); - // treeRoot()->addChildNode(cpp14::make_unique< WTreeNode >("Coach")); - // treeRoot()->expand(); - - // subtree_->addChildNode(cpp14::make_unique< WTreeNode >("Doc")); - // subtree_->addChildNode(cpp14::make_unique< WTreeNode >("Grumpy")); - // subtree_->addChildNode(cpp14::make_unique< WTreeNode >("Happy")); - // subtree_->addChildNode(cpp14::make_unique< WTreeNode >("Sneezy")); - // subtree_->addChildNode(cpp14::make_unique< WTreeNode >("Dopey")); - // subtree_->addChildNode(cpp14::make_unique< WTreeNode >("Bashful")); - // subtree_->addChildNode(cpp14::make_unique< WTreeNode >("Sleepy")); - - // Wt::WTreeNode node{""}; - - // auto root_category = categories->root(); - - // node.selected().connect([ this, category = root_category.get() ](auto selected) { - // if(selected) - // this->_categorySelected(category); - // }); - - // node.expanded() - - // auto children = root_category->children(); - // for(const auto & category : *children) { - // } + for(const auto child : _root->children()) { + /// TODO load image into WTreeNode + auto node = populate(treeRoot(), child); + registerForUpdate(node); + } } -void DefaultCategoriesTree::registerOnCategoryChanged(std::function< void(const Category *) >) {} +void DefaultCategoriesTree::registerOnCategoryChanged(std::function< void(const Category *) > cb) { + _categorySelected.connect(cb); +} + +void DefaultCategoriesTree::handleTreeNodeSelect() { + auto allSelected = selectedNodes(); + + if(allSelected.size() == 1) { + const auto selected = *allSelected.begin(); + const auto category = _categories.find(selected)->second; + + _categorySelected.emit(category); + } +} } // namespace eedb diff --git a/src/libs/webapp/src/DefaultHomePage.cpp b/src/libs/webapp/src/DefaultHomePage.cpp index d1de3ae..f11afbc 100644 --- a/src/libs/webapp/src/DefaultHomePage.cpp +++ b/src/libs/webapp/src/DefaultHomePage.cpp @@ -20,6 +20,7 @@ #include #include +#include namespace eedb { @@ -27,37 +28,28 @@ eedb::DefaultHomePage::DefaultHomePage(Session & session, std::unique_ptr< NavigationBar > navigationBar, std::unique_ptr< CategoriesTree > tree) : _session(session) { - auto stackedWidget = std::make_unique< Wt::WStackedWidget >(); - - // navigationBar->registerLogoutAction([=]() { this->_session.login().logout(); }); - - stackedWidget->addWidget(std::move(navigationBar)); - // _navigationBar->attachTo(stackedWidget.get()); + navigationBar->registerLogoutAction([=]() { this->_session.logout(); }); auto vbox = std::make_unique< Wt::WVBoxLayout >(); vbox->setPreferredImplementation(Wt::LayoutImplementation::JavaScript); - { - auto hbox = std::make_unique< Wt::WHBoxLayout >(); - hbox->setPreferredImplementation(Wt::LayoutImplementation::JavaScript); - { - // auto tree = make_tree(); - // tree->clicked().connect([](Wt::WModelIndex, Wt::WMouseEvent) { Wt::log("notice") << "Item selection changed"; }); - // /// TODO #7 collumn size based on the actual size of text - // tree->setColumnWidth(0, 100.0); - hbox->addWidget(std::move(tree), 1); - } - { - auto contents = std::make_unique< Wt::WStackedWidget >(); - contents->setId("contents"); - hbox->addWidget(std::move(contents), 2); - } - hbox->setResizable(0, true); + auto stackedWidget = vbox->addWidget(std::make_unique< Wt::WStackedWidget >(), 0); + stackedWidget->addWidget(std::move(navigationBar)); - vbox->addWidget(std::move(stackedWidget), 0); - vbox->addLayout(std::move(hbox), 20); - } + auto hbox = vbox->addLayout(std::make_unique< Wt::WHBoxLayout >(), 20); + hbox->setPreferredImplementation(Wt::LayoutImplementation::JavaScript); + auto catTree = hbox->addWidget(std::move(tree), 1); + /// TODO #7 collumn size based on the actual size of text + // tree->setColumnWidth(0, 100.0); + + auto contents = hbox->addWidget(std::make_unique< Wt::WStackedWidget >(), 2); + + auto text = contents->addWidget(std::make_unique< Wt::WText >("some text")); + + catTree->registerOnCategoryChanged([text](const Category * cat) { text->setText(std::string{cat->displayName()}); }); + + hbox->setResizable(0, true); this->setLayout(std::move(vbox)); }