Compare commits

..

58 Commits

Author SHA1 Message Date
fd5e396b72 Code cleaning. 2016-01-15 18:35:53 +01:00
5bd28326c2 Added source for sql scripts. 2016-01-15 17:59:21 +01:00
eef2a52f48 Integrated new registration workflow.
Added optional "mailer.subject_prefix" configuration item.
Added CMS_SETUP.utf_8_site_name for convenience.
Fixed a few potential unicode issues.
Fixed various typos.
2016-01-15 17:46:56 +01:00
a6642e9f3e Fixed location of library "http_client_extension" in recaptcha library. 2016-01-15 14:11:51 +01:00
affe3beb27 Merge branch 'roc_register' of https://github.com/jvelilla/ROC into roc_register 2016-01-15 13:30:58 +01:00
a013efd6f7 Cosmetic in DEMO_CMS_EXECUTION
Removed persistence/mysql which is not used.
2016-01-15 13:30:07 +01:00
jvelilla
2f95c66295 Removed unneeded template
Updated Sql sentence.
2016-01-14 08:39:35 -03:00
f6885ff581 remove roc.exe 2016-01-13 22:05:49 +01:00
de443a2163 Do not use ODBC by default.
(bad for default, since it depends on odbc drivers to be installed)
2016-01-13 17:30:38 +01:00
a179ee3239 Reverted executable name to "demo" 2016-01-13 10:38:27 +01:00
ed0d9c8d07 Use {CMS_LOG}.level_notice and related constant when using api.log(..) 2016-01-12 16:14:54 +01:00
67fbee737d Keep only sqlite3 persistence as default.
To include mysql and other, uncomment related code in demo-safe.ecf and demo_cms_execution.
2016-01-12 16:14:18 +01:00
jvelilla
f244e86f13 Updated user.sql added tabled auth_temp_users.
Added CMS_TEMP_USER as part of the core.
Moved the code from CMS_TEMP_USER_API and CMS_TEMP_USER_STORAGE_* to
CMS_USER_API and CMS_USER_STORAGE_*.
2016-01-12 09:34:39 -03:00
jvelilla
0cf6e59a76 Updated templates and fixed typos.
Renamed classes
2016-01-08 20:26:34 -03:00
56b9355f3c Updated email messaging of Auth modules to use the CMS_API.process_email (..) system.
as a consequence, removed usage of email_service library.
Updated the meaning for site.email to be sender email addressed.
Added notification.email to set the email address that will received system email notification.
2016-01-08 22:24:52 +01:00
jvelilla
0ca336d467 Updated templates
Replaced hardcoded name "ROC CMS" for placeholder $sitename, and
missing href's with $host.
Renamed database script and database table for temporal users.
Renamed CMS_AUTH_API AS CMS_USER_TEMP_API.
Revert design to use CMS_TEMPORAL_USER and clean CMS_USER.
Refactor rename cms_auth_storage_* classes to CMS_TEMPORAL_USER_STORAGE_*
Added Pending Registrations to the admin menu to show the list of pending registrarions
added CSS to display temporal users
2016-01-06 21:29:21 -03:00
jvelilla
5d8ea2065e Rename script name and table name for
temporary users.
Updated message, after account reactivation.
Updated message, post account application.
Updated Form name, Registration instead of Registration Form.
Updated CMS_USER to have two optional features used for temporary users.
Updated CMS_AUTH_API to user CMS_USER instead of CMS_TEMPORAL_USER
Removed CMS_TEMPORAL_USER
Updateed CMS_AUTHENTICATION_MODULE, with new permission to enable
activate, reject or reactivate a pending user registration.
Updated User Storage and API to create a new user from a temporal user.
2016-01-04 21:14:13 -03:00
jvelilla
682193d116 Updated Register Module.
Worlflow

1- Register
1.1 Create a new temporal user
1.2 Email to the new User
1.3 Email to Web Master
2 Web Master Review th Account Application
2.1 Accept and Send an confirmation email to the user and remove the temporal user
2.2 Reject the application send a rejection email to the user and remove the temporal

Added a new table to save temporal users to review their Application to the site.
Updated Register Form with an new input Application and Recaptcha validation.
Updated Emails templates and messages. (TODO improve messages)
Updated mails templates. Simple messages (Todo improve messages).
Added a new handler to reject a user
Updated existing hanlders to handler the new workflow.
2015-12-30 12:32:00 -03:00
0813abe0bb Fixed ROC CMS library compilation. 2015-12-18 15:29:43 +01:00
1094acb3ec Removed unused local variable 2015-12-16 21:05:57 +01:00
e7c9a54f3f Removed unused local. 2015-12-16 21:03:15 +01:00
bbbdac12c8 Moved taxonomy html generation to CMS_TAXONOMY_API. 2015-12-16 21:03:03 +01:00
jvelilla
22528315cb Removed unneeded file. 2015-12-16 16:01:02 +01:00
jvelilla
090a48eb85 Updated class CMS_TOKEN_GENERATOR.
Remove once in sha1 feature.
Updated encoded_base_64 to base_64
2015-12-16 16:01:01 +01:00
jvelilla
e05c4dca3a Fixed typos
Renamed class CMS_SESSION_CONSTANT to CMS_SESSION_CONSTANTS
Removed unneeded classes and files.
Update SQL implementation.
2015-12-16 16:00:59 +01:00
jvelilla
2255fcc0f6 Added Module Session Authentication with Cookies.
Updated Demo example with the Module Session (Authentication with Cookies)
Fixed little issue with SQL query in OpenID module.
2015-12-16 16:00:58 +01:00
e50fb6959e Moved taxonomy integration for web form inside CMS_TAXONOMY_API.
Moved a few helpers routine from CMS_RESPONSE to CMS_API.
Added CMS_CONTENT.identifier: detachable READABLE_STRING_32 .
2015-12-16 15:59:22 +01:00
jvelilla
3b88c746a1 Removed unneeded file. 2015-12-16 10:43:21 -03:00
jvelilla
fa8ef44a4a Merge branch 'jvelilla-roc_login_session' 2015-12-16 10:11:55 -03:00
jvelilla
068943734f Updated class CMS_TOKEN_GENERATOR.
Remove once in sha1 feature.
Updated encoded_base_64 to base_64
2015-12-16 10:03:35 -03:00
jvelilla
089179e60e Fixed typos
Renamed class CMS_SESSION_CONSTANT to CMS_SESSION_CONSTANTS
Removed unneeded classes and files.
Update SQL implementation.
2015-12-15 15:32:31 -03:00
jvelilla
c25590c9cd Added Module Session Authentication with Cookies.
Updated Demo example with the Module Session (Authentication with Cookies)
Fixed little issue with SQL query in OpenID module.
2015-12-13 18:19:25 -03:00
23d266497b Made the SQL storage more flexible with INTEGER_32, by allowing to retrieve INTEGER_64 and convert to INTEGER_32 if value can be converted to integer 32. 2015-12-10 11:26:28 +01:00
ce8de442e9 Implemented taxonomy administration pages
- create term, vocabulary, add or remove term from vocabularies, ...
Fixed content editing related to taxonomy  (especially with multiple terms vs tags).
Fixed various SQL storage issue related to taxonomy and vocabularies.
Added CMS_RESPONSE.wsf_theme as helper.
2015-12-10 11:21:20 +01:00
e3ae564746 Removed an obsolete call to CMS_RESPONSE.hooks . 2015-12-07 22:08:37 +01:00
b0626d5250 Use + instead of concat(..) in javascript. 2015-12-07 21:36:24 +01:00
276dcc6fcd Added back CMS_MODULE.register_modules (CMS_RESPONSE) as obsolete, to avoid breaking existing modules.
Note: all module SHOULD migrate to new hook setup!
2015-12-07 21:24:48 +01:00
6313007fbf Refactored and update CMS hooks design. (Move from CMS_RESPONSE to CMS_API).
Moved content_types and content_type_webform_managers from CMS_RESPONSE to CMS_API.
Updated the way to output content (node, ...) to html page.
   See CMS_CONTENT_TYPE_WEBFORM_MANAGER.append_cointent_as_html_to (...).
   Added notion of "teaser" (short version of the content), as opposed to full content.
One can use CMS_API.html_encoder ... when possible, same for `formats', ...
Added bridge from CMS_MODULE_API to CMS_API's encoders.
Added new CMS_TAXONOMY_HOOK used to retrieve list of content associated with a specific term.
Moved up to CMS_RESPONSE a few features which was available only in specific descendants.

Added /taxonomy/term/{termid} implementation.
2015-12-07 18:21:40 +01:00
ecbcb6a5cb Added notion of CMS_CONTENT as ancestor of CMS_NODE.
Moved CMS_CONTENT_TYPE to core library.
Added basic and limited taxonomy query /taxonomy/term/{termid} .
2015-12-03 23:01:31 +01:00
a5c117e46e Merge branch 'taxonomy' 2015-12-03 19:26:43 +01:00
20dfce1396 Improved taxonomy by supporting tags, multiple terms allowed, and required kind of vocabulary for specific content type.
Updated node web form, to support taxonomy editing if allowed (specific support for CMS_VOCABULARY.is_tags: BOOLEAN).
Added notion of required or optional module dependencies.
2015-12-03 19:24:58 +01:00
jvelilla
1bfc4a6741 Merge branch 'jvelilla-roc_delete_trash' 2015-12-03 06:51:37 -03:00
jvelilla
3fdbcb2eef Merge branch 'roc_delete_trash' of https://github.com/jvelilla/ROC into jvelilla-roc_delete_trash 2015-12-03 06:50:59 -03:00
jvelilla
a11a93c285 Update code to use CMS_API.unset_path_alias
Updated CMS_NODE_STORAGE_SQL renamed sql_restore_node as sql_update_note_status, updated
related code.
2015-12-02 16:14:54 -03:00
jvelilla
fade19bbee Added precondition to NODE_FORM_RESPONSE.new_delete_form
Added transaction support to CMS_NODE_STORAGE_SQL.delete_node_base
2015-12-02 12:10:03 -03:00
jvelilla
d10612f94b Made test.ecf compilable. 2015-12-02 10:56:18 -03:00
jvelilla
9da8b8a025 Fixed: delete-trash a node.
Added code to remove path_aliase when we delete a node.
2015-12-01 19:20:16 -03:00
f1f3c126dd Use module site files system for the (un)install SQL scripts.
Changed CMS_TERM.id type to INTEGER_64 .
Removed CMS_TERM.parent_id .
Implemented CMS_TERM saving.
2015-11-23 18:05:53 +01:00
1d4ce37ebf Added CMS_STORAGE.as_sql_storage: detachable CMS_STORAGE_SQL_I to ease development based on SQL database. 2015-11-23 18:03:55 +01:00
Jocelyn Fiat
10102e80fa Fixed a few grammar and style errors. 2015-11-23 16:57:49 +01:00
3791ffacdc Added first steps toward Taxonomy module. 2015-11-23 15:27:04 +01:00
b8920ee8b3 Added module administration from /admin/modules/ 2015-11-23 11:08:06 +01:00
2cf2b1da8c Merge branch 'master' of https://github.com/EiffelWebFramework/ROC 2015-11-17 22:19:34 +01:00
17ae27df40 Updated ROC CMS documentation.
Cosmetic, comments, typo.
2015-11-17 22:18:02 +01:00
Jocelyn Fiat
a976b1e21a Create doc/readme.md 2015-11-13 15:53:45 +01:00
04df6b85f0 Removed unused local variables. 2015-11-12 18:48:37 +01:00
79d30ee3a7 Added export of core data, such as users, path_aliases, custom_values.
Added export of node revisions.
2015-11-12 18:19:06 +01:00
a5973c9c8a Added exportation solution via CMS_HOOK_EXPORT.
Updated blocks settings for demo example project.
2015-11-10 10:30:10 +01:00
165 changed files with 8945 additions and 1391 deletions

View File

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

View File

BIN
doc/img_diagram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

396
doc/readme.md Normal file
View File

@@ -0,0 +1,396 @@
ROC CMS Documentation
=====================
[TOC]
## Overview
**ROC CMS** stands for "REST On CMS", however, until now, no particular focus was done on the REST API approach, and so far a more pragmatic approach dominated.
Part of the design is inspired by Drupal (blocks, hooks, Role-based access control, ...), and other parts related to Eiffel. Priorities, modules and related have been driven by concrete need, in order to fulfill the https://eiffel.org/ websites. Also a contribution (as student projects, or others) helped build various modules or functionality.
Currently, **ROC CMS** is a library or **framework** that provides components, tools and resources to build a CMS (Content Management System). It is not currently a CMS product, one can install and customize without any code.
Thus, it will be interesting for people willing to build a website using **Eiffel**. This will enable to reuse other Eiffel components, better integration with other Eiffel projects, and of course benefit from all the goodies of the Eiffel technologies (Eiffel language, DbC, re-usability, portability, IDE, debugger,...).
It depends on the **Eiffel Web Framework** (known as "Eiffel Web" or "EWF"), and thus can be executed as standalone, or CGI, libFCGI mode on Apache2 for instance, and on any Windows or Linux platform).
The main notions are:
- CMS Execution
- CMS APIs
- CMS Response
- CMS Modules
- CMS Hooks
- CMS Theme, blocks, links, ...
Those points will be described later in appropriated sections.
## Setup
The ROC CMS source is available either with the latest EiffelStudio release under the locations:
- $ISE_LIBRARY\unstable\library\web\cms
- or from github project https://github.com/EiffelWebFramework/ROC branch v0 for now.
```
git clone https://github.com/EiffelWebFramework/ROC -b v0
```
Note that if you use the source code from the github repository, you will need to use the latest release of EiffelStudio as it relieѕ on recent version of various libraries such as EWF, sqlite3, ....
And using the "master" branch, even the trunk version of EiffelStudio libraries. So for now, we encourage you to use the ROC CMS shipped with your EiffelStudio.
Once you have the source code, you should compile project <code>cms/example/demo/demo-safe.ecf</code> target "demo_standalone".
```
# from Command line
cd example
cd demo
ec -config demo-safe.ecf -c_compile -finalize
cp ./EIFGENs/demo_standalone/F_Code/demo.exe demo.exe
demo.exe
# or launch EiffelStudio, and open that project, compile and execute it inside the debugger for instance.
````
This demo includes all the official ROC CMS modules, files, and use libsqlite3 as default storage engine. So you should be able to execute it easily. The **standalone** target is configured to listen on port 9090 by default. (Mostly to avoid conflict on other app that my listen on port 80 or 8080).
In the directory <code>site</code> you will find all the expected files that should be in the root directory.
* config/ : it contains the various configuration files, especially the **cms.ini**.
* modules/ : files associated with each installed ROC CMS module.
* scripts/ : common scripts used mainly to initialize SQL databases.
* themes/ : folder containing the available ROC CMS themes.
* files/ : folder containing files available from the ROC CMS app.
* And also demo.ini that contains the settings for the web launcher, (in our case, the standalone Eiffel server), such as port_number.
Now that you know how to compile, execute, and see the related configuration files, let's describes the main notions of the ROC CMS, first from
* an admin point of view (dev using ROC CMS to build its site),
* and then from a developer point of view (in case you want to contribute to ROC CMS).
## Usage
### Main entries
As a CMS administrator, you will need to setup your CMS application (here the demo example). For this purpose, the main entry points are the CMS_EXECUTION interface, and then the <code>site/</code> files (configuration, themes, templates, ...).
### CMS initialization/Execution
The `CMS_EXECUTION` interface is deferred, and your CMS application needs to inherit from it and define `setup_storage`, `initial_cms_setup` and `setup_modules`. See for instance `DEMO_CMS_EXECUTION`.
So, the descendant of `CMS_EXECUTION` (`DEMO_CMS_EXECUTION` in the example), is creating the `CMS_SETUP`, declares the available **storage** builders (for persistency), and declares the available **modules**.
#### Persistence/Storage
Depending on the **configuration**, the CMS engine will instantiate and use a specific **CMS_STORAGE** (the default is based on `Eiffel sqlite3`, otherwise `EiffelStore+MySQL` and `EiffelStore+ODBC` are available). The storage solution is used to implement the persistence layer, and thus store and load CMS data to disk, or database.
The CMS provides, for now, storage based on
* EiffelStore + MySQL
* EiffelStore + ODBC (could be used for MySQL, sqlite, SQLserver, ...)
* Eiffel sqlite3 : that one is the default storage, since it is convenient for testing, but it is recommended to use EiffelStore+MySQL in production CMS site.
A typical implementation of <code>setup_storage</code> is:
```eiffel
setup_storage (a_setup: CMS_SETUP)
do
a_setup.storage_drivers.force (create {CMS_STORAGE_SQLITE3_BUILDER}.make, "sqlite3")
-- a_setup.storage_drivers.force (create {CMS_STORAGE_STORE_ODBC_BUILDER}.make, "odbc")
end
```
And the CMS decides which storage should be used. It depends on the application configuration. See the **configuration** section.
Those data could be user information (login, email, password, ...), custom values, logs, emails, path aliases, ... and any data modules may need to store (for instance node content, for the `node` module.)
#### Modules
The `setup_module` is used to declare available **modules** (instances of `CMS_MODULE` effective types).
The modular design provides a simple way to extend or alter the CMS functionalities/behaviors.
Most of the CMS features are implemented by modules, and each module relies on the core of the CMS core.
This **core** contains the `CMS_API`, `CMS_USER_API`, and various internal mechanisms such as mailer, logger, ...
Use `setup_module (a_setup: CMS_SETUP)` to customize the `CMS_SETUP` object created by `initial_cms_setup`.
For your convenience, ROC CMS provides a `CMS_DEFAULT_SETUP` that import configuration from `site/config/cms.ini`
So far, what you need to remember is `CMS_EXECUTION` class and descendants are used to set up the ROC CMS application, for storage, modules, and also how to load configuration.
Note that a module can have 3 states:
- not installed,
- installed and enabled,
- installed and disabled.
At first, to install the modules, open your browser at location `https://hostname:port/admin/install` and click the associated button.
(Note: for new module addition, you also need to install them, using the same link, in the future, there will be a proper module management interface, in the admin front-end.)
To enable or disable a module, you will need to use the `cms.ini` configuration file, please see the **configuration** section.
Existing modules:
- **admin**: basic administration pages, to manage modules, roles, permissions, users, caches, ... (note: it is still very basic, and need effort to improve it.)
- authentication modules based on **auth**:
- **basic_auth**: account signing using basic HTTP Authorization solution
- **oauth20**: sign using a thirdparty OAuth2.0 account (such as Google, Facebook, github, ...)
- **openid**: sign using an OpenID account.
- **node**: the base of node management, include **Page** content type.
- **blog**: extends the **node** module with a **blog** content type.
- **recent_changes**: compute recent changes of CMS (integration with **node** management, and any modules that implement the `CMS_RECENT_CHANGES_HOOK`).
- **feed_aggregator**: aggregate one or many feeds (rss, atom, ...), and provide associated pages or blocks.
- **google_search**: provides search facilities using the Google Custom Search API.
### Configuration
When `CMS_DEFAULT_SETUP` is used, the CMS configuration is loaded from `site/config/cms.ini`.
That file contains a few sections:
- **site**: to set the `name`, `email` and the name of the `theme`. (See "Themes" section pour information.)
- **layout**: the application layout (or environment) can precise the `root-dir`, `themes-dir`, `modules-dir`. If not defined, the values are computed from Current working directory.
- **mailer**: the CMS can send email notification for various reasons, such as new users, or reset password functionalities, ... In this section, you can use
- `smtp` settings to precise an SMTP server (+ port),
- or `sendmail` to use an external script using the sendmail usage,
- or just an `output` file such as @stderr, or a path to a file on disk.
- **modules**: used to enable or disable modules.
- `*=on` -> modules are enabled by default
- `*=off` -> modules are disabled by default
- Note the default value is `on`
- For each module, this can be overwritten with `module_name=on|off`
- **blocks**: settings for blocks (See Themes, Blocks sections for more information on the block). A few parameters are available to customize blocks. The general form is `block-name.param=value` (note that "foo.bar" is a value block name.)
- `block-name.region`: assign the block `block-name` to a specific region. A block can be assigned to **only one region**.
- `block-name.title`: used to overwrite the block title (with <none> , the title is hidden).
- `block-name.weight`: used to order blocks in the same region (blocks with lower weight goes first).
- `block-name.expiration`: used to provide a basic cache system based on expiration. The value is a number of seconds before the cache expires (-1: never expires, 0: never cache, n: cache expires after `n` seconds).
- `block-name.condition`, or `block-name.conditions[]`: include `block-name` only under specific condition(s). The condition can be
- `is_front`: which is True only for the front page, usually at url "/"
- `path:foo/bar`, `path:foo/*/bar`: True only for CMS location matching the patterns after "path:"
- `<none>`: related block is disabled.
- *note: There can be multiple conditions processed as any of the conditions (i.e: "or").*
- `block-name.options[varname]: pass a table of options `varname => value` to the related block. This can be used to pass parameters for block builder (for instance, recent_changes modules accept parameters "size" to know how many changes should be included.)
- To be able to include a block content into multiple region, it is possible to use aliases feature. For instance `&aliases[new_block]=block-name`, in this case, a `new_block` is declared, and it has same content as `block-name`, on this alias, the parameters `region, condition(s), title, weight` are supported, but not `options[]`.
- **admin**: various admin related settings such as
- `installation_access` which accepts 3 values: "all", "none" or "permission", to precise who has access to the modules installation page; either "all" for anyone, "none" to disable installation of new modules, or "permission" to use the CMS permissions solution to determine if the current user can install a new module.
Then, the configuration `cms.ini` can also define other parameters, and sections, that may be used by specific modules.
Note it is also possible to include another ini file with instruction `@include=path-to-file.ini`.
Check the `example/demo/site/cms.ini` for example.
### User management
The CMS core includes the notion of user, via interface `CMS_USER`, which has an id, a name, a password, ... and profile. Without any module, the CMS does not include any mean to authenticate, but still the CMS has the support for user management, and permissions system for current user. To be able to sign into the CMS, the site should include the module `auth`, and one or many of:
- `basic_auth`: authentication using the HTTP Authorization header.
- `oauth20`: being able to sign with an OAuth2.0 account (such as Google, Facebook, ...)
- `OpenID`: being able to sign with an OpenID account.
Whatever authentication solution is used, when a user is signed-in, there is an instance of `CMS_USER` representing the associated CMS user account.
There is a predefined user `admin` who is the administrator of the CMS, and by definition, this **admin** has all the permissions. It is initialized by default with username `admin` and password `istrator#`.
The access control is role-based permissions system. This means, a user can have one or many *roles*, and each *role* includes a list of *permissions*.
There are two built-in roles:
- **anonymous**: when no user is signed in (typically anonymous visitors).
- **authenticated**: when a user is signed in the CMS.
With those 2 built-ins roles, and any custom role the admin will create, it is possible to give specific permissions, to a group of users.
The CMS core defines a few permissions, and each module can also define their own permissions, for instance: "view any page", "create page", "edit page", "delete page", "clear cache", "install modules", ... (when the administrator is signed-in, go to url `/admin/role/1/edit` to see all the available permissions).
### Modules
A module is the way to extend the CMS engine.
First via the inherited `CMS_MODULE` interface that enables a module to:
- have a custom `install` and `uninstall` procedure by redefining the related routines.
- add its **routes** via `setup_router`. (i.e associated url or template of url with a specific request handler).
- register itself to hooks via `register_hooks`.
- declare new permissions by redefining `permissions`.
- provide a specific module api by redefining `module_api`.
- add its **filters** by redefining `filters`.
Using the `hooks` system, a module can be deeply integrated with the CMS engine, and even alter behaviors (for instance, add link, add css, javascript, ...). See related developer documentation on hooks.
It is simple to create your own modules (check the developer documentation).
The ROC CMS library provides a few modules for now, for instance: basic_auth, oauth20, openid, node, blog, feed_aggregator, recent_changes, google_search, ... and others (the list keeps growing...).
**Reminder**: to include a module to your CMS site, you need to
- include the associated .ecf file in your CMS site .ecf file.
- and also declare them in your descendant of CMS_EXECUTION.
- copy the eventual resources, configuration, ... files in the corresponding `site`.
Note: a tool **roc** is under development to ease such operations, for now it only copies needed files from module to site location. In the future, it should also update .ecf files, associated CMS_EXECUTION effective class.
### Themes
When talking about CMS, a major topic is how a request is rendered in a web browser. Here comes the notion of **theme** which is a collection of templates, accepting various values as input (including the content of the blocks), and renders as an html5 page. It also includes various assets such as css, javascript, icons, images, ...
The ROC CMS theming is inspired by Drupal, with the notion of **region** and **block**.
Note: for now, there is no simple "theme" module or similar, and the common way to start your CMS site is to copy an existing project such as the one available with the demo example (i.e: copying the source code, but also the `site` folder).
Currently the default theme of the demo example `SMARTY_CMS_THEME` is based on Eiffel **smarty** template library (Check [smarty doc](https://svn.eiffel.com/eiffelstudio/trunk/Src/contrib/library/text/template/smarty/README.md) for syntax and functionalities).
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.
```
+----------------------------------------------------------+
| Page_top |
+----------------------------------------------------------+
| Header |
+---------------+-------------------------+----------------+
| | Highlighted | |
| Sidebar_first +-------------------------+ Sidebar_second |
| | Help | |
| +-------------------------+ |
| | | |
| | Content | |
| | | |
+---------------+-------------------------+----------------+
| Footer |
+----------------------------------------------------------+
| Page_bottom |
+----------------------------------------------------------+
```
The regions available for a theme, are defined in a configuration file `theme.info` located in the theme directory. For example:
```
name=default_theme
engine=smarty
version=0.1
regions[page_top] = Top
regions[header] = Header
regions[content] = Content
regions[highlighted] = Highlighted
regions[help] = Help
regions[footer] = Footer
regions[sidebar_first] = first sidebar
regions[sidebar_second] = second sidebar
regions[page_bottom] = Bottom
```
Note: the value for each region is the human readable region name.
Note the regions may be disposed with other layout (two sidebars on the left, or right, ... and so on), responsive design or not, and so on. But on the CMS side, a *block* can be inserted into a *region*, and depending if the region is included in the theme, the related block content will be displayed or not.
To sort *block* inside a region, the CMS is using the `weight` property (that can be set via code, and/or overridden via configuration, i.e: `cms.ini`).
This is how a site can support many themes, using the region as content holders, and theme for the layout and style.
Internally the block contents are stored in the values associated with each region.
The theme also has access to specific `values` such as
- `site_url`: the absolute url of the CMS website.
- `host`: the host name.
- `is_https`: True if the connection is using https://
- `user`: contains the username of the signed user, if any.
- `site_title`: site title.
- `page_title`: per page title.
- and also `page: CMS_HTML_PAGE` which represents the CMS page to render with the theme.
- `page` provides values via expression, such as `$page.type`, `$page.is_front`, `$page.is_https`, `$page.title`, ...
- and also a smart expression for region via `$page.region_xyz` for region `xyz` if any, ... (note the region are also available with expression like `$region_xyz` or `$page.region_xyz` ...)
==Note for developers: internally, the deferred class `CMS_RESPONSE` provides an abstraction to render the response for the request using the **theme**, in fact, the theme is controlled by the CMS_RESPONSE implementation (to set value, build expected theme, and finally render as html).==
### Blocks
As previously said, a region holds smaller piece of content called blocks.
Blocks hold chunks of content, like the user login form, navigation menu, information for the footer, or anything provided by each module.
For instance the `feed_aggregator` module provides a block to display the latest elements of a aggregated feed.
Currently there are different kind of `CMS_BLOCK`:
- `CMS_CONTENT_BLOCK`: it holds a simple text to render as it is on the page.
- `CMS_MENU_BLOCK`: it holds a `CMS_MENU` as a collection of `CMS_LINK` generally used to hold a menu, or set of links such as navigation or management menus.
- `CMS_SMARTY_TEMPLATE_BLOCK`: it holds a simple text to render as it is in the page.
Internally, there are two other kinds of block:
- `CMS_ALIAS_BLOCK`: being the alias of another block, but with specific properties.
- `CMS_CACHE_BLOCK`: there is a simple cache solution for blocks, based on expiration. See the configuration section to know how to define the expiration for a block.
For now, creating a block is only possible via block, an evolution of ROC CMS should allow the administrator to add new block without coding.
### Persistence
The persistence or storage layer is used by the CMS to store custom values, path aliases, logs, emails, user information, but it is also used by module (unless a module wants to use its own persistence solution, disk, cloud, ...).
Currently, there are only SQL based implementations of that `CMS_STORAGE`, but nothing prevents to implement it with other solutions (plain text file, NoSQL db, ...).
The current implementation are using either:
- EiffelStore + MySQL: recommended for production, however Eiffel MySQL requires to configure your environment by setting, for instance MYSQL variable on Windows, and MYSQLINC on Linux.
- EiffelStore + ODBC: via ODBC, there is a large range of available database (MySQL, SQLite, SQLserver, ...), but it requires to set up your environment (for instance install sqliteODBC driver to use SQLite database).
- Eiffel sqlite3 wrapper: it is very convenient for development, but maybe not recommended for production websites. It does not require any environment setup, so this is a simple solution to build tests for instance.
In practice, how to use a storage or another?
The project needs to include the expected storage, the following instructions explains how to include sqlite3, EiffelStore+ODBC and EiffelStore+MYSQL storage.
1. First the associated .ecf file need to be included in your project file (.ecf)
For instance
```xml
<library name="persistence_sqlite3" location="$ISE_LIBRARY\unstable\library\web\cms\library\persistence\sqlite3\sqlite3-safe.ecf"/>
<library name="persistence_store_odbc" location="$ISE_LIBRARY\unstable\library\web\cms\library\persistence\store_odbc\store_odbc-safe.ecf"/>
<library name="persistence_store_mysql" location="$ISE_LIBRARY\unstable\library\web\cms\library\persistence\store_mysql\store_mysql-safe.ecf"/>
```
2. Then in the descendant of `CMS_EXECUTION`, in the demo `DEMO_CMS_EXECUTION`, see the code of `setup_storage`:
```eiffel
setup_storage (a_setup: CMS_SETUP)
do
a_setup.storage_drivers.force (create {CMS_STORAGE_SQLITE3_BUILDER}.make, "sqlite3")
a_setup.storage_drivers.force (create {CMS_STORAGE_STORE_MYSQL_BUILDER}.make, "mysql")
a_setup.storage_drivers.force (create {CMS_STORAGE_STORE_ODBC_BUILDER}.make, "odbc")
end
```
3. And finally, in the configuration file `site/config/demo.json` (in fact, the executable name + ".json"), define the driver and environment of the datasource. For instance the following code defines **sqlite3** as default CMS storage, and environment *sqlite3* that defines the path of SQLite database as "site/database.sqlite3". Note the way to declare sqlite with ODBC, mysql with ODBC, or mysql directly with EiffelStore.
```json
{
"database": {
"datasource": {
"driver": "sqlite3",
"environment": "sqlite3",
},
"environments": {
"sqlite3": {
"connection_string":"Database=./site/database.sqlite3;"
},
"odbc-sqlite": {
"connection_string":"Driver=SQLite3 ODBC Driver;Database=./site/database.sqlite;LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;"
},
"odbc-mysql": {
"connection_string":"Driver=mysql ODBC Driver;Server=localhost;Port=3306;Database=roc;Uid=roc;Pwd=roc;"
},
"mysql": {
"connection_string":"Driver=mysql;Server=localhost;Port=3306;Database=roc;Uid=roc;Pwd=roc;"
}
}
}
}
```
To use EiffelStore+MySQL, just change the "driver" to be "mysql" and "environment" to "mysql". The connection string for server database defines the credentials with "Uid" and "Pwd".
### How to run the CMS site?
As any Eiffel Web application (EWF), it can be executed as
- **standalone**: using Eiffel standalone httpd server included in the "standalone" connector, and then no setup is needed.
- **CGI** or **libFCGI** server: using, for instance, Apache2. Please refer to the Eiffel Web Framework documentation.
### Conclusion
At this point, you know enough to build and administrate a ROC CMS site.
However, for a real site, it is likely that you will need to build your own modules, you will learn how doing that in the Developer Documentation.
***
## Developper Documentation
This diagram shows the main interfaces, they will be described in this documentation, but for now, it introduces those class names.
![Diagram](img_diagram.png)
### CMS APIs
An instance of CMS_API is available either via argument, or via attribute / function of various CMS components.
It provides routine specific to the ROC CMS engine (access to setup, modules, logs, custom values, ...).
### CMS Hooks
Hooks is a mechanism which provides a way for modules to interact with each other and extending blocks of the current CMS.
- [CMS_HOOK](../library/src/hooks/cms_hook.e): deferred class CMS_HOOK is a marker interface for CMS Hook
- [CMS_HOOK_AUTO_REGISTER](../library/src/hooks/cms_hook_auto_register.e): when inheriting from this deferred class, the declared hooks are automatically registered (note only the CMS core hooks are supported, as opposed to hook a module may propose). Otherwise, each descendant has to register itself to the associated hook manager.
- [CMS_HOOK_BLOCK](../library/src/hooks/cms_hook_block.e): it provides a way to declare and build blocks.
- [CMS_HOOK_FORM_ALTER](../library/src/hooks/cms_hook_form_alter.e): it provides a way to alter a web form `CMS_FORM`.
- [CMS_HOOK_MENU_ALTER](../library/src/hooks/cms_hook_menu_alter.e): it provides a way to alter a menu, and thus add or remove a link. This is how a module can add a link into a specific `CMS_MENU`.
- [CMS_HOOK_MENU_SYSTEM_ALTER](../library/src/hooks/cms_hook_menu_system_alter.e): similar to CMS_HOOK_MENU_ALTER, but on built-in menu, such as management, navigation menus, and other.
- [CMS_HOOK_VALUE_TABLE_ALTER](../library/src/hooks/cms_hook_value_table_alter.e): it provides a way to alter the values table for a response (i.e: inserting custom values, or even override existing values).
- [CMS_HOOK_EXPORT](../library/src/hooks/cms_hook_export.e): it provides a simple export solution for each module. Typically used to archive data associated with a module, for instance for backup purpose. In the future, a `CMS_HOOK_IMPORT` should also be available, and it would allow importing data exported by `CMS_HOOK_EXPORT`.
- and for more hooks ... please check descendants of `CMS_HOOK`.
### Custom Module
How to build a new module?
A module is usually developed as an Eiffel library, and provide one or many implementations of `CMS_MODULE`.
It has to set or implement:
- **name**: a unique name identifying the module
- **description**: a human text to describe the purpose of the module, it will mainly be used by the administration front-end.
- **package**: put the current module into a package, mainly for admin front-end.
- **version**: version information
- **dependencies**: defines dependencies on other modules.
- **permissions**: defines permissions used by the modules (mainly for admin front-end)
- **setup_router**: associate routes with request handlers (declare various url or url template and associated request handler).
- **filters**: similar to routers setup, but for WSF Filters (See EWF documentation for more details).
- **register_hooks**: register current module with various hooks if needed.
A module can also redefine `install` and `uninstall`. This could be used during installation to create new database tables, or anything needed by the module, or clean similar resources when being uninstalled.
In addition, a module can also implement `module_api: detachable CMS_MODULE_API` in order to be integrated easily with other modules (see for instance the CMS_NODE_API defined in **node** module).
Please have a look at the [tutorial](tutorial.md) page.
## References
For the interface references, please have a look at the [ROC CMS source code](https://github.com/EiffelWebFramework/ROC).
***
*(last modified: Nov/17/2015 by Jocelyn.)*

View File

@@ -1,16 +1,17 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-14-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-14-0 http://www.eiffel.com/developers/xml/configuration-1-14-0.xsd" name="demo" uuid="3643E657-BCBE-46AA-931B-71EAEA877A18" library_target="demo">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-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">
<root class="DEMO_CMS_SERVER" feature="make_and_launch"/>
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
<exclude>/CVS$</exclude>
<exclude>/EIFGENs$</exclude>
</file_rule>
<option debug="true" warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="transitional">
<option debug="true" warning="true" full_class_checking="false" is_attached_by_default="true" is_obsolete_routine_type="true" void_safety="all" syntax="transitional">
<debug name="dbglog" enabled="true"/>
</option>
<setting name="executable_name" value="demo"/>
<setting name="concurrency" value="thread"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="cms" location="..\..\cms-safe.ecf" readonly="false">
@@ -32,14 +33,15 @@
<library name="cms_oauth_20_module" location="..\..\modules\oauth20\oauth20-safe.ecf" readonly="false"/>
<library name="cms_openid_module" location="..\..\modules\openid\openid-safe.ecf" readonly="false"/>
<library name="cms_recent_changes_module" location="..\..\modules\recent_changes\recent_changes-safe.ecf" readonly="false"/>
<library name="cms_session_auth_module" location="..\..\modules\session_auth\cms_session_auth-safe.ecf" readonly="false"/>
<library name="cms_taxnomy_module" location="..\..\modules\taxonomy\taxonomy-safe.ecf" readonly="false"/>
<library name="persistence_sqlite3" location="..\..\library\persistence\sqlite3\sqlite3-safe.ecf" readonly="false">
<option>
<assertions/>
</option>
</library>
<library name="persistence_store_odbc" location="..\..\library\persistence\store_odbc\store_odbc-safe.ecf" />
<!--
<library name="persistence_store_odbc" location="..\..\library\persistence\store_odbc\store_odbc-safe.ecf"/>
<library name="persistence_store_mysql" location="..\..\library\persistence\store_mysql\store_mysql-safe.ecf" />
-->
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>

View File

@@ -12,3 +12,4 @@ set ROC_CMS_DIR=%~dp0
%ROC_CMD% install --module ..\..\modules\recent_changes --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\feed_aggregator --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\google_search --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\taxonomy --dir %ROC_CMS_DIR%

View File

@@ -4,14 +4,28 @@ root-dir=site/www
#modules-dir=site/modules
[site]
# Name of the site, for the title, and eventual message.
name=Eiffel CMS
email=your@email.com
# Email used for notification
email=noreply@example.com
# Name of website theme.
theme=bootstrap
[notification]
# By default, notification.email = site.email
# you can change here the email that will receive internal messages.
email=webmaster@example.com
[mailer]
#smtp=localhost:25
#sendmail=/usr/bin/sendmail
output=@stderr
#The mailer is used mostly used by the CMS to send email messages.
# you can change the "From:" by setting mailer.from value"
subject_prefix=[Eiffel CMS]
#from=...
smtp=localhost:25
#sendmail=site\bin\roc_sendmail.bat
output=site\db\mailer.log
[modules]
# Module status

View File

@@ -0,0 +1,7 @@
{
"subject": "Thank you for contacting us",
"recaptcha": {
"site_key":"6Lex9RMTAAAAAKleC4x6TaRlFcpLbEWgH_U7MSiD",
"secret_key":"6Lex9RMTAAAAAAkBczvX5DUiyg_xoM_EthVVgRRx"
}
}

View File

@@ -0,0 +1,28 @@
ul.cms-temp-users {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
}
ul.cms-temp-users li {
border-top: dotted 1px #ccc;
}
ul.cms-temp-users li:first-child {
border-top: none;
}
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
}
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li {
border-top: dotted 1px #ccc;
}
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li:first-child {
border-top: none;
}
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li.cms_temp_user_detail_information::before {
content: "[personal information] ";
}
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li.cms_temp_user_detail_email::before {
content: "[email] ";
}

View File

@@ -0,0 +1,37 @@
ul.cms-temp-users {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
li{
border-top: dotted 1px #ccc;
&:first-child {
border-top: none;
}
}
li.cms_temp_user {
ul.cms_temp_user_details {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
li{
border-top: dotted 1px #ccc;
&:first-child {
border-top: none;
}
}
li.cms_temp_user_detail_information::before{
content: "[personal information] "
}
li.cms_temp_user_detail_email::before{
content: "[email] "
}
}
}
}

View File

@@ -4,15 +4,10 @@
<meta charset="utf-8">
<title>Activation</title>
<meta name="description" content="Activation">
<meta name="author" content="ROC CMS">
<meta name="author" content="$sitename">
</head>
<body>
<p>Thank you for registering at <a href="$host">ROC CMS</a></p>
<p>To complete your registration, please click on this link to activate your account:<p>
<p><a href="$link">$link</a></p>
<p>Thank you for joining us.</p>
<p>"$user ($email)", thank you for applying to <a href="$host">$sitename</a>.</p>
<p>We will review your application and send you a resolution.<p>
</body>
</html>

View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Activation Confirmation</title>
<meta name="description" content="Activation Confirmation">
<meta name="author" content="$sitename">
</head>
<body>
<p>Your account "$user ($email)" is confirmed at <a href="$host">$sitename</a>.</p>
<p>Thank you for joining us.</p>
</body>
</html>

View File

@@ -4,14 +4,12 @@
<meta charset="utf-8">
<title>New Password</title>
<meta name="description" content="New Password">
<meta name="author" content="ROC CMS">
<meta name="author" content="$sitename">
</head>
<body>
<p>You have required a new password at <a href="$host">ROC CMS</a></p>
<p>To complete your request, please click on this link to genereate a new password:<p>
<p><a href="$link">$link</a></p>
<p>You have requested a new password at <a href="$host">$sitename</a>.</p>
<p>To complete your request, please click on the following link to generate a new password:
<ul><a href="$link">$link</a></ul>
</p>
</body>
</html>

View File

@@ -4,15 +4,14 @@
<meta charset="utf-8">
<title>New Activation</title>
<meta name="description" content="New Activation token">
<meta name="author" content="ROC CMS">
<meta name="author" content="$sitename">
</head>
<body>
<p>You have request a new activation token at <a href="$host">ROC CMS</a></p>
<p>You have requested a new activation token at <a href="$host">$sitename</a>.</p>
<p>To complete your registration, please click on this link to activate your account:<p>
<p><a href="$link">$link</a></p>
<p>To complete your registration, please click on the following link to re-activate your account:
<ul><a href="$link">$link</a></ul>
</p>
<p>Thank you for joining us.</p>
</body>
</html>

View File

@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Application Rejected</title>
<meta name="description" content="Application Rejected">
<meta name="author" content="$sitename">
</head>
<body>
<p>Your account application is rejected, it was not respecting the requirements from <a href="$host">$sitename</a>.</p>
</body>
</html>

View File

@@ -4,10 +4,16 @@
<meta charset="utf-8">
<title>Welcome</title>
<meta name="description" content="Welcome">
<meta name="author" content="ROC CMS">
<meta name="author" content="$sitename">
</head>
<body>
<p>Welcome to<a href="$host">ROC CMS</a></p>
<p>Welcome to <a href="$host">$sitename</a>.</p>
<p>Your account information:
<ul>
<li>Email address: "$email" .</li>
<li>User name: "$user" .</li>
</ul>
</p>
<p>Thank you for joining us.</p>
</body>
</html>

View File

@@ -0,0 +1,26 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Account Evaluation</title>
<meta name="description" content="Account Evaluation">
<meta name="author" content="$sitename">
</head>
<body>
<h2> Account Evaluation </h2>
<p>The user $user ($email) wants to register to the site <a href="$host">$sitename</a></p>
<blockquote><p>User application:</p>
<p>$application</p>
</blockquote>
<p>To complete the registration, please click on the following link to activate the user account:<p>
<p><a href="$activation_url">$activation_url</a></p>
<p>To reject the registration, please click on the following link <p>
<p><a href="$rejection_url<">$rejection_url</a></p>
</body>
</html>

View File

@@ -1,3 +1,3 @@
<div>
<p>We have send you a new activation code, check your email to activate your account.</p>
<p>Thanks for your application, we will review it to activate your account.</p>
</div>

View File

@@ -1,3 +1,3 @@
<div>
<p>Thanks for register, check your email to activate your account.</p>
<p>Thanks for your application, we will review it to activate your account.</p>
</div>

View File

@@ -1,7 +1,7 @@
<div>
<form action="{$site_url/}account/roc-register" method="post">
<fieldset>
<legend>Register Form</legend>
<legend>Registration</legend>
<div>
<input type="text" id="name" name="name" value="{$name/}" required autofocus />
<label for="name">Name</label>
@@ -20,8 +20,19 @@
<span><i>{$error_email/}</i></span> <br>
{/if}
</div>
<div>
<textarea rows="4" cols="50" name="personal_information" id="personal_information" required>
{$personal_information/}
</textarea>
<label for="personal_information">Tell us why you want to register an account</label>
{if isset="$error_application"}
<span><i>{$error_application/}</i></span> <br>
{/if}
</div>
{unless isempty="$recaptcha_site_key"}
<div class="g-recaptcha" data-sitekey="{$recaptcha_site_key/}"></div>
<br/>
{/unless}
<button type="submit">Register</button>
</fieldset>
</form>

View File

@@ -11,7 +11,7 @@ ROC_AUTH.login = function() {
var username = form.username.value;
var password = form.password.value;
//var host = form.host.value;
var origin = window.location.origin.concat(window.location.pathname);
var origin = window.location.origin + window.location.pathname;
var _login = function(){
@@ -322,4 +322,4 @@ ROC_AUTH.validatePassword =function(){
if ((password != null) && (confirm_password != null)) {
password.onchange = ROC_AUTH.validatePassword();
confirm_password.onkeyup = ROC_AUTH.validatePassword;
}
}

View File

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

View File

@@ -0,0 +1,37 @@
<div class="primary-tabs">
{unless isset="$user"}
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3>
<div>
<div>
<form name="cms_session_auth" action="{$site_url/}account/login-with-session" method="POST">
<div>
<input type="text" name="username" id="username" required value="{$username/}">
<label>Username</label>
</div>
<div>
<input type="password" name="password" id="password" required >
<label>Password</label>
</div>
<button type="submit">Login</button>
</form>
</div>
</div>
<div>
<div>
<p>
<a href="{$site_url/}account/new-password">Forgot password?</a>
</p>
</div>
</div>
{/unless}
{if isset=$error}
<div>
<div>
<p>
<strong>{$error/}
</p>
</div>
</div>
{/if}
</div>

View File

@@ -0,0 +1,26 @@
ul.taxonomy {
font-size: 80%;
list-style-type: none;
font-style: italic;
margin: 0;
}
ul.taxonomy li {
padding: 2px;
margin-right: 3px;
display: inline-block;
border: none;
}
ul.taxonomy li a:hover {
text-decoration: none;
}
ul.taxonomy li:hover {
padding: 1px;
border-top: solid 1px #66f;
border-bottom: solid 1px #66f;
background-color: #ddf;
}
table.taxonomy td {
border: solid 1px #ccc;
padding: 2px;
}

View File

@@ -0,0 +1,27 @@
ul.taxonomy {
font-size: 80%;
list-style-type: none;
font-style: italic;
margin: 0;
li {
a:hover {
text-decoration: none;
}
padding: 2px;
margin-right: 3px;
display: inline-block;
border: none;
&:hover {
padding: 1px;
border-top: solid 1px #66f;
border-bottom: solid 1px #66f;
background-color: #ddf;
}
}
}
table.taxonomy {
td {
border: solid 1px #ccc;
padding: 2px;
}
}

View File

@@ -0,0 +1,24 @@
CREATE TABLE taxonomy_term (
`tid` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT UNIQUE,
`text` VARCHAR(255) NOT NULL,
`weight` INTEGER,
`description` TEXT,
`langcode` VARCHAR(12)
);
CREATE TABLE taxonomy_hierarchy (
`tid` INTEGER NOT NULL,
`parent` INTEGER,
CONSTRAINT PK_tid_parent PRIMARY KEY (tid,parent)
);
/* Associate tid with unique (type,entity)
* for instance: "page" + "$nid" -> "tid"
*/
CREATE TABLE taxonomy_index (
`tid` INTEGER NOT NULL,
`entity` VARCHAR(255),
`type` VARCHAR(255) NOT NULL,
CONSTRAINT PK_tid_entity_type PRIMARY KEY (tid,entity,type)
);

View File

@@ -0,0 +1,3 @@
DROP TABLE IF EXISTS taxonomy_term;
DROP TABLE IF EXISTS taxonomy_hierarchy;
DROP TABLE IF EXISTS taxonomy_index;

View File

@@ -46,3 +46,18 @@ CREATE TABLE `users_password_recovery` (
CONSTRAINT `token` UNIQUE (`token`)
);
CREATE TABLE `auth_temp_users` (
`uid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL,
`name` VARCHAR(100) NOT NULL,
`password` VARCHAR(100) NOT NULL,
`salt` VARCHAR(100) NOT NULL,
`email` VARCHAR(250) NOT NULL,
`application` TEXT NOT NULL,
CONSTRAINT `name`
UNIQUE(`name`)
);

View File

@@ -90,3 +90,11 @@ ul.horizontal li {
border: solid 1px red;
padding: 5px 2px 5px 2px;
}
table.with_border thead td {
font-weight: bold;
}
table.with_border td {
border: solid 1px #ccc;
padding: 2px 5px 2px 5px;
}

View File

@@ -95,3 +95,13 @@ ul.horizontal {
border: solid 1px red;
padding: 5px 2px 5px 2px;
}
table.with_border {
thead td {
font-weight: bold;
}
td {
border: solid 1px #ccc;
padding: 2px 5px 2px 5px;
}
}

View File

@@ -35,56 +35,41 @@ feature -- CMS storage
do
a_setup.storage_drivers.force (create {CMS_STORAGE_SQLITE3_BUILDER}.make, "sqlite3")
-- a_setup.storage_drivers.force (create {CMS_STORAGE_STORE_MYSQL_BUILDER}.make, "mysql")
a_setup.storage_drivers.force (create {CMS_STORAGE_STORE_ODBC_BUILDER}.make, "odbc")
-- a_setup.storage_drivers.force (create {CMS_STORAGE_STORE_ODBC_BUILDER}.make, "odbc")
end
feature -- CMS modules
setup_modules (a_setup: CMS_SETUP)
-- Setup additional modules.
local
m: CMS_MODULE
do
create {CMS_ADMIN_MODULE} m.make
a_setup.register_module (m)
-- Admin
a_setup.register_module (create {CMS_ADMIN_MODULE}.make)
-- Auth
create {CMS_AUTHENTICATION_MODULE} m.make
a_setup.register_module (m)
create {CMS_BASIC_AUTH_MODULE} m.make
a_setup.register_module (m)
create {CMS_OAUTH_20_MODULE} m.make
a_setup.register_module (m)
create {CMS_OPENID_MODULE} m.make
a_setup.register_module (m)
a_setup.register_module (create {CMS_AUTHENTICATION_MODULE}.make)
a_setup.register_module (create {CMS_BASIC_AUTH_MODULE}.make)
a_setup.register_module (create {CMS_OAUTH_20_MODULE}.make)
a_setup.register_module (create {CMS_OPENID_MODULE}.make)
-- Nodes
create {CMS_NODE_MODULE} m.make (a_setup)
a_setup.register_module (m)
a_setup.register_module (create {CMS_NODE_MODULE}.make (a_setup))
a_setup.register_module (create {CMS_BLOG_MODULE}.make)
create {CMS_BLOG_MODULE} m.make
a_setup.register_module (m)
-- Taxonomy
a_setup.register_module (create {CMS_TAXONOMY_MODULE}.make)
-- Recent changes
create {CMS_RECENT_CHANGES_MODULE} m.make
a_setup.register_module (m)
a_setup.register_module (create {CMS_RECENT_CHANGES_MODULE}.make)
-- Recent changes
create {FEED_AGGREGATOR_MODULE} m.make
a_setup.register_module (m)
-- Feed aggregator
a_setup.register_module (create {FEED_AGGREGATOR_MODULE}.make)
-- Miscellanious
create {CMS_DEBUG_MODULE} m.make
a_setup.register_module (m)
create {CMS_DEMO_MODULE} m.make
a_setup.register_module (m)
create {GOOGLE_CUSTOM_SEARCH_MODULE} m.make
a_setup.register_module (m)
a_setup.register_module (create {CMS_DEBUG_MODULE}.make)
a_setup.register_module (create {CMS_DEMO_MODULE}.make)
a_setup.register_module (create {GOOGLE_CUSTOM_SEARCH_MODULE}.make)
a_setup.register_module (create {CMS_SESSION_AUTH_MODULE}.make)
end
end

View File

@@ -35,12 +35,14 @@ feature {NONE} -- Initialization
parameters: EMAIL_SERVICE_PARAMETERS
-- Associated parameters.
admin_email: IMMUTABLE_STRING_8
-- Site admin's email.
mailer: NOTIFICATION_MAILER
-- SMTP protocol.
feature -- Access
admin_email: IMMUTABLE_STRING_8
-- Site admin's email.
feature -- Basic Operations
send_internal_email (a_content: READABLE_STRING_GENERAL)

View File

@@ -7,7 +7,6 @@ class
GCSE_PAGE_ITEM
inherit
DEBUG_OUTPUT
feature -- Access
@@ -139,62 +138,62 @@ feature -- Element change
feature -- Output
debug_output: STRING_8
-- <Precursor>
do
create Result.make_from_string ("%NPage Item details%N")
if attached title as l_title then
Result.append ("Title:")
Result.append (l_title)
Result.append_character ('%N')
end
if attached kind as l_kind then
Result.append ("Kind:")
Result.append (l_kind)
Result.append_character ('%N')
end
if attached html_title as l_html_title then
Result.append ("Html title:")
Result.append (l_html_title)
Result.append_character ('%N')
end
if attached link as l_link then
Result.append ("Link:")
Result.append (l_link)
Result.append_character ('%N')
end
if attached display_link as l_display_link then
Result.append ("Display link:")
Result.append (l_display_link)
Result.append_character ('%N')
end
if attached snippet as l_snippet then
Result.append ("Snippet:")
Result.append (l_snippet)
Result.append_character ('%N')
end
if attached html_snippet as l_html_snippet then
Result.append ("Html snippet:")
Result.append (l_html_snippet)
Result.append_character ('%N')
end
if attached cache_id as l_cache_id then
Result.append ("Cache_id:")
Result.append (l_cache_id)
Result.append_character ('%N')
end
if attached formatted_url as l_formatted_url then
Result.append ("Formatted url:")
Result.append (l_formatted_url)
Result.append_character ('%N')
end
if attached html_formatted_url as l_html_formatted_url then
Result.append ("Html formatted url:")
Result.append (l_html_formatted_url)
Result.append_character ('%N')
end
debug_output: STRING_8
-- <Precursor>
do
create Result.make_from_string ("%NPage Item details%N")
if attached title as l_title then
Result.append ("Title:")
Result.append (l_title)
Result.append_character ('%N')
end
if attached kind as l_kind then
Result.append ("Kind:")
Result.append (l_kind)
Result.append_character ('%N')
end
if attached html_title as l_html_title then
Result.append ("Html title:")
Result.append (l_html_title)
Result.append_character ('%N')
end
if attached link as l_link then
Result.append ("Link:")
Result.append (l_link)
Result.append_character ('%N')
end
if attached display_link as l_display_link then
Result.append ("Display link:")
Result.append (l_display_link)
Result.append_character ('%N')
end
if attached snippet as l_snippet then
Result.append ("Snippet:")
Result.append (l_snippet)
Result.append_character ('%N')
end
if attached html_snippet as l_html_snippet then
Result.append ("Html snippet:")
Result.append (l_html_snippet)
Result.append_character ('%N')
end
if attached cache_id as l_cache_id then
Result.append ("Cache_id:")
Result.append (l_cache_id)
Result.append_character ('%N')
end
if attached formatted_url as l_formatted_url then
Result.append ("Formatted url:")
Result.append (l_formatted_url)
Result.append_character ('%N')
end
if attached html_formatted_url as l_html_formatted_url then
Result.append ("Html formatted url:")
Result.append (l_html_formatted_url)
Result.append_character ('%N')
end
end
note
copyright: "2011-2015 Javier Velilla, Jocelyn Fiat, Eiffel Software and others"

View File

@@ -1,7 +1,7 @@
note
description : "test application root class"
date : "$Date: 2015-10-08 07:51:29 -0300 (ju., 08 oct. 2015) $"
revision : "$Revision: 97966 $"
date : "$Date: 2015-12-02 10:27:38 -0300 (mi. 02 de dic. de 2015) $"
revision : "$Revision: 98180 $"
class
APPLICATION
@@ -27,20 +27,20 @@ feature {NONE} -- Initialization
if attached {GCSE_RESPONSE} gcse.last_result as l_result then
if attached l_result.current_page as l_page then
print ("Current Page%N")
print (l_page.to_string)
print (l_page.debug_output)
end
if attached l_result.next_page as l_page then
print ("Next Page%N")
print (l_page.to_string)
print (l_page.debug_output)
end
if attached l_result.previous_page as l_page then
print ("Previous Page%N")
print (l_page.to_string)
print (l_page.debug_output)
end
if attached l_result.items as l_items then
print ("Number of items:" + l_items.count.out)
across l_items as ic loop print (ic.item.to_string) end
across l_items as ic loop print (ic.item.debug_output) end
end
if attached l_result.next_page as l_page then
@@ -52,20 +52,20 @@ feature {NONE} -- Initialization
if attached {GCSE_RESPONSE} gcse.last_result as l_result then
if attached l_result.current_page as l_page then
print ("Current Page%N")
print (l_page.to_string)
print (l_page.debug_output)
end
if attached l_result.next_page as l_page then
print ("Next Page%N")
print (l_page.to_string)
print (l_page.debug_output)
end
if attached l_result.previous_page as l_page then
print ("Previous Page%N")
print (l_page.to_string)
print (l_page.debug_output)
end
if attached l_result.items as l_items then
print ("Number of items:" + l_items.count.out)
across l_items as ic loop print (ic.item.to_string) end
across l_items as ic loop print (ic.item.debug_output) end
end
end

View File

@@ -6,7 +6,6 @@
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<setting name="console_application" value="true"/>
<precompile name="base_pre" location="$ISE_PRECOMP\base-safe.ecf"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="gcse" location="..\gcse-safe.ecf" readonly="false"/>
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>

View File

@@ -0,0 +1,45 @@
note
description: "User for temporary account."
date: "$Date$"
revision: "$Revision$"
class
CMS_TEMP_USER
inherit
CMS_USER
create
make,
make_with_id
feature -- Access
personal_information: detachable STRING_32
-- User personal information.
salt: detachable STRING_32
-- User's password salt.
feature -- Element change
set_personal_information (a_personal_information: like personal_information)
-- Assign `personal_information' with `a_personal_information'.
do
personal_information := a_personal_information
ensure
personal_information_assigned: personal_information = a_personal_information
end
set_salt (a_salt: like salt)
-- Assign `salt' with `a_salt'.
do
salt := a_salt
ensure
salt_assigned: salt = a_salt
end
note
copyright: "2011-2016, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -62,7 +62,7 @@ feature -- Access
hashed_password: detachable READABLE_STRING_8
-- Hashed user password.
email: detachable READABLE_STRING_32
email: detachable READABLE_STRING_8
-- User email.
profile: detachable CMS_USER_PROFILE
@@ -80,7 +80,6 @@ feature -- Access
-- active
-- trashed
feature -- Access: helper
utf_8_name: STRING_8
@@ -302,6 +301,6 @@ invariant
id_or_name_set: id > 0 or else not name.is_whitespace
note
copyright: "2011-2015, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
copyright: "2011-2016, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -152,6 +152,7 @@ feature -- Query
-- Retrieved value at `a_index' position in `item'.
local
l_item: like sql_item
i64: INTEGER_64
do
l_item := sql_item (a_index)
if attached {INTEGER_32} l_item as i then
@@ -159,7 +160,18 @@ feature -- Query
elseif attached {INTEGER_32_REF} l_item as l_value then
Result := l_value.item
else
check is_integer_32: False end
if attached {INTEGER_64} l_item as i then
i64 := i
elseif attached {INTEGER_64_REF} l_item as l_value then
i64 := l_value.item
else
check is_integer_32: False end
end
if i64 <= {INTEGER_32}.max_value then
Result := i64.to_integer_32
else
check is_integer_32: False end
end
end
end

View File

@@ -1,30 +0,0 @@
BEGIN;
CREATE TABLE `logs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`category` VARCHAR(255) NOT NULL,
`level` int(11) NOT NULL,
`uid` int(11) DEFAULT NULL,
`message` text NOT NULL,
`info` text,
`link` text,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `custom_values` (
`type` VARCHAR(255) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`value` VARCHAR(255) NOT NULL
);
CREATE TABLE `path_aliases` (
`pid` int(11) NOT NULL AUTO_INCREMENT,
`source` varchar(255) NOT NULL,
`alias` varchar(255) NOT NULL,
`lang` varchar(12) DEFAULT NULL,
PRIMARY KEY (`pid`)
);
COMMIT;

View File

@@ -1,24 +0,0 @@
BEGIN;
CREATE TABLE nodes (
nid INTEGER PRIMARY KEY AUTO_INCREMENT 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 AUTO_INCREMENT NOT NULL CHECK( nid >=0),
revision INTEGER,
parent INTEGER
);
COMMIT;

View File

@@ -1,66 +0,0 @@
BEGIN;
CREATE TABLE `users` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`password` varchar(100) NOT NULL,
`salt` varchar(100) NOT NULL,
`email` varchar(250) NOT NULL,
`status` int(11) DEFAULT NULL,
`created` datetime NOT NULL,
`signed` datetime DEFAULT NULL,
CHECK (`uid` >= 0),
PRIMARY KEY (`uid`),
UNIQUE KEY `name` (`name`)
);
CREATE TABLE `roles` (
`rid` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
CHECK (`rid` >= 0),
PRIMARY KEY (`rid`),
UNIQUE KEY `name` (`name`)
);
CREATE TABLE `users_roles` (
`uid` int(11) NOT NULL,
`rid` int(11) NOT NULL,
CHECK (`uid` >= 0),
CHECK (`rid` >= 0)
);
CREATE TABLE `role_permissions` (
`rid` int(11) NOT NULL,
`permission` varchar(255) NOT NULL,
`module` varchar(255) DEFAULT NULL,
CHECK (`rid` >= 0)
);
CREATE TABLE `users_activations` (
`aid` int(11) NOT NULL AUTO_INCREMENT,
`token` varchar(255) NOT NULL,
`uid` int(11) NOT NULL,
`created` datetime NOT NULL,
CHECK (`aid` >= 0),
CHECK (`uid` >= 0),
PRIMARY KEY (`aid`),
UNIQUE KEY `token` (`token`)
);
CREATE TABLE `users_password_recovery` (
`aid` int(11) NOT NULL AUTO_INCREMENT,
`token` varchar(255) NOT NULL,
`uid` int(11) NOT NULL,
`created` datetime NOT NULL,
CHECK (`aid` >= 0),
CHECK (`uid` >= 0),
PRIMARY KEY (`aid`),
UNIQUE KEY `token` (`token`)
);
COMMIT;

View File

@@ -0,0 +1,4 @@
Recaptcha Eiffel Lbrary
Based on https://developers.google.com/recaptcha/

View File

@@ -0,0 +1,10 @@
${NOTE_KEYWORD}
copyright: "2011-${YEAR} Javier Velilla, 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
]"

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="recaptcha" uuid="2A966489-284A-48A0-91BC-31E84EA9C3B1" library_target="recaptcha">
<target name="recaptcha">
<root all_classes="true"/>
<file_rule>
<exclude>/.git$</exclude>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" is_obsolete_routine_type="true" void_safety="all">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<setting name="console_application" value="true"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http_client_extension" location="..\http_client_extension\http_client_extension-safe.ecf"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
<cluster name="recaptcha" location=".\src\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,22 @@
<?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="recaptcha" uuid="2A966489-284A-48A0-91BC-31E84EA9C3B1" library_target="recaptcha">
<target name="recaptcha">
<root all_classes="true"/>
<file_rule>
<exclude>/.git$</exclude>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" void_safety="none">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<setting name="console_application" value="true"/>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension.ecf"/>
<library name="http_client_extension" location="..\http_client_extension\http_client_extension.ecf"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json.ecf" readonly="false"/>
<cluster name="recaptcha" location=".\src\" recursive="true">
</cluster>
</target>
</system>

View File

@@ -0,0 +1,147 @@
note
description: "[
Simple API to call {RECAPTCHA} Google API.
Example call:
https://www.google.com/recaptcha/api/siteverify?secret=your_secret&response=response_string&remoteip=user_ip_address
]"
date: "$Date: 2015-01-28 11:44:15 -0300 (mi. 28 de ene. de 2015) $"
revision: "$Revision: 96551 $"
EIS: "name=RECAPTCHA", "src=https://developers.google.com/recaptcha/", "protocol=uri"
EIS: "name=RECAPTCHA API verify", "src=https://developers.google.com/recaptcha/docs/verify", "protocol=uri"
class
RECAPTCHA_API
create
make
feature {NONE} -- Initialization
make (a_secret_key, a_response: READABLE_STRING_8)
-- Create an object Recaptcha with secret key `a_secret_key' and response token `a_response'.
do
secret := a_secret_key
response := a_response
ensure
secret_set: secret.same_string (a_secret_key)
response_set: response.same_string (a_response)
end
feature -- Access
base_uri: STRING_8 = "https://www.google.com/recaptcha/api/siteverify"
-- Recaptcha base URI
secret: READABLE_STRING_8
-- Required. The shared key between your site and ReCAPTCHA.
response: READABLE_STRING_8
-- Required. The user response token provided by the reCAPTCHA to the user and provided to your site on.
remoteip: detachable READABLE_STRING_8
-- Optional. The user's IP address.
feature -- Status Reports
errors: detachable LIST [READABLE_STRING_8]
-- optional table of error codes
-- missing-input-secret The secret parameter is missing.
-- invalid-input-secret The secret parameter is invalid or malformed.
-- missing-input-response The response parameter is missing.
-- invalid-input-response The response parameter is invalid or malformed.
feature -- Change Element
set_remoteip (a_remoteip: READABLE_STRING_8)
-- Set `remoteip' with `a_remoteip'.
do
remoteip := a_remoteip
ensure
remoteip_set: remoteip = a_remoteip
end
feature -- API
verify: BOOLEAN
-- Verify the user's response
local
l_parser: JSON_PARSER
do
if attached get as l_response then
if attached l_response.body as l_body then
create l_parser.make_with_string (l_body)
l_parser.parse_content
if
l_parser.is_parsed and then attached {JSON_OBJECT} l_parser.parsed_json_object as jv and then
attached {JSON_BOOLEAN} jv.item ("success") as l_success
then
Result := l_success.item
if not Result and then attached {JSON_ARRAY} jv.item ("error-codes") as l_error_codes then
across
l_error_codes as c
loop
if attached {JSON_STRING} c.item as ji then
put_error (ji.unescaped_string_32)
end
end
end
end
else
put_error (l_response.status.out)
end
else
put_error ("unknown")
end
end
feature {NONE} -- REST API
get: detachable RESPONSE
-- Reading Data
local
l_request: REQUEST
do
create l_request.make ("GET", new_uri)
Result := l_request.execute
end
feature {NONE} -- Implementation
new_uri: STRING_8
-- new uri (BaseUri?secret=secret_value&response=response_value[&remoteip=remoteip_value]
do
create Result.make_from_string (base_uri)
Result.append ("?secret=")
Result.append (secret)
Result.append ("&response=")
Result.append (response)
if attached remoteip as l_remoteip then
Result.append ("&remoteip=" + l_remoteip)
end
end
put_error (a_code: READABLE_STRING_GENERAL)
local
l_errors: like errors
utf: UTF_CONVERTER
do
l_errors := errors
if l_errors = Void then
create {ARRAYED_LIST [STRING]} l_errors.make (1)
errors := l_errors
end
l_errors.force (utf.utf_32_string_to_utf_8_string_8 (a_code))
end
note
copyright: "2011-2015 Javier Velilla, 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

@@ -0,0 +1,61 @@
note
description : "test application root class"
date : "$Date: 2015-01-14 15:37:57 -0300 (mi. 14 de ene. de 2015) $"
revision : "$Revision: 96458 $"
class
APPLICATION
inherit
ARGUMENTS
create
make
feature {NONE} -- Initialization
make
-- Run application.
do
test_invalid_input
test_missing_input
test_missing_key_input
end
test_invalid_input
-- invalid-input-response
local
l_captcha: RECAPTCHA_API
do
create l_captcha.make ("","234")
check
not_true:not l_captcha.verify
end
end
test_missing_input
-- missing-input-response
local
l_captcha: RECAPTCHA_API
do
create l_captcha.make ("key","")
check
not_true:not l_captcha.verify
end
end
test_missing_key_input
-- missing-input-response
-- invalid-input-response
local
l_captcha: RECAPTCHA_API
do
create l_captcha.make ("","")
l_captcha.set_remoteip("localhost")
check
not_true:not l_captcha.verify
end
end
end

View File

@@ -0,0 +1,69 @@
note
description: "[
Eiffel tests that can be executed by testing tool.
]"
author: "EiffelStudio test wizard"
date: "$Date: 2015-01-14 15:37:57 -0300 (mi. 14 de ene. de 2015) $"
revision: "$Revision: 96458 $"
testing: "type/manual"
class
RECAPTCHA_API_TEST_SET
inherit
EQA_TEST_SET
feature -- Test routines
test_invalid_input
-- invalid-input-response
local
l_captcha: RECAPTCHA_API
do
create l_captcha.make ("","234")
check
not_true:not l_captcha.verify
end
assert ("Not true", not l_captcha.verify)
assert ("Has error invalid-input-response",has_error (l_captcha,"invalid-input-response"))
end
test_missing_input
-- missing-input-response
local
l_captcha: RECAPTCHA_API
do
create l_captcha.make ("key","")
check
not_true:not l_captcha.verify
end
assert ("Not true", not l_captcha.verify)
assert ("Has error missing-input-response",has_error (l_captcha,"missing-input-response"))
end
test_missing_key_input
-- missing-input-response
-- invalid-input-response
local
l_captcha: RECAPTCHA_API
do
create l_captcha.make ("","")
l_captcha.set_remoteip("localhost")
assert ("Not true", not l_captcha.verify)
assert ("Has error missing-input-response",has_error (l_captcha,"missing-input-response"))
assert ("Has error invalid-input-response",has_error (l_captcha,"invalid-input-response"))
end
feature {NONE} -- Implementation
has_error (l_captcha: RECAPTCHA_API; a_error: READABLE_STRING_32): BOOLEAN
do
if attached l_captcha.errors as l_errors then
l_errors.compare_objects
Result := l_errors.has (a_error)
end
end
end

View File

@@ -0,0 +1,21 @@
<?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="test" uuid="CE9FCE69-EE0A-4028-AA02-BD9F8ABA7586">
<target name="test">
<root class="APPLICATION" feature="make"/>
<option warning="true" void_safety="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<setting name="console_application" value="true"/>
<precompile name="base_pre" location="$ISE_PRECOMP\base-safe.ecf"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="recaptcha" location="..\recaptcha-safe.ecf" readonly="false"/>
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
<cluster name="test" location=".\" recursive="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
</cluster>
</target>
</system>

View File

@@ -47,6 +47,8 @@ feature -- Access: router
configure_web (a_api: CMS_API; a_router: WSF_ROUTER)
local
l_admin_handler: CMS_ADMIN_HANDLER
l_modules_handler: CMS_ADMIN_MODULES_HANDLER
l_users_handler: CMS_ADMIN_USERS_HANDLER
l_roles_handler: CMS_ADMIN_ROLES_HANDLER
@@ -62,6 +64,10 @@ feature -- Access: router
create l_uri_mapping.make_trailing_slash_ignored ("/admin", l_admin_handler)
a_router.map (l_uri_mapping, a_router.methods_get_post)
create l_modules_handler.make (a_api)
create l_uri_mapping.make_trailing_slash_ignored ("/admin/modules", l_modules_handler)
a_router.map (l_uri_mapping, a_router.methods_get_post)
create l_users_handler.make (a_api)
create l_uri_mapping.make_trailing_slash_ignored ("/admin/users", l_users_handler)
a_router.map (l_uri_mapping, a_router.methods_get_post)
@@ -105,6 +111,7 @@ feature -- Security
Result.force ("admin core caches")
Result.force ("clear blocks cache")
Result.force ("admin export")
Result.force ("export core")
end
feature -- Hooks
@@ -133,7 +140,13 @@ feature -- Hooks
create lnk.make ("Admin", "admin")
lnk.set_permission_arguments (<<"manage " + {CMS_ADMIN_MODULE}.name>>)
a_menu_system.management_menu.extend (lnk)
end
create lnk.make ("Module", "admin/modules")
lnk.set_permission_arguments (<<"manage module">>)
a_menu_system.management_menu.extend (lnk)
-- Per module cache permission!
create lnk.make ("Cache", "admin/cache")
a_menu_system.management_menu.extend (lnk)

View File

@@ -44,7 +44,7 @@ feature -- Execution
create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api)
f := clear_cache_web_form (l_response)
create s.make_empty
f.append_to_html (create {CMS_TO_WSF_THEME}.make (l_response, l_response.theme), s)
f.append_to_html (l_response.wsf_theme, s)
l_response.set_main_content (s)
l_response.execute
end
@@ -63,14 +63,14 @@ feature -- Execution
fd.is_valid
then
if attached fd.string_item ("op") as l_op and then l_op.same_string (text_clear_all_caches) then
l_response.hooks.invoke_clear_cache (Void, l_response)
api.hooks.invoke_clear_cache (Void, l_response)
l_response.add_notice_message ("Caches cleared (if allowed)!")
else
fd.report_error ("Invalid form data!")
end
end
create s.make_empty
f.append_to_html (create {CMS_TO_WSF_THEME}.make (l_response, l_response.theme), s)
f.append_to_html (l_response.wsf_theme, s)
l_response.set_main_content (s)
l_response.execute
end

View File

@@ -44,7 +44,7 @@ feature -- Execution
create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api)
f := exportation_web_form (l_response)
create s.make_empty
f.append_to_html (create {CMS_TO_WSF_THEME}.make (l_response, l_response.theme), s)
f.append_to_html (l_response.wsf_theme, s)
l_response.set_main_content (s)
l_response.execute
end
@@ -64,8 +64,12 @@ feature -- Execution
fd.is_valid
then
if attached fd.string_item ("op") as l_op and then l_op.same_string (text_export_all_data) then
create l_exportation_parameters.make (api.site_location.extended ("export").extended ((create {DATE_TIME}.make_now_utc).formatted_out ("yyyy-[0]mm-[0]dd_hh12-[0]mi-[0]ss")))
l_response.hooks.invoke_export_to (Void, l_exportation_parameters, l_response)
if attached fd.string_item ("folder") as l_folder then
create l_exportation_parameters.make (api.site_location.extended ("export").extended (l_folder))
else
create l_exportation_parameters.make (api.site_location.extended ("export").extended ((create {DATE_TIME}.make_now_utc).formatted_out ("yyyy-[0]mm-[0]dd---hh24-[0]mi-[0]ss")))
end
api.hooks.invoke_export_to (Void, l_exportation_parameters, l_response)
l_response.add_notice_message ("All data exported (if allowed)!")
create s.make_empty
across
@@ -81,7 +85,7 @@ feature -- Execution
end
end
create s.make_empty
f.append_to_html (create {CMS_TO_WSF_THEME}.make (l_response, l_response.theme), s)
f.append_to_html (l_response.wsf_theme, s)
l_response.set_main_content (s)
l_response.execute
end
@@ -90,9 +94,16 @@ feature -- Widget
exportation_web_form (a_response: CMS_RESPONSE): CMS_FORM
local
f_name: WSF_FORM_TEXT_INPUT
but: WSF_FORM_SUBMIT_INPUT
do
create Result.make (a_response.url (a_response.location, Void), "export_all_data")
Result.extend_raw_text ("Export CMS data to ")
create f_name.make_with_text ("folder", (create {DATE_TIME}.make_now_utc).formatted_out ("yyyy-[0]mm-[0]dd---hh24-[0]mi-[0]ss"))
f_name.set_label ("Export folder name")
f_name.set_description ("Folder name under 'exports' folder.")
f_name.set_is_required (True)
Result.extend (f_name)
create but.make_with_text ("op", text_export_all_data)
Result.extend (but)
end

View File

@@ -0,0 +1,320 @@
note
description: "[
Administrate modules.
]"
date: "$Date$"
revision: "$Revision$"
class
CMS_ADMIN_MODULES_HANDLER
inherit
CMS_HANDLER
WSF_URI_HANDLER
rename
new_mapping as new_uri_mapping
end
WSF_RESOURCE_HANDLER_HELPER
redefine
do_get, do_post
end
REFACTORING_HELPER
CMS_SETUP_ACCESS
CMS_ACCESS
create
make
feature -- Execution
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
end
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
s: STRING
f: CMS_FORM
l_denied: BOOLEAN
do
if
attached {WSF_STRING} req.query_parameter ("op") as l_op and then l_op.same_string ("uninstall") and then
attached {WSF_TABLE} req.query_parameter ("module_uninstallation") as tb
then
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
if attached api.setup.string_8_item ("admin.installation_access") as l_access then
if l_access.is_case_insensitive_equal ("none") then
l_denied := True
elseif l_access.is_case_insensitive_equal ("permission") then
l_denied := not r.has_permission ("install modules")
end
else
l_denied := True
end
if l_denied then
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
r.set_main_content ("You do not have permission to access CMS module uninstallation procedure!")
else
create s.make_empty
across
tb as ic
loop
if attached api.setup.modules.item_by_name (ic.item.string_representation) as l_module then
if api.is_module_installed (l_module) then
api.uninstall_module (l_module)
if api.is_module_installed (l_module) then
s.append ("<p>ERROR: Module " + l_module.name + " failed to be uninstalled!</p>")
else
s.append ("<p>Module " + l_module.name + " was successfully uninstalled.</p>")
end
else
s.append ("<p>Module " + l_module.name + " is not installed.</p>")
end
end
end
s.append (r.link ("Back to modules management", r.location, Void))
r.set_main_content (s)
end
r.execute
else
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
f := modules_collection_web_form (r)
create s.make_empty
f.append_to_html (r.wsf_theme, s)
r.set_page_title ("Modules")
r.set_main_content (s)
r.execute
end
end
do_post (req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
s: STRING
f: CMS_FORM
l_denied: BOOLEAN
do
if attached {WSF_STRING} req.item ("op") as l_op then
if l_op.same_string ("Install modules") then
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
if attached api.setup.string_8_item ("admin.installation_access") as l_access then
if l_access.is_case_insensitive_equal ("none") then
l_denied := True
elseif l_access.is_case_insensitive_equal ("permission") then
l_denied := not r.has_permission ("install modules")
end
else
l_denied := True
end
if l_denied then
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
r.set_main_content ("You do not have permission to access CMS module installation procedure!")
else
f := modules_collection_web_form (r)
if l_op.same_string ("Install modules") then
f.submit_actions.extend (agent on_installation_submit)
f.process (r)
elseif l_op.same_string ("uninstall") then
f.submit_actions.extend (agent on_uninstallation_submit)
f.process (r)
end
if
not attached f.last_data as l_data or else
not l_data.is_valid
then
r.add_error_message ("Error occurred.")
create s.make_empty
f.append_to_html (r.wsf_theme, s)
r.set_page_title ("Modules")
r.set_main_content (s)
else
r.add_notice_message ("Operation on module(s) succeeded.")
r.set_redirection (r.location)
end
end
r.execute
else
create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api)
r.execute
end
else
do_get (req, res)
end
end
modules_collection_web_form (a_response: CMS_RESPONSE): CMS_FORM
local
mod: CMS_MODULE
f_cb: WSF_FORM_CHECKBOX_INPUT
w_tb: WSF_WIDGET_TABLE
w_row: WSF_WIDGET_TABLE_ROW
w_item: WSF_WIDGET_TABLE_ITEM
w_submit: WSF_FORM_SUBMIT_INPUT
w_set: WSF_FORM_FIELD_SET
l_mods_to_install: ARRAYED_LIST [CMS_MODULE]
do
create Result.make (a_response.url (a_response.location, Void), "modules_collection")
create w_tb.make
w_tb.add_css_class ("modules_table")
create w_row.make (5)
create w_item.make_with_text ("Enabled ")
w_row.add_item (w_item)
create w_item.make_with_text ("Module")
w_row.add_item (w_item)
create w_item.make_with_text ("Version")
w_row.add_item (w_item)
create w_item.make_with_text ("Description")
w_row.add_item (w_item)
w_tb.add_head_row (w_row)
create l_mods_to_install.make (0)
across
a_response.api.setup.modules as ic
loop
mod := ic.item
if not a_response.api.is_module_installed (mod) then
l_mods_to_install.extend (mod)
else
create w_row.make (5)
create f_cb.make ("module_" + mod.name)
f_cb.set_text_value (mod.name)
f_cb.set_checked (mod.is_enabled)
f_cb.set_is_readonly (True)
create w_item.make_with_content (f_cb)
w_row.add_item (w_item)
create w_item.make_with_text (mod.name)
w_row.add_item (w_item)
create w_item.make_with_text (mod.version)
w_row.add_item (w_item)
if attached mod.description as l_desc then
create w_item.make_with_text (l_desc)
w_row.add_item (w_item)
else
create w_item.make_with_text ("")
w_row.add_item (w_item)
end
create w_item.make_with_text (a_response.link ("Uninstall", a_response.location + "?op=uninstall&module_uninstallation[]=" + mod.name, Void))
w_row.add_item (w_item)
w_tb.add_row (w_row)
end
end
create w_set.make
w_set.set_legend ("Installed modules")
w_set.extend (w_tb)
-- create w_submit.make ("op")
-- w_submit.set_text_value ("Save")
-- w_set.extend (w_submit)
Result.extend (w_set)
Result.extend_html_text ("<br/>")
if not l_mods_to_install.is_empty then
create w_tb.make
w_tb.add_css_class ("modules_table")
create w_row.make (3)
create w_item.make_with_text ("Install ")
w_row.add_item (w_item)
create w_item.make_with_text ("Module")
w_row.add_item (w_item)
create w_item.make_with_text ("Description")
w_row.add_item (w_item)
w_tb.add_head_row (w_row)
across
l_mods_to_install as ic
loop
mod := ic.item
create w_row.make (3)
create f_cb.make ("module_installation[" + mod.name + "]")
f_cb.set_text_value (mod.name)
create w_item.make_with_content (f_cb)
w_row.add_item (w_item)
create w_item.make_with_text (mod.name)
w_row.add_item (w_item)
if attached mod.description as l_desc then
create w_item.make_with_text (l_desc)
w_row.add_item (w_item)
else
create w_item.make_with_text ("")
w_row.add_item (w_item)
end
w_tb.add_row (w_row)
end
create w_set.make
w_set.set_legend ("Available modules for installation")
w_set.extend (w_tb)
create w_submit.make ("op")
w_submit.set_text_value ("Install modules")
w_set.extend (w_submit)
Result.extend (w_set)
end
end
on_installation_submit (fd: WSF_FORM_DATA)
local
l_mods: CMS_MODULE_COLLECTION
do
if attached {WSF_TABLE} fd.table_item ("module_installation") as tb and then not tb.is_empty then
l_mods := api.setup.modules
across
tb as ic
loop
if
attached {WSF_STRING} ic.item as l_mod_name and then
attached l_mods.item_by_name (l_mod_name.value) as m
then
api.install_module (m)
if not api.is_module_installed (m) then
fd.report_error ("Installation failed for module " + m.name)
end
else
fd.report_error ("Can not find associated module" + ic.item.as_string.url_encoded_value)
end
end
else
fd.report_error ("No module to install!")
end
end
on_uninstallation_submit (fd: WSF_FORM_DATA)
local
l_mods: CMS_MODULE_COLLECTION
do
if attached {WSF_TABLE} fd.table_item ("module_uninstallation") as tb and then not tb.is_empty then
l_mods := api.setup.modules
across
tb as ic
loop
if
attached {WSF_STRING} ic.item as l_mod_name and then
attached l_mods.item_by_name (l_mod_name.value) as m
then
api.uninstall_module (m)
if api.is_module_installed (m) then
fd.report_error ("Un-Installation failed for module " + m.name)
end
else
fd.report_error ("Can not find associated module" + ic.item.as_string.url_encoded_value)
end
end
else
fd.report_error ("No module to uninstall!")
end
end
end

View File

@@ -8,30 +8,10 @@ class
inherit
CMS_RESPONSE
redefine
make,
initialize
end
create
make
feature {NONE} -- Initialization
make (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: like api)
do
create {WSF_NULL_THEME} wsf_theme.make
Precursor (req, res, a_api)
end
initialize
do
Precursor
create {CMS_TO_WSF_THEME} wsf_theme.make (Current, theme)
end
wsf_theme: WSF_THEME
feature -- Process
process

View File

@@ -8,32 +8,12 @@ class
inherit
CMS_RESPONSE
redefine
make,
initialize
end
CMS_SHARED_SORTING_UTILITIES
create
make
feature {NONE} -- Initialization
make (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: like api)
do
create {WSF_NULL_THEME} wsf_theme.make
Precursor (req, res, a_api)
end
initialize
do
Precursor
create {CMS_TO_WSF_THEME} wsf_theme.make (Current, theme)
end
wsf_theme: WSF_THEME
feature -- Query
role_id_path_parameter (req: WSF_REQUEST): INTEGER_64
@@ -84,7 +64,7 @@ feature -- Process Edit
do
create b.make_empty
f := new_edit_form (a_role, url (request.percent_encoded_path_info, Void), "edit-user")
hooks.invoke_form_alter (f, fd, Current)
api.hooks.invoke_form_alter (f, fd, Current)
if request.is_post_request_method then
f.validation_actions.extend (agent edit_form_validate(?,a_role, b))
f.submit_actions.extend (agent edit_form_submit(?, a_role, b))
@@ -117,7 +97,7 @@ feature -- Process Delete
do
create b.make_empty
f := new_delete_form (a_role, url (request.percent_encoded_path_info, Void), "edit-user")
hooks.invoke_form_alter (f, fd, Current)
api.hooks.invoke_form_alter (f, fd, Current)
if request.is_post_request_method then
f.process (Current)
fd := f.last_data
@@ -149,7 +129,7 @@ feature -- Process New
do
create b.make_empty
f := new_edit_form (l_role, url (request.percent_encoded_path_info, Void), "create-role")
hooks.invoke_form_alter (f, fd, Current)
api.hooks.invoke_form_alter (f, fd, Current)
if request.is_post_request_method then
f.validation_actions.extend (agent new_form_validate(?, b))
f.submit_actions.extend (agent edit_form_submit(?, l_role, b))

View File

@@ -8,31 +8,10 @@ class
inherit
CMS_RESPONSE
redefine
make,
initialize
end
create
make
feature {NONE} -- Initialization
make (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: like api;)
do
create {WSF_NULL_THEME} wsf_theme.make
Precursor (req, res, a_api)
end
initialize
do
Precursor
create {CMS_TO_WSF_THEME} wsf_theme.make (Current, theme)
end
wsf_theme: WSF_THEME
feature -- Query
role_id_path_parameter (req: WSF_REQUEST): INTEGER_64

View File

@@ -7,32 +7,11 @@ class
CMS_USER_FORM_RESPONSE
inherit
CMS_RESPONSE
redefine
make,
initialize
end
create
make
feature {NONE} -- Initialization
make (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: like api)
do
create {WSF_NULL_THEME} wsf_theme.make
Precursor (req, res, a_api)
end
initialize
do
Precursor
create {CMS_TO_WSF_THEME} wsf_theme.make (Current, theme)
end
wsf_theme: WSF_THEME
feature -- Query
user_id_path_parameter (req: WSF_REQUEST): INTEGER_64
@@ -86,7 +65,7 @@ feature -- Process Edit
do
create b.make_empty
f := new_edit_form (a_user, url (location, Void), "edit-user")
hooks.invoke_form_alter (f, fd, Current)
api.hooks.invoke_form_alter (f, fd, Current)
if request.is_post_request_method then
f.submit_actions.extend (agent edit_form_submit (?, a_user, b))
f.process (Current)
@@ -118,7 +97,7 @@ feature -- Process Delete
do
create b.make_empty
f := new_delete_form (a_user, url (location, Void), "edit-user")
hooks.invoke_form_alter (f, fd, Current)
api.hooks.invoke_form_alter (f, fd, Current)
if request.is_post_request_method then
f.process (Current)
fd := f.last_data
@@ -151,7 +130,7 @@ feature -- Process New
do
create b.make_empty
f := new_edit_form (l_user, url (location, Void), "create-user")
hooks.invoke_form_alter (f, fd, Current)
api.hooks.invoke_form_alter (f, fd, Current)
if request.is_post_request_method then
f.validation_actions.extend (agent new_form_validate (?, b))
f.submit_actions.extend (agent edit_form_submit (?, l_user, b))

View File

@@ -8,31 +8,10 @@ class
inherit
CMS_RESPONSE
redefine
make,
initialize
end
create
make
feature {NONE} -- Initialization
make (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: like api;)
do
create {WSF_NULL_THEME} wsf_theme.make
Precursor (req, res, a_api)
end
initialize
do
Precursor
create {CMS_TO_WSF_THEME} wsf_theme.make (Current, theme)
end
wsf_theme: WSF_THEME
feature -- Query
user_id_path_parameter (req: WSF_REQUEST): INTEGER_64
@@ -94,7 +73,7 @@ feature -- Execution
s.append ("<div class=%"info%"> ")
s.append ("<h4>Account Information</h4>")
s.append ("<p>Username: ")
s.append (a_user.name)
s.append (html_encoded (a_user.name))
s.append ("</p>")
if attached a_user.email as l_email then
s.append ("<p>Email: ")

View File

@@ -1,34 +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="auth_module" uuid="AAB9EE7D-A671-4727-8658-D417A48B2B57" library_target="auth_module">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="auth_module" uuid="AAB9EE7D-A671-4727-8658-D417A48B2B57" library_target="auth_module">
<target name="auth_module">
<root all_classes="true"/>
<file_rule>
<exclude>/.git$</exclude>
<exclude>/EIFGENs$</exclude>
<exclude>/.svn$</exclude>
<exclude>/EIFGENs$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard">
<option warning="true" full_class_checking="true" is_attached_by_default="true" is_obsolete_routine_type="true" void_safety="all" syntax="standard">
</option>
<library name="apis" location="$ISE_LIBRARY\contrib\library\web\authentication\oauth\cypress\consumer\apis\apis.ecf" readonly="false"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="cms" location="..\..\cms-safe.ecf" readonly="false"/>
<library name="cms_app_env" location="..\..\library\app_env\app_env-safe.ecf" readonly="false"/>
<library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/>
<library name="config" location="..\..\library\configuration\config-safe.ecf"/>
<library name="cypress_consumer" location="$ISE_LIBRARY\contrib\library\web\authentication\oauth\cypress\consumer-safe.ecf" readonly="false"/>
<library name="email_service" location="..\..\library\email\email-safe.ecf"/>
<library name="encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder-safe.ecf"/>
<library name="error" location="$ISE_LIBRARY\contrib\library\utility\general\error\error-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
<library name="recaptcha" location="..\..\library\recaptcha\recaptcha-safe.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
<library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension-safe.ecf" readonly="false"/>
<library name="wsf_html" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf_html\wsf_html-safe.ecf" readonly="false"/>
<library name="error" location="$ISE_LIBRARY\contrib\library\utility\general\error\error-safe.ecf"/>
<library name="email_service" location="..\..\library\email\email-safe.ecf"/>
<library name="apis" location="$ISE_LIBRARY\contrib\library\web\authentication\oauth\cypress\consumer\apis\apis.ecf" readonly="false"/>
<library name="cypress_consumer" location="$ISE_LIBRARY\contrib\library\web\authentication\oauth\cypress\consumer-safe.ecf" readonly="false"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
<cluster name="src" location=".\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,209 @@
note
description: "Summary description for {CMS_AUTHENTICATION_EMAIL_SERVICE}."
date: "$Date$"
revision: "$Revision$"
class
CMS_AUTHENTICATION_EMAIL_SERVICE
create
make
feature {NONE} -- Initialization
make (a_params: like parameters)
-- Create instance of email service with `a_params' data.
do
parameters := a_params
initialize
end
initialize
-- Initialize service.
do
create error_handler.make
reset_error
end
feature -- Access
parameters: CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS
-- Associated parameters.
cms_api: CMS_API
do
Result := parameters.cms_api
end
contact_email_address: IMMUTABLE_STRING_8
-- contact email.
do
Result := parameters.contact_email_address
end
notif_email_address: IMMUTABLE_STRING_8
-- Site admin's email.
do
Result := parameters.notif_email_address
end
sender_email_address: IMMUTABLE_STRING_8
-- Site sender's email.
do
Result := parameters.sender_email_address
end
feature -- Error
error_handler: ERROR_HANDLER
has_error: BOOLEAN
do
Result := error_handler.has_error
end
reset_error
do
error_handler.reset
end
feature -- Basic Operations / Internal
send_internal_email (a_content: READABLE_STRING_GENERAL)
do
send_message (sender_email_address, notif_email_address, "Notification Contact", a_content)
end
send_email_internal_server_error (a_content: READABLE_STRING_GENERAL)
do
send_message (sender_email_address, notif_email_address, "Internal Server Error", a_content)
end
feature -- Basic Operations / Contact
send_account_evaluation (a_user: CMS_USER; a_application, a_url_activate, a_url_reject, a_host: READABLE_STRING_8)
-- Send new user register to webmaster to confirm or reject itt.
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_evaluation)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.utf_8_site_name)
l_message.replace_substring_all ("$user", a_user.utf_8_name)
if attached a_user.email as l_email then
l_message.replace_substring_all ("$email", l_email)
else
l_message.replace_substring_all ("$email", "unknown email")
end
l_message.replace_substring_all ("$application", a_application)
l_message.replace_substring_all ("$activation_url", a_url_activate)
l_message.replace_substring_all ("$rejection_url", a_url_reject)
send_message (contact_email_address, contact_email_address, parameters.contact_subject_account_evaluation, l_message)
end
send_contact_email (a_to: READABLE_STRING_8; a_user: CMS_USER; a_host: READABLE_STRING_8)
-- Send successful contact message for user `a_user' to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_activation)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.utf_8_site_name)
l_message.replace_substring_all ("$user", a_user.utf_8_name)
send_message (contact_email_address, a_to, parameters.contact_subject_register, l_message)
end
send_contact_activation_email (a_to: READABLE_STRING_8; a_user: CMS_USER; a_link, a_host: READABLE_STRING_8)
-- Send successful message activation to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_re_activation)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.utf_8_site_name)
l_message.replace_substring_all ("$link", a_link)
send_message (contact_email_address, a_to, parameters.contact_subject_activate, l_message)
end
send_contact_activation_confirmation_email (a_to: READABLE_STRING_8; a_user: CMS_USER; a_host: READABLE_STRING_8)
-- Send successful message activation to a_to.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_activation_confirmation)
l_message.replace_substring_all ("$hot", a_host)
l_message.replace_substring_all ("$sitename", parameters.utf_8_site_name)
l_message.replace_substring_all ("$user", a_user.utf_8_name)
l_message.replace_substring_all ("$email", a_to)
send_message (contact_email_address, a_to, parameters.contact_subject_activated, l_message)
end
send_contact_activation_reject_email (a_to: READABLE_STRING_8; a_user: CMS_USER; a_host: READABLE_STRING_8)
-- Send successful contact activation reject message to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_rejected)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.utf_8_site_name)
l_message.replace_substring_all ("$email", a_to)
l_message.replace_substring_all ("$user", a_user.utf_8_name)
send_message (contact_email_address, a_to, parameters.contact_subject_rejected, l_message)
end
send_contact_password_email (a_to: READABLE_STRING_8; a_user: CMS_USER; a_link, a_host: READABLE_STRING_8)
-- Send successful new account password message to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_password)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.utf_8_site_name)
l_message.replace_substring_all ("$link", a_link)
send_message (contact_email_address, a_to, parameters.contact_subject_password, l_message)
end
send_contact_welcome_email (a_to: READABLE_STRING_8; a_user: CMS_USER; a_host: READABLE_STRING_8)
-- Send successful welcome message to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_welcome)
l_message.replace_substring_all ("$host", a_host)
l_message.replace_substring_all ("$sitename", parameters.utf_8_site_name)
l_message.replace_substring_all ("$email", a_to)
l_message.replace_substring_all ("$user", a_user.utf_8_name)
send_message (contact_email_address, a_to, parameters.contact_subject_oauth, l_message)
end
feature {NONE} -- Implementation
send_message (a_from_address, a_to_address: READABLE_STRING_8; a_subjet: READABLE_STRING_GENERAL; a_content: READABLE_STRING_GENERAL)
local
l_email: CMS_EMAIL
utf: UTF_CONVERTER
do
reset_error
l_email := cms_api.new_email (a_to_address, utf.escaped_utf_32_string_to_utf_8_string_8 (a_subjet), utf.escaped_utf_32_string_to_utf_8_string_8 (a_content))
l_email.set_from_address (a_from_address)
l_email.add_header_line ("MIME-Version:1.0")
l_email.add_header_line ("Content-Type: text/html; charset=utf-8")
cms_api.process_email (l_email)
if cms_api.has_error then
error_handler.add_custom_error (-1, generator + "send_message failed", cms_api.string_representation_of_errors)
end
end
end

View File

@@ -6,9 +6,6 @@ note
class
CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS
inherit
EMAIL_SERVICE_PARAMETERS
create
make
@@ -17,25 +14,21 @@ feature {NONE} -- Initialization
make (a_cms_api: CMS_API)
local
utf: UTF_CONVERTER
l_site_name: READABLE_STRING_8
s: detachable READABLE_STRING_32
l_utf8_site_name: IMMUTABLE_STRING_8
l_contact_email, l_subject_register, l_subject_activate, l_subject_password, l_subject_oauth: detachable READABLE_STRING_8
do
cms_api := a_cms_api
-- Use global smtp setting if any, otherwise "localhost"
smtp_server := utf.escaped_utf_32_string_to_utf_8_string_8 (a_cms_api.setup.text_item_or_default ("smtp", "localhost"))
l_site_name := utf.escaped_utf_32_string_to_utf_8_string_8 (a_cms_api.setup.site_name)
admin_email := a_cms_api.setup.site_email
create l_utf8_site_name.make_from_string (a_cms_api.setup.utf_8_site_name)
utf_8_site_name := l_utf8_site_name
notif_email_address := a_cms_api.setup.site_notification_email
sender_email_address := a_cms_api.setup.site_email
if not admin_email.has ('<') then
admin_email := l_site_name + " <" + admin_email +">"
if not notif_email_address.has ('<') then
notif_email_address := l_utf8_site_name + " <" + notif_email_address + ">"
end
if attached {CONFIG_READER} a_cms_api.module_configuration_by_name ({CMS_AUTHENTICATION_MODULE}.name, Void) as cfg then
if attached cfg.text_item ("smtp") as l_smtp then
-- Overwrite global smtp setting if any.
smtp_server := utf.utf_32_string_to_utf_8_string_8 (l_smtp)
end
if attached a_cms_api.module_configuration_by_name ({CMS_AUTHENTICATION_MODULE}.name, Void) as cfg then
s := cfg.text_item ("email")
if s /= Void then
l_contact_email := utf.utf_32_string_to_utf_8_string_8 (s)
@@ -56,16 +49,15 @@ feature {NONE} -- Initialization
if s /= Void then
l_subject_oauth := utf.utf_32_string_to_utf_8_string_8 (s)
end
end
if l_contact_email = Void then
l_contact_email := notif_email_address
end
if not l_contact_email.has ('<') then
l_contact_email := l_utf8_site_name + " <" + l_contact_email + ">"
end
contact_email_address := l_contact_email
end
if l_contact_email /= Void then
if not l_contact_email.has ('<') then
l_contact_email := l_site_name + " <" + l_contact_email + ">"
end
contact_email := l_contact_email
else
contact_email := admin_email
end
if l_subject_register /= Void then
contact_subject_register := l_subject_register
else
@@ -88,23 +80,40 @@ feature {NONE} -- Initialization
contact_subject_oauth := "Welcome."
end
contact_subject_account_evaluation := "New register, account evalution."
contact_subject_rejected := "Your account was rejected."
contact_subject_activated := "Your account was activated."
end
feature -- Access
cms_api: CMS_API
smtp_server: IMMUTABLE_STRING_8
notif_email_address: IMMUTABLE_STRING_8
admin_email: IMMUTABLE_STRING_8
sender_email_address: IMMUTABLE_STRING_8
contact_email: IMMUTABLE_STRING_8
contact_email_address: IMMUTABLE_STRING_8
-- Contact email.
utf_8_site_name: IMMUTABLE_STRING_8
-- UTF-8 encoded Site name.
contact_subject_account_evaluation: IMMUTABLE_STRING_8
contact_subject_register: IMMUTABLE_STRING_8
contact_subject_activate: IMMUTABLE_STRING_8
contact_subject_password: IMMUTABLE_STRING_8
contact_subject_oauth: IMMUTABLE_STRING_8
contact_subject_rejected: IMMUTABLE_STRING_8
contact_subject_activated: IMMUTABLE_STRING_8
account_evaluation: STRING
-- Account evaluation template email message.
do
Result := template_string ("admin_account_evaluation.html", default_template_account_evaluation)
end
account_activation: STRING
-- Account activation template email message.
@@ -112,12 +121,24 @@ feature -- Access
Result := template_string ("account_activation.html", default_template_account_activation)
end
account_activation_confirmation: STRING
-- Account activation confirmation template email message.
do
Result := template_string ("account_activation_confirmation.html", default_template_account_activation_confirmation)
end
account_re_activation: STRING
-- Account re_activation template email message.
do
Result := template_string ("accunt_re_activation.html", default_template_account_re_activation)
end
account_rejected: STRING
-- Account rejected template email message.
do
Result := template_string ("accunt_rejected.html", default_template_account_rejected)
end
account_password: STRING
-- Account password template email message.
do
@@ -146,7 +167,7 @@ feature {NONE} -- Implementation: Template
local
p: PATH
do
p := template_path ("account_activation.html")
p := template_path (a_name)
if attached read_template_file (p) as l_content then
Result := l_content
else
@@ -177,6 +198,36 @@ feature {NONE} -- Implementation
feature {NONE} -- Message email
default_template_account_evaluation: STRING = "[
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Account Evaluation</title>
<meta name="description" content="Account Evaluation">
<meta name="author" content="$sitename">
</head>
<body>
<h2> Account Evaluation </h2>
<p>The user $user ($email) wants to register to the site <a href="$host">$sitename</a></p>
<blockquote><p>This is his/her application.</p>
<p>$application</p>
</blockquote>
<p>To complete the registration, please click on the following link to activate the user account:<p>
<p><a href="$activation_url">$activation_url</a></p>
<p>To reject the registration, please click on the following link <p>
<p><a href="$rejection_url">$rejection_url</a></p>
</body>
</html>
]"
default_template_account_activation: STRING = "[
<!doctype html>
<html lang="en">
@@ -184,21 +235,53 @@ feature {NONE} -- Message email
<meta charset="utf-8">
<title>Activation</title>
<meta name="description" content="Activation">
<meta name="author" content="ROC CMS">
<meta name="author" content="$sitename">
</head>
<body>
<p>Thank you for registering at <a href="...">ROC CMS</a></p>
<p>Thank you for applying to <a href="$host">$sitename</a> $user</p>
<p>To complete your registration, please click on the following link to activate your account:<p>
<p><a href="$link">$link</a></p>
<p>We will review your application and send you an email<p>
<p>Thank you for joining us.</p>
</body>
</html>
]"
default_template_account_activation_confirmation: STRING = "[
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Activation</title>
<meta name="description" content="Activation Confirmation">
<meta name="author" content="$sitename">
</head>
<body>
<p>Your account has been confirmed <a href="$host">$sitename</a> $email</p>
<p>Thank you for joining us.</p>
</body>
</html>
]"
default_template_account_rejected: STRING = "[
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Application Rejected</title>
<meta name="description" content="Application Rejected">
<meta name="author" content="$sitename">
</head>
<body>
<p>You requested has been rejected, your application does not conform our rules <a href="$host">$sitename</a></p>
</body>
</html>
]"
default_template_account_re_activation: STRING = "[
<!doctype html>
<html lang="en">
@@ -206,11 +289,11 @@ feature {NONE} -- Message email
<meta charset="utf-8">
<title>New Activation</title>
<meta name="description" content="New Activation token">
<meta name="author" content="ROC CMS">
<meta name="author" content="$sitename">
</head>
<body>
<p>You have requested a new activation token at <a href="...">ROC CMS</a></p>
<p>You have requested a new activation token at <a href="$host">$sitename</a></p>
<p>To complete your registration, please click on the following link to activate your account:<p>
@@ -229,11 +312,11 @@ feature {NONE} -- Message email
<meta charset="utf-8">
<title>New Password</title>
<meta name="description" content="New Password">
<meta name="author" content="ROC CMS">
<meta name="author" content="$sitename">
</head>
<body>
<p>You have required a new password at <a href="...">ROC CMS</a></p>
<p>You have required a new password at <a href="$host">$sitename</a></p>
<p>To complete your request, please click on this link to generate a new password:<p>
@@ -250,11 +333,11 @@ feature {NONE} -- Message email
<meta charset="utf-8">
<title>Welcome</title>
<meta name="description" content="Welcome">
<meta name="author" content="ROC CMS">
<meta name="author" content="$sitename">
</head>
<body>
<p>Welcome to<a href="...">ROC CMS</a></p>
<p>Welcome to<a href="...">$sitename</a></p>
<p>Thank you for joining us.</p>
</body>
</html>

View File

@@ -7,14 +7,17 @@ class
CMS_AUTHENTICATION_MODULE
inherit
CMS_MODULE
redefine
setup_hooks
setup_hooks,
permissions
end
CMS_HOOK_AUTO_REGISTER
CMS_HOOK_RESPONSE_ALTER
CMS_HOOK_VALUE_TABLE_ALTER
CMS_HOOK_BLOCK
@@ -43,7 +46,6 @@ feature {NONE} -- Initialization
version := "1.0"
description := "Authentication module"
package := "authentication"
create root_dir.make_current
cache_duration := 0
end
@@ -52,6 +54,17 @@ feature -- Access
name: STRING = "auth"
permissions: LIST [READABLE_STRING_8]
-- List of permission ids, used by this module, and declared.
do
Result := Precursor
Result.force ("account register")
Result.force ("account activate")
Result.force ("account reject")
Result.force ("account reactivate")
Result.force ("admin registration")
end
feature -- Access: docs
root_dir: PATH
@@ -73,20 +86,29 @@ feature -- Router
-- <Precursor>
do
configure_web (a_api, a_router)
configure_web_admin (a_api, a_router)
end
configure_web (a_api: CMS_API; a_router: WSF_ROUTER)
do
a_router.handle ("/account", create {WSF_URI_AGENT_HANDLER}.make (agent handle_account (a_api, ?, ?)), a_router.methods_head_get)
a_router.handle ("/account/roc-login", create {WSF_URI_AGENT_HANDLER}.make (agent handle_login (a_api, ?, ?)), a_router.methods_head_get)
a_router.handle ("/account/roc-logout", create {WSF_URI_AGENT_HANDLER}.make (agent handle_logout (a_api, ?, ?)), a_router.methods_head_get)
a_router.handle ("/account/roc-register", create {WSF_URI_AGENT_HANDLER}.make (agent handle_register (a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/activate/{token}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_activation (a_api, ?, ?)), a_router.methods_head_get)
a_router.handle ("/account/reactivate", create {WSF_URI_AGENT_HANDLER}.make (agent handle_reactivation (a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/new-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_new_password (a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/reset-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_reset_password (a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/change-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_change_password (a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/post-change-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_post_change_password (a_api, ?, ?)), a_router.methods_get)
a_router.handle ("/account", create {WSF_URI_AGENT_HANDLER}.make (agent handle_account(a_api, ?, ?)), a_router.methods_head_get)
a_router.handle ("/account/roc-login", create {WSF_URI_AGENT_HANDLER}.make (agent handle_login(a_api, ?, ?)), a_router.methods_head_get)
a_router.handle ("/account/roc-logout", create {WSF_URI_AGENT_HANDLER}.make (agent handle_logout(a_api, ?, ?)), a_router.methods_head_get)
a_router.handle ("/account/roc-register", create {WSF_URI_AGENT_HANDLER}.make (agent handle_register(a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/activate/{token}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_activation(a_api, ?, ?)), a_router.methods_head_get)
a_router.handle ("/account/reject/{token}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_reject(a_api, ?, ?)), a_router.methods_head_get)
a_router.handle ("/account/reactivate", create {WSF_URI_AGENT_HANDLER}.make (agent handle_reactivation(a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/new-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_new_password(a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/reset-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_reset_password(a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/change-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_change_password(a_api, ?, ?)), a_router.methods_get_post)
a_router.handle ("/account/post-change-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_post_change_password(a_api, ?, ?)), a_router.methods_get)
end
configure_web_admin (a_api: CMS_API; a_router: WSF_ROUTER)
-- Configure router mapping for admin web interface.
do
a_router.handle ("/admin/pending-registrations/", create {WSF_URI_AGENT_HANDLER}.make (agent handle_admin_pending_registrations (?, ?, a_api)), a_router.methods_get)
end
feature -- Hooks configuration
@@ -97,6 +119,7 @@ feature -- Hooks configuration
auto_subscribe_to_hooks (a_hooks)
a_hooks.subscribe_to_block_hook (Current)
a_hooks.subscribe_to_value_table_alter_hook (Current)
a_hooks.subscribe_to_menu_system_alter_hook (Current)
end
value_table_alter (a_value: CMS_VALUE_TABLE; a_response: CMS_RESPONSE)
@@ -112,7 +135,7 @@ feature -- Hooks configuration
lnk: CMS_LOCAL_LINK
do
if attached a_response.user as u then
create lnk.make (u.name, "account" )
create lnk.make (u.name, "account")
lnk.set_weight (97)
a_menu_system.primary_menu.extend (lnk)
create lnk.make ("Logout", "account/roc-logout")
@@ -123,7 +146,11 @@ feature -- Hooks configuration
lnk.set_weight (98)
a_menu_system.primary_menu.extend (lnk)
end
-- Add the link to the taxonomy to the main menu
if a_response.has_permission ("admin registration") then
create lnk.make ("Registration", "admin/pending-registrations/")
a_menu_system.management_menu.extend (lnk)
end
end
feature -- Handler
@@ -133,7 +160,6 @@ feature -- Handler
r: CMS_RESPONSE
do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
if attached template_block ("account_info", r) as l_tpl_block then
if attached r.user as l_user then
r.set_value (api.user_api.user_roles (l_user), "roles")
@@ -175,11 +201,14 @@ feature -- Handler
local
r: CMS_RESPONSE
l_user_api: CMS_USER_API
u: CMS_USER
u: CMS_TEMP_USER
l_exist: BOOLEAN
es: CMS_AUTHENTICATON_EMAIL_SERVICE
l_url: STRING
es: CMS_AUTHENTICATION_EMAIL_SERVICE
l_url_activate: STRING
l_url_reject: STRING
l_token: STRING
l_captcha_passed: BOOLEAN
l_email: READABLE_STRING_8
do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
if r.has_permission ("account register") then
@@ -187,49 +216,77 @@ feature -- Handler
if
attached {WSF_STRING} req.form_parameter ("name") as l_name and then
attached {WSF_STRING} req.form_parameter ("password") as l_password and then
attached {WSF_STRING} req.form_parameter ("email") as l_email
attached {WSF_STRING} req.form_parameter ("email") as p_email and then
attached {WSF_STRING} req.form_parameter ("personal_information") as l_personal_information
then
l_user_api := api.user_api
if p_email.value.is_valid_as_string_8 then
l_email := p_email.value.to_string_8
l_user_api := api.user_api
if attached l_user_api.user_by_name (l_name.value) or else attached l_user_api.temp_user_by_name (l_name.value) then
-- Username already exist.
r.set_value ("User name already exists!", "error_name")
l_exist := True
end
if attached l_user_api.user_by_email (l_email) or else attached l_user_api.temp_user_by_email (l_email) then
-- Emails already exist.
r.set_value ("An account is already associated with that email address!", "error_email")
l_exist := True
end
if attached recaptcha_secret_key (api) as l_recaptcha_key then
if attached {WSF_STRING} req.form_parameter ("g-recaptcha-response") as l_recaptcha_response and then is_captcha_verified (l_recaptcha_key, l_recaptcha_response.value) then
l_captcha_passed := True
else
--| Bad or missing captcha
l_captcha_passed := False
end
else
--| reCaptcha is not setup, so no verification
l_captcha_passed := True
end
if not l_exist then
-- New temp user
create u.make (l_name.value)
u.set_email (l_email)
u.set_password (l_password.value)
u.set_personal_information (l_personal_information.value)
l_user_api.new_temp_user (u)
if attached l_user_api.user_by_name (l_name.value) then
-- Username already exist.
r.set_value ("User name already exists!", "error_name")
l_exist := True
end
if attached l_user_api.user_by_email (l_email.value) then
-- Emails already exist.
r.set_value ("An account is already associated with that email address!", "error_email")
l_exist := True
end
-- Create activation token
l_token := new_token
l_user_api.new_activation (l_token, u.id)
l_url_activate := req.absolute_script_url ("/account/activate/" + l_token)
l_url_reject := req.absolute_script_url ("/account/reject/" + l_token)
if not l_exist then
-- New user
create u.make (l_name.value)
u.set_email (l_email.value)
u.set_password (l_password.value)
l_user_api.new_user (u)
-- Create activation token
l_token := new_token
l_user_api.new_activation (l_token, u.id)
l_url := req.absolute_script_url ("/account/activate/" + l_token)
-- Send Email
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
write_debug_log (generator + ".handle register: send_contact_email")
es.send_contact_email (l_email.value, l_url)
-- Send Email to webmaster
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
write_debug_log (generator + ".handle register: send_register_email")
es.send_account_evaluation (u, l_personal_information.value, l_url_activate, l_url_reject, req.absolute_script_url (""))
-- Send Email to user
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
write_debug_log (generator + ".handle register: send_contact_email")
es.send_contact_email (l_email, u, req.absolute_script_url (""))
else
r.set_value (l_name.value, "name")
r.set_value (l_email, "email")
r.set_value (l_personal_information.value, "personal_information")
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end
else
r.set_value (l_name.value, "name")
r.set_value (l_email.value, "email")
r.set_value (p_email.value, "email")
r.set_value (l_personal_information.value, "personal_information")
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end
else
create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api)
r.set_main_content ("There were issue with your application, invalid or missing values.")
end
end
else
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
r.set_main_content ("You can also contact the webmaster to ask for an account.")
end
r.execute
end
@@ -238,110 +295,187 @@ feature -- Handler
r: CMS_RESPONSE
l_user_api: CMS_USER_API
l_ir: INTERNAL_SERVER_ERROR_CMS_RESPONSE
es: CMS_AUTHENTICATION_EMAIL_SERVICE
do
l_user_api := api.user_api
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
if attached {WSF_STRING} req.path_parameter ("token") as l_token then
if r.has_permission ("account activate") then
if attached {WSF_STRING} req.path_parameter ("token") as l_token then
if attached {CMS_TEMP_USER} l_user_api.temp_user_by_activation_token (l_token.value) as l_user then
if attached {CMS_USER} l_user_api.user_by_activation_token (l_token.value) as l_user then
-- Valid user_id
l_user.mark_active
l_user_api.update_user (l_user)
l_user_api.remove_activation (l_token.value)
r.set_main_content ("<p> Your account <i>"+ l_user.name +"</i> has been activated</p>")
-- TODO copy the personal information
--! to CMS_USER_PROFILE and persist data
--! check also CMS_USER.data_items
-- Delete temporal User
l_user_api.delete_temp_user (l_user)
-- Valid user_id
l_user.set_id (0)
l_user.mark_active
l_user_api.new_user_from_temp_user (l_user)
l_user_api.remove_activation (l_token.value)
r.set_main_content ("<p> The account <i>" + html_encoded (l_user.name) + "</i> has been activated</p>")
-- Send Email
if attached l_user.email as l_email then
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
write_debug_log (generator + ".handle register: send_contact_activation_confirmation_email")
es.send_contact_activation_confirmation_email (l_email, l_user, req.absolute_script_url (""))
end
else
-- the token does not exist, or it was already used.
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
r.set_main_content ("<p>The token <i>" + l_token.value + "</i> is not valid " + r.link ("Reactivate Account", "account/reactivate", Void) + "</p>")
end
r.execute
else
-- the token does not exist, or it was already used.
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
r.set_main_content ("<p>The token <i>" + l_token.value +"</i> is not valid " + r.link ("Reactivate Account", "account/reactivate", Void) + "</p>")
create l_ir.make (req, res, api)
l_ir.execute
end
r.execute
else
create l_ir.make (req, res, api)
l_ir.execute
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
r.execute
end
end
handle_reject (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
es: CMS_AUTHENTICATION_EMAIL_SERVICE
l_ir: INTERNAL_SERVER_ERROR_CMS_RESPONSE
l_user_api: CMS_USER_API
do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
if r.has_permission ("account reject") then
if attached {WSF_STRING} req.path_parameter ("token") as l_token then
l_user_api := api.user_api
if attached {CMS_TEMP_USER} l_user_api.temp_user_by_activation_token (l_token.value) as l_user then
l_user_api.delete_temp_user (l_user)
r.set_main_content ("<p> The temporal account for <i>" + html_encoded (l_user.name) + "</i> has been removed</p>")
-- Send Email
if attached l_user.email as l_email then
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
write_debug_log (generator + ".handle register: send_contact_activation_reject_email")
es.send_contact_activation_reject_email (l_email, l_user, req.absolute_script_url (""))
end
else
-- the token does not exist, or it was already used.
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
r.set_main_content ("<p>The token <i>" + l_token.value + "</i> is not valid ")
end
r.execute
else
create l_ir.make (req, res, api)
l_ir.execute
end
else
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
r.execute
end
end
handle_reactivation (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
es: CMS_AUTHENTICATON_EMAIL_SERVICE
es: CMS_AUTHENTICATION_EMAIL_SERVICE
l_user_api: CMS_USER_API
l_token: STRING
l_url: STRING
l_url_activate: STRING
l_url_reject: STRING
l_email: READABLE_STRING_8
do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
if req.is_post_request_method then
if
attached {WSF_STRING} req.form_parameter ("email") as l_email
then
l_user_api := api.user_api
if attached {CMS_USER} l_user_api.user_by_email (l_email.value) as l_user then
-- User exist create a new token and send a new email.
if l_user.is_active then
r.set_value ("The asociated user to the given email " + l_email.value + " , is already active", "is_active")
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
if r.has_permission ("account reactivate") then
if req.is_post_request_method then
if attached {WSF_STRING} req.form_parameter ("email") as p_email then
if p_email.value.is_valid_as_string_8 then
l_email := p_email.value.to_string_8
l_user_api := api.user_api
if attached {CMS_TEMP_USER} l_user_api.temp_user_by_email (l_email) as l_user then
-- User exist create a new token and send a new email.
if l_user.is_active then
r.set_value ("The asociated user to the given email " + l_email + " , is already active", "is_active")
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
else
l_token := new_token
l_user_api.new_activation (l_token, l_user.id)
l_url_activate := req.absolute_script_url ("/account/activate/" + l_token)
l_url_reject := req.absolute_script_url ("/account/reject/" + l_token)
-- Send Email to webmaster
if attached l_user.personal_information as l_personal_information then
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
write_debug_log (generator + ".handle register: send_register_email")
es.send_account_evaluation (l_user, l_personal_information, l_url_activate, l_url_reject, req.absolute_script_url (""))
end
end
else
r.set_value ("The email does not exist !", "error_email")
r.set_value (l_email, "email")
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end
else
l_token := new_token
l_user_api.new_activation (l_token, l_user.id)
l_url := req.absolute_script_url ("/account/activate/" + l_token)
-- Send Email
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
write_debug_log (generator + ".handle register: send_contact_activation_email")
es.send_contact_activation_email (l_email.value, l_url)
r.set_value ("The email is not valid!", "error_email")
r.set_value (p_email.value, "email")
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end
else
r.set_value ("The email does not exist or !", "error_email")
r.set_value (l_email.value, "email")
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end
end
else
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
r.execute
end
r.execute
end
handle_new_password (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
es: CMS_AUTHENTICATON_EMAIL_SERVICE
es: CMS_AUTHENTICATION_EMAIL_SERVICE
l_user_api: CMS_USER_API
l_token: STRING
l_url: STRING
l_email: READABLE_STRING_8
do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
if req.is_post_request_method then
l_user_api := api.user_api
if attached {WSF_STRING} req.form_parameter ("email") as l_email then
if attached {CMS_USER} l_user_api.user_by_email (l_email.value) as l_user then
if attached {WSF_STRING} req.form_parameter ("email") as p_email then
if p_email.value.is_valid_as_string_8 then
l_email := p_email.value.to_string_8
if attached {CMS_USER} l_user_api.user_by_email (l_email) as l_user then
-- User exist create a new token and send a new email.
l_token := new_token
l_user_api.new_password (l_token, l_user.id)
l_url := req.absolute_script_url ("/account/reset-password?token=" + l_token)
l_token := new_token
l_user_api.new_password (l_token, l_user.id)
l_url := req.absolute_script_url ("/account/reset-password?token=" + l_token)
-- Send Email
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
write_debug_log (generator + ".handle register: send_contact_password_email")
es.send_contact_password_email (l_email.value, l_url)
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
write_debug_log (generator + ".handle register: send_contact_password_email")
es.send_contact_password_email (l_email, l_user, l_url, req.absolute_script_url (""))
else
r.set_value ("The email does not exist !", "error_email")
r.set_value (p_email.value, "email")
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end
else
r.set_value ("The email does not exist !", "error_email")
r.set_value (l_email.value, "email")
r.set_value ("The email is not valid!", "error_email")
r.set_value (p_email.value, "email")
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end
elseif attached {WSF_STRING} req.form_parameter ("username") as l_username then
if attached {CMS_USER} l_user_api.user_by_name (l_username) as l_user and then
attached l_user.email as l_email
if
attached {CMS_USER} l_user_api.user_by_name (l_username) as l_user and then
attached l_user.email as l_user_email
then
-- User exist create a new token and send a new email.
-- User exist create a new token and send a new email.
l_token := new_token
l_user_api.new_password (l_token, l_user.id)
l_url := req.absolute_script_url ("/account/reset-password?token=" + l_token)
-- Send Email
-- Send Email
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
write_debug_log (generator + ".handle register: send_contact_password_email")
es.send_contact_password_email (l_email, l_url)
es.send_contact_password_email (l_user_email, l_user, l_url, req.absolute_script_url (""))
else
r.set_value ("The username does not exist !", "error_username")
r.set_value (l_username.value, "username")
@@ -352,7 +486,6 @@ feature -- Handler
r.execute
end
handle_reset_password (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)
local
r: CMS_RESPONSE
@@ -360,24 +493,18 @@ feature -- Handler
do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
l_user_api := api.user_api
if attached {WSF_STRING} req.query_parameter ("token") as l_token then
if attached {WSF_STRING} req.query_parameter ("token") as l_token then
r.set_value (l_token.value, "token")
if l_user_api.user_by_password_token (l_token.value) = Void then
r.set_value ("The token " + l_token.value + " is not valid, " + r.link ("click here" , "account/new-password", Void) + " to generate a new token.", "error_token")
if l_user_api.user_by_password_token (l_token.value) = Void then
r.set_value ("The token " + l_token.value + " is not valid, " + r.link ("click here", "account/new-password", Void) + " to generate a new token.", "error_token")
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
end
end
if req.is_post_request_method then
if
attached {WSF_STRING} req.form_parameter ("token") as l_token and then
attached {WSF_STRING} req.form_parameter ("password") as l_password and then
attached {WSF_STRING} req.form_parameter ("confirm_password") as l_confirm_password
then
-- Does the passwords match?
if attached {WSF_STRING} req.form_parameter ("token") as l_token and then attached {WSF_STRING} req.form_parameter ("password") as l_password and then attached {WSF_STRING} req.form_parameter ("confirm_password") as l_confirm_password then
-- Does the passwords match?
if l_password.value.same_string (l_confirm_password.value) then
-- is the token valid?
-- is the token valid?
if attached {CMS_USER} l_user_api.user_by_password_token (l_token.value) as l_user then
l_user.set_password (l_password.value)
l_user_api.update_user (l_user)
@@ -400,22 +527,17 @@ feature -- Handler
do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
l_user_api := api.user_api
if req.is_post_request_method then
if attached r.user as l_user then
if attached r.user as l_user then
r.set_value (api.user_api.user_roles (l_user), "roles")
if
attached {WSF_STRING} req.form_parameter ("password") as l_password and then
attached {WSF_STRING} req.form_parameter ("confirm_password") as l_confirm_password and then
l_password.value.same_string (l_confirm_password.value)
then
-- Does the passwords match?
if attached {WSF_STRING} req.form_parameter ("password") as l_password and then attached {WSF_STRING} req.form_parameter ("confirm_password") as l_confirm_password and then l_password.value.same_string (l_confirm_password.value) then
-- Does the passwords match?
l_user.set_password (l_password.value)
l_user_api.update_user (l_user)
r.set_redirection (req.absolute_script_url ("/account/post-change-password"))
else
if attached template_block ("account_info", r) as l_tpl_block then
-- r.set_value (l_user, "user")
-- r.set_value (l_user, "user")
r.set_value ("Passwords Don't Match", "error_password")
r.set_status_code ({HTTP_CONSTANTS}.bad_request)
r.add_block (l_tpl_block, "content")
@@ -437,11 +559,102 @@ feature -- Handler
r.execute
end
handle_admin_pending_registrations (req: WSF_REQUEST; res: WSF_RESPONSE; api: CMS_API)
local
l_response: CMS_RESPONSE
s: STRING
u: CMS_TEMP_USER
l_page_helper: CMS_PAGINATION_GENERATOR
s_pager: STRING
l_count: INTEGER
l_user_api: CMS_USER_API
do
-- At the moment the template are hardcoded, but we can
-- get them from the configuration file and load them into
-- the setup class.
create {FORBIDDEN_ERROR_CMS_RESPONSE} l_response.make (req, res, api)
if
l_response.has_permission ("admin registration")
then
l_user_api := api.user_api
l_count := l_user_api.temp_users_count
create {GENERIC_VIEW_CMS_RESPONSE} l_response.make (req, res, api)
create s.make_empty
if l_count > 1 then
l_response.set_title ("Listing " + l_count.out + " Pending Registrations")
else
l_response.set_title ("Listing " + l_count.out + " Pending Registration")
end
create s_pager.make_empty
create l_page_helper.make ("admin/pending-registrations/?page={page}&size={size}", l_user_api.temp_users_count.as_natural_64, 25) -- FIXME: Make this default page size a global CMS settings
l_page_helper.get_setting_from_request (req)
if l_page_helper.has_upper_limit and then l_page_helper.pages_count > 1 then
l_page_helper.append_to_html (l_response, s_pager)
if l_page_helper.page_size > 25 then
s.append (s_pager)
end
end
if attached l_user_api.temp_recent_users (create {CMS_DATA_QUERY_PARAMETERS}.make (l_page_helper.current_page_offset, l_page_helper.page_size)) as lst then
s.append ("<ul class=%"cms-temp-users%">%N")
across
lst as ic
loop
u := ic.item
s.append ("<li class=%"cms_temp_user%">")
s.append ("User:" + html_encoded (u.name))
s.append ("<ul class=%"cms_temp_user_details%">")
if attached u.personal_information as l_information then
s.append ("<li class=%"cms_temp_user_detail_information%">")
s.append (html_encoded (l_information))
s.append ("</li>%N")
end
if attached u.email as l_email then
s.append ("<li class=%"cms_temp_user_detail_email%">")
s.append (l_email)
s.append ("</li>%N")
end
if attached l_user_api.token_by_temp_user_id (u.id) as l_token then
s.append ("<li>")
s.append ("<a href=%"")
s.append (req.absolute_script_url ("/account/activate/" + l_token))
s.append ("%">")
s.append (html_encoded ("Activate"))
s.append ("</a>")
s.append ("</li>%N")
s.append ("<li>")
s.append ("<a href=%"")
s.append (req.absolute_script_url ("/account/reject/" + l_token))
s.append ("%">")
s.append (html_encoded ("Reject"))
s.append ("</a>")
s.append ("</li>%N")
end
s.append ("</ul>%N")
s.append ("</li>%N")
end
s.append ("</ul>%N")
end
-- Again the pager at the bottom, if needed
s.append (s_pager)
l_response.set_main_content (s)
l_response.execute
else
l_response.execute
end
end
block_list: ITERABLE [like {CMS_BLOCK}.name]
local
l_string: STRING
do
Result := <<"register", "reactivate", "new_password", "reset_password">>
Result := <<"register", "reactivate", "new_password", "reset_password", "registration">>
debug ("roc")
create l_string.make_empty
across
@@ -450,32 +663,22 @@ feature -- Handler
l_string.append (ic.item)
l_string.append_character (' ')
end
write_debug_log (generator + ".block_list:" + l_string )
write_debug_log (generator + ".block_list:" + l_string)
end
end
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
do
if
a_block_id.is_case_insensitive_equal_general ("register") and then
a_response.location.starts_with ("account/roc-register")
then
if a_block_id.is_case_insensitive_equal_general ("register") and then a_response.location.starts_with ("account/roc-register") then
get_block_view_register (a_block_id, a_response)
elseif
a_block_id.is_case_insensitive_equal_general ("reactivate") and then
a_response.location.starts_with ("account/reactivate")
then
elseif a_block_id.is_case_insensitive_equal_general ("reactivate") and then a_response.location.starts_with ("account/reactivate") then
get_block_view_reactivate (a_block_id, a_response)
elseif
a_block_id.is_case_insensitive_equal_general ("new_password") and then
a_response.location.starts_with ("account/new-password")
then
elseif a_block_id.is_case_insensitive_equal_general ("new_password") and then a_response.location.starts_with ("account/new-password") then
get_block_view_new_password (a_block_id, a_response)
elseif
a_block_id.is_case_insensitive_equal_general ("reset_password") and then
a_response.location.starts_with ("account/reset-password")
then
elseif a_block_id.is_case_insensitive_equal_general ("reset_password") and then a_response.location.starts_with ("account/reset-password") then
get_block_view_reset_password (a_block_id, a_response)
elseif a_block_id.is_case_insensitive_equal_general ("registration") and then a_response.location.starts_with ("admin/pending-registrations") then
get_block_view_registration (a_block_id, a_response)
end
end
@@ -491,10 +694,13 @@ feature {NONE} -- Token Generation
create l_security
l_token := l_security.token
create l_encode
from until l_token.same_string (l_encode.encoded_string (l_token)) loop
-- Loop ensure that we have a security token that does not contain characters that need encoding.
-- We cannot simply to an encode-decode because the email sent to the user will contain an encoded token
-- but the user will need to use an unencoded token if activation has to be done manually.
from
until
l_token.same_string (l_encode.encoded_string (l_token))
loop
-- Loop ensure that we have a security token that does not contain characters that need encoding.
-- We cannot simply to an encode-decode because the email sent to the user will contain an encoded token
-- but the user will need to use an unencoded token if activation has to be done manually.
l_token := l_security.token
end
Result := l_token
@@ -509,7 +715,6 @@ feature {NONE} -- Helpers
do
create p.make_from_string ("templates")
p := p.extended ("block_").appended (a_block_id).appended_with_extension ("tpl")
p := a_response.api.module_theme_resource_location (Current, p)
if p /= Void then
if attached p.entry as e then
@@ -522,32 +727,14 @@ feature {NONE} -- Helpers
feature {NONE} -- Block views
-- get_block_view_login (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
-- local
---- vals: CMS_VALUE_TABLE
-- do
-- if attached template_block (a_block_id, a_response) as l_tpl_block then
---- create vals.make (1)
---- -- add the variable to the block
---- value_table_alter (vals, a_response)
---- across
---- vals as ic
---- loop
---- l_tpl_block.set_value (ic.item, ic.key)
---- end
-- a_response.put_required_block (l_tpl_block, "content")
-- else
-- debug ("cms")
-- a_response.add_warning_message ("Error with block [" + a_block_id + "]")
-- end
-- end
-- end
get_block_view_register (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
do
if a_response.has_permission ("account register") then
if a_response.request.is_get_request_method then
if attached template_block (a_block_id, a_response) as l_tpl_block then
if attached recaptcha_site_key (a_response.api) as l_recaptcha_site_key then
l_tpl_block.set_value (l_recaptcha_site_key, "recaptcha_site_key")
end
a_response.add_block (l_tpl_block, "content")
else
debug ("cms")
@@ -557,10 +744,13 @@ feature {NONE} -- Block views
elseif a_response.request.is_post_request_method then
if a_response.values.has ("error_name") or else a_response.values.has ("error_email") then
if attached template_block (a_block_id, a_response) as l_tpl_block then
-- l_tpl_block.set_value (a_response.values.item ("error_name"), "error_name")
-- l_tpl_block.set_value (a_response.values.item ("error_email"), "error_email")
-- l_tpl_block.set_value (a_response.values.item ("email"), "email")
-- l_tpl_block.set_value (a_response.values.item ("name"), "name")
-- l_tpl_block.set_value (a_response.values.item ("error_name"), "error_name")
-- l_tpl_block.set_value (a_response.values.item ("error_email"), "error_email")
-- l_tpl_block.set_value (a_response.values.item ("email"), "email")
-- l_tpl_block.set_value (a_response.values.item ("name"), "name")
if attached recaptcha_site_key (a_response.api) as l_recaptcha_site_key then
l_tpl_block.set_value (l_recaptcha_site_key, "recaptcha_site_key")
end
a_response.add_block (l_tpl_block, "content")
else
debug ("cms")
@@ -593,9 +783,9 @@ feature {NONE} -- Block views
elseif a_response.request.is_post_request_method then
if a_response.values.has ("error_email") or else a_response.values.has ("is_active") then
if attached template_block (a_block_id, a_response) as l_tpl_block then
-- l_tpl_block.set_value (a_response.values.item ("error_email"), "error_email")
-- l_tpl_block.set_value (a_response.values.item ("email"), "email")
-- l_tpl_block.set_value (a_response.values.item ("is_active"), "is_active")
-- l_tpl_block.set_value (a_response.values.item ("error_email"), "error_email")
-- l_tpl_block.set_value (a_response.values.item ("email"), "email")
-- l_tpl_block.set_value (a_response.values.item ("is_active"), "is_active")
a_response.add_block (l_tpl_block, "content")
else
debug ("cms")
@@ -625,12 +815,12 @@ feature {NONE} -- Block views
end
end
elseif a_response.request.is_post_request_method then
if a_response.values.has ("error_email") or else a_response.values.has ("error_username") then
if a_response.values.has ("error_email") or else a_response.values.has ("error_username") then
if attached template_block (a_block_id, a_response) as l_tpl_block then
-- l_tpl_block.set_value (a_response.values.item ("error_email"), "error_email")
-- l_tpl_block.set_value (a_response.values.item ("email"), "email")
-- l_tpl_block.set_value (a_response.values.item ("error_username"), "error_username")
-- l_tpl_block.set_value (a_response.values.item ("username"), "username")
-- l_tpl_block.set_value (a_response.values.item ("error_email"), "error_email")
-- l_tpl_block.set_value (a_response.values.item ("email"), "email")
-- l_tpl_block.set_value (a_response.values.item ("error_username"), "error_username")
-- l_tpl_block.set_value (a_response.values.item ("username"), "username")
a_response.add_block (l_tpl_block, "content")
else
debug ("cms")
@@ -653,8 +843,8 @@ feature {NONE} -- Block views
do
if a_response.request.is_get_request_method then
if attached template_block (a_block_id, a_response) as l_tpl_block then
-- l_tpl_block.set_value (a_response.values.item ("token"), "token")
-- l_tpl_block.set_value (a_response.values.item ("error_token"), "error_token")
-- l_tpl_block.set_value (a_response.values.item ("token"), "token")
-- l_tpl_block.set_value (a_response.values.item ("error_token"), "error_token")
a_response.add_block (l_tpl_block, "content")
else
debug ("cms")
@@ -662,11 +852,11 @@ feature {NONE} -- Block views
end
end
elseif a_response.request.is_post_request_method then
if a_response.values.has ("error_token") or else a_response.values.has ("error_password") then
if a_response.values.has ("error_token") or else a_response.values.has ("error_password") then
if attached template_block (a_block_id, a_response) as l_tpl_block then
-- l_tpl_block.set_value (a_response.values.item ("error_token"), "error_token")
-- l_tpl_block.set_value (a_response.values.item ("error_password"), "error_password")
-- l_tpl_block.set_value (a_response.values.item ("token"), "token")
-- l_tpl_block.set_value (a_response.values.item ("error_token"), "error_token")
-- l_tpl_block.set_value (a_response.values.item ("error_password"), "error_password")
-- l_tpl_block.set_value (a_response.values.item ("token"), "token")
a_response.add_block (l_tpl_block, "content")
else
debug ("cms")
@@ -685,14 +875,75 @@ feature {NONE} -- Block views
end
end
get_block_view_registration (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
do
end
feature -- Recaptcha
recaptcha_secret_key (api: CMS_API): detachable READABLE_STRING_8
-- Get recaptcha security key.
local
utf: UTF_CONVERTER
do
if attached api.module_configuration (Current, Void) as cfg then
if attached cfg.text_item ("recaptcha.secret_key") as l_recaptcha_key and then not l_recaptcha_key.is_empty then
Result := utf.utf_32_string_to_utf_8_string_8 (l_recaptcha_key)
end
end
end
recaptcha_site_key (api: CMS_API): detachable READABLE_STRING_8
-- Get recaptcha security key.
local
utf: UTF_CONVERTER
do
if attached api.module_configuration (Current, Void) as cfg then
if attached cfg.text_item ("recaptcha.site_key") as l_recaptcha_key and then not l_recaptcha_key.is_empty then
Result := utf.utf_32_string_to_utf_8_string_8 (l_recaptcha_key)
end
end
end
feature -- Response Alter
response_alter (a_response: CMS_RESPONSE)
do
a_response.add_javascript_url ("https://www.google.com/recaptcha/api.js")
a_response.add_style (a_response.url ("/module/" + name + "/files/css/auth.css", Void), Void)
end
feature {NONE} -- Implementation
is_captcha_verified (a_secret, a_response: READABLE_STRING_8): BOOLEAN
local
api: RECAPTCHA_API
l_errors: STRING
do
write_debug_log (generator + ".is_captcha_verified with response: [" + a_response + "]")
create api.make (a_secret, a_response)
Result := api.verify
if not Result and then attached api.errors as l_api_errors then
create l_errors.make_empty
l_errors.append_character ('%N')
across
l_api_errors as ic
loop
l_errors.append (ic.item)
l_errors.append_character ('%N')
end
write_error_log (generator + ".is_captcha_verified api_errors [" + l_errors + "]")
end
end
note
copyright: "Copyright (c) 1984-2013, 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
]"
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,88 +0,0 @@
note
description: "Summary description for {CMS_AUTHENTICATON_EMAIL_SERVICE}."
date: "$Date$"
revision: "$Revision$"
class
CMS_AUTHENTICATON_EMAIL_SERVICE
inherit
EMAIL_SERVICE
redefine
initialize,
parameters
end
create
make
feature {NONE} -- Initialization
initialize
do
Precursor
contact_email := parameters.contact_email
end
parameters: CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS
-- Associated parameters.
feature -- Access
contact_email: IMMUTABLE_STRING_8
-- contact email.
feature -- Basic Operations
send_contact_email (a_to, a_content: READABLE_STRING_8)
-- Send successful contact message `a_token' to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_activation)
l_message.replace_substring_all ("$link", a_content)
send_message (contact_email, a_to, parameters.contact_subject_register, l_message)
end
send_contact_activation_email (a_to, a_content: READABLE_STRING_8)
-- Send successful contact message `a_token' to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_re_activation)
l_message.replace_substring_all ("$link", a_content)
send_message (contact_email, a_to, parameters.contact_subject_activate, l_message)
end
send_contact_password_email (a_to, a_content: READABLE_STRING_8)
-- Send successful contact message `a_token' to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_password)
l_message.replace_substring_all ("$link", a_content)
send_message (contact_email, a_to, parameters.contact_subject_password, l_message)
end
send_contact_welcome_email (a_to, a_content: READABLE_STRING_8)
-- Send successful contact message `a_token' to `a_to'.
require
attached_to: a_to /= Void
local
l_message: STRING
do
create l_message.make_from_string (parameters.account_welcome)
l_message.replace_substring_all ("$link", a_content)
send_message (contact_email, a_to, parameters.contact_subject_oauth, l_message)
end
end

View File

@@ -0,0 +1,7 @@
{
"subject": "Thank you for contacting us",
"recaptcha": {
"site_key":"6Lex9RMTAAAAAKleC4x6TaRlFcpLbEWgH_U7MSiD",
"secret_key":"6Lex9RMTAAAAAAkBczvX5DUiyg_xoM_EthVVgRRx"
}
}

View File

@@ -0,0 +1,28 @@
ul.cms-temp-users {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
}
ul.cms-temp-users li {
border-top: dotted 1px #ccc;
}
ul.cms-temp-users li:first-child {
border-top: none;
}
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
}
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li {
border-top: dotted 1px #ccc;
}
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li:first-child {
border-top: none;
}
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li.cms_temp_user_detail_information::before {
content: "[personal information] ";
}
ul.cms-temp-users li.cms_temp_user ul.cms_temp_user_details li.cms_temp_user_detail_email::before {
content: "[email] ";
}

View File

@@ -0,0 +1,37 @@
ul.cms-temp-users {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
li{
border-top: dotted 1px #ccc;
&:first-child {
border-top: none;
}
}
li.cms_temp_user {
ul.cms_temp_user_details {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
li{
border-top: dotted 1px #ccc;
&:first-child {
border-top: none;
}
}
li.cms_temp_user_detail_information::before{
content: "[personal information] "
}
li.cms_temp_user_detail_email::before{
content: "[email] "
}
}
}
}

View File

@@ -4,15 +4,10 @@
<meta charset="utf-8">
<title>Activation</title>
<meta name="description" content="Activation">
<meta name="author" content="ROC CMS">
<meta name="author" content="$sitename">
</head>
<body>
<p>Thank you for registering at <a href="$host">ROC CMS</a></p>
<p>To complete your registration, please click on this link to activate your account:<p>
<p><a href="$link">$link</a></p>
<p>Thank you for joining us.</p>
<p>"$user ($email)", thank you for applying to <a href="$host">$sitename</a>.</p>
<p>We will review your application and send you a resolution.<p>
</body>
</html>

View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Activation Confirmation</title>
<meta name="description" content="Activation Confirmation">
<meta name="author" content="$sitename">
</head>
<body>
<p>Your account "$user ($email)" is confirmed at <a href="$host">$sitename</a>.</p>
<p>Thank you for joining us.</p>
</body>
</html>

View File

@@ -4,14 +4,12 @@
<meta charset="utf-8">
<title>New Password</title>
<meta name="description" content="New Password">
<meta name="author" content="ROC CMS">
<meta name="author" content="$sitename">
</head>
<body>
<p>You have required a new password at <a href="$host">ROC CMS</a></p>
<p>To complete your request, please click on this link to genereate a new password:<p>
<p><a href="$link">$link</a></p>
<p>You have requested a new password at <a href="$host">$sitename</a>.</p>
<p>To complete your request, please click on the following link to generate a new password:
<ul><a href="$link">$link</a></ul>
</p>
</body>
</html>

View File

@@ -4,15 +4,14 @@
<meta charset="utf-8">
<title>New Activation</title>
<meta name="description" content="New Activation token">
<meta name="author" content="ROC CMS">
<meta name="author" content="$sitename">
</head>
<body>
<p>You have request a new activation token at <a href="$host">ROC CMS</a></p>
<p>You have requested a new activation token at <a href="$host">$sitename</a>.</p>
<p>To complete your registration, please click on this link to activate your account:<p>
<p><a href="$link">$link</a></p>
<p>To complete your registration, please click on the following link to re-activate your account:
<ul><a href="$link">$link</a></ul>
</p>
<p>Thank you for joining us.</p>
</body>
</html>

View File

@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Application Rejected</title>
<meta name="description" content="Application Rejected">
<meta name="author" content="$sitename">
</head>
<body>
<p>Your account application is rejected, it was not respecting the requirements from <a href="$host">$sitename</a>.</p>
</body>
</html>

View File

@@ -4,10 +4,16 @@
<meta charset="utf-8">
<title>Welcome</title>
<meta name="description" content="Welcome">
<meta name="author" content="ROC CMS">
<meta name="author" content="$sitename">
</head>
<body>
<p>Welcome to<a href="$host">ROC CMS</a></p>
<p>Welcome to <a href="$host">$sitename</a>.</p>
<p>Your account information:
<ul>
<li>Email address: "$email" .</li>
<li>User name: "$user" .</li>
</ul>
</p>
<p>Thank you for joining us.</p>
</body>
</html>

View File

@@ -0,0 +1,26 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Account Evaluation</title>
<meta name="description" content="Account Evaluation">
<meta name="author" content="$sitename">
</head>
<body>
<h2> Account Evaluation </h2>
<p>The user $user ($email) wants to register to the site <a href="$host">$sitename</a></p>
<blockquote><p>User application:</p>
<p>$application</p>
</blockquote>
<p>To complete the registration, please click on the following link to activate the user account:<p>
<p><a href="$activation_url">$activation_url</a></p>
<p>To reject the registration, please click on the following link <p>
<p><a href="$rejection_url<">$rejection_url</a></p>
</body>
</html>

View File

@@ -1,3 +1,3 @@
<div>
<p>We have send you a new activation code, check your email to activate your account.</p>
<p>Thanks for your application, we will review it to activate your account.</p>
</div>

View File

@@ -1,3 +1,3 @@
<div>
<p>Thanks for register, check your email to activate your account.</p>
<p>Thanks for your application, we will review it to activate your account.</p>
</div>

View File

@@ -1,7 +1,7 @@
<div>
<form action="{$site_url/}account/roc-register" method="post">
<fieldset>
<legend>Register Form</legend>
<legend>Registration</legend>
<div>
<input type="text" id="name" name="name" value="{$name/}" required autofocus />
<label for="name">Name</label>
@@ -20,8 +20,19 @@
<span><i>{$error_email/}</i></span> <br>
{/if}
</div>
<div>
<textarea rows="4" cols="50" name="personal_information" id="personal_information" required>
{$personal_information/}
</textarea>
<label for="personal_information">Tell us why you want to register an account</label>
{if isset="$error_application"}
<span><i>{$error_application/}</i></span> <br>
{/if}
</div>
{unless isempty="$recaptcha_site_key"}
<div class="g-recaptcha" data-sitekey="{$recaptcha_site_key/}"></div>
<br/>
{/unless}
<button type="submit">Register</button>
</fieldset>
</form>

View File

@@ -11,7 +11,7 @@ ROC_AUTH.login = function() {
var username = form.username.value;
var password = form.password.value;
//var host = form.host.value;
var origin = window.location.origin.concat(window.location.pathname);
var origin = window.location.origin + window.location.pathname;
var _login = function(){
@@ -322,4 +322,4 @@ ROC_AUTH.validatePassword =function(){
if ((password != null) && (confirm_password != null)) {
password.onchange = ROC_AUTH.validatePassword();
confirm_password.onkeyup = ROC_AUTH.validatePassword;
}
}

View File

@@ -36,7 +36,7 @@ feature {NONE} -- Initialization
Precursor
-- Create the node storage for type blog
if attached {CMS_STORAGE_SQL_I} storage as l_storage_sql then
if attached storage.as_sql_storage as l_storage_sql then
create {CMS_BLOG_STORAGE_SQL} blog_storage.make (l_storage_sql)
else
create {CMS_BLOG_STORAGE_NULL} blog_storage.make

View File

@@ -65,8 +65,8 @@ feature {CMS_API} -- Module Initialization
loop
ct.extend_format (ic.item)
end
l_node_api.add_content_type (ct)
l_node_api.add_content_type_webform_manager (create {CMS_BLOG_NODE_TYPE_WEBFORM_MANAGER}.make (ct))
l_node_api.add_node_type (ct)
l_node_api.add_node_type_webform_manager (create {CMS_BLOG_NODE_TYPE_WEBFORM_MANAGER}.make (ct, l_node_api))
-- 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.
@@ -83,7 +83,7 @@ feature {CMS_API} -- Module management
sql: STRING
do
-- Schema
if attached {CMS_STORAGE_SQL_I} api.storage as l_sql_storage then
if attached api.storage.as_sql_storage as l_sql_storage then
if not l_sql_storage.sql_table_exists ("blog_post_nodes") then
sql := "[
CREATE TABLE blog_post_nodes(
@@ -188,7 +188,10 @@ feature -- Hooks
a_export_id_list = Void
or else across a_export_id_list as ic some ic.item.same_string ("blog") end
then
if attached blog_api as l_blog_api then
if
a_response.has_permissions (<<"export any node", "export blog">>) and then
attached blog_api as l_blog_api
then
lst := l_blog_api.blogs_order_created_desc
a_export_parameters.log ("Exporting " + lst.count.out + " blogs")
across
@@ -207,6 +210,30 @@ feature -- Hooks
f.put_string (json_to_string (blog_node_to_json (n)))
f.close
end
-- Revisions.
if
attached node_api as l_node_api and then
attached l_node_api.node_revisions (n) as l_revisions and then l_revisions.count > 1
then
a_export_parameters.log (n.content_type + " " + l_revisions.count.out + " revisions.")
p := a_export_parameters.location.extended ("nodes").extended (n.content_type).extended (n.id.out)
create d.make_with_path (p)
if not d.exists then
d.recursive_create_dir
end
across
l_revisions as revs_ic
loop
if attached {CMS_BLOG} revs_ic.item as l_blog then
create f.make_with_path (p.extended ("rev-" + n.revision.out).appended_with_extension ("json"))
if not f.exists or else f.is_access_writable then
f.open_write
f.put_string (json_to_string (blog_node_to_json (l_blog)))
end
f.close
end
end
end
end
end
end

View File

@@ -13,7 +13,7 @@ inherit
populate_form,
update_node,
new_node,
append_html_output_to
append_content_as_html_to
end
create
@@ -76,34 +76,24 @@ feature -- form
feature -- Output
append_html_output_to (a_node: CMS_NODE; a_response: NODE_RESPONSE)
append_content_as_html_to (a_node: CMS_BLOG; is_teaser: BOOLEAN; a_output: STRING; a_response: detachable CMS_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
Precursor (a_node, is_teaser, a_output, a_response)
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> ")
a_output.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> ")
a_output.append ("<span class=%"tag%">")
a_output.append (cms_api.html_encoded (ic.item))
a_output.append ("</span> ")
end
s.append ("</div>")
a_output.append ("</div>")
end
end
a_response.set_main_content (s)
end
end

View File

@@ -206,7 +206,7 @@ feature -- HTML Output
do
if attached n.author as l_author then
a_output.append ("by ")
a_output.append ("<a class=%"blog_user_link%" href=%"/blogs/user/" + l_author.id.out + "%">" + l_author.name + "</a>")
a_output.append ("<a class=%"blog_user_link%" href=%"/blogs/user/" + l_author.id.out + "%">" + html_encoded (l_author.name) + "</a>")
end
end
@@ -232,7 +232,7 @@ feature -- HTML Output
if attached api.format (n.format) as f then
f.append_formatted_to (l_summary, a_output)
else
page.formats.default_format.append_formatted_to (l_summary, a_output)
api.formats.default_format.append_formatted_to (l_summary, a_output)
end
a_output.append ("<br />")
a_output.append (page.link ("See more...", lnk.location, Void))

View File

@@ -40,9 +40,7 @@ feature {NONE} -- Initialization
local
ct: CMS_PAGE_NODE_TYPE
do
-- Initialize content types.
create content_types.make (1)
create content_type_webform_managers.make (1)
-- Initialize node content types.
create ct
--| For now, add all available formats to content type `ct'.
across
@@ -50,8 +48,8 @@ feature {NONE} -- Initialization
loop
ct.extend_format (ic.item)
end
add_content_type (ct)
add_content_type_webform_manager (create {CMS_PAGE_NODE_TYPE_WEBFORM_MANAGER}.make (ct))
add_node_type (ct)
add_node_type_webform_manager (create {CMS_PAGE_NODE_TYPE_WEBFORM_MANAGER}.make (ct, Current))
end
feature {CMS_MODULE} -- Access nodes storage.
@@ -60,15 +58,18 @@ feature {CMS_MODULE} -- Access nodes storage.
feature -- Content type
content_types: ARRAYED_LIST [CMS_CONTENT_TYPE]
-- Available content types
add_node_type (a_type: CMS_NODE_TYPE [CMS_NODE])
-- Register node content type `a_type'.
do
cms_api.add_content_type (a_type)
end
node_types: ARRAYED_LIST [attached like node_type]
-- Node content types.
do
create Result.make (content_types.count)
create Result.make (cms_api.content_types.count)
across
content_types as ic
cms_api.content_types as ic
loop
if attached {like node_type} ic.item as l_node_type then
Result.extend (l_node_type)
@@ -76,32 +77,11 @@ feature -- Content type
end
end
add_content_type (a_type: CMS_CONTENT_TYPE)
-- Register content type `a_type'.
do
content_types.force (a_type)
end
content_type (a_name: READABLE_STRING_GENERAL): detachable CMS_CONTENT_TYPE
-- Content type named `a_named' if any.
do
across
content_types as ic
until
Result /= Void
loop
Result := ic.item
if not a_name.is_case_insensitive_equal (Result.name) then
Result := Void
end
end
end
node_type (a_name: READABLE_STRING_GENERAL): detachable CMS_NODE_TYPE [CMS_NODE]
-- Content type named `a_named' if any.
do
across
content_types as ic
cms_api.content_types as ic
until
Result /= Void
loop
@@ -125,31 +105,16 @@ feature -- Content type
feature -- Content type webform
content_type_webform_managers: ARRAYED_LIST [CMS_CONTENT_TYPE_WEBFORM_MANAGER]
content_type_webform_managers: ARRAYED_LIST [CMS_CONTENT_TYPE_WEBFORM_MANAGER [CMS_CONTENT]]
-- Available content types
add_content_type_webform_manager (a_manager: CMS_CONTENT_TYPE_WEBFORM_MANAGER)
-- Register webform manager `a_manager'.
do
content_type_webform_managers.force (a_manager)
Result := cms_api.content_type_webform_managers
end
content_type_webform_manager (a_content_type: CMS_CONTENT_TYPE): detachable CMS_CONTENT_TYPE_WEBFORM_MANAGER
-- Web form manager for content type `a_content_type' if any.
local
l_type_name: READABLE_STRING_GENERAL
add_node_type_webform_manager (a_manager: CMS_NODE_TYPE_WEBFORM_MANAGER [CMS_NODE])
-- Register webform manager `a_manager'.
do
l_type_name := a_content_type.name
across
content_type_webform_managers as ic
until
Result /= Void
loop
Result := ic.item
if not l_type_name.is_case_insensitive_equal (Result.name) then
Result := Void
end
end
cms_api.add_content_type_webform_manager (a_manager)
end
node_type_webform_manager (a_node_type: CMS_CONTENT_TYPE): detachable CMS_NODE_TYPE_WEBFORM_MANAGER_I [CMS_NODE]

View File

@@ -25,6 +25,8 @@ inherit
CMS_RECENT_CHANGES_HOOK
CMS_TAXONOMY_HOOK
CMS_HOOK_EXPORT
CMS_EXPORT_NODE_UTILITIES
@@ -41,6 +43,9 @@ feature {NONE} -- Initialization
description := "Service to manage content based on 'node'"
package := "core"
config := a_setup
-- Optional dependencies, mainly for information.
put_dependency ({CMS_RECENT_CHANGES_MODULE}, False)
put_dependency ({CMS_TAXONOMY_MODULE}, False)
end
config: CMS_SETUP
@@ -63,7 +68,7 @@ feature {CMS_API} -- Module Initialization
Precursor (a_api)
-- Storage initialization
if attached {CMS_STORAGE_SQL_I} a_api.storage as l_storage_sql then
if attached a_api.storage.as_sql_storage as l_storage_sql then
create {CMS_NODE_STORAGE_SQL} l_node_storage.make (l_storage_sql)
else
-- FIXME: in case of NULL storage, should Current be disabled?
@@ -111,7 +116,7 @@ feature {CMS_API} -- Module management
-- Is Current module installed?
do
Result := Precursor (a_api)
if Result and attached {CMS_STORAGE_SQL_I} a_api.storage as l_sql_storage then
if Result and attached a_api.storage.as_sql_storage as l_sql_storage then
Result := l_sql_storage.sql_table_exists ("nodes") and
l_sql_storage.sql_table_exists ("page_nodes")
end
@@ -120,7 +125,7 @@ feature {CMS_API} -- Module management
install (a_api: CMS_API)
do
-- Schema
if attached {CMS_STORAGE_SQL_I} a_api.storage as l_sql_storage then
if attached a_api.storage.as_sql_storage as l_sql_storage then
l_sql_storage.sql_execute_file_script (a_api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended (name).appended_with_extension ("sql")), Void)
end
Precursor {CMS_MODULE}(a_api)
@@ -151,10 +156,11 @@ feature -- Access
do
Result := Precursor
Result.force ("create any node")
Result.force ("export any node")
if attached node_api as l_node_api then
across
l_node_api.content_types as ic
l_node_api.node_types as ic
loop
l_type_name := ic.item.name
if not l_type_name.is_whitespace then
@@ -177,6 +183,8 @@ feature -- Access
Result.force ("view unpublished " + l_type_name)
Result.force ("view revisions own " + l_type_name)
Result.force ("export " + l_type_name)
end
end
Result.force ("view trash")
@@ -238,6 +246,7 @@ feature -- Hooks
-- Module specific hook, if available.
a_hooks.subscribe_to_hook (Current, {CMS_RECENT_CHANGES_HOOK})
a_hooks.subscribe_to_hook (Current, {CMS_TAXONOMY_HOOK})
end
response_alter (a_response: CMS_RESPONSE)
@@ -279,7 +288,7 @@ feature -- Hooks
create perms.make (2)
perms.force ("create any node")
across
l_node_api.content_types as ic
l_node_api.node_types as ic
loop
perms.force ("create " + ic.item.name)
end
@@ -294,7 +303,7 @@ feature -- Hooks
do
if
attached node_api as l_node_api and then
attached l_node_api.content_types as l_types and then
attached l_node_api.node_types as l_types and then
not l_types.is_empty
then
create lst.make (l_types.count)
@@ -358,6 +367,51 @@ feature -- Hooks
end
end
populate_content_associated_with_term (t: CMS_TERM; a_contents: CMS_TAXONOMY_ENTITY_CONTAINER)
local
l_node_typenames: ARRAYED_LIST [READABLE_STRING_8]
nid: INTEGER_64
l_info_to_remove: ARRAYED_LIST [TUPLE [entity: READABLE_STRING_32; typename: detachable READABLE_STRING_32]]
do
if
attached node_api as l_node_api and then
attached l_node_api.node_types as l_node_types and then
not l_node_types.is_empty
then
create l_node_typenames.make (l_node_types.count)
across
l_node_types as ic
loop
l_node_typenames.force (ic.item.name)
end
create l_info_to_remove.make (0)
across
a_contents.taxonomy_info as ic
loop
if
attached ic.item.typename as l_typename and then
across l_node_typenames as t_ic some t_ic.item.same_string (l_typename) end
then
if ic.item.entity.is_integer then
nid := ic.item.entity.to_integer_64
if nid > 0 and then attached l_node_api.node (nid) as l_node then
if l_node.link = Void then
l_node.set_link (l_node_api.node_link (l_node))
end
a_contents.force (create {CMS_TAXONOMY_ENTITY}.make (l_node, l_node.modification_date))
l_info_to_remove.force (ic.item)
end
end
end
end
across
l_info_to_remove as ic
loop
a_contents.taxonomy_info.prune_all (ic.item)
end
end
end
export_to (a_export_id_list: detachable ITERABLE [READABLE_STRING_GENERAL]; a_export_parameters: CMS_EXPORT_PARAMETERS; a_response: CMS_RESPONSE)
-- Export data identified by `a_export_id_list',
-- or export all data if `a_export_id_list' is Void.
@@ -375,6 +429,7 @@ feature -- Hooks
loop
l_node_type := types_ic.item
if
a_response.has_permissions (<<"export any node", "export " + l_node_type.name>>) and then
l_node_type.name.same_string_general ("page") and then
( a_export_id_list = Void
or else across a_export_id_list as ic some ic.item.same_string (l_node_type.name) end
@@ -384,17 +439,17 @@ feature -- Hooks
-- For now, handle only page from this node module.
lst := l_node_api.nodes_of_type (l_node_type)
a_export_parameters.log ("Exporting " + lst.count.out + " nodes of type " + l_node_type.name)
p := a_export_parameters.location.extended ("nodes").extended (l_node_type.name)
create d.make_with_path (p)
if not d.exists then
d.recursive_create_dir
end
across
lst as ic
loop
n := l_node_api.full_node (ic.item)
a_export_parameters.log (l_node_type.name + " #" + n.id.out)
p := a_export_parameters.location.extended ("nodes").extended (l_node_type.name).extended (n.id.out)
create d.make_with_path (p.parent)
if not d.exists then
d.recursive_create_dir
end
create f.make_with_path (p)
a_export_parameters.log (l_node_type.name + " #" + n.id.out + " rev=" + n.revision.out)
create f.make_with_path (p.extended (n.id.out).appended_with_extension ("json"))
if not f.exists or else f.is_access_writable then
f.open_write
if attached {CMS_PAGE} n as l_page then
@@ -404,6 +459,30 @@ feature -- Hooks
end
f.close
end
-- Revisions.
if attached l_node_api.node_revisions (n) as l_revisions and then l_revisions.count > 1 then
a_export_parameters.log (l_node_type.name + " " + l_revisions.count.out + " revisions.")
p := a_export_parameters.location.extended ("nodes").extended (l_node_type.name).extended (n.id.out)
create d.make_with_path (p)
if not d.exists then
d.recursive_create_dir
end
across
l_revisions as revs_ic
loop
n := revs_ic.item
create f.make_with_path (p.extended ("rev-" + n.revision.out).appended_with_extension ("json"))
if not f.exists or else f.is_access_writable then
f.open_write
if attached {CMS_PAGE} n as l_page then
f.put_string (json_to_string (page_node_to_json (l_page)))
else
f.put_string (json_to_string (node_to_json (n)))
end
f.close
end
end
end
end
end
end

View File

@@ -10,7 +10,13 @@ deferred class
CMS_NODE
inherit
DEBUG_OUTPUT
CMS_CONTENT
rename
has_identifier as has_id
redefine
debug_output, has_id
end
REFACTORING_HELPER
feature{NONE} -- Initialization
@@ -59,6 +65,12 @@ feature -- Conversion
feature -- Access
identifier: detachable IMMUTABLE_STRING_32
-- Optional identifier.
do
create Result.make_from_string_general (id.out)
end
id: INTEGER_64 assign set_id
-- Unique id.
--| Should we use NATURAL_64 instead?
@@ -67,12 +79,6 @@ feature -- Access
-- Revision value.
--| Note: for now version is not supported.
content_type: READABLE_STRING_8
-- Associated content type name.
-- Page, Article, Blog, News, etc.
deferred
end
feature -- Status reports
status: INTEGER
@@ -113,12 +119,6 @@ feature -- Access
deferred
end
format: detachable READABLE_STRING_8
-- Format associated with `content' and `summary'.
-- For example: text, mediawiki, html, etc
deferred
end
feature -- Access: date
modification_date: DATE_TIME
@@ -155,12 +155,6 @@ feature -- status report
valid_result: Result implies a_node.id = id
end
is_typed_as (a_content_type: READABLE_STRING_GENERAL): BOOLEAN
-- Is current node of type `a_content_type' ?
do
Result := a_content_type.is_case_insensitive_equal (content_type)
end
feature -- Access: menu
link: detachable CMS_LOCAL_LINK
@@ -174,13 +168,7 @@ feature -- Status report
create Result.make_from_string_general ("#")
Result.append_integer_64 (id)
Result.append_character (' ')
Result.append_character ('<')
Result.append_string_general (content_type)
Result.append_character ('>')
Result.append_character (' ')
Result.append_character ('%"')
Result.append (title)
Result.append_character ('%"')
Result.append (Precursor)
end
feature -- Element change

View File

@@ -7,12 +7,12 @@ note
class
CMS_EXPORT_NODE_UTILITIES
inherit
CMS_EXPORT_JSON_UTILITIES
feature -- Access
node_to_json (n: CMS_NODE): JSON_OBJECT
local
jo,j_author: JSON_OBJECT

View File

@@ -1,33 +0,0 @@
note
description: "[
Html builder for content type `content_type'.
This is used to build webform and html output for a specific node, or node content type.
]"
date: "$Date$"
revision: "$Revision$"
deferred class
CMS_CONTENT_TYPE_WEBFORM_MANAGER
inherit
CMS_API_ACCESS
feature {NONE} -- Initialization
make (a_type: like content_type)
do
content_type := a_type
end
feature -- Access
content_type: CMS_CONTENT_TYPE
-- Associated content type.
name: READABLE_STRING_8
-- Associated content type name.
do
Result := content_type.name
end
end

View File

@@ -48,8 +48,8 @@ feature -- Forms ...
if a_node /= Void then
ta.set_text_value (a_node.content)
end
ta.set_label ("Content")
ta.set_description ("This is the main content")
ta.set_label (response.translation ("Content", Void))
ta.set_description (response.translation ("This is the main content", Void))
ta.set_is_required (False)
-- Summary
@@ -61,8 +61,8 @@ feature -- Forms ...
if a_node /= Void then
sum.set_text_value (a_node.summary)
end
sum.set_label ("Summary")
sum.set_description ("Text displayed in short view.")
sum.set_label (response.translation ("Summary", Void))
sum.set_description (response.translation ("Text displayed in short view.", Void))
sum.set_is_required (False)
create fset.make
@@ -92,10 +92,18 @@ feature -- Forms ...
f.extend (fset)
-- Path alias
-- Path alias
populate_form_with_taxonomy (response, f, a_node)
populate_form_with_path_alias (response, f, a_node)
end
populate_form_with_taxonomy (response: CMS_RESPONSE; f: CMS_FORM; a_content: detachable CMS_CONTENT)
do
if attached {CMS_TAXONOMY_API} response.api.module_api ({CMS_TAXONOMY_MODULE}) as l_taxonomy_api then
l_taxonomy_api.populate_edit_form (response, f, content_type.name, a_content)
end
end
populate_form_with_path_alias (response: NODE_RESPONSE; f: CMS_FORM; a_node: detachable CMS_NODE)
local
ti: WSF_FORM_TEXT_INPUT
@@ -179,7 +187,7 @@ feature -- Forms ...
elseif a_node /= Void and then attached a_node.format as s_format and then attached response.api.format (s_format) as f_format then
f := f_format
else
f := response.formats.default_format
f := cms_api.formats.default_format
end
-- Update node with summary and body content
@@ -243,7 +251,7 @@ feature -- Forms ...
elseif a_node /= Void and then attached a_node.format as s_format and then attached response.api.format (s_format) as f_format then
f := f_format
else
f := response.formats.default_format
f := cms_api.formats.default_format
end
-- Update node with summary and content
@@ -255,106 +263,104 @@ feature -- Forms ...
feature -- Output
append_html_output_to (a_node: CMS_NODE; a_response: NODE_RESPONSE)
append_content_as_html_to (a_node: G; is_teaser: BOOLEAN; a_output: STRING; a_response: detachable CMS_RESPONSE)
-- <Precursor>
local
lnk: CMS_LOCAL_LINK
lnk: detachable CMS_LOCAL_LINK
hdate: HTTP_DATE
s: STRING
node_api: CMS_NODE_API
l_node_api: CMS_NODE_API
do
node_api := a_response.node_api
a_response.set_value (a_node, "node")
l_node_api := node_api
-- Show tabs only if a user is authenticated.
if attached a_response.user as l_user then
lnk := a_response.node_local_link (a_node, a_response.translation ("View", Void))
if
not is_teaser and then
a_response /= Void and then
attached a_response.user as l_user
then
lnk := a_node.link
if lnk /= Void then
lnk := a_response.local_link (a_response.translation ("View", Void), lnk.location)
else
lnk := a_response.local_link (a_response.translation ("View", Void), l_node_api.node_path (a_node))
end
lnk.set_weight (1)
a_response.add_to_primary_tabs (lnk)
if a_node.status = {CMS_NODE_API}.trashed then
create lnk.make ("Delete", node_api.node_path (a_node) + "/delete")
create lnk.make ("Delete", l_node_api.node_path (a_node) + "/delete")
lnk.set_weight (2)
a_response.add_to_primary_tabs (lnk)
elseif a_node.has_id then
-- Node in {{CMS_NODE_API}.published} or {CMS_NODE_API}.not_published} status.
create lnk.make ("Edit", node_api.node_path (a_node) + "/edit")
create lnk.make ("Edit", l_node_api.node_path (a_node) + "/edit")
lnk.set_weight (2)
a_response.add_to_primary_tabs (lnk)
if
node_api.has_permission_for_action_on_node ("view revisions", a_node, l_user)
l_node_api.has_permission_for_action_on_node ("view revisions", a_node, l_user)
then
create lnk.make ("Revisions", node_api.node_path (a_node) + "/revision")
create lnk.make ("Revisions", l_node_api.node_path (a_node) + "/revision")
lnk.set_weight (3)
a_response.add_to_primary_tabs (lnk)
end
if
node_api.has_permission_for_action_on_node ("trash", a_node, l_user)
l_node_api.has_permission_for_action_on_node ("trash", a_node, l_user)
then
create lnk.make ("Move to trash", node_api.node_path (a_node) + "/trash")
create lnk.make ("Move to trash", l_node_api.node_path (a_node) + "/trash")
lnk.set_weight (3)
a_response.add_to_primary_tabs (lnk)
end
end
end
create s.make_empty
s.append ("<div class=%"cms-node node-" + a_node.content_type + "%">")
s.append ("<div class=%"info%"> ")
a_output.append ("<div class=%"")
if is_teaser then
a_output.append (" cms-teaser")
end
a_output.append ("cms-node node-" + a_node.content_type + "%">")
a_output.append ("<div class=%"info%"> ")
if attached a_node.author as l_author then
s.append (" by ")
s.append (a_response.html_encoded (l_author.name))
a_output.append (" by ")
a_output.append (l_node_api.html_encoded (l_author.name))
end
if attached a_node.modification_date as l_modified then
s.append (" (modified: ")
a_output.append (" (modified: ")
create hdate.make_from_date_time (l_modified)
s.append (hdate.yyyy_mmm_dd_string)
s.append (")")
a_output.append (hdate.yyyy_mmm_dd_string)
a_output.append (")")
end
s.append ("</div>")
a_output.append ("</div>")
if
a_response /= Void and then
attached {CMS_TAXONOMY_API} cms_api.module_api ({CMS_TAXONOMY_MODULE}) as l_taxonomy_api
then
l_taxonomy_api.append_taxonomy_to_xhtml (a_node, a_response, a_output)
end
-- We don't show the summary on the detail page, since its just a short view of the full content. Otherwise we would write the same thing twice.
-- The usage of the summary is to give a short overview in the list of nodes or for the meta tag "description"
-- if attached a_node.summary as l_summary then
-- s.append ("<p class=%"summary%">")
-- if attached node_api.cms_api.format (a_node.format) as f then
-- append_formatted_output (l_content, f, s)
-- else
-- append_formatted_output (l_content, a_response.formats.default_format, s)
-- end
-- s.append ("</p>")
-- end
if attached a_node.content as l_content then
s.append ("<p class=%"content%">")
if attached node_api.cms_api.format (a_node.format) as f then
append_formatted_output (l_content, f, s)
else
append_formatted_output (l_content, a_response.formats.default_format, s)
if is_teaser then
if attached a_node.summary as l_summary then
a_output.append ("<p class=%"summary%">")
if attached cms_api.format (a_node.format) as f then
append_formatted_content_to (l_summary, f, a_output)
else
append_formatted_content_to (l_summary, cms_api.formats.default_format, a_output)
end
a_output.append ("</p>")
end
s.append ("</p>")
end
s.append ("</div>")
a_response.set_title (a_node.title)
a_response.set_main_content (s)
end
append_formatted_output (a_content: READABLE_STRING_GENERAL; a_format: CONTENT_FORMAT; a_output: STRING_8)
-- Format `a_content' with format `a_format'.
do
if a_content.is_valid_as_string_8 then
a_output.append (a_format.formatted_output (a_content.to_string_8))
else
a_format.append_formatted_to (a_content, a_output)
elseif attached a_node.content as l_content then
a_output.append ("<p class=%"content%">")
if attached cms_api.format (a_node.format) as f then
append_formatted_content_to (l_content, f, a_output)
else
append_formatted_content_to (l_content, cms_api.formats.default_format, a_output)
end
a_output.append ("</p>")
end
a_output.append ("</div>")
end
end

View File

@@ -10,16 +10,35 @@ deferred class
CMS_NODE_TYPE_WEBFORM_MANAGER_I [G -> CMS_NODE]
inherit
CMS_CONTENT_TYPE_WEBFORM_MANAGER
CMS_CONTENT_TYPE_WEBFORM_MANAGER [CMS_NODE]
rename
make as old_make
redefine
content_type
end
feature {NONE} -- Initialization
make (a_type: like content_type; a_node_api: CMS_NODE_API)
do
node_api := a_node_api
old_make (a_type)
end
feature -- Access
content_type: CMS_NODE_TYPE [G]
-- Associated content type.
cms_api: CMS_API
-- API for current instance of CMS.
do
Result := node_api.cms_api
end
node_api: CMS_NODE_API
-- Associated node API.
feature -- Query
has_valid_node_type (a_node: CMS_NODE): BOOLEAN
@@ -57,11 +76,18 @@ feature -- Node ...
feature -- Output
append_html_output_to (a_node: CMS_NODE; a_response: NODE_RESPONSE)
append_content_as_html_to_page (a_node: G; a_response: NODE_RESPONSE)
-- Append an html representation of `a_node' to response `a_response'.
require
has_valid_node_type (a_node)
deferred
local
s: STRING
do
create s.make_empty
a_response.set_value (a_node, "node")
a_response.set_title (a_node.title)
append_content_as_html_to (a_node, False, s, a_response)
a_response.set_main_content (s)
end
end

View File

@@ -10,7 +10,7 @@ inherit
CMS_NODE_TYPE_WEBFORM_MANAGER [CMS_PAGE]
redefine
content_type,
append_html_output_to,
append_content_as_html_to,
populate_form,
new_node,
update_node
@@ -102,27 +102,27 @@ feature -- Forms ...
parent_validation (a_response: NODE_RESPONSE; fd: WSF_FORM_DATA)
local
node_api: CMS_NODE_API
l_node_api: CMS_NODE_API
l_parent_id: INTEGER_64
nid: INTEGER_64
l_parent_node: detachable CMS_NODE
do
node_api := a_response.node_api
l_node_api := node_api
if attached fd.integer_item ("select_parent_node") as s_parent_node then
l_parent_id := s_parent_node.to_integer_64
else
l_parent_id := 0
end
if l_parent_id > 0 then
l_parent_node := node_api.node (l_parent_id)
l_parent_node := l_node_api.node (l_parent_id)
if l_parent_node = Void then
fd.report_invalid_field ("select_parent_node", "Invalid parent, not found id #" + l_parent_id.out)
else
nid := a_response.node_id_path_parameter
if
nid > 0 and then
attached node_api.node (nid) as l_node and then
node_api.is_node_a_parent_of (l_node, l_parent_node)
attached l_node_api.node (nid) as l_node and then
l_node_api.is_node_a_parent_of (l_node, l_parent_node)
then
fd.report_invalid_field ("select_parent_node", "Invalid parent due to cycle (node #" + nid.out + " is already a parent of node #" + l_parent_id.out)
end
@@ -137,50 +137,51 @@ feature -- Forms ...
feature -- Output
append_html_output_to (a_node: CMS_NODE; a_response: NODE_RESPONSE)
append_content_as_html_to (a_node: CMS_PAGE; is_teaser: BOOLEAN; a_output: STRING; a_response: detachable CMS_RESPONSE)
-- <Precursor>
local
s: STRING
node_api: CMS_NODE_API
l_node_api: CMS_NODE_API
lnk: CMS_LOCAL_LINK
do
node_api := a_response.node_api
Precursor (a_node, a_response)
if a_node.has_id and then not a_node.is_trashed then
if node_api.has_permission_for_action_on_node ("create", a_node, a_response.user) then
create lnk.make ("Add Child", "node/add/page?parent=" + a_node.id.out)
lnk.set_weight (3)
a_response.add_to_primary_tabs (lnk)
end
end
if attached a_response.main_content as l_main_content then
s := l_main_content
else
create s.make_empty
end
if attached {CMS_PAGE} a_node as l_node_page then
s.append ("<ul class=%"page-navigation%">")
if attached l_node_page.parent as l_parent_node then
s.append ("<li class=%"page-parent%">Go to parent page ")
s.append (a_response.link (l_parent_node.title, a_response.node_api.node_path (l_parent_node), Void))
s.append ("</li>")
end
if attached node_api.children (a_node) as l_children then
across
l_children as ic
loop
s.append ("<li>")
s.append (a_response.link (ic.item.title, a_response.node_api.node_path (ic.item), Void))
s.append ("</li>")
Precursor (a_node, is_teaser, a_output, a_response)
if not is_teaser then
l_node_api := node_api
if
a_response /= Void and then
a_node.has_id and then not a_node.is_trashed
then
if
l_node_api.has_permission_for_action_on_node ("create", a_node, a_response.user)
then
create lnk.make ("Add Child", "node/add/page?parent=" + a_node.id.out)
lnk.set_weight (3)
a_response.add_to_primary_tabs (lnk)
end
end
s.append ("</ul>")
end
a_response.set_main_content (s)
if
a_response /= Void and then
attached {CMS_PAGE} a_node as l_node_page
then
a_output.append ("<ul class=%"page-navigation%">")
if attached l_node_page.parent as l_parent_node then
a_output.append ("<li class=%"page-parent%">Go to parent page ")
a_output.append (a_response.link (l_parent_node.title, l_node_api.node_path (l_parent_node), Void))
a_output.append ("</li>")
end
if attached l_node_api.children (a_node) as l_children then
across
l_children as ic
loop
a_output.append ("<li>")
a_output.append (a_response.link (ic.item.title, l_node_api.node_path (ic.item), Void))
a_output.append ("</li>")
end
end
a_output.append ("</ul>")
end
end
end
end

View File

@@ -7,30 +7,10 @@ class
inherit
NODE_RESPONSE
redefine
make,
initialize
end
create
make
feature {NONE} -- Initialization
make (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: like api; a_node_api: like node_api)
do
create {WSF_NULL_THEME} wsf_theme.make
Precursor (req, res, a_api, a_node_api)
end
initialize
do
Precursor
create {CMS_TO_WSF_THEME} wsf_theme.make (Current, theme)
end
wsf_theme: WSF_THEME
feature -- Execution
process
@@ -114,10 +94,10 @@ feature {NONE} -- Create a new node
if attached a_type.new_node (Void) as l_node then
-- create new node
f := new_edit_form (l_node, url (location, Void), "edit-" + a_type.name, a_type)
hooks.invoke_form_alter (f, fd, Current)
api.hooks.invoke_form_alter (f, fd, Current)
if request.is_post_request_method then
f.validation_actions.extend (agent edit_form_validate (?, b))
f.submit_actions.extend (agent edit_form_submit (?, l_node, a_type, b))
f.submit_actions.put_front (agent edit_form_submit (?, l_node, a_type, b))
f.process (Current)
fd := f.last_data
end
@@ -144,10 +124,10 @@ feature {NONE} -- Create a new node
fd: detachable WSF_FORM_DATA
do
f := new_edit_form (A_node, url (location, Void), "edit-" + a_type.name, a_type)
hooks.invoke_form_alter (f, fd, Current)
api.hooks.invoke_form_alter (f, fd, Current)
if request.is_post_request_method then
f.validation_actions.extend (agent edit_form_validate (?, b))
f.submit_actions.extend (agent edit_form_submit (?, a_node, a_type, b))
f.submit_actions.put_front (agent edit_form_submit (?, a_node, a_type, b))
f.process (Current)
fd := f.last_data
end
@@ -173,25 +153,29 @@ feature {NONE} -- Create a new node
f: like new_edit_form
fd: detachable WSF_FORM_DATA
do
f := new_delete_form (a_node, url (location, Void), "delete-" + a_type.name, a_type)
hooks.invoke_form_alter (f, fd, Current)
if request.is_post_request_method then
f.process (Current)
fd := f.last_data
end
if a_node.has_id then
add_to_menu (node_local_link (a_node, translation ("View", Void)), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), node_api.node_path (a_node) + "/edit"), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make ("Delete", node_api.node_path (a_node) + "/delete"), primary_tabs)
end
if a_node.is_trashed then
f := new_delete_form (a_node, url (location, Void), "delete-" + a_type.name, a_type)
api.hooks.invoke_form_alter (f, fd, Current)
if request.is_post_request_method then
f.process (Current)
fd := f.last_data
end
if a_node.has_id then
add_to_menu (node_local_link (a_node, translation ("View", Void)), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make (translation ("Edit", Void), node_api.node_path (a_node) + "/edit"), primary_tabs)
add_to_menu (create {CMS_LOCAL_LINK}.make ("Delete", node_api.node_path (a_node) + "/delete"), primary_tabs)
end
if attached redirection as l_location then
-- FIXME: Hack for now
set_title (a_node.title)
b.append (html_encoded (a_type.title) + " deleted")
if attached redirection as l_location then
-- FIXME: Hack for now
set_title (a_node.title)
b.append (html_encoded (a_type.title) + " deleted")
else
set_title (formatted_string (translation ("Delete $1 #$2", Void), [a_type.title, a_node.id]))
f.append_to_html (wsf_theme, b)
end
else
set_title (formatted_string (translation ("Delete $1 #$2", Void), [a_type.title, a_node.id]))
f.append_to_html (wsf_theme, b)
--
end
end
@@ -202,7 +186,7 @@ feature {NONE} -- Create a new node
fd: detachable WSF_FORM_DATA
do
f := new_trash_form (a_node, url (location, Void), "trash-" + a_type.name, a_type)
hooks.invoke_form_alter (f, fd, Current)
api.hooks.invoke_form_alter (f, fd, Current)
if request.is_post_request_method then
f.process (Current)
fd := f.last_data
@@ -294,10 +278,10 @@ feature -- Form
if attached user as u then
api.log ("node",
"User %"" + user_html_link (u) + "%" " + s + " node " + node_html_link (l_node, a_type.name + " #" + l_node.id.out),
0, node_local_link (l_node, Void)
{CMS_LOG}.level_notice, node_local_link (l_node, Void)
)
else
api.log ("node", "Anonymous " + s + " node " + a_type.name +" #" + l_node.id.out, 0, node_local_link (l_node, Void))
api.log ("node", "Anonymous " + s + " node " + a_type.name +" #" + l_node.id.out, {CMS_LOG}.level_notice, node_local_link (l_node, Void))
end
if node_api.has_error then
add_error_message ("Node #" + l_node.id.out + " failed to save.")
@@ -355,6 +339,8 @@ feature -- Form
new_delete_form (a_node: detachable CMS_NODE; a_url: READABLE_STRING_8; a_name: STRING; a_node_type: CMS_NODE_TYPE [CMS_NODE]): CMS_FORM
-- Create a web form named `a_name' for node `a_node' (if set), using form action url `a_url', and for type of node `a_node_type'.
require
is_trashed: attached a_node as l_node and then a_node.is_trashed
local
f: CMS_FORM
ts: WSF_FORM_SUBMIT_INPUT
@@ -375,10 +361,27 @@ feature -- Form
ts.set_default_value (translation ("Delete"))
]")
f.extend (ts)
to_implement ("Refactor code to use the new wsf_html HTML5 support")
f.extend_html_text("<input type='submit' value='Cancel' formmethod='GET', formaction='/node/"+a_node.id.out+"'>" )
create ts.make ("op")
ts.set_default_value ("Cancel")
ts.set_formaction ("/node/"+a_node.id.out)
ts.set_formmethod ("GET")
f.extend (ts)
end
f.extend_html_text ("<br/>")
f.extend_html_text ("<legend>Do you want to restore the current node?</legend>")
if
a_node /= Void and then
a_node.id > 0
then
create ts.make ("op")
ts.set_default_value ("Restore")
ts.set_formaction ("/node/"+a_node.id.out+"/delete")
ts.set_formmethod ("POST")
fixme ("[
ts.set_default_value (translation ("Restore"))
]")
f.extend (ts)
end
Result := f
end
@@ -404,19 +407,6 @@ feature -- Form
]")
f.extend (ts)
end
f.extend_html_text ("<br/>")
f.extend_html_text ("<legend>Do you want to restore the current node?</legend>")
if
a_node /= Void and then
a_node.id > 0
then
create ts.make ("op")
ts.set_default_value ("Restore")
fixme ("[
ts.set_default_value (translation ("Restore"))
]")
f.extend (ts)
end
Result := f
end

View File

@@ -173,6 +173,11 @@ feature -- HTTP Methods
l_op.value.same_string ("Delete")
then
do_delete (req, res)
elseif
attached {WSF_STRING} req.form_parameter ("op") as l_op and then
l_op.value.same_string ("Restore")
then
do_restore (req, res)
end
elseif req.percent_encoded_path_info.ends_with ("/trash") then
if
@@ -180,11 +185,6 @@ feature -- HTTP Methods
l_op.value.same_string ("Trash")
then
do_trash (req, res)
elseif
attached {WSF_STRING} req.form_parameter ("op") as l_op and then
l_op.value.same_string ("Restore")
then
do_restore (req, res)
end
elseif req.percent_encoded_path_info.starts_with ("/node/add/") then
create edit_response.make (req, res, api, node_api)
@@ -242,15 +242,19 @@ feature {NONE} -- Trash:Restore
do_delete (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Delete a node from the database.
local
l_source: STRING
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 node_api.node (l_id.integer_value) as l_node
attached {CMS_NODE} node_api.node (l_id.integer_value) as l_node
then
if node_api.has_permission_for_action_on_node ("delete", l_node, current_user (req)) then
node_api.delete_node (l_node)
l_source := node_api.node_path (l_node)
api.unset_path_alias (l_source, api.location_alias (l_source))
res.send (create {CMS_REDIRECTION_RESPONSE_MESSAGE}.make (req.absolute_script_url ("")))
else
send_access_denied (req, res)

View File

@@ -42,15 +42,6 @@ feature -- Helpers
feature -- Helpers: cms link
user_local_link (u: CMS_USER; a_opt_title: detachable READABLE_STRING_GENERAL): CMS_LOCAL_LINK
do
if a_opt_title /= Void then
create Result.make (a_opt_title, user_url (u))
else
create Result.make (u.name, user_url (u))
end
end
node_local_link (n: CMS_NODE; a_opt_title: detachable READABLE_STRING_GENERAL): CMS_LOCAL_LINK
do
if attached n.link as lnk then
@@ -59,17 +50,12 @@ feature -- Helpers: cms link
Result := node_api.node_link (n)
end
if a_opt_title /= Void and then not Result.title.same_string_general (a_opt_title) then
create Result.make (a_opt_title, Result.location)
Result := local_link (a_opt_title, Result.location)
end
end
feature -- Helpers: html link
user_html_link (u: CMS_USER): like link
do
Result := link (u.name, "user/" + u.id.out, Void)
end
node_html_link (n: CMS_NODE; a_opt_title: detachable READABLE_STRING_GENERAL): like link
local
l_title: detachable READABLE_STRING_GENERAL
@@ -80,18 +66,10 @@ feature -- Helpers: html link
l_title := n.title
end
Result := link (l_title, node_api.node_path (n), Void)
end
feature -- Helpers: URL
user_url (u: CMS_USER): like url
require
u_with_id: u.has_id
do
Result := url ("user/" + u.id.out, Void)
end
node_url (n: CMS_NODE): like url
require
n_with_id: n.has_id

View File

@@ -8,30 +8,10 @@ class
inherit
NODE_RESPONSE
redefine
make,
initialize
end
create
make
feature {NONE} -- Initialization
make (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: like api; a_node_api: like node_api)
do
create {WSF_NULL_THEME} wsf_theme.make
Precursor (req, res, a_api, a_node_api)
end
initialize
do
Precursor
create {CMS_TO_WSF_THEME} wsf_theme.make (Current, theme)
end
wsf_theme: WSF_THEME
feature -- Access
node: detachable CMS_NODE
@@ -71,7 +51,7 @@ feature -- Execution
attached node_api.node_type_for (l_node) as l_content_type and then
attached node_api.node_type_webform_manager (l_content_type) as l_manager
then
l_manager.append_html_output_to (l_node, Current)
l_manager.append_content_as_html_to_page (l_node, Current)
end
elseif revision > 0 then
set_main_content ("Missing revision node!")

View File

@@ -96,7 +96,7 @@ feature -- HTTP Methods
s.append (" <em>(trashed)</em>")
end
debug
if attached node_api.content_type (n.content_type) as ct then
if attached node_api.node_type (n.content_type) as ct then
s.append ("<span class=%"description%">")
s.append (html_encoded (ct.title))
s.append ("</span>")

View File

@@ -14,6 +14,7 @@
<library name="cms" location="..\..\cms-safe.ecf"/>
<library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/>
<library name="cms_recent_changes_module" location="..\..\modules\recent_changes\recent_changes-safe.ecf" readonly="false"/>
<library name="cms_taxonomy_module" location="..\..\modules\taxonomy\taxonomy-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="http_authorization" location="$ISE_LIBRARY\contrib\library\web\authentication\http_authorization\http_authorization-safe.ecf" readonly="false"/>

View File

@@ -14,6 +14,7 @@
<library name="cms" location="..\..\cms.ecf"/>
<library name="cms_model" location="..\..\library\model\cms_model.ecf" readonly="false"/>
<library name="cms_recent_changes_module" location="..\..\modules\recent_changes\recent_changes.ecf" readonly="false"/>
<library name="cms_taxonomy_module" location="..\..\modules\taxonomy\taxonomy.ecf" readonly="false"/>
<library name="error" location="$ISE_LIBRARY\contrib\library\utility\general\error\error.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http.ecf"/>
<library name="http_authorization" location="$ISE_LIBRARY\contrib\library\network\authentication\http_authorization\http_authorization.ecf" readonly="false"/>

View File

@@ -384,6 +384,7 @@ feature -- Change: Node
l_parameters: STRING_TABLE [ANY]
l_time: DATE_TIME
do
sql_begin_transaction
create l_time.make_now_utc
write_information_log (generator + ".delete_node_base {" + a_node.id.out + "}")
@@ -400,6 +401,9 @@ feature -- Change: Node
if not error_handler.has_error then
extended_delete (a_node)
sql_commit_transaction
else
sql_rollback_transaction
end
end
@@ -415,9 +419,9 @@ feature -- Change: Node
error_handler.reset
create l_parameters.make (1)
l_parameters.put (l_time, "changed")
l_parameters.put ({CMS_NODE_API}.not_published, "status")
l_parameters.put ({CMS_NODE_API}.published, "status")
l_parameters.put (a_id, "nid")
sql_modify (sql_restore_node, l_parameters)
sql_modify (sql_update_node_status, l_parameters)
sql_finalize
end
@@ -560,8 +564,8 @@ feature {NONE} -- Queries
sql_delete_node: STRING = "DELETE FROM nodes WHERE nid=:nid"
-- Physical deletion with free metadata.
sql_restore_node: STRING = "UPDATE nodes SET changed=:changed, status =:status WHERE nid=:nid"
-- Restore node to {CMS_NODE_API}.not_publised.
sql_update_node_status: STRING = "UPDATE nodes SET changed=:changed, status =:status WHERE nid=:nid"
-- Restore node to {CMS_NODE_API}.published
sql_last_insert_node_id: STRING = "SELECT MAX(nid) FROM nodes;"
@@ -584,6 +588,7 @@ feature {NONE} -- Queries
sql_delete_node_revisions: STRING = "DELETE FROM node_revisions WHERE nid=:nid;"
feature {NONE} -- Sql Queries: USER_ROLES collaborators, author
Select_user_author: STRING = "SELECT uid, name, password, salt, email, users.status, users.created, signed FROM nodes INNER JOIN users ON nodes.author=users.uid AND nodes.nid = :nid AND nodes.revision = :revision;"

View File

@@ -101,7 +101,7 @@ feature -- Persistence
l_parent_id /= a_node.id and then
attached node_storage.node_by_id (l_parent_id) as l_parent
then
if attached {CMS_PAGE_NODE_TYPE} node_api.content_type (l_parent.content_type) as l_parent_ct then
if attached {CMS_PAGE_NODE_TYPE} node_api.node_type (l_parent.content_type) as l_parent_ct then
ct := l_parent_ct
else
create ct

View File

@@ -72,7 +72,7 @@ feature {CMS_API} -- Module Initialization
Precursor (a_api)
-- Storage initialization
if attached {CMS_STORAGE_SQL_I} a_api.storage as l_storage_sql then
if attached a_api.storage.as_sql_storage as l_storage_sql then
create {CMS_OAUTH_20_STORAGE_SQL} l_user_auth_storage.make (l_storage_sql)
else
-- FIXME: in case of NULL storage, should Current be disabled?
@@ -93,13 +93,13 @@ feature {CMS_API} -- Module management
l_consumers: LIST [STRING]
do
-- Schema
if attached {CMS_STORAGE_SQL_I} api.storage as l_sql_storage then
if attached api.storage.as_sql_storage as l_sql_storage then
if not l_sql_storage.sql_table_exists ("oauth2_consumers") then
--| Schema
l_sql_storage.sql_execute_file_script (api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended ("oauth2_consumers.sql")), Void)
if l_sql_storage.has_error then
api.logger.put_error ("Could not initialize database for blog module", generating_type)
api.logger.put_error ("Could not initialize database for oauth_20 module", generating_type)
end
-- TODO workaround.
l_sql_storage.sql_execute_file_script (api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended ("oauth2_consumers_initialize.sql")), Void)
@@ -108,11 +108,11 @@ feature {CMS_API} -- Module management
-- TODO workaround, until we have an admin module
l_sql_storage.sql_query ("SELECT name FROM oauth2_consumers;", Void)
if l_sql_storage.has_error then
api.logger.put_error ("Could not initialize database for differnent consumerns", generating_type)
api.logger.put_error ("Could not initialize database for differnent consumers", generating_type)
else
from
l_sql_storage.sql_start
create {ARRAYED_LIST[STRING]} l_consumers.make (2)
create {ARRAYED_LIST [STRING]} l_consumers.make (2)
until
l_sql_storage.sql_after
loop
@@ -227,7 +227,10 @@ feature -- Hooks
until
lnk2 /= Void
loop
if ic.item.location.same_string ("account/roc-logout") then
if
ic.item.location.same_string ("account/roc-logout") or else
ic.item.location.same_string ("basic_auth_logoff")
then
lnk2 := ic.item
end
end
@@ -427,7 +430,7 @@ feature -- OAuth2 Login with Provider
l_user: CMS_USER
l_roles: LIST [CMS_USER_ROLE]
l_cookie: WSF_COOKIE
es: CMS_AUTHENTICATON_EMAIL_SERVICE
es: CMS_AUTHENTICATION_EMAIL_SERVICE
do
if attached {WSF_STRING} req.path_parameter ({CMS_OAUTH_20_CONSTANTS}.oauth_callback) as l_callback and then
attached {CMS_OAUTH_20_CONSUMER} a_user_oauth_api.oauth_consumer_by_callback (l_callback.value) as l_consumer and then
@@ -490,7 +493,7 @@ feature -- OAuth2 Login with Provider
-- Send Email
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
write_debug_log (generator + ".handle_callback_oauth: send_contact_welcome_email")
es.send_contact_welcome_email (l_email, "")
es.send_contact_welcome_email (l_email, l_user, req.absolute_script_url (""))
end
end
r.set_redirection (r.front_page_url)

View File

@@ -74,7 +74,7 @@ feature {CMS_API} -- Module Initialization
Precursor (a_api)
-- Storage initialization
if attached {CMS_STORAGE_SQL_I} a_api.storage as l_storage_sql then
if attached a_api.storage.as_sql_storage as l_storage_sql then
create {CMS_OPENID_STORAGE_SQL} l_openid_storage.make (l_storage_sql)
else
-- FIXME: in case of NULL storage, should Current be disabled?
@@ -93,7 +93,7 @@ feature {CMS_API} -- Module management
install (api: CMS_API)
do
-- Schema
if attached {CMS_STORAGE_SQL_I} api.storage as l_sql_storage then
if attached api.storage.as_sql_storage as l_sql_storage then
if not l_sql_storage.sql_table_exists ("openid_consumers") then
--| Schema
l_sql_storage.sql_execute_file_script (api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended ("openid_consumers.sql")), Void)
@@ -203,7 +203,10 @@ feature -- Hooks
until
lnk2 /= Void
loop
if ic.item.location.same_string ("account/roc-logout") then
if
ic.item.location.same_string ("account/roc-logout") or else
ic.item.location.same_string ("basic_auth_logoff")
then
lnk2 := ic.item
end
end
@@ -387,7 +390,7 @@ feature -- Openid Login
l_user: CMS_USER
l_roles: LIST [CMS_USER_ROLE]
l_cookie: WSF_COOKIE
es: CMS_AUTHENTICATON_EMAIL_SERVICE
es: CMS_AUTHENTICATION_EMAIL_SERVICE
b: STRING
o: OPENID_CONSUMER
v: OPENID_CONSUMER_VALIDATION
@@ -440,7 +443,7 @@ feature -- Openid Login
-- Send Email
create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api))
write_debug_log (generator + ".handle_callback_openid: send_contact_welcome_email")
es.send_contact_welcome_email (l_email, "")
es.send_contact_welcome_email (l_email, l_user, req.absolute_script_url (""))
end
end
r.set_redirection (r.front_page_url)

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