Compare commits

...

134 Commits

Author SHA1 Message Date
3fa29340b2 Updated code to follow review comments. 2015-05-12 20:01:14 +02:00
jvelilla
b1988d5fe7 Updated CMS_NODE_API, with status, not_published, published and trashed.
Removed class cms_node_constants.
Updated Form response to use permission scopes.
Updated sqlquery to retrieve user author.
Added logger info in cms_response
2015-05-11 23:51:25 -03:00
jvelilla
e767e1bc47 Updated table node to use status (1:not_published, 2:published, 3:trash )instead of deleted_at to implement soft deletes.
Updated queries to use the new status field.
Updated CMS_NODE with a new status attribute.
2015-05-11 16:38:51 -03:00
jvelilla
c2d0fbf445 Updated table nodes to support soft deletes using the new field
'deleted_at' as Datetime and give us free metadata.
Updated Sqlite builder to test different scenarios for users and roles.
Updated NODE_FORM_RESPONSE.edit_form feature to add a delete operation iff
there is a node ie node id >0 and the current user has delete permission on it.
Updated NODE_HANDLER.do_post to handle the operation "DELETE".
Updated queries to retrieve nodes filter by no logical deleted rows (ie. deleted_at is NULL).
Updated CMS_USER_API.has_permissions. (authenticated_user_role seems to generic).
2015-05-08 18:40:46 -03:00
fdff2bef36 Fixed compilation of autotests suites for sqlite and mysql.
TODO: reintroduce tests for node management.
2015-05-04 23:17:06 +02:00
1603086905 Fixed node editing workflow (especially creation/updating). 2015-04-30 19:46:18 +02:00
99b2fa9fdb Commented line registering the MYSQL storage builder,
since it reguires to setup MYSQL environment variable and so on.
So by default, we use sqlite, easier to run out of the box.
2015-04-30 19:38:17 +02:00
e17011de97 for backward compatibility alias CMS_LAYOUT to CMS_ENVIRONMENT 2015-04-30 10:05:04 +02:00
17fe37aedd Added {CMS_RESPONSE}.formats: CMS_FORMATS 2015-04-30 09:50:47 +02:00
dd3688fab8 Now node and basic_auth modules are standalone cms modules (as .ecf library)
Moved to complete void-safety
Use port 9090 for demo by configuration.
2015-04-29 23:27:36 +02:00
7771a452cf Moved src/modules under modules cluster. 2015-04-29 23:08:45 +02:00
6ff7a6493c Simplify CMS_SERVICE initialization, and CMS server (launcher).
Renamed "layout" lib as "app_env" with APPLICATION_ENVIRONMENT interface.
  applied changed to callers.
Added CMS_THEME.has_region (a_name): BOOLEAN to know if a region is declared in a defined theme.
2015-04-29 23:01:42 +02:00
0eb2b70d0f Cleaned the node module, to remove for now the REST api attempt.
This will be redone with care once the web cms is ready.
2015-04-29 20:02:09 +02:00
c982f0ea9c Implemented view node by content type (no more hardcoded cases).
Added CMS_NODE_TYPE as descendant of CMS_CONTENT_TYPE,
  in case we have content which is not a node in the future.
  (probably useless, but for now, this extra abstraction is harmful)
Moved all node related code under node module cluster.
Applied comments from Javier Velilla.
Code cleaning.
2015-04-29 17:28:33 +02:00
e8bb3790ba Removed unused variables. 2015-04-27 18:50:05 +02:00
e206c1e133 Code cleaning. 2015-04-27 18:48:51 +02:00
5582dd9058 Merge branch 'jvelilla-nodes' into nodes 2015-04-27 18:44:35 +02:00
jvelilla
d54cd6032f Added comments 2015-04-24 17:55:32 -03:00
jvelilla
8b24c86ff1 Updated Authentication JS, still work in progress 2015-04-23 11:43:57 -03:00
jvelilla
fc4c2e76b6 Added login form with Javascript (example).
Updated feature and class comments.
2015-04-22 18:40:36 -03:00
a56338ad17 Added blog module as example, this is far from being a real blog module.
but this is an example about on to add a new content type, and support it.
Fixed new node form workflow.

The current state is not final, it requires many changes, but for now, it implements a node editing workflow.
2015-04-15 22:32:38 +02:00
f2bb061488 Added support for log stored in CMS_STORAGE.
Added support for custom value stored in CMS_STORAGE.
Added optional css classes addition to CMS_BLOCK output.
Refactored storage, to manage node from node module code only (or mostly).

TODO: improved view for a cms node, for now hardcoded.
2015-04-15 16:39:03 +02:00
2b25c23977 Added helper function to CMS_RESPONSE, to deal with permissions. 2015-04-14 16:11:04 +02:00
ea2b5b87d3 Added helper functions to get uri path for a node, and other related resources.
Added description to cms content type.
Fixed initialization of node module to create test bed nodes.
2015-04-14 16:07:09 +02:00
133c243126 Implemented CMS storage for user and nodes.
Implemented role and permission storage.
Introduced the CMS_PARTIAL_NODE and CMS_PARTIAL_USER.
Added support for node storage extension
  - storage of data specific to each node content type,
  - in addition to the core CMS_NODE)
  - For now, only implemented for SQL storage.
Note: in current version, CMS_PAGE support is hard coded in the core,
    (as opposed to be only supported by the node module.)
Commented/removed for now, the Web API code to update node summary, title, via REST request.
2015-04-14 11:25:02 +02:00
Jocelyn Fiat
734f661add Merge pull request #21 from jvelilla/roc_jv_09042015
Added missing descriptions/comments
2015-04-10 10:50:52 +02:00
jvelilla
e41b0631d6 Added missing descriptions 2015-04-09 22:45:37 -03:00
jvelilla
98621cb265 Merge branch 'jocelyn-jfiat' 2015-04-09 21:44:52 -03:00
9a8683a139 Updated configuration of the example to use EiffelStore sqlite database by default. 2015-04-09 23:59:57 +02:00
f3c3407b0a Got rid of CMS_GENERIC_RESPONSE, and replace with CMS_RESPONSE_MESSAGE descendants.
Update node module to use new uri mapping, and cleaned dev purpose code.
2015-04-09 23:59:13 +02:00
20471923fd Fixed the basic auth logout by using the ://foo@hostname... workaround.
Added support for ?destination=... so that login or logout will return to previous visited page.
Revisited the sending of generic response such as access denied, unauthorized, redirection ...
Fixed support of CMS_RESPONSE.header which was  previously ignored.
Added support for CMS_RESPONSE.redirection: detachable READABLE_STRING_8, to allow easy url redirection.
Added CMS_NODE.make_empty
+ Cosmetic.
2015-04-09 23:54:14 +02:00
b235fb30a7 Updated design related to logger, to prepare move to SCOOP concurrency. 2015-04-02 21:15:05 +02:00
e94d860fd8 Commented "mysql" support to make it easier to compile at first. 2015-03-20 19:45:14 +01:00
bd6524ebe7 Fixed issue with ini config component and include functionality.
Added {CMS_SETUP}.cms_config_ini_name to define the CMS Configuration file name,
   and provide an easy way to change the name.
2015-03-09 19:27:30 +01:00
ca10c57b4b Added is_https: BOOLEAN query to CMS (on page, but also as 'is_https' value) 2015-02-16 20:14:45 +01:00
8d59d25ace Added weight into to the CMS_LINK and provide a `sort' feature for CMS_MENU and related.
Protected cms service from registering many time the same module type.
Moved library/persistence/implementation/* under library/persistence/.
Moved site/www/themes to site/themes
For SQLite storage driver, auto create sqlite db file using associated sql script (to be completed).
Added code in demo module to reuse storage for module purpose.
Always call sql_post_execution in sql_query and sql_change, and not anymore by the callers.
Removed is_web and is_html from {CMS_SETUP}, it was not used.
Reused SHARED_*_ENCODER in CMS_ENCODERS
Added CMS_API.logger rather than using directly the SHARED_LOGGER.log ...
Centralize the implementation of current_user in CMS_REQUEST_UTIL
Removed the inheritance on WSF_FILTER for node handlers, since it is useless and unused.
Added CMS_NODE_API and CMS_USER_API
Prefix html id for block generated html items with "block-", to avoid css name conflict on "main", "content" or similar.
Code cleaning
2015-02-16 13:01:06 +01:00
a810b1176c Revisited application layout, shared logger and relation with cms to avoid mixing various layout. 2015-02-05 10:28:46 +01:00
Jocelyn Fiat
e40f8ee4d2 Fixed location of logs folder. 2015-02-03 19:25:38 +01:00
Jocelyn Fiat
83af7f6a38 Fixed shared logger code (there was an issue on non Windows machine)
Now, it is possible to set logs folder from config file.
2015-02-03 19:19:27 +01:00
02368fe3d2 Removed unused local variable.
Updated SHARED_LOGGER to remove a few obsolete calls on json parser.
2015-01-30 19:40:10 +01:00
be0b5c23d2 Added debug output to CMS_BLOCK.
Updated SHARED_LOGGER to remove a few obsolete calls on json parser.
Added favicon.ico specific handling.
Fixed issue with theme and non raw block.
2015-01-30 19:37:12 +01:00
jvelilla
88ec1452d8 Added the new Schema for MySQL 2015-01-29 12:10:01 -03:00
5ddc2006e2 Moved library/src to src 2015-01-27 19:58:13 +01:00
d97c4b1a4a Merge branch 'master' of https://github.com/EiffelWebFramework/ROC 2015-01-27 19:49:49 +01:00
7d5869f3b9 Revisited the persistence layer.
Simplified schema to focus on user and node.
Now possible to have sqlite via ODBC and/or mysql support, and select using configuration file.
Updated demo example.
2015-01-27 19:48:37 +01:00
jvelilla
8c74c7a268 Updated log directory location if the argument `-d' is present. 2015-01-14 20:55:24 -03:00
db9e40cec4 Updated CMS_SERVICE to make the cms library complete void-safe.
Reviewed configuration related feature.
Renamed JSON_CONFIGURATION as APPLICATION_JSON_CONFIGURATION_HELPER to avoid confusion.
Updated CMS_DEFAULT_SETUP to use configuration from cms configuration library.
Added {CMS_API}.module_configuration (a_module_name: READABLE_STRING_GENERAL; a_name: detachable READABLE_STRING_GENERAL): detachable CONFIG_READER  to help getting access to configuration of a module (for now, only json and ini are supported, but in the future, this could support database layer directly)
Added CMS_HOOK_BLOCK_HELPER to reuse the template_block (..): ... function.
Cosmetic
Removed CMS_SETUP.smtp_server since for now, there is no need for such general setting.
Add header line "X-ServerEWF-App: CMS" as a simple way to know if request is processed by the CMS.
2015-01-14 18:25:26 +01:00
Javier Velilla
792880aa7a Update Module implementation 2015-01-02 10:43:17 -03:00
Javier Velilla
5ad8c680a6 Add your own Module 2014-12-31 08:06:54 -03:00
jvelilla
e2f02953f4 Refactor rename error_500_cms_response to internal_server_error_cms_response
Added bad_request_error_cms_response
Updated code example to use the new internal_server_error_cms_response instead of error_500_cms_response class.
Removed class error_500_cms_response.

Updated cms setup and configuration design:
  Removed CMS_SETUP.configuration: CMS_CONFIGURATION
  Removed CMS_CONFIGURATION and replaced it by using the configuration library.
  Added CMS_DEFAULT_SETUP.configuration: CONFIG_READER
  Addec CMS_SETUP.text_item (name): detachable READABLE_STRING_32 ...
    in order to access option not publish by the CMS_SETUP interface.
Removed CMS_SERVICE.configuration: CMS_CONFIGURATION since it was not used.

Moved configuration library from eiffel-lang to cms libraries.
Fixed issue related to ini config when parsing from string content,
  and also issue related to section included in file via @include.
Updated cms setup and configuration design:
  Removed CMS_SETUP.configuration: CMS_CONFIGURATION
  Removed CMS_CONFIGURATION and replaced it by using the configuration library.
  Added CMS_DEFAULT_SETUP.configuration: CONFIG_READER
  Addec CMS_SETUP.text_item (name): detachable READABLE_STRING_32 ...
    in order to access option not publish by the CMS_SETUP interface.
Removed CMS_SERVICE.configuration: CMS_CONFIGURATION since it was not used.
Improved the email service and related.
2014-12-19 18:03:52 -03:00
jvelilla
bd26deb6c1 Updated cms configuration file with an smtp server property.
Updated cms code to use the new property.
Removed title from the home response.
2014-12-17 09:16:19 -03:00
jvelilla
a9109ca8f7 Updated CMS_SMARTY_TEMPALTE_BLOCK, redefined out to be used by the logger.
Updated CMS_API, added wrapper features to access error_handler. has_error, reset, as_string_representation, hide
the actual error hanlder implementation.
Updated Error Filter with better logging.
2014-11-26 13:57:04 -03:00
09e5dc4032 Removed a few obsolete calls related to JSON library.
+ cosmetic
2014-11-20 15:14:34 +01:00
d082326784 Removed useless CMS_CUSTOM_SETUP. 2014-11-20 14:57:19 +01:00
51462829c7 reverted renaming to use `modules' for available modules.
Added CMS_SETUP.register_module (m) to avoid extending directly to the CMS_SETUP.modules
2014-11-20 14:53:54 +01:00
ba58fcdf75 Updated cms library with comments, and removed a few JSON obsolete calls. 2014-11-20 14:11:28 +01:00
Javier Velilla
d84f164dbd Update concepts.md
Updated concepts
2014-11-19 13:20:53 -03:00
jvelilla
c3d022ce46 Refactor raname {CMS_SETUP}.modules as {CMS_SETUP}.available_modules
Refactor raname {CMS_SETUP}.modules_enabled as {CMS_SETUP}.enabled_modules
Updated code to use the new features names.
2014-11-19 13:20:07 -03:00
jvelilla
aac01e093a Added {CMS_SETUP}.modules_enabled: CMS_MODULE_COLLECTION
Updated {CMS_SERVIDE}.intialize_modules to use the new feature {CMS_SETUP}.modules_enabled
Updated cms_hook_block description
2014-11-19 12:13:07 -03:00
jvelilla
fb62a1bb3e Merge branch 'roc_template' of https://github.com/jvelilla/ROC into roc_template 2014-11-19 11:50:56 -03:00
Javier Velilla
6162432d52 Update concepts.md
Updated Concepts table of contents
2014-11-19 11:32:59 -03:00
Javier Velilla
ebed52ae01 Update concepts.md
Updated concepts with Modules and Hooks
2014-11-19 11:16:02 -03:00
b58eeeac26 Added comments. 2014-11-19 13:34:42 +01:00
jvelilla
9169bdcd43 Removed shared_error from CMS_API
Added Missing theme and Missing tempalte classes.
Updated CMS_RESPONSE to handle missing template and send a 503 status code
with a raw response.
2014-11-19 09:22:31 -03:00
jvelilla
e36465f86d Update concepts.md
Added references to the important classes.
2014-11-18 09:26:52 -03:00
76190de218 Fixed non void-safe compilations, and cleaned .ecf files.
+Cosmetic
2014-11-18 10:05:50 +01:00
jvelilla
0edff7853b Removed default_theme.
Update theme and smarty theme description
2014-11-17 22:37:10 -03:00
jvelilla
e20a7af301 Merge pull request #15 from jvelilla/roc_template
Roc template
2014-11-17 13:08:33 -03:00
jvelilla
089b367c95 Update concepts.md
Updated default regions
2014-11-17 13:08:01 -03:00
jvelilla
503f2faf08 Update concepts.md
Updated
2014-11-17 13:03:13 -03:00
jvelilla
b887c13664 Renamed files and added tutorial document 2014-11-17 12:44:37 -03:00
jvelilla
bbfe063b5c Update CMS_concepts.md
Added table of contents
2014-11-17 12:26:58 -03:00
jvelilla
1a4e2935da Update README.md
Update readme file
2014-11-17 12:23:37 -03:00
jvelilla
c3a582f85c Added cms_concepts 2014-11-17 12:10:51 -03:00
8bfb66af30 Added cms_smarty_template_block
Added CMS_RESPONSE.module_assets_location and CMS_RESPONSE.module_assets_theme_location
    that help locating module related assets.
Added CMS_BLOCK.is_raw to abstract CMS_CONTENT_BLOCK.is_raw
2014-11-14 19:31:40 +01:00
6aad460b11 Updated ecf files, and added non void-safe .ecf files. 2014-11-14 14:20:01 +01:00
jvelilla
0dc12b82b8 Merge pull request #14 from jvelilla/roc_template
Update sqlite implemenation to make it compile
2014-11-14 08:26:06 -03:00
jvelilla
8047880c2b Update sqlite implemenation to make it compile 2014-11-13 23:46:02 -03:00
jvelilla
48283742aa Merge pull request #13 from jocelyn/minor_changes_20141113
Renamed {CMS_SETUP} theme_resource_location as theme_assets_location
2014-11-13 15:28:39 -03:00
76bdbeaa2a Renamed {CMS_SETUP} theme_resource_location as theme_assets_location
Added missing known hook in auto register hook.
Implemented /theme/* file system response.
Implemented $page.type for the smarty template.
Added CMS_DEBUG_MODULE .
Added NOT_FOUND_ERROR_CMS_RESPONSE .
2014-11-13 19:25:01 +01:00
Jocelyn Fiat
44a1dd62cb Merge pull request #12 from jvelilla/roc_template
Refactor directory structrue	d963fd2
Fixed typo in readme.md
2014-11-13 16:10:40 +01:00
jvelilla
1f8be4e37f Fixed typo in readme.md 2014-11-13 11:59:14 -03:00
jvelilla
d963fd218b Refactor directory structrue 2014-11-13 11:57:36 -03:00
Jocelyn Fiat
8ab4343d5b Merge pull request #11 from jvelilla/roc_template
Added README documentation.
Renamed examples/roc_api to demo.
Added contracts
2014-11-13 14:57:46 +01:00
jvelilla
9af6356f0a Added README doc.
Renamed example/roc_api to demo.
Added contracts
2014-11-13 10:50:54 -03:00
jvelilla
b16048eb18 Merge pull request #10 from jocelyn/copyright_20141113
Added copyright, note, and minor improvements.
2014-11-13 09:00:21 -03:00
71734a6dd7 Renamed model-safe.ecf as cms_model-safe.ecf since it is very specific to the cms.
Fixed compilation issue due to recent use of STRING_TABLE.
2014-11-13 11:15:35 +01:00
9cd53c7c78 updated readme. 2014-11-13 10:53:57 +01:00
a51d0d3c68 Added copyright, various description notes.
Added CMS_EXTERNAL_LINK, and improve various link interfaces.
Structured the model library with sub folder: user, link and content.
2014-11-13 10:50:22 +01:00
jvelilla
b3c2879b07 Merge pull request #9 from jocelyn/auto_hook_20141112
Restored implementation for auto register hooks.
2014-11-12 22:37:30 -03:00
e1feee51f9 Restore implementation for auto register hooks. 2014-11-12 22:35:24 +01:00
Jocelyn Fiat
2aaed89417 Merge pull request #8 from jvelilla/roc_template
Move libraries `layout', `model', `peristence' under cms folder
2014-11-12 21:55:25 +01:00
jvelilla
789b26eafa Move libraries layout', model', `peristence' under cms folder
Updated code to the new layout.
Added missing comments.
Remove /example/api
2014-11-12 17:24:34 -03:00
jvelilla
a576c38d42 Merge pull request #7 from jocelyn/cosmetic_20141112
Cosmetic 20141112
2014-11-12 13:19:59 -03:00
a524b80108 Made CMS_SETUP.site_url detachable.
Cosmetic, avoid long lines of comments.
Added debug ("refactor_fixme") around a few REFACTORING_HELPER.fixme (...)
Better message for a few fixme(...) related to unimplemented routines.
2014-11-12 17:13:18 +01:00
48a8ac4a1c First step toward more generic way to handle hook subscribers. 2014-11-12 16:53:42 +01:00
Jocelyn Fiat
1d4e9df917 Merge pull request #6 from jvelilla/roc_template
Updated Descriptions to classes and features
2014-11-12 16:51:23 +01:00
jvelilla
2d5c1a5e41 Updated Descriptions to classes and features 2014-11-12 12:30:09 -03:00
jvelilla
fba9b598f9 Merge pull request #5 from jocelyn/hook_20141112
name changes related to CMS HOOK and callers.
2014-11-12 12:27:00 -03:00
c3d48c47cc Renamed CMS_RESPONSE.add_..hook with subscribe_to_..._hook
Renamed CMS_RESPONSE.call_..hook  with invoke_..._hook
Renamed CMS_HOOK_VALUE_ALTER as CMS_HOOK_VALUE_TABLE_ALTER
Renamed CMS_HOOK_MENU_ALTER as CMS_HOOK_MENU_SYSTEM_ALTER
Added new CMS_HOOK_MENU_ALTER that acts on CMS_MENU object.

Cosmetic, comments.
2014-11-12 16:12:42 +01:00
jvelilla
96ceb2481a Merge pull request #4 from jvelilla/roc_template
Roc template
2014-11-12 07:07:12 -03:00
jvelilla
590bd8fc3a Merge pull request #1 from jocelyn/roc_template_jfiat
Reversed dependencies between CMS_SETUP and CMS_API(_SERVICE).
2014-11-12 06:44:37 -03:00
96da59c4cb Added notion of "front" page.
Changed CMS_HOOK_BLOCK.get_block_view to accept only attached string for `a_block_id'.
Keep simple name in CMS_MENU_SYSTEM.
Module that implements a CMS_HOOK need now to redefine CMS_MODULE.register_hooks .
Added simple code for NODE_MODULE, in order to see something.
Added CMS_URL_UTILITIES that should be used to compute url for cms path such as "/foo/bar".
Implemented get_active in CMS_RESPONSE to update the "is_active" on each link.
Added NOT_IMPLEMENTED_ERROR_CMS_RESPONSE.
Implemented a few hooks in DEMO module, for testing.
Updated smarty template related code.
2014-11-10 19:22:01 +01:00
b0930299fc Fixed assertion violation when DATABASE_NULL is instanciated. 2014-11-10 15:00:00 +01:00
abe9de621e Made examples/api compilable. 2014-11-10 14:59:30 +01:00
241b003542 Renamed CMS_API_SERVICE as CMS_API .
Reversed the design, and break dependency CMS_SETUP => CMS_API .
Now CMS_API has attribute setup: CMS_SETUP .
Moved error_handler from CMS_SETUP to CMS_API.
The instance of CMS_SETUP is used when instanciating modules.
The instance of CMS_API is used when instanciating CMS_REPONSE and Handlers/Filters.
The instance of CMS_API is passed as argument to build the CMS_MODULE.router and filter.
2014-11-10 14:59:17 +01:00
jvelilla
730f6d42a4 Updated Node module and theme to use the new rendering strategy. 2014-11-08 06:10:43 -03:00
jvelilla
75d34870fa Merged Old CMS code with new CMS code.
Pending: Update code to use the new theme
2014-11-07 18:23:25 -03:00
jvelilla
2c130cf882 Update theme information defining a navigation strategy
Updated code to use a new navigation strategy.
2014-11-07 09:15:30 -03:00
jvelilla
223a5fafdb Updated page header template 2014-11-07 07:52:44 -03:00
jvelilla
f1b911b6e3 Updated block and template to render regions 2014-11-06 22:33:48 -03:00
jvelilla
b90e3b3df0 Added a CMS_ENCODER utility class.
Added a block header template: smarty engine.
Added a menu template: smarty engine.
2014-11-05 07:45:36 -03:00
jvelilla
bafdc085d9 Added refactoring helper class to add comments. 2014-11-04 11:31:43 -03:00
jvelilla
b11462105a Initial implementation with Hooks, Regions and Templates
Updated Modules to support hooks, still work in progress.
2014-11-03 12:40:54 -03:00
jvelilla
5cb26f0b24 Updated Peristance layer to use the new error_hanler based on EWF error library.
Remove once use from DATABASE_ERROR_HANDLER.
Initial support transaction handling.
2014-10-17 08:53:02 -03:00
jvelilla
3c73202a0d Initial Import Model Library 2014-10-15 19:41:47 -03:00
jvelilla
8a06dc11ac Merge branch 'roc_pe' of https://github.com/jocelyn/ROC into roc_pe
Conflicts:
	cms/cms-safe.ecf
2014-10-14 17:22:40 -03:00
jvelilla
ab76a752d7 Added nested transaction support.
Added test cases showing transaction support scenarios.
2014-10-14 17:59:45 +02:00
jvelilla
4b9a692c2c Initial Import: Database transaction handling.
Initial Import: Error handling using ewf error library.
Added a CMS_ERROR_FILTER as part of registered filters of CMS_SERVICE
2014-10-14 17:59:45 +02:00
jvelilla
b8257e7bf0 Clean code: removed unused variables.
Move BASIC_AUTH module to ROC_SERVER setup, as an example
of module extension
2014-10-14 17:58:01 +02:00
4841039d4a Renamed void-safe ecf using -safe.ecf convention.
Added a cms_demo_module, for now pretty empty, but it will be used to develop/test the cms core.
2014-10-14 15:24:24 +02:00
jvelilla
609d71a0e9 Added nested transaction support.
Added test cases showing transaction support scenarios.
2014-10-13 18:45:45 -03:00
jvelilla
8d79447cf8 Initial Import: Database transaction handling.
Initial Import: Error handling using ewf error library.
Added a CMS_ERROR_FILTER as part of registered filters of CMS_SERVICE
2014-10-09 10:01:49 -03:00
jvelilla
36dc48125c Clean code: removed unused variables.
Move BASIC_AUTH module to ROC_SERVER setup, as an example
of module extension
2014-10-08 16:33:41 -03:00
jvelilla
d183ab8130 Merge pull request #3 from jocelyn/jfiat_roc_auth
Various design changes
2014-10-08 14:45:51 -03:00
6fc38272fe Merged back list of available modules in CMS_SETUP. 2014-10-08 19:32:30 +02:00
51e1058409 Redesign part of CMS_MODULE, and implementation.
Prepare the module before creating the service.
Remove the possibility to add module after the creation of the service.
Renamed CMS_MODULE_CONFIGURATOR as CMS_MODULE_COLLECTION.
2014-10-08 17:04:34 +02:00
jvelilla
965b0e9f7d Added CMS_MODULE_CONFIGURATOR.
Added a default implementation of CMS_MODULE_CONGIRATOR.
Updated CMS_SERVICE, to use the new CMS_MODULE_CONFIGURATOR.
Updated Example.
2014-10-08 14:36:16 +02:00
c94e5391e9 Layout: got rid of onces per thread function.
Renamed `launch_cms' as `initialize_cms' which reflects better the implementation.
Minor cosmetic or warning changes.
2014-10-08 14:24:49 +02:00
jvelilla
b004ac8ae0 Merge branch 'jvelilla-roc_auth' 2014-10-02 21:02:06 -03:00
jvelilla
c3e23e1697 Merge branch 'roc_auth' of https://github.com/jvelilla/ROC into jvelilla-roc_auth
Conflicts:
	cms/src/service/cms_service.e
2014-10-02 21:01:32 -03:00
jvelilla
3fe166b768 Updated CMS libary:
Initial Basic Authentication Node with filters.
Updated ROC API to use the new module.
2014-10-02 20:52:14 -03:00
jvelilla
a0cb7c0ecc Added Initial Basic Auth Module 2014-10-02 15:32:30 -03:00
jvelilla
e053ffceef Fixed issue with Filters. 2014-10-02 12:00:10 -03:00
435 changed files with 18634 additions and 20303 deletions

3
.gitignore vendored
View File

@@ -1,4 +1,5 @@
EIFGENs
*.swp
*.log*
*.rc
*.rc
*.bak

34
README.md Normal file
View File

@@ -0,0 +1,34 @@
Eiffel CMS Library
===============
Eiffel CMS library is build with [EWF](http://eiffelwebframework.github.io/EWF/) and inspired by [Drupal](https://www.drupal.org/).
The goal of the library is to provide the following features.
- content type
- user management
- module design
- theme
- API
**Directory Structure**
- library --Library
- layout -- application layout library.
- model -- domain model library.
- persistence -- persistence layer library.
- src -- cms source code.
- example
- demo -- example using the cms library.
- doc -- Documentation.
**Documentation**
>[CMS concepts](/doc/concepts.md).
>[CMS design](/doc/design.md).
>[CMS tutorial](/doc/tutorial.md).

View File

@@ -2,24 +2,30 @@
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="cms" uuid="8CC0D052-57D1-4CAA-AFF1-448FA290734B" library_target="cms">
<target name="cms">
<root all_classes="true"/>
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
<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>
<mapping old_name="CMS_LAYOUT" new_name="CMS_ENVIRONMENT"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-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="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="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
<library name="layout" location="..\layout\layout.ecf"/>
<library name="persistence_mysql" location="..\persistence\implementation\mysql\persistence_mysql.ecf" readonly="false"/>
<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"/>
<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"/>
<cluster name="src" location=".\src\" recursive="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
</cluster>
<library name="wsf_html" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf_html\wsf_html-safe.ecf" readonly="false"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
</system>

31
cms.ecf Normal file
View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="cms" uuid="8CC0D052-57D1-4CAA-AFF1-448FA290734B" library_target="cms">
<target name="cms">
<root all_classes="true"/>
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="false" void_safety="none" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<mapping old_name="CMS_LAYOUT" new_name="CMS_ENVIRONMENT"/>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="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="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json.ecf" readonly="false"/>
<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="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"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf.ecf"/>
<library name="wsf_html" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf_html\wsf_html.ecf" readonly="false"/>
<library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension.ecf" readonly="false"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
</system>

View File

@@ -1,298 +0,0 @@
class
CMS_CONFIGURATION
inherit
ANY
SHARED_EXECUTION_ENVIRONMENT
export
{NONE} all
end
create
make
feature {NONE} -- Initialization
make (a_layout: CMS_LAYOUT)
-- Initialize `Current'.
local
p: PATH
do
layout := a_layout
create options.make_equal (10)
configuration_location := layout.cms_config_ini_path
import_from_path (layout.cms_config_ini_path)
analyze
end
analyze
do
get_root_location
get_var_location
get_themes_location
get_files_location
end
feature -- Access
configuration_location: detachable PATH
option (a_name: READABLE_STRING_GENERAL): detachable ANY
do
Result := options.item (a_name)
end
options: STRING_TABLE [STRING_32]
feature -- Conversion
append_to_string (s: STRING)
local
utf: UTF_CONVERTER
do
s.append ("Options:%N")
across
options as c
loop
s.append (c.key.to_string_8)
s.append_character ('=')
utf.string_32_into_utf_8_string_8 (c.item, s)
s.append_character ('%N')
end
s.append ("Specific:%N")
s.append ("root_location=" + root_location.utf_8_name + "%N")
s.append ("var_location=" + var_location.utf_8_name + "%N")
s.append ("files_location=" + files_location.utf_8_name + "%N")
s.append ("themes_location=" + themes_location.utf_8_name + "%N")
end
feature -- Element change
set_option (a_name: READABLE_STRING_GENERAL; a_value: STRING_32)
do
options.force (a_value, a_name.as_string_8)
end
feature -- Access
var_location: PATH
root_location: PATH
files_location: PATH
themes_location: PATH
theme_name (dft: detachable like theme_name): READABLE_STRING_8
do
if attached options.item ("theme") as s then
Result := s
elseif dft /= Void then
Result := dft
else
Result := "default"
end
end
site_id: READABLE_STRING_8
do
if attached options.item ("site.id") as s then
Result := s
else
Result := "_EWF_CMS_NO_ID_"
end
end
site_name (dft: like site_name): READABLE_STRING_8
do
if attached options.item ("site.name") as s then
Result := s
else
Result := dft
end
end
site_url (dft: like site_url): READABLE_STRING_8
do
if attached options.item ("site.url") as s then
Result := s
else
Result := dft
end
if Result /= Void then
if Result.is_empty then
-- ok
elseif not Result.ends_with ("/") then
Result := Result + "/"
end
end
end
site_script_url (dft: like site_script_url): detachable READABLE_STRING_8
do
if attached options.item ("site.script_url") as s then
Result := s
else
Result := dft
end
if Result /= Void then
if Result.is_empty then
elseif not Result.ends_with ("/") then
Result := Result + "/"
end
end
end
site_email (dft: like site_email): READABLE_STRING_8
do
if attached options.item ("site.email") as s then
Result := s
else
Result := dft
end
end
feature -- Change
get_var_location
local
utf: UTF_CONVERTER
do
if attached options.item ("var-dir") as s then
create var_location.make_from_string (utf.utf_8_string_8_to_escaped_string_32 (s))
else
var_location := execution_environment.current_working_path
end
end
get_root_location
local
utf: UTF_CONVERTER
do
root_location := layout.www_path
end
get_files_location
local
utf: UTF_CONVERTER
do
if attached options.item ("files-dir") as s then
create files_location.make_from_string (utf.utf_8_string_8_to_escaped_string_32 (s))
else
create files_location.make_from_string ("files")
end
end
get_themes_location
local
utf: UTF_CONVERTER
do
if attached options.item ("themes-dir") as s then
create themes_location.make_from_string (utf.utf_8_string_8_to_escaped_string_32 (s))
else
themes_location := root_location.extended ("themes")
end
end
feature {NONE} -- Implementation
import_from_file (fn: READABLE_STRING_GENERAL)
do
import_from_path (create {PATH}.make_from_string (fn))
end
import_from_path (a_filename: PATH)
-- Import ini file content
local
f: PLAIN_TEXT_FILE
l,v: STRING_8
p: INTEGER
do
create f.make_with_path (a_filename)
if f.exists and f.is_readable then
f.open_read
from
f.read_line
until
f.exhausted
loop
l := f.last_string
l.left_adjust
if not l.is_empty then
if l[1] = '#' then
-- commented line
else
p := l.index_of ('=', 1)
if p > 1 then
v := l.substring (p + 1, l.count)
l.keep_head (p - 1)
v.left_adjust
v.right_adjust
l.right_adjust
if l.is_case_insensitive_equal ("@include") then
import_from_file (resolved_string (v))
else
set_option (l.as_lower, resolved_string (v))
end
end
end
end
f.read_line
end
f.close
end
end
feature {NONE} -- Environment
resolved_string (s: READABLE_STRING_8): STRING_32
-- Resolved `s' using `options' or else environment variables.
local
i,n,b,e: INTEGER
k: detachable READABLE_STRING_8
do
from
i := 1
n := s.count
create Result.make (s.count)
until
i > n
loop
if i + 1 < n and then s[i] = '$' and then s[i+1] = '{' then
b := i + 2
e := s.index_of ('}', b) - 1
if e > 0 then
k := s.substring (b, e)
if attached option (k) as v then
if attached {READABLE_STRING_32} v as s32 then
Result.append (s32)
else
Result.append (v.out)
end
i := e + 1
elseif attached execution_environment.item (k) as v then
Result.append (v)
i := e + 1
else
Result.extend (s[i])
end
else
Result.extend (s[i])
end
else
Result.extend (s[i])
end
i := i + 1
end
end
feature -- Implementation
layout: CMS_LAYOUT
-- Cms layout
end

View File

@@ -1,123 +0,0 @@
note
description: "Summary description for {CMS_DEFAULT_SETUP}."
date: "$Date$"
revision: "$Revision$"
class
CMS_DEFAULT_SETUP
inherit
CMS_SETUP
REFACTORING_HELPER
create
make
feature {NONE} -- Initialization
make (a_layout: CMS_LAYOUT)
do
layout := a_layout
create configuration.make (layout)
site_id := configuration.site_id
site_url := configuration.site_url ("")
site_name := configuration.site_name ("EWF::CMS")
site_email := configuration.site_email ("webmaster")
site_dir := configuration.root_location
site_var_dir := configuration.var_location
files_location := configuration.files_location
themes_location := configuration.themes_location
theme_name := configuration.theme_name ("default")
compute_theme_location
compute_theme_resource_location
initialize
end
initialize
do
build_api_service
build_auth_engine
build_mailer
build_modules
end
feature -- Access
modules: ARRAYED_LIST [CMS_MODULE]
-- List of possible modules
is_html: BOOLEAN
-- <Precursor>
do
-- Enable change the mode
Result := (create {CMS_JSON_CONFIGURATION}).is_html_mode(layout.application_config_path)
end
is_web: BOOLEAN
-- <Precursor>
do
Result := (create {CMS_JSON_CONFIGURATION}).is_web_mode(layout.application_config_path)
end
feature {NONE} -- Initialization
build_modules
-- Core modules. (User, Admin, Node)
-- At the moment only node is supported.
local
m: CMS_MODULE
do
create modules.make (3)
-- -- Core
-- create {USER_MODULE} m.make
-- m.enable
-- modules.extend (m)
-- create {ADMIN_MODULE} m.make
-- m.enable
-- modules.extend (m)
create {NODE_MODULE} m.make (Current)
m.enable
modules.extend (m)
end
build_api_service
local
dn: PATH
l_database: DATABASE_CONNECTION
do
to_implement ("Refactor database setup")
if attached (create {JSON_CONFIGURATION}).new_database_configuration (layout.application_config_path) as l_database_config then
create {DATABASE_CONNECTION_MYSQL} l_database.login_with_connection_string (l_database_config.connection_string)
create api_service.make (create {CMS_STORAGE_MYSQL}.make (l_database))
else
create {DATABASE_CONNECTION_NULL} l_database.make_common
create api_service.make (create {CMS_STORAGE_NULL})
end
end
build_auth_engine
do
to_implement ("Not implemented authentication")
end
build_mailer
do
to_implement ("Not implemented mailer")
end
feature -- Change
add_module (m: CMS_MODULE)
-- Add a module `m' to the list of modules `modules'.
do
modules.force (m)
end
end

View File

@@ -1,47 +0,0 @@
note
description: "Summary description for {CMS_JSON_CONFIGURATION}."
date: "$Date$"
revision: "$Revision$"
class
CMS_JSON_CONFIGURATION
inherit
JSON_CONFIGURATION
feature -- Access
is_html_mode (a_path: PATH): BOOLEAN
-- Is the server running on web mode?
local
l_parser: JSON_PARSER
do
if attached json_file_from (a_path) as json_file then
l_parser := new_json_parser (json_file)
if attached {JSON_OBJECT} l_parser.parse as jv and then l_parser.is_parsed and then
attached {JSON_OBJECT} jv.item ("server") as l_server and then
attached {JSON_STRING} l_server.item ("mode") as l_mode then
Result := l_mode.item.is_case_insensitive_equal_general ("html")
end
end
end
is_web_mode (a_path: PATH): BOOLEAN
-- Is the server running on web mode?
local
l_parser: JSON_PARSER
do
if attached json_file_from (a_path) as json_file then
l_parser := new_json_parser (json_file)
if attached {JSON_OBJECT} l_parser.parse as jv and then l_parser.is_parsed and then
attached {JSON_OBJECT} jv.item ("server") as l_server and then
attached {JSON_STRING} l_server.item ("mode") as l_mode then
Result := l_mode.item.is_case_insensitive_equal_general ("web")
end
end
end
end

View File

@@ -1,32 +0,0 @@
note
description: "Summary description for {CMS_LAYOUT}."
date: "$Date$"
revision: "$Revision$"
class
CMS_LAYOUT
inherit
APPLICATION_LAYOUT
create
make_default,
make_with_path
feature -- Access
theme_path: PATH
-- Directory for templates (HTML, etc).
once
Result := www_path.extended ("theme")
end
cms_config_ini_path: PATH
-- Database Configuration file path.
once
Result := config_path.extended ("cms.ini")
end
end

View File

@@ -1,85 +0,0 @@
note
description: "Summary description for {CMS_SETUP}."
date: "$Date$"
revision: "$Revision$"
deferred class
CMS_SETUP
feature -- Access
configuration: CMS_CONFIGURATION
-- cms configuration.
layout: CMS_LAYOUT
-- CMS layout.
api_service: CMS_API_SERVICE
-- cms api service.
modules: LIST[CMS_MODULE]
-- Possible list of modules.
-- |If we remove Modules from setup.
-- |we can let the CMS_SERVICE define the basic modules.
deferred
end
is_html: BOOLEAN
-- api with progresive enhacements css and js, server side rendering.
deferred
end
is_web: BOOLEAN
-- web: Web Site with progresive enhacements css and js and Ajax calls.
deferred
end
feature -- Access: Site
site_id: READABLE_STRING_8
site_name: READABLE_STRING_32
site_email: READABLE_STRING_8
site_url: READABLE_STRING_8
site_dir: PATH
site_var_dir: PATH
files_location: PATH
feature -- Access:Theme
themes_location: PATH
theme_location: PATH
theme_resource_location: PATH
--
theme_information_location: PATH
-- theme informations.
do
Result := theme_location.extended ("theme.info")
end
theme_name: READABLE_STRING_32
-- theme name
feature -- Compute location
compute_theme_location
do
theme_location := themes_location.extended (theme_name)
end
compute_theme_resource_location
-- assets (js, css, images, etc)
-- Not used at the moment.
do
theme_resource_location := theme_location
end
end

View File

@@ -1,48 +0,0 @@
note
description: "Summary description for {WSF_CMS_MODULE}."
date: "$Date$"
revision: "$Revision$"
deferred class
CMS_MODULE
feature -- Access
is_enabled: BOOLEAN
name: STRING
description: STRING
package: STRING
version: STRING
feature -- Router
router: WSF_ROUTER
-- Router configuration.
deferred
end
feature -- Settings
enable
do
is_enabled := True
end
disable
do
is_enabled := False
end
feature -- Hooks
help_text (a_path: STRING): STRING
do
create Result.make_empty
end
end

View File

@@ -1,59 +0,0 @@
note
description: "Summary description for {NODES_HANDLER}."
date: "$Date$"
revision: "$Revision$"
class
NODES_HANDLER
inherit
CMS_HANDLER
WSF_FILTER
WSF_URI_HANDLER
rename
execute as uri_execute,
new_mapping as new_uri_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)
execute_next (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
l_page: CMS_RESPONSE
do
-- At the moment the template is hardcoded, but we can
-- get them from the configuration file and load them into
-- the setup class.
create {GENERIC_VIEW_CMS_RESPONSE} l_page.make (req, res, setup, "modules/nodes")
l_page.add_variable (api_service.nodes, "nodes")
l_page.execute
end
end

View File

@@ -1,127 +0,0 @@
note
description: "Summary description for {CMS_MODULE}."
date: "$Date$"
revision: "$Revision$"
class
NODE_MODULE
inherit
CMS_MODULE
create
make
feature {NONE} -- Initialization
make (a_config: CMS_SETUP)
do
name := "node"
version := "1.0"
description := "Service to manage content based on 'node'"
package := "core"
config := a_config
setup_router
enable
end
feature -- Access
router: WSF_ROUTER
-- Node router.
config: CMS_SETUP
-- Node configuration.
feature -- Implementation
setup_router
-- Setup `router'.
do
create router.make (5)
configure_api_node
configure_api_nodes
configure_api_node_title
configure_api_node_summary
configure_api_node_content
end
feature -- Configure Node Resources Routes
configure_api_node
local
l_node_handler: NODE_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_node_handler.make (config)
create l_methods
l_methods.enable_get
l_methods.enable_post
l_methods.enable_put
router.handle_with_request_methods ("/node", l_node_handler, l_methods)
create l_node_handler.make (config)
create l_methods
l_methods.enable_get
l_methods.enable_post
l_methods.enable_put
l_methods.enable_delete
router.handle_with_request_methods ("/node/{id}", l_node_handler, l_methods)
end
configure_api_nodes
local
l_nodes_handler: NODES_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_nodes_handler.make (config)
create l_methods
l_methods.enable_get
router.handle_with_request_methods ("/nodes", l_nodes_handler, l_methods)
end
configure_api_node_summary
local
l_report_handler: NODE_SUMMARY_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_report_handler.make (config)
create l_methods
l_methods.enable_get
l_methods.enable_post
l_methods.enable_put
router.handle_with_request_methods ("/node/{id}/summary", l_report_handler, l_methods)
end
configure_api_node_title
local
l_report_handler: NODE_TITLE_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_report_handler.make (config)
create l_methods
l_methods.enable_get
l_methods.enable_post
l_methods.enable_put
router.handle_with_request_methods ("/node/{id}/title", l_report_handler, l_methods)
end
configure_api_node_content
local
l_report_handler: NODE_CONTENT_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_report_handler.make (config)
create l_methods
l_methods.enable_get
l_methods.enable_post
l_methods.enable_put
router.handle_with_request_methods ("/node/{id}/content", l_report_handler, l_methods)
end
end

View File

@@ -1,127 +0,0 @@
note
description: "Summary description for {CMS_API_SERVICE}."
date: "$Date$"
revision: "$Revision$"
class
CMS_API_SERVICE
inherit
SHARED_ERROR
REFACTORING_HELPER
create make
feature -- Initialize
make (a_storage: CMS_STORAGE)
-- Create the API service with an storege `a_storage'.
do
storage := a_storage
set_successful
ensure
storage_set: storage = a_storage
end
feature -- Access
login_valid (l_auth_login, l_auth_password: READABLE_STRING_32): BOOLEAN
local
l_security: SECURITY_PROVIDER
do
Result := storage.is_valid_credential (l_auth_login, l_auth_password)
end
feature -- Access: Node
nodes: LIST[CMS_NODE]
-- List of nodes.
do
fixme ("Implementation")
Result := storage.recent_nodes (0, 10)
end
recent_nodes (a_offset, a_rows: INTEGER): LIST[CMS_NODE]
-- List of the `a_rows' most recent nodes starting from `a_offset'.
do
Result := storage.recent_nodes (a_offset, a_rows)
end
node (a_id: INTEGER_64): detachable CMS_NODE
-- Node by ID.
do
fixme ("Check preconditions")
Result := storage.node (a_id)
end
feature -- Change: Node
new_node (a_node: CMS_NODE)
-- Add a new node
do
storage.save_node (a_node)
end
delete_node (a_id: INTEGER_64)
do
storage.delete_node (a_id)
end
update_node (a_id: like {CMS_USER}.id; a_node: CMS_NODE)
do
storage.update_node (a_id,a_node)
end
update_node_title (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_title: READABLE_STRING_32)
do
fixme ("Check preconditions")
storage.update_node_title (a_id,a_node_id,a_title)
end
update_node_summary (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_summary: READABLE_STRING_32)
do
fixme ("Check preconditions")
storage.update_node_summary (a_id,a_node_id, a_summary)
end
update_node_content (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_content: READABLE_STRING_32)
do
fixme ("Check preconditions")
storage.update_node_content (a_id,a_node_id, a_content)
end
feature -- Access: User
user_by_name (a_username: READABLE_STRING_32): detachable CMS_USER
do
Result := storage.user_by_name (a_username)
end
feature -- Change User
new_user (a_user: CMS_USER)
-- Add a new user `a_user'.
do
if
attached a_user.password as l_password and then
attached a_user.email as l_email
then
storage.save_user (a_user)
else
fixme ("Add error")
end
end
feature {NONE} -- Implemenataion
storage: CMS_STORAGE
-- Persistence storage
end

View File

@@ -1,156 +0,0 @@
note
description: "[
This class implements the CMS service
It could be used to implement the main EWF service, or
even for a specific handler.
]"
class
CMS_SERVICE
inherit
WSF_ROUTED_SKELETON_SERVICE
undefine
requires_proxy
redefine
execute_default
end
WSF_FILTERED_SERVICE
WSF_FILTER
rename
execute as execute_filter
end
WSF_NO_PROXY_POLICY
WSF_URI_HELPER_FOR_ROUTED_SERVICE
WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE
REFACTORING_HELPER
SHARED_LOGGER
create
make
feature {NONE} -- Initialization
make (a_setup: CMS_SETUP)
do
setup := a_setup
configuration := a_setup.configuration
modules := a_setup.modules
initialize_users
initialize_auth_engine
initialize_mailer
initialize_router
initialize_modules
end
initialize_users
do
end
initialize_mailer
do
to_implement ("To Implement mailer")
end
setup_router
do
configure_api_root
end
initialize_modules
-- Intialize modules, import router definitions
-- from enabled modules.
do
log.write_debug (generator + ".initialize_modules")
across
modules as m
loop
if m.item.is_enabled then
router.import (m.item.router)
end
end
configure_api_file_handler
end
initialize_auth_engine
do
to_implement ("To Implement authentication engine")
end
configure_api_root
local
l_root_handler: CMS_ROOT_HANDLER
l_methods: WSF_REQUEST_METHODS
do
log.write_debug (generator + ".configure_api_root")
create l_root_handler.make (setup)
create l_methods
l_methods.enable_get
router.handle_with_request_methods ("/", l_root_handler, l_methods)
end
configure_api_file_handler
local
fhdl: WSF_FILE_SYSTEM_HANDLER
do
log.write_debug (generator + ".configure_api_file_handler")
create fhdl.make_hidden_with_path (setup.layout.www_path)
fhdl.disable_index
fhdl.set_not_found_handler (agent (ia_uri: READABLE_STRING_8; ia_req: WSF_REQUEST; ia_res: WSF_RESPONSE)
do
execute_default (ia_req, ia_res)
end)
router.handle_with_request_methods ("/", fhdl, router.methods_GET)
end
feature -- Access
setup: CMS_SETUP
-- CMS setup.
configuration: CMS_CONFIGURATION
-- CMS configuration.
-- | Maybe we can compute it (using `setup') instead of using memory.
modules: LIST [CMS_MODULE]
-- List of possible modules.
-- | Maybe we can compute it (using `setup') instead of using memory.
feature -- Logging
feature -- Notification
feature -- Execution
execute_default (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Default request handler if no other are relevant
local
do
fixme ("To Implement")
end
note
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -1,36 +0,0 @@
note
description: "Summary description for {CMS_HANDLER}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
CMS_HANDLER
inherit
CMS_REQUEST_UTIL
SHARED_LOGGER
REFACTORING_HELPER
feature {NONE} -- Initialization
make (a_setup: CMS_SETUP)
do
setup := a_setup
end
feature -- Setup
setup: CMS_SETUP
feature -- API Service
api_service: CMS_API_SERVICE
do
Result := setup.api_service
end
end

View File

@@ -1,62 +0,0 @@
note
description: "Summary description for {CMS_GENERIC_RESPONSE}."
date: "$Date$"
revision: "$Revision$"
class
CMS_GENERIC_RESPONSE
feature -- Responses
new_response_redirect (req: WSF_REQUEST; res: WSF_RESPONSE; a_location: READABLE_STRING_32)
-- Redirect to `a_location'
local
h: HTTP_HEADER
do
create h.make
h.put_content_type_text_html
h.put_current_date
h.put_location (a_location)
res.set_status_code ({HTTP_STATUS_CODE}.see_other)
res.put_header_text (h.string)
end
new_response_authenticate (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Handle authenticate.
local
h: HTTP_HEADER
do
create h.make
h.put_content_type_text_html
h.put_current_date
h.put_header_key_value ({HTTP_HEADER_NAMES}.header_www_authenticate, "Basic realm=%"CMS-User%"")
res.set_status_code ({HTTP_STATUS_CODE}.unauthorized)
res.put_header_text (h.string)
end
new_response_denied (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Handle access denied.
local
h: HTTP_HEADER
do
create h.make
h.put_content_type_text_html
h.put_current_date
res.set_status_code ({HTTP_STATUS_CODE}.unauthorized)
res.put_header_text (h.string)
end
new_response_unauthorized (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Handle not authorized.
local
h: HTTP_HEADER
output: STRING
do
create h.make
h.put_content_type_text_html
h.put_current_date
res.set_status_code ({HTTP_STATUS_CODE}.forbidden)
res.put_header_text (h.string)
end
end

View File

@@ -1,190 +0,0 @@
note
description: "Generic CMS Response, place to add HOOKS features as collaborators."
date: "$Date$"
revision: "$Revision$"
deferred class
CMS_RESPONSE
inherit
CMS_REQUEST_UTIL
REFACTORING_HELPER
feature {NONE} -- Initialization
make (req: WSF_REQUEST; res: WSF_RESPONSE; a_setup: like setup; a_template: like template)
do
status_code := {HTTP_STATUS_CODE}.ok
setup := a_setup
request := req
response := res
template := a_template
create header.make
initialize
end
initialize
do
get_theme
end
feature -- Access
request: WSF_REQUEST
response: WSF_RESPONSE
setup: CMS_SETUP
-- Current setup
status_code: INTEGER
header: WSF_HEADER
title: detachable READABLE_STRING_32
page_title: detachable READABLE_STRING_32
-- Page title
main_content: detachable STRING_8
template: READABLE_STRING_32
-- Current template.
feature -- Element change
set_title (t: like title)
do
title := t
set_page_title (t)
end
set_page_title (t: like page_title)
do
page_title := t
end
set_main_content (s: like main_content)
do
main_content := s
end
feature -- Theme
theme: CMS_THEME
-- Current theme
get_theme
local
l_info: CMS_THEME_INFORMATION
do
if attached setup.theme_information_location as fn then
create l_info.make (fn)
else
create l_info.make_default
end
if l_info.engine.is_case_insensitive_equal_general ("smarty") then
create {SMARTY_CMS_THEME} theme.make (setup, l_info, template)
else
create {DEFAULT_CMS_THEME} theme.make (setup, l_info)
end
end
feature -- Element Change
set_status_code (a_status: INTEGER)
-- Set `status_code' with `a_status'.
note
EIS: "src=eiffel:?class=HTTP_STATUS_CODE"
do
to_implement ("Feature to test if a_status is a valid status code!!!.")
status_code := a_status
ensure
status_code_set: status_code = a_status
end
feature -- Generation
prepare (page: CMS_HTML_PAGE)
do
common_prepare (page)
custom_prepare (page)
end
common_prepare (page: CMS_HTML_PAGE)
do
fixme ("Fix generacion common")
page.register_variable (request.absolute_script_url (""), "host")
page.register_variable (setup.is_web, "web")
page.register_variable (setup.is_html, "html")
if attached current_user_name (request) as l_user then
page.register_variable (l_user, "user")
end
end
custom_prepare (page: CMS_HTML_PAGE)
do
end
feature -- Custom Variables
variables: detachable STRING_TABLE[ANY]
-- Custom variables to feed the templates.
feature -- Element change: Add custom variables.
add_variable (a_element: ANY; a_key:READABLE_STRING_32)
local
l_variables: like variables
do
l_variables := variables
if l_variables = Void then
create l_variables.make (5)
variables := l_variables
end
l_variables.force (a_element, a_key)
end
feature -- Execution
execute
do
begin
process
terminate
end
feature {NONE} -- Execution
begin
do
end
process
deferred
end
frozen terminate
local
cms_page: CMS_HTML_PAGE
page: CMS_HTML_PAGE_RESPONSE
do
create cms_page.make
prepare (cms_page)
create page.make (theme.page_html (cms_page))
page.set_status_code (status_code)
response.send (page)
on_terminated
end
on_terminated
do
end
end

View File

@@ -1,48 +0,0 @@
note
description: "Summary description for {WSF_CMS_THEME}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
CMS_THEME
feature {NONE} -- Access
setup: CMS_SETUP
feature -- Access
name: STRING
deferred
end
regions: ARRAY [STRING]
deferred
end
page_template: CMS_TEMPLATE
deferred
end
feature -- Conversion
page_html (page: CMS_HTML_PAGE): STRING_8
-- Render `page' as html.
deferred
end
feature {NONE} -- Implementation
note
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -1,100 +0,0 @@
note
description: "Summary description for {CMS_HTML_TEMPLATE}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
DEFAULT_CMS_HTML_TEMPLATE
inherit
CMS_HTML_TEMPLATE
DEFAULT_CMS_TEMPLATE
create
make
feature {NONE} -- Initialization
make (t: DEFAULT_CMS_THEME)
do
theme := t
create variables.make (0)
end
variables: STRING_TABLE [detachable ANY]
feature -- Access
register (v: STRING_8; k: STRING_8)
do
variables.force (v, k)
end
theme: DEFAULT_CMS_THEME
prepare (page: CMS_HTML_PAGE)
do
variables.make (10)
across
page.variables as ic
loop
variables.force (ic.item, ic.key)
end
if attached page.title as l_title then
variables.force (l_title, "title")
variables.force (l_title, "head_title")
else
variables.force ("", "title")
variables.force ("", "head_title")
end
variables.force (page.language, "language")
variables.force (page.head_lines_to_string, "head_lines")
end
to_html (page: CMS_HTML_PAGE): STRING
do
-- Process html generation
create Result.make_from_string (template)
apply_template_engine (Result)
end
feature {NONE} -- Implementation
template: STRING
once
Result := "[
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="$language" lang="$language" version="XHTML+RDFa 1.0" dir="ltr">
<head>
$head
<title>$head_title</title>
$styles
$scripts
$head_lines
</head>
<body class="$body_classes" $body_attributes>
$page_top
$page
$page_bottom
</body>
</html>
]"
end
note
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -1,102 +0,0 @@
note
description: "Summary description for {CMS_PAGE_TEMPLATE}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
DEFAULT_CMS_PAGE_TEMPLATE
inherit
CMS_PAGE_TEMPLATE
DEFAULT_CMS_TEMPLATE
create
make
feature {NONE} -- Initialization
make (t: DEFAULT_CMS_THEME)
do
theme := t
create variables.make (0)
end
variables: STRING_TABLE [detachable ANY]
feature -- Access
theme: DEFAULT_CMS_THEME
prepare (page: CMS_HTML_PAGE)
do
variables.make (10)
across
page.variables as ic
loop
variables.force (ic.item, ic.key)
end
if attached page.title as l_title then
variables.force (l_title, "title")
else
variables.force ("", "title")
end
across
theme.regions as r
loop
variables.force (page.region (r.item), r.item)
end
end
to_html (page: CMS_HTML_PAGE): STRING
do
-- Process html generation
create Result.make_from_string (template)
apply_template_engine (Result)
end
feature -- Registration
register (v: STRING_8; k: STRING_8)
do
variables.force (v, k)
end
feature {NONE} -- Implementation
template: STRING
once
Result := "[
<div id="page-wrapper">
<div id="page">
<div id="header">
$header
</div>
<div id="main-wrapper">
<div id="main">
<div id="first_sidebar" class="sidebar $first_sidebar_css_class">$first_sidebar</div>
<div id="content" class="$content_css_class">$content</div>
<div id="second_sidebar" class="sidebar $second_sidebar_css_class">$second_sidebar</div>
</div>
</div>
<div id="footer">$footer</div>
</div>
</div>
]"
end
note
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -1,96 +0,0 @@
note
description: "Summary description for {CMS_THEME}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
DEFAULT_CMS_THEME
inherit
CMS_THEME
create
make
feature {NONE} -- Initialization
make (a_setup: like setup; a_info: like information)
do
setup := a_setup
information := a_info
end
information: CMS_THEME_INFORMATION
feature -- Access
name: STRING = "CMS"
regions: ARRAY [STRING]
once
Result := <<"header", "content", "footer", "first_sidebar", "second_sidebar">>
end
html_template: DEFAULT_CMS_HTML_TEMPLATE
local
tpl: like internal_html_template
do
tpl := internal_html_template
if tpl = Void then
create tpl.make (Current)
internal_html_template := tpl
end
Result := tpl
end
page_template: DEFAULT_CMS_PAGE_TEMPLATE
local
tpl: like internal_page_template
do
tpl := internal_page_template
if tpl = Void then
create tpl.make (Current)
internal_page_template := tpl
end
Result := tpl
end
feature -- Conversion
prepare (page: CMS_HTML_PAGE)
do
-- page.add_style (url ("/theme/style.css", Void), Void)
end
page_html (page: CMS_HTML_PAGE): STRING_8
local
l_content: STRING_8
do
prepare (page)
page_template.prepare (page)
l_content := page_template.to_html (page)
html_template.prepare (page)
html_template.register (l_content, "page")
Result := html_template.to_html (page)
end
feature {NONE} -- Internal
internal_page_template: detachable like page_template
internal_html_template: detachable like html_template
invariant
attached internal_page_template as inv_p implies inv_p.theme = Current
note
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -1,104 +0,0 @@
note
description: "Summary description for {SMARTY_CMS_THEME}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
SMARTY_CMS_THEME
inherit
CMS_THEME
create
make
feature {NONE} -- Initialization
make (a_setup: like setup; a_info: like information; a_template: like template)
do
setup := a_setup
information := a_info
template := a_template
if attached a_info.item ("template_dir") as s then
templates_directory := a_setup.theme_location.extended (s)
else
templates_directory := a_setup.theme_location
end
ensure
setup_set: setup = a_setup
information_set: information = a_info
template_set: template = a_template
end
feature -- Access
name: STRING = "smarty-CMS"
template: STRING;
templates_directory: PATH
information: CMS_THEME_INFORMATION
regions: ARRAY [STRING]
local
i: INTEGER
utf: UTF_CONVERTER
once
if attached information.regions as tb and then not tb.is_empty then
i := 1
create Result.make_filled ("", i, i + tb.count - 1)
across
tb as ic
loop
Result.force (utf.utf_32_string_to_utf_8_string_8 (ic.key), i) -- NOTE: UTF-8 encoded !
i := i + 1
end
else
Result := <<"header", "content", "footer", "first_sidebar", "second_sidebar">>
end
end
page_template: SMARTY_CMS_PAGE_TEMPLATE
local
tpl: like internal_page_template
do
tpl := internal_page_template
if tpl = Void then
create tpl.make (template, Current)
internal_page_template := tpl
end
Result := tpl
end
feature -- Conversion
prepare (page: CMS_HTML_PAGE)
do
end
page_html (page: CMS_HTML_PAGE): STRING_8
do
prepare (page)
page_template.prepare (page)
Result := page_template.to_html (page)
end
feature {NONE} -- Internal
internal_page_template: detachable like page_template
invariant
attached internal_page_template as inv_p implies inv_p.theme = Current
note
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

93
doc/concepts.md Normal file
View File

@@ -0,0 +1,93 @@
CMS Concepts
============
>Current implemented concepts
##### Table of Contents
1. [**Theme**](#theme)
2. [**Regions**](#regions)
- [**Default Page Layout**](#page_layout)
- [**Regions Holds blocks**](#regions_blocks)
3. [**Blocks**](#blocks)
4. [**Modules**](#modules)
5. [**Hooks**](#hooks)
<a name="theme"/>
Theme
-----
In a CMS , a theme is a collection of templates files (HTML, CSS, Images, etc ) that determine how a CMS web site looks. The goal of a theme is to let you change the look and feel of the site.
Eiffel CMS is inspired by Drupal, and use the same default region names as default drupal theme.
#### Important Classes
* [CMS_THEME] (/library/src/theme/cms_theme.e): Abstraction defining the interface of a CMS theme.
* [SMARTY_CMS_THEME] (/library/src/theme/smarty_theme/smarty_cms_theme.e): Theme implemented using the [Eiffel Smarty library] (https://github.com/eiffelhub/template-smarty).
* [CMS_TEMPLATE] (/library/src/theme/cms_template.e): Template Abstraction that contains theme, variables needed by template when rendering page as html. At the moment there is only one implementation SMARTY_CMS_PAGE_TEMPLATE. At the moment there is only one implementation [SMARTY_CMS_PAGE_TEMPLATE] (/library/src/theme/smarty_theme/smarty_cms_page_template.e).
<a name="regions"/>
Regions
-------
The layout of a CMS web page has predefined area called **regions**. The Eiffel CMS uses the same default regions as Drupal, so let's see them in the following image.
<a name="page_layout"/>
![default page layout](http://themery.com/sites/default/files/figure-15-10.png)
```
regions[page_top] = Top
regions[header] = Header
regions[content] = Content
regions[highlighted] = Highlighted
regions[help] = Help
regions[footer] = Footer
regions[first_sidebar] = first sidebar
regions[second_sidebar] = second sidebar
regions[page_bottom] = Bottom
```
<a name="regions_blocks"/>
**A Region holds blocks**
**What goes inside regions?**
Generally, regions hold smaller piece of content called blocks. Blocks hold chunks of content, like the user login form, navigation menu or the information for the footer.
Regions are defined in a configuration file theme.info.
<a name="blocks"/>
CMS_BLOCK
---------
**What is a cms block?**
Blocks are chunk of content that can be created to display whatever you want, and then can be placed in various resgions in your template (theme) layout.
#### Important Classes
* [CMS_BLOCK] (/library/src/kernel/content/cms_block.e): The deferred class CMS_BLOCK provides an abstraction to describe content to be placed inside Regions.
* [CMS_CONTENT_BLOCK] (/library/src/kernel/content/cms_content_block.e): The class CMS_CONTENT_BLOCK describe how to provide generic content.
* [CMS_MENU_BLOCK](/library/src/kernel/content/cms_menu_block.e): The class CMS_MENU_BLOCK describe how to provides a menu of navigational links.
* [CMS_SMARTY_TEMPLATE_BLOCK] (/library/src/kernel/content/cms_smarty_templateblock.e) The class CMS_SMARTY_TEMPLATE_BLOCK describe how to use a CMS block with smarty template file content.
<a name="modules"/>
CMS_MODULES
-----------
**What is a cms module?**
Modules are piece of code that adds one or more features to your web site.
Modules can be plugged and combined to provide a web site customized to your needs. There are modules for many purposes, for example Administratiton, Basic Authentication, etc.
#### Important Classes
* [CMS_MODULE] (/library/src/modules/cms_module.e): The deferred class CMS_MODULE provides an abstraction to describe a generic module that add features to your web site.
* [CMS_RESPONSE](/library/src/service/response/cms_response.e). The deferred class CMS_RESPONSE provide an abstraction to builds the content to get process to render the output.
<a name="hooks">
CMS_HOOK
--------
Hooks is a mechanism which provide a way for modules to interact with each other and extending blocks of the current CMS.
* [CMS_HOOK] (/library/src/hooks/cms_hook.e): The deferred class CMS_HOOK is a marker interface for CMS Hook
* [CMS_HOOK_AUTO_REGISTER] (/library/src/hooks/cms_hook_auto_register.e): The deferred class provides an abstraction that when inheriting from this class, the declared hooks are automatically registered, otherwise, each descendant has to add it to the cms service itself.
* [CMS_HOOK_BLOCK](/library/src/hooks/cms_hook_block.e): The class CMS_HOOK_BLOCK describe a hook providing a way to alter a generic block.
* [CMS_HOOK_FORM_ALTER](/library/src/hooks/cms_hook_form_alter.e): The class CMS_HOOK_FORM_ATLER describe a hook providing a way to alter a form.
* [CMS_HOOK_MENU_ALTER](/library/src/hooks/cms_hook_menu_alter.e): The class CMS_HOOK_MENU_ATLER describe a hook providing a way to alter a menu.
* [CMS_HOOK_MENU_SYSTEM_ALTER](/library/src/hooks/cms_hook_menu_system_alter.e): The class CMS_HOOK_MENU_SYSTEM_ALTER describe a hook providing a way to alter the CMS menu system.
* [CMS_HOOK_VALUE_TABLE_ALTER](/library/src/hooks/cms_hook_value_table_alter.e):: The class CMS_HOOK_VALUE_TABLE_ALTER describe a hook providing a way to alter the value table for a response.

121
doc/tutorial.md Normal file
View File

@@ -0,0 +1,121 @@
CMS Tutorial
============
[Work in progress]
##### Table of Contents
[Getting Started](#init)
[Building your module](#module)
[Lifecycle](#cycle)
<a name="init"/>
Getting Started
-------------
<a name="module"/>
Building your own module
------------------------
A [Module](/doc/concepts.md#modules) as we already describe it, enable us to add functionallity based on your needs.
Here we will describe the basics steps to write your own modules.
* The first thing to do is inherit from the class [CMS_MODULE] () and redefine the register_hooks (2) feature.
* Implement (via inheritance) the needed [Hooks] (/doc/concepts.md#hooks).
* Define the module API through route definition. (1)
* Define the list of block to be handle by the current module (3).
* Render the block (4) (could be defined in Eiffel itself or using a template file (smarty)).
* API implementation (5).
```
class MY_NEW_MODULE
inherit
CMS_MODULE
redefine
register_hooks
end
CMS_HOOK_BLOCK
CMS_HOOK_MENU_SYSTEM_ALTER
create
make
feature {NONE} -- Initialization
make
-- Create current module
do
name := "new module"
version := "1.0"
description := "Eiffel new module"
package := "example"
end
feature -- Access: router
router (a_api: CMS_API): WSF_ROUTER
-- (1) Node router.
do
create Result.make (1)
Result.handle_with_request_methods ("/demo", create {WSF_URI_AGENT_HANDLER}.make (agent handle_demo (a_api, ?, ?)), Result.methods_head_get)
end
feature -- Hooks
register_hooks (a_response: CMS_RESPONSE)
do
-- (2)
a_response.subscribe_to_menu_system_alter_hook (Current)
a_response.subscribe_to_block_hook (Current)
end
block_list: ITERABLE [like {CMS_BLOCK}.name]
do
-- (3) List of block names, managed by current object.
end
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
do
-- (4) Get block object identified by `a_block_id' and associate with `a_response'.
end
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
local
lnk: CMS_LOCAL_LINK
do
create lnk.make ("Demo", "/demo/")
a_menu_system.primary_menu.extend (lnk)
end
feature -- Handler
handle_demo (a_api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE;)
local
r: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE
do
-- (5)
create r.make (req, res, a_api)
r.set_main_content ("NODE module does not yet implement %"" + req.path_info + "%" ...")
r.add_error_message ("NODE Module: not yet implemented")
r.execute
end
end
```
<a name="cycle"/>
Lifecycle
---------

View File

@@ -1,49 +0,0 @@
CMS Hypermedia API and Adaptive Web Design
============================================
A content management system is not a simple domain.
This example shows how to build a basic Hypermedia API for a CMS using HTML5 and progressive enhacement.
The idea is based on an existing [Eiffel CMS] (https://github.com/EiffelWebFramework/cms), the goal is learn the domain and create a new modular CMS.
Persistence
============
The current solution uses MySQL and only handle users and nodes concept.
Authentication/Authorization
============================
Basic Auth.
API features
============
There is no session.
The root uri:
shows Navigation and the possiblity to add a New Node (only for loggedin users).
shows a predefined number of nodes the `n' most recent nodes.
Guest users will be able to list all the nodes and view a particular node.
Logged in users.
Logged users are able to
Add a new node
Edit an existing node
Edit a node title
Edit a node summary
Edit a node content
Delete a node
Server Modes
============
api: HTML5 API
html: api with progresive enhacements css and js, server side rendering.
web: api with progresive enhacements css and js and Ajax calls.
References
1: http://codeartisan.blogspot.se/2012/07/using-html-as-media-type-for-your-api.html
2: https://github.com/gustafnk/combining-html-hypermedia-apis-and-adaptive-web-design

View File

@@ -1,24 +0,0 @@
note
description: "[
Effective class for APPLICATION_LAUNCHER_I
You can put modification in this class
]"
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
class
APPLICATION_LAUNCHER
inherit
APPLICATION_LAUNCHER_I
feature -- Custom
is_console_output_supported: BOOLEAN
do
Result := False
end
end

View File

@@ -1,102 +0,0 @@
note
description: "[
Specific application launcher
DO NOT EDIT THIS CLASS
you can customize APPLICATION_LAUNCHER
]"
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
deferred class
APPLICATION_LAUNCHER_I
inherit
SHARED_EXECUTION_ENVIRONMENT
feature -- Execution
launch (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
-- nature: like launcher_nature
do
-- nature := launcher_nature
-- if nature = Void or else nature = nature_nino then
-- launch_nino (a_service, opts)
-- elseif nature = nature_cgi then
-- launch_cgi (a_service, opts)
-- elseif nature = nature_libfcgi then
launch_libfcgi (a_service, opts)
-- else
-- -- bye bye
-- (create {EXCEPTIONS}).die (-1)
-- end
end
feature {NONE} -- Access
launcher_nature: detachable READABLE_STRING_8
-- Initialize the launcher nature
-- either cgi, libfcgi, or nino.
--| We could extend with more connector if needed.
--| and we could use WSF_DEFAULT_SERVICE_LAUNCHER to configure this at compilation time.
local
p: PATH
ext: detachable READABLE_STRING_32
do
create p.make_from_string (execution_environment.arguments.command_name)
if attached p.entry as l_entry then
ext := l_entry.extension
end
if ext /= Void then
if ext.same_string (nature_nino) then
Result := nature_nino
end
if ext.same_string (nature_cgi) then
Result := nature_cgi
end
if ext.same_string (nature_libfcgi) or else ext.same_string ("fcgi") then
Result := nature_libfcgi
end
end
end
feature {NONE} -- nino
nature_nino: STRING = "nino"
launch_nino (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
launcher: WSF_NINO_SERVICE_LAUNCHER
do
create launcher.make_and_launch (a_service, opts)
end
feature {NONE} -- cgi
nature_cgi: STRING = "cgi"
launch_cgi (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
launcher: WSF_CGI_SERVICE_LAUNCHER
do
create launcher.make_and_launch (a_service, opts)
end
feature {NONE} -- libfcgi
nature_libfcgi: STRING = "libfcgi"
launch_libfcgi (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
launcher: WSF_LIBFCGI_SERVICE_LAUNCHER
do
create launcher.make_and_launch (a_service, opts)
end
end

View File

@@ -1,54 +0,0 @@
note
description: "[
Effective class for APPLICATION_LAUNCHER_I
You can put modification in this class
]"
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
class
APPLICATION_LAUNCHER
inherit
APPLICATION_LAUNCHER_I
SHARED_EXECUTION_ENVIRONMENT
feature -- Status Report
is_console_output_supported: BOOLEAN
do
Result := launcher_nature = nature_nino
end
feature {NONE} -- Initialization
launcher_nature: detachable READABLE_STRING_8
-- Initialize the launcher nature
-- either cgi, libfcgi, or nino.
--| We could extend with more connector if needed.
--| and we could use WSF_DEFAULT_SERVICE_LAUNCHER to configure this at compilation time.
local
p: PATH
ext: detachable READABLE_STRING_32
do
create p.make_from_string (execution_environment.arguments.command_name)
if attached p.entry as l_entry then
ext := l_entry.extension
end
if ext /= Void then
if ext.same_string (nature_nino) then
Result := nature_nino
end
end
end
feature {NONE} -- nino
nature_nino: STRING = "nino"
end

View File

@@ -1,2 +0,0 @@
port=8088
#verbose=true

View File

@@ -1,82 +0,0 @@
<?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="api" uuid="8B2873E9-8E2A-4490-8B6C-1122B579FD1D" library_target="api">
<target name="common" abstract="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">
<debug name="esa" enabled="true"/>
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<setting name="console_application" value="true"/>
<setting name="exception_trace" value="true"/>
<setting name="concurrency" value="thread"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="conneg" location="$ISE_LIBRARY\contrib\library\network\protocol\content_negotiation\conneg-safe.ecf"/>
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf"/>
<library name="persistence_mysql" location="..\..\persistence\implementation\mysql\persistence_mysql.ecf" readonly="false"/>
<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="http_authorization" location="$ISE_LIBRARY\contrib\library\network\authentication\http_authorization\http_authorization-safe.ecf" readonly="false"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
<library name="layout" location="..\..\layout\layout.ecf"/>
<library name="logging" location="$ISE_LIBRARY\library\runtime\logging\logging-safe.ecf"/>
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf"/>
<library name="process" location="$ISE_LIBRARY\library\process\process-safe.ecf"/>
<library name="smarty" location="$ISE_LIBRARY\contrib\library\text\template\smarty\smarty-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="api_any" extends="common">
<root class="ROC_SERVER" feature="make_and_launch"/>
<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"/>
<cluster name="launcher" location=".\launcher\any\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<target name="api_nino" extends="common">
<root class="ROC_SERVER" feature="make_and_launch"/>
<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="api_cgi" extends="common">
<root class="ROC_SERVER" feature="make_and_launch"/>
<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="api_libfcgi" extends="common">
<root class="ROC_SERVER" feature="make_and_launch"/>
<library name="cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\cgi-safe.ecf"/>
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-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" readonly="false"/>
<library name="wgi_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\ewsgi\connectors\nino\nino-safe.ecf"/>
<cluster name="launcher" location=".\launcher\any\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<!-- <target name="api_test" extends="common">
<root class="APPLICATION_TEST" feature="make"/>
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<library name="ewsgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\ewsgi\ewsgi-safe.ecf" readonly="false">
<option>
<assertions precondition="true" postcondition="true" check="true" supplier_precondition="true"/>
</option>
</library>
<library name="http_client" location="$ISE_LIBRARY\contrib\library\network\http_client\http_client-safe.ecf"/>
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
<library name="wgi_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\ewsgi\connectors\nino\nino-safe.ecf"/>
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
<cluster name="src" location="src\" recursive="true"/>
<cluster name="test" location="test\" recursive="true"/>
</target>
-->
<target name="api" extends="api_nino">
</target>
</system>

View File

@@ -1,40 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
{include file="master2/head.tpl"/}
</head>
<body>
<!-- Site Navigation -->
{include file="master2/site_navigation.tpl"/}
<!--<header class="main-navi">
{include file="master2/header.tpl"/}
</header> -->
<div class="container">
<hr>
<div class="row">
<main class="main">
{include file="master2/content.tpl"/}
</main>
</div>
</div>
<div id="footer">
<footer class="site-footer">
{include file="master2/footer.tpl"/}
</footer>
</div>
{if condition="$web"}
{include file="master2/optional_enhancement_js.tpl"/}
{/if}
{if condition="$html"}
{include file="master2/optional_enhancement_js.tpl"/}
{/if}
</body>
</html>

View File

@@ -1,11 +0,0 @@
<div itemscope itemtype="http://schema.org/ItemList">
<h2 itemprop="name">Top most recent nodes</h2><br>
<meta itemprop="itemListOrder" content="Descending" />
{foreach from="$nodes" item="item"}
<div class="page-header">
<h3><span itemprop="itemListElement"><a href="{$host/}/node/{$item.id/}" rel="node"><strong>{$item.title/}</strong></a></span> <small>{$item.summary/} - {$item.publication_date_output/} </small></h3>
</div>
{/foreach}
</div>

View File

@@ -1,18 +0,0 @@
<h3> Error: {$code/} </h3>
{assign name="status400" value="400"/}
{assign name="status404" value="404"/}
{assign name="status500" value="500"/}
{if condition="$code ~ $status500"}
<p>Internal server error, for the request <strong>{$request/}</string> </p>
{/if}
{if condition="$code ~ $status404"}
<p> Resourse not found, for the request <strong>{$request/}</string> </p>
{/if}
{if condition="$code ~ $status400"}
<p> Bad request, the request <strong>{$request/}</string> is not valid</p>
{/if}

View File

@@ -1,7 +0,0 @@
<small>
<center>
<p class="text-muted"><a href="#" target="_blank" class="info">API Documentation </a>&nbsp;&nbsp;&nbsp;
<a href="#" 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>

View File

@@ -1,10 +0,0 @@
<meta charset="utf-8">
<link rel="icon" href="{$host/}/static/images/favicon.ico">
<title>Eiffel RESTonCMS</title>
{if condition="$web"}
{include file="master2/optional_styling_css.tpl"/}
{/if}
{if condition="$html"}
{include file="master2/optional_styling_css.tpl"/}
{/if}

View File

@@ -1,2 +0,0 @@
<h1>RESTonCMS</h1>
<p>Tagline</p>

View File

@@ -1,5 +0,0 @@
<p>You have successfully signed out</p>
You may want to return
Press this neat little button:<a href="{$host/}/">Take Me Home </a>

View File

@@ -1,5 +0,0 @@
<!--<ul>
<li class="main-navi-item"><a href="">Nav1</a></li>
<li><a href="">Nav2</a></li>
</ul>
-->

View File

@@ -1,5 +0,0 @@
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
{if condition="$web"}
<script src="{$host/}/static/js/roc.js"></script>
{/if}

View File

@@ -1,9 +0,0 @@
{if condition="$html"}
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="http://getbootstrap.com/assets/css/docs.min.css">
{/if}
{if condition="$web"}
<link rel="stylesheet" href="{$host/}/static/css/bootstrap.css">
<link rel="stylesheet" href="{$host/}/static/css/dashboard.css">
{/if}

View File

@@ -1,27 +0,0 @@
<nav id="" class="navbar navbar-default navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="{$host/}" rel="home">Rest on CMS</a>
</div>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="nav navbar-nav">
<li class="ListOfNodes"><a title="Nodes" href="{$host/}/nodes" rel="node">List of Nodes</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
{if isset="$user"}
<li><a>{$user/}</a></li>
<li><a title="Node" href="{$host/}/node" rel="node">New Node</a></li>
<li><a title="Logoff" href="{$host/}/logoff" rel="logoff">Logoff</a></li>
{/if}
{unless isset="$user"}
<li><a title="Login" href="{$host/}/login" rel="login">Login</a></li>
<li><a title="Register" href="{$host/}/user" rel="register">Register</a></li>
{/unless}
</ul>
</div>
</div>
</nav>

View File

@@ -1,8 +0,0 @@
{if isset="$user"}
<a title="Logoff" class="" href="{$host/}/logoff">Logoff</a>
{/if}
{unless isset="$user"}
<a title="Login" class="" href="{$host/}/login">Login</a>
<a title="Register" class="" href="{$host/}/Register">Register</a>
{/unless}
<a title="Nodes" class="" href="{$host/}/nodes">List of Nodes</a>

View File

@@ -1,174 +0,0 @@
{if condition="html"}
<!DOCTYPE html>
<html lang="en">
<head>
{include file="master2/head.tpl"/}
</head>
<body>
{/if}
{unless condition="$web"}
<!-- Site Navigation -->
{include file="master2/site_navigation.tpl"/}
{/unless}
{if condition="html"}
<div class="container">
<hr>
<div class="row">
<main class="main">
{/if}
<div class="bs-docs-example">
{if condition="$web"}
<ul id="myTab" class="nav nav-tabs" role="tablist">
<li class=""><a href="#view" role="tab" data-toggle="tab">View</a></li>
<li class="active"><a href="#edit" role="tab" data-toggle="tab">Edit</a></li>
<li class=""><a href="#delete" role="tab" data-toggle="tab">Delete</a></li>
</ul>
{/if}
{if condition="$html"}
<ul id="myTab" class="nav nav-tabs" role="tablist">
<li class=""><a href="#view" role="tab" data-toggle="tab">View</a></li>
<li class="active"><a href="#edit" role="tab" data-toggle="tab">Edit</a></li>
<li class=""><a href="#delete" role="tab" data-toggle="tab">Delete</a></li>
</ul>
{/if}
<div id="myTabContent" class="tab-content">
<div class="tab-pane" id="view">
{if isset="$node"}
<hr>
<div class="container-fluid">
<div class="row" itemscope itemtype="http://schema.org/Article">
<div class="row">
<div class="col-sm-6 col-md-4 col-lg-3"><h1><span itemprop="name">{$node.title/}</span></h1></div>
</div>
<div class="row">
<div class="col-sm-6 col-md-4 col-lg-3"><span itemprop="text">{$node.content/}<span></div>
</div>
</div>
</div>
{/if}
</div>
<div class="tab-pane fade active in" id="edit">
{if isset="$user"}
<hr>
<div class="container-fluid">
<div class="col-xs-12" itemscope itemtype="http://schema.org/Article">
{if isset="$node"}
<form class="form-inline well" action="{$host/}/node/{$node.id/}" itemprop="url" method="POST">
<input type="hidden" name="method" value="PUT">
{/if}
{unless isset="$node"}
<form class="form-inline well" action="{$host/}/node" itemprop="url" method="POST">
{/unless/}
<fieldset>
<legend>Edit Node</legend>
<div class="span3">
<p>Add or Edit a Node</p>
</div>
<div class="row">
<div class="col-xs-1">
{if isset="$node"}
<label><span itemprop="name"><a href="{$host/}/node/{$node.id/}/title" rel="node">Title:</a></span></label>
{/if}
{unless isset="$node"}
<label><span itemprop="name">Title:</span> </label>
{/unless}
</div>
<div class="col-xs-7">
<input id="title" type="text" class="form-control" name="title" placeholder="Title" required value="{$node.title/}"/>
</div>
</div>
<div class="row">
<div class="col-xs-1">
{if isset="$node"}
<label> <span itemprop="description"><a href="{$host/}/node/{$node.id/}/content" rel="node">Summary:</a></span></label>
{/if}
{unless isset="$node"}
<label> <span itemprop="description">Summary:</span></label>
{/unless}
</div>
<div class="col-xs-7">
<textarea id="summary" rows="3" class="form-control" cols="100" name="summary" placeholder="Node summary" required>{$node.summary/}</textarea>
</div>
</div>
<div class="row">
<div class="col-xs-1">
{if isset="$node"}
<label> <span itemprop="text"><a href="{$host/}/node/{$node.id/}/content" rel="node">Content</a></span> </label>
{/if}
{unless isset="$node"}
<label> <span itemprop="text">Content:</span> </label>
{/unless}
</div>
<div class="col-xs-7">
<textarea id="content" rows="25" cols="100" class="form-control" name="content" placeholder="Node content" required>{$node.content/}</textarea>
</div>
</div>
<div>
<label>
<span>&nbsp;</span>
<input type="Submit" value="Send" />
</label>
</div>
</fieldset>
</form>
</div>
{/if}
</div>
</div>
<div class="tab-pane" id="delete">
{if isset="$user"}
<hr>
<div class="container-fluid">
{if isset="$node"}
<form action="{$host/}/node/{$node.id/}" method="POST" class="">
<input type="hidden" name="method" value="DELETE">
<fieldset>
<legend>Delete Node</legend>
<div>
<label>
<span>&nbsp;</span>
<input type="Submit" value="Delete" />
</label>
</div>
</fieldset>
</form>
{/if}
</div>
{/if}
</div>
</div>
</div>
{if condition="html"}
</main>
</div>
</div>
{/if}
{if condition="html"}
<div id="footer">
<footer class="site-footer">
{include file="master2/footer.tpl"/}
</footer>
</div>
{include file="master2/optional_enhancement_js.tpl"/}
</body>
</html>
{/if}

View File

@@ -1,70 +0,0 @@
{if condition="html"}
<!DOCTYPE html>
<html lang="en">
<head>
{include file="master2/head.tpl"/}
</head>
<body>
{/if}
{unless condition="$web"}
<!-- Site Navigation -->
{include file="master2/site_navigation.tpl"/}
{/unless}
{if condition="html"}
<div class="container">
<hr>
<div class="row">
<main class="main">
{/if}
<div class="container-fluid">
<div class="col-xs-12" itemscope itemtype="http://schema.org/Article">
<form class="form-inline well" action="{$host/}/node/{$id/}/content" method="POST" class="">
<input type="hidden" name="method" value="PUT">
<fieldset>
<legend>Edit Node Content</legend>
<div class="row">
<div class="col-xs-1">
<label> <span itemprop="text">Content:</span> </label>
</div>
<div class="col-xs-7">
<textarea id="content" rows="25" cols="100" class="form-control" name="content" placeholder="Node content" required>{$content/}</textarea>
</div>
</div>
<div>
<label>
<span>&nbsp;</span>
<input type="Submit" value="Update" />
</label>
</div>
</fieldset>
</form>
</div>
</div>
{if condition="html"}
</main>
</div>
</div>
{/if}
{if condition="html"}
<div id="footer">
<footer class="site-footer">
{include file="master2/footer.tpl"/}
</footer>
</div>
{include file="master2/optional_enhancement_js.tpl"/}
</body>
</html>
{/if}

View File

@@ -1,71 +0,0 @@
{if condition="html"}
<!DOCTYPE html>
<html lang="en">
<head>
{include file="master2/head.tpl"/}
</head>
<body>
{/if}
{unless condition="$web"}
<!-- Site Navigation -->
{include file="master2/site_navigation.tpl"/}
{/unless}
{if condition="html"}
<div class="container">
<hr>
<div class="row">
<main class="main">
{/if}
<div class="container-fluid">
<div class="col-xs-12" itemscope itemtype="http://schema.org/Article">
<form class="form-inline well" action="{$host/}/node/{$id/}/summary" method="POST">
<input type="hidden" name="method" value="PUT">
<fieldset>
<legend>Edit Node Summary</legend>
<div class="row">
<div class="col-xs-1">
<label> <span itemprop="text">Summary:</span> </label>
</div>
<div class="col-xs-7">
<textarea id="summary" rows="3" cols="80" name="summary" placeholder="Node summary" required>{$summary/}</textarea>
</div>
</div>
<div>
<label>
<span>&nbsp;</span>
<input type="Submit" value="Send" />
</label>
</div>
</fieldset>
</form>
</div>
</div>
{if condition="html"}
</main>
</div>
</div>
{/if}
{if condition="html"}
<div id="footer">
<footer class="site-footer">
{include file="master2/footer.tpl"/}
</footer>
</div>
{include file="master2/optional_enhancement_js.tpl"/}
</body>
</html>
{/if}

View File

@@ -1,70 +0,0 @@
{if condition="html"}
<!DOCTYPE html>
<html lang="en">
<head>
{include file="master2/head.tpl"/}
</head>
<body>
{/if}
{unless condition="$web"}
<!-- Site Navigation -->
{include file="master2/site_navigation.tpl"/}
{/unless}
{if condition="html"}
<div class="container">
<hr>
<div class="row">
<main class="main">
{/if}
<div class="container-fluid">
<div class="col-xs-12" itemscope itemtype="http://schema.org/Article">
<form class="form-inline well" action="{$host/}/node/{$id/}/title" method="POST">
<input type="hidden" name="method" value="PUT">
<fieldset>
<legend>Edit Node Title</legend>
<div class="row">
<div class="col-xs-1">
<label> <span itemprop="text">Title:</span> </label>
</div>
<div class="col-xs-7">
<input id="title" type="text" name="title" placeholder="Title" required value="{$title/}"/>
</div>
</div>
<div>
<label>
<span>&nbsp;</span>
<input type="Submit" value="Send" />
</label>
</div>
</fieldset>
</form>
</div>
</div>
{if condition="html"}
</main>
</div>
</div>
{/if}
{if condition="html"}
<div id="footer">
<footer class="site-footer">
{include file="master2/footer.tpl"/}
</footer>
</div>
{include file="master2/optional_enhancement_js.tpl"/}
</body>
</html>
{/if}

View File

@@ -1,52 +0,0 @@
{if condition="html"}
<!DOCTYPE html>
<html lang="en">
<head>
{include file="master2/head.tpl"/}
</head>
<body>
{/if}
{unless condition="$web"}
<!-- Site Navigation -->
{include file="master2/site_navigation.tpl"/}
{/unless}
{if condition="html"}
<div class="container">
<hr>
<div class="row">
<main class="main">
{/if}
<div itemscope itemtype="http://schema.org/ItemList">
<h2 itemprop="name">List nodes</h2><br>
<meta itemprop="itemListOrder" content="Descending" />
{foreach from="$nodes" item="item"}
<div class="page-header">
<h3><span itemprop="itemListElement"><a href="{$host/}/node/{$item.id/}" rel="node"><strong>{$item.title/}</strong></a></span> <small>{$item.summary/} -{$item.publication_date_output/} </small></h3>
</div>
{/foreach}
</div>
{if condition="html"}
</main>
</div>
</div>
{/if}
{if condition="html"}
<div id="footer">
<footer class="site-footer">
{include file="master2/footer.tpl"/}
</footer>
</div>
{include file="master2/optional_enhancement_js.tpl"/}
</body>
</html>
{/if}

View File

@@ -1,100 +0,0 @@
{if condition="html"}
<!DOCTYPE html>
<html lang="en">
<head>
{include file="master2/head.tpl"/}
</head>
<body>
{/if}
{unless condition="$web"}
<!-- Site Navigation -->
{include file="master2/site_navigation.tpl"/}
{/unless}
{if condition="html"}
<div class="container">
<hr>
<div class="row">
<main class="main">
{/if}
<div class="container-fluid">
<div class="col-xs-12" itemscope itemtype="http://schema.org/Person">
<form class="form-inline well" action="{$host/}/user" data-rel="user-register" method="POST" >
<fieldset>
<legend>Register</legend>
<div class="span3">
<p>Register new user</p>
</div>
<div class="row">
<div class="col-xs-2">
<label><span itemprop="name">Username:</span> </label>
</div>
<div class="col-xs-7">
<input id="username" type="text" name="username" placeholder="Username" required/>
</div>
</div>
<div class="row" itemscope itemtype="http://schema.org/Text">
<div class="col-xs-2">
<label><span itemprop="accessCode">Password:</span> </label>
</div>
<div class="col-xs-7">
<input id="password" type="password" name="password" placeholder="Password" required/>
</div>
</div>
<div class="row" itemscope itemtype="http://schema.org/Text">
<div class="col-xs-2">
<label><span itemprop="accessCode">Re-type Password:</span> </label>
</div>
<div class="col-xs-7">
<input id="check_password" type="password" name="check_password" placeholder="Password" required/>
</div>
</div>
<div class="row">
<div class="col-xs-2">
<label><span itemprop="email">Email:</span> </label>
</div>
<div class="col-xs-7">
<input id="email" type="email" name="email" placeholder="Email" required/>
</div>
s</div>
<div>
<label>
<span>&nbsp;</span>
<input type="Submit" value="Send" />
</label>
</div>
</fieldset>
</form>
</div>
</div>
{if condition="html"}
</main>
</div>
</div>
{/if}
{if condition="html"}
<div id="footer">
<footer class="site-footer">
{include file="master2/footer.tpl"/}
</footer>
</div>
{include file="master2/optional_enhancement_js.tpl"/}
</body>
</html>
{/if}

View File

@@ -1,19 +0,0 @@
note
description: "Summary description for {ESA_APPLICATION_CONSTANTS}."
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
APPLICATION_CONSTANTS
feature -- Access
major: INTEGER = 0
minor: INTEGER = 1
built: STRING = "0001"
version: STRING
do
Result := major.out + "." + minor.out + "." + built
end
end

View File

@@ -1,70 +0,0 @@
note
description: "API configuration factory"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
CONFIGURATION_FACTORY
inherit
SHARED_EXECUTION_ENVIRONMENT
SHARED_ERROR
feature -- Factory
roc_config (a_dir: detachable STRING): ROC_CONFIG
local
l_layout: APPLICATION_LAYOUT
l_email_service: ROC_EMAIL_SERVICE
l_database: DATABASE_CONNECTION
l_api_service: ROC_API_SERVICE
l_retried: BOOLEAN
do
if not l_retried then
if attached a_dir then
create l_layout.make_with_path (create {PATH}.make_from_string (a_dir))
else
create l_layout.make_default
end
log.write_information (generator + ".roc_config " + l_layout.path.name.out)
create l_email_service.make ((create {JSON_CONFIGURATION}).new_smtp_configuration(l_layout.application_config_path))
if attached (create {JSON_CONFIGURATION}).new_database_configuration (l_layout.application_config_path) as l_database_config then
create {DATABASE_CONNECTION_MYSQL} l_database.login_with_connection_string (l_database_config.connection_string)
create l_api_service.make (create {CMS_STORAGE_MYSQL}.make (l_database))
create Result.make (l_database, l_api_service, l_email_service, l_layout)
if (create {ROC_JSON_CONFIGURATION}).is_web_mode(l_layout.application_config_path) then
Result.mark_web
elseif (create {ROC_JSON_CONFIGURATION}).is_html_mode(l_layout.application_config_path) then
Result.mark_html
end
set_successful
else
create {DATABASE_CONNECTION_NULL} l_database.make_common
create l_api_service.make (create {CMS_STORAGE_NULL})
create Result.make (l_database, l_api_service, l_email_service, l_layout)
set_last_error ("Database Connections", generator + ".roc_config")
log.write_error (generator + ".roc_config Error database connection" )
end
else
if attached a_dir then
create l_layout.make_with_path (create {PATH}.make_from_string (a_dir))
else
create l_layout.make_default
end
create l_email_service.make ((create {JSON_CONFIGURATION}).new_smtp_configuration(l_layout.application_config_path))
create {DATABASE_CONNECTION_NULL} l_database.make_common
create l_api_service.make (create {CMS_STORAGE_NULL})
create Result.make (l_database, l_api_service, l_email_service, l_layout)
end
rescue
set_last_error_from_exception ("Database Connection execution")
log.write_critical (generator + ".roc_config Database Connection execution exceptions")
l_retried := True
retry
end
end

View File

@@ -1,48 +0,0 @@
note
description: "Summary description for {ROC_JSON_CONFIGURATION}."
date: "$Date$"
revision: "$Revision$"
class
ROC_JSON_CONFIGURATION
inherit
JSON_CONFIGURATION
feature -- Access
is_html_mode (a_path: PATH): BOOLEAN
-- Is the server running on web mode?
local
l_parser: JSON_PARSER
do
if attached json_file_from (a_path) as json_file then
l_parser := new_json_parser (json_file)
if attached {JSON_OBJECT} l_parser.parse as jv and then l_parser.is_parsed and then
attached {JSON_OBJECT} jv.item ("server") as l_server and then
attached {JSON_STRING} l_server.item ("mode") as l_mode then
Result := l_mode.item.is_case_insensitive_equal_general ("html")
end
end
end
is_web_mode (a_path: PATH): BOOLEAN
-- Is the server running on web mode?
local
l_parser: JSON_PARSER
do
if attached json_file_from (a_path) as json_file then
l_parser := new_json_parser (json_file)
if attached {JSON_OBJECT} l_parser.parse as jv and then l_parser.is_parsed and then
attached {JSON_OBJECT} jv.item ("server") as l_server and then
attached {JSON_STRING} l_server.item ("mode") as l_mode then
Result := l_mode.item.is_case_insensitive_equal_general ("web")
end
end
end
end

View File

@@ -1,29 +0,0 @@
note
description: "Template shared common features to all the templates"
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
deferred class
TEMPLATE_SHARED
inherit
ROC_TEMPLATE_PAGE
feature --
add_host (a_host: READABLE_STRING_GENERAL)
-- Add value `a_host' to `host'
do
template.add_value (a_host, "host")
end
add_user (a_user: detachable ANY)
-- Add value `a_host' to `host'
do
if attached a_user then
template.add_value (a_user,"user")
end
end
end

View File

@@ -1,143 +0,0 @@
note
description: "Summary description for {ROC_RESPONSE}."
date: "$Date$"
revision: "$Revision$"
class
ROC_RESPONSE
inherit
APP_HANDLER
TEMPLATE_SHARED
create
make
feature {NONE} -- Initialization
make (a_request: WSF_REQUEST; a_template: READABLE_STRING_32)
do
request := a_request
-- Set template to HTML
set_template_folder (html_path)
-- Build Common Template
set_template_file_name (a_template)
-- Process the current tempate.
set_value (a_request.absolute_script_url (""), "host")
if attached current_user_name (request) as l_user then
set_value (l_user, "user")
end
end
feature -- Access
request: WSF_REQUEST
feature -- Access
values: STRING_TABLE [detachable ANY]
do
Result := template.values
end
value (a_key: READABLE_STRING_GENERAL): detachable ANY
do
Result := template.values.item (a_key)
end
feature -- Element change
set_value (a_value: detachable ANY; a_key: READABLE_STRING_GENERAL)
do
template.add_value (a_value, a_key)
end
feature -- Output
send_to (res: WSF_RESPONSE)
do
process
if attached representation as l_output then
new_response (res, l_output, {HTTP_STATUS_CODE}.ok)
end
end
new_response_redirect (req: WSF_REQUEST; res: WSF_RESPONSE; a_location: READABLE_STRING_32)
-- Redirect to `a_location'
local
h: HTTP_HEADER
do
create h.make
h.put_content_type_text_html
h.put_current_date
h.put_location (a_location)
res.set_status_code ({HTTP_STATUS_CODE}.see_other)
res.put_header_text (h.string)
end
new_response_authenticate (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Handle forbidden.
local
h: HTTP_HEADER
do
create h.make
h.put_content_type_text_html
h.put_current_date
h.put_header_key_value ({HTTP_HEADER_NAMES}.header_www_authenticate, "Basic realm=%"CMS-User%"")
res.set_status_code ({HTTP_STATUS_CODE}.unauthorized)
res.put_header_text (h.string)
end
new_response_denied (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Handle forbidden.
local
h: HTTP_HEADER
do
process
create h.make
if attached representation as l_output then
h.put_content_length (l_output.count)
end
h.put_content_type_text_html
h.put_current_date
res.set_status_code ({HTTP_STATUS_CODE}.unauthorized)
res.put_header_text (h.string)
if attached representation as l_output then
res.put_string (l_output)
end
end
new_response_unauthorized (req: WSF_REQUEST; res: WSF_RESPONSE)
local
h: HTTP_HEADER
output: STRING
do
create h.make
h.put_content_type_text_html
h.put_current_date
res.set_status_code ({HTTP_STATUS_CODE}.forbidden)
res.put_header_text (h.string)
end
feature {NONE} -- Implemenation
new_response (res: WSF_RESPONSE; output: STRING; status_code: INTEGER)
local
h: HTTP_HEADER
do
create h.make
h.put_content_type_text_html
h.put_content_length (output.count)
h.put_current_date
res.set_status_code (status_code)
res.put_header_text (h.string)
res.put_string (output)
end
end

View File

@@ -1,76 +0,0 @@
note
description: "Abstract template class"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
deferred class
ROC_TEMPLATE_PAGE
inherit
SHARED_TEMPLATE_CONTEXT
SHARED_LOGGER
ARGUMENTS
feature -- Status
representation: detachable STRING
-- String representation, if any.
set_template_folder (v: PATH)
-- Set template folder to `v'.
do
template_context.set_template_folder (v)
end
set_template_file_name (v: STRING)
-- Set `template' to `v'.
do
create template.make_from_file (v)
end
set_template (v: like template)
-- Set `template' to `v'.
do
template := v
end
template: TEMPLATE_FILE
layout: APPLICATION_LAYOUT
local
l_env: EXECUTION_ENVIRONMENT
once
create l_env
if attached separate_character_option_value ('d') as l_dir then
create Result.make_with_path (create {PATH}.make_from_string (l_dir))
else
create Result.make_default
end
end
html_path: PATH
-- Html template paths.
do
Result := layout.template_path.extended ("html")
end
feature -- Process
process
-- Process the current template.
do
template_context.enable_verbose
template.analyze
template.get_output
if attached template.output as l_output then
representation := l_output
debug
log.write_debug (generator + ".make " + l_output)
end
end
end
end

View File

@@ -1,119 +0,0 @@
note
description: "Abstract API service"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
deferred class
ROC_ABSTRACT_API
inherit
WSF_ROUTED_SKELETON_SERVICE
undefine
requires_proxy
redefine
execute_default
end
WSF_NO_PROXY_POLICY
WSF_URI_HELPER_FOR_ROUTED_SERVICE
WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE
SHARED_CONNEG_HELPER
SHARED_LOGGER
feature {NONE} -- Initialization
make (a_esa_config: ROC_CONFIG; a_server: ROC_SERVER)
do
roc_config := a_esa_config
server := a_server
initialize_router
end
feature -- ESA
roc_config: ROC_CONFIG
-- Configuration
server: ROC_SERVER
-- Server
feature -- Router setup
setup_router
-- Setup `router'
deferred
end
layout: APPLICATION_LAYOUT
do
Result := roc_config.layout
end
feature -- Access
handle_debug (req: WSF_REQUEST; res: WSF_RESPONSE)
local
s: STRING_8
h: HTTP_HEADER
do
if req.is_get_request_method then
s := "debug"
create h.make_with_count (1)
h.put_content_type_text_html
h.put_content_length (s.count)
res.put_header_lines (h)
res.put_string (s)
else
create s.make (30_000)
across
req.form_parameters as c
loop
s.append (c.item.url_encoded_name)
s.append ("=")
s.append (c.item.string_representation)
s.append ("<br/>")
end
if s.is_empty then
req.read_input_data_into (s)
end
create h.make_with_count (1)
h.put_content_type_text_html
h.put_content_length (s.count)
res.put_header_lines (h)
res.put_string (s)
end
end
feature -- Handler
not_yet_implemented_uri_template_handler (msg: READABLE_STRING_8): WSF_URI_TEMPLATE_HANDLER
do
create {WSF_URI_TEMPLATE_AGENT_HANDLER} Result.make (agent not_yet_implemented(?, ?, msg))
end
not_yet_implemented (req: WSF_REQUEST; res: WSF_RESPONSE; msg: detachable READABLE_STRING_8)
local
m: WSF_NOT_IMPLEMENTED_RESPONSE
do
create m.make (req)
if msg /= Void then
m.set_body (msg)
end
res.send (m)
end
feature -- Default Execution
execute_default (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Dispatch requests without a matching handler.
local
do
end
end

View File

@@ -1,87 +0,0 @@
note
description: "Eiffel Suppor API configuration"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
ROC_CONFIG
inherit
SHARED_ERROR
create
make
feature -- Initialization
make (a_database: DATABASE_CONNECTION; a_api_service: ROC_API_SERVICE; a_email_service: ROC_EMAIL_SERVICE; a_layout: APPLICATION_LAYOUT )
-- Create an object with defaults.
do
database := a_database
api_service := a_api_service
email_service := a_email_service
layout := a_layout
mark_api
ensure
database_set: database = a_database
api_service_set: api_service = a_api_service
email_service_set: email_service = a_email_service
layout_set: layout = a_layout
end
feature -- Access
is_successful: BOOLEAN
-- Is the configuration successful?
do
Result := successful
end
is_api: BOOLEAN
-- Is the server running on server mode API
is_web: BOOLEAN
-- Is the server running on server mode API
is_html: BOOLEAN
-- Is the server running on html mode API
database: DATABASE_CONNECTION
-- Database connection.
api_service: ROC_API_SERVICE
-- Support API.
email_service: ROC_EMAIL_SERVICE
-- Email service.
layout: APPLICATION_LAYOUT
-- Api layout.
mark_api
-- Set server mode to api.
do
is_api := True
is_html := False
is_web := False
end
mark_web
-- Set server mode to web.
do
is_web := True
is_api := False
is_html := False
end
mark_html
-- Set server mode to web.
do
is_html := True
is_api := False
is_web := False
end
end

View File

@@ -1,210 +0,0 @@
note
description: "[
application service
]"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
ROC_SERVER
inherit
WSF_LAUNCHABLE_SERVICE
rename
make_and_launch as make_and_launch_service
redefine
initialize
end
WSF_FILTERED_SERVICE
WSF_FILTER
rename
execute as execute_filter
end
SHARED_EXECUTION_ENVIRONMENT
export
{NONE} all
end
APPLICATION_CONSTANTS
REFACTORING_HELPER
ARGUMENTS
create
make_and_launch
feature {NONE} -- Initialization
make_and_launch
do
setup_config
create launcher
make_and_launch_service
end
initialize
-- Initialize current service.
do
Precursor
service_options := create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI}.make_from_file ("roc.ini")
initialize_filter
end
feature {NONE} -- Launch operation
launcher: APPLICATION_LAUNCHER
launch (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
l_retry: BOOLEAN
l_message: STRING
do
if not l_retry then
launcher.launch (a_service, opts)
else
-- error hanling.
create l_message.make (1024)
if attached ((create {EXCEPTION_MANAGER}).last_exception) as l_exception then
if attached l_exception.description as l_description then
l_message.append (l_description.as_string_32)
l_message.append ("%N%N")
elseif attached l_exception.trace as l_trace then
l_message.append (l_trace)
l_message.append ("%N%N")
else
l_message.append (l_exception.out)
l_message.append ("%N%N")
end
else
l_message.append ("The application crash without available information")
l_message.append ("%N%N")
end
roc_config.email_service.send_shutdown_email (l_message)
roc_config.log.write_emergency (generator + ".launch %N" + l_message)
end
rescue
l_retry := True
retry
end
feature {ROC_ABSTRACT_API} -- Services
api_service: ROC_REST_API
-- rest api.
local
s: like internal_api_service
do
s := internal_api_service
if s = Void then
create s.make (roc_config, Current)
internal_api_service := s
end
Result := s
end
feature {NONE} -- Internal
internal_api_service: detachable like api_service
feature -- ESA Configuraion
roc_config: ROC_CONFIG
-- Configuration.
setup_config
-- Configure API.
local
l_configuration_factory: CONFIGURATION_FACTORY
do
create l_configuration_factory
roc_config := l_configuration_factory.roc_config (separate_character_option_value ('d'))
if attached l_configuration_factory.last_error as l_error then
roc_config.set_last_error_from_handler (l_error)
else
roc_config.set_successful
end
end
feature -- Execute Filter
execute_filter (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the filter.
do
res.put_header_line ("Date: " + (create {HTTP_DATE}.make_now_utc).string)
res.put_header_line ("ROCServer: " + version)
api_service.execute (req, res)
end
feature -- Filters
create_filter
-- Create `filter'.
local
f, l_filter: detachable WSF_FILTER
fh: WSF_CUSTOM_HEADER_FILTER
do
l_filter := Void
-- Header
create fh.make (1)
fh.set_next (l_filter)
fh.custom_header.put_header ("X-ROCServer: " + version)
l_filter := fh
-- Maintenance
create {WSF_MAINTENANCE_FILTER} f
f.set_next (l_filter)
l_filter := f
if launcher.is_console_output_supported then
-- Logging for nino
create {WSF_LOGGING_FILTER} f.make_with_output (io.output)
f.set_next (l_filter)
l_filter := f
end
-- CORS Authentication
create {CORS_FILTER} f
f.set_next (l_filter)
l_filter := f
-- Logger Filter
create {LOGGER_FILTER} f.make (roc_config)
f.set_next (l_filter)
l_filter := f
-- Error Filter
create {ERROR_FILTER} f.make (roc_config)
f.set_next (l_filter)
l_filter := f
-- Authentication
create {AUTHENTICATION_FILTER} f.make (roc_config)
f.set_next (l_filter)
l_filter := f
filter := l_filter
end
setup_filter
-- Setup `filter'.
local
f: WSF_FILTER
do
from
f := filter
until
not attached f.next as l_next
loop
f := l_next
end
f.set_next (Current)
end
end

View File

@@ -1,60 +0,0 @@
note
description: "Authentication filter."
author: "Olivier Ligot"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
AUTHENTICATION_FILTER
inherit
WSF_URI_TEMPLATE_HANDLER
APP_ABSTRACT_HANDLER
rename
set_esa_config as make
end
WSF_FILTER
create
make
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the filter
local
l_auth: HTTP_AUTHORIZATION
do
log.write_debug (generator + ".execute " )
create l_auth.make (req.http_authorization)
if attached req.raw_header_data as l_raw_data then
log.write_debug (generator + ".execute " + l_raw_data )
end
-- A valid user
if (attached l_auth.type as l_auth_type and then l_auth_type.is_case_insensitive_equal ("basic")) and then
attached l_auth.login as l_auth_login and then attached l_auth.password as l_auth_password then
if api_service.login_valid (l_auth_login, l_auth_password) then
if attached api_service.user_by_name (l_auth_login) as l_user then
req.set_execution_variable ("user", l_user)
execute_next (req, res)
else
-- Internal server error
end
else
log.write_error (generator + ".execute login_valid failed for: " + l_auth_login )
execute_next (req, res)
end
else
log.write_error (generator + ".execute Not valid")
execute_next (req, res)
end
end
note
copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,42 +0,0 @@
note
description: "Error filter"
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
class
ERROR_FILTER
inherit
WSF_URI_TEMPLATE_HANDLER
APP_ABSTRACT_HANDLER
rename
set_esa_config as make
end
WSF_FILTER
create
make
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the filter
do
if roc_config.is_successful and then roc_config.api_service.successful then
log.write_information (generator + ".execute")
execute_next (req, res)
else
-- send internal server error.
end
end
note
copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,54 +0,0 @@
note
description: "Logger filter"
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
class
LOGGER_FILTER
inherit
WSF_URI_TEMPLATE_HANDLER
APP_ABSTRACT_HANDLER
rename
set_esa_config as make
end
WSF_FILTER
create
make
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the filter.
local
s: STRING_8
do
log.write_debug (generator + ".execute")
create s.make (2048)
if attached req.content_type as l_type then
s.append ("[length=")
s.append_natural_64 (req.content_length_value)
s.append_character (']')
s.append_character (' ')
s.append (l_type.debug_output)
s.append_character ('%N')
end
append_iterable_to ("Path parameters", req.path_parameters, s)
append_iterable_to ("Query parameters", req.query_parameters, s)
append_iterable_to ("Form parameters", req.form_parameters, s)
if not s.is_empty then
log.write_debug (generator + ".execute" + s)
end
execute_next (req, res)
end
note
copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,48 +0,0 @@
note
description: "Abstrat Eiffel Support API Handler."
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
deferred class
APP_ABSTRACT_HANDLER
inherit
WSF_HANDLER
APP_HANDLER
SHARED_CONNEG_HELPER
feature -- Change
set_esa_config (a_esa_config: like roc_config)
-- Set `roc_config' to `a_esa_condig'.
do
roc_config := a_esa_config
ensure
esa_config_set: roc_config = a_esa_config
end
feature -- Access
roc_config: ROC_CONFIG
-- Configuration.
api_service: ROC_API_SERVICE
-- api Service.
do
Result := roc_config.api_service
end
email_service: ROC_EMAIL_SERVICE
-- Email Service.
do
Result := roc_config.email_service
end
is_web: BOOLEAN
do
Result := roc_config.is_web
end
end

View File

@@ -1,98 +0,0 @@
note
description: "Summary description for {ESA_HANDLER}."
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
APP_HANDLER
inherit
SHARED_LOGGER
feature -- User
current_user_name (req: WSF_REQUEST): detachable READABLE_STRING_32
-- Current user name or Void in case of Guest users.
note
EIS: "src=eiffel:?class=AUTHENTICATION_FILTER&feature=execute"
do
if attached {CMS_USER} current_user (req) as l_user then
Result := l_user.name
end
end
current_user (req: WSF_REQUEST): detachable CMS_USER
-- Current user or Void in case of Guest user.
note
EIS: "eiffel:?class=AUTHENTICATION_FILTER&feature=execute"
do
if attached {CMS_USER} req.execution_variable ("user") as l_user then
Result := l_user
end
end
feature -- Media Type
current_media_type (req: WSF_REQUEST): detachable READABLE_STRING_32
-- Current media type or Void if it's not acceptable.
do
if attached {STRING} req.execution_variable ("media_type") as l_type then
Result := l_type
end
end
feature -- Absolute Host
absolute_host (req: WSF_REQUEST; a_path:STRING): STRING
do
Result := req.absolute_script_url (a_path)
if Result.last_index_of ('/', Result.count) = Result.count then
Result.remove_tail (1)
end
log.write_debug (generator + ".absolute_host " + Result )
end
feature -- Compression
current_compression (req: WSF_REQUEST): detachable READABLE_STRING_32
-- Current compression encoding or Void if it's not acceptable.
do
if attached {STRING} req.execution_variable ("compression") as l_encoding then
Result := l_encoding
end
end
feature {NONE} -- Implementations
append_iterable_to (a_title: READABLE_STRING_8; it: detachable ITERABLE [WSF_VALUE]; s: STRING_8)
local
n: INTEGER
do
if it /= Void then
across it as c loop
n := n + 1
end
if n > 0 then
s.append (a_title)
s.append_character (':')
s.append_character ('%N')
across
it as c
loop
s.append (" - ")
s.append (c.item.url_encoded_name)
s.append_character (' ')
s.append_character ('{')
s.append (c.item.generating_type)
s.append_character ('}')
s.append_character ('=')
s.append (c.item.debug_output.as_string_8)
s.append_character ('%N')
end
end
end
end
end

View File

@@ -1,57 +0,0 @@
note
description: "Summary description for {NAVIGATION_HANDLER}."
date: "$Date$"
revision: "$Revision$"
class
NAVIGATION_HANDLER
inherit
APP_ABSTRACT_HANDLER
rename
set_esa_config as make
end
WSF_FILTER
WSF_URI_HANDLER
rename
execute as uri_execute,
new_mapping as new_uri_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)
execute_next (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
l_page: ROC_RESPONSE
do
create l_page.make (req, "modules/navigation.tpl")
l_page.send_to (res)
end
end

View File

@@ -1,190 +0,0 @@
note
description: "Summary description for {NEW_CONTENT_HANDLER}."
date: "$Date$"
revision: "$Revision$"
class
NODE_CONTENT_HANDLER
inherit
APP_ABSTRACT_HANDLER
rename
set_esa_config as make
end
WSF_FILTER
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_put
end
REFACTORING_HELPER
create
make
feature -- execute
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
execute_next (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
uri_template_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
l_page: ROC_RESPONSE
do
if attached current_user_name (req) then
-- Existing node
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
if l_id.is_integer and then attached {CMS_NODE} api_service.node (l_id.integer_value) as l_node then
create l_page.make (req, "modules/node_content.tpl")
l_page.set_value (l_node.content, "content")
l_page.set_value (l_id.value, "id")
l_page.set_value (roc_config.is_web, "web")
l_page.set_value (roc_config.is_html, "html")
l_page.send_to (res)
else
do_error (req, res, l_id)
end
else
-- Todo extract method
create l_page.make (req, "master2/error.tpl")
l_page.set_value ("500", "code")
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
else
(create {ROC_RESPONSE}.make(req,"")).new_response_unauthorized (req, res)
end
end
do_post (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
u_node: CMS_NODE
l_page: ROC_RESPONSE
do
if attached current_user_name (req) then
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
if l_id.is_integer and then attached {CMS_NODE} api_service.node (l_id.integer_value) as l_node then
if attached {WSF_STRING} req.form_parameter ("method") as l_method then
if l_method.is_case_insensitive_equal ("PUT") then
do_put (req, res)
else
create l_page.make (req, "master2/error.tpl")
l_page.set_value ("500", "code")
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
end
else
do_error (req, res, l_id)
end
else
create l_page.make (req, "master2/error.tpl")
l_page.set_value ("500", "code")
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
else
(create {ROC_RESPONSE}.make(req,"")).new_response_unauthorized (req, res)
end
end
do_put (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
u_node: CMS_NODE
l_page: ROC_RESPONSE
do
to_implement ("Check if user has permissions")
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 {CMS_NODE} api_service.node (l_id.integer_value) as l_node then
u_node := extract_data_form (req)
u_node.set_id (l_id.integer_value)
api_service.update_node_content (l_user.id, u_node.id, u_node.content)
(create {ROC_RESPONSE}.make (req, "")).new_response_redirect (req, res, req.absolute_script_url (""))
else
do_error (req, res, l_id)
end
else
create l_page.make (req, "master2/error.tpl")
l_page.set_value ("500", "code")
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
else
(create {ROC_RESPONSE}.make(req,"")).new_response_unauthorized (req, res)
end
end
feature -- Error
do_error (req: WSF_REQUEST; res: WSF_RESPONSE; a_id: WSF_STRING)
-- Handling error.
local
l_page: ROC_RESPONSE
do
create l_page.make (req, "master2/error.tpl")
if a_id.is_integer then
-- resource not found
l_page.set_value ("404", "code")
else
-- bad request
l_page.set_value ("400", "code")
end
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to(res)
end
feature -- {NONE} Form data
extract_data_form (req: WSF_REQUEST): CMS_NODE
-- Extract request form data and build a object
-- Node
do
create Result.make ("", "", "")
if attached {WSF_STRING}req.form_parameter ("content") as l_content then
Result.set_content (l_content.value)
end
end
end

View File

@@ -1,225 +0,0 @@
note
description: "Summary description for {NODE_HANDLER}."
date: "$Date$"
revision: "$Revision$"
class
NODE_HANDLER
inherit
APP_ABSTRACT_HANDLER
rename
set_esa_config as make
end
WSF_FILTER
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_put,
do_delete
end
REFACTORING_HELPER
create
make
feature -- execute
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
execute_next (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
uri_template_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
l_page: ROC_RESPONSE
do
-- Existing node
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
if l_id.is_integer and then attached {CMS_NODE} api_service.node (l_id.integer_value) as l_node then
create l_page.make (req, "modules/node.tpl")
l_page.set_value (l_node, "node")
l_page.set_value (roc_config.is_web, "web")
l_page.set_value (roc_config.is_html, "html")
l_page.send_to (res)
else
do_error (req, res, l_id)
end
else
-- Factory
new_node (req, res)
end
end
do_post (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
u_node: CMS_NODE
l_page: ROC_RESPONSE
do
to_implement ("Check user permissions!!!")
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 {CMS_NODE} api_service.node (l_id.integer_value) as l_node then
if attached {WSF_STRING} req.form_parameter ("method") as l_method then
if l_method.is_case_insensitive_equal ("DELETE") then
do_delete (req, res)
elseif l_method.is_case_insensitive_equal ("PUT") then
do_put (req, res)
else
create l_page.make (req, "master2/error.tpl")
l_page.set_value ("500", "code")
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
end
else
do_error (req, res, l_id)
end
else
-- New node
u_node := extract_data_form (req)
u_node.set_author (l_user)
api_service.new_node (u_node)
(create {ROC_RESPONSE}.make (req, "")).new_response_redirect (req, res, req.absolute_script_url (""))
end
else
(create {ROC_RESPONSE}.make(req,"")).new_response_unauthorized (req, res)
end
end
do_put (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
u_node: CMS_NODE
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 {CMS_NODE} api_service.node (l_id.integer_value) as l_node then
u_node := extract_data_form (req)
u_node.set_id (l_id.integer_value)
api_service.update_node (l_user.id,u_node)
(create {ROC_RESPONSE}.make (req, "")).new_response_redirect (req, res, req.absolute_script_url (""))
else
do_error (req, res, l_id)
end
else
-- Internal server error
end
else
(create {ROC_RESPONSE}.make(req,"")).new_response_unauthorized (req, res)
end
end
do_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
do
if attached current_user_name (req) then
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
if l_id.is_integer and then attached {CMS_NODE} api_service.node (l_id.integer_value) as l_node then
api_service.delete_node (l_id.integer_value)
(create {ROC_RESPONSE}.make (req, "")).new_response_redirect (req, res, req.absolute_script_url (""))
else
do_error (req, res, l_id)
end
else
-- Internal server error
end
else
(create {ROC_RESPONSE}.make(req,"")).new_response_unauthorized (req, res)
end
end
feature -- Error
do_error (req: WSF_REQUEST; res: WSF_RESPONSE; a_id: WSF_STRING)
-- Handling error.
local
l_page: ROC_RESPONSE
do
create l_page.make (req, "master2/error.tpl")
if a_id.is_integer then
-- resource not found
l_page.set_value ("404", "code")
else
-- bad request
l_page.set_value ("400", "code")
end
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
feature {NONE} -- Node
new_node (req: WSF_REQUEST; res: WSF_RESPONSE)
local
l_page: ROC_RESPONSE
do
if attached current_user_name (req) then
create l_page.make (req, "modules/node.tpl")
l_page.set_value (roc_config.is_web, "web")
l_page.set_value (roc_config.is_html, "html")
l_page.send_to (res)
else
(create {ROC_RESPONSE}.make (req, "")).new_response_unauthorized (req, res)
end
end
feature -- {NONE} Form data
extract_data_form (req: WSF_REQUEST): CMS_NODE
-- Extract request form data and build a object
-- Node
do
create Result.make ("", "", "")
if attached {WSF_STRING} req.form_parameter ("title") as l_title then
Result.set_title (l_title.value)
end
if attached {WSF_STRING} req.form_parameter ("summary") as l_summary then
Result.set_summary (l_summary.value)
end
if attached {WSF_STRING} req.form_parameter ("content") as l_content then
Result.set_content (l_content.value)
end
end
end

View File

@@ -1,199 +0,0 @@
note
description: "Summary description for {NODE_SUMMARY_HANDLER}."
date: "$Date$"
revision: "$Revision$"
class
NODE_SUMMARY_HANDLER
inherit
APP_ABSTRACT_HANDLER
rename
set_esa_config as make
end
WSF_FILTER
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_put
end
REFACTORING_HELPER
create
make
feature -- execute
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
execute_next (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
uri_template_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
l_page: ROC_RESPONSE
do
if attached current_user_name (req) then
-- Existing node
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
if l_id.is_integer and then attached {CMS_NODE} api_service.node (l_id.integer_value) as l_node then
create l_page.make (req, "modules/node_summary.tpl")
l_page.set_value (l_node.summary, "summary")
l_page.set_value (roc_config.is_web, "web")
l_page.set_value (roc_config.is_html, "html")
l_page.set_value (l_id.value, "id")
l_page.send_to (res)
else
do_error (req, res, l_id)
end
else
create l_page.make (req, "master2/error.tpl")
l_page.set_value ("500", "code")
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
else
(create {ROC_RESPONSE}.make(req,"")).new_response_unauthorized (req, res)
end
end
do_post (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
u_node: CMS_NODE
l_page: ROC_RESPONSE
do
if attached current_user_name (req) then
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
if l_id.is_integer and then attached {CMS_NODE} api_service.node (l_id.integer_value) as l_node then
if attached {WSF_STRING} req.form_parameter ("method") as l_method then
if l_method.is_case_insensitive_equal ("PUT") then
do_put (req, res)
else
create l_page.make (req, "master2/error.tpl")
l_page.set_value ("500", "code")
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
end
else
do_error (req, res, l_id)
end
else
create l_page.make (req, "master2/error.tpl")
l_page.set_value ("500", "code")
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
else
(create {ROC_RESPONSE}.make(req,"")).new_response_unauthorized (req, res)
end
end
do_put (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
u_node: CMS_NODE
l_page: ROC_RESPONSE
do
to_implement ("Check if user has permissions!!!")
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 {CMS_NODE} api_service.node (l_id.integer_value) as l_node then
u_node := extract_data_form (req)
u_node.set_id (l_id.integer_value)
api_service.update_node_summary (l_user.id,u_node.id, u_node.summary)
(create {ROC_RESPONSE}.make (req, "")).new_response_redirect (req, res, req.absolute_script_url (""))
else
do_error (req, res, l_id)
end
else
create l_page.make (req, "master2/error.tpl")
l_page.set_value ("500", "code")
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
else
(create {ROC_RESPONSE}.make(req,"")).new_response_unauthorized (req, res)
end
end
feature -- Error
do_error (req: WSF_REQUEST; res: WSF_RESPONSE; a_id: WSF_STRING)
-- Handling error.
local
l_page: ROC_RESPONSE
do
create l_page.make (req, "master2/error.tpl")
if a_id.is_integer then
-- resource not found
l_page.set_value ("404", "code")
else
-- bad request
l_page.set_value ("400", "code")
end
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to(res)
end
feature {NONE} -- Node
new_node (req: WSF_REQUEST; res: WSF_RESPONSE)
local
l_page: ROC_RESPONSE
do
create l_page.make (req, "modules/node.tpl")
l_page.send_to (res)
end
feature -- {NONE} Form data
extract_data_form (req: WSF_REQUEST): CMS_NODE
-- Extract request form data and build a object
-- Node
do
create Result.make ("", "", "")
if attached {WSF_STRING}req.form_parameter ("summary") as l_summary then
Result.set_summary (l_summary.value)
end
end
end

View File

@@ -1,199 +0,0 @@
note
description: "Summary description for {NODE_TITLE_HANDLER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
NODE_TITLE_HANDLER
inherit
APP_ABSTRACT_HANDLER
rename
set_esa_config as make
end
WSF_FILTER
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_put
end
REFACTORING_HELPER
create
make
feature -- execute
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
execute_next (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
uri_template_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
l_page: ROC_RESPONSE
do
if attached current_user_name (req) as l_user then
-- Existing node
if attached {WSF_STRING} req.path_parameter ("id") as l_id then
if l_id.is_integer and then attached {CMS_NODE} api_service.node (l_id.integer_value) as l_node then
create l_page.make (req, "modules/node_title.tpl")
l_page.set_value (l_node.title, "title")
l_page.set_value (l_id.value, "id")
l_page.set_value (roc_config.is_web, "web")
l_page.set_value (roc_config.is_html, "html")
l_page.send_to (res)
else
do_error (req, res, l_id)
end
else
create l_page.make (req, "master2/error.tpl")
l_page.set_value ("500", "code")
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
else
(create {ROC_RESPONSE}.make(req,"")).new_response_unauthorized (req, res)
end
end
do_post (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
u_node: CMS_NODE
l_page: ROC_RESPONSE
do
if attached current_user_name (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 {CMS_NODE} api_service.node (l_id.integer_value) as l_node then
if attached {WSF_STRING} req.form_parameter ("method") as l_method then
if l_method.is_case_insensitive_equal ("PUT") then
do_put (req, res)
else
create l_page.make (req, "master2/error.tpl")
l_page.set_value ("500", "code")
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
end
else
do_error (req, res, l_id)
end
else
create l_page.make (req, "master2/error.tpl")
l_page.set_value ("500", "code")
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
else
(create {ROC_RESPONSE}.make(req,"")).new_response_unauthorized (req, res)
end
end
do_put (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
u_node: CMS_NODE
l_page: ROC_RESPONSE
do
to_implement ("Check if user has permissions")
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 {CMS_NODE} api_service.node (l_id.integer_value) as l_node then
u_node := extract_data_form (req)
u_node.set_id (l_id.integer_value)
api_service.update_node_title (l_user.id,u_node.id, u_node.title)
(create {ROC_RESPONSE}.make (req, "")).new_response_redirect (req, res, req.absolute_script_url (""))
else
do_error (req, res, l_id)
end
else
create l_page.make (req, "master2/error.tpl")
l_page.set_value ("500", "code")
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
else
(create {ROC_RESPONSE}.make(req,"")).new_response_unauthorized (req, res)
end
end
feature -- Error
do_error (req: WSF_REQUEST; res: WSF_RESPONSE; a_id: WSF_STRING)
-- Handling error.
local
l_page: ROC_RESPONSE
do
create l_page.make (req, "master2/error.tpl")
if a_id.is_integer then
-- resource not found
l_page.set_value ("404", "code")
else
-- bad request
l_page.set_value ("400", "code")
end
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
feature {NONE} -- Node
new_node (req: WSF_REQUEST; res: WSF_RESPONSE)
local
l_page: ROC_RESPONSE
do
create l_page.make (req, "modules/node.tpl")
l_page.send_to (res)
end
feature -- {NONE} Form data
extract_data_form (req: WSF_REQUEST): CMS_NODE
-- Extract request form data and build a object
-- Node
do
create Result.make ("", "", "")
if attached {WSF_STRING} req.form_parameter ("title") as l_title then
Result.set_title (l_title.value)
end
end
end

View File

@@ -1,62 +0,0 @@
note
description: "Summary description for {NODES_HANDLER}."
date: "$Date$"
revision: "$Revision$"
class
NODES_HANDLER
inherit
APP_ABSTRACT_HANDLER
rename
set_esa_config as make
end
WSF_FILTER
WSF_URI_HANDLER
rename
execute as uri_execute,
new_mapping as new_uri_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)
execute_next (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
l_page: ROC_RESPONSE
do
create l_page.make (req, "modules/nodes.tpl")
l_page.set_value (api_service.nodes, "nodes")
l_page.set_value (roc_config.is_web, "web")
l_page.set_value (roc_config.is_html, "html")
l_page.send_to (res)
end
end

View File

@@ -1,63 +0,0 @@
note
description: "Handle Login using Basic Authentication"
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
class
ROC_LOGIN_HANDLER
inherit
APP_ABSTRACT_HANDLER
rename
set_esa_config as make
end
WSF_URI_HANDLER
rename
execute as uri_execute,
new_mapping as new_uri_mapping
end
WSF_FILTER
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)
execute_next (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler.
do
execute_methods (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
do
if attached {STRING_32} current_user_name (req) as l_user then
(create {ROC_RESPONSE}.make(req,"")).new_response_redirect (req, res, req.absolute_script_url(""))
else
(create {ROC_RESPONSE}.make(req,"")).new_response_authenticate (req, res)
end
end
end

View File

@@ -1,59 +0,0 @@
note
description: "Handle Logoff for Basic Authentication"
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
class
ROC_LOGOFF_HANDLER
inherit
APP_ABSTRACT_HANDLER
rename
set_esa_config as make
end
WSF_URI_HANDLER
rename
execute as uri_execute,
new_mapping as new_uri_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_methods (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
do
log.write_information(generator + ".do_get Processing logoff")
if attached req.query_parameter ("prompt") as l_prompt then
(create {ROC_RESPONSE}.make(req,"")).new_response_unauthorized (req, res)
else
(create {ROC_RESPONSE}.make(req,"master2/logoff.tpl")).new_response_denied (req, res)
end
end
end

View File

@@ -1,63 +0,0 @@
note
description: "ROOT_HANDLER."
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
class
ROC_ROOT_HANDLER
inherit
APP_ABSTRACT_HANDLER
rename
set_esa_config as make
end
WSF_FILTER
WSF_URI_HANDLER
rename
execute as uri_execute,
new_mapping as new_uri_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)
execute_next (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
l_page: ROC_RESPONSE
do
create l_page.make (req, "layout2.tpl")
l_page.set_value (api_service.recent_nodes (0,5), "nodes")
l_page.set_value (is_web, "web")
l_page.set_value (roc_config.is_html, "html")
l_page.send_to (res)
end
end

View File

@@ -1,163 +0,0 @@
note
description: "Summary description for {USER_HANDLER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
USER_HANDLER
inherit
APP_ABSTRACT_HANDLER
rename
set_esa_config as make
end
WSF_FILTER
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_put,
do_delete
end
REFACTORING_HELPER
create
make
feature -- execute
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
execute_next (req, res)
end
uri_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
uri_template_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
feature -- HTTP Methods
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
l_page: ROC_RESPONSE
do
-- Existing node
create l_page.make (req, "modules/register.tpl")
l_page.set_value (roc_config.is_web, "web")
l_page.set_value (roc_config.is_html, "html")
l_page.send_to (res)
end
do_post (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
u_node: CMS_NODE
l_page: ROC_RESPONSE
do
-- New user
api_service.new_user (extract_data_form (req))
if api_service.successful then
(create {ROC_RESPONSE}.make (req, "")).new_response_redirect (req, res, req.absolute_script_url (""))
else
end
end
do_put (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
u_node: CMS_NODE
do
end
do_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
do
end
feature -- Error
do_error (req: WSF_REQUEST; res: WSF_RESPONSE; a_id: WSF_STRING)
-- Handling error.
local
l_page: ROC_RESPONSE
do
create l_page.make (req, "master2/error.tpl")
if a_id.is_integer then
-- resource not found
l_page.set_value ("404", "code")
else
-- bad request
l_page.set_value ("400", "code")
end
l_page.set_value (req.absolute_script_url (req.path_info), "request")
l_page.send_to (res)
end
feature {NONE} -- Node
new_node (req: WSF_REQUEST; res: WSF_RESPONSE)
local
l_page: ROC_RESPONSE
do
if attached current_user_name (req) then
create l_page.make (req, "modules/node.tpl")
l_page.send_to (res)
else
(create {ROC_RESPONSE}.make (req, "")).new_response_unauthorized (req, res)
end
end
feature -- {NONE} Form data
extract_data_form (req: WSF_REQUEST): CMS_USER
-- Extract request form data and build a object
-- user
do
create Result.make ("")
if attached {WSF_STRING} req.form_parameter ("username") as l_username then
Result.set_name (l_username)
end
if
attached {WSF_STRING} req.form_parameter ("password") as l_password and then
attached {WSF_STRING} req.form_parameter ("check_password") as l_check_password and then
l_password.value.is_case_insensitive_equal (l_check_password.value)
then
Result.set_password (l_password)
end
if attached {WSF_STRING} req.form_parameter ("email") as l_email then
Result.set_email (l_email)
end
end
end

View File

@@ -1,126 +0,0 @@
note
description: "API Service facade to the underlying business logic"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
ROC_API_SERVICE
inherit
SHARED_ERROR
REFACTORING_HELPER
create make
feature -- Initialize
make (a_storage: CMS_STORAGE)
-- Create the API service with an storege `a_storage'.
do
storage := a_storage
set_successful
ensure
storage_set: storage = a_storage
end
feature -- Access
login_valid (l_auth_login, l_auth_password: READABLE_STRING_32): BOOLEAN
local
l_security: SECURITY_PROVIDER
do
Result := storage.is_valid_credential (l_auth_login, l_auth_password)
end
feature -- Access: Node
nodes: LIST[CMS_NODE]
-- List of nodes.
do
fixme ("Implementation")
Result := storage.recent_nodes (0, 10)
end
recent_nodes (a_offset, a_rows: INTEGER): LIST[CMS_NODE]
-- List of the `a_rows' most recent nodes starting from `a_offset'.
do
Result := storage.recent_nodes (a_offset, a_rows)
end
node (a_id: INTEGER_64): detachable CMS_NODE
-- Node by ID.
do
fixme ("Check preconditions")
Result := storage.node (a_id)
end
feature -- Change: Node
new_node (a_node: CMS_NODE)
-- Add a new node
do
storage.save_node (a_node)
end
delete_node (a_id: INTEGER_64)
do
storage.delete_node (a_id)
end
update_node (a_id: like {CMS_USER}.id; a_node: CMS_NODE)
do
storage.update_node (a_id,a_node)
end
update_node_title (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_title: READABLE_STRING_32)
do
fixme ("Check preconditions")
storage.update_node_title (a_id,a_node_id,a_title)
end
update_node_summary (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_summary: READABLE_STRING_32)
do
fixme ("Check preconditions")
storage.update_node_summary (a_id,a_node_id, a_summary)
end
update_node_content (a_id: like {CMS_USER}.id; a_node_id: like {CMS_NODE}.id; a_content: READABLE_STRING_32)
do
fixme ("Check preconditions")
storage.update_node_content (a_id,a_node_id, a_content)
end
feature -- Access: User
user_by_name (a_username: READABLE_STRING_32): detachable CMS_USER
do
Result := storage.user_by_name (a_username)
end
feature -- Change User
new_user (a_user: CMS_USER)
-- Add a new user `a_user'.
do
if
attached a_user.password as l_password and then
attached a_user.email as l_email
then
storage.save_user (a_user)
else
fixme ("Add error")
end
end
feature {NONE} -- Implemenataion
storage: CMS_STORAGE
-- Persistence storage
end

View File

@@ -1,127 +0,0 @@
note
description: "Provides email access"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
ROC_EMAIL_SERVICE
inherit
SHARED_ERROR
create
make
feature {NONE} -- Initialization
make (a_smtp_server: READABLE_STRING_32)
-- Create an instance of {ESA_EMAIL_SERVICE} with an smtp_server `a_smtp_server'.
-- Using "noreplies@eiffel.com" as admin email.
local
l_address_factory: INET_ADDRESS_FACTORY
do
-- Get local host name needed in creation of SMTP_PROTOCOL.
create l_address_factory
create smtp_protocol.make (a_smtp_server, l_address_factory.create_localhost.host_name)
set_successful
end
admin_email: IMMUTABLE_STRING_8
-- Administrator email.
once
Result := "noreplies@eiffel.com"
end
webmaster_email: IMMUTABLE_STRING_8
-- Webmaster email.
once
Result := "webmaster@eiffel.com"
end
smtp_protocol: SMTP_PROTOCOL
-- SMTP protocol.
feature -- Basic Operations
send_template_email (a_to, a_token, a_host: STRING)
-- Send successful registration message containing activation code `a_token' to `a_to'.
require
attached_to: a_to /= Void
attached_token: a_token /= Void
attached_host: a_host /= Void
local
l_content: STRING
l_url: URL_ENCODER
l_path: PATH
l_html: HTML_ENCODER
l_email: EMAIL
do
if successful then
log.write_information (generator + ".send_post_registration_email to [" + a_to + "]" )
create l_path.make_current
create l_url
create l_html
create l_content.make (1024)
l_content.append ("Thank you for registering at CMS.%N%NTo complete your registration, please click on this link to activate your account:%N%N")
l_content.append (a_host)
l_content.append ("/activation?code=")
l_content.append (l_url.encoded_string (a_token))
l_content.append ("&email=")
l_content.append (l_url.encoded_string (a_to))
l_content.append ("%N%NOnce there, please enter the following information and then click the Activate Account, button.%N%N")
l_content.append ("Your e-mail: ")
l_content.append (l_html.encoded_string (a_to))
l_content.append ("%N%NYour activation code: ")
l_content.append (l_html.encoded_string(a_token))
l_content.append ("%N%NThank you for joining us.%N%N CMS team.")
l_content.append (Disclaimer)
-- Create our message.
create l_email.make_with_entry (admin_email, a_to)
l_email.set_message (l_content)
l_email.add_header_entry ({EMAIL_CONSTANTS}.H_subject, "CMS Site: Account Activation")
send_email (l_email)
end
end
send_shutdown_email (a_message: READABLE_STRING_GENERAL)
-- Send email shutdown cause by an unexpected condition.
local
l_email: EMAIL
l_content: STRING
do
create l_email.make_with_entry (admin_email, webmaster_email)
create l_content.make (2048)
l_content.append (a_message.as_string_32)
l_email.set_message (l_content)
l_email.add_header_entry ({EMAIL_CONSTANTS}.H_subject, "ROC API exception")
send_email (l_email)
end
feature {NONE} -- Implementation
send_email (a_email: EMAIL)
-- Send the email represented by `a_email'.
local
l_retried: BOOLEAN
do
if not l_retried then
log.write_information (generator + ".send_email Process send email.")
smtp_protocol.initiate_protocol
smtp_protocol.transfer (a_email)
smtp_protocol.close_protocol
log.write_information (generator + ".send_email Email sent.")
set_successful
else
log.write_error (generator + ".send_email Email not send" + last_error_message )
end
rescue
set_last_error_from_exception (generator + ".send_email")
l_retried := True
retry
end
Disclaimer: STRING = "This email is generated automatically, and the address is not monitored for responses. If you try contacting us by using %"reply%", you will not receive an answer."
-- Email not monitored disclaimer.
end

View File

@@ -1,185 +0,0 @@
note
description: "[
REST API configuration
We manage URI and Uri templates using Routers. They are used to delegate calls (to the corresponing handlers) based on a URI template.
We define a Rooter and attach handlers to it.
]"
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
class
ROC_REST_API
inherit
ROC_ABSTRACT_API
create
make
feature -- Initialization
setup_router
-- Setup `router'.
local
fhdl: WSF_FILE_SYSTEM_HANDLER
do
configure_api_root
configure_api_node
configure_api_navigation
configure_api_login
configure_api_nodes
configure_api_node_title
configure_api_node_summary
configure_api_node_content
configure_api_logoff
configure_api_register
create fhdl.make_hidden_with_path (layout.www_path)
fhdl.disable_index
fhdl.set_not_found_handler (agent (ia_uri: READABLE_STRING_8; ia_req: WSF_REQUEST; ia_res: WSF_RESPONSE)
do
execute_default (ia_req, ia_res)
end)
router.handle_with_request_methods ("/", fhdl, router.methods_GET)
end
feature -- Configure Resources Routes
configure_api_root
local
l_root_handler:ROC_ROOT_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_root_handler.make (roc_config)
create l_methods
l_methods.enable_get
router.handle_with_request_methods ("/", l_root_handler, l_methods)
end
configure_api_node
local
l_report_handler: NODE_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_report_handler.make (roc_config)
create l_methods
l_methods.enable_get
l_methods.enable_post
l_methods.enable_put
router.handle_with_request_methods ("/node", l_report_handler, l_methods)
create l_report_handler.make (roc_config)
create l_methods
l_methods.enable_get
l_methods.enable_post
l_methods.enable_put
l_methods.enable_delete
router.handle_with_request_methods ("/node/{id}", l_report_handler, l_methods)
end
configure_api_navigation
local
l_report_handler: NAVIGATION_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_report_handler.make (roc_config)
create l_methods
l_methods.enable_get
router.handle_with_request_methods ("/navigation", l_report_handler, l_methods)
end
configure_api_login
local
l_report_handler: ROC_LOGIN_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_report_handler.make (roc_config)
create l_methods
l_methods.enable_get
router.handle_with_request_methods ("/login", l_report_handler, l_methods)
end
configure_api_logoff
local
l_report_handler: ROC_LOGOFF_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_report_handler.make (roc_config)
create l_methods
l_methods.enable_get
router.handle_with_request_methods ("/logoff", l_report_handler, l_methods)
end
configure_api_nodes
local
l_report_handler: NODES_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_report_handler.make (roc_config)
create l_methods
l_methods.enable_get
router.handle_with_request_methods ("/nodes", l_report_handler, l_methods)
end
configure_api_node_summary
local
l_report_handler: NODE_SUMMARY_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_report_handler.make (roc_config)
create l_methods
l_methods.enable_get
l_methods.enable_post
l_methods.enable_put
router.handle_with_request_methods ("/node/{id}/summary", l_report_handler, l_methods)
end
configure_api_node_title
local
l_report_handler: NODE_TITLE_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_report_handler.make (roc_config)
create l_methods
l_methods.enable_get
l_methods.enable_post
l_methods.enable_put
router.handle_with_request_methods ("/node/{id}/title", l_report_handler, l_methods)
end
configure_api_node_content
local
l_report_handler: NODE_CONTENT_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_report_handler.make (roc_config)
create l_methods
l_methods.enable_get
l_methods.enable_post
l_methods.enable_put
router.handle_with_request_methods ("/node/{id}/content", l_report_handler, l_methods)
end
configure_api_register
local
l_report_handler: USER_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_report_handler.make (roc_config)
create l_methods
l_methods.enable_get
l_methods.enable_post
l_methods.enable_put
router.handle_with_request_methods ("/user", l_report_handler, l_methods)
end
end

View File

@@ -1,48 +0,0 @@
note
description: "Conneg Helper"
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
class
SHARED_CONNEG_HELPER
feature -- Access
conneg (req: WSF_REQUEST): SERVER_CONTENT_NEGOTIATION
-- Content negotiatior for all requests.
once
create Result.make ({HTTP_MIME_TYPES}.text_html, "en", "UTF-8", "identity")
end
mime_types_supported (req: WSF_REQUEST): LIST [STRING]
-- All values for Accept header that `Current' can serve.
do
create {ARRAYED_LIST [STRING]} Result.make_from_array (<<{HTTP_MIME_TYPES}.text_html, "application/vnd.collection+json">>)
Result.compare_objects
ensure
mime_types_supported_includes_default: Result.has (conneg (req).default_media_type)
end
media_type_variants (req: WSF_REQUEST): HTTP_ACCEPT_MEDIA_TYPE_VARIANTS
-- Media type negotiation.
do
Result := conneg (req).media_type_preference (mime_types_supported (req), req.http_accept)
end
compression_supported (req: WSF_REQUEST): LIST [STRING]
-- All values for Accept-Encofing header that `Current' can serve.
do
create {ARRAYED_LIST [STRING]} Result.make_from_array (<<"identity","deflate">>)
Result.compare_objects
ensure
compression_supported_includes_default: Result.has (conneg (req).default_encoding)
end
compression_variants (req: WSF_REQUEST): HTTP_ACCEPT_ENCODING_VARIANTS
-- Compression negotiation.
do
Result := conneg (req).encoding_preference (compression_supported (req), req.http_accept_encoding)
end
end

View File

@@ -1,58 +0,0 @@
note
description: "Provide input validation"
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
deferred class
ROC_INPUT_VALIDATOR
feature -- Basic Operations
input_from (a_request: ITERABLE [WSF_VALUE])
-- Update current object using parameters extracted from QUERY_STRING.
-- If there are errors they are set to the errors parameter.
do
if attached {STRING_TABLE[WSF_VALUE]} a_request as l_table_request then
validate (l_table_request)
end
end
feature -- Validation
validate (a_request: STRING_TABLE [WSF_VALUE])
-- Validate input for control `a_request'.
deferred
end
feature -- Access
acceptable_query_parameters: ARRAY[STRING]
-- The parameters are optionals, more parameters is a bad request, the order is not important.
deferred
end
feature -- Errors
errors: STRING_TABLE[READABLE_STRING_32]
-- Hash table with errors and descriptions.
has_error: BOOLEAN
-- Has errors the last request?
do
Result := not errors.is_empty
end
error_message: STRING
-- String representation.
do
create Result.make_empty
across errors as c loop
Result.append (c.item)
Result.append ("%N")
end
end
end -- class EFA_INPUT_VALIDATOR

View File

@@ -1,25 +1,32 @@
<?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="roc_api" uuid="3643E657-BCBE-46AA-931B-71EAEA877A18" library_target="roc_api">
<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 warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
<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>
<setting name="concurrency" value="none"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="layout" location="..\..\layout\layout.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_node_module" location="..\..\modules\node\node-safe.ecf" readonly="false"/>
<!--
<library name="persistence_mysql" location="..\..\library\persistence\mysql\persistence_mysql-safe.ecf" readonly="false"/>
-->
<library name="persistence_sqlite" location="..\..\library\persistence\sqlite\persistence_sqlite-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"/>
<library name="cms" location="..\..\cms\cms.ecf" readonly="false"/>
<library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension-safe.ecf" readonly="false"/>
</target>
<target name="roc_api_any" extends="common">
<target name="demo_any" extends="common">
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
<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"/>
@@ -27,24 +34,25 @@
<cluster name="launcher" location=".\launcher\any\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<target name="roc_api_nino" extends="common">
<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="roc_api_cgi" extends="common">
<target name="demo_cgi" extends="common">
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
<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="roc_api_libfcgi" extends="common">
<target name="demo_libfcgi" extends="common">
<root class="EWF_ROC_SERVER" feature="make_and_launch"/>
<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="roc_api" extends="roc_api_nino">
<target name="demo" extends="demo_nino">
</target>
</system>

2
examples/demo/demo.ini Normal file
View File

@@ -0,0 +1,2 @@
port=9090
#verbose=true

View File

@@ -6,8 +6,8 @@ note
you can customize APPLICATION_LAUNCHER
]"
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
date: "$Date: 2015-02-09 22:29:56 +0100 (lun., 09 févr. 2015) $"
revision: "$Revision: 96596 $"
deferred class
APPLICATION_LAUNCHER_I
@@ -16,7 +16,7 @@ feature -- Execution
launch (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
launcher: WSF_SERVICE_LAUNCHER
launcher: WSF_DEFAULT_SERVICE_LAUNCHER
do
create {WSF_DEFAULT_SERVICE_LAUNCHER} launcher.make_and_launch (a_service, opts)
end

View File

@@ -0,0 +1,102 @@
note
description: "Summary description for {CMS_BLOG}."
date: "$Date$"
revision: "$Revision$"
class
CMS_BLOG
inherit
CMS_NODE
redefine
make_empty,
import_node
end
create
make_empty,
make
feature {NONE} -- Initialization
make_empty
do
Precursor
end
feature -- Conversion
import_node (a_node: CMS_NODE)
-- <Precursor>
do
Precursor (a_node)
if attached {CMS_BLOG} a_node as l_blog then
-- l_blog
end
end
feature -- Access
content_type: READABLE_STRING_8
once
Result := {CMS_BLOG_NODE_TYPE}.name
end
feature -- Access: content
summary: detachable READABLE_STRING_8
-- A short summary of the node.
content: detachable READABLE_STRING_8
-- Content of the node.
format: detachable READABLE_STRING_8
-- Format associated with `content' and `summary'.
-- For example: text, mediawiki, html, etc
tags: detachable ARRAYED_LIST [READABLE_STRING_32]
-- Optional tags
feature -- Element change
set_content (a_content: like content; a_summary: like summary; a_format: like format)
do
content := a_content
summary := a_summary
format := a_format
end
add_tag (a_tag: READABLE_STRING_32)
-- Set `parent' to `a_page'
require
not a_tag.is_whitespace
local
l_tags: like tags
do
l_tags := tags
if l_tags = Void then
create l_tags.make (1)
tags := l_tags
end
l_tags.force (a_tag)
end
set_tags_from_string (a_tags: READABLE_STRING_32)
local
t: STRING_32
do
tags := Void
across
a_tags.split (',') as ic
loop
t := ic.item
t.left_adjust
t.right_adjust
if not t.is_whitespace then
add_tag (t)
end
end
end
end

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,109 @@
note
description: "Summary description for {CMS_BLOG_NODE_TYPE_WEBFORM_MANAGER}."
date: "$Date$"
revision: "$Revision$"
class
CMS_BLOG_NODE_TYPE_WEBFORM_MANAGER
inherit
CMS_NODE_TYPE_WEBFORM_MANAGER [CMS_BLOG]
redefine
content_type,
populate_form,
update_node,
new_node,
append_html_output_to
end
create
make
feature -- Access
content_type: CMS_BLOG_NODE_TYPE
-- Associated content type.
feature -- form
populate_form (response: NODE_RESPONSE; f: CMS_FORM; a_node: detachable CMS_NODE)
local
ti: WSF_FORM_TEXT_INPUT
s: STRING_32
do
Precursor (response, f, a_node)
create ti.make ("tags")
ti.set_label ("Tags")
ti.set_size (70)
if
a_node /= Void and then
attached {CMS_BLOG} a_node as a_blog and then
attached a_blog.tags as l_tags
then
create s.make_empty
across
l_tags as ic
loop
if not s.is_empty then
s.append_character (',')
end
s.append (ic.item)
end
ti.set_text_value (s)
end
ti.set_is_required (False)
f.extend (ti)
end
update_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: CMS_NODE)
do
Precursor (response, fd, a_node)
if attached fd.string_item ("tags") as l_tags then
if attached {CMS_BLOG} a_node as l_blog then
l_blog.set_tags_from_string (l_tags)
end
end
end
new_node (response: NODE_RESPONSE; fd: WSF_FORM_DATA; a_node: detachable like new_node): like content_type.new_node
-- <Precursor>
do
Result := Precursor (response, fd, a_node)
if attached fd.string_item ("tags") as l_tags then
Result.set_tags_from_string (l_tags)
end
end
feature -- Output
append_html_output_to (a_node: CMS_NODE; a_response: NODE_RESPONSE)
-- <Precursor>
local
s: STRING
do
Precursor (a_node, a_response)
if attached a_response.main_content as l_main_content then
s := l_main_content
else
create s.make_empty
end
if attached {CMS_BLOG} a_node as l_blog_post then
if attached l_blog_post.tags as l_tags then
s.append ("<div><strong>Tags:</strong> ")
across
l_tags as ic
loop
s.append ("<span class=%"tag%">")
s.append (a_response.html_encoded (ic.item))
s.append ("</span> ")
end
s.append ("</div>")
end
end
a_response.set_main_content (s)
end
end

View File

@@ -0,0 +1,115 @@
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

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="cms_demo_module" uuid="4BB59A54-2544-4C10-BFA6-01D12E541A30" library_target="cms_demo_module">
<target name="cms_demo_module">
<root all_classes="true"/>
<file_rule>
<exclude>/.git$</exclude>
<exclude>/EIFGENs$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension-safe.ecf"/>
<library name="cms" location="..\..\..\..\cms-safe.ecf" readonly="false"/>
<library name="cms_model" location="..\..\..\..\library\model\cms_model-safe.ecf" readonly="false"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
<library name="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_encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder-safe.ecf"/>
<cluster name="src" location=".\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,186 @@
note
description: "Summary description for {CMS_DEMO_MODULE}."
author: ""
date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
revision: "$Revision: 96616 $"
class
CMS_DEMO_MODULE
inherit
CMS_MODULE
redefine
register_hooks,
initialize,
is_installed,
install
end
CMS_HOOK_MENU_SYSTEM_ALTER
CMS_HOOK_BLOCK
create
make
feature {NONE} -- Initialization
make
do
name := "Demo module"
version := "1.0"
description := "Service to demonstrate and test cms system"
package := "demo"
end
feature {CMS_API} -- Module Initialization
initialize (api: CMS_API)
-- <Precursor>
do
Precursor (api)
-- Add support for CMS_PAGE, which requires a storage extension to store the optional "parent" id.
-- For now, we only have extension based on SQL statement.
-- if attached {CMS_NODE_STORAGE_SQL} l_node_api.node_storage as l_sql_node_storage then
-- l_sql_node_storage.register_node_storage_extension (create {CMS_NODE_STORAGE_SQL_PAGE_EXTENSION}.make (l_sql_node_storage))
-- end
end
feature {CMS_API} -- Module management
is_installed (api: CMS_API): BOOLEAN
-- Is Current module installed?
do
Result := attached api.storage.custom_value ("is_initialized", "module-" + name) as v and then v.is_case_insensitive_equal_general ("yes")
end
install (api: CMS_API)
local
sql: STRING
do
-- Schema
if attached {CMS_STORAGE_SQL_I} api.storage as l_sql_storage then
if not l_sql_storage.sql_table_exists ("tb_demo") then
sql := "[
CREATE TABLE "tb_demo"(
"demo_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("demo_id">=0),
"name" VARCHAR(100) NOT NULL,
"value" TEXT
);
]"
l_sql_storage.sql_execute_script (sql)
if l_sql_storage.has_error then
api.logger.put_error ("Could not initialize database for demo module", generating_type)
end
end
api.storage.set_custom_value ("is_initialized", "module-" + name, "yes")
end
end
feature -- Access: router
router (a_api: CMS_API): WSF_ROUTER
-- Node router.
do
create Result.make (2)
map_uri_template_agent (Result, "/demo/", agent handle_demo (?,?,a_api))
map_uri_template_agent (Result, "/demo/{id}", agent handle_demo_entry (?,?,a_api))
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)
end
block_list: ITERABLE [like {CMS_BLOCK}.name]
do
Result := <<"demo-info">>
end
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
local
-- b: CMS_CONTENT_BLOCK
mb: CMS_MENU_BLOCK
m: CMS_MENU
lnk: CMS_LOCAL_LINK
do
if a_block_id.is_case_insensitive_equal_general ("demo-info") then
if a_response.request.request_uri.starts_with ("/demo/") then
create m.make_with_title (a_block_id, "Demo", 2)
create lnk.make ("/demo/abc", a_response.url ("/demo/abc", Void))
m.extend (lnk)
create lnk.make ("/demo/123", a_response.url ("/demo/123", Void))
m.extend (lnk)
create mb.make (m)
a_response.add_block (mb, "sidebar_second")
end
end
end
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
local
lnk: CMS_LOCAL_LINK
-- perms: detachable ARRAYED_LIST [READABLE_STRING_8]
do
create lnk.make ("Demo", "/demo/")
a_menu_system.primary_menu.extend (lnk)
end
feature -- Handler
handle_demo,
handle_demo_entry (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: CMS_API)
local
r: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE
do
create r.make (req, res, a_api)
r.set_main_content ("NODE module does not yet implement %"" + req.path_info + "%" ...")
r.add_error_message ("NODE 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 `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)
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 `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)
end
end

View File

@@ -1,10 +1,13 @@
{
"database": {
"datasource": {
"driver": "MySQL",
"environment": "development"
"driver": "sqlite",
"environment": "sqlite"
},
"environments": {
"sqlite": {
"connection_string":"Driver=SQLite3 ODBC Driver;Database=./site/database.sqlite;LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;"
},
"test": {
"connection_string":"Server=localhost;Port=3306;Database=cms_dev;Uid=root;Pwd=;"
},
@@ -29,4 +32,4 @@
}

View File

@@ -0,0 +1,11 @@
[layout]
root-dir=site/www
themes-dir=site/themes
[site]
name=Eiffel CMS
email=your@email.com
theme=bootstrap
[misc]
smtp=localhost

View File

@@ -0,0 +1,51 @@
BEGIN;
CREATE TABLE "users"(
"uid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("uid">=0),
"name" VARCHAR(100) NOT NULL,
"password" VARCHAR(100) NOT NULL,
"salt" VARCHAR(100) NOT NULL,
"email" VARCHAR(250) NOT NULL,
"status" INTEGER,
"created" DATETIME NOT NULL,
"signed" DATETIME,
CONSTRAINT "name"
UNIQUE("name")
);
CREATE TABLE "roles"(
"rid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("rid">=0),
"name" VARCHAR(100) NOT NULL,
CONSTRAINT "name"
UNIQUE("name")
);
CREATE TABLE "users_roles"(
"uid" INTEGER NOT NULL CHECK("uid">=0),
"rid" INTEGER NOT NULL CHECK("rid">=0)
);
CREATE TABLE "role_permissions"(
"rid" INTEGER NOT NULL CHECK("rid">=0),
"permission" VARCHAR(255) NOT NULL,
"module" VARCHAR(255)
);
CREATE TABLE "logs"(
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("id">=0),
"category" VARCHAR(255) NOT NULL,
"level" INTEGER NOT NULL CHECK("level">=1),
"uid" INTEGER,
"message" TEXT NOT NULL,
"info" TEXT,
"link" TEXT,
"date" DATETIME NOT NULL
);
CREATE TABLE "custom_values"(
"type" VARCHAR(255) NOT NULL,
"name" VARCHAR(255) NOT NULL,
"value" VARCHAR(255) NOT NULL
);
COMMIT;

View File

@@ -0,0 +1,24 @@
BEGIN;
CREATE TABLE "nodes"(
"nid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("nid">=0),
"revision" INTEGER,
"type" TEXT NOT NULL,
"title" VARCHAR(255) NOT NULL,
"summary" TEXT,
"content" MEDIUMTEXT NOT NULL,
"format" VARCHAR(255),
"author" INTEGER,
"publish" DATETIME,
"created" DATETIME NOT NULL,
"changed" DATETIME NOT NULL,
"status" INTEGER
);
CREATE TABLE page_nodes(
"nid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("nid">=0),
"revision" INTEGER,
"parent" INTEGER
);
COMMIT;

View File

@@ -0,0 +1,15 @@
ul.cms-nodes {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
}
li.cms_type_page {
border-top: dotted 1px #ccc;
}
li.cms_type_page a::before {
content: "[page] ";
}
li.cms_type_page:first-child {
border-top: none;
}

View File

@@ -0,0 +1,78 @@
ul.horizontal li {
display: inline-block;
}
#header #primary.menu ul li {
color: #555;
background-color: #fff;
padding: 10px;
margin: 0;
}
#header #primary.menu ul li a {
color: #555;
text-decoration: none;
}
#header #primary.menu ul li a:hover {
color: black;
}
#header #primary.menu ul.horizontal {
border-bottom: solid 1px #ddd;
}
#header #primary.menu ul.horizontal li {
border-top: solid 3px #fff;
}
#header #primary.menu ul.horizontal li:hover {
background-color: #ffe;
border-top: solid 3px #999;
}
#header #primary.menu ul.horizontal li.active {
font-weight: bold;
border-top: solid 3px #ddd;
background-color: #ddd;
}
#header #primary.menu ul.horizontal li.active:hover {
border-top: solid 3px blue;
}
#content {
margin-left: 20px;
}
#content #highlighted {
position: relative;
border: solid 1px #ddd;
background-color: #ffc;
width: 70%;
left: 15%;
right: 15%;
padding: 5px;
font-style: italic;
}
.sidebar {
padding: 5px;
margin: 3px;
border: solid 1px #ccc;
}
.sidebar#sidebar_first {
width: 250px;
float: left;
}
.sidebar#sidebar_second {
width: 250px;
float: right;
}
#primary-tabs ul.horizontal {
list-style-type: none;
}
#primary-tabs ul.horizontal li {
display: inline;
padding: 2px 5px;
border: solid 1px #ccf;
}
#primary-tabs ul.horizontal li.active {
border-color: #99f #99f #ddd;
border-style: solid solid none;
border-width: 2px 1px 0;
padding: 2px 7px 1px;
}

File diff suppressed because one or more lines are too long

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