replace some files
This commit is contained in:
parent
1e2cc17576
commit
4770ccc681
@ -23,5 +23,5 @@ include_directories(${CMAKE_BINARY_DIR}/external/include/date SYSTEM)
|
|||||||
include_directories(share SYSTEM)
|
include_directories(share SYSTEM)
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
add_subdirectory(tests)
|
#add_subdirectory(tests)
|
||||||
#add_subdirectory(benchmarks)
|
#add_subdirectory(benchmarks)
|
||||||
|
|||||||
160
sql/schema.sql
160
sql/schema.sql
@ -51,7 +51,7 @@ create table "group" (
|
|||||||
constraint "pk_group_gid" primary key ("gid"),
|
constraint "pk_group_gid" primary key ("gid"),
|
||||||
constraint "ux_group_name" unique ("name")
|
constraint "ux_group_name" unique ("name")
|
||||||
);
|
);
|
||||||
create trigger "update_user_group_last_update" before update on "group" FOR EACH ROW EXECUTE PROCEDURE last_update_column();
|
create trigger "update_user_group_last_update" before update on "group" for each row execute PROCEDURE last_update_column();
|
||||||
insert into "group"("name") values ('nogroup'), ('admins'), ('moderators'), ('users');
|
insert into "group"("name") values ('nogroup'), ('admins'), ('moderators'), ('users');
|
||||||
|
|
||||||
create or replace function default_group_id()
|
create or replace function default_group_id()
|
||||||
@ -95,7 +95,7 @@ create table "auth_info" (
|
|||||||
constraint "pk_auth_into_id" primary key("id"),
|
constraint "pk_auth_into_id" primary key("id"),
|
||||||
constraint "ux_auth_info_email" unique ("email")
|
constraint "ux_auth_info_email" unique ("email")
|
||||||
);
|
);
|
||||||
create trigger "update_auth_info_updated" before update on "auth_info" FOR EACH ROW EXECUTE PROCEDURE last_update_column();
|
create trigger "update_auth_info_updated" before update on "auth_info" for each row execute PROCEDURE last_update_column();
|
||||||
comment on table "auth_info" is '';
|
comment on table "auth_info" is '';
|
||||||
comment on column "auth_info"."id" is '';
|
comment on column "auth_info"."id" is '';
|
||||||
comment on column "auth_info"."group" is 'default user group';
|
comment on column "auth_info"."group" is 'default user group';
|
||||||
@ -186,7 +186,7 @@ create table "stat"(
|
|||||||
constraint "fk_stat_user" foreign key ("owner") references "auth_info" ("id") on delete cascade deferrable initially immediate,
|
constraint "fk_stat_user" foreign key ("owner") references "auth_info" ("id") on delete cascade deferrable initially immediate,
|
||||||
constraint "fk_stat_primary_group" foreign key ("group") references "group" ("gid") on delete cascade deferrable initially immediate
|
constraint "fk_stat_primary_group" foreign key ("group") references "group" ("gid") on delete cascade deferrable initially immediate
|
||||||
);
|
);
|
||||||
create trigger update_stat_last_update before update on stat FOR EACH ROW EXECUTE PROCEDURE last_update_column();
|
create trigger update_stat_last_update before update on stat for each row execute PROCEDURE last_update_column();
|
||||||
comment on table "stat" is '';
|
comment on table "stat" is '';
|
||||||
comment on column "stat"."id" is 'unique id for all objects in database';
|
comment on column "stat"."id" is 'unique id for all objects in database';
|
||||||
comment on column "stat"."owner" is 'uid of object''s owner';
|
comment on column "stat"."owner" is 'uid of object''s owner';
|
||||||
@ -271,7 +271,7 @@ create table "category"(
|
|||||||
constraint "pk_category_uid" primary key ("id"),
|
constraint "pk_category_uid" primary key ("id"),
|
||||||
constraint "fk_category_parent_id" foreign key ("parent_id") references "category"("id") on delete cascade deferrable initially immediate,
|
constraint "fk_category_parent_id" foreign key ("parent_id") references "category"("id") on delete cascade deferrable initially immediate,
|
||||||
constraint "fk_category_stat_owner" foreign key ("owner") references "auth_info"("id") deferrable initially immediate
|
constraint "fk_category_stat_owner" foreign key ("owner") references "auth_info"("id") deferrable initially immediate
|
||||||
) INHERITS (stat);
|
) inherits (stat);
|
||||||
create index "ix_category_parent_path" on "category" using GIST ("parent_path");
|
create index "ix_category_parent_path" on "category" using GIST ("parent_path");
|
||||||
create unique index "ux_category_name" on "category" ( "parent_id", "name" );
|
create unique index "ux_category_name" on "category" ( "parent_id", "name" );
|
||||||
create trigger "update_category_last_update" before update on "category" for each row execute procedure last_update_column();
|
create trigger "update_category_last_update" before update on "category" for each row execute procedure last_update_column();
|
||||||
@ -283,115 +283,101 @@ comment on column "category"."description" is '';
|
|||||||
comment on column "category"."thumbnail" is '';
|
comment on column "category"."thumbnail" is '';
|
||||||
|
|
||||||
|
|
||||||
--create table "measurand"(
|
--create table "measurands"(
|
||||||
-- "id" serial not null unique primary key,
|
-- "id" serial not null primary key,
|
||||||
-- "name" text not null unique,
|
-- "name" VARCHAR(32) not null unique,
|
||||||
-- "description" text,
|
-- "description" text
|
||||||
-- "dimension_symbol" text
|
|
||||||
--);
|
--);
|
||||||
|
|
||||||
|
|
||||||
--create table "metric_system"(
|
--create table "metric_system"(
|
||||||
-- "id" serial not null primary key,
|
-- "id" serial not null primary key,
|
||||||
-- "name" VARCHAR(32) not null unique,
|
-- "name" VARCHAR(32) not null unique,
|
||||||
-- "description" text
|
-- "description" text
|
||||||
--);
|
--);
|
||||||
--comment on table measurand IS 'Information about measured quantity length, time etc.';
|
|
||||||
|
|
||||||
|
--create table "unit"(
|
||||||
--create table unit_of_measurement(
|
-- "id" serial not null unique primary key,
|
||||||
-- symbol VARCHAR (20) not null,
|
-- "name" text not null unique,
|
||||||
-- description TEXT check(length(description) < 100000),
|
-- "symbol" VARCHAR (20) not null,
|
||||||
-- measurand_id int REFERENCES measurands(id),
|
-- "description" text,
|
||||||
-- base_unit int REFERENCES units(uid),
|
-- "dimension_symbol" text
|
||||||
-- metric_system int REFERENCES metric_systems(id),
|
-- "metric_system" int ,
|
||||||
-- constraint units_pkey primary key (uid),
|
-- constraint units_pkey primary key (uid),
|
||||||
-- constraint unitowner_fk foreign key (owner) REFERENCES users (uid) deferrable initially IMMEDIATE,
|
|
||||||
-- constraint units_unique UNIQUE(name, symbol)
|
-- constraint units_unique UNIQUE(name, symbol)
|
||||||
|
--);
|
||||||
|
|
||||||
|
--create table "parameter"(
|
||||||
|
-- "unit" int,
|
||||||
|
-- constraint "pk_parameter" primary key ("id"),
|
||||||
|
-- constraint "fk_parameter_unit" foreign key ("unit") references "unit"("id") on delete cascade deferrable initially immediate
|
||||||
--) inherits(stat);
|
--) inherits(stat);
|
||||||
--comment on table unit_of_measurement IS 'Table holds information about units used in application';
|
--create trigger update_parameter_last_update before update on parameter for each row execute PROCEDURE last_update_column();
|
||||||
--comment on column unit_of_measurement.name IS 'Parameter name e.g. Ampere';
|
|
||||||
--comment on column unit_of_measurement.symbol IS 'Parameter symbol e.g. A';
|
create table "item"(
|
||||||
--comment on column unit_of_measurement.description IS 'Simple description';
|
"symbol" text not null,
|
||||||
|
"original_symbol" text,
|
||||||
|
"producer" text,
|
||||||
|
"attributes" jsonb not null DEFAULT('{}'),
|
||||||
|
"short_desc" text,
|
||||||
|
"description" text,
|
||||||
|
constraint "pk_items" primary key ("id"),
|
||||||
|
constraint "fk_item_auth_info" foreign key ("owner") references "auth_info"("id") deferrable initially immediate
|
||||||
|
) inherits (stat);
|
||||||
|
create index "ix_item_attributes" on "item" USING GIN ("attributes");
|
||||||
|
create unique index "ux_item" on "item"("name", "symbol");
|
||||||
|
create trigger update_item_last_update before update on item for each row execute PROCEDURE last_update_column();
|
||||||
|
comment on table "item" is '';
|
||||||
|
comment on column "item"."symbol" is '';
|
||||||
|
comment on column "item"."original_symbol" is '';
|
||||||
|
comment on column "item"."producer" is '';
|
||||||
|
comment on column "item"."attributes" is '';
|
||||||
|
comment on column "item"."short_desc" is '';
|
||||||
|
comment on column "item"."description" is '';
|
||||||
|
|
||||||
|
|
||||||
--create table units_conversions(
|
create table "category_items"(
|
||||||
-- from_unit INTEGER not null REFERENCES units(uid),
|
"category_id" integer not null,
|
||||||
-- to_unit INTEGER not null REFERENCES units(uid),
|
"item_id" integer not null,
|
||||||
-- equation TEXT not null,
|
constraint "pk_category_items" primary key ("category_id", "item_id"),
|
||||||
-- constraint unit_conversions_unique primary key (from_unit, to_unit)
|
constraint "fk_category_id" foreign key ("category_id") references "category"("id") on delete cascade deferrable initially immediate,
|
||||||
--);
|
constraint "fk_item_id" foreign key ("item_id") references "item"("id") on delete cascade deferrable initially immediate
|
||||||
--comment on table units_conversions IS 'This table contains a mathematical equation for converting one unitl to other';
|
);
|
||||||
--comment on column units_conversions.equation IS 'this equation should be a proper script (mayby chaiscript?)';
|
comment on table "category_items" is '';
|
||||||
|
|
||||||
--create table pointed_values(
|
|
||||||
-- id serial primary key,
|
|
||||||
-- data jsonb default('{}')
|
|
||||||
--);
|
|
||||||
--create INDEX items_pointed_values_idx on pointed_values USING GIN (data);
|
|
||||||
|
|
||||||
--create table "item_namespaces"(
|
|
||||||
--);
|
|
||||||
|
|
||||||
--create table "item"(
|
|
||||||
-- "category_id" int not null,
|
|
||||||
-- "symbol" text not null,
|
|
||||||
-- "original_symbol" text,
|
|
||||||
-- "producer" text,
|
|
||||||
-- "visibility" VARCHAR(64) DEFAULT 'global' not null,
|
|
||||||
-- "attributes" jsonb not null DEFAULT('{}'),
|
|
||||||
-- "description" TEXT,
|
|
||||||
-- constraint "pk_items" primary key ("id"),
|
|
||||||
-- constraint "fk_item_category" foreign key ("category_id") references "category"("id") on delete cascade deferrable initially immediate,
|
|
||||||
-- constraint "fk_item_auth_info" foreign key ("owner") REFERENCES "auth_info"("id") deferrable initially immediate
|
|
||||||
--) INHERITS (stat);
|
|
||||||
--create index "ix_item_attributes" on "item" USING GIN ("attributes");
|
|
||||||
--create unique index "ux_item" on "item"("name", "symbol");
|
|
||||||
--create trigger update_item_last_update before update on item FOR EACH ROW EXECUTE PROCEDURE last_update_column();
|
|
||||||
--comment on table "item" is '';
|
|
||||||
--comment on column "item"."category_id" is '';
|
|
||||||
--comment on column "item"."symbol" is '';
|
|
||||||
--comment on column "item"."original_symbol" is '';
|
|
||||||
--comment on column "item"."producer" is '';
|
|
||||||
--comment on column "item"."visibility" is '';
|
|
||||||
--comment on column "item"."attributes" is '';
|
|
||||||
--comment on column "item"."description" is '';
|
|
||||||
|
|
||||||
|
|
||||||
--create table "inventory"(
|
--create table "inventory"(
|
||||||
-- "description" TEXT check(length(description)< 100000),
|
-- "description" TEXT check(length(description)< 100000),
|
||||||
-- constraint "pk_inventory" primary key ("id"),
|
-- constraint "pk_inventory" primary key ("id"),
|
||||||
-- constraint "fk_inventory_owner" foreign key ("owner") REFERENCES "auth_info" ("id") deferrable initially immediate,
|
-- constraint "fk_inventory_owner" foreign key ("owner") references "auth_info" ("id") deferrable initially immediate,
|
||||||
-- constraint "chk_inventory_name_length" check (length(name) < 100)
|
-- constraint "chk_inventory_name_length" check (length(name) < 100)
|
||||||
--) INHERITS (stat);
|
--) inherits (stat);
|
||||||
--create trigger update_inventory_last_update before update on inventory FOR EACH ROW EXECUTE PROCEDURE last_update_column();
|
--create trigger update_inventory_last_update before update on inventory for each row execute PROCEDURE last_update_column();
|
||||||
|
|
||||||
|
|
||||||
--create table "user_inventory"(
|
--create table "user_inventory"(
|
||||||
-- "auth_info_id" INTEGER not null REFERENCES "auth_info" on DELETE CASCADE,
|
-- "auth_info_id" INTEGER not null references "auth_info" on DELETE CASCADE,
|
||||||
-- "inventory_id" INTEGER not null REFERENCES "inventory" on DELETE CASCADE,
|
-- "inventory_id" INTEGER not null references "inventory" on DELETE CASCADE,
|
||||||
-- constraint user_inventory_pk primary key ("inventory_id", "auth_info_id")
|
-- constraint user_inventory_pk primary key ("inventory_id", "auth_info_id")
|
||||||
--);
|
--);
|
||||||
|
|
||||||
|
|
||||||
--create table in_stock(
|
--create table in_stock(
|
||||||
-- item_id INTEGER not null REFERENCES items,
|
-- item_id INTEGER not null references items,
|
||||||
-- inventory_id INTEGER not null REFERENCES inventory,
|
-- inventory_id INTEGER not null references inventory,
|
||||||
-- amount numeric(10,10) not null DEFAULT 0
|
-- amount numeric(10,10) not null DEFAULT 0
|
||||||
--);
|
--);
|
||||||
|
|
||||||
--comment on table in_stock IS 'Table contains information about items being available in storage';
|
--comment on table in_stock IS 'Table contains information about items being available in storage';
|
||||||
|
|
||||||
--create table inventory_operations(
|
--create table inventory_operations(
|
||||||
-- constraint inventory_operations_pkey primary key (uid),
|
-- constraint inventory_operations_pkey primary key (uid),
|
||||||
-- constraint OperationOwner_fk foreign key (owner) REFERENCES users (uid) deferrable initially IMMEDIATE,
|
-- constraint OperationOwner_fk foreign key (owner) references users (uid) deferrable initially IMMEDIATE,
|
||||||
-- constraint inventory_operation_unique UNIQUE (name)
|
-- constraint inventory_operation_unique UNIQUE (name)
|
||||||
--) INHERITS(stat);
|
--) inherits(stat);
|
||||||
|
|
||||||
--create table inventory_history(
|
--create table inventory_history(
|
||||||
-- inventory_from_id INTEGER not null REFERENCES inventory on DELETE CASCADE,
|
-- inventory_from_id INTEGER not null references inventory on DELETE CASCADE,
|
||||||
-- inventory_to_id INTEGER not null REFERENCES inventory on DELETE CASCADE,
|
-- inventory_to_id INTEGER not null references inventory on DELETE CASCADE,
|
||||||
-- operation_id INTEGER not null REFERENCES inventory_Operations on DELETE CASCADE ,
|
-- operation_id INTEGER not null references inventory_Operations on DELETE CASCADE ,
|
||||||
-- amount NUMERIC(10,10),
|
-- amount NUMERIC(10,10),
|
||||||
|
|
||||||
-- date timestamp not null default now()
|
-- date timestamp not null default now()
|
||||||
@ -404,10 +390,10 @@ comment on column "category"."thumbnail" is '';
|
|||||||
-- create INDEX files_stat_index on files (uid, owner, group, unixperms, status) with ( FILLFACTOR=100 );
|
-- create INDEX files_stat_index on files (uid, owner, group, unixperms, status) with ( FILLFACTOR=100 );
|
||||||
-- create INDEX items_stat_index on items (uid, owner, group, unixperms, status) with ( FILLFACTOR=100 );
|
-- create INDEX items_stat_index on items (uid, owner, group, unixperms, status) with ( FILLFACTOR=100 );
|
||||||
|
|
||||||
-- create trigger update_parameters_last_update before update on parameters FOR EACH ROW EXECUTE PROCEDURE last_update_column();
|
-- create trigger update_parameters_last_update before update on parameters for each row execute PROCEDURE last_update_column();
|
||||||
-- create trigger update_files_last_update before update on files FOR EACH ROW EXECUTE PROCEDURE last_update_column();
|
-- create trigger update_files_last_update before update on files for each row execute PROCEDURE last_update_column();
|
||||||
-- create trigger update_packages_last_update before update on packages FOR EACH ROW EXECUTE PROCEDURE last_update_column();
|
-- create trigger update_packages_last_update before update on packages for each row execute PROCEDURE last_update_column();
|
||||||
-- create trigger update_units_last_update before update on units FOR EACH ROW EXECUTE PROCEDURE last_update_column();
|
-- create trigger update_units_last_update before update on units for each row execute PROCEDURE last_update_column();
|
||||||
-- create trigger update_items_last_update before update on items FOR EACH ROW EXECUTE PROCEDURE last_update_column();
|
-- create trigger update_items_last_update before update on items for each row execute PROCEDURE last_update_column();
|
||||||
-- create trigger update_shelfs_last_update before update on shelfs FOR EACH ROW EXECUTE PROCEDURE last_update_column();
|
-- create trigger update_shelfs_last_update before update on shelfs for each row execute PROCEDURE last_update_column();
|
||||||
-- create trigger update_inventory_operations_lats_update before update on inventory_operations FOR EACH ROW EXECUTE PROCEDURE last_update_column();
|
-- create trigger update_inventory_operations_lats_update before update on inventory_operations for each row execute PROCEDURE last_update_column();
|
||||||
|
|||||||
@ -2,5 +2,5 @@ project( eedb_app )
|
|||||||
INCLUDE_DIRECTORIES(.)
|
INCLUDE_DIRECTORIES(.)
|
||||||
|
|
||||||
add_subdirectory(utils)
|
add_subdirectory(utils)
|
||||||
add_subdirectory(eedb)
|
add_subdirectory(libs)
|
||||||
add_subdirectory(app)
|
add_subdirectory(app)
|
||||||
|
|||||||
@ -1,20 +1,18 @@
|
|||||||
set(SOURCES
|
#set(SOURCES
|
||||||
main.cpp)
|
# main.cpp)
|
||||||
|
|
||||||
add_executable(eedb ${SOURCES} )
|
#add_executable(eedb_app ${SOURCES})
|
||||||
|
|
||||||
include_directories( ${PostgreSQL_INCLUDE_DIRS} )
|
#target_link_libraries(eedb_app
|
||||||
|
# wthttp # or {Wt_HTTP_DEBUG_LIBRARY}
|
||||||
target_link_libraries(eedb
|
# wt # or {Wt_DEBUG_LIBRARY}
|
||||||
wthttp # or {Wt_HTTP_DEBUG_LIBRARY}
|
# postgresql_connector
|
||||||
wt # or {Wt_DEBUG_LIBRARY}
|
# auth
|
||||||
eedb_db
|
# eedb
|
||||||
eedb_auth
|
# Boost::system
|
||||||
eedb_app
|
# Boost::filesystem
|
||||||
Boost::system
|
# Boost::thread
|
||||||
Boost::filesystem
|
# Boost::program_options
|
||||||
Boost::thread
|
# z
|
||||||
Boost::program_options
|
# )
|
||||||
z
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
file(GLOB AUTH_SOURCE auth/* )
|
|
||||||
|
|
||||||
file(GLOB SOURCE
|
|
||||||
EEDB.cpp
|
|
||||||
WebSession.cpp
|
|
||||||
|
|
||||||
data/*
|
|
||||||
widgets/*
|
|
||||||
)
|
|
||||||
|
|
||||||
include_directories(${CMAKE_BINARY_DIR}/external/include SYSTEM)
|
|
||||||
|
|
||||||
include_directories( ${PostgreSQL_INCLUDE_DIRS} )
|
|
||||||
add_subdirectory(db)
|
|
||||||
|
|
||||||
add_library(eedb_auth ${AUTH_SOURCE})
|
|
||||||
target_link_libraries(eedb_auth PUBLIC nlohmann_json)
|
|
||||||
set_target_properties(eedb_auth PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
|
||||||
cotire(eedb_auth)
|
|
||||||
|
|
||||||
add_library(eedb_app ${SOURCE})
|
|
||||||
target_link_libraries(eedb_app PUBLIC eedb_auth)
|
|
||||||
set_target_properties(eedb_app PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
|
||||||
cotire(eedb_app)
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
set(SOURCE
|
|
||||||
data/PgAuthToken.cpp
|
|
||||||
data/PgAuthIdentity.cpp
|
|
||||||
data/PgCategory.cpp
|
|
||||||
data/PgCategories.cpp
|
|
||||||
data/PgCategoriesRepository.cpp
|
|
||||||
data/PgUser.cpp
|
|
||||||
data/PgUsers.cpp
|
|
||||||
|
|
||||||
connection.cpp
|
|
||||||
config.cpp
|
|
||||||
RawSql.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
file(GLOB INCLUDES
|
|
||||||
*.h*
|
|
||||||
data/*.hpp
|
|
||||||
)
|
|
||||||
|
|
||||||
file(GLOB MODEL
|
|
||||||
model/*
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library(eedb_db ${SOURCE} ${MODEL} ${INCLUDES})
|
|
||||||
target_link_libraries(eedb_db sqlpp-postgresql)
|
|
||||||
|
|
||||||
set_target_properties(eedb_db PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
|
||||||
cotire(eedb_db)
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <eedb/db/model/auth_identity.h>
|
|
||||||
#include <eedb/db/model/auth_info.h>
|
|
||||||
#include <eedb/db/model/auth_token.h>
|
|
||||||
#include <eedb/db/model/category.h>
|
|
||||||
#include <eedb/db/model/group.h>
|
|
||||||
#include <eedb/db/model/stat.h>
|
|
||||||
#include <eedb/db/model/system_info.h>
|
|
||||||
#include <eedb/db/model/user_audit.h>
|
|
||||||
|
|
||||||
constexpr eedb::user_audit t_user_audit;
|
|
||||||
constexpr eedb::auth_identity t_auth_identity;
|
|
||||||
constexpr eedb::auth_info t_auth_info;
|
|
||||||
constexpr eedb::auth_token t_auth_token;
|
|
||||||
constexpr eedb::group t_group;
|
|
||||||
constexpr eedb::category t_category;
|
|
||||||
7
src/libs/CMakeLists.txt
Normal file
7
src/libs/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
add_subdirectory(eedb)
|
||||||
|
|
||||||
|
add_subdirectory(db)
|
||||||
|
|
||||||
|
add_subdirectory(auth)
|
||||||
|
|
||||||
|
add_subdirectory(widgets)
|
||||||
18
src/libs/auth/CMakeLists.txt
Normal file
18
src/libs/auth/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
set(LIB auth)
|
||||||
|
|
||||||
|
file(GLOB auth_SOURCE src/*)
|
||||||
|
|
||||||
|
# find packages
|
||||||
|
find_package(nlohmann_json CONFIG REQUIRED)
|
||||||
|
|
||||||
|
# create library
|
||||||
|
add_library(${LIB} ${auth_SOURCE})
|
||||||
|
|
||||||
|
# link all
|
||||||
|
target_include_directories(${LIB} PUBLIC include)
|
||||||
|
target_link_libraries(${LIB} PRIVATE eedb)
|
||||||
|
target_link_libraries(${LIB} PUBLIC nlohmann_json)
|
||||||
|
|
||||||
|
# add cotire
|
||||||
|
set_target_properties(${LIB} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
||||||
|
cotire(${LIB})
|
||||||
@ -1,4 +1,4 @@
|
|||||||
#include "PgUserAuth.hpp"
|
#include <eedb/auth/PgUserAuth.hpp>
|
||||||
|
|
||||||
#include <eedb/auth/Services.hpp>
|
#include <eedb/auth/Services.hpp>
|
||||||
#include <eedb/data/AuthIdentities.hpp>
|
#include <eedb/data/AuthIdentities.hpp>
|
||||||
1
src/libs/db/CMakeLists.txt
Normal file
1
src/libs/db/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
add_subdirectory(postgresql_connector)
|
||||||
24
src/libs/db/postgresql_connector/CMakeLists.txt
Normal file
24
src/libs/db/postgresql_connector/CMakeLists.txt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
set(LIB postgres_connector)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE postgres_connector_SOURCE src/*)
|
||||||
|
|
||||||
|
# find packages
|
||||||
|
find_package(nlohmann_json CONFIG REQUIRED)
|
||||||
|
|
||||||
|
# create library
|
||||||
|
add_library(${LIB} ${postgres_connector_SOURCE})
|
||||||
|
|
||||||
|
# link all
|
||||||
|
target_include_directories(${LIB} PRIVATE ${CMAKE_BINARY_DIR}/external/include SYSTEM)
|
||||||
|
target_include_directories(${LIB} PRIVATE ${PostgreSQL_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
target_include_directories(${LIB} PUBLIC include)
|
||||||
|
target_link_libraries(${LIB} PUBLIC nlohmann_json)
|
||||||
|
target_link_libraries(${LIB} PRIVATE eedb)
|
||||||
|
target_link_libraries(${LIB} PRIVATE sqlpp-postgresql)
|
||||||
|
|
||||||
|
# add cotire
|
||||||
|
set_target_properties(${LIB} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
||||||
|
cotire(${LIB})
|
||||||
|
|
||||||
|
add_subdirectory(test)
|
||||||
@ -21,6 +21,6 @@ class PgConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr< sqlpp::postgresql::connection > _conn;\
|
std::unique_ptr< sqlpp::postgresql::connection > _conn;
|
||||||
};
|
};
|
||||||
} // namespace eedb::db
|
} // namespace eedb::db
|
||||||
@ -29,8 +29,9 @@ class PgCategory : public Category {
|
|||||||
|
|
||||||
std::unique_ptr< Categories > children() const override;
|
std::unique_ptr< Categories > children() const override;
|
||||||
|
|
||||||
bool detached() const override;
|
// bool detached() const override;
|
||||||
std::unique_ptr< Category > create(std::string name, std::string description, std::optional< path > image = {}) const override;
|
|
||||||
|
std::unique_ptr< Category > create(std::string name, std::string description) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace eedb
|
} // namespace eedb
|
||||||
17
src/libs/db/postgresql_connector/include/model/all.hpp
Normal file
17
src/libs/db/postgresql_connector/include/model/all.hpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <model/auth_identity.h>
|
||||||
|
#include <model/auth_info.h>
|
||||||
|
#include <model/auth_token.h>
|
||||||
|
#include <model/category.h>
|
||||||
|
#include <model/group.h>
|
||||||
|
#include <model/stat.h>
|
||||||
|
#include <model/system_info.h>
|
||||||
|
#include <model/user_audit.h>
|
||||||
|
|
||||||
|
constexpr eedb::user_audit t_user_audit;
|
||||||
|
constexpr eedb::auth_identity t_auth_identity;
|
||||||
|
constexpr eedb::auth_info t_auth_info;
|
||||||
|
constexpr eedb::auth_token t_auth_token;
|
||||||
|
constexpr eedb::group t_group;
|
||||||
|
constexpr eedb::category t_category;
|
||||||
@ -1,9 +1,9 @@
|
|||||||
#include <eedb/db/RawSql.hpp>
|
#include <RawSql.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include <eedb/db/connection.hpp>
|
#include <connection.hpp>
|
||||||
#include <sqlpp11/sqlpp11.h>
|
#include <sqlpp11/sqlpp11.h>
|
||||||
|
|
||||||
namespace eedb::db{
|
namespace eedb::db{
|
||||||
@ -1,4 +1,4 @@
|
|||||||
#include <eedb/db/config.hpp>
|
#include "config.hpp"
|
||||||
|
|
||||||
#include <Wt/WEnvironment.h>
|
#include <Wt/WEnvironment.h>
|
||||||
#include <Wt/WServer.h>
|
#include <Wt/WServer.h>
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#include <eedb/db/config.hpp>
|
#include "config.hpp"
|
||||||
#include <eedb/db/connection.hpp>
|
#include "connection.hpp"
|
||||||
|
|
||||||
namespace eedb::db {
|
namespace eedb::db {
|
||||||
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
#include <eedb/db/data/PgAuthIdentity.hpp>
|
#include "data/PgAuthIdentity.hpp"
|
||||||
|
|
||||||
#include <eedb/data/User.hpp>
|
#include <eedb/data/User.hpp>
|
||||||
#include <eedb/db/connection.hpp>
|
#include <connection.hpp>
|
||||||
#include <eedb/db/model/auth_identity.h>
|
#include <model/auth_identity.h>
|
||||||
|
|
||||||
#include <sqlpp11/postgresql/exception.h>
|
#include <sqlpp11/postgresql/exception.h>
|
||||||
#include <sqlpp11/sqlpp11.h>
|
#include <sqlpp11/sqlpp11.h>
|
||||||
46
src/libs/db/postgresql_connector/src/data/PgAuthIdentity.hpp
Normal file
46
src/libs/db/postgresql_connector/src/data/PgAuthIdentity.hpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <eedb/data/AuthIdentity.hpp>
|
||||||
|
#include <eedb/data/AuthIdentities.hpp>
|
||||||
|
|
||||||
|
#include <utils/spimpl.hpp>
|
||||||
|
|
||||||
|
namespace eedb {
|
||||||
|
class User;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace eedb::db {
|
||||||
|
class PgConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace eedb {
|
||||||
|
class PgAuthIdentity final : public AuthIdentity {
|
||||||
|
public:
|
||||||
|
PgAuthIdentity(db::PgConnection & db, std::string identity, std::string provider);
|
||||||
|
// PgAuthIdentity(db::PgConnection & db, nlohmann::json data);
|
||||||
|
|
||||||
|
string_view identity() const override;
|
||||||
|
|
||||||
|
string_view provider() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PgAuthIdentityPriv;
|
||||||
|
spimpl::unique_impl_ptr< PgAuthIdentityPriv > _priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PgAuthIdentities final : public AuthIdentities {
|
||||||
|
public:
|
||||||
|
PgAuthIdentities(db::PgConnection & db, const User * owner);
|
||||||
|
// PgAuthIdentities(db::PgConnection & db, nlohmann::json data);
|
||||||
|
|
||||||
|
AuthIdentity * addIdentity(std::unique_ptr< AuthIdentity > identity) override;
|
||||||
|
|
||||||
|
AuthIdentity * byProvider(std::string_view provider) const override;
|
||||||
|
|
||||||
|
void removeProvider(std::string_view provider) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PgAuthIdentitysPriv;
|
||||||
|
spimpl::unique_impl_ptr< PgAuthIdentitysPriv > _priv;
|
||||||
|
};
|
||||||
|
} // namespace eedb
|
||||||
@ -1,9 +1,9 @@
|
|||||||
#include <eedb/db/data/PgAuthToken.hpp>
|
#include <data/PgAuthToken.hpp>
|
||||||
|
|
||||||
#include <eedb/data/User.hpp>
|
#include <eedb/data/User.hpp>
|
||||||
|
|
||||||
#include <eedb/db/connection.hpp>
|
#include <connection.hpp>
|
||||||
#include <eedb/db/model/auth_token.h>
|
#include <model/auth_token.h>
|
||||||
|
|
||||||
#include <utils/Visitor.hpp>
|
#include <utils/Visitor.hpp>
|
||||||
|
|
||||||
52
src/libs/db/postgresql_connector/src/data/PgAuthToken.hpp
Normal file
52
src/libs/db/postgresql_connector/src/data/PgAuthToken.hpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <eedb/data/AuthToken.hpp>
|
||||||
|
#include <eedb/data/AuthTokens.hpp>
|
||||||
|
|
||||||
|
#include <utils/spimpl.hpp>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace eedb {
|
||||||
|
class User;
|
||||||
|
}
|
||||||
|
namespace eedb::db {
|
||||||
|
class PgConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace eedb {
|
||||||
|
|
||||||
|
class PgAuthToken final : public AuthToken {
|
||||||
|
// AuthToken interface
|
||||||
|
public:
|
||||||
|
PgAuthToken(db::PgConnection & con, int64_t uid);
|
||||||
|
PgAuthToken(db::PgConnection & con, int64_t uid, std::string hash, us_point expirationtime);
|
||||||
|
|
||||||
|
std::string_view token() const override;
|
||||||
|
|
||||||
|
us_point expireTimepoint() const override;
|
||||||
|
|
||||||
|
bool expired() const override;
|
||||||
|
|
||||||
|
void update(std::string newHash) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PgAuthTokenPriv;
|
||||||
|
spimpl::unique_impl_ptr< PgAuthTokenPriv > _priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PgAuthTokens final : public AuthTokens {
|
||||||
|
public:
|
||||||
|
PgAuthTokens(db::PgConnection & con, const User * owner);
|
||||||
|
|
||||||
|
AuthToken * find(std::variant< std::string_view, AuthTokenRole > token) const override;
|
||||||
|
|
||||||
|
void removeToken(std::string_view token) override;
|
||||||
|
|
||||||
|
AuthToken * addToken(std::string hash, AuthTokenRole role) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PgAuthTokensPriv;
|
||||||
|
spimpl::unique_impl_ptr< PgAuthTokensPriv > _priv;
|
||||||
|
};
|
||||||
|
} // namespace eedb
|
||||||
@ -1,9 +1,9 @@
|
|||||||
#include <eedb/db/data/PgCategories.hpp>
|
#include "data/PgCategories.hpp"
|
||||||
|
|
||||||
#include <eedb/db/data/PgCategory.hpp>
|
#include <data/PgCategory.hpp>
|
||||||
|
|
||||||
#include <eedb/db/connection.hpp>
|
#include <connection.hpp>
|
||||||
#include <eedb/db/model/all.hpp>
|
#include <model/all.hpp>
|
||||||
|
|
||||||
#include <boost/iterator/transform_iterator.hpp>
|
#include <boost/iterator/transform_iterator.hpp>
|
||||||
|
|
||||||
28
src/libs/db/postgresql_connector/src/data/PgCategories.hpp
Normal file
28
src/libs/db/postgresql_connector/src/data/PgCategories.hpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <eedb/data/Category.hpp>
|
||||||
|
|
||||||
|
#include <utils/spimpl.hpp>
|
||||||
|
|
||||||
|
namespace eedb::db{
|
||||||
|
class PgConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace eedb {
|
||||||
|
class PgCategory;
|
||||||
|
|
||||||
|
class PgCategories : public Categories {
|
||||||
|
// Categories interface
|
||||||
|
public:
|
||||||
|
PgCategories(std::vector<std::unique_ptr<eedb::PgCategory> > &&data);
|
||||||
|
|
||||||
|
long size() const override;
|
||||||
|
|
||||||
|
Iterable begin() const override;
|
||||||
|
Iterable end() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PgCategoriesPriv;
|
||||||
|
spimpl::unique_impl_ptr< PgCategoriesPriv > _priv;
|
||||||
|
};
|
||||||
|
} // namespace eedb
|
||||||
@ -1,9 +1,9 @@
|
|||||||
#include <eedb/db/data/PgCategoriesRepository.hpp>
|
#include <data/PgCategoriesRepository.hpp>
|
||||||
|
|
||||||
#include <eedb/db/data/PgCategory.hpp>
|
#include <data/PgCategory.hpp>
|
||||||
|
|
||||||
#include <eedb/db/connection.hpp>
|
#include <connection.hpp>
|
||||||
#include <eedb/db/model/all.hpp>
|
#include <model/all.hpp>
|
||||||
|
|
||||||
namespace eedb {
|
namespace eedb {
|
||||||
struct PgCategoriesRepository::PgCategoriesRepositoryPriv {
|
struct PgCategoriesRepository::PgCategoriesRepositoryPriv {
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <eedb/data/Category.hpp>
|
||||||
|
|
||||||
|
#include <utils/spimpl.hpp>
|
||||||
|
|
||||||
|
namespace eedb::db {
|
||||||
|
class PgConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace eedb{
|
||||||
|
class User;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace eedb {
|
||||||
|
class PgCategoriesRepository : public CategoriesRepository {
|
||||||
|
public:
|
||||||
|
// CategoriesRepository interface
|
||||||
|
public:
|
||||||
|
PgCategoriesRepository(db::PgConnection & db, User * owner);
|
||||||
|
|
||||||
|
std::unique_ptr< Category > root() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PgCategoriesRepositoryPriv;
|
||||||
|
spimpl::unique_impl_ptr< PgCategoriesRepositoryPriv > _priv;
|
||||||
|
};
|
||||||
|
} // namespace eedb
|
||||||
@ -1,8 +1,8 @@
|
|||||||
#include <eedb/db/data/PgCategory.hpp>
|
#include <data/PgCategory.hpp>
|
||||||
|
|
||||||
#include <eedb/db/connection.hpp>
|
#include <connection.hpp>
|
||||||
#include <eedb/db/data/PgCategories.hpp>
|
#include <data/PgCategories.hpp>
|
||||||
#include <eedb/db/model/all.hpp>
|
#include <model/all.hpp>
|
||||||
|
|
||||||
#include <eedb/data/User.hpp>
|
#include <eedb/data/User.hpp>
|
||||||
|
|
||||||
@ -49,12 +49,15 @@ struct PgCategory::PgCategoryPrivate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PgCategoryPrivate(db::PgConnection & db, User * owner, Category * parent) : _db{db}, _owner{owner}, _self{parent} {
|
Category * _self{nullptr};
|
||||||
|
|
||||||
|
PgCategoryPrivate(db::PgConnection & db, User * owner, Category * parent) : _db{db}, _owner{owner}, _parent{parent} {
|
||||||
auto row = _db(select(columns()).from(table_list()).where(root_path_match()).limit(0ul));
|
auto row = _db(select(columns()).from(table_list()).where(root_path_match()).limit(0ul));
|
||||||
if(row.empty()){
|
if(row.empty()) {
|
||||||
// no root category
|
// no root category
|
||||||
row = _db(sqlpp::postgresql::insert_into(t_category)
|
row = _db(sqlpp::postgresql::insert_into(t_category)
|
||||||
.set(t_category.owner = _owner->uid(),
|
.set( //
|
||||||
|
t_category.owner = _owner->uid(),
|
||||||
t_category.status = 0,
|
t_category.status = 0,
|
||||||
t_category.parent_id = sqlpp::null,
|
t_category.parent_id = sqlpp::null,
|
||||||
t_category.name = "root",
|
t_category.name = "root",
|
||||||
@ -80,15 +83,13 @@ struct PgCategory::PgCategoryPrivate {
|
|||||||
return _parent == nullptr && _path != "root";
|
return _parent == nullptr && _path != "root";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto create(std::string name, std::string description, std::optional< Category::path > image) const {
|
auto create(std::string name, std::string description) const {
|
||||||
/// TODO test if image exists on hdd
|
|
||||||
const auto & row = _db(sqlpp::postgresql::insert_into(t_category)
|
const auto & row = _db(sqlpp::postgresql::insert_into(t_category)
|
||||||
.set(t_category.owner = _owner->uid(),
|
.set(t_category.owner = _owner->uid(),
|
||||||
t_category.status = 0,
|
t_category.status = 0,
|
||||||
t_category.parent_id = _uid,
|
t_category.parent_id = _uid,
|
||||||
t_category.name = name,
|
t_category.name = name,
|
||||||
t_category.description = description,
|
t_category.description = description) //
|
||||||
t_category.thumbnail = image.value_or("")) //
|
|
||||||
.returning(columns()))
|
.returning(columns()))
|
||||||
.front();
|
.front();
|
||||||
|
|
||||||
@ -97,6 +98,10 @@ struct PgCategory::PgCategoryPrivate {
|
|||||||
return std::make_unique< PgCategory >(std::move(priv));
|
return std::make_unique< PgCategory >(std::move(priv));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto parent() const {
|
||||||
|
return _parent;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
template < typename Row >
|
template < typename Row >
|
||||||
void init_data(Row & row) {
|
void init_data(Row & row) {
|
||||||
@ -111,33 +116,36 @@ struct PgCategory::PgCategoryPrivate {
|
|||||||
User * _owner;
|
User * _owner;
|
||||||
|
|
||||||
int64_t _uid{};
|
int64_t _uid{};
|
||||||
Category * _self{nullptr};
|
|
||||||
Category * _parent{nullptr};
|
Category * _parent{nullptr};
|
||||||
std::string _name;
|
std::string _name;
|
||||||
std::string _path;
|
std::string _path;
|
||||||
std::string _description;
|
std::string _description;
|
||||||
};
|
};
|
||||||
|
|
||||||
PgCategory::PgCategory(db::PgConnection & db, User * user) : _priv{spimpl::make_impl< PgCategoryPrivate >(db, user, this)} {}
|
PgCategory::PgCategory(db::PgConnection & db, User * user) : _priv{spimpl::make_impl< PgCategoryPrivate >(db, user, nullptr)} {
|
||||||
|
_priv->_self = this;
|
||||||
|
}
|
||||||
|
|
||||||
PgCategory::PgCategory(spimpl::impl_ptr< PgCategoryPrivate > priv) : _priv{std::move(priv)} {}
|
PgCategory::PgCategory(spimpl::impl_ptr< PgCategoryPrivate > priv) : _priv{std::move(priv)} {
|
||||||
|
_priv->_self = this;
|
||||||
|
}
|
||||||
|
|
||||||
Category::string_view PgCategory::displayName() const {}
|
Category::string_view PgCategory::displayName() const {}
|
||||||
|
|
||||||
Category * PgCategory::parent() const {
|
Category * PgCategory::parent() const {
|
||||||
return nullptr;
|
return _priv->parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr< Categories > PgCategory::children() const {
|
std::unique_ptr< Categories > PgCategory::children() const {
|
||||||
return std::make_unique< PgCategories >(_priv->categories());
|
return std::make_unique< PgCategories >(_priv->categories());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PgCategory::detached() const {
|
// bool PgCategory::detached() const {
|
||||||
return _priv->detached();
|
// return _priv->detached();
|
||||||
}
|
//}
|
||||||
|
|
||||||
std::unique_ptr< Category > PgCategory::create(std::string name, std::string description, std::optional< Category::path > image) const {
|
std::unique_ptr< Category > PgCategory::create(std::string name, std::string description) const {
|
||||||
return _priv->create(std::move(name), std::move(description), std::move(image));
|
return _priv->create(std::move(name), std::move(description));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace eedb
|
} // namespace eedb
|
||||||
37
src/libs/db/postgresql_connector/src/data/PgCategory.hpp
Normal file
37
src/libs/db/postgresql_connector/src/data/PgCategory.hpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <eedb/data/Category.hpp>
|
||||||
|
|
||||||
|
#include <utils/spimpl.hpp>
|
||||||
|
|
||||||
|
namespace eedb::db {
|
||||||
|
class PgConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace eedb {
|
||||||
|
class User;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace eedb {
|
||||||
|
|
||||||
|
class PgCategory : public Category {
|
||||||
|
private:
|
||||||
|
struct PgCategoryPrivate;
|
||||||
|
spimpl::impl_ptr< PgCategoryPrivate > _priv;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PgCategory(db::PgConnection & db, User * user);
|
||||||
|
PgCategory(spimpl::impl_ptr<PgCategoryPrivate> priv);
|
||||||
|
|
||||||
|
string_view displayName() const override;
|
||||||
|
|
||||||
|
Category * parent() const override;
|
||||||
|
|
||||||
|
std::unique_ptr< Categories > children() const override;
|
||||||
|
|
||||||
|
// bool detached() const override;
|
||||||
|
|
||||||
|
std::unique_ptr< Category > create(std::string name, std::string description) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace eedb
|
||||||
@ -1,12 +1,12 @@
|
|||||||
#include <eedb/db/data/PgUser.hpp>
|
#include <data/PgUser.hpp>
|
||||||
|
|
||||||
#include <eedb/db/connection.hpp>
|
#include <connection.hpp>
|
||||||
#include <eedb/db/data/PgAuthIdentity.hpp>
|
#include <data/PgAuthIdentity.hpp>
|
||||||
#include <eedb/db/data/PgAuthToken.hpp>
|
#include <data/PgAuthToken.hpp>
|
||||||
|
|
||||||
#include <eedb/data/AuthInfoConst.hpp>
|
#include <eedb/data/AuthInfoConst.hpp>
|
||||||
|
|
||||||
#include <eedb/db/model/all.hpp>
|
#include <model/all.hpp>
|
||||||
|
|
||||||
#include <sqlpp11/sqlpp11.h>
|
#include <sqlpp11/sqlpp11.h>
|
||||||
|
|
||||||
37
src/libs/db/postgresql_connector/src/data/PgUser.hpp
Normal file
37
src/libs/db/postgresql_connector/src/data/PgUser.hpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <eedb/data/User.hpp>
|
||||||
|
|
||||||
|
#include <eedb/data/AuthInfo.hpp>
|
||||||
|
|
||||||
|
#include <utils/spimpl.hpp>
|
||||||
|
|
||||||
|
namespace eedb::db {
|
||||||
|
class PgConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace eedb {
|
||||||
|
|
||||||
|
class PgUser : public User {
|
||||||
|
public:
|
||||||
|
PgUser(db::PgConnection & db, int uid);
|
||||||
|
|
||||||
|
int uid() const override;
|
||||||
|
|
||||||
|
const UserName & name() const override;
|
||||||
|
|
||||||
|
const UserConfig & config() const override;
|
||||||
|
|
||||||
|
void logout() override;
|
||||||
|
|
||||||
|
AuthTokens & authTokens() const override;
|
||||||
|
|
||||||
|
AuthIdentities & authIdentities() const override;
|
||||||
|
|
||||||
|
AuthInfo & authInfo() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PgUserPriv;
|
||||||
|
spimpl::unique_impl_ptr< PgUserPriv > _priv;
|
||||||
|
};
|
||||||
|
} // namespace eedb
|
||||||
@ -1,16 +1,16 @@
|
|||||||
#include <eedb/db/data/PgUsers.hpp>
|
#include <data/PgUsers.hpp>
|
||||||
|
|
||||||
#include <eedb/db/data/PgUser.hpp>
|
#include <data/PgUser.hpp>
|
||||||
|
|
||||||
#include <eedb/data/AuthIdentity.hpp>
|
#include <eedb/data/AuthIdentity.hpp>
|
||||||
#include <eedb/data/AuthToken.hpp>
|
#include <eedb/data/AuthToken.hpp>
|
||||||
#include <eedb/data/Email.hpp>
|
#include <eedb/data/Email.hpp>
|
||||||
#include <eedb/data/Password.hpp>
|
#include <eedb/data/Password.hpp>
|
||||||
|
|
||||||
#include <eedb/db/connection.hpp>
|
#include <connection.hpp>
|
||||||
#include <eedb/db/model/auth_identity.h>
|
#include <model/auth_identity.h>
|
||||||
#include <eedb/db/model/auth_info.h>
|
#include <model/auth_info.h>
|
||||||
#include <eedb/db/model/auth_token.h>
|
#include <model/auth_token.h>
|
||||||
|
|
||||||
#include <sqlpp11/sqlpp11.h>
|
#include <sqlpp11/sqlpp11.h>
|
||||||
|
|
||||||
31
src/libs/db/postgresql_connector/src/data/PgUsers.hpp
Normal file
31
src/libs/db/postgresql_connector/src/data/PgUsers.hpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <eedb/data/Users.hpp>
|
||||||
|
|
||||||
|
#include <utils/spimpl.hpp>
|
||||||
|
|
||||||
|
namespace eedb::db {
|
||||||
|
class PgConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace eedb {
|
||||||
|
class PgUsers : public Users {
|
||||||
|
// Users interface
|
||||||
|
public:
|
||||||
|
PgUsers(eedb::db::PgConnection & db);
|
||||||
|
|
||||||
|
unique_ptr< User > findWith(int64_t uid) const override;
|
||||||
|
unique_ptr< User > findWith(const AuthIdentity & name) const override;
|
||||||
|
unique_ptr< User > findWith(const Email & email) const override;
|
||||||
|
unique_ptr< User > findWith(const EmailToken & token) const override;
|
||||||
|
unique_ptr< User > findWith(const AuthToken & token) const override;
|
||||||
|
|
||||||
|
// unique_ptr< User > createRoot();
|
||||||
|
unique_ptr< User > addUser(unique_ptr< AuthInfo >, unique_ptr< AuthIdentity >) override;
|
||||||
|
void removeUser(std::unique_ptr< User > user) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PgUsersPriv;
|
||||||
|
spimpl::unique_impl_ptr< PgUsersPriv > _priv;
|
||||||
|
};
|
||||||
|
} // namespace eedb
|
||||||
7
src/libs/db/postgresql_connector/src/data/Stats.hpp
Normal file
7
src/libs/db/postgresql_connector/src/data/Stats.hpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace eedb::details {
|
||||||
|
|
||||||
|
template < typename Row, typename Data >
|
||||||
|
auto readStats(Data & data, Row & row) {}
|
||||||
|
} // namespace eedb::details
|
||||||
15
src/libs/db/postgresql_connector/test/CMakeLists.txt
Normal file
15
src/libs/db/postgresql_connector/test/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.0.2)
|
||||||
|
|
||||||
|
#project(Tests LANGUAGES CXX)
|
||||||
|
|
||||||
|
find_package(GMock CONFIG REQUIRED)
|
||||||
|
|
||||||
|
set(TEST_EXECUTABLE_NAME postgres_connector-test )
|
||||||
|
|
||||||
|
#add test files
|
||||||
|
file(GLOB_RECURSE TEST_FILES test_*.cpp )
|
||||||
|
|
||||||
|
add_executable( ${TEST_EXECUTABLE_NAME} ${TEST_FILES})
|
||||||
|
target_link_libraries(${TEST_EXECUTABLE_NAME} GMock::main eedb postgres_connector)
|
||||||
|
|
||||||
|
add_test( ${TEST_EXECUTABLE_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TEST_EXECUTABLE_NAME})
|
||||||
@ -1,8 +1,8 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
#include <eedb/db/RawSql.hpp>
|
#include <RawSql.hpp>
|
||||||
#include <eedb/db/config.hpp>
|
#include <config.hpp>
|
||||||
#include <eedb/db/connection.hpp>
|
#include <connection.hpp>
|
||||||
#include <sqlpp11/postgresql/exception.h>
|
#include <sqlpp11/postgresql/exception.h>
|
||||||
|
|
||||||
#include <boost/process.hpp>
|
#include <boost/process.hpp>
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
#include <data/PgAuthIdentity.hpp>
|
||||||
|
|
||||||
|
#include <eedb/data/AuthIdentityConst.hpp>
|
||||||
|
#include <eedb/data/User.hpp>
|
||||||
|
#include <eedb/data/Users.hpp>
|
||||||
|
|
||||||
|
#include <model/all.hpp>
|
||||||
|
#include <sqlpp11/sqlpp11.h>
|
||||||
|
|
||||||
|
#include "DbTestBase.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class UserMock : public eedb::User {
|
||||||
|
public:
|
||||||
|
MOCK_CONST_METHOD0(uid, int());
|
||||||
|
const eedb::UserName & name() const {}
|
||||||
|
const eedb::UserConfig & config() const override {}
|
||||||
|
eedb::AuthTokens & authTokens() const override {}
|
||||||
|
void logout() override {}
|
||||||
|
eedb::AuthIdentities & authIdentities() const {}
|
||||||
|
int64_t _uid;
|
||||||
|
|
||||||
|
// User interface
|
||||||
|
public:
|
||||||
|
eedb::AuthInfo & authInfo() const override {}
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
class PgAuthIdentitiesTest : public DbTestBase< PgAuthIdentitiesTest > {
|
||||||
|
public:
|
||||||
|
PgAuthIdentitiesTest() {
|
||||||
|
using namespace testing;
|
||||||
|
db().native()->start_transaction();
|
||||||
|
|
||||||
|
authInfoId = db()(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 = "none@eedb.pl", //
|
||||||
|
t_auth_info.status = 0)
|
||||||
|
.returning(t_auth_info.id))
|
||||||
|
.front()
|
||||||
|
.id;
|
||||||
|
|
||||||
|
EXPECT_CALL(user, uid()).WillRepeatedly(testing::Return(authInfoId));
|
||||||
|
sut = std::make_unique< eedb::PgAuthIdentities >(db(), &user);
|
||||||
|
}
|
||||||
|
|
||||||
|
void createIdentity(const eedb::AuthIdentityConst id) {
|
||||||
|
db()(insert_into(t_auth_identity) //
|
||||||
|
.set(t_auth_identity.auth_info_id = authInfoId,
|
||||||
|
t_auth_identity.provider = std::string{id.provider()},
|
||||||
|
t_auth_identity.identity = std::string{id.identity()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
~PgAuthIdentitiesTest() {
|
||||||
|
db().native()->rollback_transaction(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
UserMock user;
|
||||||
|
int64_t authInfoId{0};
|
||||||
|
std::unique_ptr< eedb::PgAuthIdentities > sut;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::unique_ptr< PgTestDatabasePrepare > DbTestBase< PgAuthIdentitiesTest >::_test_db = {};
|
||||||
|
|
||||||
|
using namespace sqlpp;
|
||||||
|
using namespace eedb;
|
||||||
|
|
||||||
|
TEST_F(PgAuthIdentitiesTest, searchForFalseIdentity) {
|
||||||
|
EXPECT_FALSE(sut->byProvider("nonexisting"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgAuthIdentitiesTest, findIdentity) {
|
||||||
|
createIdentity({"identity", "provider"});
|
||||||
|
EXPECT_TRUE(sut->byProvider("provider"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgAuthIdentitiesTest, addProvider) {
|
||||||
|
sut->addIdentity(std::make_unique< AuthIdentityConst >("identity2", "provider"));
|
||||||
|
EXPECT_TRUE(sut->byProvider("provider"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgAuthIdentitiesTest, removeIdentity) {
|
||||||
|
createIdentity({"identity", "provider"});
|
||||||
|
sut->removeProvider("provider");
|
||||||
|
EXPECT_FALSE(sut->byProvider("provider"));
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
#include <data/PgAuthIdentity.hpp>
|
||||||
|
|
||||||
|
#include "DbTestBase.hpp"
|
||||||
|
|
||||||
|
class PgAuthIdentityTest : public DbTestBase< PgAuthIdentityTest > {
|
||||||
|
public:
|
||||||
|
PgAuthIdentityTest() {
|
||||||
|
using namespace testing;
|
||||||
|
db().native()->start_transaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
void initCached() {
|
||||||
|
sut = std::make_unique< eedb::PgAuthIdentity >(db(), "identity", "provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
~PgAuthIdentityTest() {
|
||||||
|
db().native()->rollback_transaction(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unique_ptr< eedb::PgAuthIdentity > sut;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::unique_ptr< PgTestDatabasePrepare > DbTestBase< PgAuthIdentityTest >::_test_db = {};
|
||||||
|
|
||||||
|
using namespace sqlpp;
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
TEST_F(PgAuthIdentityTest, hasIdentity) {
|
||||||
|
initCached();
|
||||||
|
EXPECT_TRUE(sut->identity() == "identity");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgAuthIdentityTest, hasProvider) {
|
||||||
|
initCached();
|
||||||
|
EXPECT_TRUE(sut->provider() == "provider");
|
||||||
|
}
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
#include <data/PgAuthToken.hpp>
|
||||||
|
|
||||||
|
#include <eedb/data/AuthIdentity.hpp>
|
||||||
|
#include <eedb/data/Users.hpp>
|
||||||
|
|
||||||
|
#include <model/all.hpp>
|
||||||
|
#include <sqlpp11/sqlpp11.h>
|
||||||
|
|
||||||
|
#include "DbTestBase.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
class PgAuthTokenTest : public DbTestBase< PgAuthTokenTest > {
|
||||||
|
public:
|
||||||
|
PgAuthTokenTest() {
|
||||||
|
using namespace testing;
|
||||||
|
db().native()->start_transaction();
|
||||||
|
|
||||||
|
authInfoId = db()(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 = "none@eedb.pl", //
|
||||||
|
t_auth_info.status = 0)
|
||||||
|
.returning(t_auth_info.id))
|
||||||
|
.front()
|
||||||
|
.id;
|
||||||
|
|
||||||
|
sutId = db()(sqlpp::postgresql::insert_into(t_auth_token) //
|
||||||
|
.set( //
|
||||||
|
t_auth_token.auth_info_id = authInfoId, //
|
||||||
|
t_auth_token.expires = std::chrono::system_clock::now(), //
|
||||||
|
t_auth_token.role = static_cast< int >(eedb::AuthTokenRole::Auth), //
|
||||||
|
t_auth_token.value = "empty") //
|
||||||
|
.returning(t_auth_token.id))
|
||||||
|
.front()
|
||||||
|
.id;
|
||||||
|
|
||||||
|
sut = std::make_unique< eedb::PgAuthToken >(db(), sutId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setExpireDate(std::chrono::system_clock::time_point exp) {
|
||||||
|
using namespace std::chrono;
|
||||||
|
db()(update(t_auth_token).set(t_auth_token.expires = time_point_cast< microseconds >(exp)).where(t_auth_token.id == sutId));
|
||||||
|
}
|
||||||
|
|
||||||
|
~PgAuthTokenTest() {
|
||||||
|
db().native()->rollback_transaction(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int64_t authInfoId;
|
||||||
|
int64_t sutId;
|
||||||
|
std::unique_ptr< eedb::PgAuthToken > sut;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::unique_ptr< PgTestDatabasePrepare > DbTestBase< PgAuthTokenTest >::_test_db = {};
|
||||||
|
|
||||||
|
using namespace sqlpp;
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
TEST_F(PgAuthTokenTest, isExpired) {
|
||||||
|
setExpireDate(system_clock::now() - hours{1});
|
||||||
|
EXPECT_TRUE(sut->expired());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgAuthTokenTest, isNotExpired) {
|
||||||
|
setExpireDate(system_clock::now() + hours{1});
|
||||||
|
EXPECT_FALSE(sut->expired());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgAuthTokenTest, validValue) {
|
||||||
|
EXPECT_EQ(sut->token(), "empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgAuthTokenTest, updateValue) {
|
||||||
|
sut->update("NEW");
|
||||||
|
EXPECT_EQ(sut->token(), "NEW");
|
||||||
|
}
|
||||||
@ -0,0 +1,105 @@
|
|||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
#include <data/PgAuthToken.hpp>
|
||||||
|
|
||||||
|
#include <eedb/data/AuthIdentity.hpp>
|
||||||
|
#include <eedb/data/Users.hpp>
|
||||||
|
#include <eedb/data/User.hpp>
|
||||||
|
|
||||||
|
#include <model/all.hpp>
|
||||||
|
#include <sqlpp11/sqlpp11.h>
|
||||||
|
|
||||||
|
#include "DbTestBase.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class UserMock : public eedb::User {
|
||||||
|
public:
|
||||||
|
MOCK_CONST_METHOD0(uid, int());
|
||||||
|
const eedb::UserName & name() const {}
|
||||||
|
const eedb::UserConfig & config() const override {}
|
||||||
|
eedb::AuthTokens & authTokens() const override {}
|
||||||
|
void logout() override {}
|
||||||
|
eedb::AuthIdentities & authIdentities() const {}
|
||||||
|
int64_t _uid;
|
||||||
|
|
||||||
|
// User interface
|
||||||
|
public:
|
||||||
|
eedb::AuthInfo & authInfo() const override {}
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
class PgAuthTokensTest : public DbTestBase< PgAuthTokensTest > {
|
||||||
|
public:
|
||||||
|
PgAuthTokensTest() {
|
||||||
|
using namespace testing;
|
||||||
|
db().native()->start_transaction();
|
||||||
|
|
||||||
|
authInfoId = db()(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 = "none@eedb.pl", //
|
||||||
|
t_auth_info.status = 0)
|
||||||
|
.returning(t_auth_info.id))
|
||||||
|
.front()
|
||||||
|
.id;
|
||||||
|
|
||||||
|
EXPECT_CALL(user, uid()).WillRepeatedly(testing::Return(authInfoId));
|
||||||
|
sut = std::make_unique< eedb::PgAuthTokens >(db(), &user);
|
||||||
|
}
|
||||||
|
|
||||||
|
void createToken(std::string hash, eedb::AuthTokenRole role) {
|
||||||
|
db()(sqlpp::postgresql::insert_into(t_auth_token) //
|
||||||
|
.set( //
|
||||||
|
t_auth_token.value = hash, //
|
||||||
|
t_auth_token.auth_info_id = authInfoId, //
|
||||||
|
t_auth_token.role = static_cast< int16_t >(role), //
|
||||||
|
t_auth_token.expires = std::chrono::system_clock::now() + std::chrono::hours{1}));
|
||||||
|
}
|
||||||
|
|
||||||
|
~PgAuthTokensTest() {
|
||||||
|
db().native()->rollback_transaction(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
UserMock user;
|
||||||
|
int64_t authInfoId{0};
|
||||||
|
std::unique_ptr< eedb::PgAuthTokens > sut;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::unique_ptr< PgTestDatabasePrepare > DbTestBase< PgAuthTokensTest >::_test_db = {};
|
||||||
|
|
||||||
|
using namespace sqlpp;
|
||||||
|
using namespace eedb;
|
||||||
|
|
||||||
|
TEST_F(PgAuthTokensTest, authTokenFound) {
|
||||||
|
createToken("token", AuthTokenRole::Auth);
|
||||||
|
EXPECT_TRUE(sut->find("token"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgAuthTokensTest, emailTokenFound) {
|
||||||
|
createToken("emailtoken", AuthTokenRole::EmailToken);
|
||||||
|
EXPECT_TRUE(sut->find(AuthTokenRole::EmailToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgAuthTokensTest, tokenNotFound) {
|
||||||
|
EXPECT_FALSE(sut->find("token"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgAuthTokensTest, addMultipleAuthTokens) {
|
||||||
|
sut->addToken("authtoken1", eedb::AuthTokenRole::Auth);
|
||||||
|
sut->addToken("authtoken2", eedb::AuthTokenRole::Auth);
|
||||||
|
|
||||||
|
EXPECT_TRUE(sut->find("authtoken1"));
|
||||||
|
EXPECT_TRUE(sut->find("authtoken2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgAuthTokensTest, removeToken) {
|
||||||
|
sut->addToken("authtoken1", eedb::AuthTokenRole::Auth);
|
||||||
|
sut->addToken("authtoken2", eedb::AuthTokenRole::Auth);
|
||||||
|
|
||||||
|
sut->removeToken("authtoken1");
|
||||||
|
EXPECT_FALSE(sut->find("authtoken1"));
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
#include <data/PgCategories.hpp>
|
||||||
|
|
||||||
|
#include "DbTestBase.hpp"
|
||||||
|
|
||||||
|
class PgCategoriesTest : public DbTestBase< PgCategoriesTest > {
|
||||||
|
public:
|
||||||
|
PgCategoriesTest() {
|
||||||
|
db().native()->start_transaction();
|
||||||
|
|
||||||
|
// sut = std::make_unique< eedb::PgCategories >();
|
||||||
|
}
|
||||||
|
|
||||||
|
~PgCategoriesTest() {
|
||||||
|
db().native()->rollback_transaction(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr< eedb::PgCategories > sut;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::unique_ptr< PgTestDatabasePrepare > DbTestBase< PgCategoriesTest >::_test_db = {};
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <data/PgCategoriesRepository.hpp>
|
||||||
|
|
||||||
|
#include "DbTestBase.hpp"
|
||||||
|
|
||||||
|
class PgCategoriesRepositoryTest : public DbTestBase< PgCategoriesRepositoryTest > {
|
||||||
|
public:
|
||||||
|
PgCategoriesRepositoryTest() {
|
||||||
|
db().native()->start_transaction();
|
||||||
|
sut = std::make_unique< eedb::PgCategoriesRepository >(db(), static_cast< eedb::User * >(nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
~PgCategoriesRepositoryTest() {
|
||||||
|
db().native()->rollback_transaction(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unique_ptr< eedb::PgCategoriesRepository > sut;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::unique_ptr< PgTestDatabasePrepare > DbTestBase< PgCategoriesRepositoryTest >::_test_db = {};
|
||||||
|
|
||||||
|
TEST_F(PgCategoriesRepositoryTest, rootNotNull) {
|
||||||
|
auto root = sut->root();
|
||||||
|
ASSERT_TRUE(root);
|
||||||
|
// EXPECT_FALSE(root->detached());
|
||||||
|
EXPECT_FALSE(root->parent());
|
||||||
|
}
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
#include <data/PgCategory.hpp>
|
||||||
|
|
||||||
|
#include "DbTestBase.hpp"
|
||||||
|
#include <data/PgUsers.hpp>
|
||||||
|
|
||||||
|
#include <eedb/data/User.hpp>
|
||||||
|
#include <eedb/data/AuthIdentityConst.hpp>
|
||||||
|
#include <eedb/data/AuthInfoConst.hpp>
|
||||||
|
|
||||||
|
#include <model/all.hpp>
|
||||||
|
#include <sqlpp11/sqlpp11.h>
|
||||||
|
|
||||||
|
class PgCategoryTest : public DbTestBase< PgCategoryTest > {
|
||||||
|
public:
|
||||||
|
PgCategoryTest() {
|
||||||
|
db().native()->start_transaction();
|
||||||
|
|
||||||
|
eedb::PgUsers(db()) //
|
||||||
|
.addUser( //
|
||||||
|
std::make_unique< eedb::AuthInfoConst >(eedb::Password{"", "", ""}, //
|
||||||
|
eedb::Email{"root@eedb.pl"}),
|
||||||
|
std::make_unique< eedb::AuthIdentityConst >("root", "loginname"));
|
||||||
|
|
||||||
|
user = eedb::PgUsers(db()).findWith(eedb::AuthIdentityConst{"root", "loginname"});
|
||||||
|
sut = std::make_unique< eedb::PgCategory >(db(), user.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto insertCategory(std::string name, int64_t parentId) {
|
||||||
|
db()(sqlpp::postgresql::insert_into(t_category)
|
||||||
|
.set(t_category.name = name, t_category.parent_id = sqlpp::tvin(parentId))
|
||||||
|
.returning(t_category.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
~PgCategoryTest() {
|
||||||
|
db().native()->rollback_transaction(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unique_ptr< eedb::User> user;
|
||||||
|
std::unique_ptr< eedb::PgCategory > sut;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::unique_ptr< PgTestDatabasePrepare > DbTestBase< PgCategoryTest >::_test_db = {};
|
||||||
|
|
||||||
|
TEST_F(PgCategoryTest, rootCategoryHasNoParent) {
|
||||||
|
EXPECT_FALSE(sut->parent());
|
||||||
|
}
|
||||||
|
|
||||||
|
//TEST_F(PgCategoryTest, rootCategoryIsNotDetached) {
|
||||||
|
// EXPECT_FALSE(sut->detached());
|
||||||
|
//}
|
||||||
|
|
||||||
|
TEST_F(PgCategoryTest, createChild) {
|
||||||
|
sut->create("name", "description");
|
||||||
|
|
||||||
|
EXPECT_EQ(sut->children()->size(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgCategoryTest, getChildren) {
|
||||||
|
auto children = sut->children();
|
||||||
|
ASSERT_TRUE(children);
|
||||||
|
EXPECT_EQ(children->size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgCategoryTest, childHasParent ) {
|
||||||
|
sut->create("name1", "description");
|
||||||
|
sut->create("name2", "description");
|
||||||
|
|
||||||
|
auto children = sut->children();
|
||||||
|
EXPECT_EQ(children->size(), 2);
|
||||||
|
for(auto child : *children) {
|
||||||
|
EXPECT_EQ(child->parent(), sut.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
#include <data/PgUser.hpp>
|
||||||
|
|
||||||
|
#include <eedb/data/AuthIdentities.hpp>
|
||||||
|
#include <eedb/data/AuthIdentityConst.hpp>
|
||||||
|
#include <eedb/data/AuthInfoConst.hpp>
|
||||||
|
|
||||||
|
#include <model/all.hpp>
|
||||||
|
#include <sqlpp11/sqlpp11.h>
|
||||||
|
|
||||||
|
#include "DbTestBase.hpp"
|
||||||
|
|
||||||
|
#include <sqlpp11/postgresql/insert.h>
|
||||||
|
|
||||||
|
class PgUserTest : public DbTestBase< PgUserTest > {
|
||||||
|
public:
|
||||||
|
PgUserTest() {
|
||||||
|
db().native()->start_transaction();
|
||||||
|
|
||||||
|
auto info_ = std::make_unique< eedb::AuthInfoConst >(
|
||||||
|
eedb::Password{"bcrypt", "OM/Z1c4WBFXvwkxh", "$2y$07$RyytUhDhLDbAPjf0b0r2Y.dsg.FlQ7L.xzWHMmoelI81u0MfBrW7q"},
|
||||||
|
eedb::Email{"email@eedb.pl"});
|
||||||
|
auto identity_ = std::make_unique< eedb::AuthIdentityConst >("name", "loginname");
|
||||||
|
|
||||||
|
const auto & pass = info_->password();
|
||||||
|
const auto & email = info_->email();
|
||||||
|
|
||||||
|
uid = //
|
||||||
|
db()(sqlpp::postgresql::insert_into(t_auth_info)
|
||||||
|
.set( //
|
||||||
|
t_auth_info.password_hash = pass.value(), //
|
||||||
|
t_auth_info.password_method = pass.function(), //
|
||||||
|
t_auth_info.password_salt = pass.salt(), //
|
||||||
|
t_auth_info.email = std::string{email.address()},
|
||||||
|
t_auth_info.status = 0)
|
||||||
|
.returning(t_auth_info.id))
|
||||||
|
.front()
|
||||||
|
.id;
|
||||||
|
|
||||||
|
db()(insert_into(t_auth_identity)
|
||||||
|
.set( //
|
||||||
|
t_auth_identity.auth_info_id = uid, //
|
||||||
|
t_auth_identity.identity = std::string{identity_->identity()},
|
||||||
|
t_auth_identity.provider = std::string{identity_->provider()}));
|
||||||
|
|
||||||
|
sut = std::make_unique< eedb::PgUser >(db(), uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
~PgUserTest() {
|
||||||
|
db().native()->rollback_transaction(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int64_t uid;
|
||||||
|
std::unique_ptr< eedb::PgUser > sut;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::unique_ptr< PgTestDatabasePrepare > DbTestBase< PgUserTest >::_test_db = {};
|
||||||
|
|
||||||
|
using namespace sqlpp;
|
||||||
|
|
||||||
|
TEST_F(PgUserTest, readAllAuthInfoData) {
|
||||||
|
EXPECT_EQ(sut->uid(), uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgUserTest, getIdentities) {
|
||||||
|
EXPECT_TRUE(sut->authIdentities().byProvider("loginname"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgUserTest, getTokens) {}
|
||||||
132
src/libs/db/postgresql_connector/test/test_eedb_data_PgUsers.cpp
Normal file
132
src/libs/db/postgresql_connector/test/test_eedb_data_PgUsers.cpp
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
#include <data/PgUsers.hpp>
|
||||||
|
|
||||||
|
#include <eedb/data/AuthIdentityConst.hpp>
|
||||||
|
#include <eedb/data/AuthInfoConst.hpp>
|
||||||
|
|
||||||
|
#include <model/all.hpp>
|
||||||
|
#include <sqlpp11/sqlpp11.h>
|
||||||
|
|
||||||
|
#include "DbTestBase.hpp"
|
||||||
|
|
||||||
|
class PgUsersTest : public DbTestBase< PgUsersTest > {
|
||||||
|
public:
|
||||||
|
PgUsersTest() {
|
||||||
|
sut = std::make_unique< eedb::PgUsers >(db());
|
||||||
|
db().native()->start_transaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
~PgUsersTest() {
|
||||||
|
db().native()->rollback_transaction(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto createUser(std::string name, std::string email) {
|
||||||
|
auto info_ = std::make_unique< eedb::AuthInfoConst >(
|
||||||
|
eedb::Password{"bcrypt", "OM/Z1c4WBFXvwkxh", "$2y$07$RyytUhDhLDbAPjf0b0r2Y.dsg.FlQ7L.xzWHMmoelI81u0MfBrW7q"}, eedb::Email{email});
|
||||||
|
auto identity_ = std::make_unique< eedb::AuthIdentityConst >(name, "loginname");
|
||||||
|
return sut->addUser(std::move(info_), std::move(identity_));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto createTestUsers() {
|
||||||
|
createUser("test_user_1", "test_user_1@eedb.pl");
|
||||||
|
createUser("test_user_2", "test_user_2@eedb.pl");
|
||||||
|
createUser("test_user_3", "test_user_3@eedb.pl");
|
||||||
|
createUser("test_user_4", "test_user_4@eedb.pl");
|
||||||
|
createUser("test_user_5", "test_user_5@eedb.pl");
|
||||||
|
createUser("test_user_6", "test_user_6@eedb.pl");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto idMap() {
|
||||||
|
std::map< std::string, int64_t > _userIdMap;
|
||||||
|
auto ids = db()( //
|
||||||
|
select(t_auth_info.id, t_auth_identity.identity)
|
||||||
|
.from(t_auth_info //
|
||||||
|
.inner_join(t_auth_identity)
|
||||||
|
.on(t_auth_identity.auth_info_id == t_auth_info.id))
|
||||||
|
.unconditionally());
|
||||||
|
|
||||||
|
for(const auto & row : ids) {
|
||||||
|
_userIdMap[row.identity] = row.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _userIdMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unique_ptr< eedb::PgUsers > sut;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::unique_ptr< PgTestDatabasePrepare > DbTestBase< PgUsersTest >::_test_db = {};
|
||||||
|
|
||||||
|
using namespace sqlpp;
|
||||||
|
|
||||||
|
TEST_F(PgUsersTest, createValidUser) {
|
||||||
|
auto info_ = std::make_unique< eedb::AuthInfoConst >(
|
||||||
|
eedb::Password{"bcrypt", "OM/Z1c4WBFXvwkxh", "$2y$07$RyytUhDhLDbAPjf0b0r2Y.dsg.FlQ7L.xzWHMmoelI81u0MfBrW7q"},
|
||||||
|
eedb::Email{"none@eedb.pl"});
|
||||||
|
auto identity_ = std::make_unique< eedb::AuthIdentityConst >("username", "loginname");
|
||||||
|
|
||||||
|
auto new_user = sut->addUser(std::move(info_), std::move(identity_));
|
||||||
|
ASSERT_TRUE(new_user);
|
||||||
|
|
||||||
|
auto info = db()(select(sqlpp::all_of(t_auth_info)).from(t_auth_info).where(t_auth_info.id == new_user->uid()));
|
||||||
|
EXPECT_FALSE(info.empty());
|
||||||
|
|
||||||
|
EXPECT_EQ(info.front().password_hash, "$2y$07$RyytUhDhLDbAPjf0b0r2Y.dsg.FlQ7L.xzWHMmoelI81u0MfBrW7q");
|
||||||
|
EXPECT_EQ(info.front().password_method, "bcrypt");
|
||||||
|
EXPECT_EQ(info.front().password_salt, "OM/Z1c4WBFXvwkxh");
|
||||||
|
EXPECT_EQ(info.front().email, "none@eedb.pl");
|
||||||
|
EXPECT_EQ(info.front().status.value(), 0); /// ODO status:Waiting for verification
|
||||||
|
EXPECT_EQ(info.front().id.value(), new_user->uid());
|
||||||
|
|
||||||
|
auto identity = db()(select(t_auth_identity.provider, t_auth_identity.identity)
|
||||||
|
.from(t_auth_identity)
|
||||||
|
.where(t_auth_identity.auth_info_id == info.front().id));
|
||||||
|
|
||||||
|
EXPECT_EQ(identity.front().provider, "loginname");
|
||||||
|
EXPECT_EQ(identity.front().identity, "username");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgUsersTest, createSameUserMustFail) {
|
||||||
|
createUser("_test_user_", "test_email@eedb.pl");
|
||||||
|
EXPECT_THROW(createUser("_test_user_", "test_email@eedb.pl"), sqlpp::postgresql::integrity_constraint_violation);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgUsersTest, createWithSameEmailMustFail) {
|
||||||
|
createUser("_test_user_1", "test_email@eedb.pl");
|
||||||
|
EXPECT_THROW(createUser("_test_user_2", "test_email@eedb.pl"), sqlpp::postgresql::integrity_constraint_violation);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgUsersTest, findById) {
|
||||||
|
createTestUsers();
|
||||||
|
auto id = idMap().at("test_user_1");
|
||||||
|
|
||||||
|
auto u = sut->findWith(id);
|
||||||
|
ASSERT_TRUE(u);
|
||||||
|
EXPECT_EQ(id, u->uid());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgUsersTest, findByIdentity) {
|
||||||
|
createTestUsers();
|
||||||
|
|
||||||
|
auto u = sut->findWith(eedb::AuthIdentityConst{"test_user_1", "loginname"});
|
||||||
|
ASSERT_TRUE(u);
|
||||||
|
EXPECT_EQ(idMap().at("test_user_1"), u->uid());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgUsersTest, findByEmail) {
|
||||||
|
createTestUsers();
|
||||||
|
|
||||||
|
auto u = sut->findWith(eedb::Email{"test_user_5@eedb.pl"});
|
||||||
|
ASSERT_TRUE(u);
|
||||||
|
EXPECT_EQ(idMap().at("test_user_5"), u->uid());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PgUsersTest, removeUser) {
|
||||||
|
createTestUsers();
|
||||||
|
|
||||||
|
auto u = sut->findWith(eedb::AuthIdentityConst{"test_user_1", "loginname"});
|
||||||
|
ASSERT_TRUE(u);
|
||||||
|
sut->removeUser(std::move(u));
|
||||||
|
EXPECT_FALSE(sut->findWith(eedb::AuthIdentityConst{"test_user_1", "loginname"}));
|
||||||
|
}
|
||||||
7
src/libs/eedb/CMakeLists.txt
Normal file
7
src/libs/eedb/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
set(LIB eedb)
|
||||||
|
|
||||||
|
add_library(${LIB} src/dummy.cpp)
|
||||||
|
target_include_directories(${LIB} PUBLIC include)
|
||||||
|
|
||||||
|
set_target_properties(${LIB} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
||||||
|
cotire(${LIB})
|
||||||
@ -72,17 +72,17 @@ class Category {
|
|||||||
*/
|
*/
|
||||||
virtual Category * parent() const = 0;
|
virtual Category * parent() const = 0;
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* @brief detached
|
// * @brief detached
|
||||||
* @return true if category is in detached state (has no parent and is not root category)
|
// * @return true if category is in detached state (has no parent and is not root category)
|
||||||
*/
|
// */
|
||||||
virtual bool detached() const = 0;
|
// virtual bool detached() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief create
|
* @brief create
|
||||||
* @return category in detached state (not connected to any root category)
|
* @return category in detached state (not connected to any root category)
|
||||||
*/
|
*/
|
||||||
virtual std::unique_ptr< Category > create(std::string name, std::string description, std::optional< path > image = {}) const = 0;
|
virtual std::unique_ptr< Category > create(std::string name, std::string description) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief children
|
* @brief children
|
||||||
85
src/libs/eedb/include/eedb/data/Item.hpp
Normal file
85
src/libs/eedb/include/eedb/data/Item.hpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <any_iterator/any_iterator.hpp>
|
||||||
|
|
||||||
|
namespace eedb {
|
||||||
|
|
||||||
|
class Category;
|
||||||
|
class Item;
|
||||||
|
class Items;
|
||||||
|
class Values;
|
||||||
|
class Units;
|
||||||
|
/**
|
||||||
|
* @brief The ItemQueryFilters class
|
||||||
|
*/
|
||||||
|
class ItemQueryFilters {
|
||||||
|
public:
|
||||||
|
virtual ~ItemQueryFilters() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief category
|
||||||
|
* @return null if category is not taken into consideration
|
||||||
|
*/
|
||||||
|
virtual Category * category() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The ItemsRepository class
|
||||||
|
*/
|
||||||
|
class ItemsRepository {
|
||||||
|
public:
|
||||||
|
virtual ~ItemsRepository() = default;
|
||||||
|
|
||||||
|
virtual std::unique_ptr< Item > create(std::string name, std::unique_ptr< Values > value, std::string description) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief search
|
||||||
|
* @param filer
|
||||||
|
* @return Items based on given query
|
||||||
|
*/
|
||||||
|
virtual std::unique_ptr< Items > search(const ItemQueryFilters & filer) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Items class
|
||||||
|
*/
|
||||||
|
class Items {
|
||||||
|
using Iterable = IteratorTypeErasure::any_iterator< Item *, std::forward_iterator_tag, Item * >;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~Items() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief size
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
virtual long size() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief begin
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
virtual Iterable begin() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief end
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
virtual Iterable end() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Item class
|
||||||
|
*/
|
||||||
|
class Item {
|
||||||
|
public:
|
||||||
|
virtual ~Item() = default;
|
||||||
|
|
||||||
|
virtual std::string_view displayName() const = 0;
|
||||||
|
|
||||||
|
virtual Values & values() const = 0;
|
||||||
|
};
|
||||||
|
} // namespace eedb
|
||||||
18
src/libs/eedb/include/eedb/data/Unit.hpp
Normal file
18
src/libs/eedb/include/eedb/data/Unit.hpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace eedb {
|
||||||
|
|
||||||
|
class Units {
|
||||||
|
public:
|
||||||
|
virtual ~Units() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Unit {
|
||||||
|
public:
|
||||||
|
std::string_view name() const;
|
||||||
|
Unit toBase() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace eedb
|
||||||
16
src/libs/eedb/include/eedb/data/Value.hpp
Normal file
16
src/libs/eedb/include/eedb/data/Value.hpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
namespace eedb {
|
||||||
|
class Value;
|
||||||
|
class Values {
|
||||||
|
public:
|
||||||
|
virtual ~Values() = default;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Value {
|
||||||
|
public:
|
||||||
|
};
|
||||||
|
} // namespace eedb
|
||||||
0
src/libs/eedb/src/dummy.cpp
Normal file
0
src/libs/eedb/src/dummy.cpp
Normal file
18
src/libs/widgets/CMakeLists.txt
Normal file
18
src/libs/widgets/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
set(LIB widgets)
|
||||||
|
|
||||||
|
file(GLOB widget_SOURCE src/*)
|
||||||
|
|
||||||
|
# find packages
|
||||||
|
#find_package(Wt REQUIRED)
|
||||||
|
|
||||||
|
# create library
|
||||||
|
add_library(${LIB} ${widget_SOURCE})
|
||||||
|
|
||||||
|
# link all
|
||||||
|
target_include_directories(${LIB} PRIVATE include)
|
||||||
|
target_link_libraries(${LIB} PRIVATE eedb)
|
||||||
|
target_link_libraries(${LIB} PRIVATE auth)
|
||||||
|
|
||||||
|
# add cotire
|
||||||
|
set_target_properties(${LIB} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
||||||
|
cotire(${LIB})
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user