Compare commits
6 Commits
es_rev9851
...
storage_sq
| Author | SHA1 | Date | |
|---|---|---|---|
| db6afb6952 | |||
| d23cfbc300 | |||
| 4aa9c1e097 | |||
| a074a57d62 | |||
| bba0364a2c | |||
| 4dcc1b0e04 |
@@ -15,7 +15,6 @@
|
||||
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
|
||||
<library name="layout" location=".\library\layout\layout-safe.ecf"/>
|
||||
<library name="model" location=".\library\model\cms_model-safe.ecf" readonly="false"/>
|
||||
<library name="persistence_mysql" location=".\library\persistence\implementation\mysql\persistence_mysql-safe.ecf" readonly="false"/>
|
||||
<library name="smarty" location="$ISE_LIBRARY\contrib\library\text\template\smarty\smarty-safe.ecf" readonly="false"/>
|
||||
<library name="text_filter" location="$ISE_LIBRARY\unstable\library\text\text_filter\text_filter-safe.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
|
||||
@@ -9,10 +9,13 @@
|
||||
<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"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="none"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<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="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_sqlite" location="..\..\library\persistence\implementation\sqlite\persistence_sqlite-safe.ecf" readonly="false"/>
|
||||
<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"/>
|
||||
</target>
|
||||
@@ -26,6 +29,7 @@
|
||||
</target>
|
||||
<target name="demo_nino" extends="common">
|
||||
<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"/>
|
||||
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
{
|
||||
"database": {
|
||||
"datasource": {
|
||||
"driver": "MySQL",
|
||||
"driver": "sqlite",
|
||||
"environment": "sqlite_development"
|
||||
},
|
||||
"olddatasource": {
|
||||
"driver": "null",
|
||||
"environment": "development"
|
||||
},
|
||||
"environments": {
|
||||
"sqlite_development": {
|
||||
"connection_string":"Server=localhost;Port=3306;Database=site/cms_lite.db;Uid=root;Pwd=;"
|
||||
},
|
||||
"test": {
|
||||
"connection_string":"Server=localhost;Port=3306;Database=cms_dev;Uid=root;Pwd=;"
|
||||
},
|
||||
@@ -29,4 +36,4 @@
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
engine=smarty
|
||||
site.name=EWF Web CMS
|
||||
site.email=your@email.com
|
||||
var-dir=var
|
||||
files-dir=files
|
||||
[layout]
|
||||
root-dir=site/www
|
||||
themes-dir=site/www/themes
|
||||
|
||||
[site]
|
||||
name=Eiffel CMS
|
||||
email=your@email.com
|
||||
theme=bootstrap
|
||||
|
||||
[misc]
|
||||
smtp=localhost
|
||||
|
||||
@@ -147,6 +147,9 @@ feature -- CMS setup
|
||||
debug ("refactor_fixme")
|
||||
to_implement ("To implement custom storage")
|
||||
end
|
||||
a_setup.storage_drivers.force (create {CMS_STORAGE_MYSQL_BUILDER}.make, "mysql")
|
||||
a_setup.storage_drivers.force (create {CMS_STORAGE_SQLITE_BUILDER}.make, "sqlite")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ feature -- Application Configuration
|
||||
attached {JSON_OBJECT} l_environments.item (l_envrionment.item) as l_environment_selected and then
|
||||
attached {JSON_STRING} l_environment_selected.item ("connection_string") as l_connection_string
|
||||
then
|
||||
create Result.make (l_driver.item, l_connection_string.unescaped_string_8)
|
||||
create Result.make (l_driver.item, l_connection_string.unescaped_string_32)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,10 +33,65 @@ feature -- Access
|
||||
connection_string: READABLE_STRING_32
|
||||
-- Connection string
|
||||
do
|
||||
Result := "Driver={"+driver+"};" + database_string;
|
||||
Result := "Driver={" + driver + "};" + database_string
|
||||
end
|
||||
|
||||
item (a_param: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
|
||||
local
|
||||
s: READABLE_STRING_32
|
||||
lower_s: READABLE_STRING_32
|
||||
i,j: INTEGER
|
||||
k: STRING_32
|
||||
do
|
||||
create k.make_from_string_general (a_param)
|
||||
k.to_lower
|
||||
|
||||
s := database_string
|
||||
lower_s := s.as_lower
|
||||
i := lower_s.substring_index (k + {STRING_32} "=", 1)
|
||||
if i > 0 then
|
||||
if i = 1 or else s[i-1] = ';' then
|
||||
j := s.index_of (';', i + k.count + 1)
|
||||
if j = 0 then
|
||||
j := s.count + 1
|
||||
end
|
||||
Result := s.substring (i + k.count + 1, j - 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
server_name: detachable READABLE_STRING_32
|
||||
do
|
||||
Result := item ("Server")
|
||||
end
|
||||
|
||||
port: INTEGER
|
||||
do
|
||||
if
|
||||
attached item ("Port") as l_port and then
|
||||
l_port.is_integer
|
||||
then
|
||||
Result := l_port.to_integer
|
||||
end
|
||||
end
|
||||
|
||||
database_name: detachable READABLE_STRING_32
|
||||
do
|
||||
Result := item ("Database")
|
||||
end
|
||||
|
||||
user_id: detachable READABLE_STRING_32
|
||||
do
|
||||
Result := item ("Uid")
|
||||
end
|
||||
|
||||
user_password: detachable READABLE_STRING_32
|
||||
do
|
||||
Result := item ("Pwd")
|
||||
end
|
||||
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
|
||||
copyright: "2011-2015, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
note
|
||||
description: "Provides logger information"
|
||||
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
|
||||
revision: "$Revision: 95678 $"
|
||||
date: "$Date: 2015-01-15 00:00:58 +0100 (jeu., 15 janv. 2015) $"
|
||||
revision: "$Revision: 96461 $"
|
||||
|
||||
class
|
||||
SHARED_LOGGER
|
||||
@@ -29,7 +29,7 @@ feature -- Logger
|
||||
create l_environment
|
||||
if attached separate_character_option_value ('d') as l_dir then
|
||||
l_path := create {PATH}.make_from_string (l_dir)
|
||||
create l_log_writer.make_at_location (l_path.extended ("..").appended ("\api.log"))
|
||||
create l_log_writer.make_at_location (l_path.extended ("logs").appended ("\api.log"))
|
||||
else
|
||||
l_path := create {PATH}.make_current
|
||||
create l_log_writer.make_at_location (l_path.extended("api.log"))
|
||||
@@ -82,23 +82,26 @@ feature {NONE} -- JSON
|
||||
do
|
||||
create Result
|
||||
if attached json_file_from (a_path) as json_file then
|
||||
l_parser := new_json_parser (json_file)
|
||||
if attached {JSON_OBJECT} l_parser.parse as jv and then l_parser.is_parsed and then
|
||||
attached {JSON_OBJECT} jv.item ("logger") as l_logger and then
|
||||
attached {JSON_STRING} l_logger.item ("backup_count") as l_count and then
|
||||
attached {JSON_STRING} l_logger.item ("level") as l_level then
|
||||
Result.set_level (l_level.item)
|
||||
if l_count.item.is_natural then
|
||||
Result.set_backup_count (l_count.item.to_natural)
|
||||
end
|
||||
end
|
||||
l_parser := new_json_parser (json_file)
|
||||
if attached {JSON_OBJECT} l_parser.parse as jv and then l_parser.is_parsed and then
|
||||
attached {JSON_OBJECT} jv.item ("logger") as l_logger and then
|
||||
attached {JSON_STRING} l_logger.item ("backup_count") as l_count and then
|
||||
attached {JSON_STRING} l_logger.item ("level") as l_level then
|
||||
Result.set_level (l_level.item)
|
||||
if l_count.item.is_natural then
|
||||
Result.set_backup_count (l_count.item.to_natural)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
json_file_from (a_fn: PATH): detachable STRING
|
||||
local
|
||||
ut: FILE_UTILITIES
|
||||
do
|
||||
Result := (create {JSON_FILE_READER}).read_json_from (a_fn.name.out)
|
||||
if ut.file_path_exists (a_fn) then
|
||||
Result := (create {JSON_FILE_READER}).read_json_from (a_fn.name)
|
||||
end
|
||||
end
|
||||
|
||||
new_json_parser (a_string: STRING): JSON_PARSER
|
||||
@@ -107,6 +110,6 @@ feature {NONE} -- JSON
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
|
||||
copyright: "2011-2015, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
|
||||
@@ -83,8 +83,8 @@ feature -- Access
|
||||
author: detachable CMS_USER
|
||||
-- Author of current node.
|
||||
|
||||
collaborators: detachable LIST[CMS_USER]
|
||||
-- Users contributed to current Node.
|
||||
-- collaborators: detachable LIST[CMS_USER]
|
||||
-- -- Users contributed to current Node.
|
||||
|
||||
feature -- status report
|
||||
|
||||
@@ -177,18 +177,18 @@ feature -- Element change
|
||||
auther_set: author = u
|
||||
end
|
||||
|
||||
add_collaborator (a_user: CMS_USER)
|
||||
-- Add collaborator `a_user' to the collaborators list.
|
||||
local
|
||||
lst: like collaborators
|
||||
do
|
||||
lst := collaborators
|
||||
if lst = Void then
|
||||
create {ARRAYED_SET [CMS_USER]} lst.make (1)
|
||||
collaborators := lst
|
||||
end
|
||||
lst.force (a_user)
|
||||
end
|
||||
-- add_collaborator (a_user: CMS_USER)
|
||||
-- -- Add collaborator `a_user' to the collaborators list.
|
||||
-- local
|
||||
-- lst: like collaborators
|
||||
-- do
|
||||
-- lst := collaborators
|
||||
-- if lst = Void then
|
||||
-- create {ARRAYED_SET [CMS_USER]} lst.make (1)
|
||||
-- collaborators := lst
|
||||
-- end
|
||||
-- lst.force (a_user)
|
||||
-- end
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
|
||||
|
||||
@@ -13,19 +13,38 @@ inherit
|
||||
DEBUG_OUTPUT
|
||||
|
||||
create
|
||||
make
|
||||
make,
|
||||
make_with_id -- MAYBE: export to CMS_STORAGE
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_name: READABLE_STRING_32)
|
||||
-- Create an object with name `a_name'.
|
||||
require
|
||||
a_name_not_empty: not a_name.is_whitespace
|
||||
do
|
||||
name := a_name
|
||||
create creation_date.make_now_utc
|
||||
initialize
|
||||
ensure
|
||||
name_set: name = a_name
|
||||
end
|
||||
|
||||
make_with_id (a_id: INTEGER_64)
|
||||
require
|
||||
a_id_valid: a_id > 0
|
||||
do
|
||||
id := a_id
|
||||
name := {STRING_32} ""
|
||||
initialize
|
||||
ensure
|
||||
id_set: id = a_id
|
||||
end
|
||||
|
||||
initialize
|
||||
do
|
||||
create creation_date.make_now_utc
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
id: INTEGER_64
|
||||
@@ -35,7 +54,10 @@ feature -- Access
|
||||
-- User name.
|
||||
|
||||
password: detachable READABLE_STRING_32
|
||||
-- User password.
|
||||
-- User password (plain text password).
|
||||
|
||||
hashed_password: detachable READABLE_STRING_8
|
||||
-- Hashed user password.
|
||||
|
||||
email: detachable READABLE_STRING_32
|
||||
-- User email.
|
||||
@@ -113,8 +135,20 @@ feature -- Change element
|
||||
-- Set `password' with `a_password'.
|
||||
do
|
||||
password := a_password
|
||||
hashed_password := Void
|
||||
ensure
|
||||
password_set: password = a_password
|
||||
hashed_password_void: hashed_password = Void
|
||||
end
|
||||
|
||||
set_hashed_password (a_hashed_password: like hashed_password)
|
||||
-- Set `hashed_password' with `a_hashed_password'.
|
||||
do
|
||||
hashed_password := a_hashed_password
|
||||
password := Void
|
||||
ensure
|
||||
password_void: password = Void
|
||||
hashed_password_set: hashed_password = a_hashed_password
|
||||
end
|
||||
|
||||
set_email (a_email: like email)
|
||||
@@ -178,6 +212,10 @@ feature -- Change element: data
|
||||
end
|
||||
end
|
||||
|
||||
invariant
|
||||
|
||||
id_or_name_set: id > 0 or else not name.is_whitespace
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
|
||||
@@ -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
|
||||
@@ -45,14 +45,14 @@ feature -- Functionality Store Procedures
|
||||
execute_store_reader
|
||||
-- Execute a `store' to read data.
|
||||
require
|
||||
store_not_void: store /= void
|
||||
store_not_void: store /= Void
|
||||
deferred
|
||||
end
|
||||
|
||||
execute_store_writer
|
||||
-- Execute a `store' to write data.
|
||||
require
|
||||
store_not_void: store /= void
|
||||
store_not_void: store /= Void
|
||||
deferred
|
||||
end
|
||||
|
||||
@@ -61,14 +61,14 @@ feature -- SQL Queries
|
||||
execute_query
|
||||
-- Execute sql query, the read data from the database.
|
||||
require
|
||||
query_not_void: query /= void
|
||||
query_not_void: query /= Void
|
||||
deferred
|
||||
end
|
||||
|
||||
execute_change
|
||||
-- Execute sql query that update/add data.
|
||||
require
|
||||
query_not_void: query /= void
|
||||
query_not_void: query /= Void
|
||||
deferred
|
||||
end
|
||||
|
||||
@@ -153,22 +153,22 @@ feature -- Status Report
|
||||
end
|
||||
|
||||
connection: DATABASE_CONNECTION
|
||||
-- Database connection.
|
||||
-- Database connection.
|
||||
|
||||
db_control: DB_CONTROL
|
||||
-- Database control.
|
||||
-- Database control.
|
||||
do
|
||||
Result := connection.db_control
|
||||
end
|
||||
|
||||
db_result: detachable DB_RESULT
|
||||
-- Database query result.
|
||||
-- Database query result.
|
||||
|
||||
db_selection: detachable DB_SELECTION
|
||||
-- Database selection.
|
||||
-- Database selection.
|
||||
|
||||
db_change: detachable DB_CHANGE
|
||||
-- Database modification.
|
||||
-- Database modification.
|
||||
|
||||
feature -- Error handling
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ class
|
||||
DATABASE_QUERY
|
||||
|
||||
inherit
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
SHARED_LOGGER
|
||||
@@ -17,7 +16,7 @@ create
|
||||
|
||||
feature {NONE} -- Intialization
|
||||
|
||||
data_reader (a_query: STRING; a_parameters: STRING_TABLE [detachable ANY])
|
||||
data_reader (a_query: STRING; a_parameters: like parameters)
|
||||
-- SQL data reader for the query `a_query' with arguments `a_parameters'
|
||||
do
|
||||
log.write_information (generator + ".data_reader" + " execute query: " + a_query)
|
||||
@@ -65,7 +64,7 @@ feature -- Access
|
||||
query: STRING
|
||||
-- SQL query to execute.
|
||||
|
||||
parameters: STRING_TABLE [detachable ANY]
|
||||
parameters: detachable STRING_TABLE [detachable ANY]
|
||||
-- query parameters.
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
@@ -73,26 +72,24 @@ feature {NONE} -- Implementation
|
||||
set_map_name (a_base_selection: DB_EXPRESSION)
|
||||
-- Store parameters `item' and their `key'.
|
||||
do
|
||||
from
|
||||
parameters.start
|
||||
until
|
||||
parameters.after
|
||||
loop
|
||||
a_base_selection.set_map_name (parameters.item_for_iteration, parameters.key_for_iteration)
|
||||
parameters.forth
|
||||
if attached parameters as l_parameters then
|
||||
across
|
||||
l_parameters as ic
|
||||
loop
|
||||
a_base_selection.set_map_name (ic.item, ic.key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
unset_map_name (a_base_selection: DB_EXPRESSION)
|
||||
-- Remove parameters item associated with key `key'.
|
||||
do
|
||||
from
|
||||
parameters.start
|
||||
until
|
||||
parameters.after
|
||||
loop
|
||||
a_base_selection.unset_map_name (parameters.key_for_iteration)
|
||||
parameters.forth
|
||||
if attached parameters as l_parameters then
|
||||
across
|
||||
l_parameters as ic
|
||||
loop
|
||||
a_base_selection.unset_map_name (ic.key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -101,26 +98,25 @@ feature {NONE} -- Implementation
|
||||
-- exclude sensitive information.
|
||||
do
|
||||
create Result.make_empty
|
||||
from
|
||||
a_parameters.start
|
||||
until
|
||||
a_parameters.after
|
||||
loop
|
||||
Result.append ("name:")
|
||||
Result.append (a_parameters.key_for_iteration.as_string_32)
|
||||
Result.append (", value:")
|
||||
if
|
||||
a_parameters.key_for_iteration.has_substring ("Password") or else
|
||||
a_parameters.key_for_iteration.has_substring ("password")
|
||||
then
|
||||
-- Data to exclude
|
||||
else
|
||||
if attached a_parameters.item_for_iteration as l_item then
|
||||
Result.append (l_item.out)
|
||||
if a_parameters /= Void then
|
||||
across
|
||||
a_parameters as ic
|
||||
loop
|
||||
Result.append ("name:")
|
||||
Result.append (ic.key.as_string_32)
|
||||
Result.append (", value:")
|
||||
if
|
||||
ic.key.has_substring ("Password") or else
|
||||
ic.key.has_substring ("password")
|
||||
then
|
||||
-- Data to exclude
|
||||
else
|
||||
if attached ic.item as l_item then
|
||||
Result.append (l_item.out)
|
||||
end
|
||||
end
|
||||
Result.append ("%N")
|
||||
end
|
||||
Result.append ("%N")
|
||||
a_parameters.forth
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ note
|
||||
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
|
||||
revision: "$Revision: 95678 $"
|
||||
EIS: "SQL server injection", "src=http://blogs.msdn.com/b/raulga/archive/2007/01/04/dynamic-sql-sql-injection.aspx", "protocol=url"
|
||||
|
||||
expanded class
|
||||
DATABASE_SQL_SERVER_ENCODER
|
||||
|
||||
@@ -12,7 +13,7 @@ inherit
|
||||
|
||||
feature -- Escape SQL input
|
||||
|
||||
encode (a_string:READABLE_STRING_32): READABLE_STRING_32
|
||||
encode (a_string: READABLE_STRING_32): READABLE_STRING_32
|
||||
-- Escape single quote (') and braces ([,]).
|
||||
local
|
||||
l_string: STRING
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
note
|
||||
description: "Error from database"
|
||||
date: "$Date: 2013-08-08 16:39:49 -0300 (ju. 08 de ago. de 2013) $"
|
||||
revision: "$Revision: 195 $"
|
||||
date: "$Date: 2014-11-13 16:23:47 +0100 (jeu., 13 nov. 2014) $"
|
||||
revision: "$Revision: 96085 $"
|
||||
|
||||
class
|
||||
DATABASE_ERROR
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
note
|
||||
description: "Database error handler"
|
||||
date: "$Date: 2013-08-08 16:39:49 -0300 (ju. 08 de ago. de 2013) $"
|
||||
revision: "$Revision: 195 $"
|
||||
date: "$Date: 2014-11-13 16:23:47 +0100 (jeu., 13 nov. 2014) $"
|
||||
revision: "$Revision: 96085 $"
|
||||
|
||||
class
|
||||
DATABASE_ERROR_HANDLER
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
note
|
||||
description: "Summary description for {DATABASE_NO_CHANGE_ERROR}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
date: "$Date: 2014-11-13 16:23:47 +0100 (jeu., 13 nov. 2014) $"
|
||||
revision: "$Revision: 96085 $"
|
||||
|
||||
class
|
||||
DATABASE_NO_CHANGE_ERROR
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
note
|
||||
description: "Summary description for {STRING_HELPER}."
|
||||
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
|
||||
revision: "$Revision: 95593 $"
|
||||
|
||||
class
|
||||
STRING_HELPER
|
||||
|
||||
feature -- Access
|
||||
|
||||
is_blank (s: detachable READABLE_STRING_32): BOOLEAN
|
||||
local
|
||||
i,n: INTEGER
|
||||
do
|
||||
Result := True
|
||||
if s /= Void then
|
||||
from
|
||||
i := 1
|
||||
n := s.count
|
||||
until
|
||||
i > n or not Result
|
||||
loop
|
||||
Result := s[i].is_space
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
indented_text (pre: READABLE_STRING_8; t: READABLE_STRING_8): READABLE_STRING_8
|
||||
-- Indendted text.
|
||||
local
|
||||
s8: STRING_8
|
||||
do
|
||||
s8 := t.string
|
||||
s8.prepend (pre)
|
||||
s8.replace_substring_all ("%N", "%N" + pre)
|
||||
Result := s8
|
||||
end
|
||||
|
||||
|
||||
json_encode (a_string: STRING): STRING
|
||||
-- json encode `a_string'.
|
||||
local
|
||||
encode: SHARED_JSON_ENCODER
|
||||
do
|
||||
create encode
|
||||
Result := encode.json_encoder.encoded_string (a_string)
|
||||
debug
|
||||
print ("%NResult" + Result)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -7,6 +7,7 @@
|
||||
</option>
|
||||
<setting name="console_application" value="true"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="cms" location="..\..\..\..\cms-safe.ecf"/>
|
||||
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf"/>
|
||||
<library name="encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder-safe.ecf"/>
|
||||
<library name="error" location="$ISE_LIBRARY\contrib\library\utility\general\error\error-safe.ecf"/>
|
||||
@@ -23,7 +24,6 @@
|
||||
<exclude>/database/database_connection_odbc.e</exclude>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
<cluster name="interface" location="..\..\interface\" recursive="true"/>
|
||||
<cluster name="persistence_mysql" location=".\src\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
note
|
||||
description: "Summary description for {CMS_NODE_STORAGE_MYSQL}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_NODE_STORAGE_MYSQL
|
||||
|
||||
inherit
|
||||
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)
|
||||
create Result.make (db_handler, agent fetch_node)
|
||||
sql_post_execution
|
||||
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
|
||||
@@ -7,264 +7,106 @@ class
|
||||
CMS_STORAGE_MYSQL
|
||||
|
||||
inherit
|
||||
|
||||
CMS_STORAGE
|
||||
|
||||
CMS_STORAGE_STORE_SQL
|
||||
|
||||
CMS_USER_STORAGE_MYSQL
|
||||
|
||||
CMS_NODE_STORAGE_MYSQL
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
--feature {NONE} -- Initialization
|
||||
|
||||
make (a_connection: DATABASE_CONNECTION)
|
||||
--
|
||||
require
|
||||
is_connected: a_connection.is_connected
|
||||
do
|
||||
connection := a_connection
|
||||
log.write_information (generator+".make_with_database is database connected? "+ a_connection.is_connected.out )
|
||||
create node_provider.make (a_connection)
|
||||
create user_provider.make (a_connection)
|
||||
create error_handler.make
|
||||
end
|
||||
-- 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)
|
||||
|
||||
feature -- Access: user
|
||||
-- create error_handler.make
|
||||
---- error_handler.add_synchronization (db_handler.database_error_handler)
|
||||
-- end
|
||||
|
||||
has_user: BOOLEAN
|
||||
-- Has any user?
|
||||
do
|
||||
Result := user_provider.has_user
|
||||
end
|
||||
-- db_handler: DATABASE_HANDLER
|
||||
|
||||
all_users: LIST [CMS_USER]
|
||||
do
|
||||
to_implement (generator + ".all_users")
|
||||
create {ARRAYED_LIST[CMS_USER]} Result.make (0)
|
||||
end
|
||||
-- connection: DATABASE_CONNECTION
|
||||
-- -- Current database connection.
|
||||
|
||||
user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER
|
||||
do
|
||||
Result := user_provider.user (a_id)
|
||||
--feature -- Query
|
||||
|
||||
end
|
||||
-- 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
|
||||
|
||||
user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER
|
||||
do
|
||||
Result := user_provider.user_by_name (a_name)
|
||||
-- sql_begin_transaction
|
||||
-- do
|
||||
-- connection.begin_transaction
|
||||
-- end
|
||||
|
||||
end
|
||||
-- sql_commit_transaction
|
||||
-- do
|
||||
-- connection.commit
|
||||
-- end
|
||||
|
||||
user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER
|
||||
do
|
||||
Result := user_provider.user_by_email (a_email)
|
||||
-- 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
|
||||
|
||||
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
|
||||
|
||||
is_valid_credential (l_auth_login, l_auth_password: READABLE_STRING_32): BOOLEAN
|
||||
local
|
||||
l_security: SECURITY_PROVIDER
|
||||
do
|
||||
if attached user_provider.user_salt (l_auth_login) as l_hash then
|
||||
if attached user_provider.user_by_name (l_auth_login) as l_user then
|
||||
create l_security
|
||||
if
|
||||
attached l_user.password as l_password and then
|
||||
l_security.password_hash (l_auth_password, l_hash).is_case_insensitive_equal (l_password)
|
||||
then
|
||||
Result := True
|
||||
else
|
||||
log.write_information (generator + ".login_valid User: wrong username or password" )
|
||||
end
|
||||
else
|
||||
log.write_information (generator + ".login_valid User:" + l_auth_login + "does not exist" )
|
||||
end
|
||||
end
|
||||
-- sql_rows_count: INTEGER
|
||||
-- -- Number of rows for last sql execution.
|
||||
-- do
|
||||
-- Result := db_handler.count
|
||||
-- end
|
||||
|
||||
end
|
||||
-- sql_start
|
||||
-- -- Set the cursor on first element.
|
||||
-- do
|
||||
-- db_handler.start
|
||||
-- end
|
||||
|
||||
feature -- User Nodes
|
||||
-- sql_after: BOOLEAN
|
||||
-- -- Are there no more items to iterate over?
|
||||
-- do
|
||||
-- Result := db_handler.after
|
||||
-- end
|
||||
|
||||
user_collaborator_nodes (a_id: like {CMS_USER}.id): LIST[CMS_NODE]
|
||||
-- Possible list of nodes where the user identified by `a_id', is a collaborator.
|
||||
do
|
||||
to_implement (generator + ".user_collaborator_nodes")
|
||||
create {ARRAYED_LIST[CMS_NODE]} Result.make (0)
|
||||
end
|
||||
-- sql_forth
|
||||
-- -- Fetch next row from last sql execution, if any.
|
||||
-- do
|
||||
-- db_handler.forth
|
||||
-- end
|
||||
|
||||
user_author_nodes (a_id: like {CMS_USER}.id): LIST[CMS_NODE]
|
||||
-- Possible list of nodes where the user identified by `a_id', is the author.
|
||||
do
|
||||
to_implement (generator + ".user_author_nodes")
|
||||
create {ARRAYED_LIST[CMS_NODE]} Result.make (0)
|
||||
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
|
||||
|
||||
feature -- Access: roles and permissions
|
||||
|
||||
user_role_by_id (a_id: like {CMS_USER_ROLE}.id): detachable CMS_USER_ROLE
|
||||
do
|
||||
to_implement (generator + ".user_role_by_id")
|
||||
end
|
||||
|
||||
user_roles: LIST [CMS_USER_ROLE]
|
||||
do
|
||||
to_implement (generator + ".user_roles")
|
||||
create {ARRAYED_LIST[CMS_USER_ROLE]} Result.make (0)
|
||||
end
|
||||
|
||||
feature -- Change: roles and permissions
|
||||
|
||||
save_user_role (a_user_role: CMS_USER_ROLE)
|
||||
do
|
||||
to_implement (generator + ".save_user_role")
|
||||
end
|
||||
|
||||
feature -- Change: user
|
||||
|
||||
save_user (a_user: CMS_USER)
|
||||
-- Add a new user `a_user'.
|
||||
do
|
||||
|
||||
if
|
||||
attached a_user.password as l_password and then
|
||||
attached a_user.email as l_email
|
||||
then
|
||||
connection.begin_transaction
|
||||
user_provider.new_user (a_user.name, l_password, l_email)
|
||||
connection.commit
|
||||
else
|
||||
debug ("refactor_fixme")
|
||||
fixme ("maybe we should not always carry password, in this case, to implement the else part..")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access: node
|
||||
|
||||
nodes: LIST[CMS_NODE]
|
||||
-- List of nodes.
|
||||
do
|
||||
create {ARRAYED_LIST[CMS_NODE]} Result.make (0)
|
||||
across node_provider.nodes as c loop
|
||||
Result.force (c.item)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
|
||||
-- List of the `a_count' most recent nodes, starting from `a_lower'.
|
||||
do
|
||||
create {ARRAYED_LIST[CMS_NODE]} Result.make (0)
|
||||
across node_provider.recent_nodes (a_lower,a_count) as c loop
|
||||
Result.force (c.item)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
node (a_id: INTEGER_64): detachable CMS_NODE
|
||||
-- <Precursor>
|
||||
do
|
||||
Result := node_provider.node (a_id)
|
||||
|
||||
end
|
||||
|
||||
node_author (a_id: like {CMS_NODE}.id): detachable CMS_USER
|
||||
-- <Precursor>
|
||||
do
|
||||
Result := node_provider.node_author (a_id)
|
||||
|
||||
end
|
||||
|
||||
node_collaborators (a_id: like {CMS_NODE}.id): LIST [CMS_USER]
|
||||
-- Possible list of node's collaborator.
|
||||
do
|
||||
create {ARRAYED_LIST[CMS_USER]} Result.make (0)
|
||||
across node_provider.node_collaborators (a_id) as c loop Result.force (c.item) end
|
||||
end
|
||||
|
||||
feature -- Node
|
||||
|
||||
save_node (a_node: CMS_NODE)
|
||||
-- <Precursor>
|
||||
do
|
||||
node_provider.new_node (a_node)
|
||||
|
||||
end
|
||||
|
||||
delete_node (a_id: INTEGER_64)
|
||||
do
|
||||
node_provider.delete_from_user_nodes(a_id)
|
||||
node_provider.delete_node (a_id)
|
||||
|
||||
end
|
||||
|
||||
update_node (a_id: like {CMS_USER}.id; a_node: CMS_NODE)
|
||||
-- <Precursor>
|
||||
do
|
||||
node_provider.update_node (a_id, a_node)
|
||||
|
||||
end
|
||||
|
||||
update_node_title (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_title: READABLE_STRING_32)
|
||||
-- <Precursor>
|
||||
do
|
||||
node_provider.update_node_title (a_node_id, a_title)
|
||||
internal_node_update (a_id, a_node_id)
|
||||
|
||||
end
|
||||
|
||||
update_node_summary (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_summary: READABLE_STRING_32)
|
||||
-- <Precursor>
|
||||
do
|
||||
node_provider.update_node_summary (a_node_id, a_summary)
|
||||
internal_node_update (a_id, a_node_id)
|
||||
|
||||
end
|
||||
|
||||
update_node_content (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_content: READABLE_STRING_32)
|
||||
-- <Precursor>
|
||||
do
|
||||
node_provider.update_node_content (a_node_id, a_content)
|
||||
internal_node_update (a_id, a_node_id)
|
||||
|
||||
end
|
||||
|
||||
feature {NONE} -- NODE Implemenation
|
||||
|
||||
internal_node_update (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id)
|
||||
-- Update node editor or add collaborator.
|
||||
do
|
||||
if not node_provider.is_collaborator (a_id, a_node_id) then
|
||||
node_provider.add_collaborator (a_id, a_node_id)
|
||||
else
|
||||
node_provider.update_node_last_editor (a_id, a_node_id)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- User
|
||||
|
||||
new_user (a_user: CMS_USER)
|
||||
-- Add a new user `a_user'.
|
||||
do
|
||||
if
|
||||
attached a_user.password as l_password and then
|
||||
attached a_user.email as l_email
|
||||
then
|
||||
user_provider.new_user (a_user.name, l_password, l_email)
|
||||
else
|
||||
-- set error
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Post process
|
||||
|
||||
|
||||
node_provider: NODE_DATA_PROVIDER
|
||||
-- Node Data provider.
|
||||
|
||||
user_provider: USER_DATA_PROVIDER
|
||||
-- User Data provider.
|
||||
|
||||
connection: DATABASE_CONNECTION
|
||||
-- Current database connection.
|
||||
end
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
note
|
||||
description: "[
|
||||
Objects that ...
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_STORAGE_MYSQL_BUILDER
|
||||
|
||||
inherit
|
||||
CMS_STORAGE_BUILDER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
end
|
||||
|
||||
feature -- Factory
|
||||
|
||||
storage (a_setup: CMS_SETUP): detachable CMS_STORAGE_MYSQL
|
||||
local
|
||||
conn: DATABASE_CONNECTION
|
||||
do
|
||||
if attached (create {APPLICATION_JSON_CONFIGURATION_HELPER}).new_database_configuration (a_setup.layout.application_config_path) as l_database_config then
|
||||
create {DATABASE_CONNECTION_MYSQL} conn.login_with_connection_string (l_database_config.connection_string)
|
||||
if conn.is_connected then
|
||||
create Result.make (conn)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
note
|
||||
description: "Summary description for {CMS_USER_STORAGE_MYSQL}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_USER_STORAGE_MYSQL
|
||||
|
||||
inherit
|
||||
CMS_USER_STORAGE_SQL
|
||||
|
||||
|
||||
end
|
||||
@@ -1,511 +0,0 @@
|
||||
note
|
||||
description: "Database access for node uses cases."
|
||||
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
|
||||
revision: "$Revision: 95678 $"
|
||||
|
||||
class
|
||||
NODE_DATA_PROVIDER
|
||||
|
||||
inherit
|
||||
|
||||
PARAMETER_NAME_HELPER
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
SHARED_LOGGER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (a_connection: DATABASE_CONNECTION)
|
||||
-- Create a data provider.
|
||||
do
|
||||
create {DATABASE_HANDLER_IMPL} db_handler.make (a_connection)
|
||||
create error_handler.make
|
||||
post_execution
|
||||
end
|
||||
|
||||
db_handler: DATABASE_HANDLER
|
||||
-- Db handler.
|
||||
|
||||
feature -- Status Report
|
||||
|
||||
is_successful: BOOLEAN
|
||||
-- Is the last execution sucessful?
|
||||
do
|
||||
Result := not error_handler.has_error
|
||||
end
|
||||
|
||||
feature -- Error Handler
|
||||
|
||||
error_handler: ERROR_HANDLER
|
||||
|
||||
feature -- Access
|
||||
|
||||
nodes: DATABASE_ITERATION_CURSOR [CMS_NODE]
|
||||
-- List of nodes.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".nodes")
|
||||
create l_parameters.make (0)
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (Select_nodes, l_parameters))
|
||||
db_handler.execute_query
|
||||
create Result.make (db_handler, agent fetch_node)
|
||||
post_execution
|
||||
end
|
||||
|
||||
recent_nodes (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
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".recent_nodes")
|
||||
create l_parameters.make (2)
|
||||
l_parameters.put (a_rows, "rows")
|
||||
create l_query.make_from_string (select_recent_nodes)
|
||||
l_query.replace_substring_all ("$offset", a_lower.out)
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (l_query, l_parameters))
|
||||
db_handler.execute_query
|
||||
create Result.make (db_handler, agent fetch_node)
|
||||
post_execution
|
||||
end
|
||||
|
||||
node (a_id: INTEGER_64): detachable CMS_NODE
|
||||
-- Node for the given id `a_id', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".node")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id,"id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_node_by_id, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := fetch_node
|
||||
end
|
||||
post_execution
|
||||
end
|
||||
|
||||
count: INTEGER
|
||||
-- Number of items nodes.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".count")
|
||||
create l_parameters.make (0)
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_count, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := db_handler.read_integer_32 (1)
|
||||
end
|
||||
post_execution
|
||||
end
|
||||
|
||||
|
||||
last_inserted_node_id: INTEGER
|
||||
-- Last insert node id.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".last_inserted_node_id")
|
||||
create l_parameters.make (0)
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (Sql_last_insert_node_id, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := db_handler.read_integer_32 (1)
|
||||
end
|
||||
post_execution
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
new_node (a_node: CMS_NODE)
|
||||
-- Create a new node.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".new_node")
|
||||
create l_parameters.make (7)
|
||||
l_parameters.put (a_node.title, "title")
|
||||
l_parameters.put (a_node.summary, "summary")
|
||||
l_parameters.put (a_node.content, "content")
|
||||
l_parameters.put (a_node.publication_date, "publication_date")
|
||||
l_parameters.put (a_node.creation_date, "creation_date")
|
||||
l_parameters.put (a_node.modification_date, "modification_date")
|
||||
if
|
||||
attached a_node.author as l_author and then
|
||||
l_author.id > 0
|
||||
then
|
||||
l_parameters.put (l_author.id, "author_id")
|
||||
end
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_insert_node, l_parameters))
|
||||
db_handler.execute_change
|
||||
|
||||
a_node.set_id (last_inserted_node_id)
|
||||
post_execution
|
||||
end
|
||||
|
||||
update_node_title (a_id: INTEGER_64; a_title: READABLE_STRING_32)
|
||||
-- Update node title for the corresponding the report with id `a_id'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".update_node_title")
|
||||
create l_parameters.make (3)
|
||||
l_parameters.put (a_title, "title")
|
||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
|
||||
l_parameters.put (a_id, "id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_update_node_title, l_parameters))
|
||||
db_handler.execute_change
|
||||
post_execution
|
||||
end
|
||||
|
||||
update_node_summary (a_id: INTEGER_64; a_summary: READABLE_STRING_32)
|
||||
-- Update node summary for the corresponding the report with id `a_id'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".update_node_summary")
|
||||
create l_parameters.make (3)
|
||||
l_parameters.put (a_summary, "summary")
|
||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
|
||||
l_parameters.put (a_id, "id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_update_node_summary, l_parameters))
|
||||
db_handler.execute_change
|
||||
post_execution
|
||||
end
|
||||
|
||||
update_node_content (a_id: INTEGER_64; a_content: READABLE_STRING_32)
|
||||
-- Update node content for the corresponding the report with id `a_id'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".update_node_content")
|
||||
create l_parameters.make (3)
|
||||
l_parameters.put (a_content, "content")
|
||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
|
||||
l_parameters.put (a_id, "id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_update_node_content, l_parameters))
|
||||
db_handler.execute_change
|
||||
post_execution
|
||||
end
|
||||
|
||||
update_node (a_id: like {CMS_USER}.id; a_node: CMS_NODE)
|
||||
-- Update node.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".update_node")
|
||||
create l_parameters.make (7)
|
||||
l_parameters.put (a_node.title, "title")
|
||||
l_parameters.put (a_node.summary, "summary")
|
||||
l_parameters.put (a_node.content, "content")
|
||||
l_parameters.put (a_node.publication_date, "publication_date")
|
||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
|
||||
l_parameters.put (a_node.id, "id")
|
||||
l_parameters.put (a_id, "editor")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_update_node, l_parameters))
|
||||
db_handler.execute_change
|
||||
post_execution
|
||||
end
|
||||
|
||||
delete_node (a_id: INTEGER_64;)
|
||||
-- Delete node with id `a_id'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".delete_node")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id, "id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_delete_node, l_parameters))
|
||||
db_handler.execute_change
|
||||
post_execution
|
||||
end
|
||||
|
||||
delete_from_user_nodes (a_id: INTEGER_64)
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".delete_from_user_nodes")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id, "id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_delete_from_user_node, l_parameters))
|
||||
db_handler.execute_change
|
||||
post_execution
|
||||
end
|
||||
|
||||
feature -- Basic Operations: User_Nodes
|
||||
|
||||
add_author (a_user_id: INTEGER_64; a_node_id: INTEGER_64)
|
||||
-- Add author `a_user_id' to node `a_node_id'
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".add_author")
|
||||
create l_parameters.make (2)
|
||||
l_parameters.put (a_user_id,"user_id")
|
||||
l_parameters.put (a_node_id,"id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (Sql_update_node_author, l_parameters))
|
||||
db_handler.execute_change
|
||||
post_execution
|
||||
end
|
||||
|
||||
add_collaborator (a_user_id: INTEGER_64; a_node_id: INTEGER_64)
|
||||
-- Add collaborator `a_user_id' to node `a_node_id'
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".add_collaborator")
|
||||
create l_parameters.make (2)
|
||||
l_parameters.put (a_user_id,"users_id")
|
||||
l_parameters.put (a_node_id,"nodes_id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (Sql_insert_users_nodes, l_parameters))
|
||||
db_handler.execute_change
|
||||
post_execution
|
||||
end
|
||||
|
||||
update_node_last_editor (a_user_id: INTEGER_64; a_node_id: INTEGER_64)
|
||||
-- Update node last editor.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".add_collaborator")
|
||||
create l_parameters.make (2)
|
||||
l_parameters.put (a_user_id,"users_id")
|
||||
l_parameters.put (a_node_id,"nodes_id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (Slq_update_editor, l_parameters))
|
||||
db_handler.execute_change
|
||||
post_execution
|
||||
end
|
||||
|
||||
|
||||
author_nodes (a_id:INTEGER_64): DATABASE_ITERATION_CURSOR [CMS_NODE]
|
||||
-- List of Nodes for the given user `a_id'. (the user is the author of the node)
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".author_nodes")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id, "user_id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (Select_user_author, l_parameters))
|
||||
db_handler.execute_query
|
||||
create Result.make (db_handler, agent fetch_node)
|
||||
post_execution
|
||||
end
|
||||
|
||||
collaborator_nodes (a_id:INTEGER_64): DATABASE_ITERATION_CURSOR [CMS_NODE]
|
||||
-- List of Nodes for the given user `a_id' as collaborator.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".collaborator_nodes")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id, "user_id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (Select_user_collaborator, l_parameters))
|
||||
db_handler.execute_query
|
||||
create Result.make (db_handler, agent fetch_node)
|
||||
post_execution
|
||||
end
|
||||
|
||||
|
||||
node_author (a_id: INTEGER_64): detachable CMS_USER
|
||||
-- Node's author for the given node id.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".node_author")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id, "node_id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_node_author, l_parameters))
|
||||
db_handler.execute_query
|
||||
if not db_handler.after then
|
||||
Result := fetch_user
|
||||
end
|
||||
post_execution
|
||||
end
|
||||
|
||||
node_collaborators (a_id: INTEGER_64): DATABASE_ITERATION_CURSOR [CMS_USER]
|
||||
-- List of possible node's collaborator.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".node_collaborators")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id, "node_id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_node_collaborators, l_parameters))
|
||||
db_handler.execute_query
|
||||
create Result.make (db_handler, agent fetch_user)
|
||||
post_execution
|
||||
end
|
||||
|
||||
is_collaborator (a_user_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id): BOOLEAN
|
||||
-- Is the user `a_user_id' a collaborator of node `a_node_id'
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".node_collaborators")
|
||||
create l_parameters.make (2)
|
||||
l_parameters.put (a_user_id, "user_id")
|
||||
l_parameters.put (a_node_id, "node_id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_exist_user_node, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := db_handler.read_integer_32 (1) = 1
|
||||
end
|
||||
post_execution
|
||||
end
|
||||
|
||||
feature -- Connection
|
||||
|
||||
connect
|
||||
-- Connect to the database.
|
||||
do
|
||||
if not db_handler.is_connected then
|
||||
db_handler.connect
|
||||
end
|
||||
end
|
||||
|
||||
disconnect
|
||||
-- Disconnect to the database.
|
||||
do
|
||||
if db_handler.is_connected then
|
||||
db_handler.disconnect
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Queries
|
||||
|
||||
Select_count: STRING = "select count(*) from Nodes;"
|
||||
|
||||
Select_nodes: STRING = "select * from 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_recent_nodes: STRING = "select * from Nodes order by id desc, publication_date desc Limit $offset , :rows "
|
||||
|
||||
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 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 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_Delete_node: STRING = "delete from nodes where id=:id;"
|
||||
|
||||
Sql_update_node_author: STRING = "update nodes SET author_id=:user_id where id=:id;"
|
||||
|
||||
Sql_last_insert_node_id: STRING = "SELECT MAX(id) from nodes;"
|
||||
|
||||
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_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_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 --
|
||||
|
||||
|
||||
feature -- New Object
|
||||
|
||||
fetch_node: CMS_NODE
|
||||
do
|
||||
create Result.make ("", "", "")
|
||||
if attached db_handler.read_integer_32 (1) as l_id then
|
||||
Result.set_id (l_id)
|
||||
end
|
||||
if attached db_handler.read_date_time (2) as l_pd then
|
||||
Result.set_publication_date (l_pd)
|
||||
end
|
||||
if attached db_handler.read_date_time (3) as l_cd then
|
||||
Result.set_creation_date (l_cd)
|
||||
end
|
||||
if attached db_handler.read_date_time (4) as l_md then
|
||||
Result.set_modification_date (l_md)
|
||||
end
|
||||
if attached db_handler.read_string (5) as l_t then
|
||||
Result.set_title (l_t)
|
||||
end
|
||||
if attached db_handler.read_string (6) as l_s then
|
||||
Result.set_summary (l_s)
|
||||
end
|
||||
if attached db_handler.read_string (7) as l_c then
|
||||
Result.set_content (l_c)
|
||||
end
|
||||
end
|
||||
|
||||
fetch_user: CMS_USER
|
||||
do
|
||||
create Result.make ("")
|
||||
if attached db_handler.read_integer_32 (1) as l_id then
|
||||
Result.set_id (l_id)
|
||||
end
|
||||
if attached db_handler.read_string (2) as l_u then
|
||||
Result.set_name (l_u)
|
||||
end
|
||||
if attached db_handler.read_string (3) as l_p then
|
||||
Result.set_password (l_p)
|
||||
end
|
||||
if attached db_handler.read_string (5) as l_e then
|
||||
Result.set_email (l_e)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
post_execution
|
||||
-- Post database execution.
|
||||
do
|
||||
error_handler.add_synchronization (db_handler.database_error_handler)
|
||||
if error_handler.has_error then
|
||||
log.write_critical (generator + ".post_execution " + error_handler.as_string_representation)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,216 +0,0 @@
|
||||
note
|
||||
description: "Summary description for {ROLE_DATA_PROVIDER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
ROLE_DATA_PROVIDER
|
||||
|
||||
inherit
|
||||
|
||||
PARAMETER_NAME_HELPER
|
||||
|
||||
SHARED_ERROR
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (a_connection: DATABASE_CONNECTION)
|
||||
-- Create a data provider.
|
||||
do
|
||||
create {DATABASE_HANDLER_IMPL} db_handler.make (a_connection)
|
||||
post_execution
|
||||
end
|
||||
|
||||
db_handler: DATABASE_HANDLER
|
||||
-- Db handler.
|
||||
|
||||
feature -- Status Report
|
||||
|
||||
is_successful: BOOLEAN
|
||||
-- Is the last execution sucessful?
|
||||
do
|
||||
-- Result := db_handler.successful
|
||||
end
|
||||
|
||||
has_roles: BOOLEAN
|
||||
-- Has any role?
|
||||
do
|
||||
Result := count > 0
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
roles: DATABASE_ITERATION_CURSOR [CMS_USER_ROLE]
|
||||
-- List of roles.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".roles")
|
||||
create l_parameters.make (0)
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (Select_roles, l_parameters))
|
||||
db_handler.execute_query
|
||||
create Result.make (db_handler, agent fetch_role)
|
||||
post_execution
|
||||
end
|
||||
|
||||
feature -- Basic Operations
|
||||
|
||||
new_role (a_role: READABLE_STRING_32)
|
||||
-- Create a new node.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
log.write_information (generator + ".new_role")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_role,"name")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_insert_role, l_parameters))
|
||||
db_handler.execute_change
|
||||
post_execution
|
||||
end
|
||||
|
||||
role (a_id: INTEGER_64): detachable CMS_USER_ROLE
|
||||
-- Role for the given id `a_id', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".role")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id,"id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_role_by_id, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := fetch_role
|
||||
end
|
||||
post_execution
|
||||
end
|
||||
|
||||
role_by_name (a_name: READABLE_STRING_32): detachable CMS_USER_ROLE
|
||||
-- Role for the given name `a_name', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".role_by_name")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_name,"name")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_role_by_name, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := fetch_role
|
||||
end
|
||||
post_execution
|
||||
end
|
||||
|
||||
count: INTEGER
|
||||
-- Number of items users.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".count")
|
||||
create l_parameters.make (0)
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_count, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := db_handler.read_integer_32 (1)
|
||||
end
|
||||
post_execution
|
||||
end
|
||||
|
||||
save_role_permission (a_role_id: INTEGER; a_permission: READABLE_STRING_32)
|
||||
-- Add permission `a_permission' to the role id `a_role_id'.
|
||||
require
|
||||
valid_id: a_role_id > 0
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
log.write_information (generator + ".save_role_permission")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_permission,"name")
|
||||
l_parameters.put (a_role_id,"id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (SQL_Insert_permissions, l_parameters))
|
||||
db_handler.execute_change
|
||||
post_execution
|
||||
end
|
||||
|
||||
permission_by_role (a_role_id: INTEGER_64): DATABASE_ITERATION_CURSOR [READABLE_STRING_32]
|
||||
-- List of permission by role `a_role_id'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".permission_by_role")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_role_id, "id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (Select_permissions, l_parameters))
|
||||
db_handler.execute_query
|
||||
create Result.make (db_handler, agent fetch_permission)
|
||||
post_execution
|
||||
end
|
||||
|
||||
feature -- New Object
|
||||
|
||||
fetch_role: CMS_USER_ROLE
|
||||
do
|
||||
create Result.make_with_id (0,"")
|
||||
if attached db_handler.read_integer_32 (1) as l_id then
|
||||
Result.set_id (l_id)
|
||||
end
|
||||
if attached db_handler.read_string (2) as l_u then
|
||||
Result.set_name (l_u)
|
||||
end
|
||||
end
|
||||
|
||||
fetch_permission: STRING_32
|
||||
do
|
||||
create Result.make_empty
|
||||
if attached db_handler.read_string (1) as l_u then
|
||||
Result := l_u
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature {NONE} -- Sql Queries: Roles
|
||||
|
||||
Select_count: STRING = "select count(*) from Roles;"
|
||||
-- Number of roles.
|
||||
|
||||
Select_roles: STRING = "select * from Roles;"
|
||||
-- roles.
|
||||
|
||||
Select_role_by_id: STRING = "select * from Roles where id =:id;"
|
||||
-- Retrieve role by id if exists.
|
||||
|
||||
Select_role_by_name: STRING = "select * from Roles where role =:name;"
|
||||
-- Retrieve user by name if exists.
|
||||
|
||||
SQL_Insert_role: STRING = "insert into roles (role) values (:name);"
|
||||
-- SQL Insert to add a new node.
|
||||
|
||||
|
||||
feature {NONE} -- Sql Queries: Permissions
|
||||
|
||||
Select_permissions_count: STRING = "select count(*) from permissions where roles_id=:id;"
|
||||
-- Number of permissions for a given role.
|
||||
|
||||
Select_permissions: STRING = "select * from permissions where roles_id=:id;"
|
||||
-- List of permissions for a given role.
|
||||
|
||||
Select_permissions_by_id: STRING = "select name from permissions where roles_id=:id and id=:permissionid;"
|
||||
-- Permission for a given role and permission id
|
||||
|
||||
SQL_Insert_permissions: STRING = "insert into permissions (name, roles_id) values (:name, :id);"
|
||||
-- SQL Insert to add a new node.
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
post_execution
|
||||
-- Post database execution.
|
||||
do
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,337 +0,0 @@
|
||||
note
|
||||
description: "Summary description for {USER_DATA_PROVIDER}."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
USER_DATA_PROVIDER
|
||||
|
||||
inherit
|
||||
|
||||
PARAMETER_NAME_HELPER
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
SHARED_LOGGER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (a_connection: DATABASE_CONNECTION)
|
||||
-- Create a data provider.
|
||||
do
|
||||
create {DATABASE_HANDLER_IMPL} db_handler.make (a_connection)
|
||||
create error_handler.make
|
||||
post_execution
|
||||
end
|
||||
|
||||
db_handler: DATABASE_HANDLER
|
||||
-- Db handler.
|
||||
|
||||
feature -- Error Handler
|
||||
|
||||
error_handler: ERROR_HANDLER
|
||||
|
||||
|
||||
feature -- Status Report
|
||||
|
||||
is_successful: BOOLEAN
|
||||
-- Is the last execution sucessful?
|
||||
do
|
||||
Result := not error_handler.has_error
|
||||
end
|
||||
|
||||
has_user: BOOLEAN
|
||||
-- Has any user?
|
||||
do
|
||||
Result := count > 0
|
||||
end
|
||||
|
||||
feature -- Basic Operations
|
||||
|
||||
new_user (a_user_name: READABLE_STRING_32; a_password: READABLE_STRING_32; a_email: READABLE_STRING_32)
|
||||
-- Create a new node.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
l_password_salt, l_password_hash: STRING
|
||||
l_security: SECURITY_PROVIDER
|
||||
do
|
||||
error_handler.reset
|
||||
create l_security
|
||||
l_password_salt := l_security.salt
|
||||
l_password_hash := l_security.password_hash (a_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 (a_email,"email")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_insert_user, l_parameters))
|
||||
db_handler.execute_change
|
||||
post_execution
|
||||
end
|
||||
|
||||
user (a_id: INTEGER_64): detachable CMS_USER
|
||||
-- User for the given id `a_id', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".user")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id,"id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_user_by_id, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := fetch_user
|
||||
end
|
||||
post_execution
|
||||
end
|
||||
|
||||
user_by_name (a_name: READABLE_STRING_32): detachable CMS_USER
|
||||
-- User for the given name `a_name', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".user_by_name")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_name,"name")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_user_by_name, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := fetch_user
|
||||
end
|
||||
post_execution
|
||||
end
|
||||
|
||||
|
||||
user_by_email (a_email: detachable READABLE_STRING_32): detachable CMS_USER
|
||||
-- User for the given email `a_email', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".user_by_email")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_email,"email")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_user_by_email, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := fetch_user
|
||||
end
|
||||
post_execution
|
||||
end
|
||||
|
||||
user_salt (a_username: READABLE_STRING_32): detachable READABLE_STRING_32
|
||||
-- User salt for the given user `a_username', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".user_salt")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_username,"name")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_salt_by_username, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
if attached db_handler.read_string (1) as l_salt then
|
||||
Result := l_salt.as_string_32
|
||||
end
|
||||
end
|
||||
post_execution
|
||||
end
|
||||
|
||||
count: INTEGER
|
||||
-- Number of items users.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".count")
|
||||
create l_parameters.make (0)
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_count, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := db_handler.read_integer_32 (1)
|
||||
end
|
||||
post_execution
|
||||
end
|
||||
|
||||
feature -- Basic operations: User Roles
|
||||
|
||||
add_role (a_user_id: INTEGER; a_role_id: INTEGER)
|
||||
-- Add Role `a_role_id' to user `a_user_id'
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".add_role")
|
||||
create l_parameters.make (2)
|
||||
l_parameters.put (a_user_id,"users_id")
|
||||
l_parameters.put (a_role_id,"roles_id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (slq_insert_users_roles, l_parameters))
|
||||
db_handler.execute_change
|
||||
post_execution
|
||||
end
|
||||
|
||||
user_roles (a_id:INTEGER_64): DATABASE_ITERATION_CURSOR [INTEGER]
|
||||
-- List of Roles id for the given user `a_id'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".user_roles")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id, "user_id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (Select_user_roles, l_parameters))
|
||||
db_handler.execute_query
|
||||
create Result.make (db_handler, agent fetch_role_id)
|
||||
post_execution
|
||||
end
|
||||
|
||||
|
||||
feature -- Basic operations: User Profiles
|
||||
|
||||
save_profile_item (a_user_id: INTEGER_64; a_key: READABLE_STRING_32; a_value: READABLE_STRING_32)
|
||||
-- Save a profile item with (a_key and a_value) to the given user `user_id'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".save_profile_item")
|
||||
create l_parameters.make (3)
|
||||
l_parameters.put (a_key, "key")
|
||||
l_parameters.put (a_value, "value")
|
||||
l_parameters.put (a_user_id, "users_id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (Select_instert_profile_item, l_parameters))
|
||||
db_handler.execute_change
|
||||
post_execution
|
||||
end
|
||||
|
||||
save_profile (a_user_id: INTEGER_64; a_user_profile: CMS_USER_PROFILE)
|
||||
-- Save a profile item with (a_key and a_value) to the given user `user_id'.
|
||||
local
|
||||
l_cursor: TABLE_ITERATION_CURSOR [READABLE_STRING_8, READABLE_STRING_GENERAL]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".save_profile")
|
||||
from
|
||||
l_cursor := a_user_profile.new_cursor
|
||||
until
|
||||
l_cursor.after
|
||||
loop
|
||||
save_profile_item (a_user_id, l_cursor.key.as_string_32, l_cursor.item)
|
||||
l_cursor.forth
|
||||
end
|
||||
|
||||
post_execution
|
||||
end
|
||||
|
||||
user_profile (a_user_id: INTEGER_64): CMS_USER_PROFILE
|
||||
-- User profile for a user with id `a_user_id'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".user_profile")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_user_id, "users_id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (Select_user_profile, l_parameters))
|
||||
db_handler.execute_query
|
||||
create Result.make
|
||||
if not db_handler.after then
|
||||
from
|
||||
db_handler.start
|
||||
until
|
||||
db_handler.after
|
||||
loop
|
||||
if
|
||||
attached db_handler.read_string (1) as l_key and then
|
||||
attached db_handler.read_string (2) as l_value
|
||||
then
|
||||
Result.force (l_value, l_key)
|
||||
end
|
||||
db_handler.forth
|
||||
end
|
||||
end
|
||||
post_execution
|
||||
end
|
||||
|
||||
|
||||
feature -- New Object
|
||||
|
||||
fetch_user: CMS_USER
|
||||
do
|
||||
create Result.make ("")
|
||||
if attached db_handler.read_integer_32 (1) as l_id then
|
||||
Result.set_id (l_id)
|
||||
end
|
||||
if attached db_handler.read_string (2) as l_u then
|
||||
Result.set_name (l_u)
|
||||
end
|
||||
if attached db_handler.read_string (3) as l_p then
|
||||
Result.set_password (l_p)
|
||||
end
|
||||
if attached db_handler.read_string (5) as l_e then
|
||||
Result.set_email (l_e)
|
||||
end
|
||||
end
|
||||
|
||||
fetch_role_id: INTEGER
|
||||
do
|
||||
if attached db_handler.read_integer_32 (1) as l_id then
|
||||
Result := l_id
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Sql Queries: USER
|
||||
|
||||
Select_count: STRING = "select count(*) from Users;"
|
||||
-- Number of users.
|
||||
|
||||
Select_user_by_id: STRING = "select * from Users where id =:id;"
|
||||
-- Retrieve user by id if exists.
|
||||
|
||||
Select_user_by_name: STRING = "select * from Users where username =:name;"
|
||||
-- Retrieve user by name if exists.
|
||||
|
||||
Select_user_by_email: STRING = "select * from Users where email =:email;"
|
||||
-- Retrieve user by email if exists.
|
||||
|
||||
Select_salt_by_username: STRING = "select salt from Users where username =:name;"
|
||||
-- Retrieve salt by username if exists.
|
||||
|
||||
SQL_Insert_user: STRING = "insert into users (username, password, salt, email) values (:username, :password, :salt, :email);"
|
||||
-- SQL Insert to add a new node.
|
||||
|
||||
|
||||
feature {NONE} -- Sql Queries: USER_ROLES
|
||||
|
||||
Slq_insert_users_roles: STRING = "insert into users_roles (users_id, roles_id) values (:users_id, :roles_id);"
|
||||
|
||||
Select_user_roles: STRING = "Select roles_id from users_roles where users_id = :user_id"
|
||||
|
||||
feature {NONE} -- SQL Queries: Profile
|
||||
|
||||
Select_instert_profile_item: STRING = "insert into profiles (profiles.key, value, users_id) values (:key, :value, :users_id);"
|
||||
|
||||
Select_user_profile: STRING = "Select profiles.key, value from profiles where users_id = :users_id;"
|
||||
|
||||
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
post_execution
|
||||
-- Post database execution.
|
||||
do
|
||||
error_handler.add_synchronization (db_handler.database_error_handler)
|
||||
if error_handler.has_error then
|
||||
log.write_critical (generator + ".post_execution " + error_handler.as_string_representation)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -7,6 +7,7 @@
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="cms" location="..\..\..\..\..\cms-safe.ecf"/>
|
||||
<library name="model" location="..\..\..\..\model\cms_model-safe.ecf"/>
|
||||
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf"/>
|
||||
<library name="persitence_mysql" location="..\persistence_mysql-safe.ecf" readonly="false"/>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</option>
|
||||
<setting name="console_application" value="true"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="cms" location="..\..\..\..\cms-safe.ecf"/>
|
||||
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf"/>
|
||||
<library name="encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder-safe.ecf"/>
|
||||
<library name="error" location="$ISE_LIBRARY\contrib\library\utility\general\error\error-safe.ecf"/>
|
||||
@@ -19,7 +20,6 @@
|
||||
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<cluster name="common" location="..\common\" recursive="true"/>
|
||||
<cluster name="interface" location="..\..\interface\" recursive="true"/>
|
||||
<cluster name="persistence_sqlite" location=".\src\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
@@ -0,0 +1,75 @@
|
||||
note
|
||||
description: "Summary description for {CMS_NODE_STORAGE_SQLITE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_NODE_STORAGE_SQLITE
|
||||
|
||||
inherit
|
||||
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
|
||||
@@ -7,243 +7,106 @@ class
|
||||
CMS_STORAGE_SQLITE
|
||||
|
||||
inherit
|
||||
|
||||
CMS_STORAGE
|
||||
|
||||
CMS_STORAGE_STORE_SQL
|
||||
|
||||
CMS_USER_STORAGE_SQLITE
|
||||
|
||||
CMS_NODE_STORAGE_SQLITE
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
--feature {NONE} -- Initialization
|
||||
|
||||
make (a_connection: DATABASE_CONNECTION)
|
||||
--
|
||||
require
|
||||
is_connected: a_connection.is_connected
|
||||
do
|
||||
log.write_information (generator+".make_with_database is database connected? "+ a_connection.is_connected.out )
|
||||
create node_provider.make (a_connection)
|
||||
create user_provider.make (a_connection)
|
||||
create error_handler.make
|
||||
end
|
||||
-- make (a_connection: DATABASE_CONNECTION)
|
||||
-- --
|
||||
-- require
|
||||
-- is_connected: a_connection.is_connected
|
||||
-- do
|
||||
-- connection := a_connection
|
||||
-- log.write_information (generator + ".make_with_database is database connected? "+ a_connection.is_connected.out )
|
||||
|
||||
-- create {DATABASE_HANDLER_IMPL} db_handler.make (a_connection)
|
||||
|
||||
feature -- Access: user
|
||||
-- create error_handler.make
|
||||
---- error_handler.add_synchronization (db_handler.database_error_handler)
|
||||
-- end
|
||||
|
||||
has_user: BOOLEAN
|
||||
-- Has any user?
|
||||
do
|
||||
Result := user_provider.has_user
|
||||
-- db_handler: DATABASE_HANDLER
|
||||
|
||||
end
|
||||
-- connection: DATABASE_CONNECTION
|
||||
-- -- Current database connection.
|
||||
|
||||
--feature -- Access: user
|
||||
|
||||
all_users: LIST [CMS_USER]
|
||||
do
|
||||
to_implement("Not implemented!!!")
|
||||
create {ARRAYED_LIST[CMS_USER]} Result.make (0)
|
||||
end
|
||||
-- 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
|
||||
|
||||
user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER
|
||||
do
|
||||
Result := user_provider.user (a_id)
|
||||
-- sql_begin_transaction
|
||||
-- do
|
||||
-- connection.begin_transaction
|
||||
-- end
|
||||
|
||||
end
|
||||
-- sql_commit_transaction
|
||||
-- do
|
||||
-- connection.commit
|
||||
-- end
|
||||
|
||||
user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER
|
||||
do
|
||||
Result := user_provider.user_by_name (a_name)
|
||||
-- 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
|
||||
|
||||
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
|
||||
|
||||
user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER
|
||||
do
|
||||
Result := user_provider.user_by_email (a_email)
|
||||
-- sql_rows_count: INTEGER
|
||||
-- -- Number of rows for last sql execution.
|
||||
-- do
|
||||
-- Result := db_handler.count
|
||||
-- end
|
||||
|
||||
end
|
||||
-- sql_start
|
||||
-- -- Set the cursor on first element.
|
||||
-- do
|
||||
-- db_handler.start
|
||||
-- end
|
||||
|
||||
is_valid_credential (l_auth_login, l_auth_password: READABLE_STRING_32): BOOLEAN
|
||||
local
|
||||
l_security: SECURITY_PROVIDER
|
||||
do
|
||||
if attached user_provider.user_salt (l_auth_login) as l_hash then
|
||||
if attached user_provider.user_by_name (l_auth_login) as l_user then
|
||||
create l_security
|
||||
if
|
||||
attached l_user.password as l_password and then
|
||||
l_security.password_hash (l_auth_password, l_hash).is_case_insensitive_equal (l_password)
|
||||
then
|
||||
Result := True
|
||||
else
|
||||
log.write_information (generator + ".login_valid User: wrong username or password" )
|
||||
end
|
||||
else
|
||||
log.write_information (generator + ".login_valid User:" + l_auth_login + "does not exist" )
|
||||
end
|
||||
end
|
||||
-- sql_after: BOOLEAN
|
||||
-- -- Are there no more items to iterate over?
|
||||
-- do
|
||||
-- Result := db_handler.after
|
||||
-- end
|
||||
|
||||
end
|
||||
-- sql_forth
|
||||
-- -- Fetch next row from last sql execution, if any.
|
||||
-- do
|
||||
-- db_handler.forth
|
||||
-- end
|
||||
|
||||
feature -- Change: user
|
||||
|
||||
save_user (a_user: CMS_USER)
|
||||
-- Add a new user `a_user'.
|
||||
do
|
||||
if
|
||||
attached a_user.password as l_password and then
|
||||
attached a_user.email as l_email
|
||||
then
|
||||
user_provider.new_user (a_user.name, l_password, l_email)
|
||||
else
|
||||
-- set error
|
||||
end
|
||||
end
|
||||
|
||||
feature -- User Nodes
|
||||
|
||||
user_collaborator_nodes (a_id: like {CMS_USER}.id): LIST[CMS_NODE]
|
||||
-- Possible list of nodes where the user identified by `a_id', is a collaborator.
|
||||
do
|
||||
create {ARRAYED_LIST[CMS_NODE]} Result.make (0)
|
||||
to_implement ("Not implemented")
|
||||
end
|
||||
|
||||
user_author_nodes (a_id: like {CMS_USER}.id): LIST[CMS_NODE]
|
||||
-- Possible list of nodes where the user identified by `a_id', is the author.
|
||||
do
|
||||
create {ARRAYED_LIST[CMS_NODE]} Result.make (0)
|
||||
to_implement ("Not implemented")
|
||||
end
|
||||
|
||||
feature -- Users roles and permissions
|
||||
|
||||
user_role_by_id (a_id: like {CMS_USER_ROLE}.id): detachable CMS_USER_ROLE
|
||||
-- User role by id `a_id', if any.
|
||||
do
|
||||
to_implement ("Not implemented")
|
||||
end
|
||||
|
||||
user_roles: LIST [CMS_USER_ROLE]
|
||||
-- Possible list of user roles.
|
||||
do
|
||||
create {ARRAYED_LIST[CMS_USER_ROLE]} Result.make (0)
|
||||
to_implement ("Not implemented")
|
||||
end
|
||||
|
||||
feature -- Change: roles and permissions
|
||||
|
||||
save_user_role (a_user_role: CMS_USER_ROLE)
|
||||
-- Save user role `a_user_role'
|
||||
do
|
||||
to_implement ("Not implemented")
|
||||
end
|
||||
|
||||
|
||||
feature -- Access: node
|
||||
|
||||
nodes: LIST[CMS_NODE]
|
||||
-- List of nodes.
|
||||
do
|
||||
create {ARRAYED_LIST[CMS_NODE]} Result.make (0)
|
||||
across node_provider.nodes as c loop
|
||||
Result.force (c.item)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
|
||||
-- List of the `a_count' most recent nodes, starting from `a_lower'.
|
||||
do
|
||||
create {ARRAYED_LIST[CMS_NODE]} Result.make (0)
|
||||
across node_provider.recent_nodes (a_lower,a_count) as c loop
|
||||
Result.force (c.item)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
node (a_id: INTEGER_64): detachable CMS_NODE
|
||||
--
|
||||
do
|
||||
Result := node_provider.node (a_id)
|
||||
|
||||
end
|
||||
|
||||
|
||||
feature -- Node
|
||||
|
||||
save_node (a_node: CMS_NODE)
|
||||
-- Add a new node
|
||||
do
|
||||
node_provider.new_node (a_node)
|
||||
|
||||
end
|
||||
|
||||
delete_node (a_id: INTEGER_64)
|
||||
do
|
||||
node_provider.delete_node (a_id)
|
||||
|
||||
end
|
||||
|
||||
update_node (a_id: like {CMS_USER}.id; a_node: CMS_NODE)
|
||||
do
|
||||
node_provider.update_node (a_node)
|
||||
|
||||
end
|
||||
|
||||
update_node_title (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_title: READABLE_STRING_32)
|
||||
do
|
||||
node_provider.update_node_title (a_id, a_title)
|
||||
|
||||
end
|
||||
|
||||
update_node_summary (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_summary: READABLE_STRING_32)
|
||||
do
|
||||
node_provider.update_node_summary (a_id, a_summary)
|
||||
|
||||
end
|
||||
|
||||
update_node_content (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_content: READABLE_STRING_32)
|
||||
do
|
||||
node_provider.update_node_content (a_id, a_content)
|
||||
|
||||
end
|
||||
|
||||
|
||||
node_author (a_id: like {CMS_NODE}.id): detachable CMS_USER
|
||||
-- Node's author. if any.
|
||||
do
|
||||
to_implement ("Not implemented")
|
||||
end
|
||||
|
||||
node_collaborators (a_id: like {CMS_NODE}.id): LIST [CMS_USER]
|
||||
-- Possible list of node's collaborator.
|
||||
do
|
||||
create {ARRAYED_LIST[CMS_USER]} Result.make (0)
|
||||
to_implement ("Not implemented")
|
||||
end
|
||||
|
||||
|
||||
feature -- User
|
||||
|
||||
new_user (a_user: CMS_USER)
|
||||
-- Add a new user `a_user'.
|
||||
do
|
||||
if
|
||||
attached a_user.password as l_password and then
|
||||
attached a_user.email as l_email
|
||||
then
|
||||
user_provider.new_user (a_user.name, l_password, l_email)
|
||||
else
|
||||
-- set error
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
node_provider: NODE_DATA_PROVIDER
|
||||
-- Node Data provider.
|
||||
|
||||
user_provider: USER_DATA_PROVIDER
|
||||
-- User Data provider.
|
||||
-- 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
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
note
|
||||
description: "[
|
||||
Objects that ...
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_STORAGE_SQLITE_BUILDER
|
||||
|
||||
inherit
|
||||
CMS_STORAGE_BUILDER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
end
|
||||
|
||||
feature -- Factory
|
||||
|
||||
storage (a_setup: CMS_SETUP): detachable CMS_STORAGE_SQLITE
|
||||
local
|
||||
s: STRING
|
||||
do
|
||||
if attached (create {APPLICATION_JSON_CONFIGURATION_HELPER}).new_database_configuration (a_setup.layout.application_config_path) as l_database_config then
|
||||
s := "Driver=SQLite3 ODBC Driver;Database="
|
||||
if attached l_database_config.database_name as db_name then
|
||||
s.append (db_name)
|
||||
end
|
||||
s.append (";LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;")
|
||||
create Result.make (create {DATABASE_CONNECTION_ODBC}.login_with_connection_string (s))
|
||||
--create Result.make (create {DATABASE_CONNECTION_ODBC}.login_with_connection_string (l_database_config.connection_string))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
note
|
||||
description: "Summary description for {CMS_USER_STORAGE_SQLITE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_USER_STORAGE_SQLITE
|
||||
|
||||
inherit
|
||||
CMS_USER_STORAGE_SQL
|
||||
|
||||
|
||||
end
|
||||
@@ -1,275 +0,0 @@
|
||||
note
|
||||
description: "Database access for node uses cases."
|
||||
date: "$Date: 2014-11-13 12:23:47 -0300 (ju., 13 nov. 2014) $"
|
||||
revision: "$Revision: 96085 $"
|
||||
|
||||
class
|
||||
NODE_DATA_PROVIDER
|
||||
|
||||
inherit
|
||||
|
||||
PARAMETER_NAME_HELPER
|
||||
|
||||
SHARED_ERROR
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (a_connection: DATABASE_CONNECTION)
|
||||
-- Create a data provider.
|
||||
do
|
||||
create {DATABASE_HANDLER_IMPL} db_handler.make (a_connection)
|
||||
|
||||
end
|
||||
|
||||
db_handler: DATABASE_HANDLER
|
||||
-- Db handler.
|
||||
|
||||
feature -- Status Report
|
||||
|
||||
is_successful: BOOLEAN
|
||||
-- Is the last execution sucessful?
|
||||
do
|
||||
Result := not db_handler.has_error
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
nodes: DATABASE_ITERATION_CURSOR [CMS_NODE]
|
||||
-- List of nodes.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".nodes")
|
||||
create l_parameters.make (0)
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (Select_nodes, l_parameters))
|
||||
db_handler.execute_query
|
||||
create Result.make (db_handler, agent fetch_node)
|
||||
|
||||
end
|
||||
|
||||
recent_nodes (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
|
||||
log.write_information (generator + ".recent_nodes")
|
||||
create l_parameters.make (2)
|
||||
l_parameters.put (a_rows, "rows")
|
||||
create l_query.make_from_string (select_recent_nodes)
|
||||
l_query.replace_substring_all ("$offset", a_lower.out)
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (l_query, l_parameters))
|
||||
db_handler.execute_query
|
||||
create Result.make (db_handler, agent fetch_node)
|
||||
|
||||
end
|
||||
|
||||
node (a_id: INTEGER_64): detachable CMS_NODE
|
||||
-- Node for the given id `a_id', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".node")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id,"id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_node_by_id, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := fetch_node
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
count: INTEGER
|
||||
-- Number of items nodes.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".count")
|
||||
create l_parameters.make (0)
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_count, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := db_handler.read_integer_32 (1)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
new_node (a_node: CMS_NODE)
|
||||
-- Create a new node.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".new_node")
|
||||
create l_parameters.make (6)
|
||||
l_parameters.put (a_node.title, "title")
|
||||
l_parameters.put (a_node.summary, "summary")
|
||||
l_parameters.put (a_node.content, "content")
|
||||
l_parameters.put (a_node.publication_date, "publication_date")
|
||||
l_parameters.put (a_node.creation_date, "creation_date")
|
||||
l_parameters.put (a_node.modification_date, "modification_date")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_insert_node, l_parameters))
|
||||
db_handler.execute_change
|
||||
|
||||
end
|
||||
|
||||
update_node_title (a_id: INTEGER_64; a_title: READABLE_STRING_32)
|
||||
-- Update node title for the corresponding the report with id `a_id'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".update_node_title")
|
||||
create l_parameters.make (3)
|
||||
l_parameters.put (a_title, "title")
|
||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
|
||||
l_parameters.put (a_id, "id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_update_node_title, l_parameters))
|
||||
db_handler.execute_change
|
||||
|
||||
end
|
||||
|
||||
update_node_summary (a_id: INTEGER_64; a_summary: READABLE_STRING_32)
|
||||
-- Update node summary for the corresponding the report with id `a_id'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".update_node_summary")
|
||||
create l_parameters.make (3)
|
||||
l_parameters.put (a_summary, "summary")
|
||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
|
||||
l_parameters.put (a_id, "id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_update_node_summary, l_parameters))
|
||||
db_handler.execute_change
|
||||
|
||||
end
|
||||
|
||||
update_node_content (a_id: INTEGER_64; a_content: READABLE_STRING_32)
|
||||
-- Update node content for the corresponding the report with id `a_id'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".update_node_content")
|
||||
create l_parameters.make (3)
|
||||
l_parameters.put (a_content, "content")
|
||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
|
||||
l_parameters.put (a_id, "id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_update_node_content, l_parameters))
|
||||
db_handler.execute_change
|
||||
|
||||
end
|
||||
|
||||
update_node (a_node: CMS_NODE)
|
||||
-- Update node.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".update_node")
|
||||
create l_parameters.make (7)
|
||||
l_parameters.put (a_node.title, "title")
|
||||
l_parameters.put (a_node.summary, "summary")
|
||||
l_parameters.put (a_node.content, "content")
|
||||
l_parameters.put (a_node.publication_date, "publication_date")
|
||||
l_parameters.put (a_node.creation_date, "creation_date")
|
||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
|
||||
l_parameters.put (a_node.id, "id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_update_node, l_parameters))
|
||||
db_handler.execute_change
|
||||
|
||||
end
|
||||
|
||||
delete_node (a_id: INTEGER_64;)
|
||||
-- Delete node with id `a_id'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".delete_node")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id, "id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_delete_node, l_parameters))
|
||||
db_handler.execute_change
|
||||
end
|
||||
|
||||
feature -- Connection
|
||||
|
||||
connect
|
||||
-- Connect to the database.
|
||||
do
|
||||
if not db_handler.is_connected then
|
||||
db_handler.connect
|
||||
end
|
||||
end
|
||||
|
||||
disconnect
|
||||
-- Disconnect to the database.
|
||||
do
|
||||
if db_handler.is_connected then
|
||||
db_handler.disconnect
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Queries
|
||||
|
||||
Select_count: STRING = "select count(*) from Nodes;"
|
||||
|
||||
Select_nodes: STRING = "select * from 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_recent_nodes: STRING = "select * from Nodes order by id desc, publication_date desc Limit $offset , :rows "
|
||||
|
||||
SQL_Insert_node: STRING = "insert into nodes (title, summary, content, publication_date, creation_date, modification_date) values (:title, :summary, :content, :publication_date, :creation_date, :modification_date);"
|
||||
-- SQL Insert to add a new node.
|
||||
|
||||
SQL_Update_node_title: STRING ="update nodes SET title=:title, modification_date=:modification_date where id=:id;"
|
||||
-- SQL update node title.
|
||||
|
||||
SQL_Update_node_summary: STRING ="update nodes SET summary=:summary, modification_date=:modification_date where id=:id;"
|
||||
-- SQL update node summary.
|
||||
|
||||
SQL_Update_node_content: STRING ="update nodes SET content=:content, modification_date=:modification_date where id=:id;"
|
||||
-- SQL node content.
|
||||
|
||||
SQL_Update_node : STRING = "update nodes SET title=:title, summary=:summary, content=:content, publication_date=:publication_date, creation_date=:creation_date, modification_date=:modification_date where id=:id;"
|
||||
-- SQL node.
|
||||
|
||||
SQL_Delete_node: STRING = "delete from nodes where id=:id;"
|
||||
|
||||
|
||||
feature -- New Object
|
||||
|
||||
fetch_node: CMS_NODE
|
||||
do
|
||||
create Result.make ("", "", "")
|
||||
if attached db_handler.read_integer_32 (1) as l_id then
|
||||
Result.set_id (l_id)
|
||||
end
|
||||
if attached db_handler.read_date_time (2) as l_pd then
|
||||
Result.set_publication_date (l_pd)
|
||||
end
|
||||
if attached db_handler.read_date_time (3) as l_cd then
|
||||
Result.set_creation_date (l_cd)
|
||||
end
|
||||
if attached db_handler.read_date_time (4) as l_md then
|
||||
Result.set_modification_date (l_md)
|
||||
end
|
||||
if attached db_handler.read_string (5) as l_t then
|
||||
Result.set_title (l_t)
|
||||
end
|
||||
if attached db_handler.read_string (6) as l_s then
|
||||
Result.set_summary (l_s)
|
||||
end
|
||||
if attached db_handler.read_string (7) as l_c then
|
||||
Result.set_content (l_c)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -1,193 +0,0 @@
|
||||
note
|
||||
description: "Summary description for {USER_DATA_PROVIDER}."
|
||||
date: "$Date: 2014-11-13 12:23:47 -0300 (ju., 13 nov. 2014) $"
|
||||
revision: "$Revision: 96085 $"
|
||||
|
||||
class
|
||||
USER_DATA_PROVIDER
|
||||
|
||||
inherit
|
||||
|
||||
PARAMETER_NAME_HELPER
|
||||
|
||||
SHARED_ERROR
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (a_connection: DATABASE_CONNECTION)
|
||||
-- Create a data provider.
|
||||
do
|
||||
create {DATABASE_HANDLER_IMPL} db_handler.make (a_connection)
|
||||
|
||||
end
|
||||
|
||||
db_handler: DATABASE_HANDLER
|
||||
-- Db handler.
|
||||
|
||||
feature -- Status Report
|
||||
|
||||
is_successful: BOOLEAN
|
||||
-- Is the last execution sucessful?
|
||||
do
|
||||
Result := not db_handler.has_error
|
||||
end
|
||||
|
||||
has_user: BOOLEAN
|
||||
-- Has any user?
|
||||
do
|
||||
Result := count > 0
|
||||
end
|
||||
|
||||
feature -- Basic Operations
|
||||
|
||||
new_user (a_user_name: READABLE_STRING_32; a_password: READABLE_STRING_32; a_email: READABLE_STRING_32)
|
||||
-- Create a new node.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
l_password_salt, l_password_hash: STRING
|
||||
l_security: SECURITY_PROVIDER
|
||||
do
|
||||
create l_security
|
||||
l_password_salt := l_security.salt
|
||||
l_password_hash := l_security.password_hash (a_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 (a_email,"email")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_insert_user, l_parameters))
|
||||
db_handler.execute_change
|
||||
|
||||
end
|
||||
|
||||
user (a_id: INTEGER_64): detachable CMS_USER
|
||||
-- User for the given id `a_id', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".user")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id,"id")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_user_by_id, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := fetch_user
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
user_by_name (a_name: READABLE_STRING_32): detachable CMS_USER
|
||||
-- User for the given name `a_name', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".user_by_name")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_name,"name")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_user_by_name, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := fetch_user
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
user_by_email (a_email: detachable READABLE_STRING_32): detachable CMS_USER
|
||||
-- User for the given email `a_email', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
log.write_information (generator + ".user_by_email")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_email,"email")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_user_by_email, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := fetch_user
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
user_salt (a_username: READABLE_STRING_32): detachable READABLE_STRING_32
|
||||
-- User salt for the given user `a_username', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".user_salt")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_username,"name")
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_salt_by_username, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
if attached db_handler.read_string (1) as l_salt then
|
||||
Result := l_salt.as_string_32
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
count: INTEGER
|
||||
-- Number of items users.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".count")
|
||||
create l_parameters.make (0)
|
||||
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_count, l_parameters))
|
||||
db_handler.execute_query
|
||||
if db_handler.count = 1 then
|
||||
Result := db_handler.read_integer_32 (1)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
feature -- New Object
|
||||
|
||||
fetch_user: CMS_USER
|
||||
do
|
||||
create Result.make ("")
|
||||
if attached db_handler.read_integer_32 (1) as l_id then
|
||||
Result.set_id (l_id)
|
||||
end
|
||||
if attached db_handler.read_string (2) as l_u then
|
||||
Result.set_name (l_u)
|
||||
end
|
||||
if attached db_handler.read_string (3) as l_p then
|
||||
Result.set_password (l_p)
|
||||
end
|
||||
if attached db_handler.read_string (5) as l_e then
|
||||
Result.set_email (l_e)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Sql Queries
|
||||
|
||||
Select_count: STRING = "select count(*) from Users;"
|
||||
-- Number of users.
|
||||
|
||||
Select_user_by_id: STRING = "select * from Users where id =:id;"
|
||||
-- Retrieve user by id if exists.
|
||||
|
||||
Select_user_by_name: STRING = "select * from Users where username =:name;"
|
||||
-- Retrieve user by name if exists.
|
||||
|
||||
Select_user_by_email: STRING = "select * from Users where email =:email;"
|
||||
-- Retrieve user by email if exists.
|
||||
|
||||
Select_salt_by_username: STRING = "select salt from Users where username =:name;"
|
||||
-- Retrieve salt by username if exists.
|
||||
|
||||
SQL_Insert_user: STRING = "insert into users (username, password, salt, email) values (:username, :password, :salt, :email);"
|
||||
-- SQL Insert to add a new node.
|
||||
|
||||
|
||||
|
||||
end
|
||||
@@ -216,6 +216,7 @@ feature -- Test routines
|
||||
across 1 |..| 10 as c loop
|
||||
storage.save_node (custom_node ("Content_" + c.item.out, "Summary_" + c.item.out, "Title_" + c.item.out))
|
||||
end
|
||||
assert ("has nodes", storage.nodes.count > 5)
|
||||
assert ("Node id: 10", attached storage.node (10) as l_node and then l_node.title ~ "Title_10" )
|
||||
end
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="cms" location="..\..\..\..\..\cms-safe.ecf" readonly="false"/>
|
||||
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf"/>
|
||||
<library name="model" location="..\..\..\..\model\cms_model-safe.ecf"/>
|
||||
<library name="persitence_sqlite" location="..\persistence_sqlite-safe.ecf" readonly="false"/>
|
||||
|
||||
@@ -12,8 +12,8 @@ feature -- Database connection
|
||||
connection: DATABASE_CONNECTION_ODBC
|
||||
-- odbc database connection
|
||||
once
|
||||
-- create Result.login_with_connection_string ("Driver=SQLite3 ODBC Driver;Database=PATH/SQLITE.FILE;LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;")
|
||||
create Result.make_basic ("cms_dev")
|
||||
create Result.login_with_connection_string ("Driver=SQLite3 ODBC Driver;Database=cms_lite.db;LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;")
|
||||
-- create Result.make_basic ("cms_lite.db")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,261 +0,0 @@
|
||||
|
||||
note
|
||||
description : "[
|
||||
CMS interface to storage
|
||||
]"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_STORAGE
|
||||
|
||||
inherit
|
||||
|
||||
SHARED_LOGGER
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
do
|
||||
end
|
||||
|
||||
feature -- Error Handling
|
||||
|
||||
error_handler: ERROR_HANDLER
|
||||
-- Error handler.
|
||||
|
||||
feature -- Access: user
|
||||
|
||||
has_user: BOOLEAN
|
||||
-- Has any user?
|
||||
deferred
|
||||
end
|
||||
|
||||
all_users: LIST [CMS_USER]
|
||||
-- Possible list of users.
|
||||
deferred
|
||||
end
|
||||
|
||||
user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER
|
||||
-- User with id `a_id', if any.
|
||||
require
|
||||
a_id > 0
|
||||
deferred
|
||||
ensure
|
||||
same_id: Result /= Void implies Result.id = a_id
|
||||
password: Result /= Void implies Result.password /= Void
|
||||
end
|
||||
|
||||
user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER
|
||||
-- User with name `a_name', if any.
|
||||
require
|
||||
a_name /= Void and then not a_name.is_empty
|
||||
deferred
|
||||
ensure
|
||||
same_name: Result /= Void implies a_name ~ Result.name
|
||||
password: Result /= Void implies Result.password /= Void
|
||||
end
|
||||
|
||||
user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER
|
||||
-- User with name `a_email', if any.
|
||||
deferred
|
||||
ensure
|
||||
same_email: Result /= Void implies a_email ~ Result.email
|
||||
password: Result /= Void implies Result.password /= Void
|
||||
end
|
||||
|
||||
is_valid_credential (a_u, a_p: READABLE_STRING_32): BOOLEAN
|
||||
-- Does account with username `a_username' and password `a_password' exist?
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- User Nodes
|
||||
|
||||
user_collaborator_nodes (a_id: like {CMS_USER}.id): LIST[CMS_NODE]
|
||||
-- Possible list of nodes where the user identified by `a_id', is a collaborator.
|
||||
require
|
||||
a_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
user_author_nodes (a_id: like {CMS_USER}.id): LIST[CMS_NODE]
|
||||
-- Possible list of nodes where the user identified by `a_id', is the author.
|
||||
require
|
||||
a_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Change: user
|
||||
|
||||
save_user (a_user: CMS_USER)
|
||||
-- Save user `a_user'.
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Access: roles and permissions
|
||||
|
||||
user_has_permission (u: detachable CMS_USER; s: detachable READABLE_STRING_8): BOOLEAN
|
||||
-- Anonymous or user `u' has permission for `s' ?
|
||||
--| `s' could be "create page",
|
||||
do
|
||||
-- if s = Void then
|
||||
-- Result := True
|
||||
-- elseif u = Void then
|
||||
---- Result := user_role_has_permission (anonymous_user_role, s)
|
||||
-- else
|
||||
-- Result := user_role_has_permission (authenticated_user_role, s)
|
||||
-- if not Result and attached u.roles as l_roles then
|
||||
-- across
|
||||
-- l_roles as r
|
||||
-- until
|
||||
-- Result
|
||||
-- loop
|
||||
-- if attached user_role_by_id (r.item) as ur then
|
||||
-- Result := user_role_has_permission (ur, s)
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
end
|
||||
|
||||
user_role_has_permission (a_role: CMS_USER_ROLE; s: READABLE_STRING_8): BOOLEAN
|
||||
do
|
||||
Result := a_role.has_permission (s)
|
||||
end
|
||||
|
||||
user_role_by_id (a_id: like {CMS_USER_ROLE}.id): detachable CMS_USER_ROLE
|
||||
-- User role by id `a_id', if any.
|
||||
deferred
|
||||
end
|
||||
|
||||
user_roles: LIST [CMS_USER_ROLE]
|
||||
-- Possible list of user roles.
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Change: roles and permissions
|
||||
|
||||
save_user_role (a_user_role: CMS_USER_ROLE)
|
||||
-- Save user role `a_user_role'
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Email
|
||||
|
||||
-- save_email (a_email: NOTIFICATION_EMAIL)
|
||||
-- deferred
|
||||
-- end
|
||||
|
||||
--feature -- Log
|
||||
|
||||
-- recent_logs (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_LOG]
|
||||
-- deferred
|
||||
-- end
|
||||
|
||||
-- log (a_id: like {CMS_LOG}.id): detachable CMS_LOG
|
||||
-- require
|
||||
-- a_id > 0
|
||||
-- deferred
|
||||
-- end
|
||||
|
||||
-- save_log (a_log: CMS_LOG)
|
||||
-- deferred
|
||||
-- end
|
||||
|
||||
feature -- Access: Node
|
||||
|
||||
recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
|
||||
-- List of recent `a_count' nodes with an offset of `lower'.
|
||||
deferred
|
||||
end
|
||||
|
||||
node (a_id: INTEGER_64): detachable CMS_NODE
|
||||
-- Retrieve node by id `a_id', if any.
|
||||
require
|
||||
a_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
node_author (a_id: like {CMS_NODE}.id): detachable CMS_USER
|
||||
-- Node's author. if any.
|
||||
require
|
||||
valid_node: a_id >0
|
||||
deferred
|
||||
end
|
||||
|
||||
node_collaborators (a_id: like {CMS_NODE}.id): LIST [CMS_USER]
|
||||
-- Possible list of node's collaborator.
|
||||
require
|
||||
valid_node: a_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Change: Node
|
||||
|
||||
save_node (a_node: CMS_NODE)
|
||||
-- Save node `a_node'.
|
||||
require
|
||||
valid_user: attached a_node.author as l_author and then l_author.id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
delete_node (a_id: INTEGER_64)
|
||||
-- Remove node by id `a_id'.
|
||||
require
|
||||
valid_node_id: a_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
update_node (a_id: like {CMS_USER}.id; a_node: CMS_NODE)
|
||||
-- Update node content `a_node'.
|
||||
-- The user `a_id' is an existing or new collaborator.
|
||||
require
|
||||
valid_node_id: a_node.id > 0
|
||||
valid_user_id: a_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
update_node_title (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_title: READABLE_STRING_32)
|
||||
-- Update node title to `a_title', node identified by id `a_node_id'.
|
||||
-- The user `a_id' is an existing or new collaborator.
|
||||
require
|
||||
valid_node_id: a_node_id > 0
|
||||
valid_user_id: a_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
update_node_summary (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_summary: READABLE_STRING_32)
|
||||
-- Update node summary to `a_summary', node identified by id `a_node_id'.
|
||||
-- The user `a_id' is an existing or new collaborator.
|
||||
require
|
||||
valid_id: a_node_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
update_node_content (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_content: READABLE_STRING_32)
|
||||
-- Update node content to `a_content', node identified by id `a_node_id'.
|
||||
-- The user `a_id' is an existing or new collaborator.
|
||||
require
|
||||
valid_id: a_node_id > 0
|
||||
valid_user_id: a_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
--feature -- Misc
|
||||
|
||||
-- set_custom_value (a_name: READABLE_STRING_8; a_value: attached like custom_value; a_type: READABLE_STRING_8)
|
||||
-- -- Save data `a_name:a_value' for type `a_type'
|
||||
-- deferred
|
||||
-- end
|
||||
|
||||
-- custom_value (a_name: READABLE_STRING_8; a_type: READABLE_STRING_8): detachable TABLE_ITERABLE [READABLE_STRING_8, STRING_8]
|
||||
-- -- Data for name `a_name' and type `a_type'.
|
||||
-- deferred
|
||||
-- end
|
||||
|
||||
-- custom_value_names_where (a_where_key, a_where_value: READABLE_STRING_8; a_type: READABLE_STRING_8): detachable LIST [READABLE_STRING_8]
|
||||
-- -- Names where custom value has item `a_where_key' same as `a_where_value' for type `a_type'.
|
||||
-- deferred
|
||||
-- end
|
||||
|
||||
end
|
||||
@@ -31,7 +31,10 @@ feature {NONE} -- Initialization
|
||||
do
|
||||
configure
|
||||
create modules.make (3)
|
||||
create storage_drivers.make (2)
|
||||
|
||||
build_mailer
|
||||
initialize_storages
|
||||
initialize_modules
|
||||
end
|
||||
|
||||
@@ -72,6 +75,12 @@ feature {NONE} -- Initialization
|
||||
compute_theme_assets_location
|
||||
end
|
||||
|
||||
initialize_storages
|
||||
-- Initialize storages
|
||||
do
|
||||
storage_drivers.force (create {CMS_STORAGE_NULL_BUILDER}, "null")
|
||||
end
|
||||
|
||||
initialize_modules
|
||||
-- Intialize core modules.
|
||||
local
|
||||
@@ -144,6 +153,11 @@ feature -- Access
|
||||
to_implement ("Not implemented mailer")
|
||||
end
|
||||
|
||||
feature -- Access: storage
|
||||
|
||||
storage_drivers: STRING_TABLE [CMS_STORAGE_BUILDER]
|
||||
-- Precursor
|
||||
|
||||
feature -- Element change
|
||||
|
||||
register_module (m: CMS_MODULE)
|
||||
|
||||
@@ -6,6 +6,9 @@ note
|
||||
deferred class
|
||||
CMS_SETUP
|
||||
|
||||
inherit
|
||||
REFACTORING_HELPER
|
||||
|
||||
feature -- Access
|
||||
|
||||
layout: CMS_LAYOUT
|
||||
@@ -88,7 +91,6 @@ feature -- Query
|
||||
deferred
|
||||
end
|
||||
|
||||
|
||||
feature -- Access: Theme
|
||||
|
||||
themes_location: PATH
|
||||
@@ -109,6 +111,54 @@ feature -- Access: Theme
|
||||
theme_name: READABLE_STRING_32
|
||||
-- theme name.
|
||||
|
||||
feature -- Access: storage
|
||||
|
||||
storage_drivers: STRING_TABLE [CMS_STORAGE_BUILDER]
|
||||
deferred
|
||||
end
|
||||
|
||||
storage (a_error_handler: ERROR_HANDLER): detachable CMS_STORAGE
|
||||
local
|
||||
retried: BOOLEAN
|
||||
l_message: STRING
|
||||
do
|
||||
if not retried then
|
||||
to_implement ("Refactor database setup")
|
||||
if
|
||||
attached (create {APPLICATION_JSON_CONFIGURATION_HELPER}).new_database_configuration (layout.application_config_path) as l_database_config and then
|
||||
attached storage_drivers.item (l_database_config.driver) as l_builder
|
||||
then
|
||||
Result := l_builder.storage (Current)
|
||||
else
|
||||
create {CMS_STORAGE_NULL} Result
|
||||
end
|
||||
else
|
||||
to_implement ("Workaround code, persistence layer does not implement yet this kind of error handling.")
|
||||
-- error hanling.
|
||||
create {CMS_STORAGE_NULL} Result
|
||||
create l_message.make (1024)
|
||||
if attached ((create {EXCEPTION_MANAGER}).last_exception) as l_exception then
|
||||
if attached l_exception.description as l_description then
|
||||
l_message.append (l_description.as_string_32)
|
||||
l_message.append ("%N%N")
|
||||
elseif attached l_exception.trace as l_trace then
|
||||
l_message.append (l_trace)
|
||||
l_message.append ("%N%N")
|
||||
else
|
||||
l_message.append (l_exception.out)
|
||||
l_message.append ("%N%N")
|
||||
end
|
||||
else
|
||||
l_message.append ("The application crash without available information")
|
||||
l_message.append ("%N%N")
|
||||
end
|
||||
a_error_handler.add_custom_error (0, " Database Connection ", l_message)
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
register_module (m: CMS_MODULE)
|
||||
|
||||
@@ -120,7 +120,7 @@ feature -- HTTP Methods
|
||||
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
|
||||
if l_id.is_integer and then attached {CMS_NODE} api.node (l_id.integer_value) as l_node then
|
||||
u_node := extract_data_form (req)
|
||||
u_node.set_id (l_id.integer_value)
|
||||
u_node.set_id (l_id.value.to_integer_64)
|
||||
api.update_node_content (l_user.id, u_node.id, u_node.content)
|
||||
(create {CMS_GENERIC_RESPONSE}).new_response_redirect (req, res, req.absolute_script_url (""))
|
||||
else
|
||||
|
||||
@@ -68,7 +68,10 @@ feature -- HTTP Methods
|
||||
do
|
||||
-- Existing node
|
||||
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
|
||||
if l_id.is_integer and then attached {CMS_NODE} api.node (l_id.integer_value) as l_node then
|
||||
if
|
||||
l_id.is_integer and then
|
||||
attached api.node (l_id.value.to_integer_64) as l_node
|
||||
then
|
||||
create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api)
|
||||
l_page.add_variable (l_node, "node")
|
||||
l_page.execute
|
||||
@@ -89,7 +92,10 @@ feature -- HTTP Methods
|
||||
to_implement ("Check user permissions!!!")
|
||||
if attached current_user (req) as l_user then
|
||||
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
|
||||
if l_id.is_integer and then attached {CMS_NODE} api.node (l_id.integer_value) as l_node then
|
||||
if
|
||||
l_id.is_integer and then
|
||||
attached {CMS_NODE} api.node (l_id.value.to_integer_64) as l_node
|
||||
then
|
||||
if attached {WSF_STRING} req.form_parameter ("method") as l_method then
|
||||
if l_method.is_case_insensitive_equal ("DELETE") then
|
||||
do_delete (req, res)
|
||||
@@ -104,7 +110,8 @@ feature -- HTTP Methods
|
||||
end
|
||||
else
|
||||
-- New node
|
||||
u_node := extract_data_form (req)
|
||||
create u_node.make ("", "", "")
|
||||
update_node_from_data_form (req, u_node)
|
||||
u_node.set_author (l_user)
|
||||
api.new_node (u_node)
|
||||
(create {CMS_GENERIC_RESPONSE}).new_response_redirect (req, res, req.absolute_script_url (""))
|
||||
@@ -116,16 +123,17 @@ feature -- HTTP Methods
|
||||
|
||||
do_put (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- <Precursor>
|
||||
local
|
||||
u_node: CMS_NODE
|
||||
do
|
||||
|
||||
if attached current_user (req) as l_user then
|
||||
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
|
||||
if l_id.is_integer and then attached {CMS_NODE} api.node (l_id.integer_value) as l_node then
|
||||
u_node := extract_data_form (req)
|
||||
u_node.set_id (l_id.integer_value)
|
||||
api.update_node (l_user.id,u_node)
|
||||
if
|
||||
l_id.is_integer and then
|
||||
attached api.node (l_id.value.to_integer_64) as l_node
|
||||
then
|
||||
update_node_from_data_form (req, l_node)
|
||||
l_node.set_author (l_user)
|
||||
api.update_node (l_node)
|
||||
(create {CMS_GENERIC_RESPONSE}).new_response_redirect (req, res, req.absolute_script_url (""))
|
||||
else
|
||||
do_error (req, res, l_id)
|
||||
@@ -136,7 +144,6 @@ feature -- HTTP Methods
|
||||
else
|
||||
(create {CMS_GENERIC_RESPONSE}).new_response_unauthorized (req, res)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
@@ -144,7 +151,10 @@ feature -- HTTP Methods
|
||||
do
|
||||
if attached current_user_name (req) then
|
||||
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
|
||||
if l_id.is_integer and then attached {CMS_NODE} api.node (l_id.integer_value) as l_node then
|
||||
if
|
||||
l_id.is_integer and then
|
||||
attached api.node (l_id.integer_value) as l_node
|
||||
then
|
||||
api.delete_node (l_id.integer_value)
|
||||
(create {CMS_GENERIC_RESPONSE}).new_response_redirect (req, res, req.absolute_script_url (""))
|
||||
else
|
||||
@@ -198,19 +208,18 @@ feature {NONE} -- Node
|
||||
|
||||
feature -- {NONE} Form data
|
||||
|
||||
extract_data_form (req: WSF_REQUEST): CMS_NODE
|
||||
update_node_from_data_form (req: WSF_REQUEST; a_node: CMS_NODE)
|
||||
-- Extract request form data and build a object
|
||||
-- Node
|
||||
do
|
||||
create Result.make ("", "", "")
|
||||
if attached {WSF_STRING} req.form_parameter ("title") as l_title then
|
||||
Result.set_title (l_title.value)
|
||||
a_node.set_title (l_title.value)
|
||||
end
|
||||
if attached {WSF_STRING} req.form_parameter ("summary") as l_summary then
|
||||
Result.set_summary (l_summary.value)
|
||||
a_node.set_summary (l_summary.value)
|
||||
end
|
||||
if attached {WSF_STRING} req.form_parameter ("content") as l_content then
|
||||
Result.set_content (l_content.value)
|
||||
a_node.set_content (l_content.value)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ feature -- HTTP Methods
|
||||
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
|
||||
if l_id.is_integer and then attached {CMS_NODE} api.node (l_id.integer_value) as l_node then
|
||||
u_node := extract_data_form (req)
|
||||
u_node.set_id (l_id.integer_value)
|
||||
u_node.set_id (l_id.value.to_integer_64)
|
||||
api.update_node_summary (l_user.id,u_node.id, u_node.summary)
|
||||
(create {CMS_GENERIC_RESPONSE}).new_response_redirect (req, res, req.absolute_script_url (""))
|
||||
else
|
||||
|
||||
@@ -118,7 +118,7 @@ feature -- HTTP Methods
|
||||
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
|
||||
if l_id.is_integer and then attached {CMS_NODE} api.node (l_id.integer_value) as l_node then
|
||||
u_node := extract_data_form (req)
|
||||
u_node.set_id (l_id.integer_value)
|
||||
u_node.set_id (l_id.value.to_integer_64)
|
||||
api.update_node_title (l_user.id,u_node.id, u_node.title)
|
||||
(create {CMS_GENERIC_RESPONSE}).new_response_redirect (req, res, req.absolute_script_url (""))
|
||||
else
|
||||
|
||||
@@ -33,7 +33,6 @@ feature {NONE} -- Initialization
|
||||
config := a_setup
|
||||
end
|
||||
|
||||
|
||||
config: CMS_SETUP
|
||||
-- Node configuration.
|
||||
|
||||
@@ -159,10 +158,42 @@ feature -- Handler
|
||||
do_get_nodes (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: CMS_API)
|
||||
local
|
||||
r: CMS_RESPONSE
|
||||
s: STRING
|
||||
l_user: CMS_USER
|
||||
l_node: CMS_NODE
|
||||
do
|
||||
create {NOT_IMPLEMENTED_ERROR_CMS_RESPONSE} r.make (req, res, a_api)
|
||||
r.set_main_content ("Sorry: listing the CMS nodes is not yet implemented.")
|
||||
r.add_block (create {CMS_CONTENT_BLOCK}.make ("nodes_warning", Void, "/nodes/ is not yet implemented", Void), "highlighted")
|
||||
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_api)
|
||||
|
||||
if attached a_api.user_by_name ("foo") as u then
|
||||
l_user := u
|
||||
else
|
||||
create l_user.make ("foo")
|
||||
l_user.set_password ("foobar#")
|
||||
l_user.set_email ("test@example.com")
|
||||
a_api.new_user (l_user)
|
||||
end
|
||||
if a_api.nodes_count = 0 then
|
||||
create l_node.make ({STRING_32} "This is a content", {STRING_32} "And a summary", {STRING_32} "Nice title")
|
||||
l_node.set_author (l_user)
|
||||
a_api.new_node (l_node)
|
||||
end
|
||||
|
||||
create s.make_from_string ("<p>Nodes:</p>")
|
||||
if attached a_api.nodes as lst then
|
||||
across
|
||||
lst as ic
|
||||
loop
|
||||
s.append ("<li>")
|
||||
s.append (a_api.html_encoded (ic.item.title))
|
||||
s.append (" (")
|
||||
s.append (ic.item.id.out)
|
||||
s.append (")")
|
||||
s.append ("</li>%N")
|
||||
end
|
||||
end
|
||||
|
||||
r.set_main_content (s)
|
||||
r.add_block (create {CMS_CONTENT_BLOCK}.make ("nodes_warning", Void, "/nodes/ is not yet fully implemented<br/>", Void), "highlighted")
|
||||
r.execute
|
||||
end
|
||||
|
||||
|
||||
47
library/src/persistence/cms_storage.e
Normal file
47
library/src/persistence/cms_storage.e
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
note
|
||||
description : "[
|
||||
CMS interface to storage
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_STORAGE
|
||||
|
||||
inherit
|
||||
CMS_USER_STORAGE
|
||||
|
||||
CMS_NODE_STORAGE
|
||||
|
||||
SHARED_LOGGER
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
do
|
||||
end
|
||||
|
||||
feature -- Error Handling
|
||||
|
||||
error_handler: ERROR_HANDLER
|
||||
-- Error handler.
|
||||
|
||||
feature -- Misc
|
||||
|
||||
-- set_custom_value (a_name: READABLE_STRING_8; a_value: attached like custom_value; a_type: READABLE_STRING_8)
|
||||
-- -- Save data `a_name:a_value' for type `a_type'
|
||||
-- deferred
|
||||
-- end
|
||||
|
||||
-- custom_value (a_name: READABLE_STRING_8; a_type: READABLE_STRING_8): detachable TABLE_ITERABLE [READABLE_STRING_8, STRING_8]
|
||||
-- -- Data for name `a_name' and type `a_type'.
|
||||
-- deferred
|
||||
-- end
|
||||
|
||||
-- custom_value_names_where (a_where_key, a_where_value: READABLE_STRING_8; a_type: READABLE_STRING_8): detachable LIST [READABLE_STRING_8]
|
||||
-- -- Names where custom value has item `a_where_key' same as `a_where_value' for type `a_type'.
|
||||
-- deferred
|
||||
-- end
|
||||
|
||||
end
|
||||
18
library/src/persistence/cms_storage_builder.e
Normal file
18
library/src/persistence/cms_storage_builder.e
Normal file
@@ -0,0 +1,18 @@
|
||||
note
|
||||
description: "[
|
||||
Objects that ...
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_STORAGE_BUILDER
|
||||
|
||||
feature -- Factory
|
||||
|
||||
storage (a_setup: CMS_SETUP): detachable CMS_STORAGE
|
||||
deferred
|
||||
end
|
||||
|
||||
end
|
||||
@@ -7,13 +7,13 @@ class
|
||||
CMS_STORAGE_NULL
|
||||
|
||||
inherit
|
||||
|
||||
CMS_STORAGE
|
||||
redefine
|
||||
default_create
|
||||
select
|
||||
default_create
|
||||
end
|
||||
|
||||
REFACTORING_HELPER
|
||||
rename
|
||||
default_create as default_create_rh
|
||||
@@ -33,7 +33,7 @@ feature -- Access: user
|
||||
do
|
||||
end
|
||||
|
||||
all_users: LIST [CMS_USER]
|
||||
users: LIST [CMS_USER]
|
||||
do
|
||||
create {ARRAYED_LIST[CMS_USER]} Result.make (0)
|
||||
end
|
||||
@@ -70,11 +70,16 @@ feature -- User Nodes
|
||||
|
||||
feature -- Change: user
|
||||
|
||||
save_user (a_user: CMS_USER)
|
||||
new_user (a_user: CMS_USER)
|
||||
-- Add a new user `a_user'.
|
||||
do
|
||||
end
|
||||
|
||||
update_user (a_user: CMS_USER)
|
||||
-- Update user `a_user'.
|
||||
do
|
||||
end
|
||||
|
||||
feature -- Access: roles and permissions
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
|
||||
feature -- Access: node
|
||||
|
||||
nodes_count: INTEGER_64
|
||||
-- Count of nodes.
|
||||
do
|
||||
end
|
||||
|
||||
nodes: LIST[CMS_NODE]
|
||||
-- List of nodes.
|
||||
do
|
||||
@@ -126,7 +135,7 @@ feature -- Access: node
|
||||
|
||||
feature -- Node
|
||||
|
||||
save_node (a_node: CMS_NODE)
|
||||
new_node (a_node: CMS_NODE)
|
||||
-- Add a new node
|
||||
do
|
||||
end
|
||||
@@ -136,31 +145,24 @@ feature -- Node
|
||||
do
|
||||
end
|
||||
|
||||
update_node (a_id: like {CMS_NODE}.id; a_node: CMS_NODE)
|
||||
update_node (a_node: CMS_NODE)
|
||||
-- <Precursor>
|
||||
do
|
||||
end
|
||||
|
||||
update_node_title (a_id: like {CMS_NODE}.id; a_node_id: like {CMS_NODE}.id; a_title: READABLE_STRING_32)
|
||||
update_node_title (a_user_id: like {CMS_NODE}.id; a_node_id: like {CMS_NODE}.id; a_title: READABLE_STRING_32)
|
||||
-- <Precursor>
|
||||
do
|
||||
end
|
||||
|
||||
update_node_summary (a_id: like {CMS_NODE}.id; a_node_id: like {CMS_NODE}.id; a_summary: READABLE_STRING_32)
|
||||
update_node_summary (a_user_id: like {CMS_NODE}.id; a_node_id: like {CMS_NODE}.id; a_summary: READABLE_STRING_32)
|
||||
-- <Precursor>
|
||||
do
|
||||
end
|
||||
|
||||
update_node_content (a_id: like {CMS_NODE}.id; a_node_id: like {CMS_NODE}.id; a_content: READABLE_STRING_32)
|
||||
update_node_content (a_user_id: like {CMS_NODE}.id; a_node_id: like {CMS_NODE}.id; a_content: READABLE_STRING_32)
|
||||
-- <Precursor>
|
||||
do
|
||||
end
|
||||
|
||||
feature -- User
|
||||
|
||||
new_user (a_user: CMS_USER)
|
||||
-- Add a new user `a_user'.
|
||||
do
|
||||
end
|
||||
|
||||
end
|
||||
22
library/src/persistence/cms_storage_null_builder.e
Normal file
22
library/src/persistence/cms_storage_null_builder.e
Normal file
@@ -0,0 +1,22 @@
|
||||
note
|
||||
description: "[
|
||||
Objects that ...
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_STORAGE_NULL_BUILDER
|
||||
|
||||
inherit
|
||||
CMS_STORAGE_BUILDER
|
||||
|
||||
feature -- Factory
|
||||
|
||||
storage (a_setup: CMS_SETUP): detachable CMS_STORAGE_NULL
|
||||
do
|
||||
create Result
|
||||
end
|
||||
|
||||
end
|
||||
210
library/src/persistence/cms_storage_sql.e
Normal file
210
library/src/persistence/cms_storage_sql.e
Normal file
@@ -0,0 +1,210 @@
|
||||
note
|
||||
description: "Summary description for {CMS_STORAGE_SQL}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_STORAGE_SQL
|
||||
|
||||
feature -- Error handler
|
||||
|
||||
error_handler: ERROR_HANDLER
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
sql_begin_transaction
|
||||
deferred
|
||||
end
|
||||
|
||||
sql_commit_transaction
|
||||
deferred
|
||||
end
|
||||
|
||||
sql_post_execution
|
||||
-- Post database execution.
|
||||
deferred
|
||||
end
|
||||
|
||||
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])
|
||||
deferred
|
||||
end
|
||||
|
||||
sql_change (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY])
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
sql_rows_count: INTEGER
|
||||
-- Number of rows for last sql execution.
|
||||
deferred
|
||||
end
|
||||
|
||||
sql_start
|
||||
-- Set the cursor on first element.
|
||||
deferred
|
||||
end
|
||||
|
||||
sql_after: BOOLEAN
|
||||
-- Are there no more items to iterate over?
|
||||
deferred
|
||||
end
|
||||
|
||||
sql_forth
|
||||
-- Fetch next row from last sql execution, if any.
|
||||
deferred
|
||||
end
|
||||
|
||||
sql_item (a_index: INTEGER): detachable ANY
|
||||
deferred
|
||||
end
|
||||
|
||||
sql_read_integer_64 (a_index: INTEGER): INTEGER_64
|
||||
-- Retrieved value at `a_index' position in `item'.
|
||||
local
|
||||
l_item: like sql_item
|
||||
do
|
||||
l_item := sql_item (a_index)
|
||||
if attached {INTEGER_64} l_item as i then
|
||||
Result := i
|
||||
elseif attached {INTEGER_64_REF} l_item as l_value then
|
||||
Result := l_value.item
|
||||
else
|
||||
Result := sql_read_integer_32 (a_index).to_integer_64
|
||||
end
|
||||
end
|
||||
|
||||
sql_read_integer_32 (a_index: INTEGER): INTEGER_32
|
||||
-- Retrieved value at `a_index' position in `item'.
|
||||
local
|
||||
l_item: like sql_item
|
||||
do
|
||||
l_item := sql_item (a_index)
|
||||
if attached {INTEGER_32} l_item as i then
|
||||
Result := i
|
||||
elseif attached {INTEGER_32_REF} l_item as l_value then
|
||||
Result := l_value.item
|
||||
else
|
||||
-- check is_integer_32: False end
|
||||
end
|
||||
end
|
||||
|
||||
sql_read_string (a_index: INTEGER): detachable STRING
|
||||
-- Retrieved value at `a_index' position in `item'.
|
||||
local
|
||||
l_item: like sql_item
|
||||
do
|
||||
l_item := sql_item (a_index)
|
||||
if attached {READABLE_STRING_8} l_item as l_string then
|
||||
Result := l_string
|
||||
elseif attached {BOOLEAN} l_item as l_boolean then
|
||||
Result := l_boolean.out
|
||||
elseif attached {BOOLEAN_REF} l_item as l_boolean_ref then
|
||||
Result := l_boolean_ref.item.out
|
||||
else
|
||||
-- check is_string: False end
|
||||
end
|
||||
end
|
||||
|
||||
sql_read_string_32 (a_index: INTEGER): detachable STRING_32
|
||||
-- Retrieved value at `a_index' position in `item'.
|
||||
local
|
||||
l_item: like sql_item
|
||||
do
|
||||
-- FIXME: handle string_32 !
|
||||
l_item := sql_item (a_index)
|
||||
if attached {READABLE_STRING_32} l_item as l_string then
|
||||
Result := l_string
|
||||
else
|
||||
if attached sql_read_string (a_index) as s8 then
|
||||
Result := s8.to_string_32 -- FIXME
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
sql_read_date_time (a_index: INTEGER): detachable DATE_TIME
|
||||
-- Retrieved value at `a_index' position in `item'.
|
||||
local
|
||||
l_item: like sql_item
|
||||
do
|
||||
l_item := sql_item (a_index)
|
||||
if attached {DATE_TIME} l_item as dt then
|
||||
Result := dt
|
||||
else
|
||||
-- check is_date_time: False end
|
||||
end
|
||||
end
|
||||
|
||||
sql_read_boolean (a_index: INTEGER): detachable BOOLEAN
|
||||
-- Retrieved value at `a_index' position in `item'.
|
||||
local
|
||||
l_item: like sql_item
|
||||
do
|
||||
l_item := sql_item (a_index)
|
||||
if attached {BOOLEAN} l_item as l_boolean then
|
||||
Result := l_boolean
|
||||
elseif attached {BOOLEAN_REF} l_item as l_boolean_ref then
|
||||
Result := l_boolean_ref.item
|
||||
else
|
||||
check is_boolean: False end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
103
library/src/persistence/node/cms_node_storage.e
Normal file
103
library/src/persistence/node/cms_node_storage.e
Normal file
@@ -0,0 +1,103 @@
|
||||
note
|
||||
description: "Summary description for {CMS_NODE_STORAGE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_NODE_STORAGE
|
||||
|
||||
inherit
|
||||
SHARED_LOGGER
|
||||
|
||||
feature -- Error Handling
|
||||
|
||||
error_handler: ERROR_HANDLER
|
||||
-- Error handler.
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
nodes_count: INTEGER_64
|
||||
-- Count of nodes.
|
||||
deferred
|
||||
end
|
||||
|
||||
nodes: LIST [CMS_NODE]
|
||||
-- List of nodes.
|
||||
deferred
|
||||
end
|
||||
|
||||
recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
|
||||
-- List of recent `a_count' nodes with an offset of `lower'.
|
||||
deferred
|
||||
end
|
||||
|
||||
node (a_id: INTEGER_64): detachable CMS_NODE
|
||||
-- Retrieve node by id `a_id', if any.
|
||||
require
|
||||
a_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
node_author (a_id: like {CMS_NODE}.id): detachable CMS_USER
|
||||
-- Node's author. if any.
|
||||
require
|
||||
valid_node: a_id >0
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Change: Node
|
||||
|
||||
new_node (a_node: CMS_NODE)
|
||||
-- Save node `a_node'.
|
||||
require
|
||||
no_id: not a_node.has_id
|
||||
valid_user: attached a_node.author as l_author and then l_author.id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
delete_node (a_id: INTEGER_64)
|
||||
-- Remove node by id `a_id'.
|
||||
require
|
||||
valid_node_id: a_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
update_node (a_node: CMS_NODE)
|
||||
-- Update node content `a_node'.
|
||||
-- The user `a_id' is an existing or new collaborator.
|
||||
require
|
||||
has_id: a_node.has_id
|
||||
has_author: attached a_node.author as l_author and then l_author.has_id
|
||||
deferred
|
||||
end
|
||||
|
||||
update_node_title (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_title: READABLE_STRING_32)
|
||||
-- Update node title to `a_title', node identified by id `a_node_id'.
|
||||
-- The user `a_id' is an existing or new collaborator.
|
||||
require
|
||||
valid_node_id: a_node_id > 0
|
||||
valid_user_id: a_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
update_node_summary (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_summary: READABLE_STRING_32)
|
||||
-- Update node summary to `a_summary', node identified by id `a_node_id'.
|
||||
-- The user `a_id' is an existing or new collaborator.
|
||||
require
|
||||
valid_id: a_node_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
update_node_content (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_content: READABLE_STRING_32)
|
||||
-- Update node content to `a_content', node identified by id `a_node_id'.
|
||||
-- The user `a_id' is an existing or new collaborator.
|
||||
require
|
||||
valid_id: a_node_id > 0
|
||||
valid_user_id: a_id > 0
|
||||
deferred
|
||||
end
|
||||
|
||||
end
|
||||
342
library/src/persistence/node/cms_node_storage_sql.e
Normal file
342
library/src/persistence/node/cms_node_storage_sql.e
Normal file
@@ -0,0 +1,342 @@
|
||||
note
|
||||
description: "Summary description for {CMS_NODE_STORAGE_SQL}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_NODE_STORAGE_SQL
|
||||
|
||||
inherit
|
||||
CMS_NODE_STORAGE
|
||||
|
||||
CMS_STORAGE_SQL
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
SHARED_LOGGER
|
||||
|
||||
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]
|
||||
-- List of nodes.
|
||||
do
|
||||
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
|
||||
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".nodes")
|
||||
|
||||
from
|
||||
sql_query (select_nodes, Void)
|
||||
sql_post_execution
|
||||
sql_start
|
||||
until
|
||||
sql_after
|
||||
loop
|
||||
if attached fetch_node as l_node then
|
||||
Result.force (l_node)
|
||||
end
|
||||
sql_forth
|
||||
end
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
|
||||
-- List of recent `a_count' nodes with an offset of `lower'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
|
||||
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".nodes")
|
||||
|
||||
from
|
||||
create l_parameters.make (2)
|
||||
l_parameters.put (a_count, "rows")
|
||||
l_parameters.put (a_lower, "offset")
|
||||
sql_query (select_recent_nodes, l_parameters)
|
||||
sql_post_execution
|
||||
sql_start
|
||||
until
|
||||
sql_after
|
||||
loop
|
||||
if attached fetch_node as l_node then
|
||||
Result.force (l_node)
|
||||
end
|
||||
sql_forth
|
||||
end
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
node (a_id: INTEGER_64): detachable CMS_NODE
|
||||
-- Retrieve node by id `a_id', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".node")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id,"id")
|
||||
sql_query (select_node_by_id, l_parameters)
|
||||
if sql_rows_count = 1 then
|
||||
Result := fetch_node
|
||||
end
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
node_author (a_id: like {CMS_NODE}.id): detachable CMS_USER
|
||||
-- Node's author for the given node id.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".node_author")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id, "node_id")
|
||||
sql_query (select_node_author, l_parameters)
|
||||
if sql_rows_count >= 1 then
|
||||
Result := fetch_author
|
||||
end
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
last_inserted_node_id: INTEGER_64
|
||||
-- Last insert node id.
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".last_inserted_node_id")
|
||||
sql_query (Sql_last_insert_node_id, Void)
|
||||
if sql_rows_count = 1 then
|
||||
Result := sql_read_integer_64 (1)
|
||||
end
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
feature -- Change: Node
|
||||
|
||||
new_node (a_node: CMS_NODE)
|
||||
-- Save node `a_node'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
-- New node
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".new_node")
|
||||
create l_parameters.make (7)
|
||||
l_parameters.put (a_node.title, "title")
|
||||
l_parameters.put (a_node.summary, "summary")
|
||||
l_parameters.put (a_node.content, "content")
|
||||
l_parameters.put (a_node.publication_date, "publish")
|
||||
l_parameters.put (a_node.creation_date, "created")
|
||||
l_parameters.put (a_node.modification_date, "changed")
|
||||
if
|
||||
attached a_node.author as l_author and then
|
||||
l_author.id > 0
|
||||
then
|
||||
l_parameters.put (l_author.id, "author")
|
||||
else
|
||||
l_parameters.put (0, "author")
|
||||
end
|
||||
sql_change (sql_insert_node, l_parameters)
|
||||
sql_post_execution
|
||||
if not error_handler.has_error then
|
||||
a_node.set_id (last_inserted_node_id)
|
||||
sql_post_execution
|
||||
end
|
||||
end
|
||||
|
||||
delete_node (a_id: INTEGER_64)
|
||||
-- Remove node by id `a_id'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
log.write_information (generator + ".delete_node")
|
||||
|
||||
error_handler.reset
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id, "id")
|
||||
sql_change (sql_delete_node, l_parameters)
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
update_node (a_node: CMS_NODE)
|
||||
-- Update node content `a_node'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
now: DATE_TIME
|
||||
do
|
||||
create now.make_now_utc
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".update_node")
|
||||
create l_parameters.make (7)
|
||||
l_parameters.put (a_node.title, "title")
|
||||
l_parameters.put (a_node.summary, "summary")
|
||||
l_parameters.put (a_node.content, "content")
|
||||
l_parameters.put (a_node.publication_date, "publish")
|
||||
l_parameters.put (now, "changed")
|
||||
l_parameters.put (a_node.id, "id")
|
||||
if attached a_node.author as l_author then
|
||||
l_parameters.put (l_author.id, "author")
|
||||
else
|
||||
l_parameters.put (0, "author")
|
||||
end
|
||||
sql_change (sql_update_node, l_parameters)
|
||||
sql_post_execution
|
||||
if not error_handler.has_error then
|
||||
a_node.set_modification_date (now)
|
||||
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 to `a_title', node identified by id `a_node_id'.
|
||||
-- The user `a_user_id' is an existing or new collaborator.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
-- FIXME: unused a_user_id !
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".update_node_title")
|
||||
create l_parameters.make (3)
|
||||
l_parameters.put (a_title, "title")
|
||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "changed")
|
||||
l_parameters.put (a_node_id, "nid")
|
||||
sql_change (sql_update_node_title, l_parameters)
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
update_node_summary (a_user_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_summary: READABLE_STRING_32)
|
||||
-- Update node summary to `a_summary', node identified by id `a_node_id'.
|
||||
-- The user `a_user_id' is an existing or new collaborator.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
-- FIXME: unused a_user_id !
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".update_node_summary")
|
||||
create l_parameters.make (3)
|
||||
l_parameters.put (a_summary, "summary")
|
||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "changed")
|
||||
l_parameters.put (a_node_id, "nid")
|
||||
sql_change (sql_update_node_summary, l_parameters)
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
update_node_content (a_user_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_content: READABLE_STRING_32)
|
||||
-- Update node content to `a_content', node identified by id `a_node_id'.
|
||||
-- The user `a_user_id' is an existing or new collaborator.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
-- FIXME: unused a_user_id !
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".update_node_content")
|
||||
create l_parameters.make (3)
|
||||
l_parameters.put (a_content, "content")
|
||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "changed")
|
||||
l_parameters.put (a_node_id, "nid")
|
||||
sql_change (sql_update_node_content, l_parameters)
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
feature {NONE} -- Queries
|
||||
|
||||
Select_nodes_count: STRING = "select count(*) from Nodes;"
|
||||
|
||||
Select_nodes: STRING = "select * from Nodes;"
|
||||
-- SQL Query to retrieve all nodes.
|
||||
|
||||
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 nid desc, publish desc LIMIT :rows OFFSET :offset ;"
|
||||
|
||||
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_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 node.
|
||||
|
||||
SQL_Delete_node: STRING = "delete from nodes where nid=:nid;"
|
||||
|
||||
Sql_update_node_author: STRING = "update nodes SET author=:author where nid=:nid;"
|
||||
|
||||
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
|
||||
|
||||
Select_user_author: STRING = "SELECT * FROM Nodes INNER JOIN users ON nodes.author=users.uid and users.uid = :uid;"
|
||||
|
||||
Select_node_author: STRING = "SELECT * FROM Users INNER JOIN nodes ON nodes.author=users.uid and nodes.nid =:nid;"
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
fetch_node: CMS_NODE
|
||||
do
|
||||
create Result.make ("", "", "")
|
||||
if attached sql_read_integer_64 (1) as l_id then
|
||||
Result.set_id (l_id)
|
||||
end
|
||||
if attached sql_read_string_32 (4) as l_title then
|
||||
Result.set_title (l_title)
|
||||
end
|
||||
if attached sql_read_string_32 (5) as l_summary then
|
||||
Result.set_summary (l_summary)
|
||||
end
|
||||
if attached sql_read_string (6) as l_content then
|
||||
Result.set_content (l_content)
|
||||
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
|
||||
|
||||
fetch_author: detachable CMS_USER
|
||||
do
|
||||
if attached sql_read_string_32 (2) as l_name and then not l_name.is_whitespace then
|
||||
create Result.make (l_name)
|
||||
if attached sql_read_integer_32 (1) as l_id then
|
||||
Result.set_id (l_id)
|
||||
end
|
||||
if attached sql_read_string (3) as l_password then
|
||||
-- FIXME: should we return the password here ???
|
||||
Result.set_hashed_password (l_password)
|
||||
end
|
||||
if attached sql_read_string (5) as l_email then
|
||||
Result.set_email (l_email)
|
||||
end
|
||||
else
|
||||
check expected_valid_user: False end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
129
library/src/persistence/user/cms_user_storage.e
Normal file
129
library/src/persistence/user/cms_user_storage.e
Normal file
@@ -0,0 +1,129 @@
|
||||
note
|
||||
description: "Summary description for {CMS_USER_STORAGE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_USER_STORAGE
|
||||
|
||||
inherit
|
||||
SHARED_LOGGER
|
||||
|
||||
feature -- Error Handling
|
||||
|
||||
error_handler: ERROR_HANDLER
|
||||
-- Error handler.
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
has_user: BOOLEAN
|
||||
-- Has any user?
|
||||
deferred
|
||||
end
|
||||
|
||||
users: LIST [CMS_USER]
|
||||
-- List of users.
|
||||
deferred
|
||||
end
|
||||
|
||||
user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER
|
||||
-- User with id `a_id', if any.
|
||||
require
|
||||
a_id > 0
|
||||
deferred
|
||||
ensure
|
||||
same_id: Result /= Void implies Result.id = a_id
|
||||
password: Result /= Void implies (Result.hashed_password /= Void and Result.password = Void)
|
||||
end
|
||||
|
||||
user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER
|
||||
-- User with name `a_name', if any.
|
||||
require
|
||||
a_name /= Void and then not a_name.is_empty
|
||||
deferred
|
||||
ensure
|
||||
same_name: Result /= Void implies a_name ~ Result.name
|
||||
password: Result /= Void implies (Result.hashed_password /= Void and Result.password = Void)
|
||||
end
|
||||
|
||||
user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER
|
||||
-- User with name `a_email', if any.
|
||||
deferred
|
||||
ensure
|
||||
same_email: Result /= Void implies a_email ~ Result.email
|
||||
password: Result /= Void implies (Result.hashed_password /= Void and Result.password = Void)
|
||||
end
|
||||
|
||||
is_valid_credential (a_u, a_p: READABLE_STRING_32): BOOLEAN
|
||||
-- Does account with username `a_username' and password `a_password' exist?
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Change: 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'.
|
||||
require
|
||||
has_id: a_user.has_id
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Access: roles and permissions
|
||||
|
||||
user_has_permission (u: detachable CMS_USER; s: detachable READABLE_STRING_8): BOOLEAN
|
||||
-- Anonymous or user `u' has permission for `s' ?
|
||||
--| `s' could be "create page",
|
||||
do
|
||||
-- if s = Void then
|
||||
-- Result := True
|
||||
-- elseif u = Void then
|
||||
---- Result := user_role_has_permission (anonymous_user_role, s)
|
||||
-- else
|
||||
-- Result := user_role_has_permission (authenticated_user_role, s)
|
||||
-- if not Result and attached u.roles as l_roles then
|
||||
-- across
|
||||
-- l_roles as r
|
||||
-- until
|
||||
-- Result
|
||||
-- loop
|
||||
-- if attached user_role_by_id (r.item) as ur then
|
||||
-- Result := user_role_has_permission (ur, s)
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
end
|
||||
|
||||
user_role_has_permission (a_role: CMS_USER_ROLE; s: READABLE_STRING_8): BOOLEAN
|
||||
do
|
||||
Result := a_role.has_permission (s)
|
||||
end
|
||||
|
||||
user_role_by_id (a_id: like {CMS_USER_ROLE}.id): detachable CMS_USER_ROLE
|
||||
-- User role by id `a_id', if any.
|
||||
deferred
|
||||
end
|
||||
|
||||
user_roles: LIST [CMS_USER_ROLE]
|
||||
-- Possible list of user roles.
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Change: roles and permissions
|
||||
|
||||
save_user_role (a_user_role: CMS_USER_ROLE)
|
||||
-- Save user role `a_user_role'
|
||||
deferred
|
||||
end
|
||||
|
||||
end
|
||||
332
library/src/persistence/user/cms_user_storage_sql.e
Normal file
332
library/src/persistence/user/cms_user_storage_sql.e
Normal file
@@ -0,0 +1,332 @@
|
||||
note
|
||||
description: "Summary description for {CMS_USER_STORAGE_SQL}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_USER_STORAGE_SQL
|
||||
|
||||
inherit
|
||||
CMS_USER_STORAGE
|
||||
|
||||
CMS_STORAGE_SQL
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
SHARED_LOGGER
|
||||
|
||||
feature -- Access: user
|
||||
|
||||
has_user: BOOLEAN
|
||||
-- Has any user?
|
||||
do
|
||||
Result := user_count > 0
|
||||
end
|
||||
|
||||
user_count: INTEGER
|
||||
-- Number of items users.
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".user_count")
|
||||
|
||||
sql_query (select_users_count, Void)
|
||||
if sql_rows_count = 1 then
|
||||
Result := sql_read_integer_32 (1)
|
||||
end
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
users: LIST [CMS_USER]
|
||||
do
|
||||
create {ARRAYED_LIST [CMS_USER]} Result.make (0)
|
||||
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".all_users")
|
||||
|
||||
from
|
||||
sql_query (select_users, Void)
|
||||
sql_post_execution
|
||||
sql_start
|
||||
until
|
||||
sql_after
|
||||
loop
|
||||
if attached fetch_user as l_user then
|
||||
Result.force (l_user)
|
||||
end
|
||||
sql_forth
|
||||
end
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER
|
||||
-- User for the given id `a_id', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".user")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id, "uid")
|
||||
sql_query (select_user_by_id, l_parameters)
|
||||
if sql_rows_count = 1 then
|
||||
Result := fetch_user
|
||||
else
|
||||
check no_more_than_one: sql_rows_count = 0 end
|
||||
end
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER
|
||||
-- User for the given name `a_name', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".user_by_name")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_name, "name")
|
||||
sql_query (select_user_by_name, l_parameters)
|
||||
if sql_rows_count = 1 then
|
||||
Result := fetch_user
|
||||
else
|
||||
check no_more_than_one: sql_rows_count = 0 end
|
||||
end
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER
|
||||
-- User for the given email `a_email', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".user_by_email")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_email, "email")
|
||||
sql_query (select_user_by_email, l_parameters)
|
||||
if sql_rows_count = 1 then
|
||||
Result := fetch_user
|
||||
else
|
||||
check no_more_than_one: sql_rows_count = 0 end
|
||||
end
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
is_valid_credential (l_auth_login, l_auth_password: READABLE_STRING_32): BOOLEAN
|
||||
local
|
||||
l_security: SECURITY_PROVIDER
|
||||
do
|
||||
if attached user_salt (l_auth_login) as l_hash then
|
||||
if attached user_by_name (l_auth_login) as l_user then
|
||||
create l_security
|
||||
if
|
||||
attached l_user.hashed_password as l_hashed_password and then
|
||||
l_security.password_hash (l_auth_password, l_hash).is_case_insensitive_equal (l_hashed_password)
|
||||
then
|
||||
Result := True
|
||||
else
|
||||
log.write_information (generator + ".is_valid_credential User: wrong username or password" )
|
||||
end
|
||||
else
|
||||
log.write_information (generator + ".is_valid_credential User:" + l_auth_login + "does not exist" )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
feature -- Change: user
|
||||
|
||||
new_user (a_user: CMS_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
|
||||
if
|
||||
attached a_user.password as l_password and then
|
||||
attached a_user.email as l_email
|
||||
then
|
||||
sql_begin_transaction
|
||||
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
|
||||
else
|
||||
-- set error
|
||||
error_handler.add_custom_error (-1, "bad request" , "Missing password or email")
|
||||
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
|
||||
|
||||
feature -- Access: roles and permissions
|
||||
|
||||
user_role_by_id (a_id: like {CMS_USER_ROLE}.id): detachable CMS_USER_ROLE
|
||||
do
|
||||
to_implement (generator + ".user_role_by_id")
|
||||
end
|
||||
|
||||
user_roles: LIST [CMS_USER_ROLE]
|
||||
do
|
||||
to_implement (generator + ".user_roles")
|
||||
create {ARRAYED_LIST[CMS_USER_ROLE]} Result.make (0)
|
||||
end
|
||||
|
||||
feature -- Change: roles and permissions
|
||||
|
||||
save_user_role (a_user_role: CMS_USER_ROLE)
|
||||
do
|
||||
to_implement (generator + ".save_user_role")
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
user_salt (a_username: READABLE_STRING_32): detachable READABLE_STRING_8
|
||||
-- User salt for the given user `a_username', if any.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".user_salt")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_username, "name")
|
||||
sql_query (select_salt_by_username, l_parameters)
|
||||
if sql_rows_count = 1 then
|
||||
if attached sql_read_string (1) as l_salt then
|
||||
Result := l_salt
|
||||
end
|
||||
end
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
fetch_user: detachable CMS_USER
|
||||
local
|
||||
l_id: INTEGER_64
|
||||
l_name: detachable READABLE_STRING_32
|
||||
do
|
||||
if attached sql_read_integer_32 (1) as i then
|
||||
l_id := i
|
||||
end
|
||||
if attached sql_read_string_32 (2) as s and then not s.is_whitespace then
|
||||
l_name := s
|
||||
end
|
||||
|
||||
if l_name /= Void then
|
||||
create Result.make (l_name)
|
||||
if l_id > 0 then
|
||||
Result.set_id (l_id)
|
||||
end
|
||||
elseif l_id > 0 then
|
||||
create Result.make_with_id (l_id)
|
||||
end
|
||||
|
||||
if Result /= Void then
|
||||
if attached sql_read_string (3) as l_password then
|
||||
-- FIXME: should we return the password here ???
|
||||
Result.set_hashed_password (l_password)
|
||||
end
|
||||
if attached sql_read_string (5) as l_email then
|
||||
Result.set_email (l_email)
|
||||
end
|
||||
else
|
||||
check expected_valid_user: False end
|
||||
end
|
||||
end
|
||||
|
||||
last_inserted_user_id: INTEGER_64
|
||||
-- Last insert user id.
|
||||
do
|
||||
error_handler.reset
|
||||
log.write_information (generator + ".last_inserted_user_id")
|
||||
sql_query (Sql_last_insert_user_id, Void)
|
||||
if sql_rows_count = 1 then
|
||||
Result := sql_read_integer_64 (1)
|
||||
end
|
||||
sql_post_execution
|
||||
end
|
||||
|
||||
feature {NONE} -- Sql Queries: USER
|
||||
|
||||
Select_users_count: STRING = "select count(*) from Users;"
|
||||
-- Number of users.
|
||||
|
||||
Sql_last_insert_user_id: STRING = "SELECT MAX(uid) from Users;"
|
||||
|
||||
Select_users: STRING = "select * from Users;"
|
||||
-- List of users.
|
||||
|
||||
Select_user_by_id: STRING = "select * from Users where uid =:uid;"
|
||||
-- Retrieve user by id if exists.
|
||||
|
||||
Select_user_by_name: STRING = "select * from Users where name =:name;"
|
||||
-- Retrieve user by name if exists.
|
||||
|
||||
Select_user_by_email: STRING = "select * from Users where email =:email;"
|
||||
-- Retrieve user by email if exists.
|
||||
|
||||
Select_salt_by_username: STRING = "select salt from Users where name =:name;"
|
||||
-- Retrieve salt by username if exists.
|
||||
|
||||
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_update_user: STRING = "update users SET name=:name, password=:password, salt=:salt, email=:email WHERE uid=:uid;"
|
||||
|
||||
|
||||
end
|
||||
@@ -34,10 +34,16 @@ feature -- Access
|
||||
Result.keep_head (Result.count - 2)
|
||||
end
|
||||
|
||||
password_hash (a_password, a_salt: STRING): STRING
|
||||
password_hash (a_password: READABLE_STRING_GENERAL; a_salt: STRING): STRING
|
||||
-- Password hash based on password `a_password' and salt value `a_salt'.
|
||||
local
|
||||
utf: UTF_CONVERTER
|
||||
s: STRING
|
||||
do
|
||||
Result := sha1_string (a_password + a_salt )
|
||||
create s.make (a_password.count + a_salt.count)
|
||||
utf.utf_32_string_into_utf_8_string_8 (a_password, s)
|
||||
s.append (a_salt)
|
||||
Result := sha1_string (s)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
@@ -7,9 +7,20 @@ class
|
||||
CMS_API
|
||||
|
||||
inherit
|
||||
ANY
|
||||
|
||||
REFACTORING_HELPER
|
||||
|
||||
SHARED_HTML_ENCODER
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
SHARED_WSF_PERCENT_ENCODER
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
@@ -31,46 +42,13 @@ feature -- Initialize
|
||||
|
||||
initialize
|
||||
-- Initialize the persitent layer.
|
||||
local
|
||||
l_database: DATABASE_CONNECTION
|
||||
retried: BOOLEAN
|
||||
l_message: STRING
|
||||
do
|
||||
if not retried then
|
||||
to_implement ("Refactor database setup")
|
||||
if attached (create {APPLICATION_JSON_CONFIGURATION_HELPER}).new_database_configuration (setup.layout.application_config_path) as l_database_config then
|
||||
create {DATABASE_CONNECTION_MYSQL} l_database.login_with_connection_string (l_database_config.connection_string)
|
||||
create {CMS_STORAGE_MYSQL} storage.make (l_database)
|
||||
else
|
||||
create {DATABASE_CONNECTION_NULL} l_database.make_common
|
||||
create {CMS_STORAGE_NULL} storage
|
||||
end
|
||||
to_implement ("Refactor database setup")
|
||||
if attached setup.storage (error_handler) as l_storage then
|
||||
storage := l_storage
|
||||
else
|
||||
to_implement ("Workaround code, persistence layer does not implement yet this kind of error handling.")
|
||||
-- error hanling.
|
||||
create {DATABASE_CONNECTION_NULL} l_database.make_common
|
||||
create {CMS_STORAGE_NULL} storage
|
||||
create l_message.make (1024)
|
||||
if attached ((create {EXCEPTION_MANAGER}).last_exception) as l_exception then
|
||||
if attached l_exception.description as l_description then
|
||||
l_message.append (l_description.as_string_32)
|
||||
l_message.append ("%N%N")
|
||||
elseif attached l_exception.trace as l_trace then
|
||||
l_message.append (l_trace)
|
||||
l_message.append ("%N%N")
|
||||
else
|
||||
l_message.append (l_exception.out)
|
||||
l_message.append ("%N%N")
|
||||
end
|
||||
else
|
||||
l_message.append ("The application crash without available information")
|
||||
l_message.append ("%N%N")
|
||||
end
|
||||
error_handler.add_custom_error (0, " Database Connection ", l_message)
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
|
||||
feature -- Access: Error
|
||||
@@ -110,16 +88,18 @@ feature -- Status Report
|
||||
|
||||
feature -- Access: Node
|
||||
|
||||
nodes: LIST[CMS_NODE]
|
||||
-- List of nodes.
|
||||
nodes_count: INTEGER_64
|
||||
do
|
||||
debug ("refactor_fixme")
|
||||
fixme ("Implementation")
|
||||
end
|
||||
Result := storage.recent_nodes (0, 10)
|
||||
Result := storage.nodes_count
|
||||
end
|
||||
|
||||
recent_nodes (a_offset, a_rows: INTEGER): LIST[CMS_NODE]
|
||||
nodes: LIST [CMS_NODE]
|
||||
-- List of nodes.
|
||||
do
|
||||
Result := storage.nodes
|
||||
end
|
||||
|
||||
recent_nodes (a_offset, a_rows: INTEGER): LIST [CMS_NODE]
|
||||
-- List of the `a_rows' most recent nodes starting from `a_offset'.
|
||||
do
|
||||
Result := storage.recent_nodes (a_offset, a_rows)
|
||||
@@ -138,8 +118,10 @@ feature -- Change: Node
|
||||
|
||||
new_node (a_node: CMS_NODE)
|
||||
-- Add a new node `a_node'
|
||||
require
|
||||
no_id: not a_node.has_id
|
||||
do
|
||||
storage.save_node (a_node)
|
||||
storage.new_node (a_node)
|
||||
end
|
||||
|
||||
delete_node (a_id: INTEGER_64)
|
||||
@@ -148,37 +130,37 @@ feature -- Change: Node
|
||||
storage.delete_node (a_id)
|
||||
end
|
||||
|
||||
update_node (a_id: like {CMS_USER}.id; a_node: CMS_NODE)
|
||||
-- Update node by id `a_id' with `a_node' data.
|
||||
update_node (a_node: CMS_NODE)
|
||||
-- Update node `a_node' data.
|
||||
do
|
||||
storage.update_node (a_id,a_node)
|
||||
storage.update_node (a_node)
|
||||
end
|
||||
|
||||
update_node_title (a_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)
|
||||
-- Update node title, with user identified by `a_id', with node id `a_node_id' and a new title `a_title'.
|
||||
do
|
||||
debug ("refactor_fixme")
|
||||
fixme ("Check preconditions")
|
||||
end
|
||||
storage.update_node_title (a_id,a_node_id,a_title)
|
||||
storage.update_node_title (a_user_id, a_node_id, a_title)
|
||||
end
|
||||
|
||||
update_node_summary (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_summary: READABLE_STRING_32)
|
||||
-- Update node summary, with user identified by `a_id', with node id `a_node_id' and a new summary `a_summary'.
|
||||
update_node_summary (a_user_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_summary: READABLE_STRING_32)
|
||||
-- Update node summary, with user identified by `a_user_id', with node id `a_node_id' and a new summary `a_summary'.
|
||||
do
|
||||
debug ("refactor_fixme")
|
||||
fixme ("Check preconditions")
|
||||
end
|
||||
storage.update_node_summary (a_id,a_node_id, a_summary)
|
||||
storage.update_node_summary (a_user_id, a_node_id, a_summary)
|
||||
end
|
||||
|
||||
update_node_content (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_content: READABLE_STRING_32)
|
||||
-- Update node content, with user identified by `a_id', with node id `a_node_id' and a new content `a_content'.
|
||||
update_node_content (a_user_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_content: READABLE_STRING_32)
|
||||
-- Update node content, with user identified by `a_user_id', with node id `a_node_id' and a new content `a_content'.
|
||||
do
|
||||
debug ("refactor_fixme")
|
||||
fixme ("Check preconditions")
|
||||
end
|
||||
storage.update_node_content (a_id,a_node_id, a_content)
|
||||
storage.update_node_content (a_user_id, a_node_id, a_content)
|
||||
end
|
||||
|
||||
|
||||
@@ -194,12 +176,15 @@ feature -- Change User
|
||||
|
||||
new_user (a_user: CMS_USER)
|
||||
-- Add a new user `a_user'.
|
||||
require
|
||||
no_id: not a_user.has_id
|
||||
no_hashed_password: a_user.hashed_password = Void
|
||||
do
|
||||
if
|
||||
attached a_user.password as l_password and then
|
||||
attached a_user.email as l_email
|
||||
then
|
||||
storage.save_user (a_user)
|
||||
storage.new_user (a_user)
|
||||
else
|
||||
debug ("refactor_fixme")
|
||||
fixme ("Add error")
|
||||
@@ -207,6 +192,28 @@ feature -- Change User
|
||||
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
|
||||
|
||||
html_encoded (a_string: READABLE_STRING_GENERAL): STRING_8
|
||||
-- `a_string' encoded for html output.
|
||||
do
|
||||
Result := html_encoder.general_encoded_string (a_string)
|
||||
end
|
||||
|
||||
percent_encoded (a_string: READABLE_STRING_GENERAL): STRING_8
|
||||
-- `a_string' encoded with percent encoding, mainly used for url.
|
||||
do
|
||||
Result := percent_encoder.percent_encoded_string (a_string)
|
||||
end
|
||||
|
||||
feature -- Layout
|
||||
|
||||
module_configuration (a_module_name: READABLE_STRING_GENERAL; a_name: detachable READABLE_STRING_GENERAL): detachable CONFIG_READER
|
||||
|
||||
@@ -32,7 +32,9 @@ feature -- Execution
|
||||
do
|
||||
set_title ("Not Implemented")
|
||||
set_page_title (Void)
|
||||
set_main_content (request.percent_encoded_path_info + " is not implemented!")
|
||||
if main_content = Void then
|
||||
set_main_content (request.percent_encoded_path_info + " is not implemented!")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user