diff --git a/examples/demo/roc.cfg b/examples/demo/roc.cfg index 379462a..e9f7ede 100644 --- a/examples/demo/roc.cfg +++ b/examples/demo/roc.cfg @@ -4,6 +4,7 @@ "location": ".", "site_directory": "site", "modules": { + "core": { "location": "../../modules/core" }, "admin": { "location": "../../modules/admin" }, "auth": { "location": "../../modules/auth" }, "basic_auth": { "location": "../../modules/basic_auth" }, diff --git a/examples/demo/site/config/cms.ini b/examples/demo/site/config/cms.ini index 17aa909..682dd5c 100644 --- a/examples/demo/site/config/cms.ini +++ b/examples/demo/site/config/cms.ini @@ -43,7 +43,7 @@ output=site\db\mailer.log # Default is "on" # for each module, this can be overwritten with # module_name= on or off -*=all +#*=on [blocks] @include=blocks.ini diff --git a/examples/demo/site/modules/admin/files/css/admin.css b/examples/demo/site/modules/admin/files/css/admin.css index 46f06ca..34127cd 100644 --- a/examples/demo/site/modules/admin/files/css/admin.css +++ b/examples/demo/site/modules/admin/files/css/admin.css @@ -1,34 +1,54 @@ ul.cms-users { list-style-type: none; padding: 3px 3px 3px 3px; - border: solid 1px #ccc; } - ul.cms-users li { - border-top: dotted 1px #ccc; } - ul.cms-users li:first-child { - border-top: none; } - ul.cms-users li.cms_user a::before { - content: "[users] "; } + border: solid 1px #ccc; +} +ul.cms-users li { + border-top: dotted 1px #ccc; +} +ul.cms-users li:first-child { + border-top: none; +} +ul.cms-users li.cms_user a::before { + content: "[users] "; +} ul.cms-roles { list-style-type: none; padding: 3px 3px 3px 3px; - border: solid 1px #ccc; } - ul.cms-roles li { - border-top: dotted 1px #ccc; } - ul.cms-roles li:first-child { - border-top: none; } - ul.cms-roles li.cms_role a::before { - content: "[roles] "; } + border: solid 1px #ccc; +} +ul.cms-roles li { + border-top: dotted 1px #ccc; +} +ul.cms-roles li:first-child { + border-top: none; +} +ul.cms-roles li.cms_role a::before { + content: "[roles] "; +} ul.cms-permissions { list-style-type: none; padding: 3px 3px 3px 3px; - border: solid 1px #ccc; } - ul.cms-permissions li { - border-top: dotted 1px #ccc; } - ul.cms-permissions li:first-child { - border-top: none; } - ul.cms-permissions li.cms_permission a::before { - content: "[permission] "; } + border: solid 1px #ccc; +} +ul.cms-permissions li { + border-top: dotted 1px #ccc; +} +ul.cms-permissions li:first-child { + border-top: none; +} +ul.cms-permissions li.cms_permission a::before { + content: "[permission] "; +} -/*# sourceMappingURL=admin.css.map */ +form#modules_collection thead td { + font-weight: bold; +} +form#modules_collection tr { + border-bottom: dotted 1px #ccc; +} +form#modules_collection td { + padding: 3px; +} diff --git a/examples/demo/site/modules/admin/files/scss/admin.scss b/examples/demo/site/modules/admin/files/scss/admin.scss index 3068a8e..8cf64a1 100644 --- a/examples/demo/site/modules/admin/files/scss/admin.scss +++ b/examples/demo/site/modules/admin/files/scss/admin.scss @@ -54,6 +54,16 @@ ul.cms-permissions { } } - +form#modules_collection { + thead td { + font-weight: bold; + } + tr { + border-bottom: dotted 1px #ccc; + } + td { + padding: 3px; + } +} diff --git a/examples/demo/site/modules/auth/auth.json b/examples/demo/site/modules/auth/auth.json deleted file mode 100644 index 2f3e155..0000000 --- a/examples/demo/site/modules/auth/auth.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "email": "webmaster@example.com", - "subjet_register": "Thank you for regitering with us, activate account", - "subjet_activate": "New account ativation token", - "subjet_password": "Password Recovery!!!", - "subjet_oauth": "Welcome", - "smtp": "127.0.0.1" -} diff --git a/examples/demo/site/modules/auth/templates/block_account_info.tpl b/examples/demo/site/modules/auth/templates/block_account_info.tpl index 4f96ae8..e59e268 100644 --- a/examples/demo/site/modules/auth/templates/block_account_info.tpl +++ b/examples/demo/site/modules/auth/templates/block_account_info.tpl @@ -8,6 +8,9 @@
{$user.email/}
+
+ {$user.profile_name/} +
{$user.creation_date/} (UTC)
diff --git a/examples/demo/site/modules/blog/scripts/install.sql b/examples/demo/site/modules/blog/scripts/install.sql deleted file mode 100644 index 3475dbb..0000000 --- a/examples/demo/site/modules/blog/scripts/install.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE blog_post_nodes( - `nid` INTEGER NOT NULL CHECK("nid">=0), - `revision` INTEGER NOT NULL, - `tags` VARCHAR(255), - CONSTRAINT PK_nid_revision PRIMARY KEY (nid,revision) -); diff --git a/examples/demo/site/scripts/user.sql b/examples/demo/site/modules/core/scripts/core.sql similarity index 73% rename from examples/demo/site/scripts/user.sql rename to examples/demo/site/modules/core/scripts/core.sql index 161642d..4f09aef 100644 --- a/examples/demo/site/scripts/user.sql +++ b/examples/demo/site/modules/core/scripts/core.sql @@ -1,4 +1,29 @@ +CREATE TABLE `logs`( + `id` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, + `category` VARCHAR(255) NOT NULL, + `level` INTEGER NOT NULL, + `uid` INTEGER, + `message` TEXT NOT NULL, + `info` TEXT, + `link` TEXT, + `date` DATETIME NOT NULL +); + +CREATE TABLE `custom_values`( + `type` VARCHAR(255) NOT NULL, + `name` VARCHAR(255) NOT NULL, + `value` TEXT +); + +CREATE TABLE `path_aliases`( + `pid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, + `source` VARCHAR(255) NOT NULL, + `alias` VARCHAR(255) NOT NULL, + `lang` VARCHAR(12) +); + + CREATE TABLE `users`( `uid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, `name` VARCHAR(100) NOT NULL, @@ -8,6 +33,7 @@ CREATE TABLE `users`( `status` INTEGER, `created` DATETIME NOT NULL, `signed` DATETIME, + `profile_name` VARCHAR(250) NULL, CONSTRAINT `name` UNIQUE(`name`) ); diff --git a/examples/demo/site/modules/custom_block/templates/block_test.tpl b/examples/demo/site/modules/custom_block/templates/block_test.tpl deleted file mode 100644 index 842e4cd..0000000 --- a/examples/demo/site/modules/custom_block/templates/block_test.tpl +++ /dev/null @@ -1,3 +0,0 @@ -
-This is a nice custom block test for site {$sitename/}. -
diff --git a/modules/oauth20/site/scripts/oauth2_consumers_initialize.sql b/examples/demo/site/modules/oauth20/scripts/data.sql similarity index 100% rename from modules/oauth20/site/scripts/oauth2_consumers_initialize.sql rename to examples/demo/site/modules/oauth20/scripts/data.sql diff --git a/modules/oauth20/site/scripts/oauth2_consumers.sql b/examples/demo/site/modules/oauth20/scripts/install.sql similarity index 100% rename from modules/oauth20/site/scripts/oauth2_consumers.sql rename to examples/demo/site/modules/oauth20/scripts/install.sql diff --git a/examples/demo/site/scripts/core.sql b/examples/demo/site/scripts/core.sql deleted file mode 100644 index 5b5d0fe..0000000 --- a/examples/demo/site/scripts/core.sql +++ /dev/null @@ -1,23 +0,0 @@ -CREATE TABLE `logs`( - `id` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, - `category` VARCHAR(255) NOT NULL, - `level` INTEGER NOT NULL, - `uid` INTEGER, - `message` TEXT NOT NULL, - `info` TEXT, - `link` TEXT, - `date` DATETIME NOT NULL -); - -CREATE TABLE `custom_values`( - `type` VARCHAR(255) NOT NULL, - `name` VARCHAR(255) NOT NULL, - `value` TEXT -); - -CREATE TABLE `path_aliases`( - `pid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, - `source` VARCHAR(255) NOT NULL, - `alias` VARCHAR(255) NOT NULL, - `lang` VARCHAR(12) -); diff --git a/examples/demo/site/themes/bootstrap/assets/css/style.css b/examples/demo/site/themes/bootstrap/assets/css/style.css index 5accf73..8782329 100644 --- a/examples/demo/site/themes/bootstrap/assets/css/style.css +++ b/examples/demo/site/themes/bootstrap/assets/css/style.css @@ -47,6 +47,9 @@ ul.horizontal li { padding: 5px; font-style: italic; } +#content .preview { + border: solid 1px red; +} .sidebar { padding: 5px; diff --git a/examples/demo/site/themes/bootstrap/assets/scss/style.scss b/examples/demo/site/themes/bootstrap/assets/scss/style.scss index 90d2bb9..e2c4f77 100644 --- a/examples/demo/site/themes/bootstrap/assets/scss/style.scss +++ b/examples/demo/site/themes/bootstrap/assets/scss/style.scss @@ -51,6 +51,9 @@ ul.horizontal { padding: 5px; font-style: italic; } + .preview { + border: solid 1px red; + } } .sidebar { padding: 5px; diff --git a/examples/demo/src/demo_cms_execution.e b/examples/demo/src/demo_cms_execution.e index efa7875..7c6fb30 100644 --- a/examples/demo/src/demo_cms_execution.e +++ b/examples/demo/src/demo_cms_execution.e @@ -52,6 +52,8 @@ feature -- CMS modules a_setup.register_module (create {CMS_OAUTH_20_MODULE}.make) a_setup.register_module (create {CMS_OPENID_MODULE}.make) a_setup.register_module (create {CMS_SESSION_AUTH_MODULE}.make) + + -- User -- Nodes a_setup.register_module (create {CMS_NODE_MODULE}.make) diff --git a/library/model/src/user/cms_user.e b/library/model/src/user/cms_user.e index 78f0556..641e582 100644 --- a/library/model/src/user/cms_user.e +++ b/library/model/src/user/cms_user.e @@ -9,7 +9,6 @@ class CMS_USER inherit - DEBUG_OUTPUT create @@ -56,6 +55,9 @@ feature -- Access name: READABLE_STRING_32 -- User name. + profile_name: detachable READABLE_STRING_32 + -- Optional profile name. + password: detachable READABLE_STRING_32 -- User password (plain text password). @@ -94,17 +96,17 @@ feature -- Roles feature -- Access: data - data: detachable STRING_TABLE [detachable ANY] - -- Additional data. - - data_item (k: READABLE_STRING_GENERAL): detachable ANY + item (k: READABLE_STRING_GENERAL): detachable ANY assign put -- Additional item data associated with key `k'. do - if attached data as l_data then - Result := l_data.item (k) + if attached items as tb then + Result := tb.item (k) end end + items: detachable STRING_TABLE [detachable ANY] + -- Additional data. + feature -- Status report has_id: BOOLEAN @@ -158,6 +160,14 @@ feature -- Change element name_set: name = n end + set_profile_name (pn: like profile_name) + -- Set `profile_name' with `pn'. + do + profile_name := pn + ensure + profile_name_set: profile_name = pn + end + set_password (a_password: like password) -- Set `password' with `a_password'. do @@ -204,26 +214,26 @@ feature -- Element change: roles roles := lst end -feature -- Change element: data +feature -- Change element: data - set_data_item (k: READABLE_STRING_GENERAL; d: like data_item) + put (d: like item; k: READABLE_STRING_GENERAL) -- Associate data item `d' with key `k'. local - l_data: like data + tb: like items do - l_data := data - if l_data = Void then - create l_data.make (1) - data := l_data + tb := items + if tb = Void then + create tb.make (1) + items := tb end - l_data.force (d, k) + tb.force (d, k) end - remove_data_item (k: READABLE_STRING_GENERAL) + remove (k: READABLE_STRING_GENERAL) -- Remove data item associated with key `k'. do - if attached data as l_data then - l_data.remove (k) + if attached items as tb then + tb.remove (k) end end diff --git a/modules/admin/cms_admin_module.e b/modules/admin/cms_admin_module.e index 47fecb2..77bc140 100644 --- a/modules/admin/cms_admin_module.e +++ b/modules/admin/cms_admin_module.e @@ -28,6 +28,7 @@ feature {NONE} -- Initialization version := "1.0" description := "Service to Administrate CMS (users, modules, etc)" package := "core" + enable -- Is enabled by default end feature -- Access @@ -90,7 +91,7 @@ feature -- Access: router create l_admin_export_handler.make (a_api) create l_uri_mapping.make_trailing_slash_ignored ("/admin/export", l_admin_export_handler) a_router.map (l_uri_mapping, a_router.methods_get_post) - + create l_admin_import_handler.make (a_api) create l_uri_mapping.make_trailing_slash_ignored ("/admin/import", l_admin_import_handler) a_router.map (l_uri_mapping, a_router.methods_get_post) diff --git a/modules/admin/handler/cms_admin_modules_handler.e b/modules/admin/handler/cms_admin_modules_handler.e index 1b696fa..388927b 100644 --- a/modules/admin/handler/cms_admin_modules_handler.e +++ b/modules/admin/handler/cms_admin_modules_handler.e @@ -86,8 +86,11 @@ feature -- Execution r.execute else create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) - f := modules_collection_web_form (r) create s.make_empty + + f := installed_modules_collection_web_form (r) + f.append_to_html (r.wsf_theme, s) + f := modules_to_install_collection_web_form (r) f.append_to_html (r.wsf_theme, s) r.set_page_title ("Modules") r.set_main_content (s) @@ -119,14 +122,9 @@ feature -- Execution create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) r.set_main_content ("You do not have permission to access CMS module installation procedure!") else - f := modules_collection_web_form (r) - if l_op.same_string ("Install modules") then - f.submit_actions.extend (agent on_installation_submit) - f.process (r) - elseif l_op.same_string ("uninstall") then - f.submit_actions.extend (agent on_uninstallation_submit) - f.process (r) - end + f := modules_to_install_collection_web_form (r) + f.submit_actions.extend (agent on_installation_submit) + f.process (r) if not attached f.last_data as l_data or else not l_data.is_valid @@ -142,6 +140,31 @@ feature -- Execution end end r.execute + elseif l_op.same_string ("Update status") then + create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) + if api.has_permission ("admin module") then + f := installed_modules_collection_web_form (r) + f.submit_actions.extend (agent on_update_status_submit) + f.process (r) + if + not attached f.last_data as l_data or else + not l_data.is_valid + then + r.add_error_message ("Error occurred.") + create s.make_empty + f.append_to_html (r.wsf_theme, s) + r.set_page_title ("Modules") + r.set_main_content (s) + else + r.add_notice_message ("Operation on module(s) succeeded.") + r.set_redirection (r.location) + end + + else + create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api) + r.set_main_content ("You do not have permission to administrate CMS modules!") + end + r.execute else create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api) r.execute @@ -151,7 +174,7 @@ feature -- Execution end end - modules_collection_web_form (a_response: CMS_RESPONSE): CMS_FORM + installed_modules_collection_web_form (a_response: CMS_RESPONSE): CMS_FORM local mod: CMS_MODULE f_cb: WSF_FORM_CHECKBOX_INPUT @@ -160,8 +183,10 @@ feature -- Execution w_item: WSF_WIDGET_TABLE_ITEM w_submit: WSF_FORM_SUBMIT_INPUT w_set: WSF_FORM_FIELD_SET + w_hidden: WSF_FORM_HIDDEN_INPUT l_mods_to_install: ARRAYED_LIST [CMS_MODULE] + l_extra: STRING do create Result.make (a_response.url (a_response.location, Void), "modules_collection") create w_tb.make @@ -185,19 +210,41 @@ feature -- Execution if not a_response.api.is_module_installed (mod) then l_mods_to_install.extend (mod) else + create l_extra.make_empty create w_row.make (5) - create f_cb.make ("module_" + mod.name) - f_cb.set_text_value (mod.name) - f_cb.set_checked (mod.is_enabled) - f_cb.set_is_readonly (True) - create w_item.make_with_content (f_cb) - w_row.add_item (w_item) + if not mod.is_enabled and api.is_module_enabled (mod) then + create w_set.make + + create f_cb.make ("disabled_module_status[" + mod.name + "]") + f_cb.set_text_value (mod.name) + f_cb.set_checked (mod.is_enabled) + f_cb.set_checked (True) + f_cb.set_is_readonly (True) + f_cb.set_disabled (True) + w_set.extend (f_cb) + + create w_hidden.make_with_text ("module_status[" + mod.name + "]", mod.name) + w_set.extend (w_hidden) + + create w_item.make_with_content (w_set) + w_row.add_item (w_item) + else + create f_cb.make ("module_status[" + mod.name + "]") + f_cb.set_text_value (mod.name) + f_cb.set_checked (mod.is_enabled) + create w_item.make_with_content (f_cb) + w_row.add_item (w_item) + end create w_item.make_with_text (mod.name) w_row.add_item (w_item) create w_item.make_with_text (mod.version) w_row.add_item (w_item) + if attached api.installed_module_version (mod) as v and then not v.same_string (mod.version) then + w_item.add_css_class ("update-available") + l_extra.append (a_response.link (" Update(" + mod.version + ")", a_response.location + "?op=update&module_update[]=" + mod.name, Void)) + end if attached mod.description as l_desc then create w_item.make_with_text (l_desc) @@ -206,7 +253,9 @@ feature -- Execution create w_item.make_with_text ("") w_row.add_item (w_item) end - create w_item.make_with_text (a_response.link ("Uninstall", a_response.location + "?op=uninstall&module_uninstallation[]=" + mod.name, Void)) + l_extra.append (a_response.link (" Uninstall", a_response.location + "?op=uninstall&module_uninstallation[]=" + mod.name, Void)) + create w_item.make_with_text (l_extra) + w_row.add_item (w_item) w_tb.add_row (w_row) @@ -215,14 +264,38 @@ feature -- Execution create w_set.make w_set.set_legend ("Installed modules") w_set.extend (w_tb) --- create w_submit.make ("op") --- w_submit.set_text_value ("Save") --- w_set.extend (w_submit) + create w_submit.make ("op") + w_submit.set_text_value ("Update status") + w_set.extend (w_submit) Result.extend (w_set) - Result.extend_html_text ("
") + end - if not l_mods_to_install.is_empty then + modules_to_install_collection_web_form (a_response: CMS_RESPONSE): CMS_FORM + local + mod: CMS_MODULE + f_cb: WSF_FORM_CHECKBOX_INPUT + w_tb: WSF_WIDGET_TABLE + w_row: WSF_WIDGET_TABLE_ROW + w_item: WSF_WIDGET_TABLE_ITEM + w_submit: WSF_FORM_SUBMIT_INPUT + w_set: WSF_FORM_FIELD_SET + + l_mods_to_install: ARRAYED_LIST [CMS_MODULE] + do + create Result.make (a_response.url (a_response.location, Void), "modules_collection") + create l_mods_to_install.make (0) + across + a_response.api.setup.modules as ic + loop + mod := ic.item + if not a_response.api.is_module_installed (mod) then + l_mods_to_install.extend (mod) + end + end + if l_mods_to_install.is_empty then + Result.extend_html_text ("No module to install...") + else create w_tb.make w_tb.add_css_class ("modules_table") create w_row.make (3) @@ -230,6 +303,8 @@ feature -- Execution w_row.add_item (w_item) create w_item.make_with_text ("Module") w_row.add_item (w_item) + create w_item.make_with_text ("Version") + w_row.add_item (w_item) create w_item.make_with_text ("Description") w_row.add_item (w_item) w_tb.add_head_row (w_row) @@ -246,6 +321,9 @@ feature -- Execution create w_item.make_with_text (mod.name) w_row.add_item (w_item) + create w_item.make_with_text (mod.version) + w_row.add_item (w_item) + if attached mod.description as l_desc then create w_item.make_with_text (l_desc) w_row.add_item (w_item) @@ -262,6 +340,52 @@ feature -- Execution w_submit.set_text_value ("Install modules") w_set.extend (w_submit) Result.extend (w_set) + Result.extend_html_text ("
") + end + end + + on_update_status_submit (fd: WSF_FORM_DATA) + local + l_mods: CMS_MODULE_COLLECTION + l_new_enabled_modules: ARRAYED_LIST [CMS_MODULE] + l_module: detachable CMS_MODULE + do + if attached {WSF_TABLE} fd.table_item ("module_status") as tb and then not tb.is_empty then + l_mods := api.setup.modules + create l_new_enabled_modules.make (tb.count) + across + tb as ic + loop + if + attached {WSF_STRING} ic.item as l_mod_name and then + attached l_mods.item_by_name (l_mod_name.value) as m + then + if not m.is_enabled then + api.enable_module (m) + end + if not api.is_module_enabled (m) then + fd.report_error ("Enabling failed for module " + m.name) + end + l_new_enabled_modules.force (m) + else + fd.report_error ("Can not find associated module " + ic.item.as_string.url_encoded_value) + end + end + across + l_mods as ic + loop + l_module := ic.item + if not l_new_enabled_modules.has (l_module) then + if l_module.is_enabled then + api.disable_module (l_module) + end + if api.is_module_enabled (l_module) then + fd.report_error ("Disabling failed for module " + l_module.name) + end + end + end + else + fd.report_error ("No module to update!") end end diff --git a/modules/admin/handler/user/cms_user_form_response.e b/modules/admin/handler/user/cms_user_form_response.e index fc9d331..6fccfa7 100644 --- a/modules/admin/handler/user/cms_user_form_response.e +++ b/modules/admin/handler/user/cms_user_form_response.e @@ -325,6 +325,7 @@ feature -- Form fs.set_legend ("Basic User Account Information") fs.extend_html_text ("

") fs.extend_html_text (a_user.name) + if attached a_user.email as l_email then create fe.make_with_text ("email", l_email) else @@ -333,6 +334,15 @@ feature -- Form fe.set_label ("Email") fe.enable_required fs.extend (fe) + + if attached a_user.profile_name as l_profile_name then + create ti.make_with_text ("profile_name", l_profile_name) + else + create ti.make_with_text ("profile_name", "") + end + ti.set_label ("Profile name") + fs.extend (ti) + a_form.extend (fs) a_form.extend_html_text ("
") create ts.make ("op") @@ -371,6 +381,11 @@ feature -- Form fe.set_label ("Email") fe.enable_required fs.extend (fe) + + create ti.make ("profile_name") + ti.set_label ("Profile name") + fs.extend (ti) + a_form.extend (fs) a_form.extend_html_text ("
") create ts.make ("op") @@ -469,6 +484,15 @@ feature -- Form end end if not a_form_data.has_error then + if + attached a_form_data.string_item ("profile_name") as l_prof_name and then + not l_prof_name.is_whitespace + then + a_user.set_profile_name (l_prof_name) + else + a_user.set_profile_name (Void) + end + api.user_api.update_user (a_user) add_success_message ("Updated basic info") end diff --git a/modules/admin/handler/user/cms_user_view_response.e b/modules/admin/handler/user/cms_user_view_response.e index 64883b8..7a9fd2e 100644 --- a/modules/admin/handler/user/cms_user_view_response.e +++ b/modules/admin/handler/user/cms_user_view_response.e @@ -50,6 +50,7 @@ feature -- Execution lnk: CMS_LOCAL_LINK s: STRING l_role: CMS_USER_ROLE + ago: DATE_TIME_AGO_CONVERTER do a_response.set_value (a_user, "user") create lnk.make (a_response.translation ("View", Void), "admin/user/" + a_user.id.out) @@ -80,6 +81,17 @@ feature -- Execution s.append (l_email) s.append ("

") end + if attached a_user.profile_name as l_prof_name then + s.append ("

Profile name: ") + s.append (html_encoded (l_prof_name)) + s.append ("

") + end + if attached a_user.last_login_date as dt then + s.append ("

Last signed: ") + create ago.make + s.append (ago.smart_date_duration (dt)) + s.append ("

") + end if attached {LIST [CMS_USER_ROLE]} api.user_api.user_roles (a_user) as l_roles and then diff --git a/modules/admin/site/files/css/admin.css b/modules/admin/site/files/css/admin.css index 46f06ca..34127cd 100644 --- a/modules/admin/site/files/css/admin.css +++ b/modules/admin/site/files/css/admin.css @@ -1,34 +1,54 @@ ul.cms-users { list-style-type: none; padding: 3px 3px 3px 3px; - border: solid 1px #ccc; } - ul.cms-users li { - border-top: dotted 1px #ccc; } - ul.cms-users li:first-child { - border-top: none; } - ul.cms-users li.cms_user a::before { - content: "[users] "; } + border: solid 1px #ccc; +} +ul.cms-users li { + border-top: dotted 1px #ccc; +} +ul.cms-users li:first-child { + border-top: none; +} +ul.cms-users li.cms_user a::before { + content: "[users] "; +} ul.cms-roles { list-style-type: none; padding: 3px 3px 3px 3px; - border: solid 1px #ccc; } - ul.cms-roles li { - border-top: dotted 1px #ccc; } - ul.cms-roles li:first-child { - border-top: none; } - ul.cms-roles li.cms_role a::before { - content: "[roles] "; } + border: solid 1px #ccc; +} +ul.cms-roles li { + border-top: dotted 1px #ccc; +} +ul.cms-roles li:first-child { + border-top: none; +} +ul.cms-roles li.cms_role a::before { + content: "[roles] "; +} ul.cms-permissions { list-style-type: none; padding: 3px 3px 3px 3px; - border: solid 1px #ccc; } - ul.cms-permissions li { - border-top: dotted 1px #ccc; } - ul.cms-permissions li:first-child { - border-top: none; } - ul.cms-permissions li.cms_permission a::before { - content: "[permission] "; } + border: solid 1px #ccc; +} +ul.cms-permissions li { + border-top: dotted 1px #ccc; +} +ul.cms-permissions li:first-child { + border-top: none; +} +ul.cms-permissions li.cms_permission a::before { + content: "[permission] "; +} -/*# sourceMappingURL=admin.css.map */ +form#modules_collection thead td { + font-weight: bold; +} +form#modules_collection tr { + border-bottom: dotted 1px #ccc; +} +form#modules_collection td { + padding: 3px; +} diff --git a/modules/admin/site/files/scss/admin.scss b/modules/admin/site/files/scss/admin.scss index 3068a8e..8cf64a1 100644 --- a/modules/admin/site/files/scss/admin.scss +++ b/modules/admin/site/files/scss/admin.scss @@ -54,6 +54,16 @@ ul.cms-permissions { } } - +form#modules_collection { + thead td { + font-weight: bold; + } + tr { + border-bottom: dotted 1px #ccc; + } + td { + padding: 3px; + } +} diff --git a/modules/auth/cms_authentication_module.e b/modules/auth/cms_authentication_module.e index df70865..b42e8e2 100644 --- a/modules/auth/cms_authentication_module.e +++ b/modules/auth/cms_authentication_module.e @@ -47,6 +47,7 @@ feature {NONE} -- Initialization package := "authentication" create root_dir.make_current cache_duration := 0 + enable -- Is enabled by default end feature -- Access diff --git a/modules/auth/site/templates/block_account_info.tpl b/modules/auth/site/templates/block_account_info.tpl index 4f96ae8..e59e268 100644 --- a/modules/auth/site/templates/block_account_info.tpl +++ b/modules/auth/site/templates/block_account_info.tpl @@ -8,6 +8,9 @@
{$user.email/}
+
+ {$user.profile_name/} +
{$user.creation_date/} (UTC)
diff --git a/tpl/site/scripts/user.sql b/modules/core/site/scripts/core.sql similarity index 73% rename from tpl/site/scripts/user.sql rename to modules/core/site/scripts/core.sql index e9efdc1..4f09aef 100644 --- a/tpl/site/scripts/user.sql +++ b/modules/core/site/scripts/core.sql @@ -1,4 +1,29 @@ +CREATE TABLE `logs`( + `id` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, + `category` VARCHAR(255) NOT NULL, + `level` INTEGER NOT NULL, + `uid` INTEGER, + `message` TEXT NOT NULL, + `info` TEXT, + `link` TEXT, + `date` DATETIME NOT NULL +); + +CREATE TABLE `custom_values`( + `type` VARCHAR(255) NOT NULL, + `name` VARCHAR(255) NOT NULL, + `value` TEXT +); + +CREATE TABLE `path_aliases`( + `pid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, + `source` VARCHAR(255) NOT NULL, + `alias` VARCHAR(255) NOT NULL, + `lang` VARCHAR(12) +); + + CREATE TABLE `users`( `uid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, `name` VARCHAR(100) NOT NULL, @@ -8,6 +33,7 @@ CREATE TABLE `users`( `status` INTEGER, `created` DATETIME NOT NULL, `signed` DATETIME, + `profile_name` VARCHAR(250) NULL, CONSTRAINT `name` UNIQUE(`name`) ); @@ -46,6 +72,7 @@ CREATE TABLE `users_password_recovery` ( CONSTRAINT `token` UNIQUE (`token`) ); + CREATE TABLE `auth_temp_users` ( `uid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, `name` VARCHAR(100) NOT NULL, diff --git a/modules/node/handler/cms_node_type_webform_manager.e b/modules/node/handler/cms_node_type_webform_manager.e index 0ec2c44..a87dc08 100644 --- a/modules/node/handler/cms_node_type_webform_manager.e +++ b/modules/node/handler/cms_node_type_webform_manager.e @@ -263,7 +263,7 @@ feature -- Forms ... feature -- Output - append_content_as_html_to (a_node: G; is_teaser: BOOLEAN; a_output: STRING; a_response: detachable CMS_RESPONSE) + append_content_as_html_to (a_node: G; is_teaser: BOOLEAN; a_output: STRING; a_response: CMS_RESPONSE) -- local lnk: detachable CMS_LOCAL_LINK @@ -275,7 +275,6 @@ feature -- Output -- Show tabs only if a user is authenticated. if not is_teaser and then - a_response /= Void and then attached a_response.user as l_user then lnk := a_node.link @@ -322,7 +321,7 @@ feature -- Output a_output.append ("
") if attached a_node.author as l_author then a_output.append (" by ") - a_output.append (l_node_api.html_encoded (l_author.name)) + a_output.append (a_response.html_encoded (a_response.user_profile_name (l_author))) end if attached a_node.modification_date as l_modified then a_output.append (" (modified: ") @@ -333,7 +332,6 @@ feature -- Output a_output.append ("
") if - a_response /= Void and then attached {CMS_TAXONOMY_API} cms_api.module_api ({CMS_TAXONOMY_MODULE}) as l_taxonomy_api then l_taxonomy_api.append_taxonomy_to_xhtml (a_node, a_response, a_output) @@ -368,7 +366,7 @@ feature -- Output a_output.append ("") end - append_comments_as_html_to (a_node: G; a_output: STRING; a_response: detachable CMS_RESPONSE) + append_comments_as_html_to (a_node: G; a_output: STRING; a_response: CMS_RESPONSE) do if attached {CMS_COMMENTS_API} cms_api.module_api ({CMS_COMMENTS_MODULE}) as l_comments_api then if attached l_comments_api.comments_for (a_node) as l_comments and then not l_comments.is_empty then @@ -383,14 +381,14 @@ feature -- Output end end - append_comment_as_html_to (a_comment: CMS_COMMENT; a_output: STRING; a_response: detachable CMS_RESPONSE) + append_comment_as_html_to (a_comment: CMS_COMMENT; a_output: STRING; a_response: CMS_RESPONSE) local l_ago: DATE_TIME_AGO_CONVERTER do a_output.append ("
  • ") if attached a_comment.author as l_author then a_output.append ("") - a_output.append (cms_api.html_encoded (l_author.name)) + a_output.append (a_response.html_encoded (a_response.user_profile_name (l_author))) a_output.append ("") elseif attached a_comment.author_name as l_author_name then a_output.append ("") diff --git a/modules/node/handler/cms_page_node_type_webform_manager.e b/modules/node/handler/cms_page_node_type_webform_manager.e index 7ee21f2..41a0f2f 100644 --- a/modules/node/handler/cms_page_node_type_webform_manager.e +++ b/modules/node/handler/cms_page_node_type_webform_manager.e @@ -150,7 +150,7 @@ feature -- Forms ... feature -- Output - append_content_as_html_to (a_node: CMS_PAGE; is_teaser: BOOLEAN; a_output: STRING; a_response: detachable CMS_RESPONSE) + append_content_as_html_to (a_node: CMS_PAGE; is_teaser: BOOLEAN; a_output: STRING; a_response: CMS_RESPONSE) -- local l_node_api: CMS_NODE_API diff --git a/modules/node/submodules/page/cms_page_module.e b/modules/node/submodules/page/cms_page_module.e index 68a2d4c..29d5428 100644 --- a/modules/node/submodules/page/cms_page_module.e +++ b/modules/node/submodules/page/cms_page_module.e @@ -101,7 +101,7 @@ feature {CMS_API} -- Module management do -- Schema if attached a_api.storage.as_sql_storage as l_sql_storage then - if attached a_api.module ({CMS_NODE_MODULE}) as l_node_module then + if attached a_api.installed_module ({CMS_NODE_MODULE}) as l_node_module then l_sql_storage.sql_execute_file_script (a_api.module_resource_location (l_node_module, (create {PATH}.make_from_string ("scripts")).extended (name).appended_with_extension ("sql")), Void) end if l_sql_storage.has_error then diff --git a/modules/oauth20/cms_oauth_20_module.e b/modules/oauth20/cms_oauth_20_module.e index 9e615eb..8c25424 100644 --- a/modules/oauth20/cms_oauth_20_module.e +++ b/modules/oauth20/cms_oauth_20_module.e @@ -84,13 +84,13 @@ feature {CMS_API} -- Module management -- Schema if attached api.storage.as_sql_storage as l_sql_storage then --| Schema - l_sql_storage.sql_execute_file_script (api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended ("oauth2_consumers.sql")), Void) + l_sql_storage.sql_execute_file_script (api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended ("install.sql")), Void) if l_sql_storage.has_error then api.logger.put_error ("Could not initialize database for module [" + name + "]", generating_type) else -- TODO workaround. - l_sql_storage.sql_execute_file_script (api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended ("oauth2_consumers_initialize.sql")), Void) + l_sql_storage.sql_execute_file_script (api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended ("data.sql")), Void) if l_sql_storage.has_error then api.logger.put_error ("Could not initialize oauth2_consumers for module [" + name + "]", generating_type) else diff --git a/modules/oauth20/site/scripts/data.sql b/modules/oauth20/site/scripts/data.sql new file mode 100644 index 0000000..a600e71 --- /dev/null +++ b/modules/oauth20/site/scripts/data.sql @@ -0,0 +1,7 @@ + -- Change the values TO_COMPLETE based on your API. + -- API SECTET KEY AND API PUBLIC KEY +INSERT INTO oauth2_consumers (name, api_secret, api_key, scope, protected_resource_url, callback_name, extractor, authorize_url, endpoint) +VALUES ('google', 'TO-COMPLETE', 'TO-COMPLETE', 'email', 'https://www.googleapis.com/plus/v1/people/me', 'callback_google', 'json','https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI','https://accounts.google.com/o/oauth2/token'); + +INSERT INTO oauth2_consumers (name, api_secret, api_key, scope, protected_resource_url, callback_name, extractor, authorize_url, endpoint ) +VALUES ('facebook', 'TO-COMPLETE', 'TO-COMPLETE', 'email', 'https://graph.facebook.com/me', 'callback_facebook','text','https://www.facebook.com/dialog/oauth?response_type=code&client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI','https://graph.facebook.com/oauth/access_token'); diff --git a/modules/oauth20/site/scripts/install.sql b/modules/oauth20/site/scripts/install.sql new file mode 100644 index 0000000..1c7eea6 --- /dev/null +++ b/modules/oauth20/site/scripts/install.sql @@ -0,0 +1,18 @@ + +CREATE TABLE oauth2_consumers( + `cid` INTEGER PRIMARY KEY NOT NULL CHECK(`cid`>=0), + `name` VARCHAR(255) NOT NULL, + `api_secret` TEXT NOT NULL, + `api_key` TEXT NOT NULL, + `scope` VARCHAR (100) NOT NULL, + `protected_resource_url` VARCHAR (255) NOT NULL, + `callback_name` VARCHAR(255) NOT NULL, + `extractor` VARCHAR(50) NOT NULL, + `authorize_url` VARCHAR (255) NOT NULL, + `endpoint` VARCHAR (255) NOT NULL, + CONSTRAINT `cid` + UNIQUE(`cid`), + CONSTRAINT `name` + UNIQUE(`name`) + ); + diff --git a/modules/session_auth/cms_session_auth_module.e b/modules/session_auth/cms_session_auth_module.e index bc9b53c..b9f4e5b 100644 --- a/modules/session_auth/cms_session_auth_module.e +++ b/modules/session_auth/cms_session_auth_module.e @@ -34,6 +34,7 @@ feature {NONE} -- Initialization Precursor version := "1.0" description := "Service to manage cookie based authentication" + enable -- Enabled by default end feature -- Access diff --git a/src/configuration/cms_setup.e b/src/configuration/cms_setup.e index 176d4ea..5c2d179 100644 --- a/src/configuration/cms_setup.e +++ b/src/configuration/cms_setup.e @@ -115,32 +115,59 @@ feature -- Access feature {CMS_API} -- API Access - enabled_modules: CMS_MODULE_COLLECTION + frozen fill_enabled_modules (api: CMS_API) -- List of enabled modules. local + l_enabled_modules: CMS_MODULE_COLLECTION + l_modules_to_remove: CMS_MODULE_COLLECTION l_module: CMS_MODULE + l_core: CMS_CORE_MODULE do - create Result.make (modules.count) + l_enabled_modules := api.enabled_modules + + -- Include required CORE module + create l_core.make + l_core.enable + l_enabled_modules.extend (l_core) + + -- Includes other modules. across modules as ic loop l_module := ic.item update_module_status_from_configuration (l_module) + if not l_module.is_enabled then + if + api.is_module_enabled (l_module) -- Check from storage! + then + l_module.enable + end + end if l_module.is_enabled then - Result.extend (l_module) + l_enabled_modules.extend (l_module) end end across - Result as ic + l_enabled_modules as ic loop l_module := ic.item - update_module_status_within (l_module, Result) - if not l_module.is_enabled then - Result.remove (l_module) + update_module_status_within (l_module, l_enabled_modules) + if not l_module.is_enabled then -- Check from storage! + if l_modules_to_remove = Void then + create l_modules_to_remove.make (1) + end + l_modules_to_remove.extend (l_module) + end + end + if l_modules_to_remove /= Void then + across + l_modules_to_remove as ic + loop + l_enabled_modules.remove (ic.item) end end ensure - only_enabled_modules: across Result as ic all ic.item.is_enabled end + only_enabled_modules: across api.enabled_modules as ic all ic.item.is_enabled end end feature {CMS_MODULE, CMS_API, CMS_SETUP_ACCESS} -- Restricted access @@ -184,11 +211,11 @@ feature {NONE} -- Implementation: update b: BOOLEAN dft: BOOLEAN do - -- By default enabled. - if false and attached text_item ("modules.*") as l_mod_status then + -- By default, keep previous status. + if attached text_item ("modules.*") as l_mod_status then dft := l_mod_status.is_case_insensitive_equal_general ("on") else - dft := True + dft := m.is_enabled end if attached text_item ("modules." + m.name) as l_mod_status then b := l_mod_status.is_case_insensitive_equal_general ("on") @@ -430,6 +457,6 @@ feature -- Element change end note - copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/src/modules/cms_core_module.e b/src/modules/cms_core_module.e new file mode 100644 index 0000000..1a6dafb --- /dev/null +++ b/src/modules/cms_core_module.e @@ -0,0 +1,115 @@ +note + description: "Module for core functionalities" + date: "$Date$" + revision: "$Revision$" + +class + CMS_CORE_MODULE + +inherit + CMS_MODULE + redefine + initialize, + install + end + +create + make + +feature {NONE} -- Initialization + + make + do + version := "1.0.0.1" + description := "Core" + package := "core" + end + +feature -- Access + + name: STRING = "core" + +feature {CMS_API} -- Module Initialization + + initialize (api: CMS_API) + -- + do + Precursor (api) + end + +feature {CMS_API} -- Module management + + install (a_api: CMS_API) + do + -- Schema + if attached a_api.storage.as_sql_storage as l_sql_storage then + l_sql_storage.sql_execute_file_script (a_api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended (name + ".sql")), Void) + + if l_sql_storage.has_error then + a_api.logger.put_error ("Could not initialize database for module [" + name + "]", generating_type) + else + Precursor {CMS_MODULE} (a_api) + end + end + + install_core_data (a_api) + end + + install_core_data (a_api: CMS_API) + local + u: CMS_USER + l_anonymous_role, l_authenticated_role: CMS_USER_ROLE + do + --| Roles + create l_anonymous_role.make ("anonymous") + a_api.user_api.save_user_role (l_anonymous_role) + + create l_authenticated_role.make ("authenticated") + a_api.user_api.save_user_role (l_authenticated_role) + + --| Users + create u.make ("admin") + u.set_password ("istrator#") + u.set_email (a_api.setup.site_email) + u.set_status ({CMS_USER}.active) + a_api.user_api.new_user (u) + + --| Node + -- FIXME: move that initialization to node module + -- TODO: should we move the initialization to an + --! external configuration file? + --! at the moment we only have 1 admin to the whole site. + --! is that ok? + l_anonymous_role.add_permission ("view any page") + a_api.user_api.save_user_role (l_anonymous_role) + + l_authenticated_role.add_permission ("create page") + l_authenticated_role.add_permission ("view any page") + l_authenticated_role.add_permission ("edit any page") + l_authenticated_role.add_permission ("delete page") + l_authenticated_role.add_permission ("trash page") + l_authenticated_role.add_permission ("view own page") + l_authenticated_role.add_permission ("edit own page") + l_authenticated_role.add_permission ("delete own page") + l_authenticated_role.add_permission ("trash own page") + a_api.user_api.save_user_role (l_authenticated_role) + end + +feature -- Router + + setup_router (a_router: WSF_ROUTER; a_api: CMS_API) + -- + do + end + +note + copyright: "2011-2017, 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 diff --git a/src/persistence/sql/cms_storage_sql_builder.e b/src/persistence/sql/cms_storage_sql_builder.e index 5cead4c..c9f0452 100644 --- a/src/persistence/sql/cms_storage_sql_builder.e +++ b/src/persistence/sql/cms_storage_sql_builder.e @@ -16,50 +16,11 @@ inherit feature -- Initialization initialize (a_setup: CMS_SETUP; a_storage: CMS_STORAGE_SQL) - local - u: CMS_USER - l_anonymous_role, l_authenticated_role: CMS_USER_ROLE do - --| Schema - a_storage.sql_execute_file_script (a_setup.environment.site_path.extended ("scripts").extended ("core.sql"), Void) - a_storage.sql_execute_file_script (a_setup.environment.site_path.extended ("scripts").extended ("user.sql"), Void) - - --| Roles - create l_anonymous_role.make ("anonymous") - a_storage.save_user_role (l_anonymous_role) - - create l_authenticated_role.make ("authenticated") - a_storage.save_user_role (l_authenticated_role) - - --| Users - create u.make ("admin") - u.set_password ("istrator#") - u.set_email (a_setup.site_email) - u.set_status ({CMS_USER}.active) - a_storage.new_user (u) - - --| Node - -- FIXME: move that initialization to node module - -- TODO: should we move the initialization to an - --! external configuration file? - --! at the moment we only have 1 admin to the whole site. - --! is that ok? - l_anonymous_role.add_permission ("view any page") - a_storage.save_user_role (l_anonymous_role) - - l_authenticated_role.add_permission ("create page") - l_authenticated_role.add_permission ("view any page") - l_authenticated_role.add_permission ("edit any page") - l_authenticated_role.add_permission ("delete page") - l_authenticated_role.add_permission ("trash page") - l_authenticated_role.add_permission ("view own page") - l_authenticated_role.add_permission ("edit own page") - l_authenticated_role.add_permission ("delete own page") - l_authenticated_role.add_permission ("trash own page") - a_storage.save_user_role (l_authenticated_role) + -- Eventually custom database initialization... end note - copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/src/persistence/user/cms_user_storage_sql_i.e b/src/persistence/user/cms_user_storage_sql_i.e index 25bce70..bc2843a 100644 --- a/src/persistence/user/cms_user_storage_sql_i.e +++ b/src/persistence/user/cms_user_storage_sql_i.e @@ -261,22 +261,18 @@ feature -- Change: user l_password_salt := user_salt (a_user.name) end if - l_password_hash /= Void and l_password_salt /= Void and - attached a_user.email as l_email + l_password_hash /= Void and l_password_salt /= Void then sql_begin_transaction - write_information_log (generator + ".update_user") - create l_parameters.make (7) + write_information_log (generator + ".update_username") + create l_parameters.make (4) l_parameters.put (a_user.id, "uid") l_parameters.put (a_new_username, "name") l_parameters.put (l_password_hash, "password") l_parameters.put (l_password_salt, "salt") - l_parameters.put (l_email, "email") - l_parameters.put (a_user.status, "status") - l_parameters.put (a_user.last_login_date, "signed") - sql_modify (sql_update_user, l_parameters) + sql_modify (sql_update_user_name, l_parameters) sql_finalize if not error_handler.has_error then a_user.set_name (a_new_username) @@ -319,7 +315,7 @@ feature -- Change: user sql_begin_transaction write_information_log (generator + ".update_user") - create l_parameters.make (7) + create l_parameters.make (8) l_parameters.put (a_user.id, "uid") l_parameters.put (a_user.name, "name") l_parameters.put (l_password_hash, "password") @@ -327,6 +323,7 @@ feature -- Change: user l_parameters.put (l_email, "email") l_parameters.put (a_user.status, "status") l_parameters.put (a_user.last_login_date, "signed") + l_parameters.put (a_user.profile_name, "profile_name") sql_modify (sql_update_user, l_parameters) sql_finalize @@ -870,7 +867,7 @@ feature {NONE} -- Implementation: User end fetch_user: detachable CMS_USER - -- Fetch user from fields: 1:uid, 2:name, 3:password, 4:salt, 5:email, 6:status, 7:created, 8:signed. + -- Fetch user from fields: 1:uid, 2:name, 3:password, 4:salt, 5:email, 6:status, 7:created, 8:signed, 9:profile_name. local l_id: INTEGER_64 l_name: detachable READABLE_STRING_32 @@ -905,6 +902,9 @@ feature {NONE} -- Implementation: User if attached sql_read_date_time (8) as l_signed_date then Result.set_last_login_date (l_signed_date) end + if attached sql_read_string_32 (9) as l_prof_name then + Result.set_profile_name (l_prof_name) + end else check expected_valid_user: False end end @@ -940,30 +940,33 @@ feature {NONE} -- Sql Queries: USER select_users_count: STRING = "SELECT count(*) FROM users;" -- Number of users. - select_users: STRING = "SELECT * FROM users;" + select_users: STRING = "SELECT uid, name, password, salt, email, status, created, signed, profile_name FROM users;" -- List of users. - select_user_by_id: STRING = "SELECT * FROM users WHERE uid =:uid;" + select_user_by_id: STRING = "SELECT uid, name, password, salt, email, status, created, signed, profile_name FROM users WHERE uid =:uid;" -- Retrieve user by id if exists. - select_user_by_name: STRING = "SELECT * FROM users WHERE name =:name;" + select_user_by_name: STRING = "SELECT uid, name, password, salt, email, status, created, signed, profile_name FROM users WHERE name =:name;" -- Retrieve user by name if exists. - sql_select_recent_users: STRING = "SELECT uid, name, password, salt, email, status, created, signed FROM users ORDER BY uid DESC, created DESC LIMIT :rows OFFSET :offset;" + sql_select_recent_users: STRING = "SELECT uid, name, password, salt, email, status, created, signed, profile_name FROM users ORDER BY uid DESC, created DESC LIMIT :rows OFFSET :offset;" -- Retrieve recent users - select_user_by_email: STRING = "SELECT uid, name, password, salt, email, status, created, signed FROM users WHERE email =:email;" + select_user_by_email: STRING = "SELECT uid, name, password, salt, email, status, created, signed, profile_name FROM users WHERE email =:email;" -- Retrieve user by email if exists. select_salt_by_username: STRING = "SELECT salt FROM users WHERE name =:name;" -- Retrieve salt by username if exists. - sql_insert_user: STRING = "INSERT INTO users (name, password, salt, email, created, status) VALUES (:name, :password, :salt, :email, :created, :status);" + sql_insert_user: STRING = "INSERT INTO users (name, password, salt, email, created, status, profile_name) VALUES (:name, :password, :salt, :email, :created, :status, :profile_name);" -- SQL Insert to add a new user. - sql_update_user: STRING = "UPDATE users SET name=:name, password=:password, salt=:salt, email=:email, status=:status, signed=:signed WHERE uid=:uid;" + sql_update_user: STRING = "UPDATE users SET name=:name, password=:password, salt=:salt, email=:email, status=:status, signed=:signed, profile_name=:profile_name WHERE uid=:uid;" -- SQL update to update an existing user. + sql_update_user_name: STRING = "UPDATE users SET name=:name, password=:password, salt=:salt WHERE uid=:uid;" + -- SQL update to update `name` for an existing user. + sql_delete_user: STRING = "DELETE FROM users WHERE uid=:uid;" feature {NONE} -- Sql Queries: USER ROLE @@ -1023,7 +1026,7 @@ feature {NONE} -- Sql Queries: USER ACTIVATION sql_select_userid_activation: STRING = "SELECT uid FROM users_activations WHERE token = :token;" -- Retrieve userid given the activation token. - select_user_by_activation_token: STRING = "SELECT u.* FROM users as u JOIN users_activations as ua ON ua.uid = u.uid and ua.token = :token;" + select_user_by_activation_token: STRING = "SELECT u.uid, u.name, u.password, u.salt, u.email, u.status, u.created, u.signed, u.profile_name FROM users as u JOIN users_activations as ua ON ua.uid = u.uid and ua.token = :token;" -- Retrieve user by activation token if exist. sql_remove_activation: STRING = "DELETE FROM users_activations WHERE token = :token;" @@ -1037,7 +1040,7 @@ feature {NONE} -- User Password Recovery sql_remove_password: STRING = "DELETE FROM users_password_recovery WHERE token = :token;" -- Retrieve password if exist. - select_user_by_password_token: STRING = "SELECT u.* FROM users as u JOIN users_password_recovery as ua ON ua.uid = u.uid and ua.token = :token;" + select_user_by_password_token: STRING = "SELECT u.uid, u.name, u.password, u.salt, u.email, u.status, u.created, u.signed, u.profile_name FROM users as u JOIN users_password_recovery as ua ON ua.uid = u.uid and ua.token = :token;" -- Retrieve user by password token if exist. feature -- Acess: Temp users diff --git a/src/service/cms_api.e b/src/service/cms_api.e index c76050f..3c4346f 100644 --- a/src/service/cms_api.e +++ b/src/service/cms_api.e @@ -57,8 +57,9 @@ feature {NONE} -- Initialize end -- Keep enable modules list. - l_enabled_modules := setup.enabled_modules + create l_enabled_modules.make (setup.modules.count) enabled_modules := l_enabled_modules + setup.fill_enabled_modules (Current) -- Complete storage setup. storage.set_api (Current) @@ -72,6 +73,11 @@ feature {NONE} -- Initialize -- or the reverse, or merge installation and initialization -- and leave the responsability to the module to know -- if this is installed or not... + if attached {CMS_CORE_MODULE} l_module as l_core_module then + if not l_core_module.is_installed (Current) then + l_core_module.install (Current) + end + end -- if not l_module.is_installed (Current) then -- l_module.install (Current) -- end @@ -119,7 +125,7 @@ feature {NONE} -- Initialize formats.extend (f) end -feature {CMS_ACCESS} -- Installation +feature {CMS_ACCESS} -- Module management install_all_modules -- Install CMS or uninstalled module which are enabled. @@ -134,12 +140,19 @@ feature {CMS_ACCESS} -- Installation -- or the reverse, or merge installation and initialization -- and leave the responsability to the module to know -- if this is installed or not... - if not l_module.is_installed (Current) then + if l_module.is_enabled and not l_module.is_installed (Current) then install_module (l_module) end end end + installed_module_version (m: CMS_MODULE): detachable READABLE_STRING_32 + require + module_installed: is_module_installed (m) + do + Result := m.installed_version (Current) + end + install_module (m: CMS_MODULE) -- Install module `m'. require @@ -159,6 +172,22 @@ feature {CMS_ACCESS} -- Installation m.uninstall (Current) end + enable_module (m: CMS_MODULE) + -- Enable module `m'. + do + m.update_status_in_storage (True, Current) + ensure + module_enabled: is_module_enabled (m) + end + + disable_module (m: CMS_MODULE) + -- Disable module `m'. + do + m.update_status_in_storage (False, Current) + ensure + module_disabled: not is_module_enabled (m) + end + feature -- Access setup: CMS_SETUP @@ -431,13 +460,18 @@ feature -- Query: module Result := a_module.is_installed (Current) end + is_module_enabled (a_module: CMS_MODULE): BOOLEAN + do + Result := a_module.is_enabled or a_module.is_enabled_in_storage (Current) + end + enabled_modules: CMS_MODULE_COLLECTION module (a_type: TYPE [CMS_MODULE]): detachable CMS_MODULE -- Enabled module typed `a_type', if any. --| usage: if attached module ({FOO_MODULE}) as mod then ... do - Result := setup.modules.item (a_type) + Result := installed_module (a_type) if Result /= Void and then not Result.is_enabled then Result := Void end @@ -445,6 +479,16 @@ feature -- Query: module Result /= Void implies (Result.is_enabled) -- and a_type.is_conforming_to (Result.generating_type)) end + installed_module (a_type: TYPE [CMS_MODULE]): detachable CMS_MODULE + -- Module typed `a_type', if any. + -- It may not be enabled! + --| usage: if attached module ({FOO_MODULE}) as mod then ... + do + Result := setup.modules.item (a_type) + ensure +--FIXME Result /= Void implies (Result.is_enabled) -- and a_type.is_conforming_to (Result.generating_type)) + end + module_api (a_type: TYPE [CMS_MODULE]): detachable CMS_MODULE_API -- Enabled module API associated with module typed `a_type'. do diff --git a/src/service/cms_api_export_imp.e b/src/service/cms_api_export_imp.e index 471ff70..6248362 100644 --- a/src/service/cms_api_export_imp.e +++ b/src/service/cms_api_export_imp.e @@ -111,6 +111,9 @@ feature -- Export u := ic.item create j.make_empty j.put_string (u.name, "name") + if attached u.profile_name as pn then + j.put_string (pn, "profile_name") + end j.put_integer (u.status, "status") put_string_into_json (u.email, "email", j) put_string_into_json (u.password, "password", j) diff --git a/src/service/cms_api_import_imp.e b/src/service/cms_api_import_imp.e index 4aa47a9..f3fec86 100644 --- a/src/service/cms_api_import_imp.e +++ b/src/service/cms_api_import_imp.e @@ -203,6 +203,10 @@ feature -- Import if attached json_string_8_item (j, "email") as l_email then Result.set_email (l_email) end + if attached json_string_8_item (j, "profile_name") as l_profile_name then + Result.set_profile_name (l_profile_name) + end + if attached {JSON_ARRAY} j.item ("roles") as j_roles then create l_roles.make (j_roles.count) across diff --git a/src/service/cms_module.e b/src/service/cms_module.e index 7ae684d..02ffa35 100644 --- a/src/service/cms_module.e +++ b/src/service/cms_module.e @@ -92,10 +92,24 @@ feature {CMS_API} -- Access: API feature {CMS_API} -- Module management + installed_version (api: CMS_API): detachable READABLE_STRING_32 + require + is_installed (api) + do + Result := api.storage.custom_value ("is_installed", "module-" + name) + end + is_installed (api: CMS_API): BOOLEAN -- Is Current module installed? + local + v: detachable READABLE_STRING_32 do - if attached api.storage.custom_value ("is_initialized", "module-" + name) as v then + v := api.storage.custom_value ("is_installed", "module-" + name) + if v = Void then + -- Kept for backward compabilitiy + v := api.storage.custom_value ("is_initialized", "module-" + name) + end + if v /= Void then if v.is_case_insensitive_equal_general (version) then Result := True elseif v.is_case_insensitive_equal_general ("yes") then @@ -112,18 +126,58 @@ feature {CMS_API} -- Module management end end + is_enabled_in_storage (api: CMS_API): BOOLEAN + -- Is Current module installed? + local + v: detachable READABLE_STRING_32 + do + v := api.storage.custom_value ("is_enabled", "module-" + name) + if v /= Void then + if v.is_case_insensitive_equal_general (version) then + Result := True + elseif v.is_case_insensitive_equal_general ("yes") then + -- Backward compatibility. + Result := True + elseif v.is_case_insensitive_equal_general ("no") then + -- Probably a module that was installed, but now uninstalled. + Result := False + else + -- Maybe a different version is installed. + -- For now, let's assume this is installed. + Result := True + end + end + end + + update_status_in_storage (a_is_enabled: BOOLEAN; api: CMS_API) + -- Is Current module installed? + do + if a_is_enabled then + api.storage.set_custom_value ("is_enabled", version, "module-" + name) + enable + else + api.storage.unset_custom_value ("is_enabled", "module-" + name) + disable + end + end + install (api: CMS_API) require is_not_installed: not is_installed (api) do - api.storage.set_custom_value ("is_initialized", version, "module-" + name) + api.storage.set_custom_value ("is_installed", version, "module-" + name) + if is_enabled then + api.storage.set_custom_value ("is_enabled", version, "module-" + name) + else + api.storage.unset_custom_value ("is_enabled", "module-" + name) + end end uninstall (api: CMS_API) require is_installed: is_installed (api) do - api.storage.set_custom_value ("is_initialized", "no", "module-" + name) + api.storage.set_custom_value ("is_installed", "no", "module-" + name) end feature -- Router @@ -195,6 +249,6 @@ invariant version_set: not version.is_whitespace note - copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/src/service/cms_module_collection.e b/src/service/cms_module_collection.e index 1eea613..97b2b5f 100644 --- a/src/service/cms_module_collection.e +++ b/src/service/cms_module_collection.e @@ -48,8 +48,6 @@ feature -- Access Result := Void end end - ensure - Result /= Void implies (Result.is_enabled) end item_by_name (a_name: READABLE_STRING_GENERAL): detachable CMS_MODULE @@ -129,6 +127,6 @@ feature {NONE} -- Implementation -- List of available modules. ;note - copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/src/service/content/cms_content_type_webform_manager.e b/src/service/content/cms_content_type_webform_manager.e index 8b578f8..6fabd24 100644 --- a/src/service/content/cms_content_type_webform_manager.e +++ b/src/service/content/cms_content_type_webform_manager.e @@ -32,7 +32,7 @@ feature -- Access feature -- Conversion - append_content_as_html_to (a_content: G; is_teaser: BOOLEAN; a_output: STRING; a_response: detachable CMS_RESPONSE) + append_content_as_html_to (a_content: G; is_teaser: BOOLEAN; a_output: STRING; a_response: CMS_RESPONSE) -- Append `a_content' as html to `a_output', and adapt output according to `is_teaser' (full output, or teaser). -- In the context of optional `a_response'. deferred @@ -49,6 +49,6 @@ feature -- Conversion end note - copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/src/service/handler/cms_admin_install_handler.e b/src/service/handler/cms_admin_install_handler.e index c60e47b..c878f96 100644 --- a/src/service/handler/cms_admin_install_handler.e +++ b/src/service/handler/cms_admin_install_handler.e @@ -91,9 +91,11 @@ feature -- HTTP Methods if api.is_module_installed (l_module) then s.append (" was successfully installed.") - else + elseif l_module.is_enabled then s.append (" could not be installed!") s.append (" [ERROR]") + else + s.append (" is not enabled!") end s.append ("
  • %N") end @@ -105,6 +107,6 @@ feature -- HTTP Methods end note - copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/src/service/response/cms_response.e b/src/service/response/cms_response.e index b8759ef..1e68dd5 100644 --- a/src/service/response/cms_response.e +++ b/src/service/response/cms_response.e @@ -1127,7 +1127,8 @@ feature -- Generation add_to_primary_menu (lnk) api.hooks.invoke_menu_system_alter (menu_system, Current) - if api.enabled_modules.count = 0 then + if api.enabled_modules.count = 1 then + -- It is the required CMS_CORE_MODULE! add_to_primary_menu (create {CMS_LOCAL_LINK}.make ("Install", "admin/install")) end @@ -1261,6 +1262,7 @@ feature -- Generation page.register_variable (request.is_https, "is_https") if attached user as l_user then page.register_variable (l_user.name, "user") + page.register_variable (user_profile_name (l_user), "user_profile_name") end if attached title as l_title then page.register_variable (l_title, "site_title") @@ -1373,17 +1375,28 @@ feature -- Helpers: cms link if a_opt_title /= Void then create Result.make (a_opt_title, user_url (u)) else - create Result.make (u.name, user_url (u)) + create Result.make (user_profile_name (u), user_url (u)) end end -feature -- Helpers: html links +feature -- Helpers: html links + + user_profile_name (u: CMS_USER): READABLE_STRING_32 + do + if attached u.profile_name as pn and then not pn.is_whitespace then + Result := pn + elseif not u.name.is_whitespace then + Result := u.name + else + Result := {STRING_32} "user #" + u.id.out + end + end user_html_link (u: CMS_USER): STRING require u_with_name: not u.name.is_whitespace do - Result := link (u.name, "user/" + u.id.out, Void) + Result := link (user_profile_name (u), "user/" + u.id.out, Void) end feature -- Helpers: URLs diff --git a/tpl/site/scripts/core.sql b/tpl/site/scripts/core.sql deleted file mode 100644 index 5b5d0fe..0000000 --- a/tpl/site/scripts/core.sql +++ /dev/null @@ -1,23 +0,0 @@ -CREATE TABLE `logs`( - `id` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, - `category` VARCHAR(255) NOT NULL, - `level` INTEGER NOT NULL, - `uid` INTEGER, - `message` TEXT NOT NULL, - `info` TEXT, - `link` TEXT, - `date` DATETIME NOT NULL -); - -CREATE TABLE `custom_values`( - `type` VARCHAR(255) NOT NULL, - `name` VARCHAR(255) NOT NULL, - `value` TEXT -); - -CREATE TABLE `path_aliases`( - `pid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, - `source` VARCHAR(255) NOT NULL, - `alias` VARCHAR(255) NOT NULL, - `lang` VARCHAR(12) -);