Added blog module as example, this is far from being a real blog module.

but this is an example about on to add a new content type, and support it.
Fixed new node form workflow.

The current state is not final, it requires many changes, but for now, it implements a node editing workflow.
This commit is contained in:
2015-04-15 22:32:38 +02:00
parent f2bb061488
commit a56338ad17
21 changed files with 1040 additions and 226 deletions

View File

@@ -13,6 +13,7 @@
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="cms" location="..\..\cms-safe.ecf" readonly="false"/>
<library name="cms_demo_module" location="modules\demo\cms_demo_module-safe.ecf" readonly="false"/>
<library name="cms_blog_module" location="modules\blog\cms_blog_module-safe.ecf" readonly="false"/>
<library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/>
<library name="layout" location="..\..\library\layout\layout-safe.ecf" readonly="false"/>
<!--

View File

@@ -0,0 +1,103 @@
note
description: "Summary description for {CMS_BLOG}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
CMS_BLOG
inherit
CMS_NODE
redefine
make_empty,
import_node
end
create
make_empty,
make
feature {NONE} -- Initialization
make_empty
do
Precursor
end
feature {CMS_CONTENT_TYPE} -- Conversion
import_node (a_node: CMS_NODE)
-- <Precursor>
do
Precursor (a_node)
if attached {CMS_BLOG} a_node as l_blog then
-- l_blog
end
end
feature -- Access
content_type: READABLE_STRING_8
once
Result := {CMS_BLOG_CONTENT_TYPE}.name
end
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
tags: detachable ARRAYED_LIST [READABLE_STRING_32]
-- Optional tags
feature -- Element change
set_content (a_content: like content; a_summary: like summary; a_format: like format)
do
content := a_content
summary := a_summary
format := a_format
end
add_tag (a_tag: READABLE_STRING_32)
-- Set `parent' to `a_page'
require
not a_tag.is_whitespace
local
l_tags: like tags
do
l_tags := tags
if l_tags = Void then
create l_tags.make (1)
tags := l_tags
end
l_tags.force (a_tag)
end
set_tags_from_string (a_tags: READABLE_STRING_32)
local
t: STRING_32
do
tags := Void
across
a_tags.split (',') as ic
loop
t := ic.item
t.left_adjust
t.right_adjust
if not t.is_whitespace then
add_tag (t)
end
end
end
end

View File

@@ -0,0 +1,65 @@
note
description: "Summary description for {CMS_BLOG_CONTENT_TYPE}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
CMS_BLOG_CONTENT_TYPE
inherit
CMS_CONTENT_TYPE
redefine
default_create
end
feature {NONE} -- Initialization
default_create
do
Precursor
create {ARRAYED_LIST [like available_formats.item]} available_formats.make (3)
available_formats.extend (create {PLAIN_TEXT_CONTENT_FORMAT})
available_formats.extend (create {FILTERED_HTML_CONTENT_FORMAT})
available_formats.extend (create {FULL_HTML_CONTENT_FORMAT})
end
feature -- Access
name: STRING = "blog"
-- Internal name.
title: STRING_32 = "Blog"
-- Human readable name.
description: STRING_32 = "Content published as a blog post."
-- Optional description
feature -- Access
available_formats: LIST [CONTENT_FORMAT]
-- Available formats for Current type.
feature -- Factory
new_node_with_title (a_title: READABLE_STRING_32; a_partial_node: detachable CMS_NODE): like new_node
-- New node with `a_title' and fill from partial `a_partial_node' if set.
do
create Result.make (a_title)
if a_partial_node /= Void then
Result.import_node (a_partial_node)
Result.set_title (a_title)
end
end
new_node (a_partial_node: detachable CMS_NODE): CMS_BLOG
-- New node based on partial `a_partial_node', or from none.
do
create Result.make_empty
if a_partial_node /= Void then
Result.import_node (a_partial_node)
end
end
end

View File

@@ -0,0 +1,75 @@
note
description: "Summary description for {CMS_BLOG_CONTENT_TYPE_WEBFORM_MANAGER}."
date: "$Date$"
revision: "$Revision$"
class
CMS_BLOG_CONTENT_TYPE_WEBFORM_MANAGER
inherit
CMS_NODE_CONTENT_TYPE_WEBFORM_MANAGER [CMS_BLOG]
redefine
content_type,
fill_edit_form,
change_node,
new_node
end
create
make
feature -- Access
content_type: CMS_BLOG_CONTENT_TYPE
-- Associated content type.
feature -- form
fill_edit_form (response: NODE_RESPONSE; f: CMS_FORM; a_node: detachable like new_node)
local
ti: WSF_FORM_TEXT_INPUT
fset: WSF_FORM_FIELD_SET
ta: WSF_FORM_TEXTAREA
tselect: WSF_FORM_SELECT
opt: WSF_FORM_SELECT_OPTION
s: STRING_32
do
Precursor (response, f, a_node)
create ti.make ("tags")
ti.set_label ("Tags")
ti.set_size (70)
if a_node /= Void and then attached a_node.tags as l_tags then
create s.make_empty
across
l_tags as ic
loop
if not s.is_empty then
s.append_character (',')
end
s.append (ic.item)
end
ti.set_text_value (s)
end
ti.set_is_required (False)
f.extend (ti)
end
change_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: like new_node)
do
Precursor (response, fd, a_node)
if attached fd.string_item ("tags") as l_tags then
a_node.set_tags_from_string (l_tags)
end
end
new_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: detachable like new_node): like content_type.new_node
-- <Precursor>
do
Result := Precursor (response, fd, a_node)
if attached fd.string_item ("tags") as l_tags then
Result.set_tags_from_string (l_tags)
end
end
end

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="cms_blog_module" uuid="C92F6E1E-2222-4414-9B6E-AA680E324D42" library_target="cms_blog_module">
<target name="cms_blog_module">
<root all_classes="true"/>
<file_rule>
<exclude>/.git$</exclude>
<exclude>/EIFGENs$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="standard">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension-safe.ecf"/>
<library name="cms" location="..\..\..\..\cms-safe.ecf" readonly="false"/>
<library name="cms_model" location="..\..\..\..\library\model\cms_model-safe.ecf" readonly="false"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
<library name="text_filter" location="$ISE_LIBRARY\unstable\library\text\text_filter\text_filter-safe.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
<library name="wsf_html" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf_html\wsf_html-safe.ecf"/>
<library name="wsf_encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder-safe.ecf"/>
<cluster name="src" location=".\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,121 @@
note
description: "Summary description for {CMS_BLOG_MODULE}."
author: ""
date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
revision: "$Revision: 96616 $"
class
CMS_BLOG_MODULE
inherit
CMS_MODULE
redefine
register_hooks,
initialize,
is_installed,
install
end
CMS_HOOK_MENU_SYSTEM_ALTER
create
make
feature {NONE} -- Initialization
make
do
name := "Blog demo module"
version := "1.0"
description := "Service to demonstrate new node for blog"
package := "demo"
end
feature {CMS_API} -- Module Initialization
initialize (api: CMS_API)
-- <Precursor>
local
ct: CMS_BLOG_CONTENT_TYPE
do
Precursor (api)
if attached {CMS_NODE_API} api.module_api ({NODE_MODULE}) as l_node_api then
create ct
l_node_api.add_content_type (ct)
l_node_api.add_content_type_webform_manager (create {CMS_BLOG_CONTENT_TYPE_WEBFORM_MANAGER}.make (ct))
-- Add support for CMS_BLOG, which requires a storage extension to store the optional "tags" value
-- For now, we only have extension based on SQL statement.
if attached {CMS_NODE_STORAGE_SQL} l_node_api.node_storage as l_sql_node_storage then
l_sql_node_storage.register_node_storage_extension (create {CMS_NODE_STORAGE_SQL_BLOG_EXTENSION}.make (l_sql_node_storage))
end
end
end
feature {CMS_API} -- Module management
is_installed (api: CMS_API): BOOLEAN
-- Is Current module installed?
do
Result := attached api.storage.custom_value ("is_initialized", "module-" + name) as v and then v.is_case_insensitive_equal_general ("yes")
end
install (api: CMS_API)
local
sql: STRING
do
-- Schema
if attached {CMS_STORAGE_SQL_I} api.storage as l_sql_storage then
if not l_sql_storage.sql_table_exists ("blog_post_nodes") then
sql := "[
CREATE TABLE "blog_post_nodes"(
"nid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("nid">=0),
"revision" INTEGER,
"tags" VARCHAR(255)
);
]"
l_sql_storage.sql_execute_script (sql)
if l_sql_storage.has_error then
api.logger.put_error ("Could not initialize database for blog module", generating_type)
end
end
api.storage.set_custom_value ("is_initialized", "module-" + name, "yes")
end
end
feature -- Access: router
router (a_api: CMS_API): WSF_ROUTER
-- Node router.
do
create Result.make (1)
Result.handle_with_request_methods ("/blogs/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_blogs (?,?, a_api)), Result.methods_get)
end
feature -- Hooks
register_hooks (a_response: CMS_RESPONSE)
do
a_response.subscribe_to_menu_system_alter_hook (Current)
end
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
local
lnk: CMS_LOCAL_LINK
do
create lnk.make ("Blogs", "/blogs/")
a_menu_system.primary_menu.extend (lnk)
end
feature -- Handler
handle_blogs (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: CMS_API)
local
r: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE
do
create r.make (req, res, a_api)
r.set_main_content ("Blog module is in development ...")
r.execute
end
end

View File

@@ -0,0 +1,116 @@
note
description: "Storage extension for Blog nodes."
date: "$Date$"
revision: "$Revision$"
class
CMS_NODE_STORAGE_SQL_BLOG_EXTENSION
inherit
CMS_NODE_STORAGE_EXTENSION [CMS_BLOG]
CMS_PROXY_STORAGE_SQL
rename
sql_storage as node_storage
redefine
node_storage
end
create
make
feature {NONE} -- Initialization
node_storage: CMS_NODE_STORAGE_SQL
-- <Precursor>
feature -- Access
content_type: STRING
once
Result := {CMS_BLOG_CONTENT_TYPE}.name
end
feature -- Persistence
store (a_node: CMS_BLOG)
local
l_parameters: STRING_TABLE [detachable ANY]
l_new_tags: detachable STRING_32
l_previous_tags: detachable STRING_32
l_update: BOOLEAN
do
error_handler.reset
if attached api as l_api then
l_api.logger.put_information (generator + ".store", Void)
end
create l_parameters.make (2)
l_parameters.put (a_node.id, "nid")
l_parameters.put (a_node.revision, "revision")
sql_query (sql_select_blog_data, l_parameters)
if not has_error then
if sql_rows_count = 1 then
l_previous_tags := sql_read_string_32 (3)
l_update := True
end
if attached a_node.tags as l_tags and then not l_tags.is_empty then
create l_new_tags.make (0)
across
l_tags as ic
loop
if not l_new_tags.is_empty then
l_new_tags.append_character (',')
end
l_new_tags.append (ic.item)
end
else
l_new_tags := Void
end
l_parameters.put (l_new_tags, "tags")
if l_update and l_new_tags /~ l_previous_tags then
sql_change (sql_update_blog_data, l_parameters)
elseif l_new_tags /= Void then
sql_change (sql_insert_blog_data, l_parameters)
else
-- no blog data, means everything is empty.
end
end
end
load (a_node: CMS_BLOG)
local
l_parameters: STRING_TABLE [ANY]
n: INTEGER
ct: CMS_BLOG_CONTENT_TYPE
do
error_handler.reset
create l_parameters.make (2)
l_parameters.put (a_node.id, "nid")
l_parameters.put (a_node.revision, "revision")
sql_query (sql_select_blog_data, l_parameters)
if not has_error then
n := sql_rows_count
if n = 1 then
-- nid, revision, parent
if
attached sql_read_string_32 (3) as l_tags and then
not l_tags.is_whitespace
then
-- FIXME: find a simple way to access the declared content types.
a_node.set_tags_from_string (l_tags)
end
else
check unique_data: n = 0 end
end
end
end
feature -- SQL
sql_select_blog_data: STRING = "SELECT nid, revision, tags FROM blog_post_nodes WHERE nid =:nid AND revision=:revision;"
sql_insert_blog_data: STRING = "INSERT INTO blog_post_nodes (nid, revision, tags) VALUES (:nid, :revision, :tags);"
sql_update_blog_data: STRING = "UPDATE blog_post_nodes SET nid=:nid, revision=:revision, tags=:tags WHERE nid=:nid AND revision=:revision;"
end

View File

@@ -10,7 +10,10 @@ class
inherit
CMS_MODULE
redefine
register_hooks
register_hooks,
initialize,
is_installed,
install
end
CMS_HOOK_MENU_SYSTEM_ALTER
@@ -30,6 +33,51 @@ feature {NONE} -- Initialization
package := "demo"
end
feature {CMS_API} -- Module Initialization
initialize (api: CMS_API)
-- <Precursor>
do
Precursor (api)
-- Add support for CMS_PAGE, which requires a storage extension to store the optional "parent" id.
-- For now, we only have extension based on SQL statement.
-- if attached {CMS_NODE_STORAGE_SQL} l_node_api.node_storage as l_sql_node_storage then
-- l_sql_node_storage.register_node_storage_extension (create {CMS_NODE_STORAGE_SQL_PAGE_EXTENSION}.make (l_sql_node_storage))
-- end
end
feature {CMS_API} -- Module management
is_installed (api: CMS_API): BOOLEAN
-- Is Current module installed?
do
Result := attached api.storage.custom_value ("is_initialized", "module-" + name) as v and then v.is_case_insensitive_equal_general ("yes")
end
install (api: CMS_API)
local
sql: STRING
do
-- Schema
if attached {CMS_STORAGE_SQL_I} api.storage as l_sql_storage then
if not l_sql_storage.sql_table_exists ("tb_demo") then
sql := "[
CREATE TABLE "tb_demo"(
"demo_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("demo_id">=0),
"name" VARCHAR(100) NOT NULL,
"value" TEXT
);
]"
l_sql_storage.sql_execute_script (sql)
if l_sql_storage.has_error then
api.logger.put_error ("Could not initialize database for demo module", generating_type)
end
end
api.storage.set_custom_value ("is_initialized", "module-" + name, "yes")
end
end
feature -- Access: router
router (a_api: CMS_API): WSF_ROUTER
@@ -84,37 +132,11 @@ feature -- Hooks
feature -- Handler
initialize_module (a_api: CMS_API)
local
sql: STRING
do
if attached {CMS_STORAGE_SQL_I} a_api.storage as sql_db then
sql_db.sql_query ("select count(*) from tb_demo;", Void)
if sql_db.has_error then
-- Initialize db for demo module
sql := "[
CREATE TABLE "tb_demo"(
"did" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("did">=0),
"name" VARCHAR(100) NOT NULL,
"value" TEXT
);
]"
sql_db.reset_error
sql_db.sql_change (sql, Void)
if sql_db.has_error then
a_api.logger.put_error ("Could not initialize database for demo module", generating_type)
end
end
end
end
handle_demo,
handle_demo_entry (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: CMS_API)
local
r: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE
do
initialize_module (a_api)
create r.make (req, res, a_api)
r.set_main_content ("NODE module does not yet implement %"" + req.path_info + "%" ...")
r.add_error_message ("NODE Module: not yet implemented")

View File

@@ -144,6 +144,10 @@ feature -- CMS setup
create {CMS_DEMO_MODULE} m.make
m.enable
a_setup.register_module (m)
create {CMS_BLOG_MODULE} m.make
m.enable
a_setup.register_module (m)
end
setup_storage (a_setup: CMS_SETUP)

View File

@@ -45,7 +45,7 @@ feature {NONE} -- Implementation
add_content_type_webform_manager (create {CMS_PAGE_CONTENT_TYPE_WEBFORM_MANAGER}.make (ct))
end
feature {NODE_MODULE} -- Access nodes storage.
feature {CMS_MODULE} -- Access nodes storage.
node_storage: CMS_NODE_STORAGE_I
@@ -104,7 +104,7 @@ feature -- URL
-- or URI of path for selection of new content possibilities if ct is Void.
do
if ct /= Void then
Result := "/node/new/" + ct.name
Result := "/node/add/" + ct.name
else
Result := "/node/new"
end

View File

@@ -31,7 +31,7 @@ feature {CMS_CONTENT_TYPE} -- Conversion
do
Precursor (a_node)
if attached {CMS_PAGE} a_node as l_page then
set_parent (l_page)
set_parent (l_page.parent)
end
end

View File

@@ -36,8 +36,8 @@ feature -- Forms ...
end
change_node (response: NODE_RESPONSE; a_form_data: WSF_FORM_DATA; a_node: CMS_NODE)
require
a_node.has_id
-- require
-- a_node.has_id
deferred
end

View File

@@ -0,0 +1,159 @@
note
description: "Summary description for {CMS_NODE_CONTENT_TYPE_WEBFORM_MANAGER}."
date: "$Date$"
revision: "$Revision$"
class
CMS_NODE_CONTENT_TYPE_WEBFORM_MANAGER [G -> CMS_NODE]
inherit
CMS_CONTENT_TYPE_WEBFORM_MANAGER
redefine
content_type
end
create
make
feature -- Access
content_type: CMS_CONTENT_TYPE
-- Associated content type.
feature -- Forms ...
fill_edit_form (response: NODE_RESPONSE; f: CMS_FORM; a_node: detachable like new_node)
local
ti: WSF_FORM_TEXT_INPUT
fset: WSF_FORM_FIELD_SET
ta: WSF_FORM_TEXTAREA
tselect: WSF_FORM_SELECT
opt: WSF_FORM_SELECT_OPTION
do
create ti.make ("title")
ti.set_label ("Title")
ti.set_size (70)
if a_node /= Void then
ti.set_text_value (a_node.title)
end
ti.set_is_required (True)
f.extend (ti)
f.extend_html_text ("<br/>")
create ta.make ("body")
ta.set_rows (10)
ta.set_cols (70)
if a_node /= Void then
ta.set_text_value (a_node.content)
end
-- ta.set_label ("Body")
ta.set_description ("This is the main content")
ta.set_is_required (False)
create fset.make
fset.set_legend ("Body")
fset.extend (ta)
fset.extend_html_text ("<br/>")
create tselect.make ("format")
tselect.set_label ("Body's format")
tselect.set_is_required (True)
across
content_type.available_formats as c
loop
create opt.make (c.item.name, c.item.title)
if attached c.item.html_help as f_help then
opt.set_description ("<ul>" + f_help + "</ul>")
end
tselect.add_option (opt)
end
if a_node /= Void and then attached a_node.format as l_format then
tselect.set_text_by_value (l_format)
end
fset.extend (tselect)
f.extend (fset)
end
change_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: like new_node)
local
b: detachable READABLE_STRING_8
f: detachable CONTENT_FORMAT
do
if attached fd.integer_item ("id") as l_id and then l_id > 0 then
check a_node.id = l_id end
end
if attached fd.string_item ("title") as l_title then
a_node.set_title (l_title)
end
if attached fd.string_item ("body") as l_body then
b := l_body
end
if attached fd.string_item ("format") as s_format and then attached response.api.format (s_format) as f_format then
f := f_format
elseif a_node /= Void and then attached a_node.format as s_format and then attached response.api.format (s_format) as f_format then
f := f_format
else
f := response.api.formats.default_format
end
if b /= Void then
a_node.set_content (b, Void, f.name) -- FIXME: summary
end
end
new_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: detachable like new_node): like content_type.new_node
-- <Precursor>
local
b: detachable READABLE_STRING_8
f: detachable CONTENT_FORMAT
l_node: detachable like new_node
do
l_node := a_node
if attached fd.integer_item ("id") as l_id and then l_id > 0 then
if l_node /= Void then
check l_node.id = l_id end
else
if attached {like new_node} response.node_api.node (l_id) as n then
l_node := n
else
-- FIXME: Error
end
end
end
if attached fd.string_item ("title") as l_title then
if l_node = Void then
l_node := content_type.new_node (Void)
l_node.set_title (l_title)
else
l_node.set_title (l_title)
end
else
if l_node = Void then
l_node := content_type.new_node_with_title ("...", Void)
end
end
l_node.set_author (response.user)
if attached fd.string_item ("body") as l_body then
b := l_body
end
if attached fd.string_item ("format") as s_format and then attached response.api.format (s_format) as f_format then
f := f_format
elseif a_node /= Void and then attached a_node.format as s_format and then attached response.api.format (s_format) as f_format then
f := f_format
else
f := response.api.formats.default_format
end
if b /= Void then
l_node.set_content (b, Void, f.name)
end
Result := l_node
end
end

View File

@@ -8,7 +8,7 @@ class
CMS_PAGE_CONTENT_TYPE_WEBFORM_MANAGER
inherit
CMS_CONTENT_TYPE_WEBFORM_MANAGER
CMS_NODE_CONTENT_TYPE_WEBFORM_MANAGER [CMS_PAGE]
redefine
content_type
end
@@ -23,138 +23,138 @@ feature -- Access
feature -- Forms ...
fill_edit_form (response: NODE_RESPONSE; f: CMS_FORM; a_node: detachable CMS_NODE)
local
ti: WSF_FORM_TEXT_INPUT
fset: WSF_FORM_FIELD_SET
ta: WSF_FORM_TEXTAREA
tselect: WSF_FORM_SELECT
opt: WSF_FORM_SELECT_OPTION
do
create ti.make ("title")
ti.set_label ("Title")
ti.set_size (70)
if a_node /= Void then
ti.set_text_value (a_node.title)
end
ti.set_is_required (True)
f.extend (ti)
-- fill_edit_form (response: NODE_RESPONSE; f: CMS_FORM; a_node: detachable CMS_NODE)
-- local
-- ti: WSF_FORM_TEXT_INPUT
-- fset: WSF_FORM_FIELD_SET
-- ta: WSF_FORM_TEXTAREA
-- tselect: WSF_FORM_SELECT
-- opt: WSF_FORM_SELECT_OPTION
-- do
-- create ti.make ("title")
-- ti.set_label ("Title")
-- ti.set_size (70)
-- if a_node /= Void then
-- ti.set_text_value (a_node.title)
-- end
-- ti.set_is_required (True)
-- f.extend (ti)
f.extend_html_text ("<br/>")
-- f.extend_html_text ("<br/>")
create ta.make ("body")
ta.set_rows (10)
ta.set_cols (70)
if a_node /= Void then
ta.set_text_value (a_node.content)
end
-- ta.set_label ("Body")
ta.set_description ("This is the main content")
ta.set_is_required (False)
-- create ta.make ("body")
-- ta.set_rows (10)
-- ta.set_cols (70)
-- if a_node /= Void then
-- ta.set_text_value (a_node.content)
-- end
---- ta.set_label ("Body")
-- ta.set_description ("This is the main content")
-- ta.set_is_required (False)
create fset.make
fset.set_legend ("Body")
fset.extend (ta)
-- create fset.make
-- fset.set_legend ("Body")
-- fset.extend (ta)
fset.extend_html_text ("<br/>")
-- fset.extend_html_text ("<br/>")
create tselect.make ("format")
tselect.set_label ("Body's format")
tselect.set_is_required (True)
across
content_type.available_formats as c
loop
create opt.make (c.item.name, c.item.title)
if attached c.item.html_help as f_help then
opt.set_description ("<ul>" + f_help + "</ul>")
end
tselect.add_option (opt)
end
if a_node /= Void and then attached a_node.format as l_format then
tselect.set_text_by_value (l_format)
end
-- create tselect.make ("format")
-- tselect.set_label ("Body's format")
-- tselect.set_is_required (True)
-- across
-- content_type.available_formats as c
-- loop
-- create opt.make (c.item.name, c.item.title)
-- if attached c.item.html_help as f_help then
-- opt.set_description ("<ul>" + f_help + "</ul>")
-- end
-- tselect.add_option (opt)
-- end
-- if a_node /= Void and then attached a_node.format as l_format then
-- tselect.set_text_by_value (l_format)
-- end
fset.extend (tselect)
-- fset.extend (tselect)
f.extend (fset)
-- f.extend (fset)
end
-- end
change_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: like new_node)
local
b: detachable READABLE_STRING_8
f: detachable CONTENT_FORMAT
do
if attached fd.integer_item ("id") as l_id and then l_id > 0 then
check a_node.id = l_id end
end
if attached fd.string_item ("title") as l_title then
a_node.set_title (l_title)
end
-- change_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: like new_node)
-- local
-- b: detachable READABLE_STRING_8
-- f: detachable CONTENT_FORMAT
-- do
-- if attached fd.integer_item ("id") as l_id and then l_id > 0 then
-- check a_node.id = l_id end
-- end
-- if attached fd.string_item ("title") as l_title then
-- a_node.set_title (l_title)
-- end
if attached fd.string_item ("body") as l_body then
b := l_body
end
if attached fd.string_item ("format") as s_format and then attached response.api.format (s_format) as f_format then
f := f_format
elseif a_node /= Void and then attached a_node.format as s_format and then attached response.api.format (s_format) as f_format then
f := f_format
else
f := response.api.formats.default_format
end
if b /= Void then
a_node.set_content (b, Void, f.name) -- FIXME: summary
end
end
-- if attached fd.string_item ("body") as l_body then
-- b := l_body
-- end
-- if attached fd.string_item ("format") as s_format and then attached response.api.format (s_format) as f_format then
-- f := f_format
-- elseif a_node /= Void and then attached a_node.format as s_format and then attached response.api.format (s_format) as f_format then
-- f := f_format
-- else
-- f := response.api.formats.default_format
-- end
-- if b /= Void then
-- a_node.set_content (b, Void, f.name) -- FIXME: summary
-- end
-- end
new_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: detachable like new_node): CMS_PAGE
-- <Precursor>
local
b: detachable READABLE_STRING_8
f: detachable CONTENT_FORMAT
l_node: detachable like new_node
do
l_node := a_node
if attached fd.integer_item ("id") as l_id and then l_id > 0 then
if l_node /= Void then
check l_node.id = l_id end
else
if attached {like new_node} response.node_api.node (l_id) as n then
l_node := n
else
-- FIXME: Error
end
end
end
if attached fd.string_item ("title") as l_title then
if l_node = Void then
l_node := content_type.new_node (Void)
l_node.set_title (l_title)
else
l_node.set_title (l_title)
end
else
if l_node = Void then
l_node := content_type.new_node_with_title ("...", Void)
end
end
l_node.set_author (response.user)
-- new_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: detachable like new_node): CMS_PAGE
-- -- <Precursor>
-- local
-- b: detachable READABLE_STRING_8
-- f: detachable CONTENT_FORMAT
-- l_node: detachable like new_node
-- do
-- l_node := a_node
-- if attached fd.integer_item ("id") as l_id and then l_id > 0 then
-- if l_node /= Void then
-- check l_node.id = l_id end
-- else
-- if attached {like new_node} response.node_api.node (l_id) as n then
-- l_node := n
-- else
-- -- FIXME: Error
-- end
-- end
-- end
-- if attached fd.string_item ("title") as l_title then
-- if l_node = Void then
-- l_node := content_type.new_node (Void)
-- l_node.set_title (l_title)
-- else
-- l_node.set_title (l_title)
-- end
-- else
-- if l_node = Void then
-- l_node := content_type.new_node_with_title ("...", Void)
-- end
-- end
-- l_node.set_author (response.user)
if attached fd.string_item ("body") as l_body then
b := l_body
end
if attached fd.string_item ("format") as s_format and then attached response.api.format (s_format) as f_format then
f := f_format
elseif a_node /= Void and then attached a_node.format as s_format and then attached response.api.format (s_format) as f_format then
f := f_format
else
f := response.api.formats.default_format
end
if b /= Void then
l_node.set_content (b, Void, f.name)
end
Result := l_node
end
-- if attached fd.string_item ("body") as l_body then
-- b := l_body
-- end
-- if attached fd.string_item ("format") as s_format and then attached response.api.format (s_format) as f_format then
-- f := f_format
-- elseif a_node /= Void and then attached a_node.format as s_format and then attached response.api.format (s_format) as f_format then
-- f := f_format
-- else
-- f := response.api.formats.default_format
-- end
-- if b /= Void then
-- l_node.set_content (b, Void, f.name)
-- end
-- Result := l_node
-- end
end

View File

@@ -59,6 +59,41 @@ feature -- Execution
fd := f.last_data
end
if attached redirection as l_location then
-- FIXME: Hack for now
set_title (l_node.title)
add_to_menu (create {CMS_LOCAL_LINK}.make ("View", node_url (l_node)), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make ("Edit", "/node/" + l_node.id.out + "/edit"), primary_tabs)
b.append ("saved")
else
set_title ("Edit #" + l_node.id.out)
add_to_menu (create {CMS_LOCAL_LINK}.make ("View", node_url (l_node)), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make ("Edit", "/node/" + l_node.id.out + "/edit"), primary_tabs)
f.append_to_html (wsf_theme, b)
end
else
b.append ("<h1>Access denied</h1>")
end
else
set_title ("Unknown node")
end
elseif
attached {WSF_STRING} request.path_parameter ("type") as p_type and then
attached node_api.content_type (p_type.value) as l_type
then
if has_permission ("create " + l_type.name) then
if attached l_type.new_node (Void) as l_node then
f := edit_form (l_node, url (request.path_info, Void), "edit-" + l_type.name, l_type)
if request.is_post_request_method then
f.validation_actions.extend (agent edit_form_validate (?, b))
f.submit_actions.extend (agent edit_form_submit (?, l_node, l_type, b))
f.process (Current)
fd := f.last_data
end
set_title ("Edit #" + l_node.id.out)
add_to_menu (create {CMS_LOCAL_LINK}.make ("View", node_url (l_node)), primary_tabs)
@@ -66,11 +101,12 @@ feature -- Execution
f.append_to_html (wsf_theme, b)
else
b.append ("<h1>Access denied</h1>")
b.append ("<h1>Server error</h1>")
end
else
set_title ("Unknown node")
b.append ("<h1>Access denied</h1>")
end
else
set_title ("Create new content ...")
b.append ("<ul id=%"content-types%">")
@@ -140,10 +176,17 @@ feature -- Form
end
if a_node /= Void then
l_node := a_node
change_node (a_type, fd, a_node)
s := "modified"
if l_node.has_id then
change_node (a_type, fd, a_node)
s := "modified"
else
change_node (a_type, fd, a_node)
l_node.set_author (user)
s := "created"
end
else
l_node := new_node (a_type, fd, Void)
l_node.set_author (user)
s := "created"
end
node_api.save_node (l_node)

View File

@@ -129,10 +129,10 @@ feature -- HTTP Methods
elseif l_nid > 0 then --| i.e: l_node = Void
send_not_found (req, res)
else
send_bad_request (req, res)
-- send_bad_request (req, res)
-- FIXME: should not be accepted
-- Factory
-- create_new_node (req, res)
create_new_node (req, res)
end
end
end
@@ -145,6 +145,9 @@ feature -- HTTP Methods
if req.path_info.ends_with_general ("/edit") then
create edit_response.make (req, res, api, node_api)
edit_response.execute
elseif req.path_info.starts_with_general ("/node/add/") then
create edit_response.make (req, res, api, node_api)
edit_response.execute
else
to_implement ("Check user permissions!!!")
if attached current_user (req) as l_user then
@@ -293,14 +296,52 @@ feature {NONE} -- Node
create_new_node (req: WSF_REQUEST; res: WSF_RESPONSE)
local
l_page: CMS_RESPONSE
l_page: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE
l_node: detachable CMS_NODE
l_gen_page: GENERIC_VIEW_CMS_RESPONSE
edit_response: NODE_FORM_RESPONSE
s: STRING
do
if api.user_has_permission (current_user (req), "create node") then
create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api)
l_page.execute
if
attached {WSF_STRING} req.path_parameter ("type") as p_type and then
attached node_api.content_type (p_type.value) as ct
then
create edit_response.make (req, res, api, node_api)
edit_response.execute
-- create l_page.make (req, res, api)
-- l_node := ct.new_node (Void)
-- l_page.set_main_content (l_node.out)
-- l_page.execute
else
send_access_denied (req, res)
create l_gen_page.make (req, res, api)
create s.make_empty
s.append ("<ul>")
across
node_api.content_types as ic
loop
if api.user_has_permission (current_user (req), "create " + ic.item.name) then
s.append ("<li>")
s.append (l_gen_page.link (ic.item.title, node_api.new_content_path (ic.item), Void))
if attached ic.item.description as l_description then
s.append ("<p class=%"description%">")
s.append (l_gen_page.html_encoded (l_description))
s.append ("</p>")
end
s.append ("</li>")
end
end
s.append ("</ul>")
l_gen_page.set_title ("Create new content ...")
l_gen_page.set_main_content (s)
l_gen_page.execute
end
-- if api.user_has_permission (current_user (req), "create node") then
-- create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api)
-- l_page.execute
-- else
-- send_access_denied (req, res)
-- end
end
feature -- {NONE} Form data

View File

@@ -133,15 +133,15 @@ feature -- Access: router
l_methods: WSF_REQUEST_METHODS
do
create l_node_handler.make (a_api, a_node_api)
create l_methods
l_methods.enable_get
l_methods.enable_post
l_methods.lock
a_router.handle_with_request_methods ("/node", l_node_handler, l_methods)
a_router.handle_with_request_methods ("/node", l_node_handler, a_router.methods_get_post)
a_router.handle_with_request_methods ("/node/", l_node_handler, a_router.methods_get_post)
create l_new_node_handler.make (a_api, a_node_api)
a_router.handle_with_request_methods ("/node/new/{type}", create {WSF_URI_AGENT_HANDLER}.make (agent do_get_node_creation_by_type (?,?, "type", a_node_api)), a_router.methods_get)
a_router.handle_with_request_methods ("/node/new", create {WSF_URI_AGENT_HANDLER}.make (agent do_get_node_creation_selection (?,?, a_node_api)), a_router.methods_get)
a_router.handle_with_request_methods ("/node/add/{type}", l_new_node_handler, a_router.methods_get_post)
a_router.handle_with_request_methods ("/node/new", l_new_node_handler, a_router.methods_get)
-- a_router.handle_with_request_methods ("/node/new/{type}", create {WSF_URI_AGENT_HANDLER}.make (agent do_get_node_creation_by_type (?,?, "type", a_node_api)), a_router.methods_get)
-- a_router.handle_with_request_methods ("/node/new", create {WSF_URI_AGENT_HANDLER}.make (agent do_get_node_creation_selection (?,?, a_node_api)), a_router.methods_get)
create l_edit_node_handler.make (a_api, a_node_api)
a_router.handle_with_request_methods ("/node/{id}/edit", l_edit_node_handler, a_router.methods_get_post)
@@ -149,6 +149,8 @@ feature -- Access: router
create l_node_handler.make (a_api, a_node_api)
a_router.handle_with_request_methods ("/node/{id}", l_node_handler, a_router.methods_get_put_delete + a_router.methods_get_post)
-- Nodes
create l_nodes_handler.make (a_api, a_node_api)
create l_methods
@@ -261,51 +263,53 @@ feature -- Hooks
do
create lnk.make ("List of nodes", a_response.url ("/nodes", Void))
a_menu_system.primary_menu.extend (lnk)
create lnk.make ("Create ..", a_response.url ("/node/", Void))
a_menu_system.primary_menu.extend (lnk)
end
feature -- Handler
--feature -- Handler
do_get_node_creation_selection (req: WSF_REQUEST; res: WSF_RESPONSE; a_node_api: CMS_NODE_API)
local
l_page: GENERIC_VIEW_CMS_RESPONSE
s: STRING
do
create l_page.make (req, res, a_node_api.cms_api)
-- do_get_node_creation_selection (req: WSF_REQUEST; res: WSF_RESPONSE; a_node_api: CMS_NODE_API)
-- local
-- l_page: GENERIC_VIEW_CMS_RESPONSE
-- s: STRING
-- do
-- create l_page.make (req, res, a_node_api.cms_api)
create s.make_empty
s.append ("<ul>")
across
a_node_api.content_types as ic
loop
s.append ("<li>")
s.append (l_page.link (ic.item.title, a_node_api.new_content_path (ic.item), Void))
if attached ic.item.description as l_description then
s.append ("<p class=%"description%">")
s.append (l_page.html_encoded (l_description))
s.append ("</p>")
end
s.append ("</li>")
end
s.append ("</ul>")
l_page.set_title ("Create new content ...")
l_page.set_main_content (s)
l_page.execute
end
-- create s.make_empty
-- s.append ("<ul>")
-- across
-- a_node_api.content_types as ic
-- loop
-- s.append ("<li>")
-- s.append (l_page.link (ic.item.title, a_node_api.new_content_path (ic.item), Void))
-- if attached ic.item.description as l_description then
-- s.append ("<p class=%"description%">")
-- s.append (l_page.html_encoded (l_description))
-- s.append ("</p>")
-- end
-- s.append ("</li>")
-- end
-- s.append ("</ul>")
-- l_page.set_title ("Create new content ...")
-- l_page.set_main_content (s)
-- l_page.execute
-- end
do_get_node_creation_by_type (req: WSF_REQUEST; res: WSF_RESPONSE; a_type_varname: READABLE_STRING_8; a_node_api: CMS_NODE_API)
local
l_page: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE
l_node: detachable CMS_NODE
do
create l_page.make (req, res, a_node_api.cms_api)
if
attached {WSF_STRING} req.path_parameter (a_type_varname) as p_type and then
attached a_node_api.content_type (p_type.value) as ct
then
l_node := ct.new_node (Void)
l_page.set_main_content (l_node.out)
end
l_page.execute
end
-- do_get_node_creation_by_type (req: WSF_REQUEST; res: WSF_RESPONSE; a_type_varname: READABLE_STRING_8; a_node_api: CMS_NODE_API)
-- local
-- l_page: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE
-- l_node: detachable CMS_NODE
-- do
-- create l_page.make (req, res, a_node_api.cms_api)
-- if
-- attached {WSF_STRING} req.path_parameter (a_type_varname) as p_type and then
-- attached a_node_api.content_type (p_type.value) as ct
-- then
-- l_node := ct.new_node (Void)
-- l_page.set_main_content (l_node.out)
-- end
-- l_page.execute
-- end
end

View File

@@ -231,7 +231,8 @@ feature {NONE} -- Implementation
l_parameters.put (a_node.id, "nid")
sql_change (sql_update_node, l_parameters)
if not error_handler.has_error then
a_node.set_revision (a_node.revision + 1) -- FIXME: Should be incremented by one, in same transaction...but check!
-- FIXED: FOR NOW no revision
-- a_node.set_revision (a_node.revision + 1) -- FIXME: Should be incremented by one, in same transaction...but check!
a_node.set_modification_date (now)
end
else
@@ -273,7 +274,9 @@ feature {NONE} -- Queries
sql_insert_node: STRING = "INSERT INTO nodes (revision, type, title, summary, content, format, publish, created, changed, author) VALUES (1, :type, :title, :summary, :content, :format, :publish, :created, :changed, :author);"
-- SQL Insert to add a new node.
sql_update_node : STRING = "UPDATE nodes SET revision = revision + 1, type=:type, title=:title, summary=:summary, content=:content, format=:format, publish=:publish, changed=:changed, revision = revision + 1, author=:author WHERE nid=:nid;"
sql_update_node : STRING = "UPDATE nodes SET revision = revision, type=:type, title=:title, summary=:summary, content=:content, format=:format, publish=:publish, changed=:changed, author=:author WHERE nid=:nid;"
-- FIXME: for now no revision inc.!
-- sql_update_node : STRING = "UPDATE nodes SET revision = revision + 1, type=:type, title=:title, summary=:summary, content=:content, format=:format, publish=:publish, changed=:changed, revision = revision + 1, author=:author WHERE nid=:nid;"
-- SQL node.
sql_delete_node: STRING = "DELETE FROM nodes WHERE nid=:nid;"

View File

@@ -147,25 +147,38 @@ feature -- Permissions system
feature -- Query: module
module (a_type: TYPE [CMS_MODULE]): detachable CMS_MODULE
module (a_type: TYPE [detachable CMS_MODULE]): detachable CMS_MODULE
-- Enabled module typed `a_type', if any.
--| usage: if attached module ({FOO_MODULE}) as mod then ...
local
t: STRING_8
l_type: TYPE [detachable CMS_MODULE]
do
t := a_type.name
if t.starts_with ("!") then
t.remove_head (1)
end
across
setup.modules as ic
until
Result /= Void
loop
Result := ic.item
if
not Result.is_enabled
or else Result.generating_type /~ a_type
then
if not Result.is_enabled then
Result := Void
else
l_type := Result.generating_type
if a_type ~ l_type then
-- Found
elseif t.same_string (l_type.name) then
-- Found
else
Result := Void
end
end
end
ensure
Result /= Void implies (Result.is_enabled and Result.generating_type ~ a_type)
Result /= Void implies (Result.is_enabled) -- and a_type.is_conforming_to (Result.generating_type))
end
module_api (a_type: TYPE [CMS_MODULE]): detachable CMS_MODULE_API

View File

@@ -1050,11 +1050,20 @@ feature {NONE} -- Execution
h := page.header
h.put_content_length (page.html.count)
h.put_current_date
h.put_header_object (header)
if attached redirection as l_location then
h.put_location (l_location)
-- FIXME: find out if this is safe or not.
if l_location.has_substring ("://") then
-- h.put_location (l_location)
response.redirect_now (l_location)
else
-- h.put_location (request.absolute_script_url (l_location))
response.redirect_now (request.absolute_script_url (l_location))
end
else
h.put_header_object (header)
response.send (page)
end
response.send (page)
on_terminated
end

View File

@@ -46,13 +46,22 @@ feature -- Status report
elseif a_user = Void then
Result := user_role_has_permission (anonymous_user_role, a_permission)
else
Result := user_role_has_permission (authenticated_user_role, a_permission)
if not Result then
Result := across user_roles (a_user) as ic some user_role_has_permission (ic.item, a_permission) end
if is_admin_user (a_user) then
Result := True
else
Result := user_role_has_permission (authenticated_user_role, a_permission)
if not Result then
Result := across user_roles (a_user) as ic some user_role_has_permission (ic.item, a_permission) end
end
end
end
end
is_admin_user (u: CMS_USER): BOOLEAN
do
Result := u.id = 1
end
user_roles (a_user: CMS_USER): LIST [CMS_USER_ROLE]
local
l_roles: detachable LIST [CMS_USER_ROLE]