From bba0364a2c7d8f818f0375a251b09a20b5d77fba Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Wed, 21 Jan 2015 12:02:36 +0100 Subject: [PATCH] Refactored persistence with mysql and sqlite to factorize more things with a CMS_STORAGE_SQL .. based only on sql statement execution. Various changes --- examples/demo/demo-safe.ecf | 1 + .../config/application_configuration.json | 11 +- examples/demo/site/config/cms.ini | 2 +- examples/demo/src/ewf_roc_server.e | 1 + .../application_json_configuration_helper.e | 2 +- .../configuration/database_configuration.e | 59 +- library/layout/src/logger/shared_logger.e | 27 +- library/model/src/content/cms_node.e | 28 +- library/model/src/user/cms_user.e | 44 +- .../common/database/database_handler.e | 10 +- .../common/database/database_query.e | 66 ++- .../database/database_sql_server_encoder.e | 3 +- .../common/database/error/database_error.e | 4 +- .../database/error/database_error_handler.e | 4 +- .../database/error/database_no_change_error.e | 4 +- .../implementation/common/string_helper.e | 53 -- .../mysql/src/cms_node_storage_mysql.e | 75 +++ .../mysql/src/cms_storage_mysql.e | 312 +++-------- .../mysql/src/cms_user_storage_mysql.e | 14 + .../mysql/src/provider/node_data_provider.e | 511 ------------------ .../mysql/src/provider/role_data_provider.e | 216 -------- .../mysql/src/provider/user_data_provider.e | 337 ------------ .../sqlite/persistence_sqlite-safe.ecf | 2 +- .../sqlite/src/cms_node_storage_sqlite.e | 14 + .../sqlite/src/cms_storage_sqlite.e | 274 +++------- .../sqlite/src/cms_storage_sqlite_builder.e | 43 ++ .../sqlite/src/cms_user_storage_sqlite.e | 14 + .../sqlite/src/provider/node_data_provider.e | 275 ---------- .../sqlite/src/provider/user_data_provider.e | 193 ------- .../sqlite/tests/storage/storage_test_set.e | 1 + .../sqlite/tests/tests-safe.ecf | 1 + .../sqlite/tests/util/abstract_db_test.e | 4 +- library/src/modules/node/node_module.e | 23 +- library/src/persistence/cms_storage.e | 226 +------- library/src/persistence/cms_storage_null.e | 2 +- library/src/persistence/cms_storage_sql.e | 153 ++++++ .../src/persistence/node/cms_node_storage.e | 97 ++++ .../persistence/node/cms_node_storage_sql.e | 341 ++++++++++++ .../src/persistence/user/cms_user_storage.e | 120 ++++ .../persistence/user/cms_user_storage_sql.e | 285 ++++++++++ .../security/security_provider.e | 10 +- library/src/service/cms_api.e | 29 +- .../not_implemented_error_cms_response.e | 4 +- 43 files changed, 1545 insertions(+), 2350 deletions(-) delete mode 100644 library/persistence/implementation/common/string_helper.e create mode 100644 library/persistence/implementation/mysql/src/cms_node_storage_mysql.e create mode 100644 library/persistence/implementation/mysql/src/cms_user_storage_mysql.e delete mode 100644 library/persistence/implementation/mysql/src/provider/node_data_provider.e delete mode 100644 library/persistence/implementation/mysql/src/provider/role_data_provider.e delete mode 100644 library/persistence/implementation/mysql/src/provider/user_data_provider.e create mode 100644 library/persistence/implementation/sqlite/src/cms_node_storage_sqlite.e create mode 100644 library/persistence/implementation/sqlite/src/cms_storage_sqlite_builder.e create mode 100644 library/persistence/implementation/sqlite/src/cms_user_storage_sqlite.e delete mode 100644 library/persistence/implementation/sqlite/src/provider/node_data_provider.e delete mode 100644 library/persistence/implementation/sqlite/src/provider/user_data_provider.e create mode 100644 library/src/persistence/cms_storage_sql.e create mode 100644 library/src/persistence/node/cms_node_storage.e create mode 100644 library/src/persistence/node/cms_node_storage_sql.e create mode 100644 library/src/persistence/user/cms_user_storage.e create mode 100644 library/src/persistence/user/cms_user_storage_sql.e rename library/{persistence/implementation/common => src}/security/security_provider.e (92%) diff --git a/examples/demo/demo-safe.ecf b/examples/demo/demo-safe.ecf index 19227ff..c0b2da1 100644 --- a/examples/demo/demo-safe.ecf +++ b/examples/demo/demo-safe.ecf @@ -13,6 +13,7 @@ + diff --git a/examples/demo/site/config/application_configuration.json b/examples/demo/site/config/application_configuration.json index 793f8ef..2022e57 100644 --- a/examples/demo/site/config/application_configuration.json +++ b/examples/demo/site/config/application_configuration.json @@ -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 @@ } - \ No newline at end of file + diff --git a/examples/demo/site/config/cms.ini b/examples/demo/site/config/cms.ini index f434169..5879f35 100644 --- a/examples/demo/site/config/cms.ini +++ b/examples/demo/site/config/cms.ini @@ -1,6 +1,6 @@ [layout] root-dir=site/www -themes-dir=site/themes +themes-dir=site/www/themes [site] name=Eiffel CMS diff --git a/examples/demo/src/ewf_roc_server.e b/examples/demo/src/ewf_roc_server.e index 7c47c72..38a3353 100644 --- a/examples/demo/src/ewf_roc_server.e +++ b/examples/demo/src/ewf_roc_server.e @@ -148,6 +148,7 @@ feature -- CMS setup 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 diff --git a/library/layout/src/configuration/application_json_configuration_helper.e b/library/layout/src/configuration/application_json_configuration_helper.e index 992e4bf..88259ee 100644 --- a/library/layout/src/configuration/application_json_configuration_helper.e +++ b/library/layout/src/configuration/application_json_configuration_helper.e @@ -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 diff --git a/library/layout/src/configuration/database_configuration.e b/library/layout/src/configuration/database_configuration.e index 028a5dd..1703c48 100644 --- a/library/layout/src/configuration/database_configuration.e +++ b/library/layout/src/configuration/database_configuration.e @@ -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 diff --git a/library/layout/src/logger/shared_logger.e b/library/layout/src/logger/shared_logger.e index ed0051e..73e6a05 100644 --- a/library/layout/src/logger/shared_logger.e +++ b/library/layout/src/logger/shared_logger.e @@ -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 diff --git a/library/model/src/content/cms_node.e b/library/model/src/content/cms_node.e index 13010bd..ae48876 100644 --- a/library/model/src/content/cms_node.e +++ b/library/model/src/content/cms_node.e @@ -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" diff --git a/library/model/src/user/cms_user.e b/library/model/src/user/cms_user.e index b50de8a..280b321 100644 --- a/library/model/src/user/cms_user.e +++ b/library/model/src/user/cms_user.e @@ -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)" diff --git a/library/persistence/implementation/common/database/database_handler.e b/library/persistence/implementation/common/database/database_handler.e index 02fdb7b..6f63641 100644 --- a/library/persistence/implementation/common/database/database_handler.e +++ b/library/persistence/implementation/common/database/database_handler.e @@ -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 diff --git a/library/persistence/implementation/common/database/database_query.e b/library/persistence/implementation/common/database/database_query.e index 25088b3..3e2d6c2 100644 --- a/library/persistence/implementation/common/database/database_query.e +++ b/library/persistence/implementation/common/database/database_query.e @@ -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 diff --git a/library/persistence/implementation/common/database/database_sql_server_encoder.e b/library/persistence/implementation/common/database/database_sql_server_encoder.e index c576ef9..dd19a2d 100644 --- a/library/persistence/implementation/common/database/database_sql_server_encoder.e +++ b/library/persistence/implementation/common/database/database_sql_server_encoder.e @@ -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 diff --git a/library/persistence/implementation/common/database/error/database_error.e b/library/persistence/implementation/common/database/error/database_error.e index 2dcd646..3f67be1 100644 --- a/library/persistence/implementation/common/database/error/database_error.e +++ b/library/persistence/implementation/common/database/error/database_error.e @@ -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 diff --git a/library/persistence/implementation/common/database/error/database_error_handler.e b/library/persistence/implementation/common/database/error/database_error_handler.e index 5af3545..ae49e6e 100644 --- a/library/persistence/implementation/common/database/error/database_error_handler.e +++ b/library/persistence/implementation/common/database/error/database_error_handler.e @@ -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 diff --git a/library/persistence/implementation/common/database/error/database_no_change_error.e b/library/persistence/implementation/common/database/error/database_no_change_error.e index 6855279..4fcc211 100644 --- a/library/persistence/implementation/common/database/error/database_no_change_error.e +++ b/library/persistence/implementation/common/database/error/database_no_change_error.e @@ -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 diff --git a/library/persistence/implementation/common/string_helper.e b/library/persistence/implementation/common/string_helper.e deleted file mode 100644 index f280e82..0000000 --- a/library/persistence/implementation/common/string_helper.e +++ /dev/null @@ -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 diff --git a/library/persistence/implementation/mysql/src/cms_node_storage_mysql.e b/library/persistence/implementation/mysql/src/cms_node_storage_mysql.e new file mode 100644 index 0000000..b6695e5 --- /dev/null +++ b/library/persistence/implementation/mysql/src/cms_node_storage_mysql.e @@ -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 diff --git a/library/persistence/implementation/mysql/src/cms_storage_mysql.e b/library/persistence/implementation/mysql/src/cms_storage_mysql.e index cc81d6c..6489ebf 100644 --- a/library/persistence/implementation/mysql/src/cms_storage_mysql.e +++ b/library/persistence/implementation/mysql/src/cms_storage_mysql.e @@ -9,6 +9,11 @@ class inherit CMS_STORAGE + + CMS_USER_STORAGE_MYSQL + + CMS_NODE_STORAGE_MYSQL + REFACTORING_HELPER create @@ -22,249 +27,76 @@ feature {NONE} -- Initialization 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) + 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 end - -feature -- Access: user - - has_user: BOOLEAN - -- Has any user? - do - Result := user_provider.has_user - end - - all_users: LIST [CMS_USER] - do - to_implement (generator + ".all_users") - create {ARRAYED_LIST[CMS_USER]} Result.make (0) - end - - user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER - do - Result := user_provider.user (a_id) - - end - - user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER - do - Result := user_provider.user_by_name (a_name) - - end - - user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER - do - Result := user_provider.user_by_email (a_email) - - 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 - - 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 - to_implement (generator + ".user_collaborator_nodes") - create {ARRAYED_LIST[CMS_NODE]} Result.make (0) - 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 - -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 - -- - do - Result := node_provider.node (a_id) - - end - - node_author (a_id: like {CMS_NODE}.id): detachable CMS_USER - -- - 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) - -- - 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) - -- - 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) - -- - 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) - -- - 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) - -- - 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. + db_handler: DATABASE_HANDLER connection: DATABASE_CONNECTION - -- Current database connection. + -- Current database connection. + +feature -- Query + + sql_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 + + 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 + db_handler.set_query (create {DATABASE_QUERY}.data_reader (a_sql_statement, Void)) + db_handler.execute_query + end + + sql_change (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY]) + do + db_handler.set_query (create {DATABASE_QUERY}.data_reader (a_sql_statement, Void)) + db_handler.execute_change + end + + sql_rows_count: INTEGER + -- Number of rows for last sql execution. + do + Result := db_handler.count + 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 diff --git a/library/persistence/implementation/mysql/src/cms_user_storage_mysql.e b/library/persistence/implementation/mysql/src/cms_user_storage_mysql.e new file mode 100644 index 0000000..18d4fa9 --- /dev/null +++ b/library/persistence/implementation/mysql/src/cms_user_storage_mysql.e @@ -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 diff --git a/library/persistence/implementation/mysql/src/provider/node_data_provider.e b/library/persistence/implementation/mysql/src/provider/node_data_provider.e deleted file mode 100644 index 5951cc5..0000000 --- a/library/persistence/implementation/mysql/src/provider/node_data_provider.e +++ /dev/null @@ -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 diff --git a/library/persistence/implementation/mysql/src/provider/role_data_provider.e b/library/persistence/implementation/mysql/src/provider/role_data_provider.e deleted file mode 100644 index 8e82a64..0000000 --- a/library/persistence/implementation/mysql/src/provider/role_data_provider.e +++ /dev/null @@ -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 diff --git a/library/persistence/implementation/mysql/src/provider/user_data_provider.e b/library/persistence/implementation/mysql/src/provider/user_data_provider.e deleted file mode 100644 index 488d39a..0000000 --- a/library/persistence/implementation/mysql/src/provider/user_data_provider.e +++ /dev/null @@ -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 diff --git a/library/persistence/implementation/sqlite/persistence_sqlite-safe.ecf b/library/persistence/implementation/sqlite/persistence_sqlite-safe.ecf index 3899c9d..abe11ca 100644 --- a/library/persistence/implementation/sqlite/persistence_sqlite-safe.ecf +++ b/library/persistence/implementation/sqlite/persistence_sqlite-safe.ecf @@ -7,6 +7,7 @@ + @@ -19,7 +20,6 @@ - /EIFGENs$ diff --git a/library/persistence/implementation/sqlite/src/cms_node_storage_sqlite.e b/library/persistence/implementation/sqlite/src/cms_node_storage_sqlite.e new file mode 100644 index 0000000..6cafa70 --- /dev/null +++ b/library/persistence/implementation/sqlite/src/cms_node_storage_sqlite.e @@ -0,0 +1,14 @@ +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 + + +end diff --git a/library/persistence/implementation/sqlite/src/cms_storage_sqlite.e b/library/persistence/implementation/sqlite/src/cms_storage_sqlite.e index f463110..1dacee9 100644 --- a/library/persistence/implementation/sqlite/src/cms_storage_sqlite.e +++ b/library/persistence/implementation/sqlite/src/cms_storage_sqlite.e @@ -7,8 +7,12 @@ class CMS_STORAGE_SQLITE inherit - CMS_STORAGE + + CMS_USER_STORAGE_SQLITE + + CMS_NODE_STORAGE_SQLITE + REFACTORING_HELPER create @@ -21,229 +25,77 @@ feature {NONE} -- Initialization 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) + 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) + create error_handler.make end + db_handler: DATABASE_HANDLER + + connection: DATABASE_CONNECTION + -- Current database connection. feature -- Access: user - has_user: BOOLEAN - -- Has any user? + sql_post_execution + -- Post database execution. do - Result := user_provider.has_user - - end - - - all_users: LIST [CMS_USER] - do - to_implement("Not implemented!!!") - create {ARRAYED_LIST[CMS_USER]} Result.make (0) - end - - user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER - do - Result := user_provider.user (a_id) - - end - - user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER - do - Result := user_provider.user_by_name (a_name) - - end - - user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER - do - Result := user_provider.user_by_email (a_email) - - 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 +-- 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 -feature -- Change: user - - save_user (a_user: CMS_USER) - -- Add a new user `a_user'. + sql_begin_transaction 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) + 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 + db_handler.set_query (create {DATABASE_QUERY}.data_reader (a_sql_statement, Void)) + db_handler.execute_query + end + + sql_change (a_sql_statement: STRING; a_params: detachable STRING_TABLE [detachable ANY]) + do + db_handler.set_query (create {DATABASE_QUERY}.data_reader (a_sql_statement, Void)) + db_handler.execute_change + end + + sql_rows_count: INTEGER + -- Number of rows for last sql execution. + do + Result := db_handler.count + 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 - -- set error + check has_item_at_index: False end 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. - end diff --git a/library/persistence/implementation/sqlite/src/cms_storage_sqlite_builder.e b/library/persistence/implementation/sqlite/src/cms_storage_sqlite_builder.e new file mode 100644 index 0000000..2ecd752 --- /dev/null +++ b/library/persistence/implementation/sqlite/src/cms_storage_sqlite_builder.e @@ -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 diff --git a/library/persistence/implementation/sqlite/src/cms_user_storage_sqlite.e b/library/persistence/implementation/sqlite/src/cms_user_storage_sqlite.e new file mode 100644 index 0000000..42f525e --- /dev/null +++ b/library/persistence/implementation/sqlite/src/cms_user_storage_sqlite.e @@ -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 diff --git a/library/persistence/implementation/sqlite/src/provider/node_data_provider.e b/library/persistence/implementation/sqlite/src/provider/node_data_provider.e deleted file mode 100644 index 25c4606..0000000 --- a/library/persistence/implementation/sqlite/src/provider/node_data_provider.e +++ /dev/null @@ -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 diff --git a/library/persistence/implementation/sqlite/src/provider/user_data_provider.e b/library/persistence/implementation/sqlite/src/provider/user_data_provider.e deleted file mode 100644 index 60fd235..0000000 --- a/library/persistence/implementation/sqlite/src/provider/user_data_provider.e +++ /dev/null @@ -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 diff --git a/library/persistence/implementation/sqlite/tests/storage/storage_test_set.e b/library/persistence/implementation/sqlite/tests/storage/storage_test_set.e index 4d893ed..1475460 100644 --- a/library/persistence/implementation/sqlite/tests/storage/storage_test_set.e +++ b/library/persistence/implementation/sqlite/tests/storage/storage_test_set.e @@ -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 diff --git a/library/persistence/implementation/sqlite/tests/tests-safe.ecf b/library/persistence/implementation/sqlite/tests/tests-safe.ecf index a905aec..e06085e 100644 --- a/library/persistence/implementation/sqlite/tests/tests-safe.ecf +++ b/library/persistence/implementation/sqlite/tests/tests-safe.ecf @@ -7,6 +7,7 @@ + diff --git a/library/persistence/implementation/sqlite/tests/util/abstract_db_test.e b/library/persistence/implementation/sqlite/tests/util/abstract_db_test.e index 6ba5b1b..70b5fdc 100644 --- a/library/persistence/implementation/sqlite/tests/util/abstract_db_test.e +++ b/library/persistence/implementation/sqlite/tests/util/abstract_db_test.e @@ -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 diff --git a/library/src/modules/node/node_module.e b/library/src/modules/node/node_module.e index 8150e3e..3e85a4d 100644 --- a/library/src/modules/node/node_module.e +++ b/library/src/modules/node/node_module.e @@ -33,7 +33,6 @@ feature {NONE} -- Initialization config := a_setup end - config: CMS_SETUP -- Node configuration. @@ -159,10 +158,28 @@ feature -- Handler do_get_nodes (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: CMS_API) local r: CMS_RESPONSE + s: STRING 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") + + a_api.new_node (create {CMS_NODE}.make ("This is a body", "summary this node", "Oh a node")) + + create s.make_from_string ("

Sorry: listing the CMS nodes is not yet implemented.

") + if attached a_api.nodes as lst then + across + lst as ic + loop + s.append ("
  • ") + s.append (a_api.html_encoded (ic.item.title)) + s.append (" (") + s.append (ic.item.id.out) + s.append (")") + s.append ("
  • %N") + end + end + + r.set_main_content (s) + r.add_block (create {CMS_CONTENT_BLOCK}.make ("nodes_warning", Void, "/nodes/ is not yet implemented
    ", Void), "highlighted") r.execute end diff --git a/library/src/persistence/cms_storage.e b/library/src/persistence/cms_storage.e index 234613d..309bfd2 100644 --- a/library/src/persistence/cms_storage.e +++ b/library/src/persistence/cms_storage.e @@ -3,13 +3,16 @@ note description : "[ CMS interface to storage ]" - date : "$Date$" - revision : "$Revision$" + date: "$Date$" + revision: "$Revision$" deferred class CMS_STORAGE inherit + CMS_USER_STORAGE + + CMS_NODE_STORAGE SHARED_LOGGER @@ -24,224 +27,7 @@ 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 +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' diff --git a/library/src/persistence/cms_storage_null.e b/library/src/persistence/cms_storage_null.e index 89eb3df..4b0b83f 100644 --- a/library/src/persistence/cms_storage_null.e +++ b/library/src/persistence/cms_storage_null.e @@ -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 diff --git a/library/src/persistence/cms_storage_sql.e b/library/src/persistence/cms_storage_sql.e new file mode 100644 index 0000000..c9e9372 --- /dev/null +++ b/library/src/persistence/cms_storage_sql.e @@ -0,0 +1,153 @@ +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 + + 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_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_32} 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 diff --git a/library/src/persistence/node/cms_node_storage.e b/library/src/persistence/node/cms_node_storage.e new file mode 100644 index 0000000..6d036c7 --- /dev/null +++ b/library/src/persistence/node/cms_node_storage.e @@ -0,0 +1,97 @@ +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: 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 + + save_node (a_node: CMS_NODE) + -- Save node `a_node'. + require + valid_user: attached a_node.author as l_author implies 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 + +end diff --git a/library/src/persistence/node/cms_node_storage_sql.e b/library/src/persistence/node/cms_node_storage_sql.e new file mode 100644 index 0000000..a836a03 --- /dev/null +++ b/library/src/persistence/node/cms_node_storage_sql.e @@ -0,0 +1,341 @@ +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: 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 + 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 + 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 + + nodes_count: INTEGER + -- Number of items nodes. + do + error_handler.reset + log.write_information (generator + ".nodes_count") + sql_query (select_nodes_count, Void) + if sql_rows_count = 1 then + Result := sql_read_integer_32 (1) + end + sql_post_execution + end + + last_inserted_node_id: INTEGER + -- 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_32 (1) + end + sql_post_execution + end + +feature -- Change: Node + + save_node (a_node: CMS_NODE) + -- Save node `a_node'. + local + l_parameters: STRING_TABLE [detachable ANY] + do + if a_node.has_id and attached a_node.author as l_author and then l_author.has_id then + update_node (l_author.id, a_node) + else + error_handler.reset + log.write_information (generator + ".save_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 + sql_change (sql_insert_node, l_parameters) + 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 + + -- Delete from user nodes. FIXME: what is that ??? + sql_change (sql_delete_from_user_node, l_parameters) + sql_post_execution + end + + update_node (a_user_id: like {CMS_USER}.id; a_node: CMS_NODE) + -- Update node content `a_node'. + -- The user `a_user_id' is an existing or new collaborator. + local + l_parameters: STRING_TABLE [detachable 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_user_id, "editor") + sql_change (sql_update_node, l_parameters) + sql_post_execution + 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. + local + l_parameters: STRING_TABLE [detachable 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") + sql_change (sql_update_node_title, l_parameters) + sql_post_execution + 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. + local + l_parameters: STRING_TABLE [detachable 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") + sql_change (sql_update_node_summary, l_parameters) + sql_post_execution + 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. + local + l_parameters: STRING_TABLE [detachable 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") + 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 id =:id order by id desc, publication_date desc;" + + Select_recent_nodes: STRING = "select * from Nodes order by id desc, publication_date desc LIMIT :rows OFFSET :offset ;" + + SQL_Insert_node: STRING = "insert into nodes (title, summary, content, publication_date, creation_date, modification_date, author_id) values (:title, :summary, :content, :publication_date, :creation_date, :modification_date, :author_id);" + -- SQL Insert 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 {NONE} -- Implementation + + fetch_node: CMS_NODE + do + create Result.make ("", "", "") + if attached sql_read_integer_32 (1) as l_id then + Result.set_id (l_id) + end + if attached sql_read_date_time (2) as l_publication_date then + Result.set_publication_date (l_publication_date) + end + if attached sql_read_date_time (3) as l_creation_date then + Result.set_creation_date (l_creation_date) + end + if attached sql_read_date_time (4) as l_modif_date then + Result.set_modification_date (l_modif_date) + end + if attached sql_read_string_32 (5) as l_title then + Result.set_title (l_title) + end + if attached sql_read_string_32 (6) as l_summary then + Result.set_summary (l_summary) + end + if attached sql_read_string (7) as l_content then + Result.set_content (l_content) + 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 diff --git a/library/src/persistence/user/cms_user_storage.e b/library/src/persistence/user/cms_user_storage.e new file mode 100644 index 0000000..6bfc9a7 --- /dev/null +++ b/library/src/persistence/user/cms_user_storage.e @@ -0,0 +1,120 @@ +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.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 -- 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 + +end diff --git a/library/src/persistence/user/cms_user_storage_sql.e b/library/src/persistence/user/cms_user_storage_sql.e new file mode 100644 index 0000000..b0ab971 --- /dev/null +++ b/library/src/persistence/user/cms_user_storage_sql.e @@ -0,0 +1,285 @@ +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 + 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, "id") + 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 + + 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 + sql_begin_transaction + new_user (a_user) + sql_commit_transaction + 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: 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 + + 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 + error_handler.reset + create l_security + l_password_salt := l_security.salt + l_password_hash := l_security.password_hash (l_password, l_password_salt) + + log.write_information (generator + ".new_user") + create l_parameters.make (4) + l_parameters.put (a_user.name, "username") + l_parameters.put (l_password_hash, "password") + l_parameters.put (l_password_salt, "salt") + l_parameters.put (l_email, "email") + + sql_change (sql_insert_user, l_parameters) + else + -- set error + error_handler.add_custom_error (-1, "bad request" , "Missing password or email") + end + sql_post_execution + end + + fetch_user: detachable CMS_USER + 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 + +feature {NONE} -- Sql Queries: USER + + Select_users_count: STRING = "select count(*) from Users;" + -- Number of users. + + Select_users: STRING = "select * from Users;" + -- List 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 diff --git a/library/persistence/implementation/common/security/security_provider.e b/library/src/security/security_provider.e similarity index 92% rename from library/persistence/implementation/common/security/security_provider.e rename to library/src/security/security_provider.e index ae40a8c..ff2c9b2 100644 --- a/library/persistence/implementation/common/security/security_provider.e +++ b/library/src/security/security_provider.e @@ -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 diff --git a/library/src/service/cms_api.e b/library/src/service/cms_api.e index c6abbe0..119c165 100644 --- a/library/src/service/cms_api.e +++ b/library/src/service/cms_api.e @@ -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 @@ -83,10 +94,10 @@ feature -- Access: Node debug ("refactor_fixme") fixme ("Implementation") end - Result := storage.recent_nodes (0, 10) + Result := storage.nodes end - recent_nodes (a_offset, a_rows: INTEGER): LIST[CMS_NODE] + 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) @@ -174,6 +185,20 @@ feature -- Change User end 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 diff --git a/library/src/service/response/not_implemented_error_cms_response.e b/library/src/service/response/not_implemented_error_cms_response.e index b2c9e81..d4ab328 100644 --- a/library/src/service/response/not_implemented_error_cms_response.e +++ b/library/src/service/response/not_implemented_error_cms_response.e @@ -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