Compare commits
39 Commits
ewf_v1_rec
...
es_rev9797
| Author | SHA1 | Date | |
|---|---|---|---|
| ed24eb7c94 | |||
| 43d6b4a197 | |||
| dffd06e331 | |||
| 463105f29f | |||
| abebd00a4f | |||
| ec53a2682b | |||
|
|
7b2e6ab7b4 | ||
|
|
87f4de1264 | ||
|
|
ed614a662c | ||
|
|
d54ad59e5f | ||
|
|
9173ef2ded | ||
|
|
ad9e908dc2 | ||
|
|
4584917877 | ||
|
|
f7d68d09e4 | ||
| f9ecd4956f | |||
| 18e159ad3c | |||
| 438259033a | |||
| 62e74ea6cd | |||
| 32a409b7e9 | |||
|
|
eb70af6f19 | ||
| 5f4eb2cf10 | |||
| 88bc52fffb | |||
|
|
544e6540ed | ||
| 2431d7af6c | |||
|
|
0d55bd67a2 | ||
|
|
e1727cc445 | ||
|
|
634a078282 | ||
|
|
2f65a084ac | ||
|
|
13df6fd593 | ||
| ad4f020d0e | |||
| 7a13b47131 | |||
| 923089baa1 | |||
| cfec9dc7f8 | |||
| b5e7d5d201 | |||
| e1bdcb965c | |||
| 0061afcbe8 | |||
| 6a9bc8aa42 | |||
| 1d7d79d69e | |||
| 46014da3d8 |
@@ -19,6 +19,7 @@
|
||||
<library name="cms_blog_module" location="..\..\modules\blog\cms_blog_module-safe.ecf" readonly="false"/>
|
||||
<library name="cms_demo_module" location="modules\demo\cms_demo_module-safe.ecf" readonly="false"/>
|
||||
<library name="cms_email_service" location="..\..\library\email\email-safe.ecf" readonly="false"/>
|
||||
<library name="cms_feed_aggregator_module" location="..\..\modules\feed_aggregator\feed_aggregator-safe.ecf" readonly="false"/>
|
||||
<library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/>
|
||||
<library name="cms_node_module" location="..\..\modules\node\node-safe.ecf" readonly="false"/>
|
||||
<library name="cms_oauth_20_module" location="..\..\modules\oauth20\oauth20-safe.ecf" readonly="false"/>
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
setlocal
|
||||
set ROC_CMD=%~dp0..\..\tools\roc.exe
|
||||
set ROC_CMD=call %~dp0..\..\tools\roc.bat
|
||||
set ROC_CMS_DIR=%~dp0
|
||||
|
||||
%ROC_CMD% install --module ..\..\modules\admin --dir %ROC_CMS_DIR%
|
||||
%ROC_CMD% install --module ..\..\modules\auth --dir %ROC_CMS_DIR%
|
||||
%ROC_CMD% install --module ..\..\modules\basic_auth --dir %ROC_CMS_DIR%
|
||||
%ROC_CMD% install --module ..\..\modules\node --dir %ROC_CMS_DIR%
|
||||
%ROC_CMD% install --module ..\..\modules\blog --dir %ROC_CMS_DIR%
|
||||
%ROC_CMD% install --module ..\..\modules\node --dir %ROC_CMS_DIR%
|
||||
%ROC_CMD% install --module ..\..\modules\oauth20 --dir %ROC_CMS_DIR%
|
||||
%ROC_CMD% install --module ..\..\modules\openid --dir %ROC_CMS_DIR%
|
||||
%ROC_CMD% install --module ..\..\modules\recent_changes --dir %ROC_CMS_DIR%
|
||||
%ROC_CMD% install --module ..\..\modules\feed_aggregator --dir %ROC_CMS_DIR%
|
||||
|
||||
@@ -93,7 +93,7 @@ feature -- Hooks
|
||||
|
||||
block_list: ITERABLE [like {CMS_BLOCK}.name]
|
||||
do
|
||||
Result := <<"demo-info">>
|
||||
Result := <<"?demo-info">>
|
||||
end
|
||||
|
||||
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
@@ -103,8 +103,8 @@ feature -- Hooks
|
||||
m: CMS_MENU
|
||||
lnk: CMS_LOCAL_LINK
|
||||
do
|
||||
if a_block_id.is_case_insensitive_equal_general ("demo-info") then
|
||||
if a_response.request.request_uri.starts_with ("/demo/") then
|
||||
if a_block_id.same_string ("demo-info") then
|
||||
if a_response.location.starts_with_general ("demo/") then
|
||||
create m.make_with_title (a_block_id, "Demo", 2)
|
||||
create lnk.make ("demo: abc", "demo/abc")
|
||||
m.extend (lnk)
|
||||
|
||||
@@ -20,7 +20,7 @@ smtp=localhost:25
|
||||
# Default is "on"
|
||||
# for each module, this can be overwritten with
|
||||
# module_name= on or off
|
||||
*=off
|
||||
*=all
|
||||
admin=on
|
||||
auth=on
|
||||
basic_auth=on
|
||||
@@ -31,6 +31,20 @@ node=on
|
||||
oauth20=on
|
||||
openid=on
|
||||
|
||||
[blocks]
|
||||
#navigation.region=sidebar_first
|
||||
feed.eiffel.region=feed_eiffel
|
||||
feed.eiffel.condition=is_front
|
||||
|
||||
feed.forum.region=feed_forum
|
||||
feed.forum.condition=is_front
|
||||
|
||||
feed.stackoverflow.region=feed_stackoverflow
|
||||
feed.stackoverflow.condition=is_front
|
||||
|
||||
#management.condition=is_front
|
||||
#navigation.condition=is_front
|
||||
|
||||
[admin]
|
||||
# CMS Installation, are accessible by "all", "none" or uppon "permission". (default is none)
|
||||
installation_access=permission
|
||||
|
||||
28
examples/demo/site/config/modules/feed_aggregator/feeds.json
Normal file
28
examples/demo/site/config/modules/feed_aggregator/feeds.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"ids": ["eiffel", "forum"],
|
||||
"feeds": {
|
||||
"eiffel": {
|
||||
"title": "Eiffel related posts.",
|
||||
"expiration": "21600",
|
||||
"size": 10,
|
||||
"locations": [
|
||||
"https://bertrandmeyer.com/feed/",
|
||||
"https://room.eiffel.com/blog/feed",
|
||||
"https://room.eiffel.com/article/feed",
|
||||
"https://room.eiffel.com/library/feed"
|
||||
]
|
||||
, "categories": ["Eiffel"]
|
||||
,"option_description": "enabled"
|
||||
},
|
||||
"forum": {
|
||||
"title": "Eiffel Forum",
|
||||
"expiration": "21600",
|
||||
"size": 10,
|
||||
"locations": [
|
||||
"https://groups.google.com/forum/feed/eiffel-users/msgs/atom.xml?num=15".
|
||||
"http://stackoverflow.com/feeds/tag?tagnames=eiffel&sort=newest"
|
||||
]
|
||||
,"option_description": "enabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,10 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>You have required a new password at <a href="...">ROC CMS</a></p>
|
||||
<p>You have required a new password at <a href="$host">ROC CMS</a></p>
|
||||
|
||||
<p>To complete your request, please click on this link to genereate a new password:<p>
|
||||
|
||||
<p><a href="$link">$link</a></p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>You have request a new activation token at<a href="...">ROC CMS</a></p>
|
||||
<p>You have request a new activation token at <a href="$host">ROC CMS</a></p>
|
||||
|
||||
<p>To complete your registration, please click on this link to activate your account:<p>
|
||||
|
||||
<p><a href="$link">$link</a></p>
|
||||
<p>Thank you for joining us.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<meta name="author" content="ROC CMS">
|
||||
</head>
|
||||
<body>
|
||||
<p>Welcome to<a href="...">ROC CMS</a></p>
|
||||
<p>Welcome to<a href="$host">ROC CMS</a></p>
|
||||
<p>Thank you for joining us.</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -25,5 +25,5 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{/unless}
|
||||
</div>
|
||||
{/unless}
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,7 @@ ROC_AUTH.login = function() {
|
||||
var newdiv = document.createElement('div');
|
||||
newdiv.innerHTML = "<br>Invalid Credentials</br>";
|
||||
newdiv.id = 'myModalFormId';
|
||||
$("body").append(newdiv);
|
||||
$(".primary-tabs").append(newdiv);
|
||||
}
|
||||
}else{
|
||||
|
||||
@@ -49,7 +49,7 @@ ROC_AUTH.login = function() {
|
||||
var newdiv = document.createElement('div');
|
||||
newdiv.innerHTML = "<br>Invalid Credentials</br>";
|
||||
newdiv.id = 'myModalFormId';
|
||||
$("body").append(newdiv);
|
||||
$(".primary-tabs").append(newdiv);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -93,7 +93,7 @@ ROC_AUTH.login_with_redirect = function() {
|
||||
var newdiv = document.createElement('div');
|
||||
newdiv.innerHTML = "<br>Invalid Credentials</br>";
|
||||
newdiv.id = 'myModalFormId';
|
||||
$("body").append(newdiv);
|
||||
$(".primary-tabs").append(newdiv);
|
||||
$("#imgProgressRedirect").hide();
|
||||
}
|
||||
}else{
|
||||
@@ -122,8 +122,8 @@ ROC_AUTH.login_with_redirect = function() {
|
||||
var newdiv = document.createElement('div');
|
||||
newdiv.innerHTML = "<br>Invalid Credentials</br>";
|
||||
newdiv.id = 'myModalFormId';
|
||||
$("body").append(newdiv);
|
||||
$("#imgProgressRedirect").hide();
|
||||
$(".primary-tabs").append(newdiv);
|
||||
$("#imgProgressRedirect").hide();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
<div>
|
||||
<form name="cms_basic_auth" action method="POST">
|
||||
<div>
|
||||
<input type="text" name="username" required>
|
||||
<input type="text" name="username" id="username" required>
|
||||
<label>Username</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input type="password" name="password" required>
|
||||
<input type="password" name="password" id="password" required>
|
||||
<label>Password</label>
|
||||
</div>
|
||||
|
||||
@@ -25,10 +25,5 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{foreach item="item" from="$oauth_consumers"}
|
||||
<a href="{$site_url/}account/login-with-oauth/{$item/}">Login with {$item/}</a><br>
|
||||
{/foreach}
|
||||
</div>
|
||||
{/unless}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
div.feed ul {
|
||||
list-style: none;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 99%;
|
||||
}
|
||||
div.feed li {
|
||||
/* border-top: solid 1px #ddd; */
|
||||
padding: 0;
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
div.feed li a {
|
||||
font-weight: bold;
|
||||
}
|
||||
div.feed li .date {
|
||||
font-weight: bold;
|
||||
font-size: small;
|
||||
}
|
||||
div.feed li .category {
|
||||
margin-left: 20px;
|
||||
font-size: 8px;
|
||||
height: 9px;
|
||||
overflow: hidden;
|
||||
color: #999;
|
||||
}
|
||||
div.feed li .description {
|
||||
margin-left: 20px;
|
||||
font-size: small;
|
||||
height: 18px;
|
||||
overflow: hidden;
|
||||
color: #999;
|
||||
}
|
||||
div.feed li:hover {
|
||||
margin-bottom: 23px;
|
||||
}
|
||||
div.feed li:hover .description {
|
||||
padding: 5px;
|
||||
position: absolute;
|
||||
height: auto;
|
||||
overflow-y: scroll;
|
||||
overflow-x: scroll;
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
border: solid 1px #000;
|
||||
z-index: 10;
|
||||
}
|
||||
div.feed li:hover:last-child {
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
div.feed li .description::after {
|
||||
content: "...";
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
div.feed {
|
||||
ul {
|
||||
list-style: none;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 99%;
|
||||
}
|
||||
li {
|
||||
/* border-top: solid 1px #ddd; */
|
||||
padding: 0;
|
||||
margin: 0 0 5px 0;
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
}
|
||||
.date {
|
||||
font-weight: bold;
|
||||
font-size: small;
|
||||
}
|
||||
.category {
|
||||
margin-left: 20px;
|
||||
font-size: 8px;
|
||||
height: 9px;
|
||||
overflow: hidden;
|
||||
color: #999;
|
||||
}
|
||||
.description {
|
||||
margin-left: 20px;
|
||||
font-size: small;
|
||||
height: 18px;
|
||||
overflow: hidden;
|
||||
color: #999;
|
||||
}
|
||||
&:hover {
|
||||
margin-bottom: 23px;
|
||||
.description {
|
||||
padding: 5px;
|
||||
position: absolute;
|
||||
height: auto;
|
||||
overflow-y: scroll;
|
||||
overflow-x: scroll;
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
border: solid 1px #000;
|
||||
z-index: 10;
|
||||
}
|
||||
&:last-child {
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
}
|
||||
.description::after { content: "..."; }
|
||||
}
|
||||
}
|
||||
@@ -62,9 +62,15 @@
|
||||
<!-- Main Content Section -->
|
||||
{unless isempty="$page_title"}<h1 class="page-title">{$page_title/}</h1>{/unless}
|
||||
{$page.region_content/}
|
||||
{if condition="$page.is_front"}
|
||||
{if isset="$page.region_feed_eiffel"}
|
||||
<div class="column" style="width: 45%; float: left">{$page.region_feed_eiffel/}</div>
|
||||
{/if}
|
||||
{if isset="$page.region_feed_forum"}
|
||||
<div class="column" style="width: 45%; float: left">{$page.region_feed_forum/}</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -82,6 +82,9 @@ feature -- CMS setup
|
||||
create {CMS_RECENT_CHANGES_MODULE} m.make
|
||||
a_setup.register_module (m)
|
||||
|
||||
-- Recent changes
|
||||
create {FEED_AGGREGATOR_MODULE} m.make
|
||||
a_setup.register_module (m)
|
||||
|
||||
-- Miscellanious
|
||||
create {CMS_DEBUG_MODULE} m.make
|
||||
|
||||
@@ -33,11 +33,53 @@ feature -- Query
|
||||
end
|
||||
end
|
||||
|
||||
resolved_text_list_item (k: READABLE_STRING_GENERAL): detachable LIST [READABLE_STRING_32]
|
||||
-- List of String item associated with key `k',
|
||||
-- and expanded values to resolved variables ${varname}.
|
||||
do
|
||||
if attached text_list_item (k) as lst then
|
||||
from
|
||||
lst.start
|
||||
until
|
||||
lst.after
|
||||
loop
|
||||
lst.replace (resolved_expression (lst.item))
|
||||
lst.forth
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
resolved_text_table_item (k: READABLE_STRING_GENERAL): detachable STRING_TABLE [READABLE_STRING_32]
|
||||
-- Table of String item associated with key `k',
|
||||
-- and expanded values to resolved variables ${varname}.
|
||||
do
|
||||
if attached text_table_item (k) as tb then
|
||||
from
|
||||
tb.start
|
||||
until
|
||||
tb.after
|
||||
loop
|
||||
tb.replace (resolved_expression (tb.item_for_iteration), tb.key_for_iteration)
|
||||
tb.forth
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
text_item (k: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
|
||||
-- String item associated with key `k'.
|
||||
deferred
|
||||
end
|
||||
|
||||
text_list_item (k: READABLE_STRING_GENERAL): detachable LIST [READABLE_STRING_32]
|
||||
-- List of String item associated with key `k'.
|
||||
deferred
|
||||
end
|
||||
|
||||
text_table_item (k: READABLE_STRING_GENERAL): detachable STRING_TABLE [READABLE_STRING_32]
|
||||
-- Table of String item associated with key `k'.
|
||||
deferred
|
||||
end
|
||||
|
||||
integer_item (k: READABLE_STRING_GENERAL): INTEGER
|
||||
-- Integer item associated with key `k'.
|
||||
deferred
|
||||
@@ -109,7 +151,7 @@ feature -- Duplication
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
|
||||
copyright: "2011-2015, Jocelyn Fiat, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -119,14 +119,47 @@ feature -- Access: Config Reader
|
||||
|
||||
text_item (k: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
|
||||
-- String item associated with key `k'.
|
||||
local
|
||||
obj: like item
|
||||
do
|
||||
obj := item (k)
|
||||
if attached {READABLE_STRING_32} obj as s32 then
|
||||
Result := s32
|
||||
elseif attached {READABLE_STRING_8} obj as s then
|
||||
Result := utf.utf_8_string_8_to_escaped_string_32 (s)
|
||||
Result := value_to_string_32 (item (k))
|
||||
end
|
||||
|
||||
text_list_item (k: READABLE_STRING_GENERAL): detachable LIST [READABLE_STRING_32]
|
||||
-- List of String item associated with key `k'.
|
||||
do
|
||||
if attached {LIST [READABLE_STRING_8]} item (k) as l_list then
|
||||
create {ARRAYED_LIST [READABLE_STRING_32]} Result.make (l_list.count)
|
||||
Result.compare_objects
|
||||
across
|
||||
l_list as ic
|
||||
until
|
||||
Result = Void
|
||||
loop
|
||||
if attached value_to_string_32 (ic.item) as s32 then
|
||||
Result.force (s32)
|
||||
else
|
||||
Result := Void
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
text_table_item (k: READABLE_STRING_GENERAL): detachable STRING_TABLE [READABLE_STRING_32]
|
||||
-- Table of String item associated with key `k'.
|
||||
do
|
||||
if attached {STRING_TABLE [READABLE_STRING_8]} item (k) as l_list then
|
||||
create {STRING_TABLE [READABLE_STRING_32]} Result.make (l_list.count)
|
||||
Result.compare_objects
|
||||
across
|
||||
l_list as ic
|
||||
until
|
||||
Result = Void
|
||||
loop
|
||||
if attached value_to_string_32 (ic.item) as s32 then
|
||||
Result.force (s32, ic.key)
|
||||
else
|
||||
Result := Void
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -226,6 +259,15 @@ feature -- Access
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
value_to_string_32 (obj: detachable ANY): detachable STRING_32
|
||||
do
|
||||
if attached {READABLE_STRING_32} obj as s32 then
|
||||
Result := s32
|
||||
elseif attached {READABLE_STRING_8} obj as s then
|
||||
Result := utf.utf_8_string_8_to_escaped_string_32 (s)
|
||||
end
|
||||
end
|
||||
|
||||
item_from_values (a_values: STRING_TABLE [ANY]; k: READABLE_STRING_GENERAL): detachable ANY
|
||||
local
|
||||
i,j: INTEGER
|
||||
@@ -460,7 +502,7 @@ feature {NONE} -- Implementation
|
||||
invariant
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
|
||||
copyright: "2011-2015, Jocelyn Fiat, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -63,10 +63,46 @@ feature -- Access: Config Reader
|
||||
text_item (k: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
|
||||
-- String item associated with query `k'.
|
||||
do
|
||||
if attached {JSON_STRING} item (k) as l_string then
|
||||
Result := l_string.unescaped_string_32
|
||||
elseif attached {JSON_NUMBER} item (k) as l_number then
|
||||
Result := l_number.item
|
||||
Result := value_to_string_32 (item (k))
|
||||
end
|
||||
|
||||
text_list_item (k: READABLE_STRING_GENERAL): detachable LIST [READABLE_STRING_32]
|
||||
-- List of String item associated with key `k'.
|
||||
do
|
||||
if attached {JSON_ARRAY} item (k) as l_array then
|
||||
create {ARRAYED_LIST [READABLE_STRING_32]} Result.make (l_array.count)
|
||||
Result.compare_objects
|
||||
across
|
||||
l_array as ic
|
||||
until
|
||||
Result = Void
|
||||
loop
|
||||
if attached value_to_string_32 (ic.item) as s32 then
|
||||
Result.force (s32)
|
||||
else
|
||||
Result := Void
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
text_table_item (k: READABLE_STRING_GENERAL): detachable STRING_TABLE [READABLE_STRING_32]
|
||||
-- Table of String item associated with key `k'.
|
||||
do
|
||||
if attached {JSON_OBJECT} item (k) as obj then
|
||||
create {STRING_TABLE [READABLE_STRING_32]} Result.make (obj.count)
|
||||
Result.compare_objects
|
||||
across
|
||||
obj as ic
|
||||
until
|
||||
Result = Void
|
||||
loop
|
||||
if attached value_to_string_32 (ic.item) as s32 then
|
||||
Result.force (s32, ic.key.item)
|
||||
else
|
||||
Result := Void
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -105,6 +141,15 @@ feature -- Access
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
value_to_string_32 (v: detachable ANY): detachable STRING_32
|
||||
do
|
||||
if attached {JSON_STRING} v as l_string then
|
||||
Result := l_string.unescaped_string_32
|
||||
elseif attached {JSON_NUMBER} v as l_number then
|
||||
Result := l_number.item
|
||||
end
|
||||
end
|
||||
|
||||
object_json_value (a_object: JSON_OBJECT; a_query: READABLE_STRING_32): detachable JSON_VALUE
|
||||
-- Item associated with query `a_query' from object `a_object' if any.
|
||||
local
|
||||
@@ -163,7 +208,7 @@ feature {NONE} -- JSON
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
|
||||
copyright: "2011-2015, Jocelyn Fiat, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -21,6 +21,18 @@ feature -- Test
|
||||
create {INI_CONFIG} cfg.make_from_string ("[
|
||||
foo = bar
|
||||
|
||||
collection[] = a
|
||||
collection[] = b
|
||||
collection[] = c
|
||||
collection[] = 1
|
||||
collection[] = 2
|
||||
collection[] = 3
|
||||
|
||||
table[a] = 1
|
||||
table[b] = 2
|
||||
table[c] = 3
|
||||
table[d] = test
|
||||
|
||||
[first]
|
||||
abc = 1
|
||||
def = and so on
|
||||
@@ -58,6 +70,21 @@ feature -- Test
|
||||
assert ("has_item (second.is)", cfg.has_item ("second.is"))
|
||||
assert ("item (second.is)", attached cfg.text_item ("second.is") as v and then v.same_string_general ("2"))
|
||||
|
||||
assert ("has_item (collection)", cfg.has_item ("collection"))
|
||||
assert ("item (collection)", attached cfg.text_list_item ("collection") as lst and then (
|
||||
lst.has ("a") and lst.has ("b") and lst.has ("c") and lst.has ("1") and lst.has ("2") and lst.has ("3")
|
||||
)
|
||||
)
|
||||
|
||||
assert ("has_item (table)", cfg.has_item ("table"))
|
||||
assert ("item (table)", attached cfg.text_table_item ("table") as tb and then (
|
||||
tb.item ("a") ~ {STRING_32} "1" and
|
||||
tb.item ("b") ~ {STRING_32} "2" and
|
||||
tb.item ("c") ~ {STRING_32} "3" and
|
||||
tb.item ("d") ~ {STRING_32} "test"
|
||||
)
|
||||
)
|
||||
|
||||
if attached cfg.sub_config ("second") as cfg_second then
|
||||
assert ("has_item (is)", cfg_second.has_item ("is"))
|
||||
assert ("item (is)", attached cfg_second.text_item ("is") as v and then v.same_string_general ("2"))
|
||||
@@ -141,7 +168,9 @@ feature -- Test
|
||||
"is": 2,
|
||||
"the": 3,
|
||||
"end": 4
|
||||
}
|
||||
},
|
||||
"collection": ["a", "b", "c", 1, 2, 3],
|
||||
"table": { "a": 1, "b": 2, "c": 3, "d" : "test" }
|
||||
}
|
||||
]")
|
||||
|
||||
@@ -164,6 +193,21 @@ feature -- Test
|
||||
assert ("item (second.the)", attached cfg.text_item ("second.the") as v and then v.same_string_general ("3"))
|
||||
assert ("item (second.end)", attached cfg.text_item ("second.end") as v and then v.same_string_general ("4"))
|
||||
|
||||
assert ("has_item (collection)", cfg.has_item ("collection"))
|
||||
assert ("item (collection)", attached cfg.text_list_item ("collection") as lst and then (
|
||||
lst.has ("a") and lst.has ("b") and lst.has ("c") and lst.has ("1") and lst.has ("2") and lst.has ("3")
|
||||
)
|
||||
)
|
||||
|
||||
assert ("has_item (table)", cfg.has_item ("table"))
|
||||
assert ("item (table)", attached cfg.text_table_item ("table") as tb and then (
|
||||
tb.item ("a") ~ {STRING_32} "1" and
|
||||
tb.item ("b") ~ {STRING_32} "2" and
|
||||
tb.item ("c") ~ {STRING_32} "3" and
|
||||
tb.item ("d") ~ {STRING_32} "test"
|
||||
)
|
||||
)
|
||||
|
||||
if attached cfg.sub_config ("second") as cfg_second then
|
||||
assert ("has_item (is)", cfg_second.has_item ("is"))
|
||||
assert ("item (is)", attached cfg_second.text_item ("is") as v and then v.same_string_general ("2"))
|
||||
|
||||
@@ -28,7 +28,6 @@ feature {NONE} -- Initialization
|
||||
-- Initialize service.
|
||||
do
|
||||
admin_email := parameters.admin_email
|
||||
|
||||
create {NOTIFICATION_SMTP_MAILER} mailer.make (parameters.smtp_server)
|
||||
set_successful
|
||||
end
|
||||
|
||||
@@ -90,6 +90,7 @@ feature -- Security
|
||||
Result.force ("admin users")
|
||||
Result.force ("admin roles")
|
||||
Result.force ("admin modules")
|
||||
Result.force ("install modules")
|
||||
end
|
||||
|
||||
feature -- Hooks
|
||||
|
||||
@@ -84,7 +84,7 @@ feature -- Process Edit
|
||||
do
|
||||
create b.make_empty
|
||||
f := new_edit_form (a_role, url (request.percent_encoded_path_info, Void), "edit-user")
|
||||
invoke_form_alter (f, fd)
|
||||
hooks.invoke_form_alter (f, fd, Current)
|
||||
if request.is_post_request_method then
|
||||
f.validation_actions.extend (agent edit_form_validate(?,a_role, b))
|
||||
f.submit_actions.extend (agent edit_form_submit(?, a_role, b))
|
||||
@@ -117,7 +117,7 @@ feature -- Process Delete
|
||||
do
|
||||
create b.make_empty
|
||||
f := new_delete_form (a_role, url (request.percent_encoded_path_info, Void), "edit-user")
|
||||
invoke_form_alter (f, fd)
|
||||
hooks.invoke_form_alter (f, fd, Current)
|
||||
if request.is_post_request_method then
|
||||
f.process (Current)
|
||||
fd := f.last_data
|
||||
@@ -149,7 +149,7 @@ feature -- Process New
|
||||
do
|
||||
create b.make_empty
|
||||
f := new_edit_form (l_role, url (request.percent_encoded_path_info, Void), "create-role")
|
||||
invoke_form_alter (f, fd)
|
||||
hooks.invoke_form_alter (f, fd, Current)
|
||||
if request.is_post_request_method then
|
||||
f.validation_actions.extend (agent new_form_validate(?, b))
|
||||
f.submit_actions.extend (agent edit_form_submit(?, l_role, b))
|
||||
|
||||
@@ -86,7 +86,7 @@ feature -- Process Edit
|
||||
do
|
||||
create b.make_empty
|
||||
f := new_edit_form (a_user, url (location, Void), "edit-user")
|
||||
invoke_form_alter (f, fd)
|
||||
hooks.invoke_form_alter (f, fd, Current)
|
||||
if request.is_post_request_method then
|
||||
f.submit_actions.extend (agent edit_form_submit (?, a_user, b))
|
||||
f.process (Current)
|
||||
@@ -118,7 +118,7 @@ feature -- Process Delete
|
||||
do
|
||||
create b.make_empty
|
||||
f := new_delete_form (a_user, url (location, Void), "edit-user")
|
||||
invoke_form_alter (f, fd)
|
||||
hooks.invoke_form_alter (f, fd, Current)
|
||||
if request.is_post_request_method then
|
||||
f.process (Current)
|
||||
fd := f.last_data
|
||||
@@ -151,7 +151,7 @@ feature -- Process New
|
||||
do
|
||||
create b.make_empty
|
||||
f := new_edit_form (l_user, url (location, Void), "create-user")
|
||||
invoke_form_alter (f, fd)
|
||||
hooks.invoke_form_alter (f, fd, Current)
|
||||
if request.is_post_request_method then
|
||||
f.validation_actions.extend (agent new_form_validate (?, b))
|
||||
f.submit_actions.extend (agent edit_form_submit (?, l_user, b))
|
||||
|
||||
@@ -521,26 +521,26 @@ feature {NONE} -- Helpers
|
||||
|
||||
feature {NONE} -- Block views
|
||||
|
||||
get_block_view_login (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
local
|
||||
-- vals: CMS_VALUE_TABLE
|
||||
do
|
||||
if attached template_block (a_block_id, a_response) as l_tpl_block then
|
||||
-- create vals.make (1)
|
||||
-- -- add the variable to the block
|
||||
-- value_table_alter (vals, a_response)
|
||||
-- across
|
||||
-- vals as ic
|
||||
-- loop
|
||||
-- l_tpl_block.set_value (ic.item, ic.key)
|
||||
-- get_block_view_login (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
-- local
|
||||
---- vals: CMS_VALUE_TABLE
|
||||
-- do
|
||||
-- if attached template_block (a_block_id, a_response) as l_tpl_block then
|
||||
---- create vals.make (1)
|
||||
---- -- add the variable to the block
|
||||
---- value_table_alter (vals, a_response)
|
||||
---- across
|
||||
---- vals as ic
|
||||
---- loop
|
||||
---- l_tpl_block.set_value (ic.item, ic.key)
|
||||
---- end
|
||||
-- a_response.put_required_block (l_tpl_block, "content")
|
||||
-- else
|
||||
-- debug ("cms")
|
||||
-- a_response.add_warning_message ("Error with block [" + a_block_id + "]")
|
||||
-- end
|
||||
a_response.add_block (l_tpl_block, "content")
|
||||
else
|
||||
debug ("cms")
|
||||
a_response.add_warning_message ("Error with block [" + a_block_id + "]")
|
||||
end
|
||||
end
|
||||
end
|
||||
-- end
|
||||
-- end
|
||||
|
||||
get_block_view_register (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
do
|
||||
@@ -579,7 +579,6 @@ feature {NONE} -- Block views
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
get_block_view_reactivate (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
do
|
||||
if a_response.request.is_get_request_method then
|
||||
|
||||
@@ -47,6 +47,7 @@ feature -- HTTP Methods
|
||||
l_page: CMS_RESPONSE
|
||||
l_url: STRING
|
||||
i: INTEGER
|
||||
l_message: STRING
|
||||
do
|
||||
api.logger.put_information (generator + ".do_get Processing basic auth logoff", Void)
|
||||
if attached req.query_parameter ("prompt") as l_prompt then
|
||||
@@ -72,6 +73,10 @@ feature -- HTTP Methods
|
||||
l_page.set_status_code ({HTTP_STATUS_CODE}.found)
|
||||
l_page.set_redirection (l_url)
|
||||
end
|
||||
create l_message.make_from_string (logout_message)
|
||||
l_message.replace_substring_all ("$site_login", req.absolute_script_url ("/account/roc-login"))
|
||||
l_message.replace_substring_all ("$site_home", req.absolute_script_url (""))
|
||||
l_page.set_main_content (l_message)
|
||||
l_page.execute
|
||||
end
|
||||
end
|
||||
@@ -113,4 +118,15 @@ feature -- HTTP Methods
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature {NONE}-- Lougout Message
|
||||
|
||||
logout_message: STRING = "[
|
||||
<div class="cms-logout-message">
|
||||
<h2>You are now signed out</h2>
|
||||
<p>You can <a href="$site_login">log</a> in again, or go to the <a href="$site_home">front page</a>.</p>
|
||||
</div>
|
||||
]"
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -25,7 +25,7 @@ ROC_AUTH.login = function() {
|
||||
var newdiv = document.createElement('div');
|
||||
newdiv.innerHTML = "<br>Invalid Credentials</br>";
|
||||
newdiv.id = 'myModalFormId';
|
||||
$("body").append(newdiv);
|
||||
$(".primary-tabs").append(newdiv);
|
||||
}
|
||||
}else{
|
||||
|
||||
@@ -49,7 +49,7 @@ ROC_AUTH.login = function() {
|
||||
var newdiv = document.createElement('div');
|
||||
newdiv.innerHTML = "<br>Invalid Credentials</br>";
|
||||
newdiv.id = 'myModalFormId';
|
||||
$("body").append(newdiv);
|
||||
$(".primary-tabs").append(newdiv);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -93,7 +93,7 @@ ROC_AUTH.login_with_redirect = function() {
|
||||
var newdiv = document.createElement('div');
|
||||
newdiv.innerHTML = "<br>Invalid Credentials</br>";
|
||||
newdiv.id = 'myModalFormId';
|
||||
$("body").append(newdiv);
|
||||
$(".primary-tabs").append(newdiv);
|
||||
$("#imgProgressRedirect").hide();
|
||||
}
|
||||
}else{
|
||||
@@ -122,8 +122,8 @@ ROC_AUTH.login_with_redirect = function() {
|
||||
var newdiv = document.createElement('div');
|
||||
newdiv.innerHTML = "<br>Invalid Credentials</br>";
|
||||
newdiv.id = 'myModalFormId';
|
||||
$("body").append(newdiv);
|
||||
$("#imgProgressRedirect").hide();
|
||||
$(".primary-tabs").append(newdiv);
|
||||
$("#imgProgressRedirect").hide();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
<div>
|
||||
<form name="cms_basic_auth" action method="POST">
|
||||
<div>
|
||||
<input type="text" name="username" required>
|
||||
<input type="text" name="username" id="username" required>
|
||||
<label>Username</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input type="password" name="password" required>
|
||||
<input type="password" name="password" id="password" required>
|
||||
<label>Password</label>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -108,6 +108,18 @@ feature -- Persistence
|
||||
end
|
||||
end
|
||||
|
||||
delete_node (a_node: CMS_BLOG)
|
||||
-- <Precursor>
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
if a_node.has_id then
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_node.id, "nid")
|
||||
sql_change (sql_delete_node_data, l_parameters)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
node_data (a_node: CMS_NODE): detachable TUPLE [revision: INTEGER_64; tags: READABLE_STRING_32]
|
||||
@@ -136,12 +148,15 @@ feature {NONE} -- Implementation
|
||||
check unique_data: n = 0 end
|
||||
end
|
||||
end
|
||||
ensure
|
||||
accepted_revision: Result /= Void implies Result.revision <= a_node.revision
|
||||
end
|
||||
|
||||
feature -- SQL
|
||||
|
||||
sql_select_node_data: STRING = "SELECT nid, revision, tags FROM blog_post_nodes WHERE nid =:nid AND revision<=:revision ORDER BY revision DESC LIMIT 1;"
|
||||
sql_select_node_data: STRING = "SELECT nid, revision, tags FROM blog_post_nodes WHERE nid=:nid AND revision<=:revision ORDER BY revision DESC LIMIT 1;"
|
||||
sql_insert_node_data: STRING = "INSERT INTO blog_post_nodes (nid, revision, tags) VALUES (:nid, :revision, :tags);"
|
||||
sql_update_node_data: STRING = "UPDATE blog_post_nodes SET nid=:nid, revision=:revision, tags=:tags WHERE nid=:nid AND revision=:revision;"
|
||||
sql_delete_node_data: STRING = "DELETE FROM blog_post_nodes WHERE nid=:nid;"
|
||||
|
||||
end
|
||||
|
||||
115
modules/feed_aggregator/feed_aggregation.e
Normal file
115
modules/feed_aggregator/feed_aggregation.e
Normal file
@@ -0,0 +1,115 @@
|
||||
note
|
||||
description: "Feed aggregation parameters."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
FEED_AGGREGATION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_name: READABLE_STRING_GENERAL)
|
||||
do
|
||||
create name.make_from_string_general (a_name)
|
||||
create {ARRAYED_LIST [READABLE_STRING_8]} locations.make (0)
|
||||
expiration := 60*60
|
||||
description_enabled := True
|
||||
size := 10
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: IMMUTABLE_STRING_32
|
||||
-- Associated name.
|
||||
|
||||
expiration: INTEGER
|
||||
-- Suggested expiration time in seconds (default: 1 hour).
|
||||
-- If negative then never expires.
|
||||
|
||||
size: INTEGER
|
||||
-- Number of entries to display per page.
|
||||
|
||||
description: detachable IMMUTABLE_STRING_32
|
||||
-- Optional description.
|
||||
|
||||
locations: LIST [READABLE_STRING_8]
|
||||
-- List of feed location aggregated into current.
|
||||
|
||||
included_categories: detachable LIST [READABLE_STRING_32]
|
||||
-- Optional categories to filter.
|
||||
-- If Void, include any.
|
||||
|
||||
description_enabled: BOOLEAN
|
||||
-- Display description?
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_description (a_desc: detachable READABLE_STRING_GENERAL)
|
||||
do
|
||||
if a_desc = Void then
|
||||
description := Void
|
||||
else
|
||||
create description.make_from_string_general (a_desc)
|
||||
end
|
||||
end
|
||||
|
||||
set_expiration (nb_seconds: INTEGER)
|
||||
-- Set `expiration' to `nb_seconds'.
|
||||
do
|
||||
expiration := nb_seconds
|
||||
end
|
||||
|
||||
set_size (nb: INTEGER)
|
||||
-- Set `size' to `nb'.
|
||||
do
|
||||
size := nb
|
||||
end
|
||||
|
||||
set_description_enabled (b: BOOLEAN)
|
||||
-- Set `description_enabled' to `b'.
|
||||
do
|
||||
description_enabled := b
|
||||
end
|
||||
|
||||
reset_categories
|
||||
do
|
||||
included_categories := Void
|
||||
end
|
||||
|
||||
include_category (a_cat: READABLE_STRING_GENERAL)
|
||||
local
|
||||
lst: like included_categories
|
||||
s32: STRING_32
|
||||
do
|
||||
lst := included_categories
|
||||
if lst = Void then
|
||||
create {ARRAYED_LIST [READABLE_STRING_32]} lst.make (1)
|
||||
included_categories := lst
|
||||
lst.compare_objects
|
||||
end
|
||||
s32 := a_cat.to_string_32
|
||||
if not lst.has (s32) then
|
||||
lst.force (s32)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_included (e: FEED_ITEM): BOOLEAN
|
||||
do
|
||||
Result := True
|
||||
if attached e.categories as e_cats then
|
||||
if attached included_categories as lst then
|
||||
Result := across lst as ic some
|
||||
across e_cats as e_ic some
|
||||
e_ic.item.same_string (ic.item)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
19
modules/feed_aggregator/feed_aggregator-safe.ecf
Normal file
19
modules/feed_aggregator/feed_aggregator-safe.ecf
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-14-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-14-0 http://www.eiffel.com/developers/xml/configuration-1-14-0.xsd" name="feed_aggregator" uuid="6A78AB37-9B07-4C42-9E24-0CA7D3C61E12" library_target="feed_aggregator">
|
||||
<target name="feed_aggregator">
|
||||
<root all_classes="true"/>
|
||||
<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="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<library name="cms" location="..\..\cms-safe.ecf"/>
|
||||
<library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/>
|
||||
<library name="error" location="$ISE_LIBRARY\contrib\library\utility\general\error\error-safe.ecf"/>
|
||||
<library name="feed" location="$ISE_LIBRARY\contrib\library\text\parser\feed\feed-safe.ecf"/>
|
||||
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="http_client" location="$ISE_LIBRARY\contrib\library\network\http_client\http_client-safe.ecf"/>
|
||||
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
|
||||
<library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_html" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf_html\wsf_html-safe.ecf" readonly="false"/>
|
||||
<cluster name="src" location="." recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
146
modules/feed_aggregator/feed_aggregator_api.e
Normal file
146
modules/feed_aggregator/feed_aggregator_api.e
Normal file
@@ -0,0 +1,146 @@
|
||||
note
|
||||
description: "API for Feed aggregator module."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
FEED_AGGREGATOR_API
|
||||
|
||||
inherit
|
||||
CMS_MODULE_API
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Access
|
||||
|
||||
aggregations: HASH_TABLE [FEED_AGGREGATION, STRING]
|
||||
-- List of feed aggregations.
|
||||
local
|
||||
agg: FEED_AGGREGATION
|
||||
l_feed_id: READABLE_STRING_32
|
||||
l_title: detachable READABLE_STRING_GENERAL
|
||||
l_location_list: detachable LIST [READABLE_STRING_32]
|
||||
utf: UTF_CONVERTER
|
||||
l_table: like internal_aggregations
|
||||
do
|
||||
l_table := internal_aggregations
|
||||
if l_table /= Void then
|
||||
Result := l_table
|
||||
else
|
||||
create Result.make (0)
|
||||
internal_aggregations := Result
|
||||
if attached cms_api.module_configuration_by_name ({FEED_AGGREGATOR_MODULE}.name, "feeds") as cfg then
|
||||
if attached cfg.text_list_item ("ids") as l_ids then
|
||||
across
|
||||
l_ids as ic
|
||||
loop
|
||||
l_feed_id := ic.item
|
||||
l_location_list := cfg.text_list_item ({STRING_32} "feeds." + l_feed_id + ".locations")
|
||||
if
|
||||
attached cfg.text_item ({STRING_32} "feeds." + l_feed_id + ".location") as l_location
|
||||
then
|
||||
if l_location_list = Void then
|
||||
create {ARRAYED_LIST [READABLE_STRING_32]} l_location_list.make (1)
|
||||
end
|
||||
l_location_list.force (l_location)
|
||||
end
|
||||
if l_location_list /= Void and then not l_location_list.is_empty then
|
||||
l_title := cfg.text_item ({STRING_32} "feeds." + l_feed_id + ".title")
|
||||
if l_title = Void then
|
||||
l_title := l_feed_id
|
||||
end
|
||||
create agg.make (l_title)
|
||||
if attached cfg.text_item ({STRING_32} "feeds." + l_feed_id + ".expiration") as l_expiration then
|
||||
if l_expiration.is_integer then
|
||||
agg.set_expiration (l_expiration.to_integer)
|
||||
end
|
||||
end
|
||||
if attached cfg.text_item ({STRING_32} "feeds." + l_feed_id + ".size") as l_size then
|
||||
if l_size.is_integer then
|
||||
agg.set_size (l_size.to_integer)
|
||||
end
|
||||
end
|
||||
if attached cfg.text_item ({STRING_32} "feeds." + l_feed_id + ".option_description") as l_description_opt then
|
||||
agg.set_description_enabled (not l_description_opt.is_case_insensitive_equal_general ("disabled"))
|
||||
end
|
||||
across
|
||||
l_location_list as loc_ic
|
||||
loop
|
||||
agg.locations.force (utf.utf_32_string_to_utf_8_string_8 (loc_ic.item))
|
||||
end
|
||||
Result.force (agg, l_feed_id)
|
||||
if attached cfg.text_list_item ({STRING_32} "feeds." + l_feed_id + ".categories") as l_cats then
|
||||
across
|
||||
l_cats as cats_ic
|
||||
loop
|
||||
agg.include_category (cats_ic.item)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
aggregation (a_name: READABLE_STRING_GENERAL): detachable FEED_AGGREGATION
|
||||
do
|
||||
if attached a_name.is_valid_as_string_8 then
|
||||
Result := aggregations.item (a_name.as_string_8)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Access: implementation
|
||||
|
||||
internal_aggregations: detachable like aggregations
|
||||
-- Cache value for `aggregations'.
|
||||
|
||||
feature -- Operation
|
||||
|
||||
feed (a_location: READABLE_STRING_8): detachable FEED
|
||||
local
|
||||
fac: FEED_DEFAULT_PARSERS
|
||||
ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT
|
||||
do
|
||||
create fac
|
||||
if attached new_http_client_session (a_location).get ("", ctx) as res then
|
||||
if attached res.body as l_content then
|
||||
Result := fac.feed_from_string (l_content)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
aggregation_feed (agg: FEED_AGGREGATION): detachable FEED
|
||||
-- Feed from aggregation `agg'.
|
||||
local
|
||||
fac: FEED_DEFAULT_PARSERS
|
||||
f: detachable FEED
|
||||
do
|
||||
create fac
|
||||
across
|
||||
agg.locations as ic
|
||||
loop
|
||||
if attached new_http_client_session (ic.item).get ("", Void).body as res then
|
||||
f := fac.feed_from_string (res)
|
||||
if Result /= Void then
|
||||
if f /= Void then
|
||||
Result := Result + f
|
||||
end
|
||||
else
|
||||
Result := f
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
new_http_client_session (a_url: READABLE_STRING_8): HTTP_CLIENT_SESSION
|
||||
local
|
||||
cl: LIBCURL_HTTP_CLIENT
|
||||
do
|
||||
create cl.make
|
||||
Result := cl.new_session (a_url)
|
||||
Result.set_is_insecure (True)
|
||||
end
|
||||
|
||||
end
|
||||
308
modules/feed_aggregator/feed_aggregator_module.e
Normal file
308
modules/feed_aggregator/feed_aggregator_module.e
Normal file
@@ -0,0 +1,308 @@
|
||||
note
|
||||
description: "CMS module bringing support for feed aggregation."
|
||||
date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
|
||||
revision: "$Revision: 96616 $"
|
||||
|
||||
class
|
||||
FEED_AGGREGATOR_MODULE
|
||||
|
||||
inherit
|
||||
CMS_MODULE
|
||||
rename
|
||||
module_api as feed_aggregator_api
|
||||
redefine
|
||||
initialize,
|
||||
register_hooks,
|
||||
permissions,
|
||||
feed_aggregator_api
|
||||
end
|
||||
|
||||
CMS_HOOK_BLOCK
|
||||
|
||||
CMS_HOOK_RESPONSE_ALTER
|
||||
|
||||
CMS_HOOK_MENU_SYSTEM_ALTER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Create Current module, disabled by default.
|
||||
do
|
||||
version := "1.0"
|
||||
description := "Feed aggregation"
|
||||
package := "feed"
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: STRING = "feed_aggregator"
|
||||
|
||||
permissions: LIST [READABLE_STRING_8]
|
||||
-- List of permission ids, used by this module, and declared.
|
||||
do
|
||||
Result := Precursor
|
||||
Result.force ("manage feed aggregator")
|
||||
end
|
||||
|
||||
feature {CMS_API} -- Module Initialization
|
||||
|
||||
initialize (api: CMS_API)
|
||||
-- <Precursor>
|
||||
do
|
||||
Precursor (api)
|
||||
create feed_aggregator_api.make (api)
|
||||
end
|
||||
|
||||
feature {CMS_API} -- Access: API
|
||||
|
||||
feed_aggregator_api: detachable FEED_AGGREGATOR_API
|
||||
-- Eventual module api.
|
||||
|
||||
feature -- Access: router
|
||||
|
||||
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
|
||||
-- <Precursor>
|
||||
local
|
||||
h: WSF_URI_TEMPLATE_HANDLER
|
||||
do
|
||||
a_router.handle ("/admin/feed_aggregator/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_feed_aggregator_admin (a_api, ?, ?)), a_router.methods_head_get_post)
|
||||
create {WSF_URI_TEMPLATE_AGENT_HANDLER} h.make (agent handle_feed_aggregation (a_api, ?, ?))
|
||||
a_router.handle ("/feed_aggregation/", h, a_router.methods_head_get)
|
||||
a_router.handle ("/feed_aggregation/{feed_id}", h, a_router.methods_head_get)
|
||||
end
|
||||
|
||||
feature -- Handle
|
||||
|
||||
handle_feed_aggregator_admin (a_api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
nyi: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE
|
||||
do
|
||||
create nyi.make (req, res, a_api)
|
||||
nyi.execute
|
||||
end
|
||||
|
||||
handle_feed_aggregation (a_api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
r: CMS_RESPONSE
|
||||
s: STRING
|
||||
nb: INTEGER
|
||||
do
|
||||
if attached {WSF_STRING} req.query_parameter ("size") as p_size and then p_size.is_integer then
|
||||
nb := p_size.integer_value
|
||||
else
|
||||
nb := -1
|
||||
end
|
||||
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, a_api)
|
||||
if attached {WSF_STRING} req.path_parameter ("feed_id") as p_feed_id then
|
||||
if attached feed_aggregation (p_feed_id.value) as l_agg then
|
||||
create s.make_empty
|
||||
s.append ("<h1>")
|
||||
s.append (r.html_encoded (l_agg.name))
|
||||
s.append ("</h1>")
|
||||
if attached l_agg.included_categories as l_categories then
|
||||
s.append ("<span class=%"category%">")
|
||||
across
|
||||
l_categories as cats_ic
|
||||
loop
|
||||
s.append (" [")
|
||||
s.append (r.html_encoded (cats_ic.item))
|
||||
s.append ("]")
|
||||
end
|
||||
s.append ("</span>")
|
||||
end
|
||||
if attached l_agg.description as l_desc and then l_desc.is_valid_as_string_8 then
|
||||
s.append ("<div class=%"description%">")
|
||||
s.append (l_desc.as_string_8)
|
||||
s.append ("</div>")
|
||||
end
|
||||
s.append ("<ul>")
|
||||
across
|
||||
l_agg.locations as ic
|
||||
loop
|
||||
s.append ("<li><a href=%"")
|
||||
s.append (ic.item)
|
||||
s.append ("%">")
|
||||
s.append (ic.item)
|
||||
s.append ("</a></li>")
|
||||
end
|
||||
s.append ("</ul>")
|
||||
|
||||
if attached feed_to_html (p_feed_id.value, nb, True, r) as l_html then
|
||||
s.append (l_html)
|
||||
end
|
||||
r.set_main_content (s)
|
||||
else
|
||||
create {NOT_FOUND_ERROR_CMS_RESPONSE} r.make (req, res, a_api)
|
||||
end
|
||||
else
|
||||
if attached feed_aggregator_api as l_feed_agg_api then
|
||||
create s.make_empty
|
||||
across
|
||||
l_feed_agg_api.aggregations as ic
|
||||
loop
|
||||
s.append ("<li>")
|
||||
s.append (r.link (ic.key, "feed_aggregation/" + r.url_encoded (ic.key), Void))
|
||||
if attached ic.item.included_categories as l_categories then
|
||||
s.append ("<span class=%"category%">")
|
||||
across
|
||||
l_categories as cats_ic
|
||||
loop
|
||||
s.append (" [")
|
||||
s.append (r.html_encoded (cats_ic.item))
|
||||
s.append ("]")
|
||||
end
|
||||
s.append ("</span>")
|
||||
end
|
||||
if attached ic.item.description as l_desc then
|
||||
if l_desc.is_valid_as_string_8 then
|
||||
s.append ("<div class=%"description%">")
|
||||
s.append (l_desc.as_string_8)
|
||||
s.append ("</div>")
|
||||
end
|
||||
end
|
||||
s.append ("</li>")
|
||||
end
|
||||
r.set_main_content (s)
|
||||
else
|
||||
create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, a_api)
|
||||
end
|
||||
end
|
||||
r.execute
|
||||
end
|
||||
|
||||
feature -- Hooks configuration
|
||||
|
||||
register_hooks (a_response: CMS_RESPONSE)
|
||||
-- Module hooks configuration.
|
||||
do
|
||||
a_response.hooks.subscribe_to_block_hook (Current)
|
||||
a_response.hooks.subscribe_to_response_alter_hook (Current)
|
||||
a_response.hooks.subscribe_to_menu_system_alter_hook (Current)
|
||||
end
|
||||
|
||||
feature -- Hook
|
||||
|
||||
block_list: ITERABLE [like {CMS_BLOCK}.name]
|
||||
-- List of block names, managed by current object.
|
||||
local
|
||||
res: ARRAYED_LIST [like {CMS_BLOCK}.name]
|
||||
l_aggs: HASH_TABLE [FEED_AGGREGATION, STRING_8]
|
||||
do
|
||||
if attached feed_aggregator_api as l_feed_api then
|
||||
l_aggs := l_feed_api.aggregations
|
||||
create res.make (l_aggs.count)
|
||||
across
|
||||
l_aggs as ic
|
||||
loop
|
||||
res.force ("?feed." + ic.key)
|
||||
end
|
||||
else
|
||||
create res.make (0)
|
||||
end
|
||||
Result := res
|
||||
end
|
||||
|
||||
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
-- Get block object identified by `a_block_id' and associate with `a_response'.
|
||||
local
|
||||
s: READABLE_STRING_8
|
||||
b: CMS_CONTENT_BLOCK
|
||||
pref: STRING
|
||||
do
|
||||
if attached feed_aggregator_api as l_feed_api then
|
||||
pref := "feed."
|
||||
if a_block_id.starts_with (pref) then
|
||||
s := a_block_id.substring (pref.count + 1, a_block_id.count)
|
||||
else
|
||||
s := a_block_id
|
||||
end
|
||||
if attached feed_to_html (s, 0, True, a_response) as l_content then
|
||||
create b.make (a_block_id, Void, l_content, Void)
|
||||
b.set_is_raw (True)
|
||||
a_response.add_block (b, "feed_" + s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feed_aggregation (a_feed_id: READABLE_STRING_GENERAL): detachable FEED_AGGREGATION
|
||||
do
|
||||
if attached feed_aggregator_api as l_feed_api then
|
||||
Result := l_feed_api.aggregation (a_feed_id)
|
||||
end
|
||||
end
|
||||
|
||||
feed_to_html (a_feed_id: READABLE_STRING_GENERAL; a_count: INTEGER; with_feed_info: BOOLEAN; a_response: CMS_RESPONSE): detachable STRING
|
||||
local
|
||||
nb: INTEGER
|
||||
i: INTEGER
|
||||
e: FEED_ITEM
|
||||
l_cache: CMS_FILE_STRING_8_CACHE
|
||||
lnk: detachable FEED_LINK
|
||||
vis: FEED_TO_XHTML_VISITOR
|
||||
s: STRING
|
||||
do
|
||||
if attached feed_aggregator_api as l_feed_api then
|
||||
if attached l_feed_api.aggregation (a_feed_id) as l_agg then
|
||||
create l_cache.make (a_response.api.files_location.extended (".cache").extended (name).extended ("feed__" + a_feed_id + "__" + a_count.out + "_" + with_feed_info.out))
|
||||
Result := l_cache.item
|
||||
if Result = Void or l_cache.expired (Void, l_agg.expiration) then
|
||||
|
||||
create Result.make (1024)
|
||||
Result.append ("<!-- ")
|
||||
Result.append ("Updated: " + l_cache.cache_date_time.out)
|
||||
Result.append (" -->")
|
||||
|
||||
create vis.make (Result)
|
||||
if a_count = 0 then
|
||||
nb := l_agg.size
|
||||
else
|
||||
nb := a_count
|
||||
end
|
||||
vis.set_limit (nb)
|
||||
vis.set_description_enabled (l_agg.description_enabled)
|
||||
|
||||
if with_feed_info then
|
||||
create s.make_empty
|
||||
if attached l_agg.description as l_desc then
|
||||
s.append ("<div class=%"description%">")
|
||||
s.append_string_general (l_desc)
|
||||
s.append ("</div>")
|
||||
end
|
||||
vis.set_header (s)
|
||||
end
|
||||
create s.make_empty
|
||||
s.append_string ("<liv class=%"nav%">")
|
||||
s.append_string (a_response.link ("See more ...", "feed_aggregation/" + a_response.url_encoded (a_feed_id), Void))
|
||||
s.append_string ("</li>")
|
||||
vis.set_footer (s)
|
||||
|
||||
if attached l_feed_api.aggregation_feed (l_agg) as l_feed then
|
||||
l_feed.accept (vis)
|
||||
end
|
||||
l_cache.put (Result)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Hook
|
||||
|
||||
response_alter (a_response: CMS_RESPONSE)
|
||||
do
|
||||
a_response.add_style (a_response.url ("/module/" + name + "/files/css/feed_aggregator.css", Void), Void)
|
||||
end
|
||||
|
||||
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
|
||||
-- Hook execution on collection of menu contained by `a_menu_system'
|
||||
-- for related response `a_response'.
|
||||
do
|
||||
a_menu_system.navigation_menu.extend (create {CMS_LOCAL_LINK}.make ("Feeds", "feed_aggregation/"))
|
||||
if a_response.has_permission ("manage feed aggregator") then
|
||||
a_menu_system.management_menu.extend (create {CMS_LOCAL_LINK}.make ("Feeds (admin)", "admin/feed_aggregator/"))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
53
modules/feed_aggregator/site/files/css/feed_aggregator.css
Normal file
53
modules/feed_aggregator/site/files/css/feed_aggregator.css
Normal file
@@ -0,0 +1,53 @@
|
||||
div.feed ul {
|
||||
list-style: none;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 99%;
|
||||
}
|
||||
div.feed li {
|
||||
/* border-top: solid 1px #ddd; */
|
||||
padding: 0;
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
div.feed li a {
|
||||
font-weight: bold;
|
||||
}
|
||||
div.feed li .date {
|
||||
font-weight: bold;
|
||||
font-size: small;
|
||||
}
|
||||
div.feed li .category {
|
||||
margin-left: 20px;
|
||||
font-size: 8px;
|
||||
height: 9px;
|
||||
overflow: hidden;
|
||||
color: #999;
|
||||
}
|
||||
div.feed li .description {
|
||||
margin-left: 20px;
|
||||
font-size: small;
|
||||
height: 18px;
|
||||
overflow: hidden;
|
||||
color: #999;
|
||||
}
|
||||
div.feed li:hover {
|
||||
margin-bottom: 23px;
|
||||
}
|
||||
div.feed li:hover .description {
|
||||
padding: 5px;
|
||||
position: absolute;
|
||||
height: auto;
|
||||
overflow-y: scroll;
|
||||
overflow-x: scroll;
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
border: solid 1px #000;
|
||||
z-index: 10;
|
||||
}
|
||||
div.feed li:hover:last-child {
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
div.feed li .description::after {
|
||||
content: "...";
|
||||
}
|
||||
54
modules/feed_aggregator/site/files/scss/feed_aggregator.scss
Normal file
54
modules/feed_aggregator/site/files/scss/feed_aggregator.scss
Normal file
@@ -0,0 +1,54 @@
|
||||
div.feed {
|
||||
ul {
|
||||
list-style: none;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 99%;
|
||||
}
|
||||
li {
|
||||
/* border-top: solid 1px #ddd; */
|
||||
padding: 0;
|
||||
margin: 0 0 5px 0;
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
}
|
||||
.date {
|
||||
font-weight: bold;
|
||||
font-size: small;
|
||||
}
|
||||
.category {
|
||||
margin-left: 20px;
|
||||
font-size: 8px;
|
||||
height: 9px;
|
||||
overflow: hidden;
|
||||
color: #999;
|
||||
}
|
||||
.description {
|
||||
margin-left: 20px;
|
||||
font-size: small;
|
||||
height: 18px;
|
||||
overflow: hidden;
|
||||
color: #999;
|
||||
}
|
||||
&:hover {
|
||||
margin-bottom: 23px;
|
||||
.description {
|
||||
padding: 5px;
|
||||
position: absolute;
|
||||
height: auto;
|
||||
overflow-y: scroll;
|
||||
overflow-x: scroll;
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
border: solid 1px #000;
|
||||
z-index: 10;
|
||||
}
|
||||
&:last-child {
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
}
|
||||
.description::after { content: "..."; }
|
||||
}
|
||||
}
|
||||
@@ -236,11 +236,17 @@ feature -- Access: Node
|
||||
end
|
||||
|
||||
recent_nodes (params: CMS_DATA_QUERY_PARAMETERS): ITERABLE [CMS_NODE]
|
||||
-- List of the `a_rows' most recent nodes starting from `a_offset'.
|
||||
-- List of most recent nodes according to `params.offset' and `params.size'.
|
||||
do
|
||||
Result := node_storage.recent_nodes (params.offset.to_integer_32, params.size.to_integer_32)
|
||||
end
|
||||
|
||||
recent_node_changes_before (params: CMS_DATA_QUERY_PARAMETERS; a_date: DATE_TIME): ITERABLE [CMS_NODE]
|
||||
-- List of recent changes, before `a_date', according to `params' settings.
|
||||
do
|
||||
Result := node_storage.recent_node_changes_before (params.offset.to_integer_32, params.size.to_integer_32, a_date)
|
||||
end
|
||||
|
||||
node (a_id: INTEGER_64): detachable CMS_NODE
|
||||
-- Node by ID.
|
||||
do
|
||||
@@ -275,14 +281,17 @@ feature -- Access: Node
|
||||
else
|
||||
Result := l_partial_node
|
||||
end
|
||||
-- Update link with aliasing.
|
||||
if Result /= Void and then Result.has_id then
|
||||
Result.set_link (node_link (Result))
|
||||
end
|
||||
else
|
||||
Result := a_node
|
||||
if Result.has_id and Result.link = Void then
|
||||
Result.set_link (node_link (Result))
|
||||
end
|
||||
end
|
||||
|
||||
-- Update link with aliasing.
|
||||
if a_node /= Void and then a_node.has_id then
|
||||
a_node.set_link (node_link (a_node))
|
||||
end
|
||||
check has_link: Result.has_id implies attached Result.link as lnk and then lnk.location.same_string (node_link (Result).location) end
|
||||
|
||||
-- Update partial user if needed.
|
||||
if
|
||||
@@ -321,6 +330,47 @@ feature -- Access: Node
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access: page/book outline
|
||||
|
||||
children (a_node: CMS_NODE): detachable LIST [CMS_NODE]
|
||||
-- Children of node `a_node'.
|
||||
-- note: this is the partial version of the nodes.
|
||||
do
|
||||
Result := node_storage.children (a_node)
|
||||
end
|
||||
|
||||
available_parents_for_node (a_node: CMS_NODE): LIST [CMS_NODE]
|
||||
-- Potential parent nodes for node `a_node'.
|
||||
-- Ensure no cycle exists.
|
||||
do
|
||||
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
|
||||
across node_storage.available_parents_for_node (a_node) as ic loop
|
||||
check distinct: not a_node.same_node (ic.item) end
|
||||
if not is_node_a_parent_of (a_node, ic.item) then
|
||||
Result.force (ic.item)
|
||||
end
|
||||
end
|
||||
ensure
|
||||
no_cycle: across Result as c all not is_node_a_parent_of (a_node, c.item) end
|
||||
end
|
||||
|
||||
is_node_a_parent_of (a_node: CMS_NODE; a_child: CMS_NODE): BOOLEAN
|
||||
-- Is `a_node' a direct or indirect parent of node `a_child'?
|
||||
require
|
||||
distinct_nodes: not a_node.same_node (a_child)
|
||||
do
|
||||
if
|
||||
attached {CMS_PAGE} full_node (a_child) as l_child_page and then
|
||||
attached l_child_page.parent as l_parent
|
||||
then
|
||||
if l_parent.same_node (a_node) then
|
||||
Result := True
|
||||
else
|
||||
Result := is_node_a_parent_of (a_node, l_parent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Permission Scope: Node
|
||||
|
||||
has_permission_for_action_on_node (a_action: READABLE_STRING_8; a_node: CMS_NODE; a_user: detachable CMS_USER; ): BOOLEAN
|
||||
@@ -359,6 +409,7 @@ feature -- Change: Node
|
||||
|
||||
delete_node (a_node: CMS_NODE)
|
||||
-- Delete `a_node'.
|
||||
--! remove the node from the storage.
|
||||
do
|
||||
reset_error
|
||||
if a_node.has_id then
|
||||
@@ -377,7 +428,7 @@ feature -- Change: Node
|
||||
|
||||
trash_node (a_node: CMS_NODE)
|
||||
-- Trash node `a_node'.
|
||||
--! remove the node from the storage.
|
||||
-- Soft delete
|
||||
do
|
||||
reset_error
|
||||
node_storage.trash_node (a_node)
|
||||
|
||||
@@ -170,9 +170,12 @@ feature -- Access
|
||||
Result.force ("trash own " + l_type_name)
|
||||
Result.force ("restore own " + l_type_name)
|
||||
|
||||
Result.force ("view unpublished " + l_type_name)
|
||||
|
||||
Result.force ("view revisions own " + l_type_name)
|
||||
end
|
||||
end
|
||||
Result.force ("view trash")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -241,7 +244,7 @@ feature -- Hooks
|
||||
block_list: ITERABLE [like {CMS_BLOCK}.name]
|
||||
-- <Precursor>
|
||||
do
|
||||
Result := <<"node-info">>
|
||||
Result := <<"?node-info">>
|
||||
end
|
||||
|
||||
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
@@ -255,6 +258,7 @@ feature -- Hooks
|
||||
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
|
||||
local
|
||||
lnk: CMS_LOCAL_LINK
|
||||
perms: ARRAYED_LIST [READABLE_STRING_8]
|
||||
do
|
||||
debug
|
||||
create lnk.make ("List of nodes", "nodes")
|
||||
@@ -262,46 +266,89 @@ feature -- Hooks
|
||||
end
|
||||
create lnk.make ("Trash", "trash")
|
||||
a_menu_system.navigation_menu.extend (lnk)
|
||||
lnk.set_permission_arguments (<<"view trash">>)
|
||||
|
||||
create lnk.make ("Create ..", "node")
|
||||
a_menu_system.navigation_menu.extend (lnk)
|
||||
if attached node_api as l_node_api then
|
||||
create perms.make (2)
|
||||
perms.force ("create any node")
|
||||
across
|
||||
l_node_api.content_types as ic
|
||||
loop
|
||||
perms.force ("create " + ic.item.name)
|
||||
end
|
||||
lnk.set_permission_arguments (perms)
|
||||
end
|
||||
end
|
||||
|
||||
populate_recent_changes (a_changes: CMS_RECENT_CHANGE_CONTAINER; a_sources: LIST [READABLE_STRING_8])
|
||||
recent_changes_sources: detachable LIST [READABLE_STRING_8]
|
||||
-- <Precursor>
|
||||
local
|
||||
lst: ARRAYED_LIST [READABLE_STRING_8]
|
||||
do
|
||||
if
|
||||
attached node_api as l_node_api and then
|
||||
attached l_node_api.content_types as l_types and then
|
||||
not l_types.is_empty
|
||||
then
|
||||
create lst.make (l_types.count)
|
||||
across
|
||||
l_types as ic
|
||||
loop
|
||||
lst.force (ic.item.name)
|
||||
end
|
||||
Result := lst
|
||||
end
|
||||
end
|
||||
|
||||
populate_recent_changes (a_changes: CMS_RECENT_CHANGE_CONTAINER; a_current_user: detachable CMS_USER)
|
||||
local
|
||||
params: CMS_DATA_QUERY_PARAMETERS
|
||||
ch: CMS_RECENT_CHANGE_ITEM
|
||||
n: CMS_NODE
|
||||
l_info: STRING_8
|
||||
l_src: detachable READABLE_STRING_8
|
||||
l_nodes: ITERABLE [CMS_NODE]
|
||||
l_date: detachable DATE_TIME
|
||||
do
|
||||
create params.make (0, a_changes.limit)
|
||||
if attached node_api as l_node_api then
|
||||
across
|
||||
l_node_api.content_types as ic
|
||||
loop
|
||||
a_sources.force (ic.item.name)
|
||||
l_src := a_changes.source
|
||||
l_date := a_changes.date
|
||||
if l_date = Void then
|
||||
create l_date.make_now_utc
|
||||
end
|
||||
across l_node_api.recent_nodes (params) as ic loop
|
||||
n := l_node_api.full_node (ic.item)
|
||||
create ch.make (n.content_type, create {CMS_LOCAL_LINK}.make (n.title, "node/" + n.id.out), n.modification_date)
|
||||
if n.creation_date ~ n.modification_date then
|
||||
l_info := "new"
|
||||
if not n.is_published then
|
||||
l_info.append (" (unpublished)")
|
||||
end
|
||||
else
|
||||
if n.is_trashed then
|
||||
l_info := "trashed"
|
||||
else
|
||||
l_info := "updated"
|
||||
if not n.is_published then
|
||||
l_info.append (" (unpublished)")
|
||||
l_nodes := l_node_api.recent_node_changes_before (params, l_date)
|
||||
across l_nodes as ic loop
|
||||
n := ic.item
|
||||
if l_src = Void or else l_src.is_case_insensitive_equal_general (n.content_type) then
|
||||
if l_node_api.has_permission_for_action_on_node ("view", n, a_current_user) then
|
||||
n := l_node_api.full_node (n)
|
||||
create ch.make (n.content_type, create {CMS_LOCAL_LINK}.make (n.title, "node/" + n.id.out), n.modification_date)
|
||||
if n.creation_date ~ n.modification_date then
|
||||
l_info := "new"
|
||||
if not n.is_published then
|
||||
l_info.append (" (unpublished)")
|
||||
end
|
||||
else
|
||||
if n.is_trashed then
|
||||
l_info := "deleted"
|
||||
else
|
||||
l_info := "updated"
|
||||
if not n.is_published then
|
||||
l_info.append (" (unpublished)")
|
||||
end
|
||||
end
|
||||
end
|
||||
ch.set_information (l_info)
|
||||
ch.set_author (n.author)
|
||||
a_changes.force (ch)
|
||||
else
|
||||
-- Forbidden
|
||||
-- FIXME: provide a visual indication!
|
||||
end
|
||||
end
|
||||
ch.set_information (l_info)
|
||||
ch.set_author (n.author)
|
||||
a_changes.force (ch)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,7 +10,7 @@ deferred class
|
||||
CMS_NODE
|
||||
|
||||
inherit
|
||||
|
||||
DEBUG_OUTPUT
|
||||
REFACTORING_HELPER
|
||||
|
||||
feature{NONE} -- Initialization
|
||||
@@ -166,6 +166,23 @@ feature -- Access: menu
|
||||
link: detachable CMS_LOCAL_LINK
|
||||
-- Associated menu link.
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING_32
|
||||
-- <Precursor>
|
||||
do
|
||||
create Result.make_from_string_general ("#")
|
||||
Result.append_integer_64 (id)
|
||||
Result.append_character (' ')
|
||||
Result.append_character ('<')
|
||||
Result.append_string_general (content_type)
|
||||
Result.append_character ('>')
|
||||
Result.append_character (' ')
|
||||
Result.append_character ('%"')
|
||||
Result.append (title)
|
||||
Result.append_character ('%"')
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_content (a_content: like content; a_summary: like summary; a_format: like format)
|
||||
|
||||
@@ -62,14 +62,14 @@ feature -- Forms ...
|
||||
sum.set_text_value (a_node.summary)
|
||||
end
|
||||
sum.set_label ("Summary")
|
||||
sum.set_description ("This is the summary")
|
||||
sum.set_description ("Text displayed in short view.")
|
||||
sum.set_is_required (False)
|
||||
|
||||
create fset.make
|
||||
|
||||
-- Add summary
|
||||
fset.extend (sum)
|
||||
fset.extend_html_text("<br />")
|
||||
fset.extend_html_text("<br/>")
|
||||
|
||||
-- Add content
|
||||
fset.extend (ta)
|
||||
@@ -274,10 +274,10 @@ feature -- Output
|
||||
|
||||
|
||||
if a_node.status = {CMS_NODE_API}.trashed then
|
||||
create lnk.make ("Trash", node_api.node_path (a_node) + "/trash")
|
||||
create lnk.make ("Delete", node_api.node_path (a_node) + "/delete")
|
||||
lnk.set_weight (2)
|
||||
a_response.add_to_primary_tabs (lnk)
|
||||
elseif a_node /= Void and then a_node.has_id then
|
||||
elseif a_node.has_id then
|
||||
-- Node in {{CMS_NODE_API}.published} or {CMS_NODE_API}.not_published} status.
|
||||
create lnk.make ("Edit", node_api.node_path (a_node) + "/edit")
|
||||
lnk.set_weight (2)
|
||||
@@ -291,15 +291,16 @@ feature -- Output
|
||||
end
|
||||
|
||||
if
|
||||
node_api.has_permission_for_action_on_node ("delete", a_node, l_user)
|
||||
node_api.has_permission_for_action_on_node ("trash", a_node, l_user)
|
||||
then
|
||||
create lnk.make ("Delete", node_api.node_path (a_node) + "/delete")
|
||||
create lnk.make ("Move to trash", node_api.node_path (a_node) + "/trash")
|
||||
lnk.set_weight (3)
|
||||
a_response.add_to_primary_tabs (lnk)
|
||||
end
|
||||
end
|
||||
end
|
||||
create s.make_empty
|
||||
s.append ("<div class=%"cms-node node-" + a_node.content_type + "%">")
|
||||
s.append ("<div class=%"info%"> ")
|
||||
if attached a_node.author as l_author then
|
||||
s.append (" by ")
|
||||
@@ -339,6 +340,7 @@ feature -- Output
|
||||
|
||||
s.append ("</p>")
|
||||
end
|
||||
s.append ("</div>")
|
||||
|
||||
a_response.set_title (a_node.title)
|
||||
a_response.set_main_content (s)
|
||||
|
||||
@@ -10,7 +10,10 @@ inherit
|
||||
CMS_NODE_TYPE_WEBFORM_MANAGER [CMS_PAGE]
|
||||
redefine
|
||||
content_type,
|
||||
append_html_output_to
|
||||
append_html_output_to,
|
||||
populate_form,
|
||||
new_node,
|
||||
update_node
|
||||
end
|
||||
|
||||
create
|
||||
@@ -21,140 +24,116 @@ feature -- Access
|
||||
content_type: CMS_PAGE_NODE_TYPE
|
||||
-- Associated content type.
|
||||
|
||||
feature -- Forms ...
|
||||
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)
|
||||
populate_form (response: NODE_RESPONSE; f: CMS_FORM; a_node: detachable CMS_NODE)
|
||||
local
|
||||
ti: WSF_FORM_NUMBER_INPUT
|
||||
fs: WSF_FORM_FIELD_SET
|
||||
l_parent_id: INTEGER_64
|
||||
do
|
||||
Precursor (response, f, a_node)
|
||||
|
||||
-- f.extend_html_text ("<br/>")
|
||||
if attached {CMS_PAGE} a_node as l_page then
|
||||
create fs.make
|
||||
fs.set_legend ("Pages structure")
|
||||
fs.set_collapsible (True)
|
||||
f.extend (fs)
|
||||
create ti.make ("select_parent_node")
|
||||
ti.set_label ("Parent page")
|
||||
ti.set_description ("The parent page is the book structure.")
|
||||
if attached l_page.parent as l_parent_node then
|
||||
l_parent_id := l_parent_node.id
|
||||
fs.extend_html_text ("<div><strong>Currently, the parent page is </strong> ")
|
||||
fs.extend_html_text (response.node_html_link (l_parent_node, l_parent_node.title))
|
||||
fs.extend_html_text ("</div>")
|
||||
end
|
||||
ti.set_validation_action (agent parent_validation (response, ?))
|
||||
fs.extend (ti)
|
||||
|
||||
-- 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)
|
||||
-- FIXME: add notion of "weight"
|
||||
|
||||
-- create fset.make
|
||||
-- fset.set_legend ("Body")
|
||||
-- fset.extend (ta)
|
||||
if
|
||||
attached {WSF_STRING} response.request.query_parameter ("parent") as p_parent and then
|
||||
p_parent.is_integer
|
||||
then
|
||||
l_parent_id := p_parent.integer_value.to_integer_64
|
||||
end
|
||||
if l_parent_id > 0 then
|
||||
ti.set_default_value (l_parent_id.out)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- fset.extend_html_text ("<br/>")
|
||||
update_node (a_response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: CMS_NODE)
|
||||
-- <Precursor>
|
||||
local
|
||||
l_parent_id: INTEGER_64
|
||||
do
|
||||
Precursor (a_response, fd, a_node)
|
||||
if attached {CMS_PAGE} a_node as l_page then
|
||||
if attached fd.integer_item ("select_parent_node") as i_parent_node then
|
||||
l_parent_id := i_parent_node.to_integer_64
|
||||
end
|
||||
if
|
||||
l_parent_id > 0 and then
|
||||
attached {CMS_PAGE} a_response.node_api.node (l_parent_id) as l_parent_page
|
||||
then
|
||||
l_page.set_parent (l_parent_page)
|
||||
elseif l_parent_id = -1 then
|
||||
-- Set parent to Void
|
||||
l_page.set_parent (Void)
|
||||
end
|
||||
end
|
||||
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
|
||||
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.integer_item ("select_parent_node") as l_parent_id then
|
||||
if l_parent_id = -1 then
|
||||
Result.set_parent (Void)
|
||||
elseif attached {CMS_PAGE} response.node_api.node (l_parent_id) as l_parent then
|
||||
Result.set_parent (l_parent)
|
||||
end
|
||||
end
|
||||
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): 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
|
||||
parent_validation (a_response: NODE_RESPONSE; fd: WSF_FORM_DATA)
|
||||
local
|
||||
node_api: CMS_NODE_API
|
||||
l_parent_id: INTEGER_64
|
||||
nid: INTEGER_64
|
||||
l_parent_node: detachable CMS_NODE
|
||||
do
|
||||
node_api := a_response.node_api
|
||||
if attached fd.integer_item ("select_parent_node") as s_parent_node then
|
||||
l_parent_id := s_parent_node.to_integer_64
|
||||
else
|
||||
l_parent_id := 0
|
||||
end
|
||||
if l_parent_id > 0 then
|
||||
l_parent_node := node_api.node (l_parent_id)
|
||||
if l_parent_node = Void then
|
||||
fd.report_invalid_field ("select_parent_node", "Invalid parent, not found id #" + l_parent_id.out)
|
||||
else
|
||||
nid := a_response.node_id_path_parameter
|
||||
if
|
||||
nid > 0 and then
|
||||
attached node_api.node (nid) as l_node and then
|
||||
node_api.is_node_a_parent_of (l_node, l_parent_node)
|
||||
then
|
||||
fd.report_invalid_field ("select_parent_node", "Invalid parent due to cycle (node #" + nid.out + " is already a parent of node #" + l_parent_id.out)
|
||||
end
|
||||
end
|
||||
elseif l_parent_id = -1 or else l_parent_id = 0 then
|
||||
-- -1 is Used to unassign a parent node
|
||||
-- 0 is not taken into account, any other input value is considered invalid.
|
||||
else
|
||||
fd.report_invalid_field ("select_parent_node", "Invalid node id")
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Output
|
||||
|
||||
@@ -162,8 +141,20 @@ feature -- Output
|
||||
-- <Precursor>
|
||||
local
|
||||
s: STRING
|
||||
node_api: CMS_NODE_API
|
||||
lnk: CMS_LOCAL_LINK
|
||||
do
|
||||
node_api := a_response.node_api
|
||||
Precursor (a_node, a_response)
|
||||
|
||||
if a_node.has_id and then not a_node.is_trashed then
|
||||
if node_api.has_permission_for_action_on_node ("create", a_node, a_response.user) then
|
||||
create lnk.make ("Add Child", "node/add/page?parent=" + a_node.id.out)
|
||||
lnk.set_weight (3)
|
||||
a_response.add_to_primary_tabs (lnk)
|
||||
end
|
||||
end
|
||||
|
||||
if attached a_response.main_content as l_main_content then
|
||||
s := l_main_content
|
||||
else
|
||||
@@ -171,11 +162,22 @@ feature -- Output
|
||||
end
|
||||
|
||||
if attached {CMS_PAGE} a_node as l_node_page then
|
||||
s.append ("<ul class=%"page-navigation%">")
|
||||
if attached l_node_page.parent as l_parent_node then
|
||||
s.append ("<div>Parent page is ")
|
||||
s.append (a_response.link (l_parent_node.title + " (#" + l_parent_node.id.out + ")", a_response.node_api.node_path (l_parent_node), Void))
|
||||
s.append ("</div>")
|
||||
s.append ("<li class=%"page-parent%">Go to parent page ")
|
||||
s.append (a_response.link (l_parent_node.title, a_response.node_api.node_path (l_parent_node), Void))
|
||||
s.append ("</li>")
|
||||
end
|
||||
if attached node_api.children (a_node) as l_children then
|
||||
across
|
||||
l_children as ic
|
||||
loop
|
||||
s.append ("<li>")
|
||||
s.append (a_response.link (ic.item.title, a_response.node_api.node_path (ic.item), Void))
|
||||
s.append ("</li>")
|
||||
end
|
||||
end
|
||||
s.append ("</ul>")
|
||||
end
|
||||
|
||||
a_response.set_main_content (s)
|
||||
|
||||
@@ -37,91 +37,30 @@ feature -- Execution
|
||||
-- Computed response message.
|
||||
local
|
||||
b: STRING_8
|
||||
f: like new_edit_form
|
||||
fd: detachable WSF_FORM_DATA
|
||||
nid: INTEGER_64
|
||||
do
|
||||
create b.make_empty
|
||||
nid := node_id_path_parameter (request)
|
||||
nid := node_id_path_parameter
|
||||
if
|
||||
nid > 0 and then
|
||||
attached node_api.node (nid) as l_node
|
||||
then
|
||||
if attached node_api.node_type_for (l_node) as l_type then
|
||||
fixme ("refactor: process_edit, process_create process edit")
|
||||
if
|
||||
location.ends_with_general ("/edit") and then
|
||||
node_api.has_permission_for_action_on_node ("edit", l_node, user)
|
||||
then
|
||||
f := new_edit_form (l_node, url (location, Void), "edit-" + l_type.name, l_type)
|
||||
invoke_form_alter (f, fd)
|
||||
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
|
||||
if l_node.has_id then
|
||||
add_to_menu (node_local_link (l_node, translation ("View", Void)), primary_tabs)
|
||||
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), node_api.node_path (l_node) + "/edit"), primary_tabs)
|
||||
add_to_menu (create {CMS_LOCAL_LINK}.make ("Delete", node_api.node_path (l_node) + "/delete"), primary_tabs)
|
||||
end
|
||||
|
||||
if attached redirection as l_location then
|
||||
-- FIXME: Hack for now
|
||||
set_title (l_node.title)
|
||||
b.append (html_encoded (l_type.title) + " saved")
|
||||
else
|
||||
set_title (formatted_string (translation ("Edit $1 #$2", Void), [l_type.title, l_node.id]))
|
||||
f.append_to_html (wsf_theme, b)
|
||||
end
|
||||
edit_node (l_node, l_type, b)
|
||||
elseif
|
||||
location.ends_with_general ("/delete") and then
|
||||
node_api.has_permission_for_action_on_node ("delete", l_node, user)
|
||||
then
|
||||
f := new_delete_form (l_node, url (location, Void), "delete-" + l_type.name, l_type)
|
||||
invoke_form_alter (f, fd)
|
||||
if request.is_post_request_method then
|
||||
f.process (Current)
|
||||
fd := f.last_data
|
||||
end
|
||||
if l_node.has_id then
|
||||
add_to_menu (node_local_link (l_node, translation ("View", Void)), primary_tabs)
|
||||
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), node_api.node_path (l_node) + "/edit"), primary_tabs)
|
||||
add_to_menu (create {CMS_LOCAL_LINK}.make ("Delete", node_api.node_path (l_node) + "/delete"), primary_tabs)
|
||||
end
|
||||
|
||||
if attached redirection as l_location then
|
||||
-- FIXME: Hack for now
|
||||
set_title (l_node.title)
|
||||
b.append (html_encoded (l_type.title) + " deleted")
|
||||
else
|
||||
set_title (formatted_string (translation ("Delete $1 #$2", Void), [l_type.title, l_node.id]))
|
||||
f.append_to_html (wsf_theme, b)
|
||||
end
|
||||
delete_node (l_node, l_type, b)
|
||||
elseif
|
||||
location.ends_with_general ("/trash") and then
|
||||
node_api.has_permission_for_action_on_node ("trash", l_node, user)
|
||||
then
|
||||
f := new_trash_form (l_node, url (location, Void), "trash-" + l_type.name, l_type)
|
||||
invoke_form_alter (f, fd)
|
||||
if request.is_post_request_method then
|
||||
f.process (Current)
|
||||
fd := f.last_data
|
||||
end
|
||||
if l_node.has_id then
|
||||
add_to_menu (node_local_link (l_node, translation ("View", Void)), primary_tabs)
|
||||
add_to_menu (create {CMS_LOCAL_LINK}.make ("Trash", node_api.node_path (l_node) + "/Trash"), primary_tabs)
|
||||
end
|
||||
|
||||
if attached redirection as l_location then
|
||||
-- FIXME: Hack for now
|
||||
set_title (l_node.title)
|
||||
b.append (html_encoded (l_type.title) + " trashed")
|
||||
else
|
||||
set_title (formatted_string (translation ("Trash $1 #$2", Void), [l_type.title, l_node.id]))
|
||||
f.append_to_html (wsf_theme, b)
|
||||
end
|
||||
trash_node (l_node, l_type, b)
|
||||
else
|
||||
b.append ("<h1>")
|
||||
b.append (translation ("Access denied", Void))
|
||||
@@ -135,29 +74,8 @@ feature -- Execution
|
||||
attached node_api.node_type (p_type.value) as l_type
|
||||
then
|
||||
if has_permissions (<<"create any", "create " + l_type.name>>) then
|
||||
if attached l_type.new_node (Void) as l_node then
|
||||
f := new_edit_form (l_node, url (location, Void), "edit-" + l_type.name, l_type)
|
||||
invoke_form_alter (f, fd)
|
||||
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 " + html_encoded (l_type.title) + " #" + l_node.id.out)
|
||||
|
||||
if l_node.has_id then
|
||||
add_to_menu (node_local_link (l_node, translation ("View", Void)), primary_tabs)
|
||||
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), node_api.node_path (l_node) + "/edit"), primary_tabs)
|
||||
end
|
||||
|
||||
f.append_to_html (wsf_theme, b)
|
||||
else
|
||||
b.append ("<h1>")
|
||||
b.append (translation ("Server error", Void))
|
||||
b.append ("</h1>")
|
||||
end
|
||||
-- create new node
|
||||
create_new_node (l_type, b)
|
||||
else
|
||||
b.append ("<h1>")
|
||||
b.append (translation ("Access denied", Void))
|
||||
@@ -185,6 +103,126 @@ feature -- Execution
|
||||
set_main_content (b)
|
||||
end
|
||||
|
||||
|
||||
feature {NONE} -- Create a new node
|
||||
|
||||
create_new_node (a_type: CMS_NODE_TYPE [CMS_NODE]; b: STRING_8)
|
||||
local
|
||||
f: like new_edit_form
|
||||
fd: detachable WSF_FORM_DATA
|
||||
do
|
||||
if attached a_type.new_node (Void) as l_node then
|
||||
-- create new node
|
||||
f := new_edit_form (l_node, url (location, Void), "edit-" + a_type.name, a_type)
|
||||
hooks.invoke_form_alter (f, fd, Current)
|
||||
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, a_type, b))
|
||||
f.process (Current)
|
||||
fd := f.last_data
|
||||
end
|
||||
|
||||
if l_node.has_id then
|
||||
set_title ("Edit " + html_encoded (a_type.title) + " #" + l_node.id.out)
|
||||
add_to_menu (node_local_link (l_node, translation ("View", Void)), primary_tabs)
|
||||
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), node_api.node_path (l_node) + "/edit"), primary_tabs)
|
||||
else
|
||||
set_title ("New " + html_encoded (a_type.title))
|
||||
end
|
||||
f.append_to_html (wsf_theme, b)
|
||||
else
|
||||
b.append ("<h1>")
|
||||
b.append (translation ("Server error", Void))
|
||||
b.append ("</h1>")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
edit_node (a_node: CMS_NODE; a_type: CMS_NODE_TYPE [CMS_NODE]; b: STRING_8)
|
||||
local
|
||||
f: like new_edit_form
|
||||
fd: detachable WSF_FORM_DATA
|
||||
do
|
||||
f := new_edit_form (A_node, url (location, Void), "edit-" + a_type.name, a_type)
|
||||
hooks.invoke_form_alter (f, fd, Current)
|
||||
if request.is_post_request_method then
|
||||
f.validation_actions.extend (agent edit_form_validate (?, b))
|
||||
f.submit_actions.extend (agent edit_form_submit (?, a_node, a_type, b))
|
||||
f.process (Current)
|
||||
fd := f.last_data
|
||||
end
|
||||
if a_node.has_id then
|
||||
add_to_menu (node_local_link (a_node, translation ("View", Void)), primary_tabs)
|
||||
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), node_api.node_path (a_node) + "/edit"), primary_tabs)
|
||||
add_to_menu (create {CMS_LOCAL_LINK}.make ("Delete", node_api.node_path (a_node) + "/delete"), primary_tabs)
|
||||
end
|
||||
|
||||
if attached redirection as l_location then
|
||||
-- FIXME: Hack for now
|
||||
set_title (a_node.title)
|
||||
b.append (html_encoded (a_type.title) + " saved")
|
||||
else
|
||||
set_title (formatted_string (translation ("Edit $1 #$2", Void), [a_type.title, a_node.id]))
|
||||
f.append_to_html (wsf_theme, b)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
delete_node (a_node: CMS_NODE; a_type: CMS_NODE_TYPE [CMS_NODE]; b: STRING_8)
|
||||
local
|
||||
f: like new_edit_form
|
||||
fd: detachable WSF_FORM_DATA
|
||||
do
|
||||
f := new_delete_form (a_node, url (location, Void), "delete-" + a_type.name, a_type)
|
||||
hooks.invoke_form_alter (f, fd, Current)
|
||||
if request.is_post_request_method then
|
||||
f.process (Current)
|
||||
fd := f.last_data
|
||||
end
|
||||
if a_node.has_id then
|
||||
add_to_menu (node_local_link (a_node, translation ("View", Void)), primary_tabs)
|
||||
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), node_api.node_path (a_node) + "/edit"), primary_tabs)
|
||||
add_to_menu (create {CMS_LOCAL_LINK}.make ("Delete", node_api.node_path (a_node) + "/delete"), primary_tabs)
|
||||
end
|
||||
|
||||
if attached redirection as l_location then
|
||||
-- FIXME: Hack for now
|
||||
set_title (a_node.title)
|
||||
b.append (html_encoded (a_type.title) + " deleted")
|
||||
else
|
||||
set_title (formatted_string (translation ("Delete $1 #$2", Void), [a_type.title, a_node.id]))
|
||||
f.append_to_html (wsf_theme, b)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
trash_node (a_node: CMS_NODE; a_type: CMS_NODE_TYPE [CMS_NODE]; b: STRING_8)
|
||||
local
|
||||
f: like new_edit_form
|
||||
fd: detachable WSF_FORM_DATA
|
||||
do
|
||||
f := new_trash_form (a_node, url (location, Void), "trash-" + a_type.name, a_type)
|
||||
hooks.invoke_form_alter (f, fd, Current)
|
||||
if request.is_post_request_method then
|
||||
f.process (Current)
|
||||
fd := f.last_data
|
||||
end
|
||||
if a_node.has_id then
|
||||
add_to_menu (node_local_link (a_node, translation ("View", Void)), primary_tabs)
|
||||
add_to_menu (create {CMS_LOCAL_LINK}.make ("Trash", node_api.node_path (a_node) + "/Trash"), primary_tabs)
|
||||
end
|
||||
|
||||
if attached redirection as l_location then
|
||||
-- FIXME: Hack for now
|
||||
set_title (a_node.title)
|
||||
b.append (html_encoded (a_type.title) + " trashed")
|
||||
else
|
||||
set_title (formatted_string (translation ("Trash $1 #$2", Void), [a_type.title, a_node.id]))
|
||||
f.append_to_html (wsf_theme, b)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature -- Form
|
||||
|
||||
edit_form_validate (fd: WSF_FORM_DATA; b: STRING)
|
||||
@@ -221,6 +259,7 @@ feature -- Form
|
||||
s: STRING
|
||||
l_path_alias: detachable READABLE_STRING_8
|
||||
do
|
||||
fixme ("Refactor code per operacion: Preview, Save")
|
||||
l_preview := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Preview")
|
||||
if not l_preview then
|
||||
debug ("cms")
|
||||
@@ -250,6 +289,7 @@ feature -- Form
|
||||
|
||||
fixme ("for now, publishing is not implemented, so let's assume any node saved is published.") -- FIXME
|
||||
l_node.mark_published
|
||||
|
||||
node_api.save_node (l_node)
|
||||
if attached user as u then
|
||||
api.log ("node",
|
||||
@@ -290,7 +330,6 @@ feature -- Form
|
||||
th: WSF_FORM_HIDDEN_INPUT
|
||||
do
|
||||
create f.make (a_url, a_name)
|
||||
|
||||
create th.make ("node-id")
|
||||
if a_node /= Void then
|
||||
th.set_text_value (a_node.id.out)
|
||||
@@ -300,8 +339,8 @@ feature -- Form
|
||||
f.extend (th)
|
||||
|
||||
populate_form (a_node_type, f, a_node)
|
||||
f.extend_html_text ("<br/>")
|
||||
|
||||
f.extend_html_text ("<br/>")
|
||||
create ts.make ("op")
|
||||
ts.set_default_value ("Save")
|
||||
f.extend (ts)
|
||||
@@ -336,7 +375,7 @@ feature -- Form
|
||||
ts.set_default_value (translation ("Delete"))
|
||||
]")
|
||||
f.extend (ts)
|
||||
fixme ("wsf_html: add support for HTML5 input attributes!!! ")
|
||||
to_implement ("Refactor code to use the new wsf_html HTML5 support")
|
||||
f.extend_html_text("<input type='submit' value='Cancel' formmethod='GET', formaction='/node/"+a_node.id.out+"'>" )
|
||||
end
|
||||
|
||||
|
||||
@@ -99,6 +99,15 @@ feature -- HTTP Methods
|
||||
edit_response.execute
|
||||
elseif req.percent_encoded_path_info.ends_with ("/revision") then
|
||||
do_revisions (req, res)
|
||||
-- elseif req.percent_encoded_path_info.ends_with ("/add_child/page") then
|
||||
-- -- Add child node
|
||||
-- l_nid := node_id_path_parameter (req)
|
||||
-- if l_nid > 0 then
|
||||
-- -- create a new child node with node id `l_id' as parent.
|
||||
-- create_new_node (req, res)
|
||||
-- else
|
||||
-- send_not_found (req, res)
|
||||
-- end
|
||||
else
|
||||
-- Display existing node
|
||||
l_nid := node_id_path_parameter (req)
|
||||
@@ -117,15 +126,29 @@ feature -- HTTP Methods
|
||||
then
|
||||
l_node := node_api.revision_node (l_nid, l_rev)
|
||||
end
|
||||
if
|
||||
l_node /= Void and then (l_rev > 0 or else l_node.is_published)
|
||||
then
|
||||
create view_response.make (req, res, api, node_api)
|
||||
view_response.set_node (l_node)
|
||||
view_response.set_revision (l_rev)
|
||||
view_response.execute
|
||||
else
|
||||
if l_node = Void then
|
||||
send_not_found (req, res)
|
||||
else
|
||||
if
|
||||
l_rev > 0 or else l_node.is_published
|
||||
then
|
||||
create view_response.make (req, res, api, node_api)
|
||||
view_response.set_node (l_node)
|
||||
view_response.set_revision (l_rev)
|
||||
view_response.execute
|
||||
elseif
|
||||
attached current_user (req) as l_user and then
|
||||
( node_api.is_author_of_node (l_user, l_node)
|
||||
or else api.user_api.user_has_permission (l_user, "view unpublished " + l_node.content_type)
|
||||
)
|
||||
then
|
||||
create view_response.make (req, res, api, node_api)
|
||||
view_response.set_node (l_node)
|
||||
view_response.set_revision (l_rev)
|
||||
view_response.execute
|
||||
else
|
||||
send_access_denied (req, res)
|
||||
end
|
||||
end
|
||||
else
|
||||
-- redirect_to (req.absolute_script_url ("/node/"), res) -- New node.
|
||||
@@ -166,6 +189,9 @@ feature -- HTTP Methods
|
||||
elseif req.percent_encoded_path_info.starts_with ("/node/add/") then
|
||||
create edit_response.make (req, res, api, node_api)
|
||||
edit_response.execute
|
||||
elseif req.percent_encoded_path_info.ends_with ("/add_child/page") then
|
||||
create edit_response.make (req, res, api, node_api)
|
||||
edit_response.execute
|
||||
else
|
||||
to_implement ("REST API")
|
||||
send_not_implemented ("REST API not yet implemented", req, res)
|
||||
@@ -179,8 +205,8 @@ feature -- HTTP Methods
|
||||
send_not_implemented ("REST API not yet implemented", req, res)
|
||||
end
|
||||
|
||||
do_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- <Precursor>
|
||||
do_trash (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Trash a node, soft delete.
|
||||
do
|
||||
if attached current_user (req) as l_user then
|
||||
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
|
||||
@@ -188,8 +214,8 @@ feature -- HTTP Methods
|
||||
l_id.is_integer and then
|
||||
attached node_api.node (l_id.integer_value) as l_node
|
||||
then
|
||||
if node_api.has_permission_for_action_on_node ("delete", l_node, current_user (req)) then
|
||||
node_api.delete_node (l_node)
|
||||
if node_api.has_permission_for_action_on_node ("trash", l_node, current_user (req)) then
|
||||
node_api.trash_node (l_node)
|
||||
res.send (create {CMS_REDIRECTION_RESPONSE_MESSAGE}.make (req.absolute_script_url ("")))
|
||||
else
|
||||
send_access_denied (req, res)
|
||||
@@ -214,8 +240,8 @@ feature -- HTTP Methods
|
||||
|
||||
feature {NONE} -- Trash:Restore
|
||||
|
||||
do_trash (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Trash a node from the database.
|
||||
do_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Delete a node from the database.
|
||||
do
|
||||
if attached current_user (req) as l_user then
|
||||
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
|
||||
@@ -223,8 +249,8 @@ feature {NONE} -- Trash:Restore
|
||||
l_id.is_integer and then
|
||||
attached node_api.node (l_id.integer_value) as l_node
|
||||
then
|
||||
if node_api.has_permission_for_action_on_node ("trash", l_node, current_user (req)) then
|
||||
node_api.trash_node (l_node)
|
||||
if node_api.has_permission_for_action_on_node ("delete", l_node, current_user (req)) then
|
||||
node_api.delete_node (l_node)
|
||||
res.send (create {CMS_REDIRECTION_RESPONSE_MESSAGE}.make (req.absolute_script_url ("")))
|
||||
else
|
||||
send_access_denied (req, res)
|
||||
@@ -355,5 +381,4 @@ feature {NONE} -- Node
|
||||
send_bad_request (req, res)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -27,12 +27,12 @@ feature -- Access
|
||||
|
||||
feature -- Helpers
|
||||
|
||||
node_id_path_parameter (req: WSF_REQUEST): INTEGER_64
|
||||
-- Node id passed as path parameter for request `req'.
|
||||
node_id_path_parameter: INTEGER_64
|
||||
-- Node id passed as path parameter for request `request'.
|
||||
local
|
||||
s: STRING
|
||||
do
|
||||
if attached {WSF_STRING} req.path_parameter ("id") as p_nid then
|
||||
if attached {WSF_STRING} request.path_parameter ("id") as p_nid then
|
||||
s := p_nid.value
|
||||
if s.is_integer_64 then
|
||||
Result := s.to_integer_64
|
||||
|
||||
@@ -56,13 +56,12 @@ feature -- Execution
|
||||
process
|
||||
-- Computed response message.
|
||||
local
|
||||
b: detachable STRING_8
|
||||
nid: INTEGER_64
|
||||
l_node: like node
|
||||
do
|
||||
l_node := node
|
||||
if l_node = Void then
|
||||
nid := node_id_path_parameter (request)
|
||||
nid := node_id_path_parameter
|
||||
if nid > 0 then
|
||||
l_node := node_api.node (nid)
|
||||
end
|
||||
@@ -85,6 +84,8 @@ feature -- Execution
|
||||
if l_node /= Void and revision > 0 then
|
||||
set_title ("Revision #" + revision.out + " of " + html_encoded (l_node.title))
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="cms" location="..\..\cms.ecf"/>
|
||||
<library name="cms_model" location="..\..\library\model\cms_model.ecf" readonly="false"/>
|
||||
<library name="cms_recent_changes_module" location="..\..\modules\recent_changes\recent_changes.ecf" readonly="false"/>
|
||||
<library name="error" location="$ISE_LIBRARY\contrib\library\utility\general\error\error.ecf"/>
|
||||
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http.ecf"/>
|
||||
<library name="http_authorization" location="$ISE_LIBRARY\contrib\library\network\authentication\http_authorization\http_authorization.ecf" readonly="false"/>
|
||||
|
||||
@@ -49,6 +49,13 @@ feature -- Persistence
|
||||
end
|
||||
end
|
||||
|
||||
delete_node (a_node: CMS_NODE)
|
||||
-- remove node extensions.
|
||||
require
|
||||
a_node_accepted: is_accepted (a_node)
|
||||
deferred
|
||||
end
|
||||
|
||||
feature {NONE} -- Persistence implementation
|
||||
|
||||
store (a_node: G)
|
||||
|
||||
@@ -44,7 +44,7 @@ feature {NONE} -- Implementation
|
||||
extended_store (a_node: CMS_NODE)
|
||||
-- Store extended data from `a_node'.
|
||||
require
|
||||
not error_handler.has_error
|
||||
not_has_error: not error_handler.has_error
|
||||
do
|
||||
if attached node_storage_extension (a_node) as ext then
|
||||
ext.store_node (a_node)
|
||||
@@ -54,13 +54,23 @@ feature {NONE} -- Implementation
|
||||
extended_load (a_node: CMS_NODE)
|
||||
-- Load extended data into `a_node'.
|
||||
require
|
||||
not error_handler.has_error
|
||||
not_has_error: not error_handler.has_error
|
||||
do
|
||||
if attached node_storage_extension (a_node) as ext then
|
||||
ext.load_node (a_node)
|
||||
end
|
||||
end
|
||||
|
||||
extended_delete (a_node: CMS_NODE)
|
||||
-- Delete extended data related to node `a_node'.
|
||||
require
|
||||
not_has_error: not error_handler.has_error
|
||||
do
|
||||
if attached node_storage_extension (a_node) as ext then
|
||||
ext.delete_node (a_node)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
nodes_count: NATURAL_64
|
||||
@@ -90,6 +100,11 @@ feature -- Access
|
||||
deferred
|
||||
end
|
||||
|
||||
recent_node_changes_before (a_lower: INTEGER; a_count: INTEGER; a_date: DATE_TIME): LIST [CMS_NODE]
|
||||
-- List of recent changes, before `a_date', according to `params' settings.
|
||||
deferred
|
||||
end
|
||||
|
||||
node_by_id (a_id: INTEGER_64): detachable CMS_NODE
|
||||
-- Retrieve node by id `a_id', if any.
|
||||
require
|
||||
@@ -112,6 +127,21 @@ feature -- Access
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Access: outline
|
||||
|
||||
children (a_node: CMS_NODE): detachable LIST [CMS_NODE]
|
||||
-- Children of node `a_node'.
|
||||
-- note: this is the partial version of the nodes.
|
||||
deferred
|
||||
end
|
||||
|
||||
available_parents_for_node (a_node: CMS_NODE): LIST [CMS_NODE]
|
||||
-- Given the node `a_node', return the list of possible parent nodes id
|
||||
deferred
|
||||
ensure
|
||||
a_node_excluded: across Result as ic all not a_node.same_node (ic.item) end
|
||||
end
|
||||
|
||||
feature -- Change: Node
|
||||
|
||||
save_node (a_node: CMS_NODE)
|
||||
@@ -145,16 +175,19 @@ feature -- Change: Node
|
||||
|
||||
delete_node (a_node: CMS_NODE)
|
||||
-- Delete `a_node'.
|
||||
require
|
||||
valid_node_id: a_node.has_id
|
||||
do
|
||||
if a_node.has_id then
|
||||
delete_node_by_id (a_node.id)
|
||||
end
|
||||
-- TODO
|
||||
-- Check if we need to use a transaction
|
||||
-- we delete a node
|
||||
-- node_revisions
|
||||
-- and extensions (PAGE, BLOG, etc).
|
||||
delete_node_base (a_node)
|
||||
end
|
||||
|
||||
delete_node_by_id (a_id: INTEGER_64)
|
||||
-- Remove node by id `a_id'.
|
||||
require
|
||||
valid_node_id: a_id > 0
|
||||
delete_node_base (a_node: CMS_NODE)
|
||||
-- Remove node `a_node'.
|
||||
deferred
|
||||
end
|
||||
|
||||
|
||||
@@ -59,6 +59,12 @@ feature -- Access: node
|
||||
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
|
||||
end
|
||||
|
||||
recent_node_changes_before (a_lower: INTEGER; a_count: INTEGER; a_date: DATE_TIME): LIST [CMS_NODE]
|
||||
-- List of recent changes, before `a_date', according to `params' settings.
|
||||
do
|
||||
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
|
||||
end
|
||||
|
||||
node_by_id (a_id: INTEGER_64): detachable CMS_NODE
|
||||
-- <Precursor>
|
||||
do
|
||||
@@ -80,6 +86,19 @@ feature -- Access: node
|
||||
create {ARRAYED_LIST [CMS_USER]} Result.make (0)
|
||||
end
|
||||
|
||||
feature -- Access: outline
|
||||
|
||||
children (a_node: CMS_NODE): detachable LIST [CMS_NODE]
|
||||
-- <Precursor>
|
||||
do
|
||||
end
|
||||
|
||||
available_parents_for_node (a_node: CMS_NODE): LIST [CMS_NODE]
|
||||
-- <Precursor>
|
||||
do
|
||||
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
|
||||
end
|
||||
|
||||
feature -- Node
|
||||
|
||||
new_node (a_node: CMS_NODE)
|
||||
@@ -87,7 +106,7 @@ feature -- Node
|
||||
do
|
||||
end
|
||||
|
||||
delete_node_by_id (a_id: INTEGER_64)
|
||||
delete_node_base (a_node: CMS_NODE)
|
||||
-- <Precursor>
|
||||
do
|
||||
end
|
||||
|
||||
@@ -53,11 +53,6 @@ feature -- Access
|
||||
end
|
||||
sql_forth
|
||||
end
|
||||
-- across
|
||||
-- Result as ic
|
||||
-- loop
|
||||
-- fill_node (ic.item)
|
||||
-- end
|
||||
end
|
||||
|
||||
node_revisions (a_node: CMS_NODE): LIST [CMS_NODE]
|
||||
@@ -95,7 +90,7 @@ feature -- Access
|
||||
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
|
||||
|
||||
error_handler.reset
|
||||
write_information_log (generator + ".trash_nodes")
|
||||
write_information_log (generator + ".trashed_nodes")
|
||||
|
||||
from
|
||||
create l_parameters.make (1)
|
||||
@@ -124,11 +119,11 @@ feature -- Access
|
||||
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
|
||||
|
||||
error_handler.reset
|
||||
write_information_log (generator + ".nodes")
|
||||
write_information_log (generator + ".recent_nodes")
|
||||
|
||||
from
|
||||
create l_parameters.make (2)
|
||||
l_parameters.put (a_count, "rows")
|
||||
l_parameters.put (a_count, "size")
|
||||
l_parameters.put (a_lower, "offset")
|
||||
sql_query (sql_select_recent_nodes, l_parameters)
|
||||
sql_start
|
||||
@@ -142,13 +137,41 @@ feature -- Access
|
||||
end
|
||||
end
|
||||
|
||||
recent_node_changes_before (a_lower: INTEGER; a_count: INTEGER; a_date: DATE_TIME): LIST [CMS_NODE]
|
||||
-- List of recent changes, before `a_date', according to `params' settings.
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
|
||||
|
||||
error_handler.reset
|
||||
write_information_log (generator + ".recent_node_changes_before")
|
||||
|
||||
from
|
||||
create l_parameters.make (3)
|
||||
l_parameters.put (a_count, "size")
|
||||
l_parameters.put (a_lower, "offset")
|
||||
l_parameters.put (a_date, "date")
|
||||
|
||||
sql_query (sql_select_recent_node_changes_before, l_parameters)
|
||||
sql_start
|
||||
until
|
||||
sql_after
|
||||
loop
|
||||
if attached fetch_node as l_node then
|
||||
Result.force (l_node)
|
||||
end
|
||||
sql_forth
|
||||
end
|
||||
end
|
||||
|
||||
node_by_id (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
|
||||
write_information_log (generator + ".node")
|
||||
write_information_log (generator + ".node_by_id")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id, "nid")
|
||||
sql_query (sql_select_node_by_id, l_parameters)
|
||||
@@ -163,7 +186,7 @@ feature -- Access
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
error_handler.reset
|
||||
write_information_log (generator + ".node")
|
||||
write_information_log (generator + ".node_by_id_and_revision")
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_node_id, "nid")
|
||||
l_parameters.put (a_revision, "revision")
|
||||
@@ -227,6 +250,58 @@ feature -- Access
|
||||
-- end
|
||||
end
|
||||
|
||||
feature -- Access: outline
|
||||
|
||||
children (a_node: CMS_NODE): detachable LIST [CMS_NODE]
|
||||
-- <Precursor>
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
|
||||
|
||||
error_handler.reset
|
||||
write_information_log (generator + ".children")
|
||||
|
||||
from
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_node.id, "nid")
|
||||
sql_query (sql_select_children_of_node, l_parameters)
|
||||
sql_start
|
||||
until
|
||||
sql_after
|
||||
loop
|
||||
if attached fetch_node as l_node then
|
||||
Result.force (l_node)
|
||||
end
|
||||
sql_forth
|
||||
end
|
||||
end
|
||||
|
||||
available_parents_for_node (a_node: CMS_NODE): LIST [CMS_NODE]
|
||||
-- <Precursor>
|
||||
local
|
||||
l_parameters: STRING_TABLE [detachable ANY]
|
||||
do
|
||||
create {ARRAYED_LIST [CMS_NODE]} Result.make (0)
|
||||
|
||||
error_handler.reset
|
||||
write_information_log (generator + ".available_parents_for_node")
|
||||
|
||||
from
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_node.id, "nid")
|
||||
sql_query (sql_select_available_parents_for_node, l_parameters)
|
||||
sql_start
|
||||
until
|
||||
sql_after
|
||||
loop
|
||||
if attached fetch_node as l_node then
|
||||
Result.force (l_node)
|
||||
end
|
||||
sql_forth
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Change: Node
|
||||
|
||||
new_node (a_node: CMS_NODE)
|
||||
@@ -241,34 +316,42 @@ feature -- Change: Node
|
||||
store_node (a_node)
|
||||
end
|
||||
|
||||
delete_node_by_id (a_id: INTEGER_64)
|
||||
trash_node_by_id (a_id: INTEGER_64)
|
||||
-- Remove node by id `a_id'.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
write_information_log (generator + ".delete_node {" + a_id.out + "}")
|
||||
write_information_log (generator + ".trash_node_by_id {" + a_id.out + "}")
|
||||
|
||||
error_handler.reset
|
||||
create l_parameters.make (3)
|
||||
l_parameters.put (create {DATE_TIME}.make_now_utc, "changed")
|
||||
l_parameters.put ({CMS_NODE_API}.trashed, "status")
|
||||
l_parameters.put (a_id, "nid")
|
||||
sql_change (sql_delete_node, l_parameters)
|
||||
sql_change (sql_trash_node, l_parameters)
|
||||
end
|
||||
|
||||
trash_node_by_id (a_id: INTEGER_64)
|
||||
delete_node_base (a_node: CMS_NODE)
|
||||
-- <Precursor>
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
l_time: DATE_TIME
|
||||
do
|
||||
create l_time.make_now_utc
|
||||
write_information_log (generator + ".trash_node {" + a_id.out + "}")
|
||||
write_information_log (generator + ".delete_node_base {" + a_node.id.out + "}")
|
||||
|
||||
error_handler.reset
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_id, "nid")
|
||||
sql_change (sql_trash_node, l_parameters)
|
||||
l_parameters.put (a_node.id, "nid")
|
||||
sql_change (sql_delete_node, l_parameters)
|
||||
|
||||
-- we remove node_revisions and pages.
|
||||
-- Check: maybe we need a transaction.
|
||||
sql_change (sql_delete_node_revisions, l_parameters)
|
||||
|
||||
if not error_handler.has_error then
|
||||
extended_delete (a_node)
|
||||
end
|
||||
end
|
||||
|
||||
restore_node_by_id (a_id: INTEGER_64)
|
||||
@@ -278,7 +361,7 @@ feature -- Change: Node
|
||||
l_time: DATE_TIME
|
||||
do
|
||||
create l_time.make_now_utc
|
||||
write_information_log (generator + ".restore_node {" + a_id.out + "}")
|
||||
write_information_log (generator + ".restore_node_by_id {" + a_id.out + "}")
|
||||
|
||||
error_handler.reset
|
||||
create l_parameters.make (1)
|
||||
@@ -402,7 +485,9 @@ feature {NONE} -- Queries
|
||||
|
||||
sql_select_node_by_id_and_revision: STRING = "SELECT nodes.nid, node_revisions.revision, nodes.type, node_revisions.title, node_revisions.summary, node_revisions.content, node_revisions.format, node_revisions.author, nodes.publish, nodes.created, node_revisions.changed, node_revisions.status FROM nodes INNER JOIN node_revisions ON nodes.nid = node_revisions.nid WHERE nodes.nid = :nid AND node_revisions.revision = :revision ORDER BY node_revisions.revision DESC;"
|
||||
|
||||
sql_select_recent_nodes: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM nodes ORDER BY nid DESC, publish DESC LIMIT :rows OFFSET :offset ;"
|
||||
sql_select_recent_nodes: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM nodes ORDER BY nid DESC, publish DESC LIMIT :size OFFSET :offset ;"
|
||||
|
||||
sql_select_recent_node_changes_before: STRING = "SELECT nid, revision, type, title, summary, content, format, author, publish, created, changed, status FROM nodes WHERE changed <= :date ORDER BY changed DESC, nid DESC LIMIT :size OFFSET :offset ;"
|
||||
|
||||
sql_insert_node: STRING = "INSERT INTO nodes (revision, type, title, summary, content, format, publish, created, changed, status, author) VALUES (:revision, :type, :title, :summary, :content, :format, :publish, :created, :changed, :status, :author);"
|
||||
-- SQL Insert to add a new node.
|
||||
@@ -410,10 +495,10 @@ feature {NONE} -- Queries
|
||||
sql_update_node : STRING = "UPDATE nodes SET revision=:revision, type=:type, title=:title, summary=:summary, content=:content, format=:format, publish=:publish, changed=:changed, status=:status, author=:author WHERE nid=:nid;"
|
||||
-- SQL update node.
|
||||
|
||||
sql_delete_node: STRING = "UPDATE nodes SET changed=:changed, status =:status WHERE nid=:nid"
|
||||
sql_trash_node: STRING = "UPDATE nodes SET changed=:changed, status =:status WHERE nid=:nid"
|
||||
-- Soft deletion with free metadata.
|
||||
|
||||
sql_trash_node: STRING = "DELETE FROM nodes WHERE nid=:nid"
|
||||
sql_delete_node: STRING = "DELETE FROM nodes WHERE nid=:nid"
|
||||
-- Physical deletion with free metadata.
|
||||
|
||||
sql_restore_node: STRING = "UPDATE nodes SET changed=:changed, status =:status WHERE nid=:nid"
|
||||
@@ -426,6 +511,20 @@ feature {NONE} -- Queries
|
||||
Sql_last_insert_node_revision: STRING = "SELECT MAX(revision) FROM node_revisions;"
|
||||
Sql_last_insert_node_revision_for_nid: STRING = "SELECT MAX(revision) FROM node_revisions WHERE nid=:nid;"
|
||||
|
||||
sql_select_available_parents_for_node : STRING = "[
|
||||
SELECT node.nid, node.revision, node.type, title, summary, content, format, author, publish, created, changed, status
|
||||
FROM nodes node LEFT JOIN page_nodes pn ON node.nid = pn.nid AND node.nid != :nid
|
||||
WHERE node.nid != :nid AND pn.parent != :nid AND node.status != -1 GROUP BY node.nid, node.revision;
|
||||
]"
|
||||
|
||||
sql_select_children_of_node: STRING = "[
|
||||
SELECT node.nid, node.revision, node.type, title, summary, content, format, author, publish, created, changed, status
|
||||
FROM nodes node LEFT JOIN page_nodes pn ON node.nid = pn.nid
|
||||
WHERE pn.parent = :nid AND node.status != -1 GROUP BY node.nid, node.revision;
|
||||
]"
|
||||
|
||||
sql_delete_node_revisions: STRING = "DELETE FROM node_revisions WHERE nid=:nid;"
|
||||
|
||||
feature {NONE} -- Sql Queries: USER_ROLES collaborators, author
|
||||
|
||||
Select_user_author: STRING = "SELECT uid, name, password, salt, email, users.status, users.created, signed FROM nodes INNER JOIN users ON nodes.author=users.uid AND nodes.nid = :nid AND nodes.revision = :revision;"
|
||||
|
||||
@@ -55,7 +55,7 @@ feature -- Persistence
|
||||
error_handler.reset
|
||||
-- Check existing record, if any.
|
||||
if attached node_data (a_node) as d then
|
||||
l_update := True
|
||||
l_update := a_node.revision = d.revision
|
||||
l_previous_parent_id := d.parent_id
|
||||
end
|
||||
if not has_error then
|
||||
@@ -112,9 +112,22 @@ feature -- Persistence
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
delete_node (a_node: CMS_PAGE)
|
||||
-- <Precursor>
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
do
|
||||
if a_node.has_id then
|
||||
create l_parameters.make (1)
|
||||
l_parameters.put (a_node.id, "nid")
|
||||
sql_change (sql_delete_node_data, l_parameters)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
node_data (a_node: CMS_NODE): detachable TUPLE [parent_id: INTEGER_64]
|
||||
node_data (a_node: CMS_NODE): detachable TUPLE [revision: INTEGER_64; parent_id: INTEGER_64]
|
||||
-- Node extension data for node `a_node' as tuple.
|
||||
local
|
||||
l_parameters: STRING_TABLE [ANY]
|
||||
@@ -129,17 +142,20 @@ feature {NONE} -- Implementation
|
||||
n := sql_rows_count
|
||||
if n = 1 then
|
||||
-- nid, revision, parent
|
||||
Result := [sql_read_integer_64 (3)]
|
||||
Result := [sql_read_integer_64 (2), sql_read_integer_64 (3)]
|
||||
else
|
||||
check unique_data: n = 0 end
|
||||
end
|
||||
end
|
||||
ensure
|
||||
accepted_revision: Result /= Void implies Result.revision <= a_node.revision
|
||||
end
|
||||
|
||||
feature -- SQL
|
||||
|
||||
sql_select_node_data: STRING = "SELECT nid, revision, parent FROM page_nodes WHERE nid =:nid AND revision<=:revision ORDER BY revision DESC LIMIT 1;"
|
||||
sql_select_node_data: STRING = "SELECT nid, revision, parent FROM page_nodes WHERE nid=:nid AND revision<=:revision ORDER BY revision DESC LIMIT 1;"
|
||||
sql_insert_node_data: STRING = "INSERT INTO page_nodes (nid, revision, parent) VALUES (:nid, :revision, :parent);"
|
||||
sql_update_node_data: STRING = "UPDATE page_nodes SET nid=:nid, revision=:revision, parent=:parent WHERE nid=:nid AND revision=:revision;"
|
||||
sql_delete_node_data: STRING = "DELETE FROM page_nodes WHERE nid=:nid;"
|
||||
|
||||
end
|
||||
|
||||
@@ -29,6 +29,10 @@ feature -- Access
|
||||
date: DATE_TIME
|
||||
-- Time of the event item.
|
||||
|
||||
author_name: detachable READABLE_STRING_32
|
||||
-- Optional author name.
|
||||
-- It is possible to have author_name /= Void and author = Void.
|
||||
|
||||
author: detachable CMS_USER
|
||||
-- Optional author.
|
||||
|
||||
@@ -41,10 +45,19 @@ feature -- Access
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_author_name (n: like author_name)
|
||||
-- Set `author_name' to `n'.
|
||||
do
|
||||
author_name := n
|
||||
end
|
||||
|
||||
set_author (u: like author)
|
||||
-- Set `author' to `u'.
|
||||
do
|
||||
author := u
|
||||
if u /= Void and author_name = Void then
|
||||
set_author_name (u.name)
|
||||
end
|
||||
end
|
||||
|
||||
set_information (a_info: like information)
|
||||
|
||||
@@ -9,26 +9,16 @@ deferred class
|
||||
inherit
|
||||
CMS_HOOK
|
||||
|
||||
-- CMS_HOOK_WITH_WRAPPER
|
||||
-- rename
|
||||
-- wrapper as recent_changes_hook_wrapper
|
||||
-- redefine
|
||||
-- recent_changes_hook_wrapper
|
||||
-- end
|
||||
|
||||
feature -- Invocation
|
||||
|
||||
populate_recent_changes (a_changes: CMS_RECENT_CHANGE_CONTAINER; a_sources: LIST [READABLE_STRING_8])
|
||||
-- Populate recent changes inside `a_changes' according to associated parameters.
|
||||
-- Also provide sources of information.
|
||||
recent_changes_sources: detachable LIST [READABLE_STRING_8]
|
||||
-- Source provided by Current hook.
|
||||
deferred
|
||||
end
|
||||
|
||||
--feature -- Wrapper
|
||||
|
||||
-- recent_changes_hook_wrapper: detachable CMS_RECENT_CHANGES_HOOK_WRAPPER
|
||||
-- do
|
||||
-- create Result.make (Current)
|
||||
-- end
|
||||
populate_recent_changes (a_changes: CMS_RECENT_CHANGE_CONTAINER; a_current_user: detachable CMS_USER)
|
||||
-- Populate recent changes inside `a_changes' according to associated parameters.
|
||||
deferred
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
note
|
||||
description: "CMS module that bring support for recent changes."
|
||||
description: "CMS module that brings support for recent changes."
|
||||
date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
|
||||
revision: "$Revision: 96616 $"
|
||||
|
||||
@@ -11,13 +11,16 @@ inherit
|
||||
rename
|
||||
module_api as recent_changes_api
|
||||
redefine
|
||||
register_hooks
|
||||
register_hooks,
|
||||
permissions
|
||||
end
|
||||
|
||||
CMS_HOOK_MENU_SYSTEM_ALTER
|
||||
|
||||
CMS_HOOK_RESPONSE_ALTER
|
||||
|
||||
CMS_HOOK_BLOCK
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
@@ -35,105 +38,349 @@ feature -- Access
|
||||
|
||||
name: STRING = "recent_changes"
|
||||
|
||||
permissions: LIST [READABLE_STRING_8]
|
||||
-- List of permission ids, used by this module, and declared.
|
||||
do
|
||||
Result := Precursor
|
||||
Result.force ("view recent changes")
|
||||
end
|
||||
|
||||
feature -- Access: router
|
||||
|
||||
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
|
||||
-- <Precursor>
|
||||
do
|
||||
a_router.handle ("/recent_changes/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_recent_changes (a_api, ?, ?)), a_router.methods_head_get)
|
||||
a_router.handle ("/recent_changes/feed", create {WSF_URI_AGENT_HANDLER}.make (agent handle_recent_changes_feed (a_api, ?, ?)), a_router.methods_head_get)
|
||||
end
|
||||
|
||||
feature -- Hook
|
||||
|
||||
block_list: ITERABLE [like {CMS_BLOCK}.name]
|
||||
-- List of block names, managed by current object.
|
||||
-- If prefixed by "?", condition will be check
|
||||
-- to determine if it should be displayed (and computed) or not.
|
||||
do
|
||||
Result := <<"?recent_changes">>
|
||||
end
|
||||
|
||||
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
-- Get block object identified by `a_block_id' and associate with `a_response'.
|
||||
local
|
||||
b: CMS_CONTENT_BLOCK
|
||||
s, l_content: STRING
|
||||
gen: FEED_TO_XHTML_VISITOR
|
||||
do
|
||||
if a_block_id.same_string_general ("recent_changes") then
|
||||
create l_content.make (1024)
|
||||
create gen.make (l_content)
|
||||
|
||||
create s.make_empty
|
||||
s.append_string ("<liv class=%"nav%">")
|
||||
s.append_string (a_response.link ("See more ...", "recent_changes/", Void))
|
||||
s.append_string ("</li>")
|
||||
gen.set_footer (s)
|
||||
|
||||
recent_changes_feed (a_response, 10, Void).accept (gen)
|
||||
|
||||
create b.make (a_block_id, Void, l_content, Void)
|
||||
a_response.put_block (b, Void, False)
|
||||
end
|
||||
end
|
||||
|
||||
recent_changes_feed (a_response: CMS_RESPONSE; a_size: NATURAL_32; a_source: detachable READABLE_STRING_8): FEED
|
||||
local
|
||||
l_changes: CMS_RECENT_CHANGE_CONTAINER
|
||||
ch: CMS_RECENT_CHANGE_ITEM
|
||||
l_user: detachable CMS_USER
|
||||
l_feed: FEED
|
||||
l_feed_item: FEED_ITEM
|
||||
lnk: FEED_LINK
|
||||
nb: NATURAL_32
|
||||
do
|
||||
l_user := Void -- Public access for the feed!
|
||||
create l_changes.make (a_size, create {DATE_TIME}.make_now_utc, a_source)
|
||||
if attached a_response.hooks.subscribers ({CMS_RECENT_CHANGES_HOOK}) as lst then
|
||||
across
|
||||
lst as ic
|
||||
loop
|
||||
if attached {CMS_RECENT_CHANGES_HOOK} ic.item as h then
|
||||
if attached h.recent_changes_sources as h_sources then
|
||||
if
|
||||
a_source = Void
|
||||
or else across h_sources as h_ic some h_ic.item.is_case_insensitive_equal (a_source) end
|
||||
then
|
||||
h.populate_recent_changes (l_changes, l_user)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
create l_feed.make ("CMS Recent changes")
|
||||
l_feed.set_date (create {DATE_TIME}.make_now_utc)
|
||||
nb := a_size
|
||||
across
|
||||
l_changes as ic
|
||||
until
|
||||
nb = 0
|
||||
loop
|
||||
ch := ic.item
|
||||
create l_feed_item.make (ch.link.title)
|
||||
l_feed_item.set_date (ch.date)
|
||||
l_feed_item.set_description (ch.information)
|
||||
l_feed_item.set_category (ch.source)
|
||||
create lnk.make (a_response.absolute_url (ch.link.location, Void))
|
||||
l_feed_item.links.force (lnk, "")
|
||||
l_feed.extend (l_feed_item)
|
||||
nb := nb - 1
|
||||
end
|
||||
l_feed.sort
|
||||
Result := l_feed
|
||||
end
|
||||
|
||||
feature -- Handler
|
||||
|
||||
handle_recent_changes_feed (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
r: CMS_RESPONSE
|
||||
htdate: HTTP_DATE
|
||||
l_content: STRING
|
||||
l_until_date: detachable DATE_TIME
|
||||
l_until_date_timestamp: INTEGER_64
|
||||
l_filter_source: detachable READABLE_STRING_8
|
||||
l_size: NATURAL_32
|
||||
mesg: CMS_CUSTOM_RESPONSE_MESSAGE
|
||||
do
|
||||
if attached {WSF_STRING} req.query_parameter ("date") as p_until_date then
|
||||
l_until_date_timestamp := p_until_date.value.to_integer_64
|
||||
create htdate.make_from_timestamp (l_until_date_timestamp)
|
||||
l_until_date := htdate.date_time
|
||||
end
|
||||
if attached {WSF_STRING} req.query_parameter ("source") as p_filter then
|
||||
l_filter_source := p_filter.url_encoded_value
|
||||
if l_filter_source.is_empty then
|
||||
l_filter_source := Void
|
||||
end
|
||||
end
|
||||
if attached {WSF_STRING} req.query_parameter ("size") as p_size then
|
||||
l_size := p_size.integer_value.to_natural_32
|
||||
end
|
||||
if l_size = 0 then
|
||||
l_size := 25
|
||||
end
|
||||
|
||||
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
|
||||
create l_content.make (1024)
|
||||
recent_changes_feed (r, l_size, l_filter_source).accept (create {ATOM_FEED_GENERATOR}.make (l_content))
|
||||
create mesg.make ({HTTP_STATUS_CODE}.ok)
|
||||
mesg.set_payload (l_content)
|
||||
res.send (mesg)
|
||||
end
|
||||
|
||||
handle_recent_changes (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
r: CMS_RESPONSE
|
||||
l_changes: CMS_RECENT_CHANGE_CONTAINER
|
||||
l_sources: ARRAYED_LIST [READABLE_STRING_8]
|
||||
dt, prev_dt: detachable DATE
|
||||
ch: CMS_RECENT_CHANGE_ITEM
|
||||
dt, prev_dt: detachable DATE_TIME
|
||||
prev_info: detachable READABLE_STRING_8
|
||||
ch: detachable CMS_RECENT_CHANGE_ITEM
|
||||
htdate: HTTP_DATE
|
||||
l_content: STRING
|
||||
l_form: CMS_FORM
|
||||
l_select: WSF_FORM_SELECT
|
||||
l_size_field: WSF_FORM_NUMBER_INPUT
|
||||
l_date_field: WSF_FORM_HIDDEN_INPUT
|
||||
l_submit: WSF_FORM_SUBMIT_INPUT
|
||||
l_until_date: detachable DATE_TIME
|
||||
l_until_date_timestamp: INTEGER_64
|
||||
l_filter_source: detachable READABLE_STRING_8
|
||||
l_size: NATURAL_32
|
||||
l_query: STRING
|
||||
opt: WSF_FORM_SELECT_OPTION
|
||||
l_user: detachable CMS_USER
|
||||
i: INTEGER
|
||||
do
|
||||
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
|
||||
create l_changes.make (25, Void, Void)
|
||||
if attached {WSF_STRING} req.query_parameter ("date") as p_until_date then
|
||||
l_until_date_timestamp := p_until_date.value.to_integer_64
|
||||
create htdate.make_from_timestamp (l_until_date_timestamp)
|
||||
l_until_date := htdate.date_time
|
||||
-- l_until_date.second_add (-1)
|
||||
end
|
||||
if attached {WSF_STRING} req.query_parameter ("source") as p_filter then
|
||||
l_filter_source := p_filter.url_encoded_value
|
||||
if l_filter_source.is_empty then
|
||||
l_filter_source := Void
|
||||
end
|
||||
end
|
||||
if attached {WSF_STRING} req.query_parameter ("size") as p_size then
|
||||
l_size := p_size.integer_value.to_natural_32
|
||||
end
|
||||
if l_size = 0 then
|
||||
l_size := 25
|
||||
end
|
||||
|
||||
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
|
||||
if r.has_permission ("view recent changes") then
|
||||
l_user := r.user
|
||||
create l_changes.make (l_size, l_until_date, l_filter_source)
|
||||
|
||||
create l_content.make (1024)
|
||||
if attached r.hooks.subscribers ({CMS_RECENT_CHANGES_HOOK}) as lst then
|
||||
create l_sources.make (lst.count)
|
||||
|
||||
across
|
||||
lst as ic
|
||||
loop
|
||||
if attached {CMS_RECENT_CHANGES_HOOK} ic.item as h then
|
||||
if attached h.recent_changes_sources as h_sources then
|
||||
l_sources.append (h_sources)
|
||||
if
|
||||
l_filter_source = Void
|
||||
or else across h_sources as h_ic some h_ic.item.is_case_insensitive_equal (l_filter_source) end
|
||||
then
|
||||
h.populate_recent_changes (l_changes, l_user)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
create l_form.make (req.percent_encoded_path_info, "recent-changes")
|
||||
l_form.set_method_get
|
||||
create l_select.make ("source")
|
||||
l_select.set_label ("Sources")
|
||||
create opt.make ("", "Any source")
|
||||
l_select.add_option (opt)
|
||||
across
|
||||
l_sources as ic
|
||||
loop
|
||||
create opt.make (ic.item, ic.item)
|
||||
if l_filter_source /= Void and then ic.item.is_case_insensitive_equal (l_filter_source) then
|
||||
opt.set_is_selected (True)
|
||||
end
|
||||
l_select.add_option (opt)
|
||||
end
|
||||
l_form.extend (l_select)
|
||||
|
||||
create l_size_field.make_with_text ("size", l_size.out)
|
||||
l_size_field.set_size (25)
|
||||
l_size_field.set_label ("Items per page")
|
||||
l_form.extend (l_size_field)
|
||||
|
||||
if l_until_date /= Void then
|
||||
create l_date_field.make_with_text ("date", l_until_date_timestamp.out)
|
||||
l_form.extend (l_date_field)
|
||||
end
|
||||
|
||||
create l_submit.make_with_text ("op", "Filter")
|
||||
l_form.extend (l_submit)
|
||||
l_form.extend_html_text ("<br/>")
|
||||
l_form.append_to_html (create {CMS_TO_WSF_THEME}.make (r, r.theme), l_content)
|
||||
end
|
||||
|
||||
l_changes.reverse_sort
|
||||
l_content.append ("<table class=%"recent-changes%">")
|
||||
l_content.append ("<thead>")
|
||||
l_content.append ("<tr>")
|
||||
l_content.append ("<th>Date</th>")
|
||||
l_content.append ("<th>Source</th>")
|
||||
l_content.append ("<th>Resource</th>")
|
||||
l_content.append ("<th>User</th>")
|
||||
l_content.append ("<th>Information</th>")
|
||||
l_content.append ("</tr>")
|
||||
l_content.append ("</thead>")
|
||||
l_content.append ("<tbody>")
|
||||
|
||||
create l_content.make (1024)
|
||||
if attached r.hooks.subscribers ({CMS_RECENT_CHANGES_HOOK}) as lst then
|
||||
create l_sources.make (lst.count)
|
||||
across
|
||||
lst as ic
|
||||
l_changes as ic
|
||||
loop
|
||||
if attached {CMS_RECENT_CHANGES_HOOK} ic.item as h then
|
||||
h.populate_recent_changes (l_changes, l_sources)
|
||||
ch := ic.item
|
||||
dt := ch.date
|
||||
if prev_dt = Void or else dt.date /~ prev_dt.date then
|
||||
l_content.append ("<tr>")
|
||||
l_content.append ("<td class=%"title%" colspan=%"5%">")
|
||||
l_content.append (dt.date.formatted_out ("ddd, dd mmm yyyy"))
|
||||
l_content.append ("</td>")
|
||||
l_content.append ("</tr>")
|
||||
end
|
||||
l_content.append ("<tr>")
|
||||
l_content.append ("<td class=%"date%">")
|
||||
if dt /~ prev_dt then
|
||||
create htdate.make_from_date_time (dt)
|
||||
htdate.append_to_rfc1123_string (l_content)
|
||||
else
|
||||
l_content.append ("<span class=%"same-value%">''</span>")
|
||||
end
|
||||
l_content.append ("</td>")
|
||||
|
||||
l_content.append ("<td class=%"source%">" + ch.source + "</td>")
|
||||
l_content.append ("<td class=%"resource%">")
|
||||
l_content.append (r.link (ch.link.title, ch.link.location, Void))
|
||||
l_content.append ("</td>")
|
||||
l_content.append ("<td class=%"user%">")
|
||||
if attached ch.author as u then
|
||||
l_content.append (r.link (u.name, "user/" + u.id.out, Void))
|
||||
elseif attached ch.author_name as un then
|
||||
l_content.append (r.html_encoded (un))
|
||||
end
|
||||
l_content.append ("</td>")
|
||||
l_content.append ("<td class=%"info%">")
|
||||
if attached ch.information as l_info and then not l_info.is_empty then
|
||||
if prev_dt ~ dt and prev_info ~ l_info then
|
||||
l_content.append ("<span class=%"same-value%">''</span>")
|
||||
else
|
||||
i := l_info.index_of ('%N', 1)
|
||||
if i > 0 and i < l_info.count then
|
||||
l_content.append (l_info.substring (1, i - 1))
|
||||
l_content.append ("<span class=%"tooltip%">")
|
||||
l_content.append (l_info.substring (i, l_info.count))
|
||||
l_content.append ("</span>")
|
||||
else
|
||||
l_content.append (l_info)
|
||||
end
|
||||
end
|
||||
prev_info := l_info
|
||||
else
|
||||
prev_info := Void
|
||||
end
|
||||
l_content.append ("</td>")
|
||||
l_content.append ("</tr>%N")
|
||||
prev_dt := dt
|
||||
end
|
||||
l_content.append ("</tbody>")
|
||||
l_content.append ("</table>%N")
|
||||
|
||||
if ch /= Void then
|
||||
if l_until_date /= Void then
|
||||
l_content.append (" <a href=%"")
|
||||
l_content.append (r.url (r.location, Void))
|
||||
l_content.append ("?size=" + l_size.out + "%"><<</a> ")
|
||||
end
|
||||
|
||||
if l_until_date /~ ch.date then
|
||||
create htdate.make_from_date_time (ch.date)
|
||||
create l_query.make_from_string ("size=" + l_size.out)
|
||||
l_query.append ("&date=")
|
||||
l_query.append (htdate.timestamp.out)
|
||||
if l_filter_source /= Void then
|
||||
l_query.append ("&filter=")
|
||||
l_query.append (l_filter_source)
|
||||
end
|
||||
l_content.append ("<a href=%"")
|
||||
l_content.append (r.url (r.location, create {CMS_API_OPTIONS}.make_from_manifest (<<["query", l_query]>>)))
|
||||
l_content.append ("%">See more ...</a>")
|
||||
end
|
||||
end
|
||||
create l_form.make (req.percent_encoded_path_info, "recent-changes")
|
||||
create l_select.make ("source")
|
||||
l_select.set_label ("Sources")
|
||||
across
|
||||
l_sources as ic
|
||||
loop
|
||||
l_select.add_option (create {WSF_FORM_SELECT_OPTION}.make (ic.item, ic.item))
|
||||
end
|
||||
l_form.extend (l_select)
|
||||
l_form.extend_html_text ("<br/>")
|
||||
l_form.append_to_html (create {CMS_TO_WSF_THEME}.make (r, r.theme), l_content)
|
||||
end
|
||||
|
||||
l_changes.reverse_sort
|
||||
l_content.append ("<table class=%"recent-changes%" style=%"border-spacing: 5px;%">")
|
||||
l_content.append ("<thead>")
|
||||
l_content.append ("<tr>")
|
||||
l_content.append ("<th>Date</th>")
|
||||
l_content.append ("<th>Source</th>")
|
||||
l_content.append ("<th>Resource</th>")
|
||||
l_content.append ("<th>User</th>")
|
||||
l_content.append ("<th>Information</th>")
|
||||
l_content.append ("</tr>")
|
||||
l_content.append ("</thead>")
|
||||
l_content.append ("<tbody>")
|
||||
|
||||
across
|
||||
l_changes as ic
|
||||
loop
|
||||
ch := ic.item
|
||||
dt := ch.date.date
|
||||
if dt /~ prev_dt then
|
||||
l_content.append ("<tr>")
|
||||
l_content.append ("<td class=%"title%" colspan=%"5%">")
|
||||
l_content.append (dt.formatted_out ("ddd, dd mmm yyyy"))
|
||||
l_content.append ("</td>")
|
||||
l_content.append ("</tr>")
|
||||
r.set_main_content (l_content)
|
||||
if l_until_date = Void then
|
||||
r.set_title ("Recent changes")
|
||||
else
|
||||
create htdate.make_from_date_time (l_until_date)
|
||||
r.set_title ("Recent changes before " + htdate.string)
|
||||
end
|
||||
prev_dt := dt
|
||||
l_content.append ("<tr>")
|
||||
l_content.append ("<td class=%"date%">")
|
||||
create htdate.make_from_date_time (ch.date)
|
||||
htdate.append_to_rfc1123_string (l_content)
|
||||
l_content.append ("</td>")
|
||||
l_content.append ("<td class=%"source%">" + ch.source + "</td>")
|
||||
l_content.append ("<td class=%"resource%">")
|
||||
l_content.append (r.link (ch.link.title, ch.link.location, Void))
|
||||
l_content.append ("</td>")
|
||||
l_content.append ("<td class=%"user%">")
|
||||
if attached ch.author as u then
|
||||
l_content.append (r.link (u.name, "user/" + u.id.out, Void))
|
||||
end
|
||||
l_content.append ("</td>")
|
||||
l_content.append ("<td class=%"info%">")
|
||||
if attached ch.information as l_info then
|
||||
l_content.append ("<strong>" + l_info + "</strong> ")
|
||||
end
|
||||
l_content.append ("</td>")
|
||||
l_content.append ("</tr>%N")
|
||||
else
|
||||
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
|
||||
end
|
||||
l_content.append ("</tbody>")
|
||||
l_content.append ("</table>%N")
|
||||
r.set_main_content (l_content)
|
||||
r.set_title ("Last " + l_changes.count.out + " changes")
|
||||
|
||||
r.execute
|
||||
end
|
||||
@@ -145,6 +392,7 @@ feature -- Hooks configuration
|
||||
do
|
||||
a_response.hooks.subscribe_to_menu_system_alter_hook (Current)
|
||||
a_response.hooks.subscribe_to_response_alter_hook (Current)
|
||||
a_response.hooks.subscribe_to_block_hook (Current)
|
||||
end
|
||||
|
||||
feature -- Hook
|
||||
@@ -172,9 +420,5 @@ feature -- Hook
|
||||
a_menu_system.navigation_menu.extend (lnk)
|
||||
end
|
||||
|
||||
-- populate_recent_changes (lst: LIST [CMS_RECENT_CHANGE_ITEM]; a_date: detachable DATE_TIME; a_limit: INTEGER)
|
||||
-- do
|
||||
-- end
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<library name="cms" location="..\..\cms-safe.ecf"/>
|
||||
<library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/>
|
||||
<library name="error" location="$ISE_LIBRARY\contrib\library\utility\general\error\error-safe.ecf"/>
|
||||
<library name="feed" location="$ISE_LIBRARY\contrib\library\text\parser\feed\feed-safe.ecf"/>
|
||||
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
|
||||
<library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension-safe.ecf" readonly="false"/>
|
||||
|
||||
18
package.iron
18
package.iron
@@ -1,4 +1,4 @@
|
||||
package ROC_cms
|
||||
package ROC
|
||||
|
||||
project
|
||||
cms = "cms-safe.ecf"
|
||||
@@ -19,6 +19,21 @@ project
|
||||
basic_auth = "modules/basic_auth/basic_auth.ecf"
|
||||
node = "modules/node/node-safe.ecf"
|
||||
node = "modules/node/node.ecf"
|
||||
demo = "examples/demo/demo-safe.ecf"
|
||||
cms_demo_module = "examples/demo/modules/demo/cms_demo_module-safe.ecf"
|
||||
config_tests = "library/configuration/tests/config_tests-safe.ecf"
|
||||
email_service = "library/email/email-safe.ecf"
|
||||
persistence_sqlite3 = "library/persistence/sqlite3/persistence_sqlite3-safe.ecf"
|
||||
store_mysql = "library/persistence/store_mysql/store_mysql-safe.ecf"
|
||||
persistence_store_odbc = "library/persistence/store_odbc/store_odbc-safe.ecf"
|
||||
tests_store_odbc = "library/persistence/store_odbc/tests/tests-safe.ecf"
|
||||
admin = "modules/admin/admin-safe.ecf"
|
||||
auth_module = "modules/auth/auth-safe.ecf"
|
||||
cms_blog_module = "modules/blog/cms_blog_module-safe.ecf"
|
||||
feed_aggregator = "modules/feed_aggregator/feed_aggregator-safe.ecf"
|
||||
oauth_module = "modules/oauth20/oauth20-safe.ecf"
|
||||
openid_module = "modules/openid/openid-safe.ecf"
|
||||
recent_changes = "modules/recent_changes/recent_changes-safe.ecf"
|
||||
|
||||
note
|
||||
title: ROC CMS
|
||||
@@ -27,5 +42,6 @@ note
|
||||
license: Eiffel Forum v2
|
||||
copyright: Jocelyn Fiat, Javier Velilla, Eiffel Software
|
||||
link[source]: "Github" https://github.com/EiffelWebFramework/ROC.git
|
||||
-- link[doc]: "Documentation" http://
|
||||
|
||||
end
|
||||
|
||||
94
src/cache/cms_cache.e
vendored
Normal file
94
src/cache/cms_cache.e
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
note
|
||||
description: "Abstract interface for cache of value conforming to formal {G}."
|
||||
date: "$Date: 2014-12-03 16:12:08 +0100 (mer., 03 déc. 2014) $"
|
||||
revision: "$Revision: 96232 $"
|
||||
|
||||
deferred class
|
||||
CMS_CACHE [G -> ANY]
|
||||
|
||||
feature -- Status report
|
||||
|
||||
exists: BOOLEAN
|
||||
-- Do associated cache file exists?
|
||||
deferred
|
||||
end
|
||||
|
||||
expired (a_reference_date: detachable DATE_TIME; a_duration_in_seconds: INTEGER): BOOLEAN
|
||||
-- Is associated cached item expired?
|
||||
-- If `a_reference_date' is attached, cache is expired if `a_reference' is more recent than cached item.
|
||||
local
|
||||
d1, d2: DATE_TIME
|
||||
do
|
||||
if exists then
|
||||
if
|
||||
a_reference_date /= Void and then
|
||||
a_reference_date > cache_date_time
|
||||
then
|
||||
Result := True
|
||||
else
|
||||
if a_duration_in_seconds = -1 then
|
||||
Result := False -- Never expires
|
||||
elseif a_duration_in_seconds = 0 then
|
||||
Result := True -- Always expires
|
||||
elseif a_duration_in_seconds > 0 then
|
||||
d1 := cache_date_time
|
||||
d2 := current_date_time
|
||||
d2.second_add (- a_duration_in_seconds) --| do not modify `cache_date_time'
|
||||
Result := d2 > d1 -- cached date + duration is older than current date
|
||||
else
|
||||
-- Invalid expiration value
|
||||
-- thus always expired.
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
else
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
item: detachable G
|
||||
-- Value from the cache.
|
||||
deferred
|
||||
end
|
||||
|
||||
cache_date_time: DATE_TIME
|
||||
-- Date time for current cache if exists.
|
||||
-- Note: it may be UTC or not , depending on cache type.
|
||||
deferred
|
||||
end
|
||||
|
||||
cache_duration_in_seconds: INTEGER_64
|
||||
-- Number of seconds since cache was set.
|
||||
require
|
||||
exists: exists
|
||||
local
|
||||
d1, d2: DATE_TIME
|
||||
do
|
||||
d1 := cache_date_time
|
||||
d2 := current_date_time
|
||||
Result := d2.relative_duration (d1).seconds_count
|
||||
end
|
||||
|
||||
current_date_time: DATE_TIME
|
||||
-- Current date time for relative duration with cache_date_time.
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
delete
|
||||
-- Remove cache.
|
||||
deferred
|
||||
end
|
||||
|
||||
put (g: G)
|
||||
-- Put `g' into cache.
|
||||
deferred
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
150
src/cache/cms_file_cache.e
vendored
Normal file
150
src/cache/cms_file_cache.e
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
note
|
||||
description: "Cache using a local file."
|
||||
date: "$Date: 2015-09-24 18:24:06 +0200 (jeu., 24 sept. 2015) $"
|
||||
revision: "$Revision: 97926 $"
|
||||
|
||||
deferred class
|
||||
CMS_FILE_CACHE [G -> ANY]
|
||||
|
||||
inherit
|
||||
CMS_CACHE [G]
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_cache_filename: PATH)
|
||||
do
|
||||
path := a_cache_filename
|
||||
end
|
||||
|
||||
path: PATH
|
||||
|
||||
feature -- Status report
|
||||
|
||||
exists: BOOLEAN
|
||||
-- Do associated cache file exists?
|
||||
local
|
||||
ut: FILE_UTILITIES
|
||||
do
|
||||
Result := ut.file_path_exists (path)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
cache_date_time: DATE_TIME
|
||||
-- <Precursor>
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make_with_path (path)
|
||||
if f.exists then
|
||||
Result := utc_file_date_time (f)
|
||||
else
|
||||
create Result.make_now_utc
|
||||
end
|
||||
end
|
||||
|
||||
current_date_time: DATE_TIME
|
||||
-- <Precursor>
|
||||
do
|
||||
-- UTC, since `cache_date_time' is UTC!
|
||||
create Result.make_now_utc
|
||||
end
|
||||
|
||||
file_size: INTEGER
|
||||
-- Associated file size.
|
||||
require
|
||||
exists: exists
|
||||
local
|
||||
f: RAW_FILE
|
||||
do
|
||||
create f.make_with_path (path)
|
||||
if f.exists and then f.is_access_readable then
|
||||
Result := f.count
|
||||
end
|
||||
end
|
||||
|
||||
item: detachable G
|
||||
local
|
||||
f: RAW_FILE
|
||||
retried: BOOLEAN
|
||||
do
|
||||
if not retried then
|
||||
create f.make_with_path (path)
|
||||
if f.exists and then f.is_access_readable then
|
||||
f.open_read
|
||||
Result := file_to_item (f)
|
||||
f.close
|
||||
end
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
delete
|
||||
-- <Precursor>
|
||||
local
|
||||
f: RAW_FILE
|
||||
retried: BOOLEAN
|
||||
do
|
||||
if not retried then
|
||||
create f.make_with_path (path)
|
||||
-- Create recursively parent directory if it does not exists.
|
||||
if f.exists and then f.is_access_writable then
|
||||
f.delete
|
||||
end
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
|
||||
put (g: G)
|
||||
-- <Precursor>
|
||||
local
|
||||
f: RAW_FILE
|
||||
d: DIRECTORY
|
||||
do
|
||||
create f.make_with_path (path)
|
||||
-- Create recursively parent directory if it does not exists.
|
||||
create d.make_with_path (path.parent)
|
||||
if not d.exists then
|
||||
d.recursive_create_dir
|
||||
end
|
||||
if not f.exists or else f.is_access_writable then
|
||||
f.open_write
|
||||
item_to_file (g, f)
|
||||
f.close
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Helpers
|
||||
|
||||
utc_file_date_time (f: FILE): DATE_TIME
|
||||
-- Last change date for file `f'.
|
||||
require
|
||||
f.exists
|
||||
do
|
||||
create Result.make_from_epoch (f.date.as_integer_32)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
file_to_item (f: FILE): detachable G
|
||||
require
|
||||
is_open_write: f.is_open_read
|
||||
deferred
|
||||
end
|
||||
|
||||
item_to_file (g: G; f: FILE)
|
||||
require
|
||||
is_open_write: f.is_open_write
|
||||
deferred
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
49
src/cache/cms_file_object_cache.e
vendored
Normal file
49
src/cache/cms_file_object_cache.e
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
note
|
||||
description: "Cache for value conforming to formal {G}, and implemented using local file."
|
||||
date: "$Date: 2014-10-30 12:13:25 +0100 (jeu., 30 oct. 2014) $"
|
||||
revision: "$Revision: 96016 $"
|
||||
|
||||
class
|
||||
CMS_FILE_OBJECT_CACHE [G -> ANY]
|
||||
|
||||
inherit
|
||||
CMS_FILE_CACHE [G]
|
||||
|
||||
SED_STORABLE_FACILITIES
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
file_to_item (f: FILE): detachable G
|
||||
local
|
||||
retried: BOOLEAN
|
||||
l_reader: SED_MEDIUM_READER_WRITER
|
||||
l_void: detachable G
|
||||
do
|
||||
if retried then
|
||||
Result := l_void
|
||||
else
|
||||
create l_reader.make_for_reading (f)
|
||||
if attached {G} retrieved (l_reader, True) as l_data then
|
||||
Result := l_data
|
||||
end
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
|
||||
item_to_file (a_data: G; f: FILE)
|
||||
local
|
||||
l_writer: SED_MEDIUM_READER_WRITER
|
||||
do
|
||||
create l_writer.make_for_writing (f)
|
||||
basic_store (a_data, l_writer, True)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
69
src/cache/cms_file_string_8_cache.e
vendored
Normal file
69
src/cache/cms_file_string_8_cache.e
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
note
|
||||
description: "Cache system for STRING_8 value."
|
||||
date: "$Date: 2014-10-30 12:13:25 +0100 (jeu., 30 oct. 2014) $"
|
||||
revision: "$Revision: 96016 $"
|
||||
|
||||
class
|
||||
CMS_FILE_STRING_8_CACHE
|
||||
|
||||
inherit
|
||||
CMS_FILE_CACHE [STRING]
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Access
|
||||
|
||||
append_to (a_output: STRING)
|
||||
-- Append `item' to `a_output'.
|
||||
local
|
||||
f: RAW_FILE
|
||||
retried: BOOLEAN
|
||||
do
|
||||
if not retried then
|
||||
create f.make_with_path (path)
|
||||
if f.exists and then f.is_access_readable then
|
||||
f.open_read
|
||||
if attached file_to_item (f) as s then
|
||||
a_output.append (s)
|
||||
end
|
||||
f.close
|
||||
end
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
file_to_item (f: FILE): detachable STRING
|
||||
local
|
||||
retried: BOOLEAN
|
||||
do
|
||||
if retried then
|
||||
Result := Void
|
||||
else
|
||||
from
|
||||
create Result.make_empty
|
||||
until
|
||||
f.exhausted or f.end_of_file
|
||||
loop
|
||||
f.read_stream_thread_aware (1_024)
|
||||
Result.append (f.last_string)
|
||||
end
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
|
||||
item_to_file (a_data: STRING; f: FILE)
|
||||
do
|
||||
f.put_string (a_data)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
61
src/cache/cms_memory_cache.e
vendored
Normal file
61
src/cache/cms_memory_cache.e
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
note
|
||||
description: "Cache relying on memory."
|
||||
date: "$Date: 2014-12-03 16:57:00 +0100 (mer., 03 déc. 2014) $"
|
||||
revision: "$Revision: 96234 $"
|
||||
|
||||
deferred class
|
||||
CMS_MEMORY_CACHE [G -> ANY]
|
||||
|
||||
inherit
|
||||
CMS_CACHE [G]
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
cache_date_time := current_date_time
|
||||
end
|
||||
|
||||
|
||||
feature -- Status report
|
||||
|
||||
exists: BOOLEAN
|
||||
-- Do associated cache memory exists?
|
||||
do
|
||||
Result := item /= Void
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
cache_date_time: DATE_TIME
|
||||
|
||||
current_date_time: DATE_TIME
|
||||
-- <Precursor>
|
||||
do
|
||||
create Result.make_now_utc
|
||||
end
|
||||
|
||||
item: detachable G
|
||||
|
||||
feature -- Element change
|
||||
|
||||
delete
|
||||
-- <Precursor>
|
||||
local
|
||||
l_default: detachable G
|
||||
do
|
||||
item := l_default
|
||||
cache_date_time := current_date_time
|
||||
end
|
||||
|
||||
put (g: G)
|
||||
-- <Precursor>
|
||||
do
|
||||
item := g
|
||||
cache_date_time := current_date_time
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -68,6 +68,18 @@ feature -- Access
|
||||
Result := configuration.resolved_text_item (a_name)
|
||||
end
|
||||
|
||||
text_list_item (a_name: READABLE_STRING_GENERAL): detachable LIST [READABLE_STRING_32]
|
||||
-- Configuration values associated with `a_name', if any.
|
||||
do
|
||||
Result := configuration.text_list_item (a_name)
|
||||
end
|
||||
|
||||
text_table_item (a_name: READABLE_STRING_GENERAL): detachable STRING_TABLE [READABLE_STRING_32]
|
||||
-- Configuration indexed values associated with `a_name', if any.
|
||||
do
|
||||
Result := configuration.text_table_item (a_name)
|
||||
end
|
||||
|
||||
string_8_item (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_8
|
||||
-- String 8 configuration value associated with `a_name', if any.
|
||||
local
|
||||
@@ -86,13 +98,19 @@ feature -- Access
|
||||
local
|
||||
retried: BOOLEAN
|
||||
f: FILE
|
||||
l_chain: NOTIFICATION_CHAIN_MAILER
|
||||
l_storage_mailer: NOTIFICATION_STORAGE_MAILER
|
||||
l_mailer: detachable NOTIFICATION_MAILER
|
||||
do
|
||||
if not retried then
|
||||
if attached text_item ("mailer.smtp") as l_smtp then
|
||||
create {NOTIFICATION_SMTP_MAILER} mailer.make (l_smtp)
|
||||
create {NOTIFICATION_SMTP_MAILER} l_mailer.make (l_smtp)
|
||||
elseif attached text_item ("mailer.sendmail") as l_sendmail then
|
||||
create {NOTIFICATION_SENDMAIL_MAILER} mailer.make_with_location (l_sendmail)
|
||||
elseif attached text_item ("mailer.output") as l_output then
|
||||
create {NOTIFICATION_SENDMAIL_MAILER} l_mailer.make_with_location (l_sendmail)
|
||||
end
|
||||
-- If a mailer.ouput is set, set a notification chain with potential previous mailer
|
||||
-- and file storage.
|
||||
if attached text_item ("mailer.output") as l_output then
|
||||
if l_output.is_case_insensitive_equal ("@stderr") then
|
||||
f := io.error
|
||||
elseif l_output.is_case_insensitive_equal ("@stdout") then
|
||||
@@ -104,10 +122,18 @@ feature -- Access
|
||||
f.close
|
||||
end
|
||||
end
|
||||
create {NOTIFICATION_STORAGE_MAILER} mailer.make (create {NOTIFICATION_EMAIL_FILE_STORAGE}.make (f))
|
||||
else
|
||||
create {NOTIFICATION_STORAGE_MAILER} mailer.make (create {NOTIFICATION_EMAIL_FILE_STORAGE}.make (io.error))
|
||||
create {NOTIFICATION_STORAGE_MAILER} l_storage_mailer.make (create {NOTIFICATION_EMAIL_FILE_STORAGE}.make (f))
|
||||
if l_mailer /= Void then
|
||||
create l_chain.make (l_mailer)
|
||||
l_chain.set_next (l_storage_mailer)
|
||||
l_mailer := l_chain
|
||||
else
|
||||
l_mailer := l_storage_mailer
|
||||
end
|
||||
elseif l_mailer = Void then
|
||||
create {NOTIFICATION_STORAGE_MAILER} l_mailer.make (create {NOTIFICATION_EMAIL_FILE_STORAGE}.make (io.error))
|
||||
end
|
||||
mailer := l_mailer
|
||||
else
|
||||
check valid_mailer: False end
|
||||
-- FIXME: should we report persistent error message? If yes, see how.
|
||||
|
||||
@@ -196,6 +196,16 @@ feature -- Query
|
||||
deferred
|
||||
end
|
||||
|
||||
text_list_item (a_name: READABLE_STRING_GENERAL): detachable LIST [READABLE_STRING_32]
|
||||
-- Configuration values associated with `a_name', if any.
|
||||
deferred
|
||||
end
|
||||
|
||||
text_table_item (a_name: READABLE_STRING_GENERAL): detachable STRING_TABLE [READABLE_STRING_32]
|
||||
-- Configuration indexed values associated with `a_name', if any.
|
||||
deferred
|
||||
end
|
||||
|
||||
text_item_or_default (a_name: READABLE_STRING_GENERAL; a_default_value: READABLE_STRING_GENERAL): READABLE_STRING_32
|
||||
-- `text_item' associated with `a_name' or if none, `a_default_value'.
|
||||
do
|
||||
|
||||
@@ -15,6 +15,8 @@ feature -- Hook
|
||||
|
||||
block_list: ITERABLE [like {CMS_BLOCK}.name]
|
||||
-- List of block names, managed by current object.
|
||||
-- If prefixed by "?", condition will be check
|
||||
-- to determine if it should be displayed (and computed) or not.
|
||||
deferred
|
||||
end
|
||||
|
||||
@@ -23,4 +25,7 @@ feature -- Hook
|
||||
deferred
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
|
||||
@@ -138,6 +138,11 @@ feature -- Hook: block
|
||||
|
||||
invoke_block (a_response: CMS_RESPONSE)
|
||||
-- Invoke block hook for response `a_response' in order to get block from modules.
|
||||
local
|
||||
bl: READABLE_STRING_8
|
||||
bl_optional: BOOLEAN
|
||||
l_ok: BOOLEAN
|
||||
l_block_cache: detachable TUPLE [block: CMS_CACHE_BLOCK; region: READABLE_STRING_8; expired: BOOLEAN]
|
||||
do
|
||||
if attached subscribers ({CMS_HOOK_BLOCK}) as lst then
|
||||
across
|
||||
@@ -147,7 +152,25 @@ feature -- Hook: block
|
||||
across
|
||||
h.block_list as blst
|
||||
loop
|
||||
h.get_block_view (blst.item, a_response)
|
||||
l_ok := False
|
||||
bl := blst.item
|
||||
bl_optional := bl.count > 0 and bl[1] = '?'
|
||||
if bl_optional then
|
||||
bl := bl.substring (2, bl.count)
|
||||
if a_response.is_block_included (bl, False) then
|
||||
l_ok := True
|
||||
end
|
||||
else
|
||||
l_ok := True
|
||||
end
|
||||
if l_ok then
|
||||
l_block_cache := a_response.block_cache (bl)
|
||||
if l_block_cache /= Void and then not l_block_cache.expired then
|
||||
a_response.add_block (l_block_cache.block, l_block_cache.region)
|
||||
else
|
||||
h.get_block_view (bl, a_response)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -24,27 +24,6 @@ feature -- Access
|
||||
Result := all_subscribers.item (a_type)
|
||||
end
|
||||
|
||||
--feature -- Invocation
|
||||
|
||||
-- invoke_module_hook (args: TUPLE; a_type: TYPE [CMS_HOOK])
|
||||
-- -- Invoke module hook typed `a_type' with argument `args'.
|
||||
-- do
|
||||
-- if attached subscribers (a_type) as lst then
|
||||
-- across
|
||||
-- lst as ic
|
||||
-- loop
|
||||
-- if
|
||||
-- attached {CMS_HOOK_WITH_WRAPPER} ic.item as hw and then
|
||||
-- attached hw.wrapper as w
|
||||
-- then
|
||||
-- if w.valid_arguments (args) then
|
||||
-- w.invoke (args)
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
|
||||
feature -- Change
|
||||
|
||||
subscribe_to_hook (h: CMS_HOOK; a_hook_type: TYPE [CMS_HOOK])
|
||||
|
||||
24
src/kernel/content/block/condition/cms_block_condition.e
Normal file
24
src/kernel/content/block/condition/cms_block_condition.e
Normal file
@@ -0,0 +1,24 @@
|
||||
note
|
||||
description: "Condition for block to be displayed."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CMS_BLOCK_CONDITION
|
||||
|
||||
feature -- Access
|
||||
|
||||
description: READABLE_STRING_32
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Evaluation
|
||||
|
||||
satisfied_for_response (res: CMS_RESPONSE): BOOLEAN
|
||||
deferred
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,60 @@
|
||||
note
|
||||
description: "Condition for block to be displayed."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_BLOCK_EXPRESSION_CONDITION
|
||||
|
||||
inherit
|
||||
CMS_BLOCK_CONDITION
|
||||
|
||||
create
|
||||
make,
|
||||
make_none
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_exp: READABLE_STRING_8)
|
||||
do
|
||||
expression := a_exp
|
||||
end
|
||||
|
||||
make_none
|
||||
do
|
||||
make ("<none>")
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
description: STRING_32
|
||||
do
|
||||
create Result.make_from_string_general ("Expression: %"")
|
||||
Result.append_string_general (expression)
|
||||
Result.append_character ('%"')
|
||||
end
|
||||
|
||||
expression: STRING
|
||||
|
||||
feature -- Evaluation
|
||||
|
||||
satisfied_for_response (res: CMS_RESPONSE): BOOLEAN
|
||||
local
|
||||
exp: like expression
|
||||
do
|
||||
exp := expression
|
||||
if exp.same_string ("is_front") then
|
||||
Result := res.is_front
|
||||
elseif exp.same_string ("*") then
|
||||
Result := True
|
||||
elseif exp.same_string ("<none>") then
|
||||
Result := False
|
||||
elseif exp.starts_with ("path:") then
|
||||
Result := res.location.same_string (exp.substring (6, exp.count))
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,45 @@
|
||||
note
|
||||
description: "Condition for block to be displayed based on location."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CMS_BLOCK_LOCATION_CONDITION
|
||||
|
||||
inherit
|
||||
CMS_BLOCK_CONDITION
|
||||
|
||||
create
|
||||
make_with_location
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_with_location (a_location: READABLE_STRING_8)
|
||||
do
|
||||
location := a_location
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
description: STRING_32
|
||||
do
|
||||
create Result.make_from_string_general ("Location: %"")
|
||||
Result.append_string_general (location)
|
||||
Result.append_character ('%"')
|
||||
end
|
||||
|
||||
location: STRING
|
||||
|
||||
feature -- Evaluation
|
||||
|
||||
satisfied_for_response (res: CMS_RESPONSE): BOOLEAN
|
||||
local
|
||||
loc: like location
|
||||
do
|
||||
Result := res.location.same_string (loc)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -23,7 +23,12 @@ feature -- Access
|
||||
html_options: detachable CMS_HTML_OPTIONS
|
||||
-- Optional addition html options.
|
||||
|
||||
feature -- status report
|
||||
feature -- Status report
|
||||
|
||||
is_empty: BOOLEAN
|
||||
-- Is current block empty?
|
||||
deferred
|
||||
end
|
||||
|
||||
is_enabled: BOOLEAN
|
||||
-- Is current block enabled?
|
||||
@@ -34,6 +39,9 @@ feature -- status report
|
||||
deferred
|
||||
end
|
||||
|
||||
conditions: detachable LIST [CMS_BLOCK_CONDITION]
|
||||
-- Optional block condition to be enabled.
|
||||
|
||||
feature -- Element change
|
||||
|
||||
add_css_class (a_class: READABLE_STRING_8)
|
||||
@@ -62,6 +70,19 @@ feature -- Element change
|
||||
opts.remove_css_class (a_class)
|
||||
end
|
||||
|
||||
add_condition (a_condition: CMS_BLOCK_CONDITION)
|
||||
-- Add condition `a_condition'.
|
||||
local
|
||||
l_conditions: like conditions
|
||||
do
|
||||
l_conditions := conditions
|
||||
if l_conditions = Void then
|
||||
create {ARRAYED_LIST [CMS_BLOCK_CONDITION]} l_conditions.make (1)
|
||||
conditions := l_conditions
|
||||
end
|
||||
l_conditions.force (a_condition)
|
||||
end
|
||||
|
||||
feature -- Conversion
|
||||
|
||||
to_html (a_theme: CMS_THEME): STRING_8
|
||||
@@ -93,4 +114,7 @@ feature -- Status report
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
|
||||
@@ -21,11 +21,10 @@ feature {NONE} -- Initialization
|
||||
feature -- Access
|
||||
|
||||
name: READABLE_STRING_8
|
||||
-- Block region name.
|
||||
-- Block region name.
|
||||
|
||||
blocks: ARRAYED_LIST [CMS_BLOCK]
|
||||
-- List of blocks.
|
||||
|
||||
-- List of blocks.
|
||||
|
||||
feature -- Element change
|
||||
|
||||
@@ -35,8 +34,15 @@ feature -- Element change
|
||||
blocks.force (b)
|
||||
end
|
||||
|
||||
;note
|
||||
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
|
||||
remove (b: CMS_BLOCK)
|
||||
require
|
||||
has_block_b: blocks.has (b)
|
||||
do
|
||||
blocks.prune_all (b)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
99
src/kernel/content/cms_cache_block.e
Normal file
99
src/kernel/content/cms_cache_block.e
Normal file
@@ -0,0 +1,99 @@
|
||||
note
|
||||
description: "[
|
||||
CMS_BLOCK implemented with a `cache'
|
||||
as caching solution.
|
||||
]"
|
||||
date: "$Date: 2014-11-18 10:13:13 +0100 (mar., 18 nov. 2014) $"
|
||||
revision: "$Revision: 96110 $"
|
||||
|
||||
class
|
||||
CMS_CACHE_BLOCK
|
||||
|
||||
inherit
|
||||
CMS_BLOCK
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_name: like name; a_cache: like cache)
|
||||
require
|
||||
a_name_not_blank: not a_name.is_whitespace
|
||||
do
|
||||
is_enabled := True
|
||||
name := a_name
|
||||
cache := a_cache
|
||||
set_is_raw (True)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: READABLE_STRING_8
|
||||
-- <Precursor>
|
||||
|
||||
title: detachable READABLE_STRING_32
|
||||
-- <Precursor>
|
||||
|
||||
cache: CMS_CACHE [READABLE_STRING_8]
|
||||
-- Cache content.
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_empty: BOOLEAN
|
||||
-- Is current block empty?
|
||||
do
|
||||
Result := is_raw and not cache.exists
|
||||
end
|
||||
|
||||
is_raw: BOOLEAN assign set_is_raw
|
||||
-- Is raw?
|
||||
-- If True, do not get wrapped it with block specific div
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_is_raw (b: BOOLEAN)
|
||||
do
|
||||
is_raw := b
|
||||
end
|
||||
|
||||
set_name (n: like name)
|
||||
-- Set `name' to `n'.
|
||||
require
|
||||
not n.is_whitespace
|
||||
do
|
||||
name := n
|
||||
end
|
||||
|
||||
set_title (a_title: like title)
|
||||
-- Set `title' to `a_title'.
|
||||
do
|
||||
title := a_title
|
||||
end
|
||||
|
||||
feature -- Conversion
|
||||
|
||||
to_html (a_theme: CMS_THEME): STRING_8
|
||||
do
|
||||
debug
|
||||
print ("REUSE CACHE for [" + name + "]!!!%N")
|
||||
end
|
||||
-- Why in this particular case theme is not used to generate the content?
|
||||
if attached cache.item as l_content then
|
||||
Result := l_content
|
||||
else
|
||||
Result := ""
|
||||
check exists: False end
|
||||
end
|
||||
end
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -49,6 +49,12 @@ feature -- Access
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_empty: BOOLEAN
|
||||
-- Is current block empty?
|
||||
do
|
||||
Result := is_raw and content.is_empty
|
||||
end
|
||||
|
||||
is_raw: BOOLEAN assign set_is_raw
|
||||
-- Is raw?
|
||||
-- If True, do not get wrapped it with block specific div
|
||||
@@ -87,7 +93,7 @@ feature -- Conversion
|
||||
end
|
||||
end
|
||||
note
|
||||
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -57,12 +57,39 @@ feature -- Access
|
||||
root_path: detachable PATH
|
||||
-- Root location for files universe.
|
||||
|
||||
resolved_location: PATH
|
||||
-- Path of related file, taking into account `root_path' and `location'.
|
||||
do
|
||||
-- Process html generation
|
||||
if attached root_path as l_root_path then
|
||||
Result := l_root_path.extended_path (location)
|
||||
else
|
||||
Result := location
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_empty: BOOLEAN
|
||||
-- Is current block empty?
|
||||
do
|
||||
Result := not exists
|
||||
debug ("cms")
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
|
||||
is_raw: BOOLEAN
|
||||
-- Is raw?
|
||||
-- If True, do not get wrapped it with block specific div
|
||||
|
||||
exists: BOOLEAN
|
||||
local
|
||||
ut: FILE_UTILITIES
|
||||
do
|
||||
Result := ut.file_path_exists (resolved_location)
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_is_raw (b: BOOLEAN)
|
||||
@@ -94,11 +121,7 @@ feature -- Conversion
|
||||
ut: FILE_UTILITIES
|
||||
do
|
||||
-- Process html generation
|
||||
if attached root_path as l_root_path then
|
||||
p := l_root_path.extended_path (location)
|
||||
else
|
||||
p := location
|
||||
end
|
||||
p := resolved_location
|
||||
if ut.file_path_exists (p) then
|
||||
create f.make_with_path (p)
|
||||
if f.exists and then f.is_access_readable then
|
||||
@@ -145,4 +168,7 @@ feature -- Debug
|
||||
end
|
||||
Result.append ("%N")
|
||||
end
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
|
||||
@@ -31,6 +31,12 @@ feature -- Access
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_empty: BOOLEAN
|
||||
-- Is current block empty?
|
||||
do
|
||||
Result := menu.is_empty
|
||||
end
|
||||
|
||||
is_horizontal: BOOLEAN assign set_is_horizontal
|
||||
-- Is horizontal layout for the menu?
|
||||
|
||||
@@ -72,4 +78,7 @@ feature -- Conversion
|
||||
Result := a_theme.menu_html (menu, is_horizontal, html_options)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
|
||||
@@ -69,6 +69,9 @@ feature -- Access
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_empty: BOOLEAN = False
|
||||
-- Is current block empty?
|
||||
|
||||
is_raw: BOOLEAN
|
||||
-- Is raw?
|
||||
-- If True, do not get wrapped it with block specific div
|
||||
@@ -192,4 +195,7 @@ feature -- Debug
|
||||
end
|
||||
Result.append ("%N}")
|
||||
end
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
|
||||
@@ -8,6 +8,7 @@ deferred class
|
||||
CMS_EDITOR
|
||||
|
||||
feature -- Initialisation
|
||||
|
||||
load_assets : STRING
|
||||
-- Loads all assest needed to show the editor
|
||||
deferred
|
||||
@@ -15,57 +16,55 @@ feature -- Initialisation
|
||||
|
||||
feature -- Javascript
|
||||
|
||||
javascript_replace_textarea (a_textarea : WSF_FORM_TEXTAREA) : STRING
|
||||
javascript_replace_textarea (a_textarea : WSF_FORM_TEXTAREA): STRING
|
||||
-- Javascript code that replaces a textarea with the editor. The editor instance should be saved in editor_variable
|
||||
deferred
|
||||
end
|
||||
|
||||
javascript_restore_textarea (a_textarea : WSF_FORM_TEXTAREA) : STRING
|
||||
javascript_restore_textarea (a_textarea : WSF_FORM_TEXTAREA): STRING
|
||||
-- Javascript code that restores a textarea
|
||||
deferred
|
||||
end
|
||||
|
||||
javascript_textarea_to_editor(a_textarea : WSF_FORM_TEXTAREA) : STRING
|
||||
javascript_textarea_to_editor (a_textarea : WSF_FORM_TEXTAREA): STRING
|
||||
-- Javascript code to display the textarea as a WYSIWIG editor as soon as the document is loaded
|
||||
do
|
||||
Result := javascript_ready(javascript_replace_textarea (a_textarea))
|
||||
Result := javascript_ready (javascript_replace_textarea (a_textarea))
|
||||
end
|
||||
|
||||
javascript_textarea_to_editor_if_selected (a_textarea : WSF_FORM_TEXTAREA; a_select_field : WSF_FORM_SELECT; a_value : STRING) : STRING
|
||||
javascript_textarea_to_editor_if_selected (a_textarea: WSF_FORM_TEXTAREA; a_select_field : WSF_FORM_SELECT; a_value : STRING) : STRING
|
||||
-- Javascript code to display the textarea as a WYSIWIG editor if a_select_field has a_value
|
||||
local
|
||||
initial_replace_code, on_select_replace_code : STRING
|
||||
initial_replace_code, on_select_replace_code: STRING
|
||||
do
|
||||
-- Javascript that replaces the textarea if a_value is selected at load time
|
||||
initial_replace_code := javascript_ready(javascript_if_selected(a_select_field, a_value, javascript_replace_textarea(a_textarea)))
|
||||
initial_replace_code := javascript_ready (javascript_if_selected (a_select_field, a_value, javascript_replace_textarea (a_textarea)))
|
||||
|
||||
-- Javascript code that replaces the textarea as soon as value is selected at a_select_field
|
||||
on_select_replace_code := javascript_ready(
|
||||
javascript_init_editor_variable(a_textarea) +
|
||||
javascript_on_select(a_select_field, a_value,
|
||||
javascript_init_editor_variable (a_textarea) +
|
||||
javascript_on_select (a_select_field, a_value,
|
||||
-- If a_value is selected, replace textarea
|
||||
javascript_replace_textarea(a_textarea),
|
||||
javascript_replace_textarea (a_textarea),
|
||||
|
||||
-- Otherwise restore it
|
||||
javascript_restore_textarea(a_textarea)
|
||||
javascript_restore_textarea (a_textarea)
|
||||
)
|
||||
)
|
||||
|
||||
Result := initial_replace_code + " " + on_select_replace_code
|
||||
end
|
||||
|
||||
javascript_init_editor_variable(a_textarea : WSF_FORM_TEXTAREA) : STRING
|
||||
javascript_init_editor_variable (a_textarea : WSF_FORM_TEXTAREA) : STRING
|
||||
-- Returns the javascript code that initializes a local variable to store the editor instance
|
||||
do
|
||||
Result := "var " + editor_variable(a_textarea) + "; "
|
||||
Result := "var " + editor_variable (a_textarea) + "; "
|
||||
end
|
||||
|
||||
|
||||
|
||||
javascript_if_selected(a_select_field : WSF_FORM_SELECT; a_value : STRING; a_code : STRING) : STRING
|
||||
javascript_if_selected (a_select_field : WSF_FORM_SELECT; a_value : STRING; a_code : STRING) : STRING
|
||||
-- Javascript that executes a_code if a_value is selected at a_select_field
|
||||
do
|
||||
Result := "if($('#" + field_id(a_select_field) + "').val() == %"" + a_value + "%"){ " + a_code + " }"
|
||||
Result := "if($('#" + field_id (a_select_field) + "').val() == %"" + a_value + "%"){ " + a_code + " }"
|
||||
end
|
||||
|
||||
javascript_ready (a_code : STRING) : STRING
|
||||
@@ -77,8 +76,8 @@ feature -- Javascript
|
||||
javascript_on_select (a_select_field : WSF_FORM_SELECT; a_value : STRING; a_then : STRING; a_else : STRING) : STRING
|
||||
-- Javascript code that executes a_then if at the given select_field the given string value is selected, otherwise it executes a_else
|
||||
do
|
||||
Result := "$('#" + field_id(a_select_field) + "').change(function(){" +
|
||||
javascript_if_selected(a_select_field, a_value, a_then) +
|
||||
Result := "$('#" + field_id (a_select_field) + "').change(function(){" +
|
||||
javascript_if_selected (a_select_field, a_value, a_then) +
|
||||
"else{" +
|
||||
a_else +
|
||||
"}" +
|
||||
@@ -100,7 +99,10 @@ feature -- Helper
|
||||
editor_variable (a_textarea : WSF_FORM_TEXTAREA) : STRING
|
||||
-- Returns the variable name that stores the editor instance of the given textarea
|
||||
do
|
||||
Result := "editor_" + a_textarea.name
|
||||
Result := "cms_ckeditor_" + a_textarea.name
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
|
||||
@@ -23,15 +23,20 @@ feature -- Javascript
|
||||
javascript_replace_textarea (a_textarea : WSF_FORM_TEXTAREA) : STRING
|
||||
-- <Precursor>
|
||||
do
|
||||
-- Replaces the textarea with an editor instance. Save the instance in a variable
|
||||
Result := editor_variable(a_textarea) + " = CKEDITOR.replace( '" + a_textarea.name + "' );"
|
||||
-- Replaces the textarea with an editor instance. Save the instance in a variable
|
||||
Result := "$(%"textarea[name="+ a_textarea.name +"]%").each(function() {"
|
||||
Result.append (editor_variable (a_textarea) + " = CKEDITOR.replace(this);")
|
||||
Result.append ("});")
|
||||
end
|
||||
|
||||
javascript_restore_textarea (a_textarea : WSF_FORM_TEXTAREA) : STRING
|
||||
-- <Precursor>
|
||||
do
|
||||
-- Replaces the textarea with an editor instance. Save the instance in a variable
|
||||
Result := "if (" + editor_variable(a_textarea) + " != undefined) " + editor_variable(a_textarea) + ".destroy();"
|
||||
-- Replaces the textarea with an editor instance. Save the instance in a variable
|
||||
Result := "if (" + editor_variable (a_textarea) + " != undefined) " + editor_variable (a_textarea) + ".destroy();"
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
|
||||
@@ -19,7 +19,7 @@ feature -- Basic operation
|
||||
|
||||
prepare (a_response: CMS_RESPONSE)
|
||||
do
|
||||
a_response.invoke_form_alter (Current, Void)
|
||||
a_response.hooks.invoke_form_alter (Current, Void, a_response)
|
||||
end
|
||||
|
||||
process (a_response: CMS_RESPONSE)
|
||||
@@ -29,7 +29,7 @@ feature -- Basic operation
|
||||
|
||||
on_prepared (a_response: CMS_RESPONSE; fd: WSF_FORM_DATA)
|
||||
do
|
||||
a_response.invoke_form_alter (Current, fd)
|
||||
a_response.hooks.invoke_form_alter (Current, fd, a_response)
|
||||
end
|
||||
|
||||
on_processed (a_response: CMS_RESPONSE; fd: WSF_FORM_DATA)
|
||||
|
||||
@@ -24,15 +24,15 @@ feature -- Initialisation
|
||||
make (a_name: like name)
|
||||
-- <Precursor>
|
||||
do
|
||||
precursor(a_name)
|
||||
Precursor (a_name)
|
||||
|
||||
-- By default we don't replace the textarea by an editor
|
||||
editor := False;
|
||||
editor_activated := False;
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
editor : BOOLEAN
|
||||
editor_activated : BOOLEAN
|
||||
-- True if the textarea should be replaced by the editor. Default is false.
|
||||
|
||||
format_field : detachable WSF_FORM_SELECT
|
||||
@@ -45,13 +45,13 @@ feature -- Editor
|
||||
show_as_editor
|
||||
-- The textarea will be replaced by a wysiwyg editor
|
||||
do
|
||||
editor := True
|
||||
editor_activated := True
|
||||
end
|
||||
|
||||
show_as_editor_if_selected (a_select_field : WSF_FORM_SELECT; a_value : STRING)
|
||||
-- Replaces the textarea only if a_select_field has a_value (or the value gets selected)
|
||||
do
|
||||
editor := True
|
||||
editor_activated := True
|
||||
format_field := a_select_field
|
||||
condition_value := a_value
|
||||
end
|
||||
@@ -61,8 +61,8 @@ feature -- Conversion
|
||||
append_item_to_html (a_theme: WSF_THEME; a_html: STRING_8)
|
||||
do
|
||||
-- Add javascript to replace textarea with editor
|
||||
precursor(a_theme, a_html)
|
||||
if editor then
|
||||
Precursor (a_theme, a_html)
|
||||
if editor_activated then
|
||||
a_html.append (load_assets)
|
||||
a_html.append ("<script type=%"text/javascript%">");
|
||||
if attached format_field as l_field and then attached condition_value as l_value then
|
||||
|
||||
@@ -51,14 +51,14 @@ feature -- Hooks configuration
|
||||
-- Module hooks configuration.
|
||||
do
|
||||
auto_subscribe_to_hooks (a_response)
|
||||
a_response.subscribe_to_block_hook (Current)
|
||||
a_response.hooks.subscribe_to_block_hook (Current)
|
||||
end
|
||||
|
||||
feature -- Hooks
|
||||
|
||||
block_list: ITERABLE [like {CMS_BLOCK}.name]
|
||||
do
|
||||
Result := <<"debug-info">>
|
||||
Result := <<"?debug-info">>
|
||||
end
|
||||
|
||||
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||
@@ -67,14 +67,13 @@ feature -- Hooks
|
||||
dbg: WSF_DEBUG_INFORMATION
|
||||
s: STRING
|
||||
do
|
||||
if a_response.theme.has_region ("debug") then
|
||||
create dbg.make
|
||||
create s.make_empty
|
||||
dbg.append_information_to (a_response.request, a_response.response, s)
|
||||
append_info_to ("Storage", a_response.api.storage.generator, a_response, s)
|
||||
create b.make ("debug-info", "Debug", s, a_response.formats.plain_text)
|
||||
a_response.add_block (b, "footer")
|
||||
end
|
||||
create dbg.make
|
||||
create s.make_empty
|
||||
dbg.append_information_to (a_response.request, a_response.response, s)
|
||||
append_info_to ("Storage", a_response.api.storage.generator, a_response, s)
|
||||
create b.make ("debug-info", "Debug", s, a_response.formats.plain_text)
|
||||
b.add_condition (create {CMS_BLOCK_EXPRESSION_CONDITION}.make_none)
|
||||
a_response.add_block (b, "footer")
|
||||
end
|
||||
|
||||
feature -- Handler
|
||||
|
||||
@@ -101,7 +101,19 @@ feature -- Custom
|
||||
|
||||
custom_value (a_name: READABLE_STRING_GENERAL; a_type: detachable READABLE_STRING_8): detachable READABLE_STRING_32
|
||||
-- Data for name `a_name' and type `a_type' (or default if none).
|
||||
local
|
||||
s: STRING_32
|
||||
do
|
||||
if attached api as l_api then
|
||||
create s.make_from_string_general ("custom_values")
|
||||
if a_type /= Void then
|
||||
s.append_character ('.')
|
||||
s.append_string_general (a_type)
|
||||
end
|
||||
s.append_character ('.')
|
||||
s.append_string_general (a_name)
|
||||
Result := l_api.setup.text_item (s)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -403,19 +403,79 @@ feature -- Blocks initialization
|
||||
create regions.make_caseless (5)
|
||||
|
||||
create l_table.make_caseless (10)
|
||||
l_table["top"] := "top"
|
||||
l_table["header"] := "header"
|
||||
l_table["highlighted"] := "highlighted"
|
||||
l_table["help"] := "help"
|
||||
l_table["content"] := "content"
|
||||
l_table["footer"] := "footer"
|
||||
l_table["management"] := "sidebar_first"
|
||||
l_table["navigation"] := "sidebar_first"
|
||||
l_table["user"] := "sidebar_first"
|
||||
l_table["bottom"] := "page_bottom"
|
||||
l_table["top"] := block_region_preference ("top", "top")
|
||||
l_table["header"] := block_region_preference ("header", "header")
|
||||
l_table["highlighted"] := block_region_preference ("highlighted", "highlighted")
|
||||
l_table["help"] := block_region_preference ("help", "help")
|
||||
l_table["content"] := block_region_preference ("content", "content")
|
||||
l_table["footer"] := block_region_preference ("footer", "footer")
|
||||
l_table["management"] := block_region_preference ("management", "sidebar_first")
|
||||
l_table["navigation"] := block_region_preference ("navigation", "sidebar_first")
|
||||
l_table["user"] := block_region_preference ("user", "sidebar_first")
|
||||
l_table["bottom"] := block_region_preference ("bottom", "page_bottom")
|
||||
|
||||
block_region_settings := l_table
|
||||
end
|
||||
|
||||
block_region_preference (a_block_id: READABLE_STRING_8; a_default_region: READABLE_STRING_8): READABLE_STRING_8
|
||||
-- Region associated with `a_block_id' in configuration, if any.
|
||||
do
|
||||
Result := setup.text_item_or_default ("blocks." + a_block_id + ".region", a_default_region)
|
||||
end
|
||||
|
||||
block_conditions (a_block_id: READABLE_STRING_8): detachable ARRAYED_LIST [CMS_BLOCK_EXPRESSION_CONDITION]
|
||||
-- Condition associated with `a_block_id' in configuration, if any.
|
||||
do
|
||||
if attached setup.text_item ("blocks." + a_block_id + ".condition") as s then
|
||||
create Result.make (1)
|
||||
Result.force (create {CMS_BLOCK_EXPRESSION_CONDITION}.make (s))
|
||||
end
|
||||
if attached setup.text_list_item ("blocks." + a_block_id + ".conditions") as lst then
|
||||
if Result = Void then
|
||||
create Result.make (lst.count)
|
||||
across
|
||||
lst as ic
|
||||
loop
|
||||
Result.force (create {CMS_BLOCK_EXPRESSION_CONDITION}.make (ic.item))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
is_block_included (a_block_id: READABLE_STRING_8; dft: BOOLEAN): BOOLEAN
|
||||
-- Is block `a_block_id' included in current response?
|
||||
-- If no preference, return `dft'.
|
||||
do
|
||||
if attached block_conditions (a_block_id) as l_conditions then
|
||||
Result := across l_conditions as ic some ic.item.satisfied_for_response (Current) end
|
||||
else
|
||||
Result := dft
|
||||
end
|
||||
end
|
||||
|
||||
block_cache (a_block_id: READABLE_STRING_8): detachable TUPLE [block: CMS_CACHE_BLOCK; region: READABLE_STRING_8; expired: BOOLEAN]
|
||||
-- Cached version of block `a_block_id'.
|
||||
local
|
||||
l_cache: CMS_FILE_STRING_8_CACHE
|
||||
do
|
||||
if
|
||||
attached setup.text_item ("blocks." + a_block_id + ".expiration") as nb_secs and then
|
||||
nb_secs.is_integer
|
||||
then
|
||||
if attached block_region_preference (a_block_id, "none") as l_region and then not l_region.same_string_general ("none") then
|
||||
create l_cache.make (api.files_location.extended (".cache").extended ("blocks").extended (a_block_id).appended_with_extension ("html"))
|
||||
if
|
||||
l_cache.exists and then
|
||||
not l_cache.expired (Void, nb_secs.to_integer)
|
||||
then
|
||||
Result := [create {CMS_CACHE_BLOCK} .make (a_block_id, l_cache), l_region, False]
|
||||
else
|
||||
Result := [create {CMS_CACHE_BLOCK} .make (a_block_id, l_cache), l_region, True]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Blocks regions
|
||||
|
||||
regions: STRING_TABLE [CMS_BLOCK_REGION]
|
||||
@@ -430,12 +490,15 @@ feature -- Blocks regions
|
||||
do
|
||||
l_region_name := block_region_settings.item (b.name)
|
||||
if l_region_name = Void then
|
||||
if a_default_region /= Void then
|
||||
if attached setup.text_item ("blocks." + b.name + ".region") as l_setup_name then
|
||||
l_region_name := l_setup_name.as_string_8 -- FIXME: potential truncated string 32.
|
||||
-- Remember for later.
|
||||
block_region_settings.force (l_region_name, b.name)
|
||||
elseif a_default_region /= Void then
|
||||
l_region_name := a_default_region
|
||||
else
|
||||
-- Default .. put it in same named region
|
||||
-- Maybe a bad idea
|
||||
|
||||
l_region_name := b.name.as_lower
|
||||
end
|
||||
end
|
||||
@@ -447,10 +510,25 @@ feature -- Blocks regions
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Blocks
|
||||
feature -- Blocks
|
||||
|
||||
put_block (b: CMS_BLOCK; a_default_region: detachable READABLE_STRING_8; is_block_included_by_default: BOOLEAN)
|
||||
-- Add block `b' to associated region or `a_default_region' if provided
|
||||
-- and check optional associated condition.
|
||||
-- If no condition then use `is_block_included_by_default' to
|
||||
-- decide if block is included or not.
|
||||
local
|
||||
l_region: detachable like block_region
|
||||
do
|
||||
if is_block_included (b.name, is_block_included_by_default) then
|
||||
l_region := block_region (b, a_default_region)
|
||||
l_region.extend (b)
|
||||
end
|
||||
end
|
||||
|
||||
add_block (b: CMS_BLOCK; a_default_region: detachable READABLE_STRING_8)
|
||||
-- Add block `b' to associated region or `a_default_region' if provided.
|
||||
-- WARNING: ignore any block condition! USE WITH CARE!
|
||||
local
|
||||
l_region: detachable like block_region
|
||||
do
|
||||
@@ -463,29 +541,29 @@ feature -- Blocks
|
||||
debug ("refactor_fixme")
|
||||
fixme ("find a way to have this in configuration or database, and allow different order")
|
||||
end
|
||||
add_block (top_header_block, "top")
|
||||
add_block (header_block, "header")
|
||||
put_block (top_header_block, "top", True)
|
||||
put_block (header_block, "header", True)
|
||||
if attached message_block as m then
|
||||
add_block (m, "content")
|
||||
put_block (m, "content", True)
|
||||
end
|
||||
if attached primary_tabs_block as m then
|
||||
add_block (m, "content")
|
||||
put_block (m, "content", True)
|
||||
end
|
||||
add_block (content_block, "content")
|
||||
add_block (content_block, "content") -- Can not be disabled!
|
||||
|
||||
if attached management_menu_block as l_block then
|
||||
add_block (l_block, "sidebar_first")
|
||||
put_block (l_block, "sidebar_first", True)
|
||||
end
|
||||
if attached navigation_menu_block as l_block then
|
||||
add_block (l_block, "sidebar_first")
|
||||
put_block (l_block, "sidebar_first", True)
|
||||
end
|
||||
if attached user_menu_block as l_block then
|
||||
add_block (l_block, "sidebar_second")
|
||||
put_block (l_block, "sidebar_second", True)
|
||||
end
|
||||
|
||||
invoke_block
|
||||
hooks.invoke_block (Current)
|
||||
debug ("cms")
|
||||
add_block (create {CMS_CONTENT_BLOCK}.make ("made_with", Void, "Made with <a href=%"http://www.eiffel.com/%">EWF</a>", Void), "footer")
|
||||
put_block (create {CMS_CONTENT_BLOCK}.make ("made_with", Void, "Made with <a href=%"https://www.eiffel.org/%">EWF</a>", Void), "footer", True)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -599,90 +677,6 @@ feature -- Hooks
|
||||
hooks: CMS_HOOK_CORE_MANAGER
|
||||
-- Manager handling hook subscriptions.
|
||||
|
||||
feature -- Hook: value alter
|
||||
|
||||
-- subscribe_to_value_table_alter_hook (h: CMS_HOOK_VALUE_TABLE_ALTER)
|
||||
-- -- Add `h' as subscriber of value table alter hooks CMS_HOOK_VALUE_TABLE_ALTER.
|
||||
-- do
|
||||
-- hooks.subscribe_to_value_table_alter_hook (h)
|
||||
-- end
|
||||
|
||||
invoke_value_table_alter (a_table: CMS_VALUE_TABLE)
|
||||
-- Invoke value table alter hook for table `a_table'.
|
||||
do
|
||||
hooks.invoke_value_table_alter (a_table, Current)
|
||||
end
|
||||
|
||||
feature -- Hook: response
|
||||
|
||||
-- subscribe_to_response_alter_hook (h: CMS_HOOK_RESPONSE_ALTER)
|
||||
-- -- Add `h' as subscriber of response alter hooks CMS_HOOK_RESPONSE_ALTER.
|
||||
-- do
|
||||
-- hooks.subscribe_to_response_alter_hook (h)
|
||||
-- end
|
||||
|
||||
invoke_response_alter (a_response: CMS_RESPONSE)
|
||||
-- Invoke response alter hook for response `a_response'.
|
||||
do
|
||||
hooks.invoke_response_alter (a_response)
|
||||
end
|
||||
|
||||
feature -- Hook: menu_system_alter
|
||||
|
||||
-- subscribe_to_menu_system_alter_hook (h: CMS_HOOK_MENU_SYSTEM_ALTER)
|
||||
-- -- Add `h' as subscriber of menu system alter hooks CMS_HOOK_MENU_SYSTEM_ALTER.
|
||||
-- do
|
||||
-- hooks.subscribe_to_menu_system_alter_hook (h)
|
||||
-- end
|
||||
|
||||
invoke_menu_system_alter (a_menu_system: CMS_MENU_SYSTEM)
|
||||
-- Invoke menu system alter hook for menu `a_menu_system'.
|
||||
do
|
||||
hooks.invoke_menu_system_alter (menu_system, Current)
|
||||
end
|
||||
|
||||
feature -- Hook: menu_alter
|
||||
|
||||
-- subscribe_to_menu_alter_hook (h: CMS_HOOK_MENU_ALTER)
|
||||
-- -- Add `h' as subscriber of menu alter hooks CMS_HOOK_MENU_ALTER.
|
||||
-- do
|
||||
-- hooks.subscribe_to_menu_alter_hook (h)
|
||||
-- end
|
||||
|
||||
invoke_menu_alter (a_menu: CMS_MENU)
|
||||
-- Invoke menu alter hook for menu `a_menu'.
|
||||
do
|
||||
hooks.invoke_menu_alter (a_menu, Current)
|
||||
end
|
||||
|
||||
feature -- Hook: form_alter
|
||||
|
||||
-- subscribe_to_form_alter_hook (h: CMS_HOOK_FORM_ALTER)
|
||||
-- -- Add `h' as subscriber of form alter hooks CMS_HOOK_FORM_ALTER.
|
||||
-- do
|
||||
-- hooks.subscribe_to_form_alter_hook (h)
|
||||
-- end
|
||||
|
||||
invoke_form_alter (a_form: CMS_FORM; a_form_data: detachable WSF_FORM_DATA)
|
||||
-- Invoke form alter hook for form `a_form' and associated data `a_form_data'
|
||||
do
|
||||
hooks.invoke_form_alter (a_form, a_form_data, Current)
|
||||
end
|
||||
|
||||
feature -- Hook: block
|
||||
|
||||
subscribe_to_block_hook (h: CMS_HOOK_BLOCK)
|
||||
-- Add `h' as subscriber of hooks CMS_HOOK_BLOCK.
|
||||
do
|
||||
hooks.subscribe_to_hook (h, {CMS_HOOK_BLOCK})
|
||||
end
|
||||
|
||||
invoke_block
|
||||
-- Invoke block hook in order to get block from modules.
|
||||
do
|
||||
hooks.invoke_block (Current)
|
||||
end
|
||||
|
||||
feature -- Menu: change
|
||||
|
||||
add_to_main_menu (lnk: CMS_LINK)
|
||||
@@ -704,9 +698,6 @@ feature -- Menu: change
|
||||
|
||||
add_to_menu (lnk: CMS_LINK; m: CMS_MENU)
|
||||
do
|
||||
-- if attached {CMS_LOCAL_LINK} lnk as l_local then
|
||||
-- l_local.get_is_active (request)
|
||||
-- end
|
||||
m.extend (lnk)
|
||||
end
|
||||
|
||||
@@ -815,13 +806,16 @@ feature -- Generation
|
||||
prepare (page: CMS_HTML_PAGE)
|
||||
local
|
||||
lnk: CMS_LINK
|
||||
l_region: CMS_BLOCK_REGION
|
||||
l_menu_list_prepared: ARRAYED_LIST [CMS_LINK_COMPOSITE]
|
||||
l_empty_blocks: detachable ARRAYED_LIST [CMS_BLOCK]
|
||||
l_block_html: STRING
|
||||
do
|
||||
-- Menu
|
||||
create {CMS_LOCAL_LINK} lnk.make ("Home", "")
|
||||
lnk.set_weight (-10)
|
||||
add_to_primary_menu (lnk)
|
||||
invoke_menu_system_alter (menu_system)
|
||||
hooks.invoke_menu_system_alter (menu_system, Current)
|
||||
|
||||
if api.enabled_modules.count = 0 then
|
||||
add_to_primary_menu (create {CMS_LOCAL_LINK}.make ("Install", "admin/install"))
|
||||
@@ -833,14 +827,29 @@ feature -- Generation
|
||||
across
|
||||
regions as reg_ic
|
||||
loop
|
||||
l_region := reg_ic.item
|
||||
across
|
||||
reg_ic.item.blocks as ic
|
||||
l_region.blocks as ic
|
||||
loop
|
||||
if attached {CMS_MENU_BLOCK} ic.item as l_menu_block then
|
||||
l_menu_list_prepared.force (l_menu_block.menu)
|
||||
prepare_links (l_menu_block.menu)
|
||||
if l_menu_block.menu.is_empty then
|
||||
if l_empty_blocks = Void then
|
||||
create l_empty_blocks.make (1)
|
||||
end
|
||||
l_empty_blocks.force (l_menu_block)
|
||||
end
|
||||
end
|
||||
end
|
||||
if l_empty_blocks /= Void then
|
||||
across
|
||||
l_empty_blocks as ic
|
||||
loop
|
||||
l_region.remove (ic.item)
|
||||
end
|
||||
l_empty_blocks := Void
|
||||
end
|
||||
end
|
||||
|
||||
-- Prepare menu not in a block.
|
||||
@@ -864,10 +873,10 @@ feature -- Generation
|
||||
custom_prepare (page)
|
||||
|
||||
-- Cms response
|
||||
invoke_response_alter (Current)
|
||||
hooks.invoke_response_alter (Current)
|
||||
|
||||
-- Cms values
|
||||
invoke_value_table_alter (values)
|
||||
hooks.invoke_value_table_alter (values, Current)
|
||||
|
||||
-- Predefined values
|
||||
page.register_variable (page, "page") -- DO NOT REMOVE
|
||||
@@ -899,7 +908,13 @@ feature -- Generation
|
||||
end
|
||||
end
|
||||
end
|
||||
page.add_to_region (theme.block_html (ic.item), reg_ic.item.name)
|
||||
l_block_html := theme.block_html (ic.item)
|
||||
if attached {CMS_CACHE_BLOCK} ic.item then
|
||||
|
||||
elseif attached block_cache (ic.item.name) as l_cache_block then
|
||||
l_cache_block.block.cache.put (l_block_html)
|
||||
end
|
||||
page.add_to_region (l_block_html, reg_ic.item.name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1055,6 +1070,7 @@ feature {NONE} -- Execution
|
||||
page: CMS_HTML_PAGE_RESPONSE
|
||||
utf: UTF_CONVERTER
|
||||
h: HTTP_HEADER
|
||||
l_new_location: READABLE_STRING_8
|
||||
do
|
||||
if attached {READABLE_STRING_GENERAL} values.item ("optional_content_type") as l_type then
|
||||
create cms_page.make_typed (utf.utf_32_string_to_utf_8_string_8 (l_type))
|
||||
@@ -1070,12 +1086,12 @@ feature {NONE} -- Execution
|
||||
if attached redirection as l_location then
|
||||
-- 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)
|
||||
l_new_location := l_location
|
||||
else
|
||||
-- h.put_location (request.absolute_url (l_location, Void))
|
||||
response.redirect_now (absolute_url (l_location, Void))
|
||||
l_new_location := absolute_url (l_location, Void)
|
||||
end
|
||||
-- h.put_location (l_new_location)
|
||||
response.redirect_now (l_new_location)
|
||||
else
|
||||
h.put_header_object (header)
|
||||
|
||||
|
||||
@@ -20,9 +20,10 @@ feature -- Generation
|
||||
|
||||
custom_prepare (page: CMS_HTML_PAGE)
|
||||
do
|
||||
set_status_code ({HTTP_STATUS_CODE}.bad_request)
|
||||
page.register_variable (absolute_url (request.percent_encoded_path_info, Void), "request")
|
||||
page.set_status_code ({HTTP_STATUS_CODE}.bad_request)
|
||||
page.register_variable (page.status_code.out, "code")
|
||||
page.set_status_code (status_code)
|
||||
page.register_variable (status_code.out, "code")
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
@@ -20,9 +20,10 @@ feature -- Generation
|
||||
|
||||
custom_prepare (page: CMS_HTML_PAGE)
|
||||
do
|
||||
set_status_code ({HTTP_STATUS_CODE}.forbidden)
|
||||
page.register_variable (absolute_url (request.percent_encoded_path_info, Void), "request")
|
||||
page.set_status_code ({HTTP_STATUS_CODE}.forbidden)
|
||||
page.register_variable (page.status_code.out, "code")
|
||||
page.set_status_code (status_code)
|
||||
page.register_variable (status_code.out, "code")
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
@@ -20,9 +20,10 @@ feature -- Generation
|
||||
|
||||
custom_prepare (page: CMS_HTML_PAGE)
|
||||
do
|
||||
set_status_code ({HTTP_STATUS_CODE}.internal_server_error)
|
||||
page.register_variable (absolute_url (location, Void), "request")
|
||||
page.set_status_code ({HTTP_STATUS_CODE}.internal_server_error)
|
||||
page.register_variable (page.status_code.out, "code")
|
||||
page.set_status_code (status_code)
|
||||
page.register_variable (status_code.out, "code")
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
@@ -20,9 +20,10 @@ feature -- Generation
|
||||
|
||||
custom_prepare (page: CMS_HTML_PAGE)
|
||||
do
|
||||
set_status_code ({HTTP_STATUS_CODE}.not_found)
|
||||
page.register_variable (absolute_url (request.percent_encoded_path_info, Void), "request")
|
||||
page.set_status_code ({HTTP_STATUS_CODE}.not_found)
|
||||
page.register_variable (page.status_code.out, "code")
|
||||
page.set_status_code (status_code)
|
||||
page.register_variable (status_code.out, "code")
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
@@ -20,9 +20,10 @@ feature -- Generation
|
||||
|
||||
custom_prepare (page: CMS_HTML_PAGE)
|
||||
do
|
||||
set_status_code ({HTTP_STATUS_CODE}.not_implemented)
|
||||
page.register_variable (absolute_url (request.percent_encoded_path_info, Void), "request")
|
||||
page.set_status_code ({HTTP_STATUS_CODE}.not_implemented)
|
||||
page.register_variable (page.status_code.out, "code")
|
||||
page.set_status_code (status_code)
|
||||
page.register_variable (status_code.out, "code")
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
39
tools/roc.bat
Normal file
39
tools/roc.bat
Normal file
@@ -0,0 +1,39 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
if "%ROC_TOOL_PATH%" == "" goto LOCAL_ROC_TOOL
|
||||
goto start
|
||||
|
||||
:LOCAL_ROC_TOOL
|
||||
if exist "%~dp0roc.exe" set ROC_TOOL_PATH=%~dp0
|
||||
|
||||
if "%ROC_TOOL_PATH%" == "" goto SEARCH_ROC_TOOL
|
||||
goto START
|
||||
|
||||
:SEARCH_ROC_TOOL
|
||||
for %%f in (roc.exe) do (
|
||||
if exist "%%~dp$PATH:f" set ROC_TOOL_PATH="%%~dp$PATH:f"
|
||||
)
|
||||
if "%ROC_TOOL_PATH%" == "" goto BUILD_ROC_TOOL
|
||||
echo Using roc.exe from %ROC_TOOL_PATH%
|
||||
goto START
|
||||
|
||||
:BUILD_ROC_TOOL
|
||||
set ROC_SRCDIR=%~dp0roc
|
||||
set ROC_COMPDIR=%~dp0.roc-comp
|
||||
mkdir %ROC_COMPDIR%
|
||||
call ecb -config %ROC_SRCDIR%\roc.ecf -finalize -c_compile -project_path %ROC_COMPDIR%
|
||||
copy %ROC_COMPDIR%\EIFGENs\roc\F_code\roc.exe %~dp0roc.exe
|
||||
rd /q/s %ROC_COMPDIR%
|
||||
|
||||
set ROC_TOOL_PATH=%~dp0
|
||||
goto START
|
||||
|
||||
:START
|
||||
echo Calling %ROC_TOOL_PATH%roc.exe %*
|
||||
call %ROC_TOOL_PATH%roc.exe %*
|
||||
goto END
|
||||
|
||||
:END
|
||||
endlocal
|
||||
exit /B 0
|
||||
Reference in New Issue
Block a user