move 'create user' functionality to user implementation class
This commit is contained in:
parent
087405ec08
commit
fa7beb80fe
@ -49,6 +49,8 @@ std::unique_ptr< Wt::WApplication > createApplication(const Wt::WEnvironment & e
|
||||
|
||||
auto factory = std::make_unique< eedb::pg::FactoryImpl >(std::move(connection));
|
||||
|
||||
factory->init();
|
||||
|
||||
return eedb::WebApplicationFactory{}.create(std::move(factory), env);
|
||||
}
|
||||
|
||||
|
||||
@ -28,6 +28,10 @@ namespace impl {
|
||||
|
||||
class Connection;
|
||||
|
||||
class CategoriesChildrenImpl : CategoriesChildren{
|
||||
|
||||
};
|
||||
|
||||
class CategoryImpl : public impl::PgCategory {
|
||||
public:
|
||||
/// TODO should be private
|
||||
@ -35,7 +39,7 @@ class CategoryImpl : public impl::PgCategory {
|
||||
spimpl::unique_impl_ptr< CategoryImplPrivate > _priv;
|
||||
|
||||
public:
|
||||
// ROOT category
|
||||
// root category
|
||||
CategoryImpl(Connection & db);
|
||||
|
||||
// creates new category
|
||||
@ -52,6 +56,11 @@ class CategoryImpl : public impl::PgCategory {
|
||||
|
||||
std::unique_ptr< CategoriesChildren > children() const override;
|
||||
|
||||
void detach();
|
||||
|
||||
Category * attachTo(Category *parent);
|
||||
|
||||
// postgresql api
|
||||
public:
|
||||
int64_t id() const override;
|
||||
void setParent(PgCategory * parent) override;
|
||||
|
||||
@ -11,6 +11,8 @@ class FactoryImpl : public Factory {
|
||||
FactoryImpl(std::unique_ptr< Connection > connection);
|
||||
~FactoryImpl() override;
|
||||
|
||||
void init() override;
|
||||
|
||||
std::unique_ptr< Users > usersRepository() const override;
|
||||
|
||||
std::unique_ptr< CategoriesRepository > categoriesRepository() const override;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <utils/spimpl.hpp>
|
||||
|
||||
namespace eedb::pg {
|
||||
|
||||
namespace impl {
|
||||
class UserImplPriv : public User {
|
||||
public:
|
||||
@ -23,6 +24,8 @@ class UserImpl : public impl::UserImplPriv {
|
||||
public:
|
||||
UserImpl(Connection & db, int uid);
|
||||
|
||||
UserImpl(Connection & db, std::unique_ptr< AuthInfo > authInfo, std::unique_ptr< AuthIdentity > authIdentity);
|
||||
|
||||
const UserConfig & config() const override;
|
||||
|
||||
AuthTokens & authTokens() const override;
|
||||
@ -32,7 +35,6 @@ class UserImpl : public impl::UserImplPriv {
|
||||
AuthInfo & authInfo() const override;
|
||||
|
||||
public:
|
||||
|
||||
int64_t id() const override;
|
||||
};
|
||||
} // namespace eedb::pg
|
||||
|
||||
@ -42,6 +42,8 @@ class CategoryMock : public impl::PgCategory {
|
||||
MOCK_CONST_METHOD0(children, std::unique_ptr< CategoriesChildren >());
|
||||
MOCK_CONST_METHOD0(id, int64_t());
|
||||
MOCK_METHOD1(setParent, void(impl::PgCategory *));
|
||||
MOCK_METHOD0(detach, void());
|
||||
MOCK_METHOD1(attachTo, Category *( Category * ) );
|
||||
|
||||
void _init_simple(std::string name) {
|
||||
_root_guard();
|
||||
|
||||
@ -17,6 +17,16 @@
|
||||
|
||||
namespace eedb::pg {
|
||||
struct CategoryImpl::CategoryImplPrivate {
|
||||
private:
|
||||
Connection & _db;
|
||||
impl::PgCategory * _parent{nullptr};
|
||||
int64_t _uid{};
|
||||
|
||||
std::vector< std::unique_ptr< Category > > _children;
|
||||
std::string _name;
|
||||
std::string _path;
|
||||
std::string _description;
|
||||
|
||||
private:
|
||||
// select
|
||||
constexpr auto stat_columns() const {
|
||||
@ -89,14 +99,12 @@ struct CategoryImpl::CategoryImplPrivate {
|
||||
public:
|
||||
impl::PgCategory * _self{nullptr};
|
||||
|
||||
CategoryImplPrivate(Connection & db, Category * parent) : _db{db}, _parent{cast(parent)} {
|
||||
auto row = _db(select(columns()).from(table_list()).where(root_path_match()).limit(1ul));
|
||||
// no root category if row empty
|
||||
if(row.empty()) {
|
||||
row = _db(sqlpp::postgresql::insert_into(t_category).set(set_rootCategoryValues()).returning(columns()));
|
||||
CategoryImplPrivate(Connection & db) : _db{db}, _parent{nullptr} {
|
||||
try {
|
||||
init_data(_db(select(columns()).from(table_list()).where(root_path_match()).limit(1ul)).front());
|
||||
} catch(const sqlpp::postgresql::failure & f) {
|
||||
throw;
|
||||
}
|
||||
|
||||
init_data(row.front());
|
||||
}
|
||||
|
||||
CategoryImplPrivate(Connection & db, std::string name, std::string description) : _db{db}, _parent{nullptr} {
|
||||
@ -115,43 +123,37 @@ struct CategoryImpl::CategoryImplPrivate {
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
void detach() {
|
||||
throw std::logic_error{"unimplemented"};
|
||||
try {
|
||||
_db(update(table_list()).set(t_category.parent_id = sqlpp::null).where(t_category.id == _uid));
|
||||
_parent = nullptr;
|
||||
} catch(sqlpp::exception) {
|
||||
}
|
||||
}
|
||||
|
||||
Category * attachTo(Category * ) {
|
||||
throw std::logic_error{"unimplemented"};
|
||||
}
|
||||
|
||||
Category * addChild(std::unique_ptr< Category > category) {
|
||||
auto pgCategory = cast(category);
|
||||
|
||||
// category can be added if
|
||||
// #1 is detached
|
||||
// #2 is unique within parent
|
||||
|
||||
if(category->parent()) {
|
||||
/// TODO can't add a category that is already attached to some other category
|
||||
throw exceptions::CategoryAddException(std::move(category), "Cannot change the parent of category");
|
||||
}
|
||||
|
||||
try {
|
||||
{
|
||||
auto data = _db(sqlpp::select(t_category.name, t_category.id, t_category.parent_id).from(t_category).unconditionally());
|
||||
std::cout << "blah1\n";
|
||||
for(const auto & row : data) {
|
||||
std::cout << row.name << " " << row.id << " " << row.parent_id << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
_db(sqlpp::update(table_list()).set(t_category.parent_id = _uid).where(t_category.id == pgCategory->id()));
|
||||
pgCategory->setParent(_self);
|
||||
|
||||
{
|
||||
auto data = _db(sqlpp::select(t_category.name, t_category.id, t_category.parent_id).from(t_category).unconditionally());
|
||||
std::cout << "blah2\n";
|
||||
for(const auto & row : data) {
|
||||
std::cout << row.name << " " << row.id << " " << row.parent_id << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
return _children.emplace_back(std::move(category)).get();
|
||||
} catch(sqlpp::postgresql::unique_violation e) {
|
||||
throw exceptions::CategoryAddException(std::move(category), e.what());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool detached() const {
|
||||
@ -170,33 +172,19 @@ struct CategoryImpl::CategoryImplPrivate {
|
||||
return _uid;
|
||||
}
|
||||
|
||||
auto path() const {
|
||||
return std::string_view{_path};
|
||||
}
|
||||
|
||||
public:
|
||||
template < typename Row >
|
||||
void init_data(Row & row) {
|
||||
void init_data(const Row & row) {
|
||||
_uid = row.id;
|
||||
_name = row.name;
|
||||
_path = row.parent_path;
|
||||
_description = row.description;
|
||||
}
|
||||
|
||||
private:
|
||||
Connection & _db;
|
||||
impl::PgCategory * _parent{nullptr};
|
||||
|
||||
int64_t _uid{};
|
||||
std::vector< std::unique_ptr< Category > > _children;
|
||||
std::string _name;
|
||||
std::string _path;
|
||||
std::string _description;
|
||||
};
|
||||
|
||||
CategoryImpl::CategoryImpl(Connection & db) //
|
||||
: _priv{spimpl::make_unique_impl< CategoryImplPrivate >(db, nullptr)} {
|
||||
_priv->_self = this;
|
||||
CategoryImpl::CategoryImpl(Connection &db) : _priv{spimpl::make_unique_impl< CategoryImplPrivate >(db)}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CategoryImpl::CategoryImpl(Connection & db, std::string name, std::string description)
|
||||
@ -225,6 +213,15 @@ std::unique_ptr< CategoriesChildren > CategoryImpl::children() const {
|
||||
return _priv->categories();
|
||||
}
|
||||
|
||||
void CategoryImpl::detach() {
|
||||
///TODO set parent children as "dirty" to force cache update
|
||||
_priv->detach();
|
||||
}
|
||||
|
||||
Category * CategoryImpl::attachTo(Category * parent) {
|
||||
return _priv->attachTo(parent);
|
||||
}
|
||||
|
||||
int64_t CategoryImpl::id() const {
|
||||
return _priv->id();
|
||||
}
|
||||
|
||||
@ -1,23 +1,72 @@
|
||||
#include <eedb/pg/Factory.hpp>
|
||||
|
||||
#include <eedb/AuthIdentityConst.hpp>
|
||||
#include <eedb/AuthInfoConst.hpp>
|
||||
|
||||
#include <eedb/pg/CategoriesRepository.hpp>
|
||||
#include <eedb/pg/ItemsRepository.hpp>
|
||||
#include <eedb/pg/Session.hpp>
|
||||
#include <eedb/pg/User.hpp>
|
||||
#include <eedb/pg/Users.hpp>
|
||||
#include <eedb/pg/connection.hpp>
|
||||
#include <eedb/pg/model/all.hpp>
|
||||
#include <eedb/pg/model/category.h>
|
||||
#include <eedb/pg/model/system_info.h>
|
||||
#include <eedb/pg/utils.hpp>
|
||||
|
||||
int64_t _global_root_uid;
|
||||
|
||||
constexpr eedb::db::category t_category;
|
||||
|
||||
namespace eedb::pg {
|
||||
|
||||
FactoryImpl::FactoryImpl(std::unique_ptr< Connection > connection) : _connection{std::move(connection)} {}
|
||||
|
||||
FactoryImpl::~FactoryImpl() {}
|
||||
|
||||
auto set_rootCategoryValues() {
|
||||
return std::make_tuple( //
|
||||
t_category.owner = app_root_id(),
|
||||
t_category.status = 0, /// TODO set status "DETACHED"
|
||||
t_category.parent_id = sqlpp::null,
|
||||
t_category.name = "root",
|
||||
t_category.description = "root category");
|
||||
}
|
||||
|
||||
void FactoryImpl::init() {
|
||||
_global_root_uid = [& db = (*_connection)]() {
|
||||
UsersImpl users{db};
|
||||
auto rootIdentity = std::make_unique< AuthIdentityConst >("root", "loginname");
|
||||
auto rootUser = users.findWith(*rootIdentity);
|
||||
if(rootUser) {
|
||||
// root available, return created ID
|
||||
return dynamic_cast< UserImpl * >(rootUser.get())->id();
|
||||
} else {
|
||||
// root user not found, create root user and return it's ID
|
||||
auto authInfo = std::make_unique< AuthInfoConst >(
|
||||
/// TODO get password from someware
|
||||
Password{"bcrypt", "OM/Z1c4WBFXvwkxh", "$2y$07$RyytUhDhLDbAPjf0b0r2Y.dsg.FlQ7L.xzWHMmoelI81u0MfBrW7q"},
|
||||
/// TODO get root user email
|
||||
Email{"root@eedb.pl"});
|
||||
|
||||
auto root = UserImpl{db, std::move(authInfo), std::move(rootIdentity)};
|
||||
return root.id();
|
||||
}
|
||||
}();
|
||||
|
||||
auto rootCategoryExists = (*_connection)( //
|
||||
sqlpp::select( //
|
||||
sqlpp::exists(select(t_category.id) //
|
||||
.from(t_category)
|
||||
.where(t_category.parent_path == "root"))))
|
||||
.front()
|
||||
.exists;
|
||||
|
||||
if(not rootCategoryExists) {
|
||||
(*_connection)(insert_into(t_category).set(set_rootCategoryValues()));
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr< Users > FactoryImpl::usersRepository() const {
|
||||
createRootUser();
|
||||
return std::make_unique< UsersImpl >(*_connection);
|
||||
}
|
||||
|
||||
@ -33,17 +82,6 @@ std::unique_ptr< Session > FactoryImpl::session() const {
|
||||
return std::make_unique< SessionImpl >(*_connection);
|
||||
}
|
||||
|
||||
void FactoryImpl::createRootUser() const {
|
||||
_global_root_uid = (*_connection)(sqlpp::postgresql::insert_into(t_auth_info)
|
||||
.set( //
|
||||
t_auth_info.password_hash = "$2y$07$RyytUhDhLDbAPjf0b0r2Y.dsg.FlQ7L.xzWHMmoelI81u0MfBrW7q",
|
||||
t_auth_info.password_method = "bcrypt",
|
||||
t_auth_info.password_salt = "OM/Z1c4WBFXvwkxh",
|
||||
t_auth_info.email = "root@eedb.pl", //
|
||||
t_auth_info.status = 0)
|
||||
.returning(t_auth_info.id))
|
||||
.front()
|
||||
.id;
|
||||
}
|
||||
void FactoryImpl::createRootUser() const {}
|
||||
|
||||
} // namespace eedb::pg
|
||||
|
||||
@ -10,6 +10,36 @@
|
||||
|
||||
namespace eedb::pg {
|
||||
|
||||
namespace {
|
||||
auto setPassword(const Password & pass) {
|
||||
return std::make_tuple(
|
||||
t_auth_info.password_hash = pass.value(), t_auth_info.password_method = pass.function(), t_auth_info.password_salt = pass.salt());
|
||||
}
|
||||
|
||||
auto setEmail(const Email & email) {
|
||||
return std::make_tuple(t_auth_info.email = std::string{email.address()});
|
||||
}
|
||||
|
||||
auto setStatus() {
|
||||
return std::make_tuple(t_auth_info.status = 0);
|
||||
}
|
||||
|
||||
auto setAuthInfo(AuthInfo * authInfo) {
|
||||
const auto & pass = authInfo->password();
|
||||
const auto & email = authInfo->email();
|
||||
|
||||
return std::tuple_cat(setPassword(pass), setEmail(email), setStatus());
|
||||
}
|
||||
|
||||
auto setAuthIdentity(const int64_t auth_info_id, AuthIdentity * authIdentity) {
|
||||
return std::make_tuple( //
|
||||
t_auth_identity.auth_info_id = auth_info_id,
|
||||
t_auth_identity.identity = std::string{authIdentity->identity()},
|
||||
t_auth_identity.provider = std::string{authIdentity->provider()});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
struct UserImpl::UserImplPriv {
|
||||
UserImplPriv(Connection & db, int uid, UserImpl * owner) : _db{db}, id{uid}, self{owner} {}
|
||||
|
||||
@ -48,6 +78,27 @@ struct UserImpl::UserImplPriv {
|
||||
|
||||
UserImpl::UserImpl(Connection & db, int uid) : _priv{spimpl::make_unique_impl< UserImplPriv >(db, uid, this)} {}
|
||||
|
||||
UserImpl::UserImpl(Connection & db, std::unique_ptr< AuthInfo > authInfo, std::unique_ptr< AuthIdentity > authIdentity)
|
||||
: _priv{spimpl::make_unique_impl< UserImplPriv >(db, 0, this)} {
|
||||
assert(authInfo);
|
||||
assert(authIdentity);
|
||||
|
||||
namespace pg = sqlpp::postgresql;
|
||||
|
||||
auto transaction = sqlpp::start_transaction(db);
|
||||
auto auth_info_id = db(pg::insert_into(t_auth_info) //
|
||||
.set(setAuthInfo(authInfo.get()))
|
||||
.returning(t_auth_info.id))
|
||||
.front()
|
||||
.id;
|
||||
|
||||
db(pg::insert_into(t_auth_identity) //
|
||||
.set(setAuthIdentity(auth_info_id, authIdentity.get())));
|
||||
transaction.commit();
|
||||
|
||||
_priv->id = auth_info_id;
|
||||
}
|
||||
|
||||
const UserConfig & UserImpl::config() const {
|
||||
return _priv->config;
|
||||
}
|
||||
|
||||
@ -82,20 +82,6 @@ struct UsersImpl::UsersImplPriv {
|
||||
.on(t_auth_info.id == t_auth_token.auth_info_id);
|
||||
}
|
||||
|
||||
// setters
|
||||
auto setPassword(const Password & pass) const {
|
||||
return std::make_tuple(
|
||||
t_auth_info.password_hash = pass.value(), t_auth_info.password_method = pass.function(), t_auth_info.password_salt = pass.salt());
|
||||
}
|
||||
|
||||
auto setEmail(const Email & email) const {
|
||||
return std::make_tuple(t_auth_info.email = std::string{email.address()});
|
||||
}
|
||||
|
||||
auto setStatus() const {
|
||||
return std::make_tuple(t_auth_info.status = 0);
|
||||
}
|
||||
|
||||
// find
|
||||
auto by(const int64_t id) const {
|
||||
return select(userData()) //
|
||||
@ -127,20 +113,6 @@ struct UsersImpl::UsersImplPriv {
|
||||
.where(authTokenEq(authToken) and statusIsValid());
|
||||
}
|
||||
|
||||
auto setAuthInfo(AuthInfo * authInfo) const {
|
||||
const auto & pass = authInfo->password();
|
||||
const auto & email = authInfo->email();
|
||||
|
||||
return std::tuple_cat(setPassword(pass), setEmail(email), setStatus());
|
||||
}
|
||||
|
||||
auto setAuthIdentity(const int64_t auth_info_id, AuthIdentity * authIdentity) {
|
||||
return std::make_tuple( //
|
||||
t_auth_identity.auth_info_id = auth_info_id,
|
||||
t_auth_identity.identity = std::string{authIdentity->identity()},
|
||||
t_auth_identity.provider = std::string{authIdentity->provider()});
|
||||
}
|
||||
|
||||
public:
|
||||
template < typename Key >
|
||||
auto find(Key && key) -> std::unique_ptr< UserImpl > {
|
||||
@ -153,20 +125,8 @@ struct UsersImpl::UsersImplPriv {
|
||||
return std::make_unique< UserImpl >(_db, result.front().id);
|
||||
}
|
||||
|
||||
auto add(AuthInfo * authInfo, AuthIdentity * authIdentity) {
|
||||
namespace pg = sqlpp::postgresql;
|
||||
|
||||
/// TODO assert transaction
|
||||
auto auth_info_id = _db(pg::insert_into(t_auth_info) //
|
||||
.set(setAuthInfo(authInfo))
|
||||
.returning(t_auth_info.id))
|
||||
.front()
|
||||
.id;
|
||||
|
||||
_db(pg::insert_into(t_auth_identity) //
|
||||
.set(setAuthIdentity(auth_info_id, authIdentity)));
|
||||
|
||||
return std::make_unique< eedb::pg::UserImpl >(_db, auth_info_id);
|
||||
auto add(std::unique_ptr< AuthInfo > authInfo, std::unique_ptr< AuthIdentity > authIdentity) {
|
||||
return std::make_unique< UserImpl >(_db, std::move(authInfo), std::move(authIdentity));
|
||||
}
|
||||
|
||||
void setDisabled( eedb::pg::UserImpl * u) const {
|
||||
@ -197,10 +157,7 @@ unique_ptr< User > UsersImpl::findWith(const user::AuthTokenHash & token) const
|
||||
}
|
||||
|
||||
unique_ptr< User > UsersImpl::addUser(unique_ptr< AuthInfo > authInfo, unique_ptr< AuthIdentity > authIdentity) {
|
||||
assert(authInfo);
|
||||
assert(authIdentity);
|
||||
|
||||
return _priv->add(authInfo.get(), authIdentity.get());
|
||||
return _priv->add(std::move(authInfo), std::move(authIdentity));
|
||||
}
|
||||
|
||||
void UsersImpl::removeUser(std::unique_ptr< User > user) const {
|
||||
|
||||
@ -63,3 +63,18 @@ TEST_F(PgCategoryTest, addSameCategoryMultipleTimesShouldFail) {
|
||||
EXPECT_THROW(
|
||||
sut->addChild(std::make_unique< eedb::pg::CategoryImpl >(db(), "category", "asdf")), eedb::exceptions::CategoryAddException);
|
||||
}
|
||||
|
||||
//TEST_F(PgCategoryTest, attachToParent) {
|
||||
// auto cat = std::make_unique< eedb::pg::CategoryImpl >(db(), "category", "asdf");
|
||||
|
||||
// cat->attachTo(sut.get());
|
||||
// EXPECT_TRUE(cat->parent()->parent());
|
||||
//}
|
||||
|
||||
//TEST_F(PgCategoryTest, detachFromParent) {
|
||||
// auto cat = std::make_unique< eedb::pg::CategoryImpl >(db(), "category", "asdf");
|
||||
|
||||
// cat->attachTo(sut.get());
|
||||
// cat->detach();
|
||||
// EXPECT_FALSE(cat->parent()->parent());
|
||||
//}
|
||||
|
||||
@ -72,8 +72,6 @@ class Category {
|
||||
public:
|
||||
virtual ~Category() = default;
|
||||
|
||||
virtual int foo() {}
|
||||
|
||||
/**
|
||||
* @brief displayName
|
||||
* @return category display name
|
||||
@ -89,7 +87,7 @@ class Category {
|
||||
/**
|
||||
* @brief addChild
|
||||
* @param category
|
||||
* @throws
|
||||
* @throws CategoryAddException()
|
||||
* @return pointer to newely added category
|
||||
*/
|
||||
virtual Category * addChild(std::unique_ptr< Category > category) = 0;
|
||||
@ -99,6 +97,17 @@ class Category {
|
||||
* @return sequence of child categories
|
||||
*/
|
||||
virtual std::unique_ptr< CategoriesChildren > children() const = 0;
|
||||
|
||||
/**
|
||||
* @brief detach category from it's parent
|
||||
*/
|
||||
virtual void detach() = 0;
|
||||
|
||||
/**
|
||||
* @brief attachTo schould act the same as addChild
|
||||
* @return a pointer to created category
|
||||
*/
|
||||
virtual Category * attachTo(Category *) = 0;
|
||||
};
|
||||
|
||||
} // namespace eedb
|
||||
|
||||
@ -13,6 +13,11 @@ class Factory {
|
||||
public:
|
||||
virtual ~Factory() = default;
|
||||
|
||||
/**
|
||||
* @brief init all data structures and default values for data store, also update to newer version
|
||||
*/
|
||||
virtual void init() = 0;
|
||||
|
||||
virtual std::unique_ptr< Users > usersRepository() const = 0;
|
||||
|
||||
virtual std::unique_ptr< CategoriesRepository > categoriesRepository() const = 0;
|
||||
|
||||
@ -8,6 +8,7 @@ class UserConfig {};
|
||||
class AuthTokens;
|
||||
class AuthInfo;
|
||||
class AuthIdentities;
|
||||
class AuthIdentity;
|
||||
|
||||
/**
|
||||
* @brief The User class
|
||||
|
||||
@ -16,5 +16,7 @@ class CategoryMock : public Category {
|
||||
return doAddChild(c.get());
|
||||
}
|
||||
MOCK_CONST_METHOD0(children, std::unique_ptr< CategoriesChildren >());
|
||||
MOCK_METHOD0(detach, void());
|
||||
MOCK_METHOD1(attachTo, Category *( Category * ) );
|
||||
};
|
||||
} // namespace eedb
|
||||
|
||||
@ -16,7 +16,9 @@ DefaultCategoriesTree::DefaultCategoriesTree(std::unique_ptr< CategoriesReposito
|
||||
|
||||
setSelectionMode(Wt::SelectionMode::Single);
|
||||
|
||||
auto node = std::make_unique< WTreeNode >(_root->displayName().data());
|
||||
const auto displayName = _root->displayName();
|
||||
|
||||
auto node = std::make_unique< WTreeNode >(std::string{displayName.data()});
|
||||
setTreeRoot(std::move(node));
|
||||
|
||||
treeRoot()->label()->setTextFormat(Wt::TextFormat::Plain);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user