Compare commits

...

124 Commits

Author SHA1 Message Date
18e159ad3c Simplified the add child mechanism, by using a query parameter ?parent=nid
(instead of specific node/{nid}/add_child/page url)
Fixed implementation of `CMS_NODE_API.is_node_a_parent_of (..)',
  and improved parent validity checking against cycle.
2015-09-09 23:04:08 +02:00
438259033a Renamed link "Trash" to "Move to trash". 2015-09-09 22:10:13 +02:00
62e74ea6cd Refactor notion of trash and delete.
- Trash a node now does a soft delete (move to trash container).
 - Delete a node now remove it from the storage (no undo).

Signed-off-by: jvelilla <javier.hector@gmail.com>
2015-09-09 22:05:23 +02:00
32a409b7e9 Refactored add child feature, to have all the page specific code in CMS_PAGE_NODE_TYPE_WEBFORM_MANAGER (and not in the general node code).
Note that ideally PAGE could be a separated page node module (as it is for blog).
Added listing of children for each "page".
2015-09-09 21:58:16 +02:00
jvelilla
eb70af6f19 CMS_NODE_API.available_parents_for_node
- Fixed comment.
     - added check to know if there are potencial cycles
     - added postcondition to ensure the list of potencial parent will not produce a cycle.

CMS_PAGE_NODE_TYPE_WEBFORM_MANAGER.update_node
     - Updated code to handle unassing parent from a node when the user
     - submit a -1 value.

NODE_FORM_RESPONSE.edit_form_validation
      - Added validation for node_parent, check if the input is valid and then
      - if exist a valid node in the list of available parents for the current node.

Signed-off-by: jvelilla <javier.hector@gmail.com>
2015-09-09 16:53:37 +02:00
5f4eb2cf10 Correct implementation of node extension save operation. 2015-09-08 20:44:00 +02:00
88bc52fffb Updated roc script, install module for the examples, and updated demo site folder. 2015-09-08 16:03:36 +02:00
jvelilla
544e6540ed Add child page support.
- Add support to create a new node as a child of an existing node.
   - Update or add a parent for a given node.
Fix delete and trash behavior: when a node is not published only the
   - author or admin see it.

Fix Node and Page node Revisions.
2015-09-08 15:57:17 +02:00
2431d7af6c Improved the recent changes modules:
- extracted from populate_recent_changes, the recent_changes_sources that enables to filter early.
Added author_name to the CMS_RECENT_CHANGE_ITEM to support author which is not related to any CMS_USER.
Implemented the simple filtering on source and add parameters size and date.
2015-09-03 14:47:17 +02:00
jvelilla
0d55bd67a2 Updated Basic Auth Module: remove the escaping from the logout message 2015-09-01 12:56:26 -03:00
jvelilla
e1727cc445 Merge branch 'jvelilla-roc_logout' 2015-09-01 11:50:37 -03:00
jvelilla
634a078282 Updated Loging form:
Display invalid credentials message inside the primary-tabs div.
Added support to submit the form using <Enter>.
2015-09-01 11:41:50 -03:00
jvelilla
2f65a084ac Updated logout message. Change message and added a div to make it easier style the site 2015-09-01 11:15:25 -03:00
jvelilla
13df6fd593 Added Logout message 2015-09-01 10:55:28 -03:00
ad4f020d0e The NULL storage may look into the CMS configuration file.
This allows to run the CMS without any database.
2015-08-21 19:16:31 +02:00
7a13b47131 Fixed cms library compilation.
CMS_FILE_BLOCK was missing `is_empty' implementation.
2015-08-19 12:34:35 +02:00
923089baa1 Better js code to apply CKEditor.replace, mainly to select only textarea.name=$name.
code cleaning.
2015-08-18 19:24:18 +02:00
cfec9dc7f8 Do not include empty blocks, this way, we avoid empty sidebars if not needed. 2015-08-18 10:58:31 +02:00
b5e7d5d201 Require "view recent changes" permission to see the recent changes. 2015-08-17 17:40:55 +02:00
e1bdcb965c Added permission arguments to "trash" and "Create" links.
Added blocks configuration settings via the cms.ini and "blocks" section
   ex: [blocks]
       navigation.region=sidebar_first
   This enables the site to change default block location, and even hides it easily, if the theme does not include associated region name.
2015-08-13 00:44:16 +02:00
0061afcbe8 use "deleted" instead of "trashed" . 2015-08-12 19:03:40 +02:00
6a9bc8aa42 Updated admin and recent_changes module permissions declaration. 2015-08-12 19:00:17 +02:00
1d7d79d69e Cleaned up hooks related code, and always go via CMS_RESPONSE.hooks 2015-08-12 17:50:23 +02:00
46014da3d8 Added recent_changes module.
Revisited hooks management, and added new CMS_HOOK_MANAGER.
Added admin, and other link into navigation menu that goes into first sidebar.
Fixed theme info, and template for sidebar ids.
Better css class name for cms node content.
2015-08-12 17:30:07 +02:00
7cb4c0e9f4 Quick fix for ROC CMS links in authentication email templates. 2015-08-10 12:55:10 +02:00
aff6b07c80 Fixing edit node form field title and id. 2015-08-10 12:49:40 +02:00
479194d6c5 Updated node module sql script file to support revisions. 2015-08-10 11:21:04 +02:00
3f123dd921 Cosmetic/comments. 2015-08-10 10:04:08 +02:00
cd0c2acd87 Added revisions support to node management.
Updated node extension implementation.
Updated known permissions for node module.
Improved code for node storage extension , in preparation to code factorization.
Ensured that author is updated when saved.
2015-08-07 19:17:25 +02:00
44ada4b6b1 Fixed demo module. 2015-08-07 19:13:01 +02:00
8efbddc8cb Removed unused local variables. 2015-08-06 11:52:47 +02:00
f26b81977c Implemented CMS_LINK.is_forbidden in all descendants. 2015-08-06 11:52:35 +02:00
bbf7456fa2 Improve permissions list display, to be sorted.
Better permission names for "admin users" and "admin roles".
2015-08-04 16:42:06 +02:00
62ef07c86b Removed unwanted files. 2015-08-04 15:22:11 +02:00
a422dea15d Improved message after successful role creation.
Removed useless code.
2015-08-04 14:56:55 +02:00
6fb7bf9a1d Updated location of http_authorization library (now under library\web\authentication\..) 2015-08-04 13:27:09 +02:00
bba1d57ce3 Fixed and improved various issue in admin module (especially the Role editing which was not working as expected.)
Added CMS_MODULE.permissions to allow module to declare the potential permissions.
Added support for CMS_LINK.is_forbidden, in relation with CMS_LOCAL_LINK.permission_arguments.
Split link "username (Logout)" into 2 links "username" and "logout".
Fixed/Changed the way auth modules alter the logout link based on "(Logout)" title, by safer solution based on `location' of the link.

Fixed usage of WSF_REQUEST.path_info by using percent_encoded_path_info which is not non unicode path info to be used most of the time.
Merged CMS_REPONSE.variables and CMS_REPONSE.values .
When possible, prefer usage of CMS_RESPONSE.user instead of CMS_REQUEST_UTIL.current_user (WSF_REQUEST) whenever it is possible.
When possible, prefer usage of CMS_RESPONSE.location, rather than usage of WSF_REQUEST.(percent_encoded_)path_info .
Code cleaning.
2015-08-04 12:48:14 +02:00
c271f839e2 Merge remote-tracking branch 'jvelilla/roc_admin' into ewf_v1 2015-08-03 14:05:03 +02:00
5d81f1d195 Improve previous commit to show allowed tabs only if user has access to it. 2015-08-03 12:56:05 +02:00
jvelilla
63f3ec12d0 Fixed issue with CMS_USER_STORAGE_SQL_I.save_user_role 2015-07-31 11:58:36 -03:00
jvelilla
863a1e7b98 Show tabs iff a user is authenticated 2015-07-30 17:36:14 -03:00
jvelilla
0fe9018ce9 Updated Admin Module, show Admin in the navigation
iff the current user is administrator.
2015-07-30 12:59:10 -03:00
jvelilla
1ef4025caa Update user storage,
Clean code
2015-07-30 11:06:03 -03:00
jvelilla
3ebffad3d6 Updated cms admin 2015-07-29 19:31:18 -03:00
500f8f78a4 Fixed implementation of CMS_USER_STORAGE_SQL_I.update_user_roles 2015-07-16 20:22:20 +02:00
47573a1950 Added permissions "$action any node" , "$action own node" for now. 2015-07-16 20:03:07 +02:00
jvelilla
2d5f985037 Merge branch 'ewf_v1' of https://github.com/EiffelWebFramework/ROC into ewf_v1 2015-07-16 13:03:18 -03:00
jvelilla
eff3552ea1 Updated block new password using Request instead of Require. 2015-07-16 13:01:53 -03:00
43b8c52d34 Merge remote-tracking branch 'ewf/ewf_v1' into ewf_v1 2015-07-16 17:18:58 +02:00
d8ac46f8b0 Added CMS_NODE.is_published and is_trashed: BOOLEAN
For now, whenever we save a node, it is marked as published.
Display a node only if published.
Updated /trash page.
Updated /nodes/ page to take into account the node status.
2015-07-16 17:16:35 +02:00
jvelilla
91f1a87b83 Added HTML5 validations.
Add required to input title.
        Added pattern to path alias with the following regex ^([A-Za-z0-9-_+ ]).+
2015-07-16 11:38:38 -03:00
769c14caf8 Display the OAuth association only in "account" page.
Improved the template to show only when pertinent.
2015-07-16 15:49:14 +02:00
3c0122d98f Fixed validation of node path alias field, for node creation.
Now,when installation a module, store the version (instead of just "yes")
2015-07-16 15:23:56 +02:00
jvelilla
77487e90f3 Added account block to link and unlink with Oauth
Updated CMS_OAUTH_20_MODULE, to handle account_info, block
2015-07-15 13:22:19 -03:00
jvelilla
5d498c0bf2 Merge branch 'ewf_v1' of https://github.com/EiffelWebFramework/ROC into ewf_v1 2015-07-15 12:25:34 -03:00
jvelilla
e42a7636ae Updated Account Info
Add Link and Unlink account with OAuth.
2015-07-15 12:24:56 -03:00
f55a52e4d0 Added CMS_USER_API.save_user_role (a_user_role) 2015-07-14 19:52:39 +02:00
2040a746dd Cleaned auth module by removing useless code.
Added CMS_USER_API.user_role_by_name (a_name: READABLE_STRING_GENERAL): detachable CMS_USER_ROLE
Added enabled/disabled status in admin/install.
2015-07-14 18:59:09 +02:00
jvelilla
d4fc9f9411 Updated account info, using a to link users to login form.
Removed unneeded file.
2015-07-14 13:08:43 -03:00
jvelilla
bba504df53 Updated Account info:
If user is not logged in, show a login option.
Updated New Password
    Added option to request a new password using username.
Updated templates to use {$site_url}
2015-07-14 10:58:16 -03:00
5688cffcf1 Fixed wrong error report for path alias validation. 2015-07-14 12:47:59 +02:00
19e8607e54 Removed unused local variable
Use new location for http_authorization library.
Added error_handler in CMS_MODULE_API (and thus all modules).
Better error handling in CMS_USER_API.
2015-07-14 12:20:43 +02:00
2d77bf6de8 Fixed change_password block template. 2015-07-13 18:48:06 +02:00
2d985ba05e Merge remote-tracking branch 'jvelilla/roc_account' into ewf_v1 2015-07-13 18:43:07 +02:00
1b0cc9dc07 Moved initialization from CMS_DEFAULT_SETUP to CMS_SETUP.initialize.
Rely on setup  "admin.installation_access" to determine who has access to /admin/install .
2015-07-13 18:42:16 +02:00
jvelilla
0164c6ec6d Updated Account Info based on review.
Updated Account info with change password form.
2015-07-13 10:25:18 -03:00
jvelilla
2fe2a7f864 Merge branch 'ewf_v1' of https://github.com/EiffelWebFramework/ROC into roc_account 2015-07-13 08:54:50 -03:00
3dec559d58 Process modules installation only for /admin/install request.
This makes installation process safer, and controlled.
2015-07-11 15:39:59 +02:00
jvelilla
dce3f71be9 Added account info, shows basic user info, logout based on login strategy.
Clean block_login.
2015-07-10 15:41:39 -03:00
3ea9e36e7c Updated comments. 2015-07-10 19:08:29 +02:00
5da01fd576 Fixed issue with CMS_USER_STORAGE_SQL_I.update_user which was passing useless parameters. 2015-07-10 18:57:56 +02:00
7f4a7b3ab9 Implemented Module enable/disable setting from configuration.
Implemented dependencies checking to set CMS_MODULE.is_enabled.
Implemented the persistence of CMS_USER.roles
2015-07-10 18:46:16 +02:00
779064a505 In SQL statement use the same case for table names, i.e all lowercase.
Otherwise on Linux+MySQL queries may fail.
2015-07-10 12:58:05 +02:00
5477bab83c Added error handler argument in CMS_STORAGE_BUILDER.storage (...) function.
Removed testing purpose code.
Update debug module.
2015-07-10 12:20:28 +02:00
d24f124e42 Fixed typo in renamed features. 2015-07-09 21:31:09 +02:00
bace9657b4 Search module configuration first in site/config/modules/$module_name/ folder to see if default is overriden,
and then in site/modules/$module_name/config/ folder.
2015-07-09 21:29:35 +02:00
6319d46f26 Added back CMS_FORMATS.filtered_html 2015-07-09 13:47:22 +02:00
31095b1b66 Merged formats, from CMS_NODE_API and CMS_API, into CMS_API.formats: CMS_FORMATS. 2015-07-09 13:41:42 +02:00
16cae0047d Revisited the format, filter and content type integration.
Now, all formats used by CMS are instances of CMS_FORMAT, mainly to prepare the admin section in order to define format by config/database.
CMS_NODE_API provides all queries to access the content types, and formats, this way a module can easily alter the formats by adding a new filter.

TODO: see how to integrate permission checking, to control who can use a specific format (such as full HTML).
2015-07-09 12:23:20 +02:00
85cff0b139 Better implementation of CMS_API.source_of_path_alias (a_alias).
That now returns the path, only if the alias exists, otherwise returns Void.
Improved path alias validation.
2015-07-07 17:40:12 +02:00
cc94c59eed Added CMS_USER.utf_8_name: STRING_8 for convenience.
Added a permission check for registering (TODO: by default allow visitor to register).
Cosmetic.
2015-07-07 17:25:56 +02:00
4c8af3ef66 Fixed implementation of path alias settings.
Now report an error if path is already aliased to another location.
2015-07-07 17:20:25 +02:00
37729f648a Merge remote-tracking branch 'ewf/ewf_v1' into ewf_v1 2015-07-03 19:35:43 +02:00
26dc018893 Added CMS_API.new_email (..): CMS_EMAIL to help CMS_EMAIL creation. 2015-07-03 19:32:49 +02:00
jvelilla
f0eff2cb98 Updated basic_auth issue with Javascript. 2015-07-03 09:28:19 -03:00
011a6b7804 Updated auto register hook with new {CMS_HOOK_RESPONSE_ALTER} 2015-07-03 09:37:40 +02:00
83e7f95425 Fixed location of .ecf file related to ROC CMS. 2015-07-03 09:33:41 +02:00
jvelilla
4f7acc5dbd Updated Javascript roc_basic_auth 2015-07-02 17:19:14 -03:00
jvelilla
922fca80ad Merge branch 'jvelilla-roc_v1_option1' into ewf_v1 2015-07-02 15:10:17 -03:00
jvelilla
9d465b3d7e Updated basic auth module, rename classes to use the prefix CMS_
Updated code based on comments
2015-07-02 14:49:33 -03:00
jvelilla
5288fe4d3c Move generic code for activation, password, reset password, re-activation to
auth module.
Updated Basic Auth module to handle specific content.
2015-07-02 12:56:10 -03:00
jvelilla
9722347736 Fixed issue with roc_auth.js 2015-07-02 10:49:58 -03:00
jvelilla
a2598fff92 Updated clean CMS_AUTHENTICATION_MODULE
Updated basic_auth module to handle templates
All the auth modules depends on CMS_AUTHENTICATION_MODULE
Send mail is done using features from CMS_AUTHENTICATION_MODULE.
Update redirect in roc_auth.js after success login to home.
2015-07-02 10:29:42 -03:00
42e7763528 Added url routing for /files/... and /module/{modname}/files/...
Added CMS_HOOK_RESPONSE_ALTER to give a last chance to alter the response before rendering.
   This hook should not be used, when there are other alternative hook that answer the need, but this is proposed for now, as a way to alter response by adding css, js url, ...
Moved blog under official modules folder.
Cleaned theme of demo example project.
Renamed NODE_MODULE as CMS_NODE_MODULE.
2015-07-01 22:50:19 +02:00
jvelilla
02fe3ba829 Merge branch 'jvelilla-roc_v1_mailer' into ewf_v1 2015-06-30 19:28:08 -03:00
jvelilla
fe3274e29a Remove unnecessary features from email service parameters for OAuth and OpenID s 2015-06-30 19:09:39 -03:00
jvelilla
96bae9f8fb Fixed typos 2015-06-30 18:52:44 -03:00
jvelilla
1cef32a1fb Updated callback url 2015-06-30 18:11:56 -03:00
jvelilla
f1e8e1da58 Updated code based on review 2015-06-30 18:06:25 -03:00
jvelilla
26276dad5d Added OpenId Module.
Better way to present handle authentication strategies in the view using tabs.
2015-06-30 16:54:09 -03:00
eb9ac980e6 Added integration configuration file all-safe.ecf
Fixed various compilation error
2015-06-30 18:18:01 +02:00
28ab4786a1 Provided a CMS_EMAIL, and CMS_API.process_email (CMS_EMAIL) 2015-06-30 16:11:49 +02:00
8294a47f17 Added usage of notification_email library.
Added CMS_SETUP.mailer
Updated implementation of email_service to use notification_email library
2015-06-30 15:53:02 +02:00
e45dac84c8 Removing unused local variables.
Fixed .ecf location for cms related libraries.
2015-06-29 18:42:11 +02:00
bb3e3b992f Merge branch 'ewf_v1_roctool' into ewf_v1 2015-06-29 17:30:39 +02:00
ebc5924c01 Made CMS_MODULE.name deferred, and implemented by constant so that it can be use as static call.
Copied site resources on related module source folder.
Renamed "login" module as "auth" module, and updated related locations and files.
2015-06-29 16:24:17 +02:00
48b0ad5195 Merge remote-tracking branch 'jvelilla/roc_tool' into ewf_v1_roctool 2015-06-26 11:25:12 +02:00
ae9eea99dd Integrate Authentication modules.
Updated code for sql that should not use parameters
   to expand :table_name in table name usage,
   since Eiffel Store will use quote,
   and MySQL does not like them.

Merge remote-tracking branch 'jvelilla/roc_auth_v1' into ewf_v1_mod_env

Conflicts:
	examples/demo/demo-safe.ecf
	modules/auth/cms_authentication_module.e
2015-06-25 23:20:51 +02:00
jvelilla
268f53e53f Fixed UUID for Oauth20 module. 2015-06-25 15:22:31 -03:00
jvelilla
e17fc570a1 Updated Demo with the new OAuth20 module
Added basic example to extend CMS Authentication using Smarty templates.
2015-06-25 13:20:04 -03:00
ba7ef17d34 Adapted to new layout, with module files inside site/modules/$module_name/... 2015-06-25 17:55:09 +02:00
jvelilla
c8bbac664b Initial commit, added new module oauth20. 2015-06-25 10:07:06 -03:00
04e98dbb48 Merge remote-tracking branch 'ewf/ewf_v1' into ewf_v1 2015-06-24 18:51:33 +02:00
2886c90782 Moved all location related queries into CMS_API, instead of CMS_SETUP.
Note that CMS_SETUP provides locations set by default or from configuration file.
Now theme related resources can be found under site/modules/$mod_name/... or site/themes/$theme/modules/...
  so only theme related resources can be overriden for now.
2015-06-24 17:15:05 +02:00
jvelilla
db6799d55b Merge branch 'jvelilla-roc_ewf_v1_email' into ewf_v1 2015-06-24 11:21:52 -03:00
jvelilla
7c0032ada4 Updated CMS:
Extract email service as a library.
Updated modules to use the email library.
Fixed compilation issue with database_connection_null.e
2015-06-24 11:17:17 -03:00
jvelilla
fa5efede2c Merge branch 'jocelyn-roc_auth_20150619' into ewf_v1 2015-06-23 15:30:01 -03:00
0fca03a4d1 Improved Authentication module code.
Updated to match recent changes from cypress the OAuth Eiffel library.
2015-06-22 21:47:06 +02:00
642b901856 Make sure CMS_BLOCK knows about page variables values.
For now only for smarty template blocks.
2015-06-19 22:48:20 +02:00
4f3bcf290f Fixing issue with index. 2015-06-19 17:58:09 +02:00
6ca8a9ce82 Fixed parts of SQL statements handling (mostly for SQL script execution). 2015-06-19 17:42:02 +02:00
2c72fe6738 Renamed login module as auth (authentication) module 2015-06-19 11:48:42 +02:00
149de898c0 Updated location for cypress the OAuth Eiffel lib.
prepare login module renaming to auth module.
2015-06-19 11:44:41 +02:00
jvelilla
a94a8857ae Initial Import ROC tool 2015-06-17 20:45:28 -03:00
270 changed files with 11862 additions and 10286 deletions

View File

@@ -12,15 +12,17 @@
</option>
<mapping old_name="CMS_LAYOUT" new_name="CMS_ENVIRONMENT"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension-safe.ecf"/>
<library name="cms_app_env" location=".\library\app_env\app_env-safe.ecf"/>
<library name="cms_model" location=".\library\model\cms_model-safe.ecf" readonly="false"/>
<library name="config" location=".\library\configuration\config-safe.ecf"/>
<library name="cms_config" location=".\library\configuration\config-safe.ecf"/>
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf"/>
<library name="encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder-safe.ecf" readonly="false"/>
<library name="error" location="$ISE_LIBRARY\contrib\library\utility\general\error\error-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="i18n" location="$ISE_LIBRARY\library\i18n\i18n-safe.ecf"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
<library name="notification_mailer" location="$ISE_LIBRARY\contrib\library\runtime\process\notification_email\notification_email-safe.ecf"/>
<library name="smarty" location="$ISE_LIBRARY\contrib\library\text\template\smarty\smarty-safe.ecf" readonly="false"/>
<library name="text_filter" location="$ISE_LIBRARY\unstable\library\text\text_filter\text_filter-safe.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>

View File

@@ -13,15 +13,17 @@
</option>
<mapping old_name="CMS_LAYOUT" new_name="CMS_ENVIRONMENT"/>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension.ecf"/>
<library name="cms_app_env" location=".\library\app_env\app_env.ecf"/>
<library name="cms_model" location=".\library\model\cms_model.ecf" readonly="false"/>
<library name="config" location=".\library\configuration\config.ecf"/>
<library name="cms_config" location=".\library\configuration\config.ecf"/>
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto.ecf"/>
<library name="encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder.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="i18n" location="$ISE_LIBRARY\library\i18n\i18n.ecf"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json.ecf" readonly="false"/>
<library name="notification_mailer" location="$ISE_LIBRARY\contrib\library\runtime\process\notification_email\notification_email.ecf"/>
<library name="smarty" location="$ISE_LIBRARY\contrib\library\text\template\smarty\smarty.ecf" readonly="false"/>
<library name="text_filter" location="$ISE_LIBRARY\unstable\library\text\text_filter\text_filter.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>

View File

@@ -1,81 +1,88 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="demo" uuid="3643E657-BCBE-46AA-931B-71EAEA877A18" library_target="demo">
<description>Example/demo for Eiffel ROC CMS library</description>
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option debug="true" warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="transitional">
<debug name="dbglog" enabled="true"/>
</option>
<setting name="concurrency" value="thread"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="cms" location="..\..\cms-safe.ecf" readonly="false"/>
<library name="cms_app_env" location="..\..\library\app_env\app_env-safe.ecf" readonly="false"/>
<library name="cms_basic_auth_module" location="..\..\modules\basic_auth\basic_auth-safe.ecf" readonly="false"/>
<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_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/>
<library name="cms_login_module" location="..\..\modules\login\login-safe.ecf" readonly="false"/>
<library name="cms_node_module" location="..\..\modules\node\node-safe.ecf" readonly="false"/>
<library name="persistence_store_mysql" location="..\..\library\persistence\store_mysql\store_mysql-safe.ecf" readonly="false"/>
<library name="persistence_store_odbc" location="..\..\library\persistence\store_odbc\store_odbc-safe.ecf" readonly="false"/>
<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"/>
</target>
<target name="demo_any" extends="common">
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
<setting name="concurrency" value="thread"/>
<library name="cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\cgi-safe.ecf"/>
<library name="libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\libfcgi-safe.ecf"/>
<library name="nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\nino-safe.ecf"/>
<library name="standalone" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\standalone-safe.ecf"/>
<cluster name="launcher" location=".\launcher\any\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<target name="demo_standalone" extends="common">
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
<option debug="true">
<debug name="dbglog" enabled="true"/>
</option>
<variable name="httpd_ssl_disabled" value="true"/><!-- for now ... due to issue with libcurl+eiffelnet ssl -->
<setting name="concurrency" value="thread"/>
<library name="default_standalone" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\standalone-safe.ecf"/>
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<target name="demo_standalone_none" extends="demo_standalone">
<setting name="concurrency" value="none"/>
</target>
<target name="demo_standalone_mt" extends="demo_standalone">
<setting name="concurrency" value="thread"/>
</target>
<target name="demo_standalone_scoop" extends="demo_standalone">
<setting name="concurrency" value="scoop"/>
</target>
<target name="demo_nino" extends="common">
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
<setting name="concurrency" value="none"/>
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<target name="demo_cgi" extends="common">
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
<setting name="concurrency" value="none"/>
<library name="default_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<target name="demo_libfcgi" extends="common">
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
<setting name="concurrency" value="none"/>
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<target name="demo" extends="demo_standalone">
</target>
<description>Example/demo for Eiffel ROC CMS library</description>
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option debug="true" warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="transitional">
<debug name="dbglog" enabled="true"/>
</option>
<setting name="concurrency" value="thread"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="cms" location="..\..\cms-safe.ecf" readonly="false"/>
<library name="cms_app_env" location="..\..\library\app_env\app_env-safe.ecf" readonly="false"/>
<library name="cms_auth_module" location="..\..\modules\auth\auth-safe.ecf" readonly="false"/>
<library name="cms_basic_auth_module" location="..\..\modules\basic_auth\basic_auth-safe.ecf" readonly="false"/>
<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_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"/>
<library name="cms_openid_module" location="..\..\modules\openid\openid-safe.ecf" readonly="false"/>
<library name="cms_admin_module" location="..\..\modules\admin\admin-safe.ecf" readonly="false"/>
<library name="cms_recent_changes_module" location="..\..\modules\recent_changes\recent_changes-safe.ecf" readonly="false"/>
<library name="persistence_store_odbc" location="..\..\library\persistence\store_odbc\store_odbc-safe.ecf" readonly="false"/>
<!--
<library name="persistence_store_mysql" location="..\..\library\persistence\store_mysql\store_mysql-safe.ecf" readonly="false"/>
-->
<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"/>
</target>
<target name="demo_any" extends="common">
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
<setting name="concurrency" value="thread"/>
<library name="cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\cgi-safe.ecf"/>
<library name="libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\libfcgi-safe.ecf"/>
<library name="nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\nino-safe.ecf"/>
<library name="standalone" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\standalone-safe.ecf"/>
<cluster name="launcher" location=".\launcher\any\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<target name="demo_standalone" extends="common">
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
<option debug="true">
<debug name="dbglog" enabled="true"/>
</option>
<setting name="concurrency" value="thread"/>
<variable name="httpd_ssl_disabled" value="true"/>
<library name="default_standalone" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\standalone-safe.ecf"/>
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<target name="demo_standalone_none" extends="demo_standalone">
<setting name="concurrency" value="none"/>
</target>
<target name="demo_standalone_mt" extends="demo_standalone">
<setting name="concurrency" value="thread"/>
</target>
<target name="demo_standalone_scoop" extends="demo_standalone">
<setting name="concurrency" value="scoop"/>
</target>
<target name="demo_nino" extends="common">
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
<setting name="concurrency" value="none"/>
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<target name="demo_cgi" extends="common">
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
<setting name="concurrency" value="none"/>
<library name="default_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<target name="demo_libfcgi" extends="common">
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
<setting name="concurrency" value="none"/>
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<target name="demo" extends="demo_standalone">
</target>
</system>

View File

@@ -0,0 +1,12 @@
setlocal
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\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%

View File

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

View File

@@ -12,7 +12,6 @@ inherit
redefine
register_hooks,
initialize,
is_installed,
install
end
@@ -27,12 +26,15 @@ feature {NONE} -- Initialization
make
do
name := "Demo module"
version := "1.0"
description := "Service to demonstrate and test cms system"
package := "demo"
end
feature -- Access
name: STRING = "demo"
feature {CMS_API} -- Module Initialization
initialize (api: CMS_API)
@@ -49,12 +51,6 @@ feature {CMS_API} -- Module Initialization
feature {CMS_API} -- Module management
is_installed (api: CMS_API): BOOLEAN
-- Is Current module installed?
do
Result := attached api.storage.custom_value ("is_initialized", "module-" + name) as v and then v.is_case_insensitive_equal_general ("yes")
end
install (api: CMS_API)
local
sql: STRING
@@ -69,12 +65,12 @@ CREATE TABLE tb_demo(
`value` TEXT
);
]"
l_sql_storage.sql_execute_script (sql)
l_sql_storage.sql_execute_script (sql, Void)
if l_sql_storage.has_error then
api.logger.put_error ("Could not initialize database for demo module", generating_type)
end
end
api.storage.set_custom_value ("is_initialized", "module-" + name, "yes")
Precursor {CMS_MODULE}(api)
end
end
@@ -83,16 +79,16 @@ feature -- Access: router
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
-- <Precursor>
do
map_uri_template_agent (a_router, "/demo/", agent handle_demo (?,?,a_api))
map_uri_template_agent (a_router, "/demo/{id}", agent handle_demo_entry (?,?,a_api))
map_uri_template_agent (a_router, "/demo/", agent handle_demo (?,?,a_api), Void)
map_uri_template_agent (a_router, "/demo/{id}", agent handle_demo_entry (?,?,a_api), Void)
end
feature -- Hooks
register_hooks (a_response: CMS_RESPONSE)
do
a_response.subscribe_to_menu_system_alter_hook (Current)
a_response.subscribe_to_block_hook (Current)
a_response.hooks.subscribe_to_menu_system_alter_hook (Current)
a_response.hooks.subscribe_to_block_hook (Current)
end
block_list: ITERABLE [like {CMS_BLOCK}.name]
@@ -137,49 +133,31 @@ feature -- Handler
r: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE
do
create r.make (req, res, a_api)
r.set_main_content ("DEMO module does not yet implement %"" + req.path_info + "%" ...")
r.set_main_content ("DEMO module does not yet implement %"" + req.percent_encoded_path_info + "%" ...")
r.add_error_message ("DEMO Module: not yet implemented")
r.execute
end
feature -- Mapping helper: uri template
map_uri_template (a_router: WSF_ROUTER; a_tpl: STRING; h: WSF_URI_TEMPLATE_HANDLER)
-- Map `h' as handler for `a_tpl'
require
a_tpl_attached: a_tpl /= Void
h_attached: h /= Void
do
map_uri_template_with_request_methods (a_router, a_tpl, h, Void)
end
map_uri_template_with_request_methods (a_router: WSF_ROUTER; a_tpl: READABLE_STRING_8; h: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS)
map_uri_template (a_router: WSF_ROUTER; a_tpl: READABLE_STRING_8; h: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS)
-- Map `h' as handler for `a_tpl' for request methods `rqst_methods'.
require
a_tpl_attached: a_tpl /= Void
h_attached: h /= Void
do
a_router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods)
a_router.map (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods)
end
feature -- Mapping helper: uri template agent
map_uri_template_agent (a_router: WSF_ROUTER; a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]])
-- Map `proc' as handler for `a_tpl'
require
a_tpl_attached: a_tpl /= Void
proc_attached: proc /= Void
do
map_uri_template_agent_with_request_methods (a_router, a_tpl, proc, Void)
end
map_uri_template_agent_with_request_methods (a_router: WSF_ROUTER; a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS)
map_uri_template_agent (a_router: WSF_ROUTER; a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS)
-- Map `proc' as handler for `a_tpl' for request methods `rqst_methods'.
require
a_tpl_attached: a_tpl /= Void
proc_attached: proc /= Void
do
map_uri_template_with_request_methods (a_router, a_tpl, create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (proc), rqst_methods)
map_uri_template (a_router, a_tpl, create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (proc), rqst_methods)
end
end

View File

@@ -1,11 +1,39 @@
[layout]
root-dir=site/www
themes-dir=site/themes
#themes-dir=site/themes
#modules-dir=site/modules
[site]
name=Eiffel CMS
email=your@email.com
theme=bootstrap
[misc]
smtp=localhost
[mailer]
smtp=localhost:25
#sendmail=/usr/bin/sendmail
#output=@stderr
[modules]
# Module status
# *=on -> modules are enabled by default
# *=off -> modules are disabled by default
# Default is "on"
# for each module, this can be overwritten with
# module_name= on or off
*=off
admin=on
auth=on
basic_auth=on
blog=on
debug=on
demo=on
node=on
oauth20=on
openid=on
[blocks]
#navigation.region=sidebar_first
[admin]
# CMS Installation, are accessible by "all", "none" or uppon "permission". (default is none)
installation_access=permission

View File

@@ -1,7 +0,0 @@
{
"api_secret":"ADD_YOUR_SECRET_KEY",
"api_key":"ADD_YOUR_PUBLIC_KEY",
"scope": "email",
"api_revoke":"https://accounts.google.com/o/oauth2/revoke?token=$ACCESS_TOKEN",
"protected_resource_url":"https://www.googleapis.com/plus/v1/people/me"
}

View File

@@ -0,0 +1,34 @@
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] "; }
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] "; }
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] "; }
/*# sourceMappingURL=admin.css.map */

View File

@@ -0,0 +1,59 @@
ul.cms-users {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
li{
border-top: dotted 1px #ccc;
&:first-child {
border-top: none;
}
}
li.cms_user a::before {
content: "[users] ";
}
}
ul.cms-roles {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
li{
border-top: dotted 1px #ccc;
&:first-child {
border-top: none;
}
}
li.cms_role a::before {
content: "[roles] ";
}
}
ul.cms-permissions {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
li{
border-top: dotted 1px #ccc;
&:first-child {
border-top: none;
}
}
li.cms_permission a::before {
content: "[permission] ";
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -0,0 +1,67 @@
<div class="primary-tabs">
{if isset="$user"}
<h3>Account Information</h3>
<div>
<div>
<div>
<label>Username:</label> {$user.name/}
</div>
<div>
<label>Email:</label> {$user.email/}
</div>
<div>
<label>Creation Date:</label> {$user.creation_date/}
</div>
<div>
<label>Last login:</label> {$user.last_login_date/}
</div>
<div>
<form method="get" action="{$site_url/}{$auth_login_strategy/}">
<button type="submit">Logout</button>
</form>
</div>
</div>
</div>
<hr>
{include file="block_change_password.tpl" /}
<hr>
<h4>Roles</h4>
<div>
{foreach item="ic" from="$roles"}
<div>
<ul>
<li>
<strong>{$ic.name/}</strong>
<ul>
<li> <i>permissions</i>
<ul>
{foreach item="ip" from="$ic.permissions"}
<li>{$ip/}</li>
{/foreach}
</ul>
</li>
</ul>
</li>
</ul>
</div>
{/foreach}
</div>
<hr>
<h4>Profile</h4>
<div>
{foreach item="the_value" key="the_name" from="$user.profile"}
<div>
<label>{$the_name/}:</label> {$the_value/}
</div>
{/foreach}
</div>
{/if}
{unless isset="$user"}
<div>
<p> You are not logged in </p>
<a href="{$site_url/}account/roc-login">Go to the login page</a>
</div>
{/unless}
</div>

View File

@@ -0,0 +1,21 @@
<div>
<form action="{$site_url/}account/change-password" method="post">
<fieldset>
<legend>Change Password Form</legend>
<div>
<input type="password" id="password" name="password" value="" required/>
<label for="password">Password</label>
</div>
<div>
<input type="password" id="confirm_password" name="confirm_password" value="" required/>
<label for="password">Confirm Password</label>
</div>
<button type="submit">Confirm</button>
{if isset="$error_password"}
<span><i>{$error_password/}</i></span> <br>
{/if}
</fieldset>
</form>
</div>

View File

@@ -1,6 +1,6 @@
<div class="primary-tabs">
{unless isset="$user"}
<h3>Login or <a href="/account/roc-register">Register</a></h3>
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3>
<div>
<div>
<form action method="POST">
@@ -21,14 +21,9 @@
<div>
<div>
<p>
<a href="/account/new-password">Forgot password?</a>
<a href="{$site_url/}account/new-password">Forgot password?</a>
</p>
</div>
</div>
<div>
{foreach item="item" from="$oauth_consumers"}
<a href="/account/login-with-oauth/{$item/}">Login with {$item/}</a><br>
{/foreach}
</div>
{/unless}
</div>
</div>

View File

@@ -0,0 +1,32 @@
<div>
<form action="{$site_url/}account/new-password" method="post">
<fieldset>
<legend>Request new password by email</legend>
<div>
<input type="email" id="email" name="email" value="{$email/}" required/>
<label for="email">Email</label>
{if isset="$error_email"}
<span><i>{$error_email/}</i></span> <br>
{/if}
<br>
</div>
<button type="submit">Send</button>
</fieldset>
</form>
<hr>
<form action="{$site_url/}account/new-password" method="post">
<fieldset>
<legend>Request new password by username</legend>
<div>
<input type="text" id="username" name="username" value="{$username/}" required/>
<label for="username">Username</label>
{if isset="$error_username"}
<span><i>{$error_username/}</i></span> <br>
{/if}
<br>
</div>
<button type="submit">Send</button>
</fieldset>
</form>
</div>

View File

@@ -0,0 +1,3 @@
<div>
<p>You new password has been saved!, Login again</p>
</div>

View File

@@ -1,5 +1,5 @@
<div>
<form action="/account/reactivate" method="post">
<form action="{$site_url/}account/reactivate" method="post">
<fieldset>
<legend>Reactivate Form</legend>
<div>

View File

@@ -1,5 +1,5 @@
<div>
<form action="/account/roc-register" method="post">
<form action="{$site_url/}account/roc-register" method="post">
<fieldset>
<legend>Register Form</legend>
<div>

View File

@@ -1,5 +1,5 @@
<div>
<form action="/account/reset-password" method="post">
<form action="{$site_url/}account/reset-password" method="post">
<fieldset>
<legend>Generate New Password Form</legend>
<div>

View File

@@ -7,7 +7,7 @@ var userAgent = navigator.userAgent.toLowerCase();
var firstLogIn = true;
ROC_AUTH.login = function() {
var form = document.forms[0];
var form = document.forms['cms_basic_auth'];
var username = form.username.value;
var password = form.password.value;
//var host = form.host.value;
@@ -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{
@@ -39,7 +39,7 @@ ROC_AUTH.login = function() {
if (request.readyState == 4) {
if (request.status==200) {
delete form;
window.location=origin;
window.location=window.location.origin;
}
else{
if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
@@ -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();
}
}
@@ -306,16 +306,20 @@ ROC_AUTH.create_form = function() {
};
var password = document.getElementById("password")
, confirm_password = document.getElementById("confirm_password");
var password = document.getElementById("password");
var confirm_password = document.getElementById("confirm_password");
ROC_AUTH.validatePassword =function(){
if(password.value != confirm_password.value) {
confirm_password.setCustomValidity("Passwords Don't Match");
} else {
confirm_password.setCustomValidity('');
}
if ((password != null) && (confirm_password != null)) {
if(password.value != confirm_password.value) {
confirm_password.setCustomValidity("Passwords Don't Match");
} else {
confirm_password.setCustomValidity('');
}
}
}
password.onchange = ROC_AUTH.validatePassword();
confirm_password.onkeyup = ROC_AUTH.validatePassword;
if ((password != null) && (confirm_password != null)) {
password.onchange = ROC_AUTH.validatePassword();
confirm_password.onkeyup = ROC_AUTH.validatePassword;
}

View File

@@ -0,0 +1,29 @@
<div class="primary-tabs">
{unless isset="$user"}
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3>
<div>
<div>
<form name="cms_basic_auth" action method="POST">
<div>
<input type="text" name="username" id="username" required>
<label>Username</label>
</div>
<div>
<input type="password" name="password" id="password" required>
<label>Password</label>
</div>
<button type="button" onclick="ROC_AUTH.login();">Login</button>
</form>
</div>
</div>
<div>
<div>
<p>
<a href="{$site_url/}account/new-password">Forgot password?</a>
</p>
</div>
</div>
{/unless}
</div>

View File

@@ -0,0 +1,37 @@
CREATE TABLE nodes (
`nid` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT UNIQUE,
`revision` INTEGER,
`type` TEXT NOT NULL,
`title` VARCHAR(255) NOT NULL,
`summary` TEXT,
`content` TEXT,
`format` VARCHAR(128),
`author` INTEGER,
`publish` DATETIME,
`created` DATETIME NOT NULL,
`changed` DATETIME NOT NULL,
`status` INTEGER,
CONSTRAINT Unique_nid_revision UNIQUE (nid,revision)
);
CREATE TABLE node_revisions (
`nid` INTEGER NOT NULL,
`revision` INTEGER NOT NULL,
`title` VARCHAR(255) NOT NULL,
`summary` TEXT,
`content` TEXT,
`format` VARCHAR(128),
`author` INTEGER,
`changed` DATETIME NOT NULL,
`status` INTEGER,
CONSTRAINT Unique_nid_revision PRIMARY KEY (nid,revision)
);
CREATE TABLE page_nodes(
`nid` INTEGER NOT NULL,
`revision` INTEGER NOT NULL,
`parent` INTEGER,
CONSTRAINT PK_nid_revision PRIMARY KEY (nid,revision)
);

View File

@@ -1,5 +1,5 @@
CREATE TABLE `oauth2_consumers`(
CREATE TABLE oauth2_consumers(
`cid` INTEGER PRIMARY KEY NOT NULL CHECK(`cid`>=0),
`name` VARCHAR(255) NOT NULL,
`api_secret` TEXT NOT NULL,

View File

@@ -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');

View File

@@ -1,10 +1,13 @@
CREATE TABLE :table_name (
CREATE TABLE $table_name (
`uid` INTEGER PRIMARY KEY NOT NULL CHECK(`uid`>=0),
`access_token` TEXT NOT NULL,
`created` DATETIME NOT NULL,
`details` TEXT NOT NULL,
`email` TEXT NOT NULL,
CONSTRAINT `uid`
UNIQUE(`uid`)
UNIQUE(`uid`),
CONSTRAINT `email`
UNIQUE(`email`)
);

View File

@@ -0,0 +1,32 @@
<hr>
{unless isempty="$oauth_associated"}
<h4>Un-Associate Account with Oauth Consumer</h4>
<div>
{foreach item="consumer" from="$oauth_associated"}
<div>
<form method="post" action="{$site_url/}account/oauth-un-associate">
<input type="hidden" name="consumer" value="{$consumer/}"/>
<div>
<button type="submit">Unlink {$consumer/}</button>
</div>
</form>
</div>
{/foreach}
</div>
{/unless}
{unless isempty="$oauth_not_associated"}
<h4>Associate Account with Oauth Consumer</h4>
<div>
{foreach item="consumer" from="$oauth_not_associated"}
<div>
<form method="post" action="{$site_url/}account/oauth-associate">
<input type="hidden" name="consumer" value="{$consumer/}"/>
<div>
<input type="email" id="email" name="email" value="{$email/}" required/>
<button type="submit">Link with {$consumer/}</button>
</div>
</form>
</div>
{/foreach}
</div>
{/unless}

View File

@@ -0,0 +1,7 @@
<div class="primary-tabs">
<div>
{foreach item="item" from="$oauth_consumers"}
<a href="{$site_url/}account/login-with-oauth/{$item/}">Login with {$item/}</a><br>
{/foreach}
</div>
</div>

View File

@@ -0,0 +1,11 @@
CREATE TABLE openid_consumers(
`cid` INTEGER PRIMARY KEY NOT NULL CHECK(`cid`>=0),
`name` VARCHAR(255) NOT NULL,
`endpoint` VARCHAR (255) NOT NULL,
CONSTRAINT `cid`
UNIQUE(`cid`),
CONSTRAINT `name`
UNIQUE(`name`)
);

View File

@@ -0,0 +1,4 @@
-- Change the values TO_COMPLETE based on your API.
-- API SECTET KEY AND API PUBLIC KEY
INSERT INTO openid_consumers (name, endpoint)
VALUES ('yahoo', 'https://me.yahoo.com/');

View File

@@ -0,0 +1,11 @@
CREATE TABLE openid_items (
`uid` INTEGER PRIMARY KEY NOT NULL CHECK(`uid`>=0),
`identity` TEXT NOT NULL,
`created` DATETIME NOT NULL,
CONSTRAINT `uid`
UNIQUE(`uid`),
CONSTRAINT `identity`
UNIQUE(`identity`)
);

View File

@@ -0,0 +1,18 @@
<div>
<form action="{$site_url/}account/roc-openid-login" id="openid-login" method="POST">
<div>
<strong><label for="openid">OpenID identifier</label></strong><br/>
<input type="text" name="openid" value="" size="50"/>
</div>
<div><input type="submit" name="op" value="Validate"/></div>
<div hgv vtid="openid">Login with
{foreach item="item" from="$openid_consumers"}
<a href="{$site_url/}account/login-with-openid/{$item/}">{$item/}</a><br>
{/foreach}
</form>
<div>
{if isset="$error"}
<span><i>{$error/}</i></span> <br>
{/if}
</div>
</div>

View File

@@ -1,22 +0,0 @@
CREATE TABLE nodes (
`nid` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT UNIQUE,
`revision` INTEGER,
`type` TEXT NOT NULL,
`title` VARCHAR(255) NOT NULL,
`summary` TEXT,
`content` TEXT,
`format` VARCHAR(128),
`author` INTEGER,
`publish` DATETIME,
`created` DATETIME NOT NULL,
`changed` DATETIME NOT NULL,
`status` INTEGER
);
CREATE TABLE page_nodes(
`nid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL,
`revision` INTEGER,
`parent` INTEGER
);

View File

@@ -1,7 +0,0 @@
-- 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");

View File

@@ -30,19 +30,19 @@ CREATE TABLE `role_permissions`(
`module` VARCHAR(255)
);
CREATE TABLE "users_activations" (
"aid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK ("aid" >= 0),
"token" VARCHAR(255) NOT NULL,
"uid" INTEGER NOT NULL CHECK ("uid" >= 0),
"created" DATETIME NOT NULL,
CONSTRAINT "token" UNIQUE ("token")
CREATE TABLE `users_activations` (
`aid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL CHECK (`aid` >= 0),
`token` VARCHAR(255) NOT NULL,
`uid` INTEGER NOT NULL CHECK (`uid` >= 0),
`created` DATETIME NOT NULL,
CONSTRAINT `token` UNIQUE (`token`)
);
CREATE TABLE "users_password_recovery" (
"aid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK ("aid" >= 0),
"token" VARCHAR(255) NOT NULL,
"uid" INTEGER NOT NULL CHECK ("uid" >= 0),
"created" DATETIME NOT NULL,
CONSTRAINT "token" UNIQUE ("token")
CREATE TABLE `users_password_recovery` (
`aid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL CHECK (`aid` >= 0),
`token` VARCHAR(255) NOT NULL,
`uid` INTEGER NOT NULL CHECK (`uid` >= 0),
`created` DATETIME NOT NULL,
CONSTRAINT `token` UNIQUE (`token`)
);

View File

@@ -51,16 +51,24 @@ ul.horizontal li {
.sidebar {
padding: 5px;
margin: 3px;
border: solid 1px #ccc;
/* border: solid 1px #ccc; */
}
.sidebar#sidebar_first {
width: 250px;
float: left;
position: fixed;
top: 45px;
left: 0;
bottom: 0;
width: 200px;
border-right: solid 1px #ddd;
}
.sidebar#sidebar_second {
width: 250px;
float: right;
}
.sidebar + .main {
margin-left: 200px;
}
#primary-tabs ul.horizontal {
list-style-type: none;
@@ -76,3 +84,9 @@ ul.horizontal li {
border-width: 2px 1px 0;
padding: 2px 7px 1px;
}
#message li.error {
background-color: #f99;
border: solid 1px red;
padding: 5px 2px 5px 2px;
}

File diff suppressed because one or more lines are too long

View File

@@ -55,15 +55,24 @@ ul.horizontal {
.sidebar {
padding: 5px;
margin: 3px;
border: solid 1px #ccc;
/* border: solid 1px #ccc; */
&#sidebar_first {
width: 250px;
float: left;
position: fixed;
top: 45px;
left: 0;
bottom: 0;
width: 200px;
border-right: solid 1px #ddd;
}
&#sidebar_second {
width: 250px;
float: right;
}
&+.main {
margin-left: 200px;
}
}
#primary-tabs {
ul.horizontal {
@@ -81,3 +90,8 @@ ul.horizontal {
}
}
}
#message li.error {
background-color: #f99;
border: solid 1px red;
padding: 5px 2px 5px 2px;
}

View File

@@ -1,7 +0,0 @@
<div class='navbar navbar-inverse'>
<div class='navbar-inner nav-collapse' style="height: auto;">
<ul class="nav">
{$header_block/}
</ul>
</div>
</div>

View File

@@ -5,13 +5,14 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- EWF CMS -->
<link rel="stylesheet" href="{$site_url/}theme/css/style.css">
<link rel="stylesheet" href="{$site_url/}theme/css/node.css">
<!-- CMS Blog Module -->
<link rel="stylesheet" href="{$site_url/}theme/css/blog.css">
<!-- jQuery dep -->
<script src="{$site_url/}theme/js/jquery-1.10.2.min.js"></script>
<script src="{$site_url/}theme/js/roc_auth.js"></script>
{if isset="$head"}{$head/}{/if}
{if isset="$styles"}{$styles/}{/if}
{if isset="$scripts"}{$scripts/}{/if}
{if isset="$head_lines"}{$head_lines/}{/if}
<!-- bootstrap framework -->
<!-- Latest compiled and minified CSS -->
@@ -48,7 +49,7 @@
{/unless}
<!-- Highlighted, Help, Content -->
<div class='span8 main'>
<div id='main' class='span8 main'>
<!-- Highlighted Section -->
{unless isempty="$page.region_highlighted"}
<div id="highlighted">{$page.region_highlighted/}</div>

View File

@@ -8,7 +8,7 @@ regions[content] = Content
regions[highlighted] = Highlighted
regions[help] = Help
regions[footer] = Footer
regions[first_sidebar] = first sidebar
regions[second_sidebar] = second sidebar
regions[sidebar_first] = first sidebar
regions[sidebar_second] = second sidebar
regions[page_bottom] = Bottom
navigation=default_nav
navigation=default_nav

View File

@@ -1 +0,0 @@
<h2>Help Section</h2>

View File

@@ -1 +0,0 @@
<h1>Highlighted Section</h1>

View File

@@ -1,8 +0,0 @@
<div class='span2 sidebar'>
<h3>Left Sidebar</h3>
<ul class="nav nav-tabs nav-stacked">
<li><a href='#'>Another Link 1</a></li>
<li><a href='#'>Another Link 2</a></li>
<li><a href='#'>Another Link 3</a></li>
</ul>
</div>

View File

@@ -1,4 +0,0 @@
<h2>Main Content Section</h2>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum.<p>
<p>Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.</p>

View File

@@ -1,9 +0,0 @@
<div id="footer">
<small>
<center>
<p class="text-muted"><a href="#" target="_blank" class="info">ROC Documentation </a>&nbsp;&nbsp;&nbsp;
<a href="http://www.eiffel.com/company/contact/" target="_blank" class="info">Questions? Comments? Let us know! </a></p>
<p>© Copyright 2014 Eiffel Software -- <a href="#" target="_blank" class="info">Privacy Policy</a>
</center>
</small>
</div>

View File

@@ -1,34 +0,0 @@
<div class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
</button>
<a class="navbar-brand" href="{$site_url/}" itemprop="home" rel="home">{unless isset="$site_name"}Eiffel CMS{/unless}{if isset="$site_name"}{$site_name/}{/if}</a>
</div>
<div class="navbar-collapse collapse">
{if isset="$primary_nav"}
<ul class="nav navbar-nav navbar-left">
{foreach item="item" from="$primary_nav.items"}
<!-- TODO check if a menu item is active or not -->
<li class="active"><a href="{$item.location/}">{$item.title/}</a></li>
{/foreach}
</ul>
{/if}
{if isset="$secondary_nav"}
<ul class="nav navbar-nav navbar-right">
{foreach item="item" from="$secondary_nav.items"}
<!-- TODO check if a menu item is active or not -->
<li class="active"><a href="{$item.location/}">{$item.title/}</a></li>
{/foreach}
</ul>
{/if}
</div>
</div>
</div>

View File

@@ -1,28 +0,0 @@
{if isset="$default_nav"}
<div class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
</button>
<a class="navbar-brand" href="${site_url/}" itemprop="home" rel="home">{$page_title/}</a>
</div>
<div class="navbar-collapse collapse">
{/if}
{if isset="$primary_nav"}
{$primary_nav/}
{/if}
{if isset="$secondary_nav"}
{$secondary_nav/}
{/if}
{if isset="$default_nav"}
</div>
</div>
</div>
{/if}

View File

@@ -1,6 +0,0 @@
<ul class="nav navbar-nav navbar-left">
{foreach item="item" from="$menu.items"}
<!-- TODO check if a menu item is active or not -->
<li class="active"><a href="{$item.location/}">{$item.title/}</a></li>
{/foreach}
</ul>

View File

@@ -1,8 +0,0 @@
<div class='span2 sidebar'>
<h3>Right Sidebar</h3>
<ul class="nav nav-tabs nav-stacked">
<li><a href='#'>Another Link 1</a></li>
<li><a href='#'>Another Link 2</a></li>
<li><a href='#'>Another Link 3</a></li>
</ul>
</div>

View File

@@ -1,7 +0,0 @@
<ul class="nav navbar-nav navbar-right">
{foreach item="item" from="$menu.items"}
<!-- TODO check if a menu item is active or not -->
<li class="active"><a href="{$item.location/}">{$item.title/}</a></li>
{/foreach}
</ul>

File diff suppressed because it is too large Load Diff

View File

@@ -1,357 +0,0 @@
/*
* Base structure
*/
/* Move down content because we have a fixed navbar that is 36px tall on small screen */
body {
padding-top: 40px;
}
/* On large screen, we give it more space and the navbar is 30px tall. */
@media (min-width: 768px) {
body {
padding-top: 45px;
}
}
/*
* Global add-ons
*/
h1 {
margin-top: initial;
margin-bottom: 5px;
}
h2.sub-header{
margin-top: 1px;
margin-bottom: 1px;
border-bottom: 1px solid #eee;
}
.container .jumbotron {
padding: 10px;
text-align: center;
}
/*
* Sidebar
*/
/* Hide for mobile, show later */
.sidebar {
display: none;
}
@media (min-width: 768px) {
.sidebar {
position: fixed;
top: 0;
left: 0;
bottom: 0;
z-index: 1000;
display: block;
padding: 70px 20px 20px;
background-color: #f5f5f5;
border-right: 1px solid #eee;
}
}
/* Sidebar navigation */
.nav-sidebar {
margin-left: -20px;
margin-right: -21px; /* 20px padding + 1px border */
margin-bottom: 20px;
}
.nav-sidebar > li > a {
padding-left: 20px;
padding-right: 20px;
}
.nav-sidebar > .active > a {
color: #fff;
background-color: #428bca;
}
/*
* Main content
*/
.main {
padding: 3px;
}
@media (min-width: 768px) {
.main {
padding-left: 15px;
padding-right: 15px;
}
}
.main .page-header {
margin-top: 0;
}
/*
* Placeholder dashboard ideas
*/
.placeholders {
margin-bottom: 30px;
text-align: center;
}
.placeholders h4 {
margin-bottom: 0;
}
.placeholder {
margin-bottom: 20px;
}
.placeholder img {
border-radius: 50%;
}
.navbar-default {
background-color:#194573;
border-color: #400040;
}
.navbar-default .navbar-brand {
color: #ffffff;
}
.navbar-default .navbar-brand:hover, .navbar-default .navbar-brand:focus {
color: #ffffff;
}
.navbar-default .navbar-text {
color: #ffffff;
}
.navbar-default .navbar-nav > li > a {
color: #ffffff;
}
.navbar-default .navbar-nav > li > a:hover, .navbar-default .navbar-nav > li > a:focus {
color: #ffffff;
}
.navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus {
color: #ffffff;
background-color: #400040;
}
.navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:hover, .navbar-default .navbar-nav > .open > a:focus {
color: #ffffff;
background-color: #400040;
}
.navbar-default .navbar-toggle {
border-color: #400040;
}
.navbar-default .navbar-toggle:hover, .navbar-default .navbar-toggle:focus {
background-color: #400040;
}
.navbar-default .navbar-toggle .icon-bar {
background-color: #ffffff;
}
.navbar-default .navbar-collapse,
.navbar-default .navbar-form {
border-color: #ffffff;
}
.navbar-default .navbar-link {
color: #ffffff;
}
.navbar-default .navbar-link:hover {
color: #ffffff;
}
@media (max-width: 767px) {
.navbar-default .navbar-nav .open .dropdown-menu > li > a {
color: #ffffff;
}
.navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
color: #ffffff;
}
.navbar-default .navbar-nav .open .dropdown-menu > .active > a, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
color: #ffffff;
background-color: #400040;
}
}
.navbar-nav > li > a {padding-top:5px !important; padding-bottom:5px !important;}
.navbar {min-height:30px !important}
.navbar-brand {
float: left;
padding: 15px;
padding-top: 5px;
padding-right: 15px;
padding-bottom: 5px;
padding-left: 15px;
font-size: 18px;
line-height: 18px;
height: 30px;
}
/* Tooltips */
.blue-tooltip + .tooltip > .tooltip-inner {background-color: #FF;}
.blue-tooltip + .tooltip > .tooltip-arrow { border-bottom-color:#FF; }
.tooltip.top .tooltip-arrow {
bottom: 0;
left: 50%;
margin-left: -5px;
border-top-color: #000000;
border-width: 5px 5px 0;
}
.tooltip-inner {
text-align: left;
color: #000;
background: #fff;
border: solid 1px #000000;
max-width: 450px
}
.tooltip.bottom .tooltip-arrow {
top: 0;
left: 50%;
margin-left: -5px;
border-bottom-color: #000000;
border-width: 0 5px 5px;
}
/* pre */
pre {
word-wrap: code;
white-space: pre-wrap;
background-color:white;
}
/* Container -Fluid */
.container-fluid {
padding: 0 2px;
}
@media (min-width: 768px) {
.container-fluid {
padding: 0 5px;
}
}
.container-fluid .row {
margin: 0px;
}
.row-padding {
margin-top: 25px;
margin-bottom: 25px;
}
/* Width for the text field to enter a bug report number in the reports page.
* We put a maximum width to override the width value coming from `form-control'. */
.form-bug-number-entry {
max-width: 100px;
}
/* Default width for the entries in a table like layout. */
.form-inline .form-control {
width: 95%;
}
.form-inline .checkbox {
font-weight: initial;
vertical-align: top;
}
/* Note that there is also a class called label. */
label {
padding-right: 5px;
}
.label {
padding: 0px;
padding-right: 5px;
}
.label-primary-api-default {
display: inline-block;
width: 105px;
text-align: left;
background: #fff;
color: #000;
font-size: 100%;
text-align: right;
}
.label-primary-api-interactions {
display: inline-block;
padding-right: 5px;
text-align: left;
color: #000;
font-size: 100%;
}
pre {
padding: 1.5px;
display: block;
margin: 0 0 10px;
font-size: 12px;
font-family: monospace;
line-height: 1.428571429;
word-break: break-word;
word-wrap: break-word;
color: #333;
border: 0px;
border-radius: 4px;
}
/* No padding, so that nested columns are always properly aligned. */
.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12 {
padding-left: 0px;
padding-right: 0px;
}
.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td {
padding:2px;
vertical-align: middle;
}
.form-control{
height:inherit;
padding: 1px 2px;
margin: 1px;
}
.btn {
padding: 1px 12px;
margin: 1px;
min-width: 100px;
}
.dropdown-toggle, .login {
cursor: pointer;
}
.pager {
margin:10px 0;
}
.pager li>a,.pager li>span {
padding:1px 12px;
border-radius:8px;
}
.well {
padding: 9px;
margin-bottom: 10px;
min-height: 44px;
}
.panel-heading {
background-color: #ddeaf2 !important;
}
.private-panel-border {
border: solid 1px #DBA458 !important;
}
.private-panel {
background-color: #f2eadd !important;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -1,108 +0,0 @@
/*
* EWF CMS javascript based on JQuery
*/
/**
* Override jQuery.fn.init to guard against XSS attacks.
*
* See http://bugs.jquery.com/ticket/9521
*/
(function () {
var jquery_init = jQuery.fn.init;
jQuery.fn.init = function (selector, context, rootjQuery) {
// If the string contains a "#" before a "<", treat it as invalid HTML.
if (selector && typeof selector === 'string') {
var hash_position = selector.indexOf('#');
if (hash_position >= 0) {
var bracket_position = selector.indexOf('<');
if (bracket_position > hash_position) {
throw 'Syntax error, unrecognized expression: ' + selector;
}
}
}
return jquery_init.call(this, selector, context, rootjQuery);
};
jQuery.fn.init.prototype = jquery_init.prototype;
})();
var ROC = ROC || { };
$('body').on('click',"a[rel='node']",function(e){
e.preventDefault();
/*
if uncomment the above line, html5 nonsupported browers won't change the url but will display the ajax content;
if commented, html5 nonsupported browers will reload the page to the specified link.
*/
//get the link location that was clicked
pageurl = $(this).attr('href');
spinner = "<span class='loading'><h3>Loading content..</h3><img src='/static/images/ajax-loader.gif' alt='loading...' class='spinner'></span>";
//to get the ajax content and display in div with class 'main'
$.ajax({url:pageurl+'?rel=node',success: function(data){
$('.main').html(data);
}});
//to change the browser URL to the given link location
//if(pageurl!=window.location){
//window.history.pushState({path:pageurl},'',pageurl);
//}
//stop refreshing to the page given in
return false;
});
$('body').on('click',"a[rel='register']",function(e){
e.preventDefault();
/*
if uncomment the above line, html5 nonsupported browers won't change the url but will display the ajax content;
if commented, html5 nonsupported browers will reload the page to the specified link.
*/
//get the link location that was clicked
pageurl = $(this).attr('href');
spinner = "<span class='loading'><h3>Loading content..</h3><img src='/static/images/ajax-loader.gif' alt='loading...' class='spinner'></span>";
//to get the ajax content and display in div with class 'main'
$.ajax({url:pageurl+'?rel=node',success: function(data){
$('.main').html(data);
}});
//to change the browser URL to the given link location
//if(pageurl!=window.location){
//window.history.pushState({path:pageurl},'',pageurl);
//}
//stop refreshing to the page given in
return false;
});
$("a[rel='node']").click(function(e){
e.preventDefault();
/*
if uncomment the above line, html5 nonsupported browers won't change the url but will display the ajax content;
if commented, html5 nonsupported browers will reload the page to the specified link.
*/
//get the link location that was clicked
pageurl = $(this).attr('href');
spinner = "<span class='loading'><h3>Loading content..</h3><img src='/static/images/ajax-loader.gif' alt='loading...' class='spinner'></span>";
//to get the ajax content and display in div with class 'main'
$.ajax({url:pageurl+'?rel=node',success: function(data){
$('.main').html(data);
}});
//to change the browser URL to the given link location
//if(pageurl!=window.location){
//window.history.pushState({path:pageurl},'',pageurl);
//}
//stop refreshing to the page given in
return false;
});

View File

@@ -55,30 +55,39 @@ feature -- CMS setup
local
m: CMS_MODULE
do
create {NODE_MODULE} m.make (a_setup)
m.enable
create {CMS_ADMIN_MODULE} m.make
a_setup.register_module (m)
-- Auth
create {CMS_AUTHENTICATION_MODULE} m.make
m.enable
a_setup.register_module (m)
create {BASIC_AUTH_MODULE} m.make
if not a_setup.module_with_same_type_registered (m) then
m.enable
a_setup.register_module (m)
end
create {CMS_DEBUG_MODULE} m.make
m.enable
create {CMS_BASIC_AUTH_MODULE} m.make
a_setup.register_module (m)
create {CMS_DEMO_MODULE} m.make
m.enable
create {CMS_OAUTH_20_MODULE} m.make
a_setup.register_module (m)
create {CMS_OPENID_MODULE} m.make
a_setup.register_module (m)
-- Nodes
create {CMS_NODE_MODULE} m.make (a_setup)
a_setup.register_module (m)
create {CMS_BLOG_MODULE} m.make
m.enable
a_setup.register_module (m)
-- Recent changes
create {CMS_RECENT_CHANGES_MODULE} m.make
a_setup.register_module (m)
-- Miscellanious
create {CMS_DEBUG_MODULE} m.make
a_setup.register_module (m)
create {CMS_DEMO_MODULE} m.make
a_setup.register_module (m)
end

View File

@@ -109,7 +109,7 @@ feature -- Access: internal
do
p := internal_application_config_path
if p = Void then
p := config_path.extended ("application_configuration.json")
p := config_path.extended (name + ".json")
internal_application_config_path := p
end
Result := p

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="config_tests" uuid="AD1DE0F7-BC8A-4A17-9A44-56C917BD5604">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="config_tests" library_target="config_tests" uuid="AD1DE0F7-BC8A-4A17-9A44-56C917BD5604">
<target name="config_tests">
<root class="TEST_CONFIG_READER_SET" feature="default_create"/>
<file_rule>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="email_service" uuid="261DC9D5-C3A0-498D-A063-0BB6C80423CC" library_target="email_service">
<target name="email_service">
<root all_classes="true"/>
<file_rule>
<exclude>/.git$</exclude>
<exclude>/EIFGENs$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="cms_app_env" location="..\app_env\app_env-safe.ecf"/>
<library name="notification_mailer" location="$ISE_LIBRARY\contrib\library\runtime\process\notification_email\notification_email-safe.ecf"/>
<cluster name="src" location=".\" recursive="true"/>
</target>
</system>

View File

@@ -7,8 +7,8 @@ class
EMAIL_SERVICE
inherit
SHARED_ERROR
SHARED_LOGGER
create
@@ -26,14 +26,10 @@ feature {NONE} -- Initialization
initialize
-- Initialize service.
local
l_address_factory: INET_ADDRESS_FACTORY
do
admin_email := parameters.admin_email
-- Get local host name needed in creation of SMTP_PROTOCOL.
create l_address_factory
create smtp_protocol.make (parameters.smtp_server, l_address_factory.create_localhost.host_name)
create {NOTIFICATION_SMTP_MAILER} mailer.make (parameters.smtp_server)
set_successful
end
@@ -43,7 +39,7 @@ feature {NONE} -- Initialization
admin_email: IMMUTABLE_STRING_8
-- Site admin's email.
smtp_protocol: SMTP_PROTOCOL
mailer: NOTIFICATION_MAILER
-- SMTP protocol.
feature -- Basic Operations
@@ -60,38 +56,34 @@ feature -- Basic Operations
send_message (a_from_address, a_to_address: READABLE_STRING_8; a_subjet: READABLE_STRING_GENERAL; a_content: READABLE_STRING_GENERAL)
local
l_email: EMAIL
l_email: NOTIFICATION_EMAIL
utf: UTF_CONVERTER
do
write_debug_log (generator + ".send_message: [from:" + a_from_address + ", to:" + a_to_address + ", subject:" + a_subjet + ", content:" + a_content)
create l_email.make_with_entry (a_from_address, a_to_address)
l_email.set_message (utf.escaped_utf_32_string_to_utf_8_string_8 (a_content))
l_email.add_header_entry ({EMAIL_CONSTANTS}.H_subject, utf.escaped_utf_32_string_to_utf_8_string_8 (a_subjet))
l_email.add_header_entry ("MIME-Version:", "1.0")
l_email.add_header_entry ("Content-Type", "text/html; charset=utf-8")
create l_email.make (a_from_address, a_to_address, utf.escaped_utf_32_string_to_utf_8_string_8 (a_subjet) , utf.escaped_utf_32_string_to_utf_8_string_8 (a_content))
l_email.add_header_line ("MIME-Version:1.0")
l_email.add_header_line ("Content-Type: text/html; charset=utf-8")
send_email (l_email)
end
feature {NONE} -- Implementation
send_email (a_email: EMAIL)
send_email (a_email: NOTIFICATION_EMAIL)
-- Send the email represented by `a_email'.
local
l_retried: BOOLEAN
do
if not l_retried then
write_information_log (generator + ".send_email Process send email.")
smtp_protocol.initiate_protocol
smtp_protocol.transfer (a_email)
smtp_protocol.close_protocol
mailer.process_email (a_email)
write_information_log (generator + ".send_email Email sent.")
if smtp_protocol.error then
if mailer.has_error then
set_last_error ("smtp_protocol reported an error", generator + ".send_email")
else
set_successful
end
else
write_error_log (generator + ".send_email Email not send " + last_error_message )
write_error_log (generator + ".send_email Email not send " + last_error_message)
end
rescue
set_last_error_from_exception (generator + ".send_email")

View File

@@ -41,6 +41,11 @@ feature -- Status report
has_children: BOOLEAN = False
-- <Precursor>
feature -- Security
is_forbidden: BOOLEAN = False
-- <Precursor>
feature -- Access
children: detachable LIST [CMS_LINK]
@@ -48,6 +53,6 @@ feature -- Access
invariant
note
copyright: "2011-2014, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
copyright: "2011-2015, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -49,7 +49,7 @@ feature -- Comparison
end
end
feature -- status report
feature -- Status report
is_active: BOOLEAN
-- Is current link active?
@@ -79,6 +79,14 @@ feature -- status report
deferred
end
feature -- Security
is_forbidden: BOOLEAN
-- Is Current link forbidden?
-- Current link could be disabled for current CMS user.
deferred
end
feature -- Element change
set_weight (a_weight: INTEGER)

View File

@@ -71,6 +71,12 @@ feature -- Status report
Result := attached children as l_children and then not l_children.is_empty
end
feature -- Security
is_forbidden: BOOLEAN
-- <Precursor>
-- Related to `permission_arguments' values.
feature -- Element change
set_title (a_title: detachable READABLE_STRING_GENERAL)
@@ -167,6 +173,16 @@ feature -- Status change
is_expandable: is_expandable = b
end
feature -- Security change
set_is_forbidden (b: BOOLEAN)
-- Set `is_forbidden' to `b'.
do
is_forbidden := b
ensure
is_forbidden: is_forbidden = b
end
feature {NONE} -- Implementation
internal_is_expandable: BOOLEAN

View File

@@ -81,6 +81,16 @@ feature -- Access
-- trashed
feature -- Access: helper
utf_8_name: STRING_8
-- UTF-8 version of `name'.
local
utf: UTF_CONVERTER
do
Result := utf.utf_32_string_to_utf_8_string_8 (name)
end
feature -- Roles
roles: detachable LIST [CMS_USER_ROLE]

View File

@@ -23,9 +23,9 @@ feature -- Initialization
-- Create a database handler for ODBC with common settings.
do
create database_error_handler.make
create db_application.login (username, password)
db_application.set_hostname (hostname)
db_application.set_data_source (database_name)
create db_application.login (default_username, default_password)
db_application.set_hostname (default_username)
db_application.set_data_source (default_database_name)
db_application.set_base
create db_control.make
end

View File

@@ -26,7 +26,7 @@ feature {NONE} -- Initialization
feature -- Factory
storage (a_setup: CMS_SETUP): detachable CMS_STORAGE_STORE_MYSQL
storage (a_setup: CMS_SETUP; a_error_handler: ERROR_HANDLER): detachable CMS_STORAGE_STORE_MYSQL
local
conn: DATABASE_CONNECTION
do
@@ -40,6 +40,8 @@ feature -- Factory
initialize (a_setup, Result)
end
end
else
a_error_handler.add_custom_error (0, "Could not connect to the MySQL storage", Void)
end
end
end

View File

@@ -26,7 +26,7 @@ feature {NONE} -- Initialization
feature -- Factory
storage (a_setup: CMS_SETUP): detachable CMS_STORAGE_STORE_ODBC
storage (a_setup: CMS_SETUP; a_error_handler: ERROR_HANDLER): detachable CMS_STORAGE_STORE_ODBC
local
s: detachable STRING
conn: detachable DATABASE_CONNECTION
@@ -53,6 +53,8 @@ feature -- Factory
initialize (a_setup, Result)
end
end
else
a_error_handler.add_custom_error (0, "Could not connect to the ODBC storage", Void)
end
else
-- Wrong mapping between storage name and storage builder!

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="tests" uuid="FE27C81D-3F7D-4E46-992B-55F4BBDA4F8B">
<target name="tests">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="tests_store_odbc" library_target="tests_store_odbc" uuid="FE27C81D-3F7D-4E46-992B-55F4BBDA4F8B">
<target name="tests_store_odbc">
<root class="APPLICATION" feature="make"/>
<option warning="true" void_safety="conformance">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>

3
license.lic Normal file
View File

@@ -0,0 +1,3 @@
${NOTE_KEYWORD}
copyright: "2011-${YEAR}, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -0,0 +1,28 @@
<?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="admin" uuid="7195898D-7ACB-40D1-B85A-EE83E0DC695A" library_target="admin">
<target name="admin">
<root all_classes="true"/>
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="cms" location="..\..\cms-safe.ecf"/>
<library name="cms_app_env" location="..\..\library\app_env\app_env-safe.ecf" readonly="false"/>
<library name="cms_auth_module" location="..\..\modules\auth\auth-safe.ecf" readonly="false"/>
<library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/>
<library name="encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder-safe.ecf"/>
<library name="error" location="$ISE_LIBRARY\contrib\library\utility\general\error\error-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="http_authorization" location="$ISE_LIBRARY\contrib\library\web\authentication\http_authorization\http_authorization-safe.ecf" readonly="false"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
<library name="wsf_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>

View File

@@ -0,0 +1,128 @@
note
description: "CMS module providing Administration support (back-end)."
date: "$Date$"
revision: "$Revision$"
class
CMS_ADMIN_MODULE
inherit
CMS_MODULE
redefine
register_hooks,
permissions
end
CMS_HOOK_MENU_SYSTEM_ALTER
CMS_HOOK_RESPONSE_ALTER
create
make
feature {NONE} -- Initialization
make
-- Create Current module, disabled by default.
do
version := "1.0"
description := "Service to Administrate CMS (users, modules, etc)"
package := "core"
end
feature -- Access
name: STRING = "admin"
feature {CMS_API} -- Module Initialization
feature -- Access: router
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
-- <Precursor>
do
configure_web (a_api, a_router)
end
configure_web (a_api: CMS_API; a_router: WSF_ROUTER)
local
l_admin_handler: CMS_ADMIN_HANDLER
l_users_handler: CMS_ADMIN_USERS_HANDLER
l_roles_handler: CMS_ADMIN_ROLES_HANDLER
l_user_handler: CMS_USER_HANDLER
l_role_handler: CMS_ROLE_HANDLER
l_uri_mapping: WSF_URI_MAPPING
do
create l_admin_handler.make (a_api)
create l_uri_mapping.make_trailing_slash_ignored ("/admin", l_admin_handler)
a_router.map (l_uri_mapping, a_router.methods_get_post)
create l_users_handler.make (a_api)
create l_uri_mapping.make_trailing_slash_ignored ("/admin/users", l_users_handler)
a_router.map (l_uri_mapping, a_router.methods_get_post)
create l_roles_handler.make (a_api)
create l_uri_mapping.make_trailing_slash_ignored ("/admin/roles", l_roles_handler)
a_router.map (l_uri_mapping, a_router.methods_get_post)
create l_user_handler.make (a_api)
a_router.handle ("/admin/add/user", l_user_handler, a_router.methods_get_post)
a_router.handle ("/admin/user/{id}", l_user_handler, a_router.methods_get)
a_router.handle ("/admin/user/{id}/edit", l_user_handler, a_router.methods_get_post)
a_router.handle ("/admin/user/{id}/delete", l_user_handler, a_router.methods_get_post)
create l_role_handler.make (a_api)
a_router.handle ("/admin/add/role", l_role_handler, a_router.methods_get_post)
a_router.handle ("/admin/role/{id}", l_role_handler, a_router.methods_get)
a_router.handle ("/admin/role/{id}/edit", l_role_handler, a_router.methods_get_post)
a_router.handle ("/admin/role/{id}/delete", l_role_handler, a_router.methods_get_post)
end
feature -- Security
permissions: LIST [READABLE_STRING_8]
-- List of permission ids, used by this module, and declared.
do
Result := Precursor
Result.force ("manage admin")
Result.force ("admin users")
Result.force ("admin roles")
Result.force ("admin modules")
Result.force ("install modules")
end
feature -- Hooks
register_hooks (a_response: CMS_RESPONSE)
-- <Precursor>
do
a_response.hooks.subscribe_to_menu_system_alter_hook (Current)
a_response.hooks.subscribe_to_response_alter_hook (Current)
end
response_alter (a_response: CMS_RESPONSE)
-- <Precursor>
do
a_response.add_style (a_response.url ("/module/" + name + "/files/css/admin.css", Void), Void)
end
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
local
lnk: CMS_LOCAL_LINK
do
if
a_response.has_permission ("manage " + {CMS_ADMIN_MODULE}.name) -- Note: admin user has all permissions enabled by default.
then
-- TODO: we should probably use more side menu and less primary_menu.
create lnk.make ("Admin", "admin")
lnk.set_permission_arguments (<<"manage " + {CMS_ADMIN_MODULE}.name>>)
a_menu_system.management_menu.extend (lnk)
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

View File

@@ -0,0 +1,89 @@
note
description: "[
handler for CMS admin in the CMS interface.
TODO: implement REST API.
]"
date: "$Date$"
revision: "$Revision$"
class
CMS_ADMIN_HANDLER
inherit
CMS_HANDLER
WSF_URI_HANDLER
rename
execute as uri_execute,
new_mapping as new_uri_mapping
end
WSF_URI_TEMPLATE_HANDLER
rename
execute as uri_template_execute,
new_mapping as new_uri_template_mapping
select
new_uri_template_mapping
end
WSF_RESOURCE_HANDLER_HELPER
redefine
do_get,
do_post
end
REFACTORING_HELPER
create
make
feature -- execute
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute (req, res)
end
uri_template_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
do
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
if r.has_permission ("manage " + {CMS_ADMIN_MODULE}.name) then
create {CMS_ADMIN_RESPONSE} r.make (req, res, api)
r.execute
else
r.execute
end
end
do_post (req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
do
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
if r.has_permission ("manage " + {CMS_ADMIN_MODULE}.name) then
create {CMS_ADMIN_RESPONSE} r.make (req, res, api)
r.execute
else
r.execute
end
end
end

View File

@@ -0,0 +1,59 @@
note
description: "Summary description for {CMS_ADMIN_RESPONSE}."
date: "$Date$"
revision: "$Revision$"
class
CMS_ADMIN_RESPONSE
inherit
CMS_RESPONSE
redefine
make,
initialize
end
create
make
feature {NONE} -- Initialization
make (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: like api)
do
create {WSF_NULL_THEME} wsf_theme.make
Precursor (req, res, a_api)
end
initialize
do
Precursor
create {CMS_TO_WSF_THEME} wsf_theme.make (Current, theme)
end
wsf_theme: WSF_THEME
feature -- Process
process
local
b: STRING
do
create b.make_empty
set_title (translation ("Admin Page", Void))
b.append ("<ul id=%"content-types%">")
fixme ("Check how to make it configurable")
if has_permissions (<< "admin users">>) then
b.append ("<li>" + link ("Users", "admin/users", Void))
b.append ("<div class=%"description%">View/Edit/Add Users</div>")
b.append ("</li>")
end
if has_permissions (<< "admin roles">>) then
b.append ("<li>" + link ("Roles", "admin/roles", Void))
b.append ("<div class=%"description%">View/Edit/Add Roles</div>")
b.append ("</li>")
end
b.append ("</ul>")
set_main_content (b)
end
end

View File

@@ -0,0 +1,112 @@
note
description: "Summary description for {CMS_ADMIN_ROLE_HANDLER}."
date: "$Date$"
revision: "$Revision$"
class
CMS_ADMIN_ROLES_HANDLER
inherit
CMS_HANDLER
WSF_URI_HANDLER
rename
execute as uri_execute,
new_mapping as new_uri_mapping
end
WSF_URI_TEMPLATE_HANDLER
rename
execute as uri_template_execute,
new_mapping as new_uri_template_mapping
select
new_uri_template_mapping
end
WSF_RESOURCE_HANDLER_HELPER
redefine
do_get
end
REFACTORING_HELPER
create
make
feature -- execute
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute (req, res)
end
uri_template_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
local
l_response: CMS_RESPONSE
s: STRING
u: CMS_USER_ROLE
l_count: INTEGER
user_api: CMS_USER_API
do
-- At the moment the template are hardcoded, but we can
-- get them from the configuration file and load them into
-- the setup class.
user_api := api.user_api
l_count := user_api.roles_count
create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api)
create s.make_empty
if l_count > 1 then
l_response.set_title ("Listing " + l_count.out + " Roles")
else
l_response.set_title ("Listing " + l_count.out + " Role")
end
if attached user_api.roles as lst then
s.append ("<ul class=%"cms-roles%">%N")
across
lst as ic
loop
u := ic.item
s.append ("<li class=%"cms_role%">")
s.append ("<a href=%"")
s.append (req.absolute_script_url ("/admin/role/" + u.id.out))
s.append ("%">")
s.append (u.name)
s.append ("</a>")
s.append ("</li>%N")
end
s.append ("</ul>%N")
end
if l_response.has_permission ("admin roles") then
s.append (l_response.link ("Add Role", "admin/add/role", Void))
end
l_response.set_main_content (s)
l_response.execute
end
end

View File

@@ -0,0 +1,509 @@
note
description: "Summary description for {CMS_ROLE_FORM_RESPONSE}."
date: "$Date$"
revision: "$Revision$"
class
CMS_ROLE_FORM_RESPONSE
inherit
CMS_RESPONSE
redefine
make,
initialize
end
CMS_SHARED_SORTING_UTILITIES
create
make
feature {NONE} -- Initialization
make (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: like api)
do
create {WSF_NULL_THEME} wsf_theme.make
Precursor (req, res, a_api)
end
initialize
do
Precursor
create {CMS_TO_WSF_THEME} wsf_theme.make (Current, theme)
end
wsf_theme: WSF_THEME
feature -- Query
role_id_path_parameter (req: WSF_REQUEST): INTEGER_64
-- Role id passed as path parameter for request `req'.
local
s: STRING
do
if attached {WSF_STRING} req.path_parameter ("id") as p_nid then
s := p_nid.value
if s.is_integer_64 then
Result := s.to_integer_64
end
end
end
feature -- Process
process
-- Computed response message.
local
b: STRING_8
uid: INTEGER_64
user_api: CMS_USER_API
do
user_api := api.user_api
create b.make_empty
uid := role_id_path_parameter (request)
if uid > 0 and then attached user_api.user_role_by_id (uid.to_integer) as l_role then
fixme ("Issues with WSD_FORM_DATA.apply_to_associated_form")
-- if we have a WSF_FORM_CHECKBOK_INPUT, cheked inputs, are not preserverd in case of error.
if location.ends_with_general ("/edit") then
edit_form (l_role)
elseif location.ends_with_general ("/delete") then
delete_form (l_role)
end
else
new_form
end
end
feature -- Process Edit
edit_form (a_role: CMS_USER_ROLE)
local
f: like new_edit_form
b: STRING
fd: detachable WSF_FORM_DATA
do
create b.make_empty
f := new_edit_form (a_role, url (request.percent_encoded_path_info, Void), "edit-user")
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))
f.process (Current)
fd := f.last_data
end
if a_role.has_id then
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("View", Void), "admin/role/" + a_role.id.out), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), "admin/role/" + a_role.id.out + "/edit"), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Delete", Void), "admin/role/" + a_role.id.out + "/delete"), primary_tabs)
end
if attached redirection as l_location then
-- FIXME: Hack for now
set_title (a_role.name)
b.append (html_encoded (a_role.name) + " saved")
else
set_title (formatted_string (translation ("Edit $1 #$2", Void), [a_role.name, a_role.id]))
f.append_to_html (wsf_theme, b)
end
set_main_content (b)
end
feature -- Process Delete
delete_form (a_role: CMS_USER_ROLE)
local
f: like new_delete_form
b: STRING
fd: detachable WSF_FORM_DATA
do
create b.make_empty
f := new_delete_form (a_role, url (request.percent_encoded_path_info, Void), "edit-user")
hooks.invoke_form_alter (f, fd, Current)
if request.is_post_request_method then
f.process (Current)
fd := f.last_data
end
if a_role.has_id then
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("View", Void), "admin/role/" + a_role.id.out), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), "admin/role/" + a_role.id.out + "/edit"), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Delete", Void), "admin/role/" + a_role.id.out + "/delete"), primary_tabs)
end
if attached redirection as l_location then
-- FIXME: Hack for now
set_title (a_role.name)
b.append (html_encoded (a_role.name) + " deleted")
else
set_title (formatted_string (translation ("Delete $1 #$2", Void), [a_role.name, a_role.id]))
f.append_to_html (wsf_theme, b)
end
set_main_content (b)
end
feature -- Process New
new_form
local
f: like new_edit_form
b: STRING
fd: detachable WSF_FORM_DATA
l_role: detachable CMS_USER_ROLE
do
create b.make_empty
f := new_edit_form (l_role, url (request.percent_encoded_path_info, Void), "create-role")
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))
f.process (Current)
fd := f.last_data
end
if attached redirection as l_location then
-- FIXME: Hack for now
if attached l_role then
set_title (l_role.name)
b.append (html_encoded (l_role.name) + " Saved")
end
else
if attached l_role then
set_title (formatted_string (translation ("Saved $1 #$2", Void), [l_role.name, l_role.id]))
end
f.append_to_html (wsf_theme, b)
end
set_main_content (b)
end
feature -- Form
edit_form_submit (fd: WSF_FORM_DATA; a_role: detachable CMS_USER_ROLE; b: STRING)
local
l_save_role: BOOLEAN
l_update_role: BOOLEAN
do
l_save_role := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Create role")
if l_save_role then
debug ("cms")
across
fd as c
loop
b.append ("<li>" + html_encoded (c.key) + "=")
if attached c.item as v then
b.append (html_encoded (v.string_representation))
end
b.append ("</li>")
end
end
create_role (fd)
else
l_update_role := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Update role")
if l_update_role then
debug ("cms")
across
fd as c
loop
b.append ("<li>" + html_encoded (c.key) + "=")
if attached c.item as v then
b.append (html_encoded (v.string_representation))
end
b.append ("</li>")
end
end
if a_role /= Void then
update_role (fd, a_role)
else
fd.report_error ("Missing Role")
end
end
end
end
edit_form_validate (fd: WSF_FORM_DATA; a_role: CMS_USER_ROLE; b: STRING)
do
if attached fd.string_item ("op") as f_op then
if f_op.is_case_insensitive_equal_general ("Update role") then
if
attached fd.string_item ("role") as l_role and then
not a_role.name.is_case_insensitive_equal (l_role)
then
if attached api.user_api.user_role_by_name (l_role) then
fd.report_invalid_field ("role", "Role already taken!")
end
else
if fd.string_item ("role") = Void then
fd.report_invalid_field ("role", "missing role")
end
end
if attached {WSF_TABLE} fd.item ("new_cms_permissions[]") as l_perm then
a_role.permissions.compare_objects
across
l_perm.values as ic
loop
if attached {WSF_STRING} ic.item as p then
if not p.value.is_valid_as_string_8 then
fd.report_invalid_field ("new_cms_permissions[]", "Permission " + p.value + " should not have any unicode character!")
elseif across a_role.permissions as p_ic some p_ic.item.is_case_insensitive_equal_general (p.value) end then
fd.report_invalid_field ("new_cms_permissions[]", "Permission " + p.value + " already exists!")
end
end
end
end
end
end
end
new_edit_form (a_role: detachable CMS_USER_ROLE; a_url: READABLE_STRING_8; a_name: STRING;): CMS_FORM
-- Create a web form named `a_name' for uSER `a_YSER' (if set), using form action url `a_url'.
local
f: CMS_FORM
th: WSF_FORM_HIDDEN_INPUT
do
create f.make (a_url, a_name)
create th.make ("role-id")
if a_role /= Void then
th.set_text_value (a_role.id.out)
else
th.set_text_value ("0")
end
f.extend (th)
populate_form (f, a_role)
Result := f
end
new_form_validate (fd: WSF_FORM_DATA; b: STRING)
do
if attached fd.string_item ("op") as f_op then
if f_op.is_case_insensitive_equal_general ("Create role") then
if attached fd.string_item ("role") as l_role then
if attached api.user_api.user_role_by_name (l_role) then
fd.report_invalid_field ("role", "Role already taken!")
end
else
fd.report_invalid_field ("role", "missing role")
end
end
end
end
new_delete_form (a_role: detachable CMS_USER_ROLE; a_url: READABLE_STRING_8; a_name: STRING;): CMS_FORM
-- Create a web form named `a_name' for role `a_role' (if set), using form action url `a_url'.
local
f: CMS_FORM
ts: WSF_FORM_SUBMIT_INPUT
do
create f.make (a_url, a_name)
f.extend_html_text ("<br/>")
f.extend_html_text ("<legend>Are you sure you want to delete?</legend>")
-- TODO check if we need to check for has_permissions!!
if a_role /= Void and then a_role.has_id then
create ts.make ("op")
ts.set_default_value ("Delete")
fixme ("[
ts.set_default_value (translation ("Delete"))
]")
f.extend (ts)
create ts.make ("op")
ts.set_default_value ("Cancel")
ts.set_formmethod ("GET")
ts.set_formaction ("/admin/role/" + a_role.id.out)
f.extend (ts)
end
Result := f
end
populate_form (a_form: WSF_FORM; a_role: detachable CMS_USER_ROLE)
-- Fill the web form `a_form' with data from `a_node' if set,
-- and apply this to content type `a_content_type'.
local
ti: WSF_FORM_TEXT_INPUT
-- fe: WSF_FORM_EMAIL_INPUT
fs: WSF_FORM_FIELD_SET
cb: WSF_FORM_CHECKBOX_INPUT
ts: WSF_FORM_SUBMIT_INPUT
-- tb: WSF_FORM_BUTTON_INPUT
lab: WSF_WIDGET_TEXT
l_role_permissions: detachable LIST [READABLE_STRING_8]
l_module_names: ARRAYED_LIST [READABLE_STRING_8]
l_mod_name: READABLE_STRING_8
do
if attached a_role as l_role then
create fs.make
fs.set_legend ("User Role")
create ti.make_with_text ("role", a_role.name)
ti.set_label ("Role")
ti.enable_required
fs.extend (ti)
a_form.extend (fs)
a_form.extend_html_text ("<br/>")
create fs.make
fs.set_legend ("Permissions")
if
attached api.user_api.role_permissions as l_permissions_by_module
then
l_role_permissions := l_role.permissions
l_role_permissions.compare_objects
create l_module_names.make (l_permissions_by_module.count)
across
l_permissions_by_module as mod_ic
loop
l_module_names.force (mod_ic.key)
end
string_sorter.sort (l_module_names)
across
l_module_names as mod_ic
loop
l_mod_name := mod_ic.item
if
attached l_permissions_by_module.item (l_mod_name) as l_permissions and then
not l_permissions.is_empty
then
if l_mod_name.is_whitespace then
l_mod_name := "... "
end
create lab.make_with_text ("<strong>" + l_mod_name + " module</strong>")
fs.extend (lab)
string_sorter.sort (l_permissions)
across l_permissions as ic loop
create cb.make_with_value ("cms_permissions", ic.item)
cb.set_checked (across l_role_permissions as rp_ic some rp_ic.item.is_case_insensitive_equal (ic.item) end)
cb.set_title (ic.item)
fs.extend (cb)
end
end
end
end
create ti.make ("new_cms_permissions[]")
fs.extend (ti)
fs.extend_html_text ("<div class=%"input_fields_wrap%"></div>")
fs.extend_html_text ("<button class=%"add_field_button%">Add More Permissions</button>")
a_form.extend (fs)
add_javascript_content (script_add_remove_items)
create ts.make ("op")
ts.set_default_value ("Update role")
a_form.extend (ts)
a_form.extend_html_text ("<hr>")
else
create fs.make
fs.set_legend ("User Role")
create ti.make ("role")
ti.set_label ("Role")
ti.enable_required
fs.extend (ti)
a_form.extend (fs)
a_form.extend_html_text ("<br/>")
create ts.make ("op")
ts.set_default_value ("Create role")
a_form.extend (ts)
a_form.extend_html_text ("<hr>")
end
end
update_role (a_form_data: WSF_FORM_DATA; a_role: CMS_USER_ROLE)
-- Update node `a_node' with form_data `a_form_data' for the given content type `a_content_type'.
local
l_perm: READABLE_STRING_8
do
if attached a_form_data.string_item ("op") as f_op then
if f_op.is_case_insensitive_equal_general ("Update role") then
if
attached a_form_data.string_item("role") as l_role_name and then
attached a_form_data.string_item ("role-id") as l_role_id
and then attached {CMS_USER_ROLE} api.user_api.user_role_by_id (l_role_id.to_integer) as l_role
then
if attached {WSF_STRING} a_form_data.item ("cms_permissions") as u_role then
a_role.permissions.wipe_out
a_role.add_permission (u_role.value)
elseif attached {WSF_MULTIPLE_STRING} a_form_data.item ("cms_permissions") as u_permissions then
a_role.permissions.wipe_out
-- Enable checked permissions.
across
u_permissions as ic
loop
l_perm := ic.item.value.as_string_8
if not l_perm.is_whitespace then
a_role.add_permission (l_perm)
end
end
else
a_role.permissions.wipe_out
end
if attached {WSF_TABLE} a_form_data.item ("new_cms_permissions[]") as l_cms_perms then
-- Add new permissions as checked.
across
l_cms_perms.values as ic
loop
if attached {WSF_STRING} ic.item as p then
l_perm := p.value.as_string_8
if not l_perm.is_whitespace then
a_role.add_permission (l_perm)
end
end
end
end
if not a_form_data.has_error then
a_role.set_name (l_role_name)
api.user_api.save_user_role (a_role)
if not api.user_api.has_error then
add_success_message ("Permissions updated")
set_redirection (absolute_url ("admin/role/" + a_role.id.out, Void))
else
add_error_message ("Error during permissions update operation.")
end
end
else
a_form_data.report_error ("Missing Role")
end
end
end
end
create_role (a_form_data: WSF_FORM_DATA)
local
u: CMS_USER_ROLE
do
if attached a_form_data.string_item ("op") as f_op then
if f_op.is_case_insensitive_equal_general ("Create role") then
if attached a_form_data.string_item ("role") as l_role then
create u.make (l_role)
api.user_api.save_user_role (u)
if api.user_api.has_error then
-- handle error
else
add_success_message ("Created Role " + link (l_role, "admin/role/" + u.id.out, Void))
set_redirection (absolute_url ("admin/role/" + u.id.out, Void))
end
else
a_form_data.report_invalid_field ("username", "Missing role!")
end
end
end
end
feature -- Generation
script_add_remove_items: STRING = "[
$(document).ready(function() {
var wrapper = $(".input_fields_wrap"); //Fields wrapper
var add_button = $(".add_field_button"); //Add button ID
$(add_button).click(function(e){ //on add input button click
e.preventDefault();
$(wrapper).append('<div><input type="text" name="new_cms_permissions[]"/><a href="#" class="remove_field">Remove</a></div>'); //add input box
});
$(wrapper).on("click",".remove_field", function(e){ //user click on remove text
e.preventDefault(); $(this).parent('div').remove(); x--;
})
});
]"
end

View File

@@ -0,0 +1,203 @@
note
description: "[
Handler for a CMS user in the CMS interface
]"
date: "$Date$"
revision: "$Revision$"
class
CMS_ROLE_HANDLER
inherit
CMS_HANDLER
WSF_URI_HANDLER
rename
execute as uri_execute,
new_mapping as new_uri_mapping
end
WSF_URI_TEMPLATE_HANDLER
rename
execute as uri_template_execute,
new_mapping as new_uri_template_mapping
select
new_uri_template_mapping
end
WSF_RESOURCE_HANDLER_HELPER
redefine
do_get,
do_post,
do_delete
end
REFACTORING_HELPER
create
make
feature -- execute
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute (req, res)
end
uri_template_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute (req, res)
end
feature -- Query
role_id_path_parameter (req: WSF_REQUEST): INTEGER_64
-- User id passed as path parameter for request `req'.
local
s: STRING
do
if attached {WSF_STRING} req.path_parameter ("id") as p_nid then
s := p_nid.value
if s.is_integer_64 then
Result := s.to_integer_64
end
end
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
l_role: detachable CMS_USER_ROLE
l_uid: INTEGER_64
edit_response: CMS_ROLE_FORM_RESPONSE
view_response: CMS_ROLE_VIEW_RESPONSE
r: CMS_RESPONSE
do
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
if r.has_permission ("admin roles") then
if req.percent_encoded_path_info.ends_with_general ("/edit") then
check valid_url: req.percent_encoded_path_info.starts_with_general ("/admin/role/") end
create edit_response.make (req, res, api)
edit_response.execute
elseif req.percent_encoded_path_info.ends_with_general ("/delete") then
check valid_url: req.percent_encoded_path_info.starts_with_general ("/admin/role/") end
create edit_response.make (req, res, api)
edit_response.execute
else
-- Display existing node
l_uid := role_id_path_parameter (req)
if l_uid > 0 then
l_role := api.user_api.user_role_by_id (l_uid.to_integer)
if
l_role /= Void
then
create view_response.make (req, res, api)
view_response.execute
else
send_not_found (req, res)
end
else
create_new_role (req, res)
end
end
else
r.execute
end
end
do_post (req: WSF_REQUEST; res: WSF_RESPONSE)
local
edit_response: CMS_ROLE_FORM_RESPONSE
r: CMS_RESPONSE
do
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
if r.has_permission ("admin roles") then
if req.percent_encoded_path_info.ends_with_general ("/edit") then
create edit_response.make (req, res, api)
edit_response.execute
elseif req.percent_encoded_path_info.ends_with_general ("/delete") then
if
attached {WSF_STRING} req.form_parameter ("op") as l_op and then
l_op.value.same_string ("Delete")
then
do_delete (req, res)
end
elseif req.percent_encoded_path_info.ends_with_general ("/add/role") then
create edit_response.make (req, res, api)
edit_response.execute
end
else
r.execute
end
end
feature -- Error
do_error (req: WSF_REQUEST; res: WSF_RESPONSE; a_id: detachable WSF_STRING)
-- Handling error.
local
l_page: CMS_RESPONSE
do
create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api)
l_page.set_value (req.absolute_script_url (req.percent_encoded_path_info), "request")
if a_id /= Void and then a_id.is_integer then
-- resource not found
l_page.set_value ("404", "code")
l_page.set_status_code (404)
else
-- bad request
l_page.set_value ("400", "code")
l_page.set_status_code (400)
end
l_page.execute
end
do_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
do
if attached current_user (req) as l_user then
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
if
l_id.is_integer and then
attached api.user_api.user_role_by_id (l_id.integer_value) as l_role
then
api.user_api.delete_role (l_role)
res.send (create {CMS_REDIRECTION_RESPONSE_MESSAGE}.make (req.absolute_script_url ("")))
else
do_error (req, res, l_id)
end
else
(create {INTERNAL_SERVER_ERROR_CMS_RESPONSE}.make (req, res, api)).execute
end
else
send_access_denied (req, res)
end
end
feature {NONE} -- New role
create_new_role (req: WSF_REQUEST; res: WSF_RESPONSE)
local
edit_response: CMS_ROLE_FORM_RESPONSE
do
if req.percent_encoded_path_info.starts_with_general ("/admin/add/role") then
create edit_response.make (req, res, api)
edit_response.execute
else
send_bad_request (req, res)
end
end
end

View File

@@ -0,0 +1,114 @@
note
description: "Summary description for {CMS_ROLE_VIEW_RESPONSE}."
date: "$Date$"
revision: "$Revision$"
class
CMS_ROLE_VIEW_RESPONSE
inherit
CMS_RESPONSE
redefine
make,
initialize
end
create
make
feature {NONE} -- Initialization
make (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: like api;)
do
create {WSF_NULL_THEME} wsf_theme.make
Precursor (req, res, a_api)
end
initialize
do
Precursor
create {CMS_TO_WSF_THEME} wsf_theme.make (Current, theme)
end
wsf_theme: WSF_THEME
feature -- Query
role_id_path_parameter (req: WSF_REQUEST): INTEGER_64
-- Role id passed as path parameter for request `req'.
local
s: STRING
do
if attached {WSF_STRING} req.path_parameter ("id") as p_nid then
s := p_nid.value
if s.is_integer_64 then
Result := s.to_integer_64
end
end
end
feature -- Execution
process
-- Computed response message.
local
uid: INTEGER_64
user_api : CMS_USER_API
do
user_api := api.user_api
uid := role_id_path_parameter (request)
if uid > 0 and then attached user_api.user_role_by_id (uid.to_integer) as l_role then
append_html_to_output (l_role, Current)
else
set_main_content ("Missing Role")
end
end
append_html_to_output (a_role: CMS_USER_ROLE; a_response: CMS_RESPONSE )
local
lnk: CMS_LOCAL_LINK
s: STRING
do
a_response.set_value (a_role, "role")
create lnk.make (a_response.translation ("View", Void), "admin/role/" + a_role.id.out)
lnk.set_is_active (True)
lnk.set_weight (1)
a_response.add_to_primary_tabs (lnk)
create lnk.make (a_response.translation ("Edit", Void), "admin/role/" + a_role.id.out + "/edit")
lnk.set_weight (2)
a_response.add_to_primary_tabs (lnk)
if a_role /= Void and then a_role.id > 0 then
create lnk.make (a_response.translation ("Delete", Void), "admin/role/" + a_role.id.out + "/delete")
lnk.set_weight (3)
a_response.add_to_primary_tabs (lnk)
end
create s.make_empty
s.append ("<div class=%"info%"> ")
s.append ("<h4>Role Information</h4>")
s.append ("<p>Role:")
s.append (a_role.name)
s.append ("</p>")
s.append ("<h4>Permissions:</h4>")
if
not a_role.permissions.is_empty
then
s.append ("<ul class=%"cms-permissions%">%N")
across a_role.permissions as ic loop
s.append ("<li class=%"cms-permission%">"+ ic.item + "</li>%N")
end
s.append ("</ul>%N")
end
s.append ("</div>")
a_response.set_title (a_role.name)
a_response.set_main_content (s)
end
end

View File

@@ -0,0 +1,128 @@
note
description: "Summary description for {CMS_ADMIN_USER_HANDLER}."
date: "$Date$"
revision: "$Revision$"
class
CMS_ADMIN_USERS_HANDLER
inherit
CMS_HANDLER
WSF_URI_HANDLER
rename
execute as uri_execute,
new_mapping as new_uri_mapping
end
WSF_URI_TEMPLATE_HANDLER
rename
execute as uri_template_execute,
new_mapping as new_uri_template_mapping
select
new_uri_template_mapping
end
WSF_RESOURCE_HANDLER_HELPER
redefine
do_get
end
REFACTORING_HELPER
create
make
feature -- execute
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute (req, res)
end
uri_template_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
local
l_response: CMS_RESPONSE
s: STRING
u: CMS_USER
l_page_helper: CMS_PAGINATION_GENERATOR
s_pager: STRING
l_count: INTEGER
user_api: CMS_USER_API
do
-- At the moment the template are hardcoded, but we can
-- get them from the configuration file and load them into
-- the setup class.
create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api)
if l_response.has_permission ("admin users") then
user_api := api.user_api
l_count := user_api.users_count
create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api)
create s.make_empty
if l_count > 1 then
l_response.set_title ("Listing " + l_count.out + " Users")
else
l_response.set_title ("Listing " + l_count.out + " User")
end
create s_pager.make_empty
create l_page_helper.make ("admin/users/?page={page}&size={size}", user_api.users_count.as_natural_64, 25) -- FIXME: Make this default page size a global CMS settings
l_page_helper.get_setting_from_request (req)
if l_page_helper.has_upper_limit and then l_page_helper.pages_count > 1 then
l_page_helper.append_to_html (l_response, s_pager)
if l_page_helper.page_size > 25 then
s.append (s_pager)
end
end
if attached user_api.recent_users (create {CMS_DATA_QUERY_PARAMETERS}.make (l_page_helper.current_page_offset, l_page_helper.page_size)) as lst then
s.append ("<ul class=%"cms-users%">%N")
across
lst as ic
loop
u := ic.item
s.append ("<li class=%"cms_user%">")
s.append ("<a href=%"")
s.append (req.absolute_script_url ("/admin/user/"+u.id.out))
s.append ("%">")
s.append (u.name)
s.append ("</a>")
s.append ("</li>%N")
end
s.append ("</ul>%N")
end
-- Again the pager at the bottom, if needed
s.append (s_pager)
if l_response.has_permission ("manage " + {CMS_ADMIN_MODULE}.name) then
s.append (l_response.link ("Add User", "admin/add/user", Void))
end
l_response.set_main_content (s)
l_response.execute
else
l_response.execute
end
end
end

View File

@@ -0,0 +1,523 @@
note
description: "Summary description for {CMS_USER_FORM_RESPONSE}."
date: "$Date$"
revision: "$Revision$"
class
CMS_USER_FORM_RESPONSE
inherit
CMS_RESPONSE
redefine
make,
initialize
end
create
make
feature {NONE} -- Initialization
make (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: like api)
do
create {WSF_NULL_THEME} wsf_theme.make
Precursor (req, res, a_api)
end
initialize
do
Precursor
create {CMS_TO_WSF_THEME} wsf_theme.make (Current, theme)
end
wsf_theme: WSF_THEME
feature -- Query
user_id_path_parameter (req: WSF_REQUEST): INTEGER_64
-- User id passed as path parameter for request `req'.
local
s: STRING
do
if attached {WSF_STRING} req.path_parameter ("id") as p_nid then
s := p_nid.value
if s.is_integer_64 then
Result := s.to_integer_64
end
end
end
feature -- Process
process
-- Computed response message.
local
b: STRING_8
uid: INTEGER_64
user_api: CMS_USER_API
do
user_api := api.user_api
create b.make_empty
uid := user_id_path_parameter (request)
if
uid > 0 and then
attached user_api.user_by_id (uid) as l_user
then
if
location.ends_with_general ("/edit")
then
edit_form (l_user)
elseif location.ends_with_general ("/delete") then
delete_form (l_user)
end
else
new_form
end
end
feature -- Process Edit
edit_form (a_user: CMS_USER)
local
f: like new_edit_form
b: STRING
fd: detachable WSF_FORM_DATA
do
create b.make_empty
f := new_edit_form (a_user, url (location, Void), "edit-user")
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)
fd := f.last_data
end
if a_user.has_id then
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("View", Void),"admin/user/" + a_user.id.out), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void),"admin/user/" + a_user.id.out + "/edit"), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Delete", Void),"admin/user/" + a_user.id.out + "/delete"), primary_tabs)
end
if attached redirection as l_location then
-- FIXME: Hack for now
set_title (a_user.name)
b.append (html_encoded (a_user.name) + " saved")
else
set_title (formatted_string (translation ("Edit $1 #$2", Void), [a_user.name, a_user.id]))
f.append_to_html (wsf_theme, b)
end
set_main_content (b)
end
feature -- Process Delete
delete_form (a_user: CMS_USER)
local
f: like new_delete_form
b: STRING
fd: detachable WSF_FORM_DATA
do
create b.make_empty
f := new_delete_form (a_user, url (location, Void), "edit-user")
hooks.invoke_form_alter (f, fd, Current)
if request.is_post_request_method then
f.process (Current)
fd := f.last_data
end
if a_user.has_id then
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("View", Void),"admin/user/" + a_user.id.out ), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void),"admin/user/" + a_user.id.out + "/edit"), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Delete", Void),"admin/user/" + a_user.id.out + "/delete"), primary_tabs)
end
if attached redirection as l_location then
-- FIXME: Hack for now
set_title (a_user.name)
b.append (html_encoded (a_user.name) + " deleted")
else
set_title (formatted_string (translation ("Delete $1 #$2", Void), [a_user.name, a_user.id]))
f.append_to_html (wsf_theme, b)
end
set_main_content (b)
end
feature -- Process New
new_form
local
f: like new_edit_form
b: STRING
fd: detachable WSF_FORM_DATA
l_user: detachable CMS_USER
do
create b.make_empty
f := new_edit_form (l_user, url (location, Void), "create-user")
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))
f.process (Current)
fd := f.last_data
end
if attached redirection as l_location then
-- FIXME: Hack for now
if attached l_user then
set_title (l_user.name)
b.append (html_encoded (l_user.name) + " Saved")
end
else
if attached l_user then
set_title (formatted_string (translation ("Saved $1 #$2", Void), [l_user.name, l_user.id]))
end
f.append_to_html (wsf_theme, b)
end
set_main_content (b)
end
feature -- Form
edit_form_submit (fd: WSF_FORM_DATA; a_user: detachable CMS_USER; b: STRING)
local
l_update_roles: BOOLEAN
l_update_user: BOOLEAN
l_save_user: BOOLEAN
l_user: detachable CMS_USER
s: STRING
lnk: CMS_LINK
do
l_update_roles := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Update user role")
if l_update_roles then
debug ("cms")
across
fd as c
loop
b.append ("<li>" + html_encoded (c.key) + "=")
if attached c.item as v then
b.append (html_encoded (v.string_representation))
end
b.append ("</li>")
end
end
if a_user /= Void then
l_user := a_user
if l_user.has_id then
create {CMS_LOCAL_LINK} lnk.make (translation ("View", Void),"admin/user/" + l_user.id.out )
change_user (fd, a_user)
s := "modified"
set_redirection (lnk.location)
end
end
end
l_update_user := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Update user")
if l_update_user then
debug ("cms")
across
fd as c
loop
b.append ("<li>" + html_encoded (c.key) + "=")
if attached c.item as v then
b.append (html_encoded (v.string_representation))
end
b.append ("</li>")
end
end
if a_user /= Void then
l_user := a_user
if l_user.has_id then
change_user (fd, a_user)
s := "modified"
end
end
end
l_save_user := attached {WSF_STRING} fd.item ("op") as l_op and then l_op.same_string ("Create user")
if l_save_user then
debug ("cms")
across
fd as c
loop
b.append ("<li>" + html_encoded (c.key) + "=")
if attached c.item as v then
b.append (html_encoded (v.string_representation))
end
b.append ("</li>")
end
end
create_user (fd)
end
end
new_edit_form (a_user: detachable CMS_USER; a_url: READABLE_STRING_8; a_name: STRING): CMS_FORM
-- Create a web form named `a_name' for uSER `a_YSER' (if set), using form action url `a_url'.
local
f: CMS_FORM
th: WSF_FORM_HIDDEN_INPUT
do
create f.make (a_url, a_name)
create th.make ("user-id")
if a_user /= Void then
th.set_text_value (a_user.id.out)
else
th.set_text_value ("0")
end
f.extend (th)
populate_form (f, a_user)
Result := f
end
new_form_validate (fd: WSF_FORM_DATA; b: STRING)
do
if attached fd.string_item ("op") as f_op then
if f_op.is_case_insensitive_equal_general ("Create user") then
if attached fd.string_item ("username") as l_username then
if attached api.user_api.user_by_name (l_username) then
fd.report_invalid_field ("username", "Username already taken!")
end
else
fd.report_invalid_field ("username", "missing username")
end
if attached fd.string_item ("email") as l_email then
if attached api.user_api.user_by_email (l_email) then
fd.report_invalid_field ("email", "Email address already associated with an existing account!")
end
else
fd.report_invalid_field ("email", "missing email address")
end
elseif f_op.is_case_insensitive_equal_general ("Update user") then
if attached fd.string_item ("username") as l_username then
if api.user_api.user_by_name (l_username) = Void then
fd.report_invalid_field ("username", "Username does not exist!")
end
else
fd.report_invalid_field ("username", "missing username")
end
end
end
end
new_delete_form (a_user: detachable CMS_USER; a_url: READABLE_STRING_8; a_name: STRING;): CMS_FORM
-- Create a web form named `a_name' for node `a_user' (if set), using form action url `a_url'.
local
f: CMS_FORM
ts: WSF_FORM_SUBMIT_INPUT
do
create f.make (a_url, a_name)
f.extend_html_text ("<br/>")
f.extend_html_text ("<legend>Are you sure you want to delete?</legend>")
-- TODO check if we need to check for has_permissions!!
if
a_user /= Void and then
a_user.has_id
then
create ts.make ("op")
ts.set_default_value ("Delete")
fixme ("[
ts.set_default_value (translation ("Delete"))
]")
f.extend (ts)
create ts.make ("op")
ts.set_default_value ("Cancel")
ts.set_formmethod ("GET")
ts.set_formaction ("/admin/user/" + a_user.id.out)
f.extend (ts)
end
Result := f
end
populate_form (a_form: WSF_FORM; a_user: detachable CMS_USER)
-- Fill the web form `a_form' with data from `a_node' if set,
-- and apply this to content type `a_content_type'.
local
ti: WSF_FORM_TEXT_INPUT
fe: WSF_FORM_EMAIL_INPUT
fs: WSF_FORM_FIELD_SET
cb: WSF_FORM_CHECKBOX_INPUT
ts: WSF_FORM_SUBMIT_INPUT
l_user_roles: detachable LIST [CMS_USER_ROLE]
do
if a_user /= Void then
create fs.make
fs.set_legend ("Basic User Account Information")
fs.extend_html_text ("<div><string><label>User name </label></strong><br></div>")
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
create fe.make_with_text ("email", "")
end
fe.set_label ("Email")
fe.enable_required
fs.extend (fe)
a_form.extend (fs)
a_form.extend_html_text ("<br/>")
create ts.make ("op")
ts.set_default_value ("Update user")
a_form.extend (ts)
a_form.extend_html_text ("<hr>")
create fs.make
fs.set_legend ("User Roles")
l_user_roles := api.user_api.user_roles (a_user)
if l_user_roles.is_empty then
l_user_roles := Void
end
across api.user_api.effective_roles as ic loop
create cb.make_with_value ("cms_roles", ic.item.id.out)
cb.set_checked (l_user_roles /= Void and then across l_user_roles as r_ic some r_ic.item.same_user_role (ic.item) end)
cb.set_title (ic.item.name)
fs.extend (cb)
end
a_form.extend (fs)
create ts.make ("op")
ts.set_default_value ("Update user role")
a_form.extend (ts)
else
create fs.make
fs.set_legend ("Basic User Account Information")
create ti.make ("username")
ti.set_label ("Username")
ti.enable_required
fs.extend (ti)
create fe.make_with_text ("email", "")
fe.set_label ("Email")
fe.enable_required
fs.extend (fe)
a_form.extend (fs)
a_form.extend_html_text ("<br/>")
create ts.make ("op")
ts.set_default_value ("Create user")
a_form.extend (ts)
a_form.extend_html_text ("<hr>")
end
end
change_user (a_form_data: WSF_FORM_DATA; a_user: CMS_USER)
-- Update node `a_node' with form_data `a_form_data' for the given content type `a_content_type'.
local
l_uroles: LIST [CMS_USER_ROLE]
do
if attached a_form_data.string_item ("op") as f_op then
if f_op.is_case_insensitive_equal_general ("Update user role") then
if attached a_form_data.string_item ("user-id") as l_user_id and then
attached {CMS_USER} api.user_api.user_by_id (l_user_id.to_integer) as l_user
then
l_uroles := api.user_api.user_roles (l_user)
l_uroles.compare_objects
if attached {WSF_STRING} a_form_data.item ("cms_roles") as l_role then
if attached api.user_api.user_role_by_id (l_role.integer_value) as role then
if not l_uroles.has (role) then
api.user_api.assign_role_to_user (role, a_user)
end
end
elseif attached {WSF_MULTIPLE_STRING} a_form_data.item ("cms_roles") as l_roles then
across l_roles as ic loop
if attached api.user_api.user_role_by_id (ic.item.integer_value) as role then
if not l_uroles.has (role) then
api.user_api.assign_role_to_user (role, a_user)
end
end
end
else
across api.user_api.roles as ic loop
api.user_api.unassign_role_from_user (ic.item, a_user)
end
end
add_success_message ("Roles updated")
else
a_form_data.report_error ("Missing User")
end
elseif f_op.is_case_insensitive_equal_general ("Update user") then
if
attached a_form_data.string_item ("user-id") as l_user_id and then
attached {CMS_USER} api.user_api.user_by_id (l_user_id.to_integer) as l_user
then
if
attached a_form_data.string_item ("email") as l_email
then
if
attached l_user.email as u_email and then
not u_email.is_case_insensitive_equal_general (l_email) and then
api.user_api.user_by_email (l_email) = Void
then
-- Valid email
a_user.set_email (l_email)
else
if attached l_user.email as u_email and then not u_email.is_case_insensitive_equal_general (l_email) then
a_form_data.report_invalid_field ("email", "Email already exist!")
end
end
if not a_form_data.has_error then
api.user_api.update_user (a_user)
add_success_message ("Updated basic info")
end
end
end
end
end
end
create_user (a_form_data: WSF_FORM_DATA)
local
u: CMS_USER
do
if attached a_form_data.string_item ("op") as f_op then
if f_op.is_case_insensitive_equal_general ("Create user") then
if
attached a_form_data.string_item ("username") as l_username and then
attached a_form_data.string_item ("email") as l_email and then
l_email.is_valid_as_string_8
then
create u.make (l_username)
u.set_email (l_email.as_string_8)
u.set_password (new_random_password (u))
api.user_api.new_user (u)
if api.user_api.has_error then
-- handle error
else
add_success_message ("Created user")
end
else
a_form_data.report_invalid_field ("username", "Missing username!")
a_form_data.report_invalid_field ("email", "Missing email address!")
end
end
end
end
feature -- Generation
new_random_password (u: CMS_USER): STRING
-- Generate a new token activation token
local
l_token: STRING
l_security: SECURITY_PROVIDER
l_encode: URL_ENCODER
do
create l_security
l_token := l_security.token
create l_encode
from until l_token.same_string (l_encode.encoded_string (l_token)) loop
-- Loop ensure that we have a security token that does not contain characters that need encoding.
-- We cannot simply to an encode-decode because the email sent to the user will contain an encoded token
-- but the user will need to use an unencoded token if activation has to be done manually.
l_token := l_security.token
end
Result := l_token + url_encoded (u.name) + u.creation_date.out
end
end

View File

@@ -0,0 +1,203 @@
note
description: "[
Handler for a CMS user in the CMS interface
]"
date: "$Date$"
revision: "$Revision$"
class
CMS_USER_HANDLER
inherit
CMS_HANDLER
WSF_URI_HANDLER
rename
execute as uri_execute,
new_mapping as new_uri_mapping
end
WSF_URI_TEMPLATE_HANDLER
rename
execute as uri_template_execute,
new_mapping as new_uri_template_mapping
select
new_uri_template_mapping
end
WSF_RESOURCE_HANDLER_HELPER
redefine
do_get,
do_post,
do_delete
end
REFACTORING_HELPER
create
make
feature -- execute
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute (req, res)
end
uri_template_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute (req, res)
end
feature -- Query
user_id_path_parameter (req: WSF_REQUEST): INTEGER_64
-- User id passed as path parameter for request `req'.
local
s: STRING
do
if attached {WSF_STRING} req.path_parameter ("id") as p_nid then
s := p_nid.value
if s.is_integer_64 then
Result := s.to_integer_64
end
end
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
l_user: detachable CMS_USER
l_uid: INTEGER_64
edit_response: CMS_USER_FORM_RESPONSE
view_response: CMS_USER_VIEW_RESPONSE
r: CMS_RESPONSE
do
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
if r.has_permission ("admin users") then
if req.percent_encoded_path_info.ends_with_general ("/edit") then
check valid_url: req.percent_encoded_path_info.starts_with_general ("/admin/user/") end
create edit_response.make (req, res, api)
edit_response.execute
elseif req.percent_encoded_path_info.ends_with_general ("/delete") then
check valid_url: req.percent_encoded_path_info.starts_with_general ("/admin/user/") end
create edit_response.make (req, res, api)
edit_response.execute
else
-- Display existing node
l_uid := user_id_path_parameter (req)
if l_uid > 0 then
l_user := api.user_api.user_by_id (l_uid)
if
l_user /= Void
then
create view_response.make (req, res, api)
view_response.execute
else
send_not_found (req, res)
end
else
create_new_user (req, res)
end
end
else
r.execute
end
end
do_post (req: WSF_REQUEST; res: WSF_RESPONSE)
local
edit_response: CMS_USER_FORM_RESPONSE
r: CMS_RESPONSE
do
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
if r.has_permission ("admin users") then
if req.percent_encoded_path_info.ends_with_general ("/edit") then
create edit_response.make (req, res, api)
edit_response.execute
elseif req.percent_encoded_path_info.ends_with_general ("/delete") then
if
attached {WSF_STRING} req.form_parameter ("op") as l_op and then
l_op.value.same_string ("Delete")
then
do_delete (req, res)
end
elseif req.percent_encoded_path_info.ends_with_general ("/add/user") then
create edit_response.make (req, res, api)
edit_response.execute
end
else
r.execute
end
end
feature -- Error
do_error (req: WSF_REQUEST; res: WSF_RESPONSE; a_id: detachable WSF_STRING)
-- Handling error.
local
l_page: CMS_RESPONSE
do
create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, api)
l_page.set_value (req.absolute_script_url (req.percent_encoded_path_info), "request")
if a_id /= Void and then a_id.is_integer then
-- resource not found
l_page.set_value ("404", "code")
l_page.set_status_code (404)
else
-- bad request
l_page.set_value ("400", "code")
l_page.set_status_code (400)
end
l_page.execute
end
do_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
do
if attached current_user (req) as l_user then
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
if
l_id.is_integer and then
attached api.user_api.user_by_id (l_id.integer_value) as u_user
then
api.user_api.delete_user(u_user)
res.send (create {CMS_REDIRECTION_RESPONSE_MESSAGE}.make (req.absolute_script_url ("")))
else
do_error (req, res, l_id)
end
else
(create {INTERNAL_SERVER_ERROR_CMS_RESPONSE}.make (req, res, api)).execute
end
else
send_access_denied (req, res)
end
end
feature {NONE} -- New User
create_new_user (req: WSF_REQUEST; res: WSF_RESPONSE)
local
edit_response: CMS_USER_FORM_RESPONSE
do
if req.percent_encoded_path_info.starts_with ("/admin/add/user") then
create edit_response.make (req, res, api)
edit_response.execute
else
send_bad_request (req, res)
end
end
end

View File

@@ -0,0 +1,131 @@
note
description: "Summary description for {CMS_USER_VIEW_RESPONSE}."
date: "$Date$"
revision: "$Revision$"
class
CMS_USER_VIEW_RESPONSE
inherit
CMS_RESPONSE
redefine
make,
initialize
end
create
make
feature {NONE} -- Initialization
make (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: like api;)
do
create {WSF_NULL_THEME} wsf_theme.make
Precursor (req, res, a_api)
end
initialize
do
Precursor
create {CMS_TO_WSF_THEME} wsf_theme.make (Current, theme)
end
wsf_theme: WSF_THEME
feature -- Query
user_id_path_parameter (req: WSF_REQUEST): INTEGER_64
-- User id passed as path parameter for request `req'.
local
s: STRING
do
if attached {WSF_STRING} req.path_parameter ("id") as p_nid then
s := p_nid.value
if s.is_integer_64 then
Result := s.to_integer_64
end
end
end
feature -- Execution
process
-- Computed response message.
local
uid: INTEGER_64
user_api : CMS_USER_API
do
user_api := api.user_api
uid := user_id_path_parameter (request)
if uid > 0 and then attached user_api.user_by_id (uid) as l_user then
append_html_to_output (l_user, Current)
else
set_main_content ("Missing User")
end
end
append_html_to_output (a_user: CMS_USER; a_response: CMS_RESPONSE)
local
lnk: CMS_LOCAL_LINK
s: STRING
l_role: CMS_USER_ROLE
do
a_response.set_value (a_user, "user")
create lnk.make (a_response.translation ("View", Void), "admin/user/" + a_user.id.out)
lnk.set_is_active (True)
lnk.set_weight (1)
a_response.add_to_primary_tabs (lnk)
create lnk.make (a_response.translation ("Edit", Void), "admin/user/" + a_user.id.out + "/edit")
lnk.set_permission_arguments (<<"manage admin", "manage users", "manage own user">>)
lnk.set_weight (2)
a_response.add_to_primary_tabs (lnk)
if a_user /= Void and then a_user.id > 0 then
create lnk.make (a_response.translation ("Delete", Void), "admin/user/" + a_user.id.out + "/delete")
lnk.set_weight (3)
a_response.add_to_primary_tabs (lnk)
end
-- FIXME: [04/aug/2015] use a CMS_FORM rather than hardcoded html.
-- So that other module may easily integrate them-selves to add information.
create s.make_empty
s.append ("<div class=%"info%"> ")
s.append ("<h4>Account Information</h4>")
s.append ("<p>Username: ")
s.append (a_user.name)
s.append ("</p>")
if attached a_user.email as l_email then
s.append ("<p>Email: ")
s.append (l_email)
s.append ("</p>")
end
if
attached {LIST [CMS_USER_ROLE]} api.user_api.user_roles (a_user) as l_roles and then
not l_roles.is_empty
then
s.append ("<h4>Role(s):</h4>")
across l_roles as ic loop
l_role := ic.item
s.append ("<i>")
s.append (link (l_role.name, "admin/role/" + l_role.id.out, Void))
s.append ("</i>")
debug
s.append ("<h5>Permissions:</h5>")
s.append ("<ul class=%"cms-permissions%">%N")
across l_role.permissions as perms_ic loop
s.append ("<li class=%"cms-permission%">" + perms_ic.item + "</li>%N")
end
s.append ("</ul>%N")
end
end
end
s.append ("</div>")
a_response.set_title (a_user.name)
a_response.set_main_content (s)
end
end

View File

@@ -0,0 +1,34 @@
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] "; }
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] "; }
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] "; }
/*# sourceMappingURL=admin.css.map */

View File

@@ -0,0 +1,59 @@
ul.cms-users {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
li{
border-top: dotted 1px #ccc;
&:first-child {
border-top: none;
}
}
li.cms_user a::before {
content: "[users] ";
}
}
ul.cms-roles {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
li{
border-top: dotted 1px #ccc;
&:first-child {
border-top: none;
}
}
li.cms_role a::before {
content: "[roles] ";
}
}
ul.cms-permissions {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
li{
border-top: dotted 1px #ccc;
&:first-child {
border-top: none;
}
}
li.cms_permission a::before {
content: "[permission] ";
}
}

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="login" uuid="AAB9EE7D-A671-4727-8658-D417A48B2B57" library_target="login">
<target name="login">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="auth_module" uuid="AAB9EE7D-A671-4727-8658-D417A48B2B57" library_target="auth_module">
<target name="auth_module">
<root all_classes="true"/>
<file_rule>
<exclude>/.git$</exclude>
@@ -10,18 +10,22 @@
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="cms" location="$ISE_LIBRARY\unstable\library\web\cms\cms-safe.ecf" readonly="false"/>
<library name="cms_app_env" location="$ISE_LIBRARY\unstable\library\web\cms\library\app_env\app_env-safe.ecf" readonly="false"/>
<library name="cms_model" location="$ISE_LIBRARY\unstable\library\web\cms\library\model\cms_model-safe.ecf" readonly="false"/>
<library name="config" location="$ISE_LIBRARY\unstable\library\web\cms\library\configuration\config-safe.ecf"/>
<library name="cms" location="..\..\cms-safe.ecf" readonly="false"/>
<library name="cms_app_env" location="..\..\library\app_env\app_env-safe.ecf" readonly="false"/>
<library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/>
<library name="config" location="..\..\library\configuration\config-safe.ecf"/>
<library name="encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
<library name="wsf_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"/>
<library name="error" location="$ISE_LIBRARY\contrib\library\utility\general\error\error-safe.ecf"/>
<library name="apis" location="$ISE_LIBRARY\contrib\library\web\communication\oauth\cypress\consumer\apis\apis.ecf" readonly="false"/>
<library name="cypress_consumer" location="$ISE_LIBRARY\contrib\library\web\communication\oauth\cypress\consumer\cypress_consumer-safe.ecf" readonly="false"/>
<library name="email_service" location="..\..\library\email\email-safe.ecf"/>
<library name="apis" location="$ISE_LIBRARY\contrib\library\web\authentication\oauth\cypress\consumer\apis\apis.ecf" readonly="false"/>
<library name="cypress_consumer" location="$ISE_LIBRARY\contrib\library\web\authentication\oauth\cypress\consumer-safe.ecf" readonly="false"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>

Some files were not shown because too many files have changed in this diff Show More