Implemented CMS storage for user and nodes.

Implemented role and permission storage.
Introduced the CMS_PARTIAL_NODE and CMS_PARTIAL_USER.
Added support for node storage extension
  - storage of data specific to each node content type,
  - in addition to the core CMS_NODE)
  - For now, only implemented for SQL storage.
Note: in current version, CMS_PAGE support is hard coded in the core,
    (as opposed to be only supported by the node module.)
Commented/removed for now, the Web API code to update node summary, title, via REST request.
This commit is contained in:
2015-04-14 11:25:02 +02:00
parent 734f661add
commit 133c243126
46 changed files with 2262 additions and 468 deletions

View File

@@ -6,10 +6,29 @@ note
date: "$Date$"
revision: "$Revision$"
class
deferred class
CMS_CONTENT_TYPE
feature -- Access
name: READABLE_STRING_8
-- Internal name.
deferred
end
title: READABLE_STRING_32
-- Human readable name.
deferred
end
feature -- Factory
new_node (a_partial_node: detachable CMS_NODE): CMS_NODE
-- New node based on partial `a_partial_node', or from none.
deferred
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

View File

@@ -6,33 +6,31 @@ note
date: "$Date: 2015-01-27 19:15:02 +0100 (mar., 27 janv. 2015) $"
revision: "$Revision: 96542 $"
class
deferred class
CMS_NODE
inherit
REFACTORING_HELPER
create
make,
make_empty
--create
-- make,
-- make_empty
feature{NONE} -- Initialization
make_empty
-- Create empty node.
do
make ({STRING_32} "", {STRING_32} "", {STRING_32} "")
make ({STRING_32} "")
end
make (a_content: READABLE_STRING_32; a_summary: READABLE_STRING_32; a_title: READABLE_STRING_32)
-- Create current node with `a_content', `a_summary' and `a_title'.
make (a_title: READABLE_STRING_32)
-- Create current node with `a_title'.
local
l_time: DATE_TIME
do
create l_time.make_now_utc
set_content (a_content)
set_summary (a_summary)
set_title (a_title)
set_creation_date (l_time)
set_modification_date (l_time)
@@ -41,32 +39,68 @@ feature{NONE} -- Initialization
debug ("refactor_fixme")
fixme ("Remove default harcoded format")
end
set_format ("HTML")
debug ("refactor_fixme")
fixme ("Remove default harcoded content type")
end
set_content_type ("Page")
ensure
content_set: content = a_content
summary_set: summary = a_summary
title_set: title = a_title
end
feature {CMS_CONTENT_TYPE} -- Conversion
import_node (a_node: CMS_NODE)
-- Import `a_node' into current node.
do
set_id (a_node.id)
set_revision (a_node.revision)
set_title (a_node.title)
set_creation_date (a_node.creation_date)
set_modification_date (a_node.modification_date)
set_publication_date (a_node.publication_date)
set_author (a_node.author)
set_content (
a_node.content,
a_node.summary,
a_node.format
)
end
feature -- Access
id: INTEGER_64 assign set_id
-- Unique id.
--| Should we use NATURAL_64 instead?
content: READABLE_STRING_32
-- Content of the node.
revision: INTEGER_64 assign set_revision
-- Revision value.
--| Note: for now version is not supported.
summary: READABLE_STRING_32
-- A short summary of the node.
content_type: READABLE_STRING_8
-- Associated content type name.
-- Page, Article, Blog, News, etc.
deferred
end
feature -- Access
title: READABLE_STRING_32
-- Full title of the node.
-- Required!
summary: detachable READABLE_STRING_8
-- A short summary of the node.
deferred
end
content: detachable READABLE_STRING_8
-- Content of the node.
deferred
end
format: detachable READABLE_STRING_8
-- Format associated with `content' and `summary'.
-- For example: text, mediawiki, html, etc
deferred
end
feature -- Access: date
modification_date: DATE_TIME
-- When the node was updated.
@@ -80,13 +114,7 @@ feature -- Access
publication_date_output: READABLE_STRING_32
-- Formatted output.
format: READABLE_STRING_32
-- Format associated with `body'.
-- For example: text, mediawiki, html, etc
content_type: READABLE_STRING_32
-- Associated content type name.
-- Page, Article, Blog, News, etc.
feature -- Access: author
author: detachable CMS_USER
-- Author of current node.
@@ -99,22 +127,31 @@ feature -- status report
Result := id > 0
end
feature -- Element change
set_content (a_content: like content)
-- Assign `content' with `a_content'.
same_node (a_node: CMS_NODE): BOOLEAN
-- Is `a_node' same node as Current?
do
content := a_content
-- FIXME: if we introduce notion of revision, update this part!
Result := Current = a_node or id = a_node.id
ensure
content_assigned: content = a_content
valid_result: Result implies a_node.id = id
end
set_summary (a_summary: like summary)
-- Assign `summary' with `a_summary'.
is_typed_as (a_content_type: READABLE_STRING_GENERAL): BOOLEAN
-- Is current node of type `a_content_type' ?
do
summary := a_summary
Result := a_content_type.is_case_insensitive_equal (content_type)
end
feature -- Element change
set_content (a_content: like content; a_summary: like summary; a_format: like format)
-- Set `content', `summary' and `format' to `a_content', `a_summary' and `a_format'.
-- The `format' is associated with both `content' and `summary'
deferred
ensure
content_assigned: content = a_content
summary_assigned: summary = a_summary
format_assigned: format = a_format
end
set_title (a_title: like title)
@@ -150,28 +187,20 @@ feature -- Element change
publication_date_assigned: publication_date = a_publication_date
end
set_content_type (a_content_type: like content_type)
-- Assign `content_type' with `a_content_type'.
set_id (a_id: like id)
-- Assign `id' with `a_id'.
do
content_type := a_content_type
id := a_id
ensure
content_type_assigned: content_type = a_content_type
id_assigned: id = a_id
end
set_format (a_format: like format)
-- Assign `format' with `a_format'.
set_revision (a_revision: like revision)
-- Assign `revision' with `a_revision'.
do
format := a_format
revision := a_revision
ensure
format_assigned: format = a_format
end
set_id (an_id: like id)
-- Assign `id' with `an_id'.
do
id := an_id
ensure
id_assigned: id = an_id
revision_assigned: revision = a_revision
end
set_author (u: like author)

View File

@@ -0,0 +1,84 @@
note
description: "Node object representing the CMS_NODE data in database."
date: "$Date$"
revision: "$Revision$"
class
CMS_PARTIAL_NODE
inherit
CMS_NODE
rename
make_empty as make_empty_node,
set_content as set_all_content
end
create
make_empty
feature {NONE} -- Initialization
make_empty (a_content_type: READABLE_STRING_8)
require
type_not_blank: not a_content_type.is_whitespace
do
content_type := a_content_type
make_empty_node
end
feature -- Access: code
content_type: READABLE_STRING_8
-- <Precursor>
feature -- Access: content
summary: detachable READABLE_STRING_8
-- A short summary of the node.
content: detachable READABLE_STRING_8
-- Content of the node.
format: detachable READABLE_STRING_8
-- Format associated with `content' and `summary'.
-- For example: text, mediawiki, html, etc
feature -- Element change
set_all_content (a_content: like content; a_summary: like summary; a_format: like format)
do
set_content (a_content)
set_summary (a_summary)
set_format (a_format)
end
set_content (a_content: like content)
-- Assign `content' with `a_content', and set the associated `format'.
do
content := a_content
ensure
content_assigned: content = a_content
end
set_summary (a_summary: like summary)
-- Assign `summary' with `a_summary'.
do
summary := a_summary
ensure
summary_assigned: summary = a_summary
end
set_format (a_format: like format)
-- Assign `format' with `a_format'.
do
format := a_format
ensure
format_assigned: format = a_format
end
invariant
note
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

View File

@@ -0,0 +1,19 @@
note
description: "Partial CMS USER."
date: "$Date$"
revision: "$Revision$"
class
CMS_PARTIAL_USER
inherit
CMS_USER
create
make,
make_with_id -- MAYBE: export to CMS_STORAGE
note
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

View File

@@ -71,6 +71,11 @@ feature -- Access
last_login_date: detachable DATE_TIME
-- User last login.
feature -- Roles
roles: detachable LIST [CMS_USER_ROLE]
-- If set, list of roles for current user.
feature -- Access: data
data: detachable STRING_TABLE [detachable ANY]
@@ -189,6 +194,14 @@ feature -- Change element
set_last_login_date (create {DATE_TIME}.make_now_utc)
end
feature -- Element change: roles
set_roles (lst: like roles)
-- Set `roles' to `lst'.
do
roles := lst
end
feature -- Change element: data
set_data_item (k: READABLE_STRING_GENERAL; d: like data_item)
@@ -217,6 +230,6 @@ 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"
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

View File

@@ -22,15 +22,25 @@ create
feature {NONE} -- Initialization
make_with_id (a_id: like id; a_name: like name)
make_with_id (a_id: like id)
-- Create current role with role id `a_id'.
do
id := a_id
make (a_name)
name := {STRING_32} ""
initialize
end
make (a_name: like name)
-- Create current role with name `a_name'.
require
a_name_valid: not a_name.is_whitespace
do
name := a_name
initialize
end
initialize
do
create {ARRAYED_LIST [READABLE_STRING_8]} permissions.make (0)
end
@@ -42,10 +52,10 @@ feature -- Status report
Result := id > 0
end
has_permission (p: READABLE_STRING_8): BOOLEAN
has_permission (p: READABLE_STRING_GENERAL): BOOLEAN
-- Has permission `p'?
do
Result := across permissions as c some c.item.is_case_insensitive_equal (p) end
Result := across permissions as c some p.is_case_insensitive_equal (c.item) end
end
feature -- Access
@@ -53,7 +63,7 @@ feature -- Access
id: INTEGER
-- Unique id associated with Current role.
name: READABLE_STRING_8
name: READABLE_STRING_32
-- Name of Current role.
permissions: LIST [READABLE_STRING_8]
@@ -115,6 +125,6 @@ feature -- Permission change
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

View File

@@ -109,6 +109,11 @@ feature -- Query
db_handler.forth
end
sql_valid_item_index (a_index: INTEGER): BOOLEAN
do
Result := attached {DB_TUPLE} db_handler.item as l_item and then l_item.valid_index (a_index)
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

View File

@@ -26,7 +26,9 @@ feature -- Access
do
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
across nodes_iterator as ic loop
Result.force (ic.item)
if attached ic.item as l_node then
Result.force (l_node)
end
end
end
@@ -34,27 +36,29 @@ feature -- Access
-- 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)
across recent_nodes_iterator (a_lower, a_count) as ic loop
if attached ic.item as l_node then
Result.force (l_node)
end
end
end
feature -- Access: iterator
nodes_iterator: DATABASE_ITERATION_CURSOR [CMS_NODE]
nodes_iterator: DATABASE_ITERATION_CURSOR [detachable CMS_NODE]
-- List of nodes.
local
l_parameters: STRING_TABLE [ANY]
do
error_handler.reset
log.write_information (generator + ".nodes_iterator")
write_information_log (generator + ".nodes_iterator")
create l_parameters.make (0)
sql_query (select_nodes, l_parameters)
sql_query (sql_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]
recent_nodes_iterator (a_lower, a_rows: INTEGER): DATABASE_ITERATION_CURSOR [detachable CMS_NODE]
-- The most recent `a_rows'.
local
l_parameters: STRING_TABLE [ANY]
@@ -62,11 +66,11 @@ feature -- Access: iterator
do
-- FIXME: check implementation...
error_handler.reset
log.write_information (generator + ".recent_nodes_iterator")
write_information_log (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)
create l_query.make_from_string (sql_select_recent_nodes)
sql_query (l_query, l_parameters)
create Result.make (db_handler, agent fetch_node)
sql_post_execution

View File

@@ -26,7 +26,9 @@ feature -- Access
do
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
across nodes_iterator as ic loop
Result.force (ic.item)
if attached ic.item as l_node then
Result.force (l_node)
end
end
end
@@ -34,14 +36,16 @@ feature -- Access
-- 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)
across recent_nodes_iterator (a_lower, a_count) as ic loop
if attached ic.item as l_node then
Result.force (l_node)
end
end
end
feature -- Access: iterator
nodes_iterator: DATABASE_ITERATION_CURSOR [CMS_NODE]
nodes_iterator: DATABASE_ITERATION_CURSOR [detachable CMS_NODE]
-- List of nodes.
local
l_parameters: STRING_TABLE [ANY]
@@ -49,11 +53,11 @@ feature -- Access: iterator
error_handler.reset
write_information_log (generator + ".nodes_iterator")
create l_parameters.make (0)
sql_query (select_nodes, l_parameters)
sql_query (sql_select_nodes, l_parameters)
create Result.make (db_handler, agent fetch_node)
end
recent_nodes_iterator (a_lower, a_rows: INTEGER): DATABASE_ITERATION_CURSOR [CMS_NODE]
recent_nodes_iterator (a_lower, a_rows: INTEGER): DATABASE_ITERATION_CURSOR [detachable CMS_NODE]
-- The most recent `a_rows'.
local
l_parameters: STRING_TABLE [ANY]
@@ -65,7 +69,7 @@ feature -- Access: 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)
create l_query.make_from_string (sql_select_recent_nodes)
sql_query (l_query, l_parameters)
create Result.make (db_handler, agent fetch_node)
end

View File

@@ -45,47 +45,27 @@ feature -- Factory
end
initialize (a_setup: CMS_SETUP; a_storage: CMS_STORAGE_STORE_SQL)
do
initialize_schema (a_setup, a_storage)
initialize_data (a_setup, a_storage)
end
initialize_schema (a_setup: CMS_SETUP; a_storage: CMS_STORAGE_STORE_SQL)
local
p: PATH
f: PLAIN_TEXT_FILE
sql: STRING
do
p := a_setup.layout.path.extended ("scripts").extended ("sqlite.sql")
create f.make_with_path (p)
if f.exists and then f.is_access_readable then
create sql.make (f.count)
f.open_read
from
f.start
until
f.exhausted or f.end_of_file
loop
f.read_stream_thread_aware (1_024)
sql.append (f.last_string)
end
f.close
a_storage.error_handler.reset
-- a_storage.sql_begin_transaction
a_storage.sql_change (sql, Void)
-- a_storage.sql_commit_transaction
end
end
initialize_data (a_setup: CMS_SETUP; a_storage: CMS_STORAGE_STORE_SQL)
local
u: CMS_USER
r: CMS_USER_ROLE
do
-- Schema
a_storage.sql_execute_file_script (a_setup.layout.path.extended ("scripts").extended ("core.sql"))
-- Data
-- Users
create u.make ("admin")
u.set_password ("#admin#")
u.set_password ("istrator#")
u.set_email (a_setup.site_email)
a_storage.new_user (u)
-- Roles
create r.make ("anonymous")
a_storage.save_user_role (r)
create r.make ("authenticated")
r.add_permission ("create page")
r.add_permission ("edit page")
a_storage.save_user_role (r)
end
end