Factorized code for Eiffel Store + SQL CMS storage.
Revisited database schema to make it simpler for now, and shorter columns name. See schema.sql under sqlite implementation
This commit is contained in:
@@ -9,13 +9,13 @@
|
|||||||
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||||
</option>
|
</option>
|
||||||
|
<setting name="concurrency" value="none"/>
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
<library name="cms" location="..\..\cms-safe.ecf" readonly="false"/>
|
<library name="cms" location="..\..\cms-safe.ecf" readonly="false"/>
|
||||||
<library name="cms_demo_module" location="modules\demo\cms_demo_module-safe.ecf" readonly="false"/>
|
<library name="cms_demo_module" location="modules\demo\cms_demo_module-safe.ecf" readonly="false"/>
|
||||||
|
<library name="layout" location="..\..\library\layout\layout-safe.ecf" readonly="false"/>
|
||||||
<library name="persistence_mysql" location="..\..\library\persistence\implementation\mysql\persistence_mysql-safe.ecf" readonly="false"/>
|
<library name="persistence_mysql" location="..\..\library\persistence\implementation\mysql\persistence_mysql-safe.ecf" readonly="false"/>
|
||||||
<library name="persistence_sqlite" location="..\..\library\persistence\implementation\sqlite\persistence_sqlite-safe.ecf" readonly="false"/>
|
<library name="persistence_sqlite" location="..\..\library\persistence\implementation\sqlite\persistence_sqlite-safe.ecf" readonly="false"/>
|
||||||
|
|
||||||
<library name="layout" location="..\..\library\layout\layout-safe.ecf" readonly="false"/>
|
|
||||||
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
|
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
|
||||||
<library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension-safe.ecf" readonly="false"/>
|
<library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension-safe.ecf" readonly="false"/>
|
||||||
</target>
|
</target>
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
</target>
|
</target>
|
||||||
<target name="demo_nino" extends="common">
|
<target name="demo_nino" extends="common">
|
||||||
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
|
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
|
||||||
|
<setting name="concurrency" value="none"/>
|
||||||
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
|
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
|
||||||
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
|
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
|
||||||
<cluster name="src" location=".\src\" recursive="true"/>
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {CMS_STORAGE_STORE_SQL}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
CMS_STORAGE_STORE_SQL
|
||||||
|
|
||||||
|
inherit
|
||||||
|
CMS_STORAGE
|
||||||
|
|
||||||
|
CMS_STORAGE_SQL
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_connection: DATABASE_CONNECTION)
|
||||||
|
--
|
||||||
|
require
|
||||||
|
is_connected: a_connection.is_connected
|
||||||
|
do
|
||||||
|
connection := a_connection
|
||||||
|
log.write_information (generator + ".make - is database connected? "+ a_connection.is_connected.out )
|
||||||
|
|
||||||
|
create {DATABASE_HANDLER_IMPL} db_handler.make (a_connection)
|
||||||
|
|
||||||
|
create error_handler.make
|
||||||
|
-- error_handler.add_synchronization (db_handler.database_error_handler)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
db_handler: DATABASE_HANDLER
|
||||||
|
|
||||||
|
connection: DATABASE_CONNECTION
|
||||||
|
-- Current database connection.
|
||||||
|
|
||||||
|
feature -- Query
|
||||||
|
|
||||||
|
sql_post_execution
|
||||||
|
-- Post database execution.
|
||||||
|
do
|
||||||
|
error_handler.append (db_handler.database_error_handler)
|
||||||
|
if error_handler.has_error then
|
||||||
|
log.write_critical (generator + ".post_execution " + error_handler.as_string_representation)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sql_begin_transaction
|
||||||
|
do
|
||||||
|
connection.begin_transaction
|
||||||
|
end
|
||||||
|
|
||||||
|
sql_commit_transaction
|
||||||
|
do
|
||||||
|
connection.commit
|
||||||
|
end
|
||||||
|
|
||||||
|
sql_query (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY])
|
||||||
|
do
|
||||||
|
check_sql_query_validity (a_sql_statement, a_params)
|
||||||
|
db_handler.set_query (create {DATABASE_QUERY}.data_reader (a_sql_statement, a_params))
|
||||||
|
db_handler.execute_query
|
||||||
|
end
|
||||||
|
|
||||||
|
sql_change (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY])
|
||||||
|
do
|
||||||
|
check_sql_query_validity (a_sql_statement, a_params)
|
||||||
|
db_handler.set_query (create {DATABASE_QUERY}.data_reader (a_sql_statement, a_params))
|
||||||
|
db_handler.execute_change
|
||||||
|
end
|
||||||
|
|
||||||
|
sql_rows_count: INTEGER
|
||||||
|
-- Number of rows for last sql execution.
|
||||||
|
do
|
||||||
|
Result := db_handler.count
|
||||||
|
end
|
||||||
|
|
||||||
|
sql_start
|
||||||
|
-- Set the cursor on first element.
|
||||||
|
do
|
||||||
|
db_handler.start
|
||||||
|
end
|
||||||
|
|
||||||
|
sql_after: BOOLEAN
|
||||||
|
-- Are there no more items to iterate over?
|
||||||
|
do
|
||||||
|
Result := db_handler.after
|
||||||
|
end
|
||||||
|
|
||||||
|
sql_forth
|
||||||
|
-- Fetch next row from last sql execution, if any.
|
||||||
|
do
|
||||||
|
db_handler.forth
|
||||||
|
end
|
||||||
|
|
||||||
|
sql_item (a_index: INTEGER): detachable ANY
|
||||||
|
do
|
||||||
|
if attached {DB_TUPLE} db_handler.item as l_item and then l_item.count >= a_index then
|
||||||
|
Result := l_item.item (a_index)
|
||||||
|
else
|
||||||
|
check has_item_at_index: False end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -7,9 +7,10 @@ class
|
|||||||
CMS_STORAGE_MYSQL
|
CMS_STORAGE_MYSQL
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
|
|
||||||
CMS_STORAGE
|
CMS_STORAGE
|
||||||
|
|
||||||
|
CMS_STORAGE_STORE_SQL
|
||||||
|
|
||||||
CMS_USER_STORAGE_MYSQL
|
CMS_USER_STORAGE_MYSQL
|
||||||
|
|
||||||
CMS_NODE_STORAGE_MYSQL
|
CMS_NODE_STORAGE_MYSQL
|
||||||
@@ -19,85 +20,93 @@ inherit
|
|||||||
create
|
create
|
||||||
make
|
make
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
--feature {NONE} -- Initialization
|
||||||
|
|
||||||
make (a_connection: DATABASE_CONNECTION)
|
-- make (a_connection: DATABASE_CONNECTION)
|
||||||
--
|
-- --
|
||||||
require
|
-- require
|
||||||
is_connected: a_connection.is_connected
|
-- is_connected: a_connection.is_connected
|
||||||
do
|
-- do
|
||||||
connection := a_connection
|
-- connection := a_connection
|
||||||
log.write_information (generator + ".make - is database connected? "+ a_connection.is_connected.out )
|
-- log.write_information (generator + ".make - is database connected? "+ a_connection.is_connected.out )
|
||||||
|
|
||||||
create {DATABASE_HANDLER_IMPL} db_handler.make (a_connection)
|
-- create {DATABASE_HANDLER_IMPL} db_handler.make (a_connection)
|
||||||
|
|
||||||
create error_handler.make
|
-- create error_handler.make
|
||||||
-- error_handler.add_synchronization (db_handler.database_error_handler)
|
---- error_handler.add_synchronization (db_handler.database_error_handler)
|
||||||
end
|
-- end
|
||||||
|
|
||||||
db_handler: DATABASE_HANDLER
|
-- db_handler: DATABASE_HANDLER
|
||||||
|
|
||||||
connection: DATABASE_CONNECTION
|
-- connection: DATABASE_CONNECTION
|
||||||
-- Current database connection.
|
-- -- Current database connection.
|
||||||
|
|
||||||
feature -- Query
|
--feature -- Query
|
||||||
|
|
||||||
sql_post_execution
|
-- sql_post_execution
|
||||||
-- Post database execution.
|
-- -- Post database execution.
|
||||||
do
|
-- do
|
||||||
error_handler.append (db_handler.database_error_handler)
|
-- error_handler.append (db_handler.database_error_handler)
|
||||||
if error_handler.has_error then
|
-- if error_handler.has_error then
|
||||||
log.write_critical (generator + ".post_execution " + error_handler.as_string_representation)
|
-- log.write_critical (generator + ".post_execution " + error_handler.as_string_representation)
|
||||||
end
|
-- end
|
||||||
end
|
-- end
|
||||||
|
|
||||||
sql_begin_transaction
|
-- sql_begin_transaction
|
||||||
do
|
-- do
|
||||||
connection.begin_transaction
|
-- connection.begin_transaction
|
||||||
end
|
-- end
|
||||||
|
|
||||||
sql_commit_transaction
|
-- sql_commit_transaction
|
||||||
do
|
-- do
|
||||||
connection.commit
|
-- connection.commit
|
||||||
end
|
-- end
|
||||||
|
|
||||||
sql_query (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY])
|
-- sql_query (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY])
|
||||||
do
|
-- do
|
||||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (a_sql_statement, a_params))
|
-- check_sql_query_validity (a_sql_statement, a_params)
|
||||||
db_handler.execute_query
|
-- db_handler.set_query (create {DATABASE_QUERY}.data_reader (a_sql_statement, a_params))
|
||||||
end
|
-- db_handler.execute_query
|
||||||
|
-- end
|
||||||
|
|
||||||
sql_change (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY])
|
-- sql_change (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY])
|
||||||
do
|
-- do
|
||||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (a_sql_statement, a_params))
|
-- check_sql_query_validity (a_sql_statement, a_params)
|
||||||
db_handler.execute_change
|
-- db_handler.set_query (create {DATABASE_QUERY}.data_reader (a_sql_statement, a_params))
|
||||||
end
|
-- db_handler.execute_change
|
||||||
|
-- end
|
||||||
|
|
||||||
sql_rows_count: INTEGER
|
-- sql_rows_count: INTEGER
|
||||||
-- Number of rows for last sql execution.
|
-- -- Number of rows for last sql execution.
|
||||||
do
|
-- do
|
||||||
Result := db_handler.count
|
-- Result := db_handler.count
|
||||||
end
|
-- end
|
||||||
|
|
||||||
sql_after: BOOLEAN
|
-- sql_start
|
||||||
-- Are there no more items to iterate over?
|
-- -- Set the cursor on first element.
|
||||||
do
|
-- do
|
||||||
Result := db_handler.after
|
-- db_handler.start
|
||||||
end
|
-- end
|
||||||
|
|
||||||
sql_forth
|
-- sql_after: BOOLEAN
|
||||||
-- Fetch next row from last sql execution, if any.
|
-- -- Are there no more items to iterate over?
|
||||||
do
|
-- do
|
||||||
db_handler.forth
|
-- Result := db_handler.after
|
||||||
end
|
-- end
|
||||||
|
|
||||||
sql_item (a_index: INTEGER): detachable ANY
|
-- sql_forth
|
||||||
do
|
-- -- Fetch next row from last sql execution, if any.
|
||||||
if attached {DB_TUPLE} db_handler.item as l_item and then l_item.count >= a_index then
|
-- do
|
||||||
Result := l_item.item (a_index)
|
-- db_handler.forth
|
||||||
else
|
-- end
|
||||||
check has_item_at_index: False end
|
|
||||||
end
|
-- sql_item (a_index: INTEGER): detachable ANY
|
||||||
end
|
-- do
|
||||||
|
-- if attached {DB_TUPLE} db_handler.item as l_item and then l_item.count >= a_index then
|
||||||
|
-- Result := l_item.item (a_index)
|
||||||
|
-- else
|
||||||
|
-- check has_item_at_index: False end
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
-- Creator: MySQL Workbench 6.1.7/ExportSQLite plugin 2009.12.02
|
|
||||||
-- Author: javier
|
|
||||||
-- Caption: New Model
|
|
||||||
-- Project: Name of the project
|
|
||||||
-- Changed: 2014-09-16 23:12
|
|
||||||
-- Created: 2014-09-16 23:12
|
|
||||||
PRAGMA foreign_keys = OFF;
|
|
||||||
|
|
||||||
-- Schema: cms_dev
|
|
||||||
BEGIN;
|
|
||||||
CREATE TABLE "nodes"(
|
|
||||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("id">=0),
|
|
||||||
"publication_date" DATE NOT NULL,
|
|
||||||
"creation_date" DATE NOT NULL,
|
|
||||||
"modification_date" DATE NOT NULL,
|
|
||||||
"title" VARCHAR(255) NOT NULL,
|
|
||||||
"summary" TEXT NOT NULL,
|
|
||||||
"content" MEDIUMTEXT NOT NULL
|
|
||||||
);
|
|
||||||
CREATE TABLE "roles"(
|
|
||||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("id">=0),
|
|
||||||
"role" VARCHAR(100) NOT NULL,
|
|
||||||
CONSTRAINT "role"
|
|
||||||
UNIQUE("role")
|
|
||||||
);
|
|
||||||
CREATE TABLE "users"(
|
|
||||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("id">=0),
|
|
||||||
"username" VARCHAR(100) NOT NULL,
|
|
||||||
"password" VARCHAR(100) NOT NULL,
|
|
||||||
"salt" VARCHAR(100) NOT NULL,
|
|
||||||
"email" VARCHAR(250) NOT NULL,
|
|
||||||
CONSTRAINT "username"
|
|
||||||
UNIQUE("username")
|
|
||||||
);
|
|
||||||
CREATE TABLE "users_nodes"(
|
|
||||||
"users_id" INTEGER NOT NULL CHECK("users_id">=0),
|
|
||||||
"nodes_id" INTEGER NOT NULL CHECK("nodes_id">=0),
|
|
||||||
PRIMARY KEY("users_id","nodes_id"),
|
|
||||||
CONSTRAINT "fk_users_has_nodes_nodes1"
|
|
||||||
FOREIGN KEY("nodes_id")
|
|
||||||
REFERENCES "nodes"("id"),
|
|
||||||
CONSTRAINT "fk_users_has_nodes_users"
|
|
||||||
FOREIGN KEY("users_id")
|
|
||||||
REFERENCES "users"("id")
|
|
||||||
);
|
|
||||||
CREATE INDEX "users_nodes.fk_users_has_nodes_nodes1_idx" ON "users_nodes"("nodes_id");
|
|
||||||
CREATE INDEX "users_nodes.fk_users_has_nodes_users_idx" ON "users_nodes"("users_id");
|
|
||||||
CREATE TABLE "users_roles"(
|
|
||||||
"users_id" INTEGER NOT NULL CHECK("users_id">=0),
|
|
||||||
"roles_id" INTEGER NOT NULL CHECK("roles_id">=0),
|
|
||||||
PRIMARY KEY("users_id","roles_id"),
|
|
||||||
CONSTRAINT "fk_users_has_roles_roles1"
|
|
||||||
FOREIGN KEY("roles_id")
|
|
||||||
REFERENCES "roles"("id"),
|
|
||||||
CONSTRAINT "fk_users_has_roles_users1"
|
|
||||||
FOREIGN KEY("users_id")
|
|
||||||
REFERENCES "users"("id")
|
|
||||||
);
|
|
||||||
CREATE INDEX "users_roles.fk_users_has_roles_roles1_idx" ON "users_roles"("roles_id");
|
|
||||||
CREATE INDEX "users_roles.fk_users_has_roles_users1_idx" ON "users_roles"("users_id");
|
|
||||||
COMMIT;
|
|
||||||
36
library/persistence/implementation/sqlite/scripts/schema.sql
Normal file
36
library/persistence/implementation/sqlite/scripts/schema.sql
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
PRAGMA foreign_keys = OFF;
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
CREATE TABLE "users"(
|
||||||
|
"uid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("uid">=0),
|
||||||
|
"name" VARCHAR(100) NOT NULL,
|
||||||
|
"password" VARCHAR(100) NOT NULL,
|
||||||
|
"salt" VARCHAR(100) NOT NULL,
|
||||||
|
"email" VARCHAR(250) NOT NULL,
|
||||||
|
"status" INTEGER,
|
||||||
|
"created" DATETIME NOT NULL,
|
||||||
|
"signed" DATETIME,
|
||||||
|
CONSTRAINT "name"
|
||||||
|
UNIQUE("name")
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "users_roles"(
|
||||||
|
"rid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("rid">=0),
|
||||||
|
"role" VARCHAR(100) NOT NULL,
|
||||||
|
CONSTRAINT "role"
|
||||||
|
UNIQUE("role")
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "nodes"(
|
||||||
|
"nid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("nid">=0),
|
||||||
|
"version" INTEGER,
|
||||||
|
"type" INTEGER,
|
||||||
|
"title" VARCHAR(255) NOT NULL,
|
||||||
|
"summary" TEXT NOT NULL,
|
||||||
|
"content" MEDIUMTEXT NOT NULL,
|
||||||
|
"author" INTEGER,
|
||||||
|
"publish" DATETIME,
|
||||||
|
"created" DATETIME NOT NULL,
|
||||||
|
"changed" DATETIME NOT NULL
|
||||||
|
);
|
||||||
|
COMMIT;
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
DROP TABLE IF EXISTS nodes;
|
|
||||||
|
|
||||||
CREATE TABLE nodes
|
|
||||||
(
|
|
||||||
id smallint unsigned NOT NULL auto_increment,
|
|
||||||
publication_date date NOT NULL, #When the article was published
|
|
||||||
creation_date date NOT NULL, #When the article was created
|
|
||||||
modification_date date NOT NULL, #When the article was updated
|
|
||||||
title varchar(255) NOT NULL, #Full title of the article
|
|
||||||
summary text NOT NULL, #A short summary of the articule
|
|
||||||
content mediumtext NOT NULL, #The HTML content of the article
|
|
||||||
|
|
||||||
PRIMARY KEY (ID)
|
|
||||||
);
|
|
||||||
@@ -9,6 +9,67 @@ deferred class
|
|||||||
|
|
||||||
inherit
|
inherit
|
||||||
CMS_NODE_STORAGE_SQL
|
CMS_NODE_STORAGE_SQL
|
||||||
|
redefine
|
||||||
|
nodes, recent_nodes
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
db_handler: DATABASE_HANDLER
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
nodes: LIST [CMS_NODE]
|
||||||
|
-- List of nodes.
|
||||||
|
do
|
||||||
|
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
|
||||||
|
across nodes_iterator as ic loop
|
||||||
|
Result.force (ic.item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
|
||||||
|
-- List of recent `a_count' nodes with an offset of `lower'.
|
||||||
|
do
|
||||||
|
create {ARRAYED_LIST [CMS_NODE]} Result.make (a_count)
|
||||||
|
across recent_nodes_iterator (a_lower, a_count) as c loop
|
||||||
|
Result.force (c.item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access: iterator
|
||||||
|
|
||||||
|
nodes_iterator: DATABASE_ITERATION_CURSOR [CMS_NODE]
|
||||||
|
-- List of nodes.
|
||||||
|
local
|
||||||
|
l_parameters: STRING_TABLE [ANY]
|
||||||
|
do
|
||||||
|
error_handler.reset
|
||||||
|
log.write_information (generator + ".nodes_iterator")
|
||||||
|
create l_parameters.make (0)
|
||||||
|
sql_query (select_nodes, l_parameters)
|
||||||
|
sql_post_execution
|
||||||
|
create Result.make (db_handler, agent fetch_node)
|
||||||
|
end
|
||||||
|
|
||||||
|
recent_nodes_iterator (a_lower, a_rows: INTEGER): DATABASE_ITERATION_CURSOR [CMS_NODE]
|
||||||
|
-- The most recent `a_rows'.
|
||||||
|
local
|
||||||
|
l_parameters: STRING_TABLE [ANY]
|
||||||
|
l_query: STRING
|
||||||
|
do
|
||||||
|
-- FIXME: check implementation...
|
||||||
|
error_handler.reset
|
||||||
|
log.write_information (generator + ".recent_nodes_iterator")
|
||||||
|
create l_parameters.make (2)
|
||||||
|
l_parameters.put (a_rows, "rows")
|
||||||
|
l_parameters.put (a_lower, "offset")
|
||||||
|
create l_query.make_from_string (select_recent_nodes)
|
||||||
|
sql_query (l_query, l_parameters)
|
||||||
|
create Result.make (db_handler, agent fetch_node)
|
||||||
|
sql_post_execution
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ class
|
|||||||
inherit
|
inherit
|
||||||
CMS_STORAGE
|
CMS_STORAGE
|
||||||
|
|
||||||
|
CMS_STORAGE_STORE_SQL
|
||||||
|
|
||||||
CMS_USER_STORAGE_SQLITE
|
CMS_USER_STORAGE_SQLITE
|
||||||
|
|
||||||
CMS_NODE_STORAGE_SQLITE
|
CMS_NODE_STORAGE_SQLITE
|
||||||
@@ -18,85 +20,93 @@ inherit
|
|||||||
create
|
create
|
||||||
make
|
make
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
--feature {NONE} -- Initialization
|
||||||
|
|
||||||
make (a_connection: DATABASE_CONNECTION)
|
-- make (a_connection: DATABASE_CONNECTION)
|
||||||
--
|
-- --
|
||||||
require
|
-- require
|
||||||
is_connected: a_connection.is_connected
|
-- is_connected: a_connection.is_connected
|
||||||
do
|
-- do
|
||||||
connection := a_connection
|
-- connection := a_connection
|
||||||
log.write_information (generator + ".make_with_database is database connected? "+ a_connection.is_connected.out )
|
-- log.write_information (generator + ".make_with_database is database connected? "+ a_connection.is_connected.out )
|
||||||
|
|
||||||
create {DATABASE_HANDLER_IMPL} db_handler.make (a_connection)
|
-- create {DATABASE_HANDLER_IMPL} db_handler.make (a_connection)
|
||||||
|
|
||||||
create error_handler.make
|
-- create error_handler.make
|
||||||
-- error_handler.add_synchronization (db_handler.database_error_handler)
|
---- error_handler.add_synchronization (db_handler.database_error_handler)
|
||||||
end
|
-- end
|
||||||
|
|
||||||
db_handler: DATABASE_HANDLER
|
-- db_handler: DATABASE_HANDLER
|
||||||
|
|
||||||
connection: DATABASE_CONNECTION
|
-- connection: DATABASE_CONNECTION
|
||||||
-- Current database connection.
|
-- -- Current database connection.
|
||||||
|
|
||||||
feature -- Access: user
|
--feature -- Access: user
|
||||||
|
|
||||||
sql_post_execution
|
-- sql_post_execution
|
||||||
-- Post database execution.
|
-- -- Post database execution.
|
||||||
do
|
-- do
|
||||||
error_handler.append (db_handler.database_error_handler)
|
-- error_handler.append (db_handler.database_error_handler)
|
||||||
if error_handler.has_error then
|
-- if error_handler.has_error then
|
||||||
log.write_critical (generator + ".post_execution " + error_handler.as_string_representation)
|
-- log.write_critical (generator + ".post_execution " + error_handler.as_string_representation)
|
||||||
end
|
-- end
|
||||||
end
|
-- end
|
||||||
|
|
||||||
sql_begin_transaction
|
-- sql_begin_transaction
|
||||||
do
|
-- do
|
||||||
connection.begin_transaction
|
-- connection.begin_transaction
|
||||||
end
|
-- end
|
||||||
|
|
||||||
sql_commit_transaction
|
-- sql_commit_transaction
|
||||||
do
|
-- do
|
||||||
connection.commit
|
-- connection.commit
|
||||||
end
|
-- end
|
||||||
|
|
||||||
sql_query (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY])
|
-- sql_query (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY])
|
||||||
do
|
-- do
|
||||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (a_sql_statement, a_params))
|
-- check_sql_query_validity (a_sql_statement, a_params)
|
||||||
db_handler.execute_query
|
-- db_handler.set_query (create {DATABASE_QUERY}.data_reader (a_sql_statement, a_params))
|
||||||
end
|
-- db_handler.execute_query
|
||||||
|
-- end
|
||||||
|
|
||||||
sql_change (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY])
|
-- sql_change (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY])
|
||||||
do
|
-- do
|
||||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (a_sql_statement, a_params))
|
-- check_sql_query_validity (a_sql_statement, a_params)
|
||||||
db_handler.execute_change
|
-- db_handler.set_query (create {DATABASE_QUERY}.data_reader (a_sql_statement, a_params))
|
||||||
end
|
-- db_handler.execute_change
|
||||||
|
-- end
|
||||||
|
|
||||||
sql_rows_count: INTEGER
|
-- sql_rows_count: INTEGER
|
||||||
-- Number of rows for last sql execution.
|
-- -- Number of rows for last sql execution.
|
||||||
do
|
-- do
|
||||||
Result := db_handler.count
|
-- Result := db_handler.count
|
||||||
end
|
-- end
|
||||||
|
|
||||||
sql_after: BOOLEAN
|
-- sql_start
|
||||||
-- Are there no more items to iterate over?
|
-- -- Set the cursor on first element.
|
||||||
do
|
-- do
|
||||||
Result := db_handler.after
|
-- db_handler.start
|
||||||
end
|
-- end
|
||||||
|
|
||||||
sql_forth
|
-- sql_after: BOOLEAN
|
||||||
-- Fetch next row from last sql execution, if any.
|
-- -- Are there no more items to iterate over?
|
||||||
do
|
-- do
|
||||||
db_handler.forth
|
-- Result := db_handler.after
|
||||||
end
|
-- end
|
||||||
|
|
||||||
sql_item (a_index: INTEGER): detachable ANY
|
-- sql_forth
|
||||||
do
|
-- -- Fetch next row from last sql execution, if any.
|
||||||
if attached {DB_TUPLE} db_handler.item as l_item and then l_item.count >= a_index then
|
-- do
|
||||||
Result := l_item.item (a_index)
|
-- db_handler.forth
|
||||||
else
|
-- end
|
||||||
check has_item_at_index: False end
|
|
||||||
end
|
-- sql_item (a_index: INTEGER): detachable ANY
|
||||||
end
|
-- do
|
||||||
|
-- if attached {DB_TUPLE} db_handler.item as l_item and then l_item.count >= a_index then
|
||||||
|
-- Result := l_item.item (a_index)
|
||||||
|
-- else
|
||||||
|
-- check has_item_at_index: False end
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -162,21 +162,23 @@ feature -- Handler
|
|||||||
l_user: CMS_USER
|
l_user: CMS_USER
|
||||||
l_node: CMS_NODE
|
l_node: CMS_NODE
|
||||||
do
|
do
|
||||||
create {NOT_IMPLEMENTED_ERROR_CMS_RESPONSE} r.make (req, res, a_api)
|
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_api)
|
||||||
|
|
||||||
if attached a_api.user_by_name ("foo") as u then
|
if attached a_api.user_by_name ("foo") as u then
|
||||||
l_user := u
|
l_user := u
|
||||||
else
|
else
|
||||||
create l_user.make ("foo")
|
create l_user.make ("foo")
|
||||||
l_user.set_password ("foobar#")
|
l_user.set_password ("foobar#")
|
||||||
l_user.set_email ("jfiat@eiffel.com")
|
l_user.set_email ("test@example.com")
|
||||||
a_api.new_user (l_user)
|
a_api.new_user (l_user)
|
||||||
end
|
end
|
||||||
create l_node.make ({STRING_32} "This is a content", {STRING_32} "And a summary", {STRING_32} "Nice title")
|
if a_api.nodes_count = 0 then
|
||||||
l_node.set_author (l_user)
|
create l_node.make ({STRING_32} "This is a content", {STRING_32} "And a summary", {STRING_32} "Nice title")
|
||||||
a_api.new_node (l_node)
|
l_node.set_author (l_user)
|
||||||
|
a_api.new_node (l_node)
|
||||||
|
end
|
||||||
|
|
||||||
create s.make_from_string ("<p>Sorry: listing the CMS nodes is not yet implemented.</p>")
|
create s.make_from_string ("<p>Nodes:</p>")
|
||||||
if attached a_api.nodes as lst then
|
if attached a_api.nodes as lst then
|
||||||
across
|
across
|
||||||
lst as ic
|
lst as ic
|
||||||
@@ -191,7 +193,7 @@ feature -- Handler
|
|||||||
end
|
end
|
||||||
|
|
||||||
r.set_main_content (s)
|
r.set_main_content (s)
|
||||||
r.add_block (create {CMS_CONTENT_BLOCK}.make ("nodes_warning", Void, "/nodes/ is not yet implemented<br/>", Void), "highlighted")
|
r.add_block (create {CMS_CONTENT_BLOCK}.make ("nodes_warning", Void, "/nodes/ is not yet fully implemented<br/>", Void), "highlighted")
|
||||||
r.execute
|
r.execute
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ class
|
|||||||
CMS_STORAGE_NULL
|
CMS_STORAGE_NULL
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
|
|
||||||
CMS_STORAGE
|
CMS_STORAGE
|
||||||
redefine
|
redefine
|
||||||
default_create
|
default_create
|
||||||
select
|
select
|
||||||
default_create
|
default_create
|
||||||
end
|
end
|
||||||
|
|
||||||
REFACTORING_HELPER
|
REFACTORING_HELPER
|
||||||
rename
|
rename
|
||||||
default_create as default_create_rh
|
default_create as default_create_rh
|
||||||
@@ -70,11 +70,16 @@ feature -- User Nodes
|
|||||||
|
|
||||||
feature -- Change: user
|
feature -- Change: user
|
||||||
|
|
||||||
save_user (a_user: CMS_USER)
|
new_user (a_user: CMS_USER)
|
||||||
-- Add a new user `a_user'.
|
-- Add a new user `a_user'.
|
||||||
do
|
do
|
||||||
end
|
end
|
||||||
|
|
||||||
|
update_user (a_user: CMS_USER)
|
||||||
|
-- Update user `a_user'.
|
||||||
|
do
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Access: roles and permissions
|
feature -- Access: roles and permissions
|
||||||
|
|
||||||
user_role_by_id (a_id: like {CMS_USER_ROLE}.id): detachable CMS_USER_ROLE
|
user_role_by_id (a_id: like {CMS_USER_ROLE}.id): detachable CMS_USER_ROLE
|
||||||
@@ -93,9 +98,13 @@ feature -- Change: roles and permissions
|
|||||||
do
|
do
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
feature -- Access: node
|
feature -- Access: node
|
||||||
|
|
||||||
|
nodes_count: INTEGER_64
|
||||||
|
-- Count of nodes.
|
||||||
|
do
|
||||||
|
end
|
||||||
|
|
||||||
nodes: LIST[CMS_NODE]
|
nodes: LIST[CMS_NODE]
|
||||||
-- List of nodes.
|
-- List of nodes.
|
||||||
do
|
do
|
||||||
@@ -156,11 +165,4 @@ feature -- Node
|
|||||||
do
|
do
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- User
|
|
||||||
|
|
||||||
new_user (a_user: CMS_USER)
|
|
||||||
-- Add a new user `a_user'.
|
|
||||||
do
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -30,6 +30,58 @@ feature -- Execution
|
|||||||
|
|
||||||
feature -- Operation
|
feature -- Operation
|
||||||
|
|
||||||
|
check_sql_query_validity (a_sql_statement: READABLE_STRING_8; a_params: detachable STRING_TABLE [detachable ANY])
|
||||||
|
local
|
||||||
|
l_sql_params: STRING_TABLE [READABLE_STRING_8]
|
||||||
|
i,j,n,m: INTEGER
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
create l_sql_params.make_caseless (0)
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
n := a_sql_statement.count
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
i := a_sql_statement.index_of (':', i)
|
||||||
|
if i = 0 then
|
||||||
|
i := n -- exit
|
||||||
|
else
|
||||||
|
from
|
||||||
|
j := i + 1
|
||||||
|
until
|
||||||
|
j > n or not (a_sql_statement[j].is_alpha_numeric or a_sql_statement[j] = '_')
|
||||||
|
loop
|
||||||
|
j := j + 1
|
||||||
|
end
|
||||||
|
s := a_sql_statement.substring (i + 1, j - 1)
|
||||||
|
l_sql_params.force (s, s)
|
||||||
|
end
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
if a_params = Void then
|
||||||
|
if not l_sql_params.is_empty then
|
||||||
|
check False end
|
||||||
|
error_handler.add_custom_error (-1, "invalid query", "missing value for sql parameters")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
across
|
||||||
|
a_params as ic
|
||||||
|
loop
|
||||||
|
if l_sql_params.has (ic.key) then
|
||||||
|
l_sql_params.remove (ic.key)
|
||||||
|
else
|
||||||
|
error_handler.add_custom_error (-1, "useless value", "value for unexpected parameter [" + ic.key + "]")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
across
|
||||||
|
l_sql_params as ic
|
||||||
|
loop
|
||||||
|
error_handler.add_custom_error (-1, "invalid query", "missing value for sql parameter [" + ic.item + "]")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
sql_query (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY])
|
sql_query (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY])
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
@@ -45,6 +97,11 @@ feature -- Access
|
|||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sql_start
|
||||||
|
-- Set the cursor on first element.
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
sql_after: BOOLEAN
|
sql_after: BOOLEAN
|
||||||
-- Are there no more items to iterate over?
|
-- Are there no more items to iterate over?
|
||||||
deferred
|
deferred
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ feature -- Error Handling
|
|||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
|
nodes_count: INTEGER_64
|
||||||
|
-- Count of nodes.
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
nodes: LIST [CMS_NODE]
|
nodes: LIST [CMS_NODE]
|
||||||
-- List of nodes.
|
-- List of nodes.
|
||||||
deferred
|
deferred
|
||||||
@@ -49,7 +54,7 @@ feature -- Change: Node
|
|||||||
-- Save node `a_node'.
|
-- Save node `a_node'.
|
||||||
require
|
require
|
||||||
no_id: not a_node.has_id
|
no_id: not a_node.has_id
|
||||||
valid_user: attached a_node.author as l_author implies l_author.id > 0
|
valid_user: attached a_node.author as l_author and then l_author.id > 0
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,18 @@ inherit
|
|||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
|
nodes_count: INTEGER_64
|
||||||
|
-- Number of items nodes.
|
||||||
|
do
|
||||||
|
error_handler.reset
|
||||||
|
log.write_information (generator + ".nodes_count")
|
||||||
|
sql_query (select_nodes_count, Void)
|
||||||
|
if sql_rows_count = 1 then
|
||||||
|
Result := sql_read_integer_64 (1)
|
||||||
|
end
|
||||||
|
sql_post_execution
|
||||||
|
end
|
||||||
|
|
||||||
nodes: LIST [CMS_NODE]
|
nodes: LIST [CMS_NODE]
|
||||||
-- List of nodes.
|
-- List of nodes.
|
||||||
do
|
do
|
||||||
@@ -29,6 +41,7 @@ feature -- Access
|
|||||||
from
|
from
|
||||||
sql_query (select_nodes, Void)
|
sql_query (select_nodes, Void)
|
||||||
sql_post_execution
|
sql_post_execution
|
||||||
|
sql_start
|
||||||
until
|
until
|
||||||
sql_after
|
sql_after
|
||||||
loop
|
loop
|
||||||
@@ -56,6 +69,7 @@ feature -- Access
|
|||||||
l_parameters.put (a_lower, "offset")
|
l_parameters.put (a_lower, "offset")
|
||||||
sql_query (select_recent_nodes, l_parameters)
|
sql_query (select_recent_nodes, l_parameters)
|
||||||
sql_post_execution
|
sql_post_execution
|
||||||
|
sql_start
|
||||||
until
|
until
|
||||||
sql_after
|
sql_after
|
||||||
loop
|
loop
|
||||||
@@ -99,18 +113,6 @@ feature -- Access
|
|||||||
sql_post_execution
|
sql_post_execution
|
||||||
end
|
end
|
||||||
|
|
||||||
nodes_count: INTEGER
|
|
||||||
-- Number of items nodes.
|
|
||||||
do
|
|
||||||
error_handler.reset
|
|
||||||
log.write_information (generator + ".nodes_count")
|
|
||||||
sql_query (select_nodes_count, Void)
|
|
||||||
if sql_rows_count = 1 then
|
|
||||||
Result := sql_read_integer_32 (1)
|
|
||||||
end
|
|
||||||
sql_post_execution
|
|
||||||
end
|
|
||||||
|
|
||||||
last_inserted_node_id: INTEGER_64
|
last_inserted_node_id: INTEGER_64
|
||||||
-- Last insert node id.
|
-- Last insert node id.
|
||||||
do
|
do
|
||||||
@@ -137,16 +139,16 @@ feature -- Change: Node
|
|||||||
l_parameters.put (a_node.title, "title")
|
l_parameters.put (a_node.title, "title")
|
||||||
l_parameters.put (a_node.summary, "summary")
|
l_parameters.put (a_node.summary, "summary")
|
||||||
l_parameters.put (a_node.content, "content")
|
l_parameters.put (a_node.content, "content")
|
||||||
l_parameters.put (a_node.publication_date, "publication_date")
|
l_parameters.put (a_node.publication_date, "publish")
|
||||||
l_parameters.put (a_node.creation_date, "creation_date")
|
l_parameters.put (a_node.creation_date, "created")
|
||||||
l_parameters.put (a_node.modification_date, "modification_date")
|
l_parameters.put (a_node.modification_date, "changed")
|
||||||
if
|
if
|
||||||
attached a_node.author as l_author and then
|
attached a_node.author as l_author and then
|
||||||
l_author.id > 0
|
l_author.id > 0
|
||||||
then
|
then
|
||||||
l_parameters.put (l_author.id, "author_id")
|
l_parameters.put (l_author.id, "author")
|
||||||
else
|
else
|
||||||
l_parameters.put (0, "author_id")
|
l_parameters.put (0, "author")
|
||||||
end
|
end
|
||||||
sql_change (sql_insert_node, l_parameters)
|
sql_change (sql_insert_node, l_parameters)
|
||||||
sql_post_execution
|
sql_post_execution
|
||||||
@@ -167,10 +169,6 @@ feature -- Change: Node
|
|||||||
create l_parameters.make (1)
|
create l_parameters.make (1)
|
||||||
l_parameters.put (a_id, "id")
|
l_parameters.put (a_id, "id")
|
||||||
sql_change (sql_delete_node, l_parameters)
|
sql_change (sql_delete_node, l_parameters)
|
||||||
sql_post_execution
|
|
||||||
|
|
||||||
-- Delete from user nodes. FIXME: what is that ???
|
|
||||||
sql_change (sql_delete_from_user_node, l_parameters)
|
|
||||||
sql_post_execution
|
sql_post_execution
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -178,25 +176,28 @@ feature -- Change: Node
|
|||||||
-- Update node content `a_node'.
|
-- Update node content `a_node'.
|
||||||
local
|
local
|
||||||
l_parameters: STRING_TABLE [detachable ANY]
|
l_parameters: STRING_TABLE [detachable ANY]
|
||||||
|
now: DATE_TIME
|
||||||
do
|
do
|
||||||
|
create now.make_now_utc
|
||||||
error_handler.reset
|
error_handler.reset
|
||||||
log.write_information (generator + ".update_node")
|
log.write_information (generator + ".update_node")
|
||||||
create l_parameters.make (7)
|
create l_parameters.make (7)
|
||||||
l_parameters.put (a_node.title, "title")
|
l_parameters.put (a_node.title, "title")
|
||||||
l_parameters.put (a_node.summary, "summary")
|
l_parameters.put (a_node.summary, "summary")
|
||||||
l_parameters.put (a_node.content, "content")
|
l_parameters.put (a_node.content, "content")
|
||||||
l_parameters.put (a_node.publication_date, "publication_date")
|
l_parameters.put (a_node.publication_date, "publish")
|
||||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
|
l_parameters.put (now, "changed")
|
||||||
l_parameters.put (a_node.id, "id")
|
l_parameters.put (a_node.id, "id")
|
||||||
if attached a_node.author as l_author then
|
if attached a_node.author as l_author then
|
||||||
l_parameters.put (l_author.id, "id")
|
l_parameters.put (l_author.id, "author")
|
||||||
l_parameters.put (l_author.id, "editor")
|
|
||||||
else
|
else
|
||||||
l_parameters.put (0, "id")
|
l_parameters.put (0, "author")
|
||||||
l_parameters.put (0, "editor")
|
|
||||||
end
|
end
|
||||||
sql_change (sql_update_node, l_parameters)
|
sql_change (sql_update_node, l_parameters)
|
||||||
sql_post_execution
|
sql_post_execution
|
||||||
|
if not error_handler.has_error then
|
||||||
|
a_node.set_modification_date (now)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
update_node_title (a_user_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_title: READABLE_STRING_32)
|
update_node_title (a_user_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_title: READABLE_STRING_32)
|
||||||
@@ -210,8 +211,8 @@ feature -- Change: Node
|
|||||||
log.write_information (generator + ".update_node_title")
|
log.write_information (generator + ".update_node_title")
|
||||||
create l_parameters.make (3)
|
create l_parameters.make (3)
|
||||||
l_parameters.put (a_title, "title")
|
l_parameters.put (a_title, "title")
|
||||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
|
l_parameters.put (create {DATE_TIME}.make_now_utc, "changed")
|
||||||
l_parameters.put (a_node_id, "id")
|
l_parameters.put (a_node_id, "nid")
|
||||||
sql_change (sql_update_node_title, l_parameters)
|
sql_change (sql_update_node_title, l_parameters)
|
||||||
sql_post_execution
|
sql_post_execution
|
||||||
end
|
end
|
||||||
@@ -227,8 +228,8 @@ feature -- Change: Node
|
|||||||
log.write_information (generator + ".update_node_summary")
|
log.write_information (generator + ".update_node_summary")
|
||||||
create l_parameters.make (3)
|
create l_parameters.make (3)
|
||||||
l_parameters.put (a_summary, "summary")
|
l_parameters.put (a_summary, "summary")
|
||||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
|
l_parameters.put (create {DATE_TIME}.make_now_utc, "changed")
|
||||||
l_parameters.put (a_node_id, "id")
|
l_parameters.put (a_node_id, "nid")
|
||||||
sql_change (sql_update_node_summary, l_parameters)
|
sql_change (sql_update_node_summary, l_parameters)
|
||||||
sql_post_execution
|
sql_post_execution
|
||||||
end
|
end
|
||||||
@@ -244,8 +245,8 @@ feature -- Change: Node
|
|||||||
log.write_information (generator + ".update_node_content")
|
log.write_information (generator + ".update_node_content")
|
||||||
create l_parameters.make (3)
|
create l_parameters.make (3)
|
||||||
l_parameters.put (a_content, "content")
|
l_parameters.put (a_content, "content")
|
||||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
|
l_parameters.put (create {DATE_TIME}.make_now_utc, "changed")
|
||||||
l_parameters.put (a_node_id, "id")
|
l_parameters.put (a_node_id, "nid")
|
||||||
sql_change (sql_update_node_content, l_parameters)
|
sql_change (sql_update_node_content, l_parameters)
|
||||||
sql_post_execution
|
sql_post_execution
|
||||||
end
|
end
|
||||||
@@ -257,49 +258,36 @@ feature {NONE} -- Queries
|
|||||||
Select_nodes: STRING = "select * from Nodes;"
|
Select_nodes: STRING = "select * from Nodes;"
|
||||||
-- SQL Query to retrieve all nodes.
|
-- SQL Query to retrieve all nodes.
|
||||||
|
|
||||||
Select_node_by_id: STRING = "select * from Nodes where id =:id order by id desc, publication_date desc;"
|
Select_node_by_id: STRING = "select * from Nodes where nid =:nid order by nid desc, publish desc;"
|
||||||
|
|
||||||
Select_recent_nodes: STRING = "select * from Nodes order by id desc, publication_date desc LIMIT :rows OFFSET :offset ;"
|
Select_recent_nodes: STRING = "select * from Nodes order by nid desc, publish desc LIMIT :rows OFFSET :offset ;"
|
||||||
|
|
||||||
SQL_Insert_node: STRING = "insert into nodes (title, summary, content, publication_date, creation_date, modification_date, author_id) values (:title, :summary, :content, :publication_date, :creation_date, :modification_date, :author_id);"
|
SQL_Insert_node: STRING = "insert into nodes (title, summary, content, publish, created, changed, author) values (:title, :summary, :content, :publish, :created, :changed, :author);"
|
||||||
-- SQL Insert to add a new node.
|
-- SQL Insert to add a new node.
|
||||||
|
|
||||||
SQL_Update_node_title: STRING ="update nodes SET title=:title, modification_date=:modification_date, version = version + 1 where id=:id;"
|
SQL_Update_node : STRING = "update nodes SET title=:title, summary=:summary, content=:content, publish=:publish, changed=:changed, version = version + 1, author=:author where nid=:nid;"
|
||||||
-- SQL update node title.
|
|
||||||
|
|
||||||
SQL_Update_node_summary: STRING ="update nodes SET summary=:summary, modification_date=:modification_date, version = version + 1 where id=:id;"
|
|
||||||
-- SQL update node summary.
|
|
||||||
|
|
||||||
SQL_Update_node_content: STRING ="update nodes SET content=:content, modification_date=:modification_date, version = version + 1 where id=:id;"
|
|
||||||
-- SQL node content.
|
|
||||||
|
|
||||||
Slq_update_editor: STRING ="update nodes SET editor_id=:users_id where id=:nodes_id;"
|
|
||||||
-- SQL node content.
|
|
||||||
|
|
||||||
SQL_Update_node : STRING = "update nodes SET title=:title, summary=:summary, content=:content, publication_date=:publication_date, modification_date=:modification_date, version = version + 1, editor_id=:editor where id=:id;"
|
|
||||||
-- SQL node.
|
-- SQL node.
|
||||||
|
|
||||||
SQL_Delete_node: STRING = "delete from nodes where id=:id;"
|
SQL_Delete_node: STRING = "delete from nodes where nid=:nid;"
|
||||||
|
|
||||||
Sql_update_node_author: STRING = "update nodes SET author_id=:user_id where id=:id;"
|
Sql_update_node_author: STRING = "update nodes SET author=:author where nid=:nid;"
|
||||||
|
|
||||||
Sql_last_insert_node_id: STRING = "SELECT MAX(id) from nodes;"
|
SQL_Update_node_title: STRING ="update nodes SET title=:title, changed=:changed, version = version + 1 where nid=:nid;"
|
||||||
|
-- SQL update node title.
|
||||||
|
|
||||||
|
SQL_Update_node_summary: STRING ="update nodes SET summary=:summary, changed=:changed, version = version + 1 where nid=:nid;"
|
||||||
|
-- SQL update node summary.
|
||||||
|
|
||||||
|
SQL_Update_node_content: STRING ="update nodes SET content=:content, changed=:changed, version = version + 1 where nid=:nid;"
|
||||||
|
-- SQL node content.
|
||||||
|
|
||||||
|
Sql_last_insert_node_id: STRING = "SELECT MAX(nid) from nodes;"
|
||||||
|
|
||||||
feature {NONE} -- Sql Queries: USER_ROLES collaborators, author
|
feature {NONE} -- Sql Queries: USER_ROLES collaborators, author
|
||||||
|
|
||||||
Sql_insert_users_nodes: STRING = "insert into users_nodes (users_id, nodes_id) values (:users_id, :nodes_id);"
|
Select_user_author: STRING = "SELECT * FROM Nodes INNER JOIN users ON nodes.author=users.uid and users.uid = :uid;"
|
||||||
|
|
||||||
select_node_collaborators: STRING = "SELECT * FROM Users INNER JOIN users_nodes ON users.id=users_nodes.users_id and users_nodes.nodes_id = :node_id;"
|
Select_node_author: STRING = "SELECT * FROM Users INNER JOIN nodes ON nodes.author=users.uid and nodes.nid =:nid;"
|
||||||
|
|
||||||
Select_user_author: STRING = "SELECT * FROM Nodes INNER JOIN users ON nodes.author_id=users.id and users.id = :user_id;"
|
|
||||||
|
|
||||||
Select_node_author: STRING = "SELECT * FROM Users INNER JOIN nodes ON nodes.author_id=users.id and nodes.id =:node_id;"
|
|
||||||
|
|
||||||
Select_user_collaborator: STRING = "SELECT * FROM Nodes INNER JOIN users_nodes ON users_nodes.nodes_id = nodes.id and users_nodes.users_id = :user_id;"
|
|
||||||
|
|
||||||
Select_exist_user_node: STRING= "Select Count(*) from Users_nodes where users_id=:user_id and nodes_id=:node_id;"
|
|
||||||
|
|
||||||
sql_delete_from_user_node: STRING = "delete from users_nodes where nodes_id=:id"
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
@@ -309,24 +297,27 @@ feature {NONE} -- Implementation
|
|||||||
if attached sql_read_integer_64 (1) as l_id then
|
if attached sql_read_integer_64 (1) as l_id then
|
||||||
Result.set_id (l_id)
|
Result.set_id (l_id)
|
||||||
end
|
end
|
||||||
if attached sql_read_date_time (2) as l_publication_date then
|
if attached sql_read_string_32 (4) as l_title then
|
||||||
Result.set_publication_date (l_publication_date)
|
|
||||||
end
|
|
||||||
if attached sql_read_date_time (3) as l_creation_date then
|
|
||||||
Result.set_creation_date (l_creation_date)
|
|
||||||
end
|
|
||||||
if attached sql_read_date_time (4) as l_modif_date then
|
|
||||||
Result.set_modification_date (l_modif_date)
|
|
||||||
end
|
|
||||||
if attached sql_read_string_32 (5) as l_title then
|
|
||||||
Result.set_title (l_title)
|
Result.set_title (l_title)
|
||||||
end
|
end
|
||||||
if attached sql_read_string_32 (6) as l_summary then
|
if attached sql_read_string_32 (5) as l_summary then
|
||||||
Result.set_summary (l_summary)
|
Result.set_summary (l_summary)
|
||||||
end
|
end
|
||||||
if attached sql_read_string (7) as l_content then
|
if attached sql_read_string (6) as l_content then
|
||||||
Result.set_content (l_content)
|
Result.set_content (l_content)
|
||||||
end
|
end
|
||||||
|
if attached sql_read_date_time (8) as l_publication_date then
|
||||||
|
Result.set_publication_date (l_publication_date)
|
||||||
|
end
|
||||||
|
if attached sql_read_date_time (9) as l_creation_date then
|
||||||
|
Result.set_creation_date (l_creation_date)
|
||||||
|
end
|
||||||
|
if attached sql_read_date_time (10) as l_modif_date then
|
||||||
|
Result.set_modification_date (l_modif_date)
|
||||||
|
end
|
||||||
|
if attached sql_read_integer_64 (7) as l_author_id then
|
||||||
|
-- access to API ...
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
fetch_author: detachable CMS_USER
|
fetch_author: detachable CMS_USER
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ feature -- Access
|
|||||||
deferred
|
deferred
|
||||||
ensure
|
ensure
|
||||||
same_id: Result /= Void implies Result.id = a_id
|
same_id: Result /= Void implies Result.id = a_id
|
||||||
password: Result /= Void implies Result.password /= Void
|
password: Result /= Void implies (Result.hashed_password /= Void and Result.password = Void)
|
||||||
end
|
end
|
||||||
|
|
||||||
user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER
|
user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER
|
||||||
@@ -46,7 +46,7 @@ feature -- Access
|
|||||||
deferred
|
deferred
|
||||||
ensure
|
ensure
|
||||||
same_name: Result /= Void implies a_name ~ Result.name
|
same_name: Result /= Void implies a_name ~ Result.name
|
||||||
password: Result /= Void implies Result.password /= Void
|
password: Result /= Void implies (Result.hashed_password /= Void and Result.password = Void)
|
||||||
end
|
end
|
||||||
|
|
||||||
user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER
|
user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER
|
||||||
@@ -54,7 +54,7 @@ feature -- Access
|
|||||||
deferred
|
deferred
|
||||||
ensure
|
ensure
|
||||||
same_email: Result /= Void implies a_email ~ Result.email
|
same_email: Result /= Void implies a_email ~ Result.email
|
||||||
password: Result /= Void implies Result.password /= Void
|
password: Result /= Void implies (Result.hashed_password /= Void and Result.password = Void)
|
||||||
end
|
end
|
||||||
|
|
||||||
is_valid_credential (a_u, a_p: READABLE_STRING_32): BOOLEAN
|
is_valid_credential (a_u, a_p: READABLE_STRING_32): BOOLEAN
|
||||||
@@ -64,8 +64,17 @@ feature -- Access
|
|||||||
|
|
||||||
feature -- Change: user
|
feature -- Change: user
|
||||||
|
|
||||||
save_user (a_user: CMS_USER)
|
new_user (a_user: CMS_USER)
|
||||||
|
-- New user `a_user'.
|
||||||
|
require
|
||||||
|
no_id: not a_user.has_id
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
update_user (a_user: CMS_USER)
|
||||||
-- Save user `a_user'.
|
-- Save user `a_user'.
|
||||||
|
require
|
||||||
|
has_id: a_user.has_id
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ feature -- Access: user
|
|||||||
from
|
from
|
||||||
sql_query (select_users, Void)
|
sql_query (select_users, Void)
|
||||||
sql_post_execution
|
sql_post_execution
|
||||||
|
sql_start
|
||||||
until
|
until
|
||||||
sql_after
|
sql_after
|
||||||
loop
|
loop
|
||||||
@@ -66,7 +67,7 @@ feature -- Access: user
|
|||||||
error_handler.reset
|
error_handler.reset
|
||||||
log.write_information (generator + ".user")
|
log.write_information (generator + ".user")
|
||||||
create l_parameters.make (1)
|
create l_parameters.make (1)
|
||||||
l_parameters.put (a_id, "id")
|
l_parameters.put (a_id, "uid")
|
||||||
sql_query (select_user_by_id, l_parameters)
|
sql_query (select_user_by_id, l_parameters)
|
||||||
if sql_rows_count = 1 then
|
if sql_rows_count = 1 then
|
||||||
Result := fetch_user
|
Result := fetch_user
|
||||||
@@ -136,20 +137,81 @@ feature -- Access: user
|
|||||||
|
|
||||||
feature -- Change: user
|
feature -- Change: user
|
||||||
|
|
||||||
save_user (a_user: CMS_USER)
|
new_user (a_user: CMS_USER)
|
||||||
-- Add a new user `a_user'.
|
-- Add a new user `a_user'.
|
||||||
|
local
|
||||||
|
l_parameters: STRING_TABLE [detachable ANY]
|
||||||
|
l_password_salt, l_password_hash: STRING
|
||||||
|
l_security: SECURITY_PROVIDER
|
||||||
do
|
do
|
||||||
if
|
if
|
||||||
attached a_user.password as l_password and then
|
attached a_user.password as l_password and then
|
||||||
attached a_user.email as l_email
|
attached a_user.email as l_email
|
||||||
then
|
then
|
||||||
sql_begin_transaction
|
sql_begin_transaction
|
||||||
new_user (a_user)
|
error_handler.reset
|
||||||
|
create l_security
|
||||||
|
l_password_salt := l_security.salt
|
||||||
|
l_password_hash := l_security.password_hash (l_password, l_password_salt)
|
||||||
|
|
||||||
|
log.write_information (generator + ".new_user")
|
||||||
|
create l_parameters.make (4)
|
||||||
|
l_parameters.put (a_user.name, "name")
|
||||||
|
l_parameters.put (l_password_hash, "password")
|
||||||
|
l_parameters.put (l_password_salt, "salt")
|
||||||
|
l_parameters.put (l_email, "email")
|
||||||
|
l_parameters.put (create {DATE_TIME}.make_now_utc, "created")
|
||||||
|
|
||||||
|
sql_change (sql_insert_user, l_parameters)
|
||||||
|
sql_post_execution
|
||||||
|
if not error_handler.has_error then
|
||||||
|
a_user.set_id (last_inserted_user_id)
|
||||||
|
sql_post_execution
|
||||||
|
end
|
||||||
sql_commit_transaction
|
sql_commit_transaction
|
||||||
else
|
else
|
||||||
debug ("refactor_fixme")
|
-- set error
|
||||||
fixme ("maybe we should not always carry password, in this case, to implement the else part..")
|
error_handler.add_custom_error (-1, "bad request" , "Missing password or email")
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
update_user (a_user: CMS_USER)
|
||||||
|
-- Save user `a_user'.
|
||||||
|
local
|
||||||
|
l_parameters: STRING_TABLE [detachable ANY]
|
||||||
|
l_password_salt, l_password_hash: detachable READABLE_STRING_8
|
||||||
|
l_security: SECURITY_PROVIDER
|
||||||
|
do
|
||||||
|
if attached a_user.password as l_password then
|
||||||
|
-- New password!
|
||||||
|
create l_security
|
||||||
|
l_password_salt := l_security.salt
|
||||||
|
l_password_hash := l_security.password_hash (l_password, l_password_salt)
|
||||||
|
else
|
||||||
|
-- Existing hashed password
|
||||||
|
l_password_hash := a_user.hashed_password
|
||||||
|
l_password_salt := user_salt (a_user.name)
|
||||||
|
end
|
||||||
|
if
|
||||||
|
l_password_hash /= Void and l_password_salt /= Void and
|
||||||
|
attached a_user.email as l_email
|
||||||
|
then
|
||||||
|
error_handler.reset
|
||||||
|
|
||||||
|
log.write_information (generator + ".update_user")
|
||||||
|
create l_parameters.make (6)
|
||||||
|
l_parameters.put (a_user.id, "uid")
|
||||||
|
l_parameters.put (a_user.name, "name")
|
||||||
|
l_parameters.put (l_password_hash, "password")
|
||||||
|
l_parameters.put (l_password_salt, "salt")
|
||||||
|
l_parameters.put (l_email, "email")
|
||||||
|
l_parameters.put (create {DATE_TIME}.make_now_utc, "changed")
|
||||||
|
|
||||||
|
sql_change (sql_update_user, l_parameters)
|
||||||
|
sql_post_execution
|
||||||
|
else
|
||||||
|
-- set error
|
||||||
|
error_handler.add_custom_error (-1, "bad request" , "Missing password or email")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -193,44 +255,6 @@ feature {NONE} -- Implementation
|
|||||||
sql_post_execution
|
sql_post_execution
|
||||||
end
|
end
|
||||||
|
|
||||||
new_user (a_user: CMS_USER)
|
|
||||||
-- Add a new user `a_user'.
|
|
||||||
require
|
|
||||||
no_id: not a_user.has_id
|
|
||||||
local
|
|
||||||
l_parameters: STRING_TABLE [detachable ANY]
|
|
||||||
l_password_salt, l_password_hash: STRING
|
|
||||||
l_security: SECURITY_PROVIDER
|
|
||||||
do
|
|
||||||
if
|
|
||||||
attached a_user.password as l_password and then
|
|
||||||
attached a_user.email as l_email
|
|
||||||
then
|
|
||||||
error_handler.reset
|
|
||||||
create l_security
|
|
||||||
l_password_salt := l_security.salt
|
|
||||||
l_password_hash := l_security.password_hash (l_password, l_password_salt)
|
|
||||||
|
|
||||||
log.write_information (generator + ".new_user")
|
|
||||||
create l_parameters.make (4)
|
|
||||||
l_parameters.put (a_user.name, "username")
|
|
||||||
l_parameters.put (l_password_hash, "password")
|
|
||||||
l_parameters.put (l_password_salt, "salt")
|
|
||||||
l_parameters.put (l_email, "email")
|
|
||||||
|
|
||||||
sql_change (sql_insert_user, l_parameters)
|
|
||||||
sql_post_execution
|
|
||||||
if not error_handler.has_error then
|
|
||||||
a_user.set_id (last_inserted_user_id)
|
|
||||||
sql_post_execution
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- set error
|
|
||||||
error_handler.add_custom_error (-1, "bad request" , "Missing password or email")
|
|
||||||
end
|
|
||||||
sql_post_execution
|
|
||||||
end
|
|
||||||
|
|
||||||
fetch_user: detachable CMS_USER
|
fetch_user: detachable CMS_USER
|
||||||
local
|
local
|
||||||
l_id: INTEGER_64
|
l_id: INTEGER_64
|
||||||
@@ -282,25 +306,27 @@ feature {NONE} -- Sql Queries: USER
|
|||||||
Select_users_count: STRING = "select count(*) from Users;"
|
Select_users_count: STRING = "select count(*) from Users;"
|
||||||
-- Number of users.
|
-- Number of users.
|
||||||
|
|
||||||
Sql_last_insert_user_id: STRING = "SELECT MAX(id) from Users;"
|
Sql_last_insert_user_id: STRING = "SELECT MAX(uid) from Users;"
|
||||||
|
|
||||||
Select_users: STRING = "select * from Users;"
|
Select_users: STRING = "select * from Users;"
|
||||||
-- List of users.
|
-- List of users.
|
||||||
|
|
||||||
Select_user_by_id: STRING = "select * from Users where id =:id;"
|
Select_user_by_id: STRING = "select * from Users where uid =:uid;"
|
||||||
-- Retrieve user by id if exists.
|
-- Retrieve user by id if exists.
|
||||||
|
|
||||||
Select_user_by_name: STRING = "select * from Users where username =:name;"
|
Select_user_by_name: STRING = "select * from Users where name =:name;"
|
||||||
-- Retrieve user by name if exists.
|
-- Retrieve user by name if exists.
|
||||||
|
|
||||||
Select_user_by_email: STRING = "select * from Users where email =:email;"
|
Select_user_by_email: STRING = "select * from Users where email =:email;"
|
||||||
-- Retrieve user by email if exists.
|
-- Retrieve user by email if exists.
|
||||||
|
|
||||||
Select_salt_by_username: STRING = "select salt from Users where username =:name;"
|
Select_salt_by_username: STRING = "select salt from Users where name =:name;"
|
||||||
-- Retrieve salt by username if exists.
|
-- Retrieve salt by username if exists.
|
||||||
|
|
||||||
SQL_Insert_user: STRING = "insert into users (username, password, salt, email) values (:username, :password, :salt, :email);"
|
Sql_Insert_user: STRING = "insert into users (name, password, salt, email, created) values (:name, :password, :salt, :email, :created);"
|
||||||
-- SQL Insert to add a new node.
|
-- SQL Insert to add a new node.
|
||||||
|
|
||||||
|
sql_update_user: STRING = "update users SET name=:name, password=:password, salt=:salt, email=:email WHERE uid=:uid;"
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -88,12 +88,14 @@ feature -- Status Report
|
|||||||
|
|
||||||
feature -- Access: Node
|
feature -- Access: Node
|
||||||
|
|
||||||
|
nodes_count: INTEGER_64
|
||||||
|
do
|
||||||
|
Result := storage.nodes_count
|
||||||
|
end
|
||||||
|
|
||||||
nodes: LIST [CMS_NODE]
|
nodes: LIST [CMS_NODE]
|
||||||
-- List of nodes.
|
-- List of nodes.
|
||||||
do
|
do
|
||||||
debug ("refactor_fixme")
|
|
||||||
fixme ("Implementation")
|
|
||||||
end
|
|
||||||
Result := storage.nodes
|
Result := storage.nodes
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -174,12 +176,15 @@ feature -- Change User
|
|||||||
|
|
||||||
new_user (a_user: CMS_USER)
|
new_user (a_user: CMS_USER)
|
||||||
-- Add a new user `a_user'.
|
-- Add a new user `a_user'.
|
||||||
|
require
|
||||||
|
no_id: not a_user.has_id
|
||||||
|
no_hashed_password: a_user.hashed_password = Void
|
||||||
do
|
do
|
||||||
if
|
if
|
||||||
attached a_user.password as l_password and then
|
attached a_user.password as l_password and then
|
||||||
attached a_user.email as l_email
|
attached a_user.email as l_email
|
||||||
then
|
then
|
||||||
storage.save_user (a_user)
|
storage.new_user (a_user)
|
||||||
else
|
else
|
||||||
debug ("refactor_fixme")
|
debug ("refactor_fixme")
|
||||||
fixme ("Add error")
|
fixme ("Add error")
|
||||||
@@ -187,6 +192,14 @@ feature -- Change User
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
update_user (a_user: CMS_USER)
|
||||||
|
-- Update user `a_user'.
|
||||||
|
require
|
||||||
|
has_id: a_user.has_id
|
||||||
|
do
|
||||||
|
storage.update_user (a_user)
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Helpers
|
feature -- Helpers
|
||||||
|
|
||||||
html_encoded (a_string: READABLE_STRING_GENERAL): STRING_8
|
html_encoded (a_string: READABLE_STRING_GENERAL): STRING_8
|
||||||
|
|||||||
Reference in New Issue
Block a user