Merge branch 'master' into fabian
This commit is contained in:
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
EIFGENs
|
||||||
|
*.swp
|
||||||
|
*.log*
|
||||||
|
*.rc
|
||||||
|
*.bak
|
||||||
|
*.sqlite
|
||||||
|
Thumbs.db
|
||||||
34
README.md
Normal file
34
README.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
Eiffel CMS Library
|
||||||
|
===============
|
||||||
|
|
||||||
|
Eiffel CMS library is build with [EWF](http://eiffelwebframework.github.io/EWF/) and inspired by [Drupal](https://www.drupal.org/).
|
||||||
|
|
||||||
|
The goal of the library is to provide the following features.
|
||||||
|
|
||||||
|
- content type
|
||||||
|
- user management
|
||||||
|
- module design
|
||||||
|
- theme
|
||||||
|
- API
|
||||||
|
|
||||||
|
|
||||||
|
**Directory Structure**
|
||||||
|
|
||||||
|
- library --Library
|
||||||
|
- layout -- application layout library.
|
||||||
|
- model -- domain model library.
|
||||||
|
- persistence -- persistence layer library.
|
||||||
|
- src -- cms source code.
|
||||||
|
- example
|
||||||
|
- demo -- example using the cms library.
|
||||||
|
- doc -- Documentation.
|
||||||
|
|
||||||
|
**Documentation**
|
||||||
|
|
||||||
|
>[CMS concepts](/doc/concepts.md).
|
||||||
|
|
||||||
|
>[CMS design](/doc/design.md).
|
||||||
|
|
||||||
|
>[CMS tutorial](/doc/tutorial.md).
|
||||||
|
|
||||||
37
cms-safe.ecf
Normal file
37
cms-safe.ecf
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?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="cms" uuid="8CC0D052-57D1-4CAA-AFF1-448FA290734B" library_target="cms">
|
||||||
|
<target name="cms">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/CVS$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||||
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<mapping old_name="CMS_LAYOUT" new_name="CMS_ENVIRONMENT"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension-safe.ecf"/>
|
||||||
|
<library name="cms_app_env" location=".\library\app_env\app_env-safe.ecf"/>
|
||||||
|
<library name="cms_config" location=".\library\configuration\config-safe.ecf"/>
|
||||||
|
<library name="cms_model" location=".\library\model\cms_model-safe.ecf" readonly="false"/>
|
||||||
|
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf"/>
|
||||||
|
<library name="encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||||
|
<library name="error" location="$ISE_LIBRARY\contrib\library\utility\general\error\error-safe.ecf"/>
|
||||||
|
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
|
||||||
|
<library name="i18n" location="$ISE_LIBRARY\library\i18n\i18n-safe.ecf"/>
|
||||||
|
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
|
||||||
|
<library name="kmp_matcher" location="$ISE_LIBRARY\library\text\regexp\kmp_matcher\kmp_matcher-safe.ecf"/>
|
||||||
|
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf"/>
|
||||||
|
<library name="notification_mailer" location="$ISE_LIBRARY\contrib\library\runtime\process\notification_email\notification_email-safe.ecf"/>
|
||||||
|
<library name="smarty" location="$ISE_LIBRARY\contrib\library\text\template\smarty\smarty-safe.ecf" readonly="false"/>
|
||||||
|
<library name="text_filter" location="$ISE_LIBRARY\unstable\library\text\text_filter\text_filter-safe.ecf"/>
|
||||||
|
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||||
|
<library name="uri_template" location="$ISE_LIBRARY\contrib\library\text\parser\uri_template\uri_template-safe.ecf"/>
|
||||||
|
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
|
||||||
|
<library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension-safe.ecf" readonly="false"/>
|
||||||
|
<library name="wsf_html" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf_html\wsf_html-safe.ecf" readonly="false"/>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
38
cms.ecf
Normal file
38
cms.ecf
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?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="cms" uuid="8CC0D052-57D1-4CAA-AFF1-448FA290734B" library_target="cms">
|
||||||
|
<description>ROC CMS library</description>
|
||||||
|
<target name="cms">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/CVS$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="false" void_safety="none" syntax="transitional">
|
||||||
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<mapping old_name="CMS_LAYOUT" new_name="CMS_ENVIRONMENT"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension.ecf"/>
|
||||||
|
<library name="cms_app_env" location=".\library\app_env\app_env.ecf"/>
|
||||||
|
<library name="cms_config" location=".\library\configuration\config.ecf"/>
|
||||||
|
<library name="cms_model" location=".\library\model\cms_model.ecf" readonly="false"/>
|
||||||
|
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto.ecf"/>
|
||||||
|
<library name="encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder.ecf" readonly="false"/>
|
||||||
|
<library name="error" location="$ISE_LIBRARY\contrib\library\utility\general\error\error.ecf"/>
|
||||||
|
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http.ecf"/>
|
||||||
|
<library name="i18n" location="$ISE_LIBRARY\library\i18n\i18n.ecf"/>
|
||||||
|
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json.ecf" readonly="false"/>
|
||||||
|
<library name="kmp_matcher" location="$ISE_LIBRARY\library\text\regexp\kmp_matcher\kmp_matcher.ecf"/>
|
||||||
|
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
||||||
|
<library name="notification_mailer" location="$ISE_LIBRARY\contrib\library\runtime\process\notification_email\notification_email.ecf"/>
|
||||||
|
<library name="smarty" location="$ISE_LIBRARY\contrib\library\text\template\smarty\smarty.ecf" readonly="false"/>
|
||||||
|
<library name="text_filter" location="$ISE_LIBRARY\unstable\library\text\text_filter\text_filter.ecf"/>
|
||||||
|
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||||
|
<library name="uri_template" location="$ISE_LIBRARY\contrib\library\text\parser\uri_template\uri_template.ecf"/>
|
||||||
|
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf.ecf"/>
|
||||||
|
<library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension.ecf" readonly="false"/>
|
||||||
|
<library name="wsf_html" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf_html\wsf_html.ecf" readonly="false"/>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
BIN
doc/img_diagram.png
Normal file
BIN
doc/img_diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
396
doc/readme.md
Normal file
396
doc/readme.md
Normal 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.
|
||||||
|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
### 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.)*
|
||||||
121
doc/tutorial.md
Normal file
121
doc/tutorial.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
CMS Tutorial
|
||||||
|
============
|
||||||
|
[Work in progress]
|
||||||
|
|
||||||
|
##### Table of Contents
|
||||||
|
[Getting Started](#init)
|
||||||
|
[Building your module](#module)
|
||||||
|
[Lifecycle](#cycle)
|
||||||
|
|
||||||
|
|
||||||
|
<a name="init"/>
|
||||||
|
Getting Started
|
||||||
|
-------------
|
||||||
|
|
||||||
|
|
||||||
|
<a name="module"/>
|
||||||
|
Building your own module
|
||||||
|
------------------------
|
||||||
|
A [Module](/doc/concepts.md#modules) as we already describe it, enable us to add functionallity based on your needs.
|
||||||
|
|
||||||
|
Here we will describe the basics steps to write your own modules.
|
||||||
|
|
||||||
|
* The first thing to do is inherit from the class [CMS_MODULE] () and redefine the register_hooks (2) feature.
|
||||||
|
* Implement (via inheritance) the needed [Hooks] (/doc/concepts.md#hooks).
|
||||||
|
* Define the module API through route definition. (1)
|
||||||
|
* Define the list of block to be handle by the current module (3).
|
||||||
|
* Render the block (4) (could be defined in Eiffel itself or using a template file (smarty)).
|
||||||
|
* API implementation (5).
|
||||||
|
|
||||||
|
```
|
||||||
|
class MY_NEW_MODULE
|
||||||
|
|
||||||
|
inherit
|
||||||
|
|
||||||
|
CMS_MODULE
|
||||||
|
redefine
|
||||||
|
register_hooks
|
||||||
|
end
|
||||||
|
|
||||||
|
CMS_HOOK_BLOCK
|
||||||
|
|
||||||
|
CMS_HOOK_MENU_SYSTEM_ALTER
|
||||||
|
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make
|
||||||
|
-- Create current module
|
||||||
|
do
|
||||||
|
name := "new module"
|
||||||
|
version := "1.0"
|
||||||
|
description := "Eiffel new module"
|
||||||
|
package := "example"
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access: router
|
||||||
|
|
||||||
|
router (a_api: CMS_API): WSF_ROUTER
|
||||||
|
-- (1) Node router.
|
||||||
|
do
|
||||||
|
create Result.make (1)
|
||||||
|
Result.handle_with_request_methods ("/demo", create {WSF_URI_AGENT_HANDLER}.make (agent handle_demo (a_api, ?, ?)), Result.methods_head_get)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Hooks
|
||||||
|
|
||||||
|
register_hooks (a_response: CMS_RESPONSE)
|
||||||
|
do
|
||||||
|
-- (2)
|
||||||
|
a_response.subscribe_to_menu_system_alter_hook (Current)
|
||||||
|
a_response.subscribe_to_block_hook (Current)
|
||||||
|
end
|
||||||
|
|
||||||
|
block_list: ITERABLE [like {CMS_BLOCK}.name]
|
||||||
|
do
|
||||||
|
-- (3) List of block names, managed by current object.
|
||||||
|
end
|
||||||
|
|
||||||
|
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||||
|
do
|
||||||
|
-- (4) Get block object identified by `a_block_id' and associate with `a_response'.
|
||||||
|
end
|
||||||
|
|
||||||
|
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
|
||||||
|
local
|
||||||
|
lnk: CMS_LOCAL_LINK
|
||||||
|
do
|
||||||
|
create lnk.make ("Demo", "/demo/")
|
||||||
|
a_menu_system.primary_menu.extend (lnk)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Handler
|
||||||
|
|
||||||
|
handle_demo (a_api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE;)
|
||||||
|
local
|
||||||
|
r: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE
|
||||||
|
do
|
||||||
|
-- (5)
|
||||||
|
create r.make (req, res, a_api)
|
||||||
|
r.set_main_content ("NODE module does not yet implement %"" + req.path_info + "%" ...")
|
||||||
|
r.add_error_message ("NODE Module: not yet implemented")
|
||||||
|
r.execute
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="cycle"/>
|
||||||
|
Lifecycle
|
||||||
|
---------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
4
examples/Readme.md
Normal file
4
examples/Readme.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
Examples CMS: examples
|
||||||
|
|
||||||
|
api: API is a simple example showing how to build a custom CMS using EWF.
|
||||||
|
roc_api: api build using a CMS library using modules, themes, etc.
|
||||||
0
examples/demo/Readme.md
Normal file
0
examples/demo/Readme.md
Normal file
84
examples/demo/demo-safe.ecf
Normal file
84
examples/demo/demo-safe.ecf
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<?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">
|
||||||
|
<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>
|
||||||
|
</file_rule>
|
||||||
|
<option debug="true" warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||||
|
<debug name="dbglog" enabled="true"/>
|
||||||
|
</option>
|
||||||
|
<setting name="concurrency" value="thread"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="cms" location="..\..\cms-safe.ecf" readonly="false">
|
||||||
|
<option>
|
||||||
|
<assertions precondition="true" postcondition="true" supplier_precondition="true"/>
|
||||||
|
</option>
|
||||||
|
</library>
|
||||||
|
<library name="cms_admin_module" location="..\..\modules\admin\admin-safe.ecf" readonly="false"/>
|
||||||
|
<library name="cms_app_env" location="..\..\library\app_env\app_env-safe.ecf" readonly="false"/>
|
||||||
|
<library name="cms_auth_module" location="..\..\modules\auth\auth-safe.ecf" readonly="false"/>
|
||||||
|
<library name="cms_basic_auth_module" location="..\..\modules\basic_auth\basic_auth-safe.ecf" readonly="false"/>
|
||||||
|
<library name="cms_blog_module" location="..\..\modules\blog\cms_blog_module-safe.ecf" readonly="false"/>
|
||||||
|
<library name="cms_demo_module" location="modules\demo\cms_demo_module-safe.ecf" readonly="false"/>
|
||||||
|
<library name="cms_email_service" location="..\..\library\email\email-safe.ecf" readonly="false"/>
|
||||||
|
<library name="cms_feed_aggregator_module" location="..\..\modules\feed_aggregator\feed_aggregator-safe.ecf" readonly="false"/>
|
||||||
|
<library name="cms_google_search_module" location="..\..\modules\google_search\google_search-safe.ecf" readonly="false" use_application_options="true"/>
|
||||||
|
<library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/>
|
||||||
|
<library name="cms_node_module" location="..\..\modules\node\node-safe.ecf" readonly="false"/>
|
||||||
|
<library name="cms_taxnomy_module" location="..\..\modules\taxonomy\taxonomy-safe.ecf" readonly="false"/>
|
||||||
|
<library name="cms_oauth_20_module" location="..\..\modules\oauth20\oauth20-safe.ecf" readonly="false"/>
|
||||||
|
<library name="cms_session_auth_module" location="..\..\modules\session_auth\cms_session_auth-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="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_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"/>
|
||||||
|
<library name="wsf_extension" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf_extension-safe.ecf" readonly="false"/>
|
||||||
|
</target>
|
||||||
|
<target name="demo_any" extends="common">
|
||||||
|
<setting name="concurrency" value="thread"/>
|
||||||
|
<library name="any_launcher" location="..\..\launcher\any-safe.ecf" readonly="false"/>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
<target name="demo_standalone" extends="common">
|
||||||
|
<option debug="true">
|
||||||
|
<debug name="dbglog" enabled="true"/>
|
||||||
|
</option>
|
||||||
|
<setting name="concurrency" value="scoop"/>
|
||||||
|
<variable name="httpd_ssl_disabled" value="true"/>
|
||||||
|
<library name="standalone_launcher" location="..\..\launcher\standalone-safe.ecf" readonly="false"/>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
<target name="demo_standalone_none" extends="demo_standalone">
|
||||||
|
<setting name="concurrency" value="none"/>
|
||||||
|
</target>
|
||||||
|
<target name="demo_standalone_mt" extends="demo_standalone">
|
||||||
|
<setting name="concurrency" value="thread"/>
|
||||||
|
</target>
|
||||||
|
<target name="demo_standalone_scoop" extends="demo_standalone">
|
||||||
|
<setting name="concurrency" value="scoop"/>
|
||||||
|
</target>
|
||||||
|
<target name="demo_cgi" extends="common">
|
||||||
|
<setting name="concurrency" value="none"/>
|
||||||
|
<library name="cgi_launcher" location="..\..\launcher\cgi-safe.ecf" readonly="false"/>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
<target name="demo_libfcgi" extends="common">
|
||||||
|
<setting name="concurrency" value="none"/>
|
||||||
|
<library name="libfcgi_launcher" location="..\..\launcher\libfcgi-safe.ecf" readonly="false"/>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
<target name="demo" extends="demo_standalone">
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
2
examples/demo/demo.ini
Normal file
2
examples/demo/demo.ini
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
port=9090
|
||||||
|
#verbose=true
|
||||||
15
examples/demo/install_modules.bat
Normal file
15
examples/demo/install_modules.bat
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
setlocal
|
||||||
|
set ROC_CMD=call %~dp0..\..\tools\roc.bat
|
||||||
|
set ROC_CMS_DIR=%~dp0
|
||||||
|
|
||||||
|
%ROC_CMD% install --module ..\..\modules\admin --dir %ROC_CMS_DIR%
|
||||||
|
%ROC_CMD% install --module ..\..\modules\auth --dir %ROC_CMS_DIR%
|
||||||
|
%ROC_CMD% install --module ..\..\modules\basic_auth --dir %ROC_CMS_DIR%
|
||||||
|
%ROC_CMD% install --module ..\..\modules\blog --dir %ROC_CMS_DIR%
|
||||||
|
%ROC_CMD% install --module ..\..\modules\node --dir %ROC_CMS_DIR%
|
||||||
|
%ROC_CMD% install --module ..\..\modules\oauth20 --dir %ROC_CMS_DIR%
|
||||||
|
%ROC_CMD% install --module ..\..\modules\openid --dir %ROC_CMS_DIR%
|
||||||
|
%ROC_CMD% install --module ..\..\modules\recent_changes --dir %ROC_CMS_DIR%
|
||||||
|
%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%
|
||||||
19
examples/demo/launcher/any/application_launcher.e
Normal file
19
examples/demo/launcher/any/application_launcher.e
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Effective class for APPLICATION_LAUNCHER_I
|
||||||
|
|
||||||
|
You can put modification in this class
|
||||||
|
]"
|
||||||
|
date: "$Date: 2013-06-12 13:55:42 +0200 (mer., 12 juin 2013) $"
|
||||||
|
revision: "$Revision: 36 $"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION_LAUNCHER [G -> WSF_EXECUTION create make end]
|
||||||
|
|
||||||
|
inherit
|
||||||
|
APPLICATION_LAUNCHER_I [G]
|
||||||
|
|
||||||
|
feature -- Custom
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
127
examples/demo/launcher/any/application_launcher_i.e
Normal file
127
examples/demo/launcher/any/application_launcher_i.e
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Specific application launcher
|
||||||
|
|
||||||
|
DO NOT EDIT THIS CLASS
|
||||||
|
|
||||||
|
you can customize APPLICATION_LAUNCHER
|
||||||
|
]"
|
||||||
|
date: "$Date: 2013-06-12 13:55:42 +0200 (mer., 12 juin 2013) $"
|
||||||
|
revision: "$Revision: 36 $"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
APPLICATION_LAUNCHER_I [G -> WSF_EXECUTION create make end]
|
||||||
|
|
||||||
|
inherit
|
||||||
|
SHARED_EXECUTION_ENVIRONMENT
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
nature: like launcher_nature
|
||||||
|
do
|
||||||
|
nature := launcher_nature
|
||||||
|
if nature = Void then
|
||||||
|
launch_standalone (opts)
|
||||||
|
elseif nature = nature_standalone then
|
||||||
|
launch_standalone (opts)
|
||||||
|
elseif nature = nature_nino then
|
||||||
|
launch_nino (opts)
|
||||||
|
elseif nature = nature_cgi then
|
||||||
|
launch_cgi (opts)
|
||||||
|
elseif nature = nature_libfcgi then
|
||||||
|
launch_libfcgi (opts)
|
||||||
|
else
|
||||||
|
-- bye bye
|
||||||
|
(create {EXCEPTIONS}).die (-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Access
|
||||||
|
|
||||||
|
launcher_nature: detachable READABLE_STRING_8
|
||||||
|
-- Initialize the launcher nature
|
||||||
|
-- either cgi, libfcgi, or nino.
|
||||||
|
--| We could extend with more connector if needed.
|
||||||
|
--| and we could use WSF_DEFAULT_SERVICE_LAUNCHER to configure this at compilation time.
|
||||||
|
local
|
||||||
|
p: PATH
|
||||||
|
ext: detachable READABLE_STRING_32
|
||||||
|
do
|
||||||
|
create p.make_from_string (execution_environment.arguments.command_name)
|
||||||
|
if attached p.entry as l_entry then
|
||||||
|
ext := l_entry.extension
|
||||||
|
end
|
||||||
|
if ext /= Void then
|
||||||
|
if ext.same_string (nature_standalone) then
|
||||||
|
Result := nature_standalone
|
||||||
|
end
|
||||||
|
if ext.same_string (nature_nino) then
|
||||||
|
Result := nature_nino
|
||||||
|
end
|
||||||
|
if ext.same_string (nature_cgi) then
|
||||||
|
Result := nature_cgi
|
||||||
|
end
|
||||||
|
if ext.same_string (nature_libfcgi) or else ext.same_string ("fcgi") then
|
||||||
|
Result := nature_libfcgi
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Result := default_nature
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- standalone
|
||||||
|
|
||||||
|
nature_standalone: STRING = "standalone"
|
||||||
|
|
||||||
|
launch_standalone (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
launcher: WSF_STANDALONE_SERVICE_LAUNCHER [G]
|
||||||
|
do
|
||||||
|
create launcher.make_and_launch (opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- nino
|
||||||
|
|
||||||
|
nature_nino: STRING = "nino"
|
||||||
|
|
||||||
|
launch_nino (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
launcher: WSF_NINO_SERVICE_LAUNCHER [G]
|
||||||
|
do
|
||||||
|
create launcher.make_and_launch (opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- cgi
|
||||||
|
|
||||||
|
nature_cgi: STRING = "cgi"
|
||||||
|
|
||||||
|
launch_cgi (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
launcher: WSF_CGI_SERVICE_LAUNCHER [G]
|
||||||
|
do
|
||||||
|
create launcher.make_and_launch (opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- libfcgi
|
||||||
|
|
||||||
|
nature_libfcgi: STRING = "libfcgi"
|
||||||
|
|
||||||
|
launch_libfcgi (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
launcher: WSF_LIBFCGI_SERVICE_LAUNCHER [G]
|
||||||
|
do
|
||||||
|
create launcher.make_and_launch (opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Default
|
||||||
|
|
||||||
|
default_nature: STRING
|
||||||
|
do
|
||||||
|
Result := nature_standalone
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
19
examples/demo/launcher/default/application_launcher.e
Normal file
19
examples/demo/launcher/default/application_launcher.e
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Effective class for APPLICATION_LAUNCHER_I
|
||||||
|
|
||||||
|
You can put modification in this class
|
||||||
|
]"
|
||||||
|
date: "$Date: 2013-06-12 13:55:42 +0200 (mer., 12 juin 2013) $"
|
||||||
|
revision: "$Revision: 36 $"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION_LAUNCHER [G -> WSF_EXECUTION create make end]
|
||||||
|
|
||||||
|
inherit
|
||||||
|
APPLICATION_LAUNCHER_I [G]
|
||||||
|
|
||||||
|
feature -- Custom
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
26
examples/demo/launcher/default/application_launcher_i.e
Normal file
26
examples/demo/launcher/default/application_launcher_i.e
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Specific application launcher
|
||||||
|
|
||||||
|
DO NOT EDIT THIS CLASS
|
||||||
|
|
||||||
|
you can customize APPLICATION_LAUNCHER
|
||||||
|
]"
|
||||||
|
date: "$Date: 2015-02-09 22:29:56 +0100 (lun., 09 févr. 2015) $"
|
||||||
|
revision: "$Revision: 96596 $"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
APPLICATION_LAUNCHER_I [G -> WSF_EXECUTION create make end]
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
launcher: WSF_DEFAULT_SERVICE_LAUNCHER [G]
|
||||||
|
do
|
||||||
|
create launcher.make_and_launch (opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
24
examples/demo/modules/demo/cms_demo_module-safe.ecf
Normal file
24
examples/demo/modules/demo/cms_demo_module-safe.ecf
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="cms_demo_module" uuid="4BB59A54-2544-4C10-BFA6-01D12E541A30" library_target="cms_demo_module">
|
||||||
|
<target name="cms_demo_module">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard">
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension-safe.ecf"/>
|
||||||
|
<library name="cms" location="..\..\..\..\cms-safe.ecf" readonly="false"/>
|
||||||
|
<library name="cms_model" location="..\..\..\..\library\model\cms_model-safe.ecf" readonly="false"/>
|
||||||
|
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
|
||||||
|
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
|
||||||
|
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||||
|
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
|
||||||
|
<library name="wsf_encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder-safe.ecf"/>
|
||||||
|
<cluster name="src" location=".\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
|
|
||||||
163
examples/demo/modules/demo/cms_demo_module.e
Normal file
163
examples/demo/modules/demo/cms_demo_module.e
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {CMS_DEMO_MODULE}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
|
||||||
|
revision: "$Revision: 96616 $"
|
||||||
|
|
||||||
|
class
|
||||||
|
CMS_DEMO_MODULE
|
||||||
|
|
||||||
|
inherit
|
||||||
|
CMS_MODULE
|
||||||
|
redefine
|
||||||
|
setup_hooks,
|
||||||
|
initialize,
|
||||||
|
install
|
||||||
|
end
|
||||||
|
|
||||||
|
CMS_HOOK_MENU_SYSTEM_ALTER
|
||||||
|
|
||||||
|
CMS_HOOK_BLOCK
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make
|
||||||
|
do
|
||||||
|
version := "1.0"
|
||||||
|
description := "Service to demonstrate and test cms system"
|
||||||
|
package := "demo"
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
name: STRING = "demo"
|
||||||
|
|
||||||
|
feature {CMS_API} -- Module Initialization
|
||||||
|
|
||||||
|
initialize (api: CMS_API)
|
||||||
|
-- <Precursor>
|
||||||
|
do
|
||||||
|
Precursor (api)
|
||||||
|
|
||||||
|
-- Add support for CMS_PAGE, which requires a storage extension to store the optional "parent" id.
|
||||||
|
-- For now, we only have extension based on SQL statement.
|
||||||
|
-- if attached {CMS_NODE_STORAGE_SQL} l_node_api.node_storage as l_sql_node_storage then
|
||||||
|
-- l_sql_node_storage.register_node_storage_extension (create {CMS_NODE_STORAGE_SQL_PAGE_EXTENSION}.make (l_sql_node_storage))
|
||||||
|
-- end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {CMS_API} -- Module management
|
||||||
|
|
||||||
|
install (api: CMS_API)
|
||||||
|
local
|
||||||
|
sql: STRING
|
||||||
|
do
|
||||||
|
-- Schema
|
||||||
|
if attached {CMS_STORAGE_SQL_I} api.storage as l_sql_storage then
|
||||||
|
if not l_sql_storage.sql_table_exists ("tb_demo") then
|
||||||
|
sql := "[
|
||||||
|
CREATE TABLE tb_demo(
|
||||||
|
`demo_id` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL CHECK("demo_id">=0),
|
||||||
|
`name` VARCHAR(100) NOT NULL,
|
||||||
|
`value` TEXT
|
||||||
|
);
|
||||||
|
]"
|
||||||
|
l_sql_storage.sql_execute_script (sql, Void)
|
||||||
|
if l_sql_storage.has_error then
|
||||||
|
api.logger.put_error ("Could not initialize database for demo module", generating_type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Precursor {CMS_MODULE}(api)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access: router
|
||||||
|
|
||||||
|
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
|
||||||
|
-- <Precursor>
|
||||||
|
do
|
||||||
|
map_uri_template_agent (a_router, "/demo/", agent handle_demo (?,?,a_api), Void)
|
||||||
|
map_uri_template_agent (a_router, "/demo/{id}", agent handle_demo_entry (?,?,a_api), Void)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Hooks
|
||||||
|
|
||||||
|
setup_hooks (a_hooks: CMS_HOOK_CORE_MANAGER)
|
||||||
|
do
|
||||||
|
a_hooks.subscribe_to_menu_system_alter_hook (Current)
|
||||||
|
a_hooks.subscribe_to_block_hook (Current)
|
||||||
|
end
|
||||||
|
|
||||||
|
block_list: ITERABLE [like {CMS_BLOCK}.name]
|
||||||
|
do
|
||||||
|
Result := <<"?demo-info">>
|
||||||
|
end
|
||||||
|
|
||||||
|
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
|
||||||
|
local
|
||||||
|
-- b: CMS_CONTENT_BLOCK
|
||||||
|
mb: CMS_MENU_BLOCK
|
||||||
|
m: CMS_MENU
|
||||||
|
lnk: CMS_LOCAL_LINK
|
||||||
|
do
|
||||||
|
if a_block_id.same_string ("demo-info") then
|
||||||
|
if a_response.location.starts_with_general ("demo/") then
|
||||||
|
create m.make_with_title (a_block_id, "Demo", 2)
|
||||||
|
create lnk.make ("demo: abc", "demo/abc")
|
||||||
|
m.extend (lnk)
|
||||||
|
create lnk.make ("demo: 123", "demo/123")
|
||||||
|
m.extend (lnk)
|
||||||
|
create mb.make (m)
|
||||||
|
a_response.add_block (mb, "sidebar_second")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
|
||||||
|
local
|
||||||
|
lnk: CMS_LOCAL_LINK
|
||||||
|
-- perms: detachable ARRAYED_LIST [READABLE_STRING_8]
|
||||||
|
do
|
||||||
|
create lnk.make ("Demo", "demo/")
|
||||||
|
a_menu_system.primary_menu.extend (lnk)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Handler
|
||||||
|
|
||||||
|
handle_demo,
|
||||||
|
handle_demo_entry (req: WSF_REQUEST; res: WSF_RESPONSE; a_api: CMS_API)
|
||||||
|
local
|
||||||
|
r: NOT_IMPLEMENTED_ERROR_CMS_RESPONSE
|
||||||
|
do
|
||||||
|
create r.make (req, res, a_api)
|
||||||
|
r.set_main_content ("DEMO module does not yet implement %"" + req.percent_encoded_path_info + "%" ...")
|
||||||
|
r.add_error_message ("DEMO Module: not yet implemented")
|
||||||
|
r.execute
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Mapping helper: uri template
|
||||||
|
|
||||||
|
map_uri_template (a_router: WSF_ROUTER; a_tpl: READABLE_STRING_8; h: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS)
|
||||||
|
-- Map `h' as handler for `a_tpl' for request methods `rqst_methods'.
|
||||||
|
require
|
||||||
|
a_tpl_attached: a_tpl /= Void
|
||||||
|
h_attached: h /= Void
|
||||||
|
do
|
||||||
|
a_router.map (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Mapping helper: uri template agent
|
||||||
|
|
||||||
|
map_uri_template_agent (a_router: WSF_ROUTER; a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS)
|
||||||
|
-- Map `proc' as handler for `a_tpl' for request methods `rqst_methods'.
|
||||||
|
require
|
||||||
|
a_tpl_attached: a_tpl /= Void
|
||||||
|
proc_attached: proc /= Void
|
||||||
|
do
|
||||||
|
map_uri_template (a_router, a_tpl, create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (proc), rqst_methods)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
25
examples/demo/site/config/blocks.ini
Normal file
25
examples/demo/site/config/blocks.ini
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
### Blocks settings
|
||||||
|
|
||||||
|
#navigation.region=sidebar_first
|
||||||
|
#navigation.condition=is_front
|
||||||
|
management.conditions[]=path:admin*
|
||||||
|
management.conditions[]=is_front
|
||||||
|
|
||||||
|
#Feeds
|
||||||
|
feed.news.weight=3
|
||||||
|
feed.news.region=feed_news
|
||||||
|
feed.news.region=content
|
||||||
|
feed.news.condition=is_front
|
||||||
|
|
||||||
|
feed.forum.weight=2
|
||||||
|
feed.forum.region=feed_forum
|
||||||
|
feed.forum.region=content
|
||||||
|
feed.forum.condition=is_front
|
||||||
|
feed.forum.options[size]=5
|
||||||
|
|
||||||
|
#Updates
|
||||||
|
recent_changes.region=content
|
||||||
|
recent_changes.condition=is_front
|
||||||
|
recent_changes.title=Updates
|
||||||
|
recent_changes.options[size]=4
|
||||||
|
|
||||||
30
examples/demo/site/config/cms.ini
Normal file
30
examples/demo/site/config/cms.ini
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
[layout]
|
||||||
|
root-dir=site/www
|
||||||
|
#themes-dir=site/themes
|
||||||
|
#modules-dir=site/modules
|
||||||
|
|
||||||
|
[site]
|
||||||
|
name=Eiffel CMS
|
||||||
|
email=your@email.com
|
||||||
|
theme=bootstrap
|
||||||
|
|
||||||
|
[mailer]
|
||||||
|
#smtp=localhost:25
|
||||||
|
#sendmail=/usr/bin/sendmail
|
||||||
|
output=@stderr
|
||||||
|
|
||||||
|
[modules]
|
||||||
|
# Module status
|
||||||
|
# *=on -> modules are enabled by default
|
||||||
|
# *=off -> modules are disabled by default
|
||||||
|
# Default is "on"
|
||||||
|
# for each module, this can be overwritten with
|
||||||
|
# module_name= on or off
|
||||||
|
*=all
|
||||||
|
|
||||||
|
[blocks]
|
||||||
|
@include=blocks.ini
|
||||||
|
|
||||||
|
[admin]
|
||||||
|
# CMS Installation, are accessible by "all", "none" or uppon "permission". (default is none)
|
||||||
|
installation_access=all
|
||||||
44
examples/demo/site/config/demo.json
Normal file
44
examples/demo/site/config/demo.json
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"database": {
|
||||||
|
"datasource": {
|
||||||
|
"driver": "sqlite3",
|
||||||
|
"environment": "sqlite3",
|
||||||
|
"-driver": "odbc",
|
||||||
|
"-environment": "odbc-sqlite"
|
||||||
|
},
|
||||||
|
"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;"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"connection_string":"Server=localhost;Port=3306;Database=cms_dev;Uid=root;Pwd=;"
|
||||||
|
},
|
||||||
|
"production": {
|
||||||
|
"connection_string":""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"smtp": {
|
||||||
|
"server": "localhost"
|
||||||
|
},
|
||||||
|
"logger": {
|
||||||
|
"level":"error",
|
||||||
|
"type":"stderr",
|
||||||
|
"backup_count":"4"
|
||||||
|
},
|
||||||
|
"server": {
|
||||||
|
"mode":"html"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BIN
examples/demo/site/database.sqlite3
Normal file
BIN
examples/demo/site/database.sqlite3
Normal file
Binary file not shown.
@@ -0,0 +1,79 @@
|
|||||||
|
<!-- Updated: 12/04/2015 12:30:04.000 AM --><div class="feed">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 08</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/-jtyp4iengE">Re: [eiffel-users] Precompile on Linux</a>
|
||||||
|
<div class="description">Hi, I just check if the .ecf files are in /usr/share/eiffelstudio-MM.mm/precomp/spec/unix and they are. When I look in the "Locations of configuration files" dialog in EiffelStudio, I see this: # Search paths for precompiled libraries are specified in the configuration file: # /usr/share/ei</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 08</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/-jtyp4iengE">RE: [eiffel-users] Precompile on Linux</a>
|
||||||
|
<div class="description">This is a bug in the Unix layout then. Do you mind submitting a problem report? Thanks, Manu *From:* eiffel...@googlegroups.com [mailto:eiffel...@googlegroups.com] *On Behalf Of *Louis *Sent:* Tuesday, December 08, 2015 23:02 *To:* eiffel...@googlegroups.com *Subject:* Re: [eiffel-users]</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 08</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/ddSxnBrvhUg">Re: [eiffel-users] Re: Version of EiffelBase2 shipped with different EiffelStudio versions</a>
|
||||||
|
<div class="description">Not really. What I need to know is when I run tests on the performance and suitability for use of EiffelBase2, do I have to repeat them with all of ES versions 15.01, 15.08 and 15.11? On 8 December 2015 at 13:52, Jocelyn Fiat <jf...@eiffelsolution.com> wrote: > As the author of EiffelBase2 does</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 08</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/ddSxnBrvhUg">RE: [eiffel-users] Re: Version of EiffelBase2 shipped with different EiffelStudio versions</a>
|
||||||
|
<div class="description">In this particular case, it is sufficient to take any version of EiffelStudio and the EiffelBase2 version that comes with it to evaluate EiffelBase2 as the library has not really changed much in the past few years. In the general case, you should stick to one version of EiffelStudio and</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 08</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/ddSxnBrvhUg">Re: [eiffel-users] Re: Version of EiffelBase2 shipped with different EiffelStudio versions</a>
|
||||||
|
<div class="description">But this doesn't answer my question. Which version of EiffelBase2 ships with which version of EiffelStudio? On 8 December 2015 at 13:05, Jocelyn Fiat <jf...@eiffel.com> wrote: > Hi all, > > Usually the version uploaded to iron server comes from the associated > branch > for instance > > - 15.01</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 08</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/ddSxnBrvhUg">Re: [eiffel-users] Re: Version of EiffelBase2 shipped with different EiffelStudio versions</a>
|
||||||
|
<div class="description">Hi all, Usually the version uploaded to iron server comes from the associated branch for instance - 15.01 has almost same content as https://svn.eiffel.com/eiffelstudio/branches/Eiffel_15.01/ - ... I said "almost" because, the ecf are modified to use iron references rather than $ISE_LIBRARY/...</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 08</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/ddSxnBrvhUg">Re: [eiffel-users] Re: Version of EiffelBase2 shipped with different EiffelStudio versions</a>
|
||||||
|
<div class="description">As the author of EiffelBase2 does not define any specific versions, I would say - EiffelStudio 14.05 ships EiffelBase2 version 14.05, and associated source code can be found at https://svn.eiffel.com/eiffelstudio/branches/Eiffel_14.05/Src/unstable/library/base2/ (last changed revision: 94979)</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 08</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/-jtyp4iengE">RE: [eiffel-users] Precompile on Linux</a>
|
||||||
|
<div class="description">We currently only ship precompiled libraries for EiffelBase, WEL on Windows and EiffelVision2. The configuration files for those precompiled library are in a read-only folder of the EiffelStudio installation. The first time EiffelStudio tries to access $ISE_PRECOMP (which if not set resolves to</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 08</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/ddSxnBrvhUg">Re: [eiffel-users] Re: Version of EiffelBase2 shipped with different EiffelStudio versions</a>
|
||||||
|
<div class="description">Come on - someone must know - the person who loaded it to iron, e.g. On 7 December 2015 at 12:03, Colin Adams <colinpa...@gmail.com> wrote: > I know what EiffelBase2 is. I was asking about the version in the iron > repository for each version of EiffelStudio. > > On 7 December 2015 at 11:59,</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 08</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/Vwsw67vq6ss">Re: Explaining high-level programming</a>
|
||||||
|
<div class="description">A very interesting article Ian. I learned more by reading it. However, the title leads me to ask: Who (precisely) is the target audience to whom the plea is being made? From my point of view, I cannot see this audience, so I am asking for your view to help me identify the audience. Thanks,</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 08</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/Vwsw67vq6ss">Explaining high-level programming</a>
|
||||||
|
<div class="description">On 4 Dec 2015, at 00:24, Bertrand Meyer <Bertran...@inf.ethz.ch> wrote: 3. The community should help spread Eiffel. The last point is particularly important. The user community needs to grow; if it moves up to the next level then we at Eiffel Software will be able to perform many more</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 08</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/-jtyp4iengE">Precompile on Linux</a>
|
||||||
|
<div class="description">Recently I installed EiffelStudio 15.08 on my Xubuntu laptop, with an assist from Louis M who showed me how to install it using apt-get. In the past, after extracting everything in the .tar.bz archive, I would run the supplied precompile script to produce the precompiled libraries I needed. The</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 07</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/4BS09rbY6UY">RE: [eiffel-users] Maximum capacity of a TUPLE</a>
|
||||||
|
<div class="description">If you are looking at TUPLE with more than 20 entries, I think I would consider using LIST or ARRAY for storing data. The issue is not so much on the TUPLE capacity (which has the same limit as a SPECIAL object) but on the number of class types any type declaration. This is a limit for all</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 07</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/YgyWglEEN3A">Re: [eiffel-users] Does {MEMORY}.collection_off reset the progress of the garbage collector?</a>
|
||||||
|
<div class="description">Thanks, that was what I was looking for.</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="date"> Dec 07</div>
|
||||||
|
<a href="https://groups.google.com/d/topic/eiffel-users/4BS09rbY6UY">Maximum capacity of a TUPLE</a>
|
||||||
|
<div class="description">The header comment to {TUPLE}.plus says the result can be Void if the result exceeds the capacity of a TUPLE. What is this maximum capacity? (without knowing it is is impossible to prove the result of such a concatenation will be attached).</div>
|
||||||
|
</li>
|
||||||
|
<liv class="nav"><a href="/feed_aggregation/forum">See more ...</a></li>
|
||||||
|
</ul>
|
||||||
34
examples/demo/site/modules/admin/files/css/admin.css
Normal file
34
examples/demo/site/modules/admin/files/css/admin.css
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
ul.cms-users {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 3px 3px 3px 3px;
|
||||||
|
border: solid 1px #ccc; }
|
||||||
|
ul.cms-users li {
|
||||||
|
border-top: dotted 1px #ccc; }
|
||||||
|
ul.cms-users li:first-child {
|
||||||
|
border-top: none; }
|
||||||
|
ul.cms-users li.cms_user a::before {
|
||||||
|
content: "[users] "; }
|
||||||
|
|
||||||
|
ul.cms-roles {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 3px 3px 3px 3px;
|
||||||
|
border: solid 1px #ccc; }
|
||||||
|
ul.cms-roles li {
|
||||||
|
border-top: dotted 1px #ccc; }
|
||||||
|
ul.cms-roles li:first-child {
|
||||||
|
border-top: none; }
|
||||||
|
ul.cms-roles li.cms_role a::before {
|
||||||
|
content: "[roles] "; }
|
||||||
|
|
||||||
|
ul.cms-permissions {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 3px 3px 3px 3px;
|
||||||
|
border: solid 1px #ccc; }
|
||||||
|
ul.cms-permissions li {
|
||||||
|
border-top: dotted 1px #ccc; }
|
||||||
|
ul.cms-permissions li:first-child {
|
||||||
|
border-top: none; }
|
||||||
|
ul.cms-permissions li.cms_permission a::before {
|
||||||
|
content: "[permission] "; }
|
||||||
|
|
||||||
|
/*# sourceMappingURL=admin.css.map */
|
||||||
59
examples/demo/site/modules/admin/files/scss/admin.scss
Normal file
59
examples/demo/site/modules/admin/files/scss/admin.scss
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
ul.cms-users {
|
||||||
|
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 3px 3px 3px 3px;
|
||||||
|
border: solid 1px #ccc;
|
||||||
|
|
||||||
|
li{
|
||||||
|
border-top: dotted 1px #ccc;
|
||||||
|
&:first-child {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li.cms_user a::before {
|
||||||
|
content: "[users] ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ul.cms-roles {
|
||||||
|
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 3px 3px 3px 3px;
|
||||||
|
border: solid 1px #ccc;
|
||||||
|
|
||||||
|
li{
|
||||||
|
border-top: dotted 1px #ccc;
|
||||||
|
&:first-child {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li.cms_role a::before {
|
||||||
|
content: "[roles] ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ul.cms-permissions {
|
||||||
|
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 3px 3px 3px 3px;
|
||||||
|
border: solid 1px #ccc;
|
||||||
|
|
||||||
|
li{
|
||||||
|
border-top: dotted 1px #ccc;
|
||||||
|
&:first-child {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li.cms_permission a::before {
|
||||||
|
content: "[permission] ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
8
examples/demo/site/modules/auth/auth.json
Normal file
8
examples/demo/site/modules/auth/auth.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"email": "webmaster@example.com",
|
||||||
|
"subjet_register": "Thank you for regitering with us, activate account",
|
||||||
|
"subjet_activate": "New account ativation token",
|
||||||
|
"subjet_password": "Password Recovery!!!",
|
||||||
|
"subjet_oauth": "Welcome",
|
||||||
|
"smtp": "127.0.0.1"
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Activation</title>
|
||||||
|
<meta name="description" content="Activation">
|
||||||
|
<meta name="author" content="ROC CMS">
|
||||||
|
</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>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>New Password</title>
|
||||||
|
<meta name="description" content="New Password">
|
||||||
|
<meta name="author" content="ROC CMS">
|
||||||
|
</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>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>New Activation</title>
|
||||||
|
<meta name="description" content="New Activation token">
|
||||||
|
<meta name="author" content="ROC CMS">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<p>You have request a new activation token at <a href="$host">ROC CMS</a></p>
|
||||||
|
|
||||||
|
<p>To complete your registration, please click on this link to activate your account:<p>
|
||||||
|
|
||||||
|
<p><a href="$link">$link</a></p>
|
||||||
|
<p>Thank you for joining us.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Welcome</title>
|
||||||
|
<meta name="description" content="Welcome">
|
||||||
|
<meta name="author" content="ROC CMS">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Welcome to<a href="$host">ROC CMS</a></p>
|
||||||
|
<p>Thank you for joining us.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<div class="primary-tabs">
|
||||||
|
{if isset="$user"}
|
||||||
|
<h3>Account Information</h3>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<label>Username:</label> {$user.name/}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Email:</label> {$user.email/}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Creation Date:</label> {$user.creation_date/}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Last login:</label> {$user.last_login_date/}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<form method="get" action="{$site_url/}{$auth_login_strategy/}">
|
||||||
|
<button type="submit">Logout</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
{include file="block_change_password.tpl" /}
|
||||||
|
<hr>
|
||||||
|
<h4>Roles</h4>
|
||||||
|
<div>
|
||||||
|
{foreach item="ic" from="$roles"}
|
||||||
|
<div>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<strong>{$ic.name/}</strong>
|
||||||
|
<ul>
|
||||||
|
<li> <i>permissions</i>
|
||||||
|
<ul>
|
||||||
|
{foreach item="ip" from="$ic.permissions"}
|
||||||
|
<li>{$ip/}</li>
|
||||||
|
{/foreach}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{/foreach}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h4>Profile</h4>
|
||||||
|
<div>
|
||||||
|
{foreach item="the_value" key="the_name" from="$user.profile"}
|
||||||
|
<div>
|
||||||
|
<label>{$the_name/}:</label> {$the_value/}
|
||||||
|
</div>
|
||||||
|
{/foreach}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{unless isset="$user"}
|
||||||
|
<div>
|
||||||
|
<p> You are not logged in </p>
|
||||||
|
<a href="{$site_url/}account/roc-login">Go to the login page</a>
|
||||||
|
</div>
|
||||||
|
{/unless}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<div>
|
||||||
|
<form action="{$site_url/}account/change-password" method="post">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Change Password Form</legend>
|
||||||
|
<div>
|
||||||
|
<input type="password" id="password" name="password" value="" required/>
|
||||||
|
<label for="password">Password</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input type="password" id="confirm_password" name="confirm_password" value="" required/>
|
||||||
|
<label for="password">Confirm Password</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit">Confirm</button>
|
||||||
|
{if isset="$error_password"}
|
||||||
|
<span><i>{$error_password/}</i></span> <br>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
29
examples/demo/site/modules/auth/templates/block_login.tpl
Normal file
29
examples/demo/site/modules/auth/templates/block_login.tpl
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<div class="primary-tabs">
|
||||||
|
{unless isset="$user"}
|
||||||
|
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<form action method="POST">
|
||||||
|
<div>
|
||||||
|
<input type="text" name="username" required>
|
||||||
|
<label>Username</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input type="password" name="password" required>
|
||||||
|
<label>Password</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="button" onclick="ROC_AUTH.login();">Login</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
<a href="{$site_url/}account/new-password">Forgot password?</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/unless}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<div>
|
||||||
|
<form action="{$site_url/}account/new-password" method="post">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Request new password by email</legend>
|
||||||
|
<div>
|
||||||
|
<input type="email" id="email" name="email" value="{$email/}" required/>
|
||||||
|
<label for="email">Email</label>
|
||||||
|
{if isset="$error_email"}
|
||||||
|
<span><i>{$error_email/}</i></span> <br>
|
||||||
|
{/if}
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<button type="submit">Send</button>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
<hr>
|
||||||
|
<form action="{$site_url/}account/new-password" method="post">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Request new password by username</legend>
|
||||||
|
<div>
|
||||||
|
<input type="text" id="username" name="username" value="{$username/}" required/>
|
||||||
|
<label for="username">Username</label>
|
||||||
|
{if isset="$error_username"}
|
||||||
|
<span><i>{$error_username/}</i></span> <br>
|
||||||
|
{/if}
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<button type="submit">Send</button>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<div>
|
||||||
|
<p>You new password has been saved!, Login again</p>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<div>
|
||||||
|
<p>We have send you a new token code, check your email to generate a new password</p>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<div>
|
||||||
|
<p>We have send you a new activation code, check your email to activate your account.</p>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<div>
|
||||||
|
<p>Thanks for register, check your email to activate your account.</p>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<div>
|
||||||
|
<p>You new password has been saved!</p>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<div>
|
||||||
|
<form action="{$site_url/}account/reactivate" method="post">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Reactivate Form</legend>
|
||||||
|
<div>
|
||||||
|
<input type="email" id="email" name="email" value="{$email/}" required/>
|
||||||
|
<label for="email">Email</label>
|
||||||
|
{if isset="$error_email"}
|
||||||
|
<span><i>{$error_email/}</i></span> <br>
|
||||||
|
{/if}
|
||||||
|
<br>
|
||||||
|
{if isset="$is_active"}
|
||||||
|
<span><i>{$is_active/}</i></span> <br>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<button type="submit">Reactivate</button>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
28
examples/demo/site/modules/auth/templates/block_register.tpl
Normal file
28
examples/demo/site/modules/auth/templates/block_register.tpl
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<div>
|
||||||
|
<form action="{$site_url/}account/roc-register" method="post">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Register Form</legend>
|
||||||
|
<div>
|
||||||
|
<input type="text" id="name" name="name" value="{$name/}" required autofocus />
|
||||||
|
<label for="name">Name</label>
|
||||||
|
{if isset="$error_name"}
|
||||||
|
<span><i>{$error_name/}</i></span> <br>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input type="password" id="password" name="password" value="" required/>
|
||||||
|
<label for="password">Password</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input type="email" id="email" name="email" value="{$email/}" required/>
|
||||||
|
<label for="email">Email</label>
|
||||||
|
{if isset="$error_email"}
|
||||||
|
<span><i>{$error_email/}</i></span> <br>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<button type="submit">Register</button>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<div>
|
||||||
|
<form action="{$site_url/}account/reset-password" method="post">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Generate New Password Form</legend>
|
||||||
|
<div>
|
||||||
|
<input type="text" id="token" name="token" value="{$token/}" required />
|
||||||
|
<label for="token">Token</label>
|
||||||
|
{if isset="$error_token"}
|
||||||
|
<span><i>{$error_token/}</i></span> <br>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input type="password" id="password" name="password" value="" required/>
|
||||||
|
<label for="password">Password</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input type="password" id="confirm_password" name="confirm_password" value="" required/>
|
||||||
|
<label for="password">Confirm Password</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit">Confirm</button>
|
||||||
|
{if isset="$error_password"}
|
||||||
|
<span><i>{$error_password/}</i></span> <br>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
325
examples/demo/site/modules/basic_auth/files/js/roc_basic_auth.js
Normal file
325
examples/demo/site/modules/basic_auth/files/js/roc_basic_auth.js
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
var ROC_AUTH = ROC_AUTH || { };
|
||||||
|
|
||||||
|
var loginURL = "/basic_auth_login";
|
||||||
|
var logoutURL = "/basic_auth_logoff";
|
||||||
|
|
||||||
|
var userAgent = navigator.userAgent.toLowerCase();
|
||||||
|
var firstLogIn = true;
|
||||||
|
|
||||||
|
ROC_AUTH.login = function() {
|
||||||
|
var form = document.forms['cms_basic_auth'];
|
||||||
|
var username = form.username.value;
|
||||||
|
var password = form.password.value;
|
||||||
|
//var host = form.host.value;
|
||||||
|
var origin = window.location.origin + window.location.pathname;
|
||||||
|
var _login = function(){
|
||||||
|
|
||||||
|
|
||||||
|
if (document.getElementById('myModalFormId') !== null ) {
|
||||||
|
ROC_AUTH.remove ('myModalFormId');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (username === "" || password === "") {
|
||||||
|
if (document.getElementById('myModalFormId') === null ) {
|
||||||
|
var newdiv = document.createElement('div');
|
||||||
|
newdiv.innerHTML = "<br>Invalid Credentials</br>";
|
||||||
|
newdiv.id = 'myModalFormId';
|
||||||
|
$(".primary-tabs").append(newdiv);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
|
||||||
|
//Instantiate HTTP Request
|
||||||
|
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
|
||||||
|
request.open("GET", loginURL, true, username, password);
|
||||||
|
request.send(null);
|
||||||
|
|
||||||
|
//Process Response
|
||||||
|
request.onreadystatechange = function(){
|
||||||
|
if (request.readyState == 4) {
|
||||||
|
if (request.status==200) {
|
||||||
|
delete form;
|
||||||
|
window.location=window.location.origin;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.getElementById('myModalFormId') === null ) {
|
||||||
|
var newdiv = document.createElement('div');
|
||||||
|
newdiv.innerHTML = "<br>Invalid Credentials</br>";
|
||||||
|
newdiv.id = 'myModalFormId';
|
||||||
|
$(".primary-tabs").append(newdiv);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var userAgent = navigator.userAgent.toLowerCase();
|
||||||
|
if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
|
||||||
|
if (firstLogIn) _login();
|
||||||
|
else logoff(_login);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
_login();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstLogIn) firstLogIn = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ROC_AUTH.login_with_redirect = function() {
|
||||||
|
var form = document.forms[2];
|
||||||
|
var username = form.username.value;
|
||||||
|
var password = form.password.value;
|
||||||
|
var host = form.host.value;
|
||||||
|
var _login = function(){
|
||||||
|
|
||||||
|
var redirectURL = form.redirect && form.redirect.value || "";
|
||||||
|
|
||||||
|
|
||||||
|
$("#imgProgressRedirect").show();
|
||||||
|
|
||||||
|
if (document.getElementById('myModalFormId') !== null ) {
|
||||||
|
ROC_AUTH.remove ('myModalFormId');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (username === "" || password === "") {
|
||||||
|
if (document.getElementById('myModalFormId') === null ) {
|
||||||
|
var newdiv = document.createElement('div');
|
||||||
|
newdiv.innerHTML = "<br>Invalid Credentials</br>";
|
||||||
|
newdiv.id = 'myModalFormId';
|
||||||
|
$(".primary-tabs").append(newdiv);
|
||||||
|
$("#imgProgressRedirect").hide();
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
|
||||||
|
//Instantiate HTTP Request
|
||||||
|
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
|
||||||
|
request.open("GET", host.concat(loginURL), true, username, password);
|
||||||
|
request.send(null);
|
||||||
|
|
||||||
|
//Process Response
|
||||||
|
request.onreadystatechange = function(){
|
||||||
|
if (request.readyState == 4) {
|
||||||
|
if (request.status==200) {
|
||||||
|
if (redirectURL === "") {
|
||||||
|
window.location=host.concat("/");
|
||||||
|
} else {
|
||||||
|
window.location=host.concat(redirectURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.getElementById('myModalFormId') === null ) {
|
||||||
|
var newdiv = document.createElement('div');
|
||||||
|
newdiv.innerHTML = "<br>Invalid Credentials</br>";
|
||||||
|
newdiv.id = 'myModalFormId';
|
||||||
|
$(".primary-tabs").append(newdiv);
|
||||||
|
$("#imgProgressRedirect").hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var userAgent = navigator.userAgent.toLowerCase();
|
||||||
|
if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
|
||||||
|
if (firstLogIn) _login();
|
||||||
|
else logoff(_login);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
_login();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstLogIn) firstLogIn = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ROC_AUTH.getQueryParameterByName = function (name) {
|
||||||
|
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
||||||
|
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
|
||||||
|
results = regex.exec(location.search);
|
||||||
|
return results === null ? " " : decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||||
|
}
|
||||||
|
|
||||||
|
ROC_AUTH.logoff = function(callback){
|
||||||
|
var form = document.forms[0];
|
||||||
|
var host = form.host.value;
|
||||||
|
|
||||||
|
if (userAgent.indexOf("msie") != -1) {
|
||||||
|
document.execCommand("ClearAuthenticationCache");
|
||||||
|
}
|
||||||
|
else if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
|
||||||
|
|
||||||
|
var request1 = new XMLHttpRequest();
|
||||||
|
var request2 = new XMLHttpRequest();
|
||||||
|
|
||||||
|
//Logout. Tell the server not to return the "WWW-Authenticate" header
|
||||||
|
request1.open("GET", host.concat(logoutURL) + "?prompt=false", true);
|
||||||
|
request1.send("");
|
||||||
|
request1.onreadystatechange = function(){
|
||||||
|
if (request1.readyState == 4) {
|
||||||
|
|
||||||
|
//Sign in with dummy credentials to clear the auth cache
|
||||||
|
request2.open("GET", host.concat(logoutURL), true, "logout", "logout");
|
||||||
|
request2.send("");
|
||||||
|
|
||||||
|
request2.onreadystatechange = function(){
|
||||||
|
if (request2.readyState == 4) {
|
||||||
|
if (callback!=null) { callback.call(); } else { window.location=host.concat(logoutURL);}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
|
||||||
|
request.open("GET", host.concat(logoutURL), true, "logout", "logout");
|
||||||
|
request.send("");
|
||||||
|
request.onreadystatechange = function(){
|
||||||
|
if (request.status==401 || request.status==403 ) { window.location=host.concat(logoutURL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ROC_AUTH.remove = function (id)
|
||||||
|
{
|
||||||
|
var element = document.getElementById(id);
|
||||||
|
element.outerHTML = "";
|
||||||
|
delete element;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
if (typeof String.prototype.contains != 'function') {
|
||||||
|
String.prototype.contains = function (str){
|
||||||
|
return this.indexOf(str) != -1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
ROC_AUTH.progressive_loging();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
ROC_AUTH.progressive_loging = function () {
|
||||||
|
|
||||||
|
ROC_AUTH.login_href();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
$(document).keypress(function(e) {
|
||||||
|
if ((e.which === 13) && (e.target.localName === 'input' && e.target.id === 'password')) {
|
||||||
|
ROC_AUTH.login();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ROC_AUTH.OnOneClick = function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
if ( document.forms[0] === undefined ) {
|
||||||
|
ROC_AUTH.create_form();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
ROC_AUTH.login_href = function() {
|
||||||
|
var els = document.getElementsByTagName("a");
|
||||||
|
for (var i = 0, l = els.length; i < l; i++) {
|
||||||
|
var el = els[i];
|
||||||
|
if (el.href.contains("/basic_auth_login?destination")) {
|
||||||
|
loginURL = el.href;
|
||||||
|
var OneClick = el;
|
||||||
|
OneClick.addEventListener('click', ROC_AUTH.OnOneClick, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ROC_AUTH.create_form = function() {
|
||||||
|
|
||||||
|
// Fetching HTML Elements in Variables by ID.
|
||||||
|
var createform = document.createElement('form'); // Create New Element Form
|
||||||
|
createform.setAttribute("action", ""); // Setting Action Attribute on Form
|
||||||
|
createform.setAttribute("method", "post"); // Setting Method Attribute on Form
|
||||||
|
$("body").append(createform);
|
||||||
|
|
||||||
|
var heading = document.createElement('h2'); // Heading of Form
|
||||||
|
heading.innerHTML = "Login Form ";
|
||||||
|
createform.appendChild(heading);
|
||||||
|
|
||||||
|
var line = document.createElement('hr'); // Giving Horizontal Row After Heading
|
||||||
|
createform.appendChild(line);
|
||||||
|
|
||||||
|
var linebreak = document.createElement('br');
|
||||||
|
createform.appendChild(linebreak);
|
||||||
|
|
||||||
|
var namelabel = document.createElement('label'); // Create Label for Name Field
|
||||||
|
namelabel.innerHTML = "Username : "; // Set Field Labels
|
||||||
|
createform.appendChild(namelabel);
|
||||||
|
|
||||||
|
var inputelement = document.createElement('input'); // Create Input Field for UserName
|
||||||
|
inputelement.setAttribute("type", "text");
|
||||||
|
inputelement.setAttribute("name", "username");
|
||||||
|
inputelement.setAttribute("required","required");
|
||||||
|
createform.appendChild(inputelement);
|
||||||
|
|
||||||
|
var linebreak = document.createElement('br');
|
||||||
|
createform.appendChild(linebreak);
|
||||||
|
|
||||||
|
var passwordlabel = document.createElement('label'); // Create Label for Password Field
|
||||||
|
passwordlabel.innerHTML = "Password : ";
|
||||||
|
createform.appendChild(passwordlabel);
|
||||||
|
|
||||||
|
var passwordelement = document.createElement('input'); // Create Input Field for Password.
|
||||||
|
passwordelement.setAttribute("type", "password");
|
||||||
|
passwordelement.setAttribute("name", "password");
|
||||||
|
passwordelement.setAttribute("id", "password");
|
||||||
|
passwordelement.setAttribute("required","required");
|
||||||
|
createform.appendChild(passwordelement);
|
||||||
|
|
||||||
|
|
||||||
|
var passwordbreak = document.createElement('br');
|
||||||
|
createform.appendChild(passwordbreak);
|
||||||
|
|
||||||
|
|
||||||
|
var submitelement = document.createElement('button'); // Append Submit Button
|
||||||
|
submitelement.setAttribute("type", "button");
|
||||||
|
submitelement.setAttribute("onclick", "ROC_AUTH.login();");
|
||||||
|
submitelement.innerHTML = "Sign In ";
|
||||||
|
createform.appendChild(submitelement);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var password = document.getElementById("password");
|
||||||
|
var confirm_password = document.getElementById("confirm_password");
|
||||||
|
|
||||||
|
ROC_AUTH.validatePassword =function(){
|
||||||
|
if ((password != null) && (confirm_password != null)) {
|
||||||
|
if(password.value != confirm_password.value) {
|
||||||
|
confirm_password.setCustomValidity("Passwords Don't Match");
|
||||||
|
} else {
|
||||||
|
confirm_password.setCustomValidity('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((password != null) && (confirm_password != null)) {
|
||||||
|
password.onchange = ROC_AUTH.validatePassword();
|
||||||
|
confirm_password.onkeyup = ROC_AUTH.validatePassword;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<div class="primary-tabs">
|
||||||
|
{unless isset="$user"}
|
||||||
|
<h3>Login or <a href="{$site_url/}account/roc-register">Register</a></h3>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<form name="cms_basic_auth" action method="POST">
|
||||||
|
<div>
|
||||||
|
<input type="text" name="username" id="username" required>
|
||||||
|
<label>Username</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input type="password" name="password" id="password" required>
|
||||||
|
<label>Password</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="button" onclick="ROC_AUTH.login();">Login</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
<a href="{$site_url/}account/new-password">Forgot password?</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/unless}
|
||||||
|
</div>
|
||||||
25
examples/demo/site/modules/blog/files/css/blog.css
Normal file
25
examples/demo/site/modules/blog/files/css/blog.css
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
ul.cms_blog_nodes {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
ul.cms_blog_nodes li.cms_type_blog {
|
||||||
|
list-style: none;
|
||||||
|
display: block;
|
||||||
|
margin-top: 20px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
border-bottom: 1px dotted black;
|
||||||
|
}
|
||||||
|
ul.cms_blog_nodes li.cms_type_blog .blog_title a {
|
||||||
|
color: black;
|
||||||
|
font-size: 18px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
margin: 6px 0;
|
||||||
|
}
|
||||||
|
ul.cms_blog_nodes li.cms_type_blog .blog_title a:hover {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
ul.cms_blog_nodes li.cms_type_blog .blog_list_summary a {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
30
examples/demo/site/modules/blog/files/scss/blog.scss
Normal file
30
examples/demo/site/modules/blog/files/scss/blog.scss
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
ul.cms_blog_nodes{
|
||||||
|
|
||||||
|
padding:0;
|
||||||
|
margin:0;
|
||||||
|
|
||||||
|
li.cms_type_blog{
|
||||||
|
list-style: none;
|
||||||
|
display: block;
|
||||||
|
margin-top:20px;
|
||||||
|
padding-bottom:20px;
|
||||||
|
border-bottom:1px dotted black;
|
||||||
|
|
||||||
|
.blog_title a{
|
||||||
|
color:black;
|
||||||
|
font-size:18px;
|
||||||
|
text-decoration: none;
|
||||||
|
display:block;
|
||||||
|
margin:6px 0;
|
||||||
|
|
||||||
|
&:hover{
|
||||||
|
color:#999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog_list_summary a{
|
||||||
|
margin-top:20px;
|
||||||
|
display:block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
examples/demo/site/modules/feed_aggregator/config/feeds.json
Normal file
28
examples/demo/site/modules/feed_aggregator/config/feeds.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"ids": ["news", "forum"],
|
||||||
|
"feeds": {
|
||||||
|
"news": {
|
||||||
|
"title": "Eiffel related posts",
|
||||||
|
"expiration": "21600",
|
||||||
|
"size": 5,
|
||||||
|
"locations": [
|
||||||
|
"https://bertrandmeyer.com/feed/",
|
||||||
|
"https://room.eiffel.com/blog/feed",
|
||||||
|
"https://room.eiffel.com/article/feed",
|
||||||
|
"https://room.eiffel.com/library/feed"
|
||||||
|
]
|
||||||
|
, "categories": ["Eiffel"]
|
||||||
|
,"option_description": "enabled"
|
||||||
|
},
|
||||||
|
"forum": {
|
||||||
|
"title": "Eiffel Forum",
|
||||||
|
"expiration": "21600",
|
||||||
|
"size": 5,
|
||||||
|
"locations": [
|
||||||
|
"https://groups.google.com/forum/feed/eiffel-users/msgs/atom.xml?num=15",
|
||||||
|
"http://stackoverflow.com/feeds/tag?tagnames=eiffel&sort=newest"
|
||||||
|
]
|
||||||
|
,"option_description": "enabled"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
div.feed ul {
|
||||||
|
list-style: none;
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
width: 99%;
|
||||||
|
}
|
||||||
|
div.feed li {
|
||||||
|
/* border-top: solid 1px #ddd; */
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 0 5px 0;
|
||||||
|
}
|
||||||
|
div.feed li a {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
div.feed li .date {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: small;
|
||||||
|
}
|
||||||
|
div.feed li .category {
|
||||||
|
margin-left: 20px;
|
||||||
|
font-size: 8px;
|
||||||
|
height: 9px;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
div.feed li .description {
|
||||||
|
margin-left: 20px;
|
||||||
|
font-size: small;
|
||||||
|
height: 18px;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
div.feed li:hover {
|
||||||
|
margin-bottom: 23px;
|
||||||
|
}
|
||||||
|
div.feed li:hover .description {
|
||||||
|
padding: 5px;
|
||||||
|
position: absolute;
|
||||||
|
height: auto;
|
||||||
|
overflow-y: scroll;
|
||||||
|
overflow-x: scroll;
|
||||||
|
color: #000;
|
||||||
|
background-color: #fff;
|
||||||
|
border: solid 1px #000;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
div.feed li:hover:last-child {
|
||||||
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
div.feed li .description::after {
|
||||||
|
content: "...";
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
div.feed {
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
width: 99%;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
/* border-top: solid 1px #ddd; */
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 0 5px 0;
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.date {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: small;
|
||||||
|
}
|
||||||
|
.category {
|
||||||
|
margin-left: 20px;
|
||||||
|
font-size: 8px;
|
||||||
|
height: 9px;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.description {
|
||||||
|
margin-left: 20px;
|
||||||
|
font-size: small;
|
||||||
|
height: 18px;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
margin-bottom: 23px;
|
||||||
|
.description {
|
||||||
|
padding: 5px;
|
||||||
|
position: absolute;
|
||||||
|
height: auto;
|
||||||
|
overflow-y: scroll;
|
||||||
|
overflow-x: scroll;
|
||||||
|
color: #000;
|
||||||
|
background-color: #fff;
|
||||||
|
border: solid 1px #000;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.description::after { content: "..."; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"gcse": {
|
||||||
|
"cx":"",
|
||||||
|
"secret_key":""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<h2>Results for <kbd>{$result.current_page.search_terms/}</kbd></h2>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- list of results -->
|
||||||
|
<ol start="{$result.current_page.start_index/}">
|
||||||
|
|
||||||
|
<!-- Item result -->
|
||||||
|
{foreach from="$result.items" item="item"}
|
||||||
|
<li>
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h3>
|
||||||
|
<cite>
|
||||||
|
<a href="{$item.link/}">{$item.title/}</a>
|
||||||
|
</cite>
|
||||||
|
</h3>
|
||||||
|
</header>
|
||||||
|
<blockquote cite="{$item.link/}">
|
||||||
|
<p>{$item.html_snippet/}</p>
|
||||||
|
<footer>
|
||||||
|
<p><abbr title="Uniform Resource Locator">Source</abbr> <a href="{$item.link/}">{$item.display_link/}</a></p>
|
||||||
|
</footer>
|
||||||
|
</blockquote>
|
||||||
|
</article>
|
||||||
|
</li>
|
||||||
|
{/foreach}
|
||||||
|
|
||||||
|
|
||||||
|
</ol>
|
||||||
|
<ul class="cms-page-links">
|
||||||
|
{if isset="$result.previous_page"}
|
||||||
|
<li><a href="{$site_url/}gcse/?q={$result.previous_page.search_terms/}&start={$result.previous_page.start_index/}&num={$result.previous_page.count/}">Previous</a></li>
|
||||||
|
{/if}
|
||||||
|
{if isset="$result.next_page"}
|
||||||
|
<li><a href="{$site_url/}gcse/?q={$result.next_page.search_terms/}&start={$result.next_page.start_index/}&num={$result.next_page.count/}">Next</a></li>
|
||||||
|
{/if}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
17
examples/demo/site/modules/node/files/css/node.css
Normal file
17
examples/demo/site/modules/node/files/css/node.css
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
ul.cms-nodes {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 3px 3px 3px 3px;
|
||||||
|
border: solid 1px #ccc;
|
||||||
|
}
|
||||||
|
ul.cms-nodes li {
|
||||||
|
border-top: dotted 1px #ccc;
|
||||||
|
}
|
||||||
|
ul.cms-nodes li:first-child {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
ul.cms-nodes li.cms_type_page a::before {
|
||||||
|
content: "[page] ";
|
||||||
|
}
|
||||||
|
ul.cms-nodes li.cms_type_blog a::before {
|
||||||
|
content: "[blog] ";
|
||||||
|
}
|
||||||
24
examples/demo/site/modules/node/files/scss/node.scss
Normal file
24
examples/demo/site/modules/node/files/scss/node.scss
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
ul.cms-nodes {
|
||||||
|
|
||||||
|
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_type_page a::before {
|
||||||
|
content: "[page] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
li.cms_type_blog a::before {
|
||||||
|
content: "[blog] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
37
examples/demo/site/modules/node/scripts/node.sql
Normal file
37
examples/demo/site/modules/node/scripts/node.sql
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
CREATE TABLE nodes (
|
||||||
|
`nid` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT UNIQUE,
|
||||||
|
`revision` INTEGER,
|
||||||
|
`type` TEXT NOT NULL,
|
||||||
|
`title` VARCHAR(255) NOT NULL,
|
||||||
|
`summary` TEXT,
|
||||||
|
`content` TEXT,
|
||||||
|
`format` VARCHAR(128),
|
||||||
|
`author` INTEGER,
|
||||||
|
`publish` DATETIME,
|
||||||
|
`created` DATETIME NOT NULL,
|
||||||
|
`changed` DATETIME NOT NULL,
|
||||||
|
`status` INTEGER,
|
||||||
|
CONSTRAINT Unique_nid_revision UNIQUE (nid,revision)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE node_revisions (
|
||||||
|
`nid` INTEGER NOT NULL,
|
||||||
|
`revision` INTEGER NOT NULL,
|
||||||
|
`title` VARCHAR(255) NOT NULL,
|
||||||
|
`summary` TEXT,
|
||||||
|
`content` TEXT,
|
||||||
|
`format` VARCHAR(128),
|
||||||
|
`author` INTEGER,
|
||||||
|
`changed` DATETIME NOT NULL,
|
||||||
|
`status` INTEGER,
|
||||||
|
CONSTRAINT Unique_nid_revision PRIMARY KEY (nid,revision)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE page_nodes(
|
||||||
|
`nid` INTEGER NOT NULL,
|
||||||
|
`revision` INTEGER NOT NULL,
|
||||||
|
`parent` INTEGER,
|
||||||
|
CONSTRAINT PK_nid_revision PRIMARY KEY (nid,revision)
|
||||||
|
);
|
||||||
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
CREATE TABLE oauth2_consumers(
|
||||||
|
`cid` INTEGER PRIMARY KEY NOT NULL CHECK(`cid`>=0),
|
||||||
|
`name` VARCHAR(255) NOT NULL,
|
||||||
|
`api_secret` TEXT NOT NULL,
|
||||||
|
`api_key` TEXT NOT NULL,
|
||||||
|
`scope` VARCHAR (100) NOT NULL,
|
||||||
|
`protected_resource_url` VARCHAR (255) NOT NULL,
|
||||||
|
`callback_name` VARCHAR(255) NOT NULL,
|
||||||
|
`extractor` VARCHAR(50) NOT NULL,
|
||||||
|
`authorize_url` VARCHAR (255) NOT NULL,
|
||||||
|
`endpoint` VARCHAR (255) NOT NULL,
|
||||||
|
CONSTRAINT `cid`
|
||||||
|
UNIQUE(`cid`),
|
||||||
|
CONSTRAINT `name`
|
||||||
|
UNIQUE(`name`)
|
||||||
|
);
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
-- Change the values TO_COMPLETE based on your API.
|
||||||
|
-- API SECTET KEY AND API PUBLIC KEY
|
||||||
|
INSERT INTO oauth2_consumers (name, api_secret, api_key, scope, protected_resource_url, callback_name, extractor, authorize_url, endpoint)
|
||||||
|
VALUES ('google', 'TO-COMPLETE', 'TO-COMPLETE', 'email', 'https://www.googleapis.com/plus/v1/people/me', 'callback_google', 'json','https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI','https://accounts.google.com/o/oauth2/token');
|
||||||
|
|
||||||
|
INSERT INTO oauth2_consumers (name, api_secret, api_key, scope, protected_resource_url, callback_name, extractor, authorize_url, endpoint )
|
||||||
|
VALUES ('facebook', 'TO-COMPLETE', 'TO-COMPLETE', 'email', 'https://graph.facebook.com/me', 'callback_facebook','text','https://www.facebook.com/dialog/oauth?response_type=code&client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI','https://graph.facebook.com/oauth/access_token');
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
CREATE TABLE $table_name (
|
||||||
|
`uid` INTEGER PRIMARY KEY NOT NULL CHECK(`uid`>=0),
|
||||||
|
`access_token` TEXT NOT NULL,
|
||||||
|
`created` DATETIME NOT NULL,
|
||||||
|
`details` TEXT NOT NULL,
|
||||||
|
`email` TEXT NOT NULL,
|
||||||
|
CONSTRAINT `uid`
|
||||||
|
UNIQUE(`uid`),
|
||||||
|
CONSTRAINT `email`
|
||||||
|
UNIQUE(`email`)
|
||||||
|
);
|
||||||
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<hr>
|
||||||
|
{unless isempty="$oauth_associated"}
|
||||||
|
<h4>Un-Associate Account with Oauth Consumer</h4>
|
||||||
|
<div>
|
||||||
|
{foreach item="consumer" from="$oauth_associated"}
|
||||||
|
<div>
|
||||||
|
<form method="post" action="{$site_url/}account/oauth-un-associate">
|
||||||
|
<input type="hidden" name="consumer" value="{$consumer/}"/>
|
||||||
|
<div>
|
||||||
|
<button type="submit">Unlink {$consumer/}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{/foreach}
|
||||||
|
</div>
|
||||||
|
{/unless}
|
||||||
|
{unless isempty="$oauth_not_associated"}
|
||||||
|
<h4>Associate Account with Oauth Consumer</h4>
|
||||||
|
<div>
|
||||||
|
{foreach item="consumer" from="$oauth_not_associated"}
|
||||||
|
<div>
|
||||||
|
<form method="post" action="{$site_url/}account/oauth-associate">
|
||||||
|
<input type="hidden" name="consumer" value="{$consumer/}"/>
|
||||||
|
<div>
|
||||||
|
<input type="email" id="email" name="email" value="{$email/}" required/>
|
||||||
|
<button type="submit">Link with {$consumer/}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{/foreach}
|
||||||
|
</div>
|
||||||
|
{/unless}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<div class="primary-tabs">
|
||||||
|
<div>
|
||||||
|
{foreach item="item" from="$oauth_consumers"}
|
||||||
|
<a href="{$site_url/}account/login-with-oauth/{$item/}">Login with {$item/}</a><br>
|
||||||
|
{/foreach}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
CREATE TABLE openid_consumers(
|
||||||
|
`cid` INTEGER PRIMARY KEY NOT NULL CHECK(`cid`>=0),
|
||||||
|
`name` VARCHAR(255) NOT NULL,
|
||||||
|
`endpoint` VARCHAR (255) NOT NULL,
|
||||||
|
CONSTRAINT `cid`
|
||||||
|
UNIQUE(`cid`),
|
||||||
|
CONSTRAINT `name`
|
||||||
|
UNIQUE(`name`)
|
||||||
|
);
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Change the values TO_COMPLETE based on your API.
|
||||||
|
-- API SECTET KEY AND API PUBLIC KEY
|
||||||
|
INSERT INTO openid_consumers (name, endpoint)
|
||||||
|
VALUES ('yahoo', 'https://me.yahoo.com/');
|
||||||
11
examples/demo/site/modules/openid/scripts/openid_items.sql
Normal file
11
examples/demo/site/modules/openid/scripts/openid_items.sql
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
CREATE TABLE openid_items (
|
||||||
|
`uid` INTEGER PRIMARY KEY NOT NULL CHECK(`uid`>=0),
|
||||||
|
`identity` TEXT NOT NULL,
|
||||||
|
`created` DATETIME NOT NULL,
|
||||||
|
CONSTRAINT `uid`
|
||||||
|
UNIQUE(`uid`),
|
||||||
|
CONSTRAINT `identity`
|
||||||
|
UNIQUE(`identity`)
|
||||||
|
);
|
||||||
|
|
||||||
18
examples/demo/site/modules/openid/templates/block_login.tpl
Normal file
18
examples/demo/site/modules/openid/templates/block_login.tpl
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<div>
|
||||||
|
<form action="{$site_url/}account/roc-openid-login" id="openid-login" method="POST">
|
||||||
|
<div>
|
||||||
|
<strong><label for="openid">OpenID identifier</label></strong><br/>
|
||||||
|
<input type="text" name="openid" value="" size="50"/>
|
||||||
|
</div>
|
||||||
|
<div><input type="submit" name="op" value="Validate"/></div>
|
||||||
|
<div hgv vtid="openid">Login with
|
||||||
|
{foreach item="item" from="$openid_consumers"}
|
||||||
|
<a href="{$site_url/}account/login-with-openid/{$item/}">{$item/}</a><br>
|
||||||
|
{/foreach}
|
||||||
|
</form>
|
||||||
|
<div>
|
||||||
|
{if isset="$error"}
|
||||||
|
<span><i>{$error/}</i></span> <br>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -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`)
|
||||||
|
);
|
||||||
|
|
||||||
@@ -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>
|
||||||
26
examples/demo/site/modules/taxonomy/files/css/taxonomy.css
Normal file
26
examples/demo/site/modules/taxonomy/files/css/taxonomy.css
Normal 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;
|
||||||
|
}
|
||||||
27
examples/demo/site/modules/taxonomy/files/scss/taxonomy.scss
Normal file
27
examples/demo/site/modules/taxonomy/files/scss/taxonomy.scss
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
examples/demo/site/modules/taxonomy/scripts/install.sql
Normal file
24
examples/demo/site/modules/taxonomy/scripts/install.sql
Normal 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)
|
||||||
|
);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
DROP TABLE IF EXISTS taxonomy_term;
|
||||||
|
DROP TABLE IF EXISTS taxonomy_hierarchy;
|
||||||
|
DROP TABLE IF EXISTS taxonomy_index;
|
||||||
23
examples/demo/site/scripts/core.sql
Normal file
23
examples/demo/site/scripts/core.sql
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
CREATE TABLE `logs`(
|
||||||
|
`id` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL,
|
||||||
|
`category` VARCHAR(255) NOT NULL,
|
||||||
|
`level` INTEGER NOT NULL,
|
||||||
|
`uid` INTEGER,
|
||||||
|
`message` TEXT NOT NULL,
|
||||||
|
`info` TEXT,
|
||||||
|
`link` TEXT,
|
||||||
|
`date` DATETIME NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `custom_values`(
|
||||||
|
`type` VARCHAR(255) NOT NULL,
|
||||||
|
`name` VARCHAR(255) NOT NULL,
|
||||||
|
`value` TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `path_aliases`(
|
||||||
|
`pid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL,
|
||||||
|
`source` VARCHAR(255) NOT NULL,
|
||||||
|
`alias` VARCHAR(255) NOT NULL,
|
||||||
|
`lang` VARCHAR(12)
|
||||||
|
);
|
||||||
48
examples/demo/site/scripts/user.sql
Normal file
48
examples/demo/site/scripts/user.sql
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
|
||||||
|
CREATE TABLE `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,
|
||||||
|
`status` INTEGER,
|
||||||
|
`created` DATETIME NOT NULL,
|
||||||
|
`signed` DATETIME,
|
||||||
|
CONSTRAINT `name`
|
||||||
|
UNIQUE(`name`)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `roles`(
|
||||||
|
`rid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL,
|
||||||
|
`name` VARCHAR(100) NOT NULL,
|
||||||
|
CONSTRAINT `name`
|
||||||
|
UNIQUE(`name`)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `users_roles`(
|
||||||
|
`uid` INTEGER NOT NULL CHECK(`uid`>=0),
|
||||||
|
`rid` INTEGER NOT NULL CHECK(`rid`>=0)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `role_permissions`(
|
||||||
|
`rid` INTEGER NOT NULL,
|
||||||
|
`permission` VARCHAR(255) NOT NULL,
|
||||||
|
`module` VARCHAR(255)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `users_activations` (
|
||||||
|
`aid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL CHECK (`aid` >= 0),
|
||||||
|
`token` VARCHAR(255) NOT NULL,
|
||||||
|
`uid` INTEGER NOT NULL CHECK (`uid` >= 0),
|
||||||
|
`created` DATETIME NOT NULL,
|
||||||
|
CONSTRAINT `token` UNIQUE (`token`)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `users_password_recovery` (
|
||||||
|
`aid` INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL CHECK (`aid` >= 0),
|
||||||
|
`token` VARCHAR(255) NOT NULL,
|
||||||
|
`uid` INTEGER NOT NULL CHECK (`uid` >= 0),
|
||||||
|
`created` DATETIME NOT NULL,
|
||||||
|
CONSTRAINT `token` UNIQUE (`token`)
|
||||||
|
);
|
||||||
|
|
||||||
100
examples/demo/site/themes/bootstrap/assets/css/style.css
Normal file
100
examples/demo/site/themes/bootstrap/assets/css/style.css
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
ul.horizontal li {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header #primary.menu ul li {
|
||||||
|
color: #555;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#header #primary.menu ul li a {
|
||||||
|
color: #555;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
#header #primary.menu ul li a:hover {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
#header #primary.menu ul.horizontal {
|
||||||
|
border-bottom: solid 1px #ddd;
|
||||||
|
}
|
||||||
|
#header #primary.menu ul.horizontal li {
|
||||||
|
border-top: solid 3px #fff;
|
||||||
|
}
|
||||||
|
#header #primary.menu ul.horizontal li:hover {
|
||||||
|
background-color: #ffe;
|
||||||
|
border-top: solid 3px #999;
|
||||||
|
}
|
||||||
|
#header #primary.menu ul.horizontal li.active {
|
||||||
|
font-weight: bold;
|
||||||
|
border-top: solid 3px #ddd;
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
#header #primary.menu ul.horizontal li.active:hover {
|
||||||
|
border-top: solid 3px blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
#content #highlighted {
|
||||||
|
position: relative;
|
||||||
|
border: solid 1px #ddd;
|
||||||
|
background-color: #ffc;
|
||||||
|
width: 70%;
|
||||||
|
left: 15%;
|
||||||
|
right: 15%;
|
||||||
|
padding: 5px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
padding: 5px;
|
||||||
|
margin: 3px;
|
||||||
|
/* border: solid 1px #ccc; */
|
||||||
|
}
|
||||||
|
.sidebar#sidebar_first {
|
||||||
|
width: 250px;
|
||||||
|
position: fixed;
|
||||||
|
top: 45px;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 200px;
|
||||||
|
border-right: solid 1px #ddd;
|
||||||
|
}
|
||||||
|
.sidebar#sidebar_second {
|
||||||
|
width: 250px;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.sidebar + .main {
|
||||||
|
margin-left: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#primary-tabs ul.horizontal {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
#primary-tabs ul.horizontal li {
|
||||||
|
display: inline;
|
||||||
|
padding: 2px 5px;
|
||||||
|
border: solid 1px #ccf;
|
||||||
|
}
|
||||||
|
#primary-tabs ul.horizontal li.active {
|
||||||
|
border-color: #99f #99f #ddd;
|
||||||
|
border-style: solid solid none;
|
||||||
|
border-width: 2px 1px 0;
|
||||||
|
padding: 2px 7px 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#message li.error {
|
||||||
|
background-color: #f99;
|
||||||
|
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;
|
||||||
|
}
|
||||||
BIN
examples/demo/site/themes/bootstrap/assets/favicon.ico
Normal file
BIN
examples/demo/site/themes/bootstrap/assets/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 994 B |
6
examples/demo/site/themes/bootstrap/assets/js/jquery-1.10.2.min.js
vendored
Normal file
6
examples/demo/site/themes/bootstrap/assets/js/jquery-1.10.2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
|||||||
|
$(document).ready(function() {
|
||||||
|
$('#gcse_search_form').submit(function() {
|
||||||
|
window.open('', 'formpopup', 'width=600,height=600,resizeable,scrollbars');
|
||||||
|
this.target = 'formpopup';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
107
examples/demo/site/themes/bootstrap/assets/scss/style.scss
Normal file
107
examples/demo/site/themes/bootstrap/assets/scss/style.scss
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
ul.horizontal {
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#header {
|
||||||
|
#primary.menu {
|
||||||
|
ul {
|
||||||
|
li {
|
||||||
|
color: #555;
|
||||||
|
a {
|
||||||
|
color: #555;
|
||||||
|
text-decoration: none;
|
||||||
|
&:hover { color: black; }
|
||||||
|
}
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
&.horizontal {
|
||||||
|
border-bottom: solid 1px #ddd;
|
||||||
|
li {
|
||||||
|
border-top: solid 3px #fff;
|
||||||
|
&:hover {
|
||||||
|
background-color: #ffe;
|
||||||
|
border-top: solid 3px #999;
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
font-weight: bold;
|
||||||
|
border-top: solid 3px #ddd;
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
&.active:hover {
|
||||||
|
border-top: solid 3px blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#content {
|
||||||
|
margin-left: 20px;
|
||||||
|
#highlighted {
|
||||||
|
position: relative;
|
||||||
|
border: solid 1px #ddd;
|
||||||
|
background-color: #ffc;
|
||||||
|
width: 70%;
|
||||||
|
left: 15%;
|
||||||
|
right: 15%;
|
||||||
|
padding: 5px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sidebar {
|
||||||
|
padding: 5px;
|
||||||
|
margin: 3px;
|
||||||
|
/* border: solid 1px #ccc; */
|
||||||
|
&#sidebar_first {
|
||||||
|
width: 250px;
|
||||||
|
position: fixed;
|
||||||
|
top: 45px;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 200px;
|
||||||
|
border-right: solid 1px #ddd;
|
||||||
|
}
|
||||||
|
&#sidebar_second {
|
||||||
|
width: 250px;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
&+.main {
|
||||||
|
margin-left: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#primary-tabs {
|
||||||
|
ul.horizontal {
|
||||||
|
list-style-type: none;
|
||||||
|
li {
|
||||||
|
display: inline;
|
||||||
|
padding: 2px 5px;
|
||||||
|
border: solid 1px #ccf;
|
||||||
|
}
|
||||||
|
li.active {
|
||||||
|
border-color: #99f #99f #ddd;
|
||||||
|
border-style: solid solid none;
|
||||||
|
border-width: 2px 1px 0;
|
||||||
|
padding: 2px 7px 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#message li.error {
|
||||||
|
background-color: #f99;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
examples/demo/site/themes/bootstrap/debug.tpl
Normal file
38
examples/demo/site/themes/bootstrap/debug.tpl
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{assign name="debug_enabled" value="True"/}
|
||||||
|
{if condition="$debug_enabled"}
|
||||||
|
<!-- start debug -->
|
||||||
|
{literal}
|
||||||
|
<style>
|
||||||
|
div.cms-debug>span {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 5px;
|
||||||
|
right: 5px;
|
||||||
|
color: #ccc;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
div.cms-debug:hover>span {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
div.cms-debug>span+ul {
|
||||||
|
display: none;
|
||||||
|
border: solid 2px red;
|
||||||
|
background-color: #ccc;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
div.cms-debug:hover>span+ul {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
bottom: 5px;
|
||||||
|
left: 1%; right: 1%;
|
||||||
|
width: 98%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{/literal}
|
||||||
|
<div class="cms-debug"><span>Show debug</span>
|
||||||
|
<ul>
|
||||||
|
{assign name="kpage" value="page"/}{assign name="kregions" value="regions"/}{foreach key="k" item="i" from="$page.variables"}{unless condition="$k ~ $kpage"}{unless condition="$k ~ $kregions"}<li><strong>{$k/}</strong>={htmlentities}{$i/}{/htmlentities}</li>{/unless}{/unless}
|
||||||
|
{/foreach}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<!-- end debug -->
|
||||||
|
{/if}
|
||||||
101
examples/demo/site/themes/bootstrap/page.tpl
Normal file
101
examples/demo/site/themes/bootstrap/page.tpl
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<!-- EWF CMS -->
|
||||||
|
<link rel="stylesheet" href="{$site_url/}theme/css/style.css">
|
||||||
|
|
||||||
|
<!-- jQuery dep -->
|
||||||
|
<script src="{$site_url/}theme/js/jquery-1.10.2.min.js"></script>
|
||||||
|
<script src="{$site_url/}theme/js/popup_search.js"></script>
|
||||||
|
|
||||||
|
{if isset="$head"}{$head/}{/if}
|
||||||
|
{if isset="$styles"}{$styles/}{/if}
|
||||||
|
{if isset="$scripts"}{$scripts/}{/if}
|
||||||
|
{if isset="$head_lines"}{$head_lines/}{/if}
|
||||||
|
|
||||||
|
<!-- bootstrap framework -->
|
||||||
|
<!-- Latest compiled and minified CSS -->
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
|
||||||
|
<!-- Optional theme -->
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css">
|
||||||
|
|
||||||
|
<title>{$head_title/}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Page Top -->
|
||||||
|
{if isset="$region_top"}
|
||||||
|
{$region_top/}
|
||||||
|
{/if}
|
||||||
|
<!-- Body -->
|
||||||
|
<div class='container-fluid'>
|
||||||
|
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div id="header">
|
||||||
|
{if isset="$page.primary_nav"}
|
||||||
|
{$page.primary_nav/}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<!-- Page search -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-2 col-md-offset-9">
|
||||||
|
<form action="{$site_url/}gcse" class="search-form" id="gcse_search_form">
|
||||||
|
<div class="form-group has-feedback">
|
||||||
|
<input type="search" class="form-control" name="q" id="gcse_search" placeholder="search">
|
||||||
|
<span class="glyphicon glyphicon-search form-control-feedback"></span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- General Page Content -->
|
||||||
|
<div id='content' class='row-fluid'>
|
||||||
|
<!-- Left Sidebar sidebar_first -->
|
||||||
|
{unless isempty="$page.region_sidebar_first"}
|
||||||
|
<div id="sidebar_first" class="sidebar">{$page.region_sidebar_first/}</div>
|
||||||
|
{/unless}
|
||||||
|
<!-- Right Sidebar sidebar_second-->
|
||||||
|
{unless isempty="$page.region_sidebar_second"}
|
||||||
|
<div id="sidebar_second" class="sidebar">{$page.region_sidebar_second/}</div>
|
||||||
|
{/unless}
|
||||||
|
|
||||||
|
<!-- Highlighted, Help, Content -->
|
||||||
|
<div id='main' class='span8 main'>
|
||||||
|
<!-- Highlighted Section -->
|
||||||
|
{unless isempty="$page.region_highlighted"}
|
||||||
|
<div id="highlighted">{$page.region_highlighted/}</div>
|
||||||
|
{/unless}
|
||||||
|
<!-- Help Section -->
|
||||||
|
{unless isempty="$page.region_help"}
|
||||||
|
<div id="help">{$page.region_help/}</div>
|
||||||
|
{/unless}
|
||||||
|
|
||||||
|
<!-- Main Content Section -->
|
||||||
|
{unless isempty="$page_title"}<h1 class="page-title">{$page_title/}</h1>{/unless}
|
||||||
|
{$page.region_content/}
|
||||||
|
{if condition="$page.is_front"}
|
||||||
|
{if isset="$page.region_feed_news"}
|
||||||
|
<div class="column" style="width: 45%; float: left">{$page.region_feed_news/}</div>
|
||||||
|
{/if}
|
||||||
|
{if isset="$page.region_feed_forum"}
|
||||||
|
<div class="column" style="width: 45%; float: left">{$page.region_feed_forum/}</div>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--Page footer -->
|
||||||
|
{$page.region_footer/}
|
||||||
|
|
||||||
|
<!-- Page Bottom -->
|
||||||
|
{$page.region_bottom/}
|
||||||
|
|
||||||
|
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
|
||||||
|
<!-- Latest compiled and minified JavaScript -->
|
||||||
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
|
||||||
|
|
||||||
|
{include file="debug.tpl"/}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
14
examples/demo/site/themes/bootstrap/theme.info
Normal file
14
examples/demo/site/themes/bootstrap/theme.info
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
name=bootstrap
|
||||||
|
engine=smarty
|
||||||
|
author=jvelilla
|
||||||
|
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
|
||||||
|
navigation=default_nav
|
||||||
97
examples/demo/src/demo_cms_execution.e
Normal file
97
examples/demo/src/demo_cms_execution.e
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
CMS Execution for the demo server.
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
DEMO_CMS_EXECUTION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
CMS_EXECUTION
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
initial_cms_setup: CMS_DEFAULT_SETUP
|
||||||
|
-- CMS setup.
|
||||||
|
local
|
||||||
|
l_env: CMS_ENVIRONMENT
|
||||||
|
do
|
||||||
|
if attached execution_environment.arguments.separate_character_option_value ('d') as l_dir then
|
||||||
|
create l_env.make_with_directory_name (l_dir)
|
||||||
|
else
|
||||||
|
create l_env.make_default
|
||||||
|
end
|
||||||
|
create Result.make (l_env)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- CMS storage
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
-- 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)
|
||||||
|
|
||||||
|
-- Nodes
|
||||||
|
create {CMS_NODE_MODULE} m.make (a_setup)
|
||||||
|
a_setup.register_module (m)
|
||||||
|
|
||||||
|
create {CMS_BLOG_MODULE} m.make
|
||||||
|
a_setup.register_module (m)
|
||||||
|
|
||||||
|
-- Taxonomy
|
||||||
|
create {CMS_TAXONOMY_MODULE} m.make
|
||||||
|
a_setup.register_module (m)
|
||||||
|
|
||||||
|
-- Recent changes
|
||||||
|
create {CMS_RECENT_CHANGES_MODULE} m.make
|
||||||
|
a_setup.register_module (m)
|
||||||
|
|
||||||
|
-- Recent changes
|
||||||
|
create {FEED_AGGREGATOR_MODULE} m.make
|
||||||
|
a_setup.register_module (m)
|
||||||
|
|
||||||
|
-- Miscellanious
|
||||||
|
create {CMS_DEBUG_MODULE} m.make
|
||||||
|
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)
|
||||||
|
|
||||||
|
create {CMS_SESSION_AUTH_MODULE} m.make
|
||||||
|
a_setup.register_module (m)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
18
examples/demo/src/demo_cms_server.e
Normal file
18
examples/demo/src/demo_cms_server.e
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
DEMO application server.
|
||||||
|
]"
|
||||||
|
date: "$Date: 2015-02-09 22:29:56 +0100 (lun., 09 févr. 2015) $"
|
||||||
|
revision: "$Revision: 96596 $"
|
||||||
|
|
||||||
|
class
|
||||||
|
DEMO_CMS_SERVER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
ROC_CMS_LAUNCHER [DEMO_CMS_EXECUTION]
|
||||||
|
|
||||||
|
create
|
||||||
|
make_and_launch
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
10
launcher/README.txt
Normal file
10
launcher/README.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Collection of ROC CMS launcher ready to use.
|
||||||
|
|
||||||
|
- Include any-safe.ecf to use any of cgi, libfcgi or standalone connector.
|
||||||
|
- Include standalone-safe.ecf to use standalone connector.
|
||||||
|
- Include libfcgi-safe.ecf to use libfcgi connector.
|
||||||
|
- Include cgi-safe.ecf to use cgi connector.
|
||||||
|
|
||||||
|
In application, the root class need to inherit from ROC_CMS_LAUNCHER with adapted CMS_EXECUTION
|
||||||
|
descendant.
|
||||||
|
|
||||||
18
launcher/any-safe.ecf
Normal file
18
launcher/any-safe.ecf
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?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="launcher" uuid="6FDCA393-AFC3-436B-A58A-870923967C86" library_target="launcher">
|
||||||
|
<target name="common" abstract="true">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="cms" location="..\cms-safe.ecf"/>
|
||||||
|
<library name="cms_app_env" location="..\library\app_env\app_env-safe.ecf" readonly="false"/>
|
||||||
|
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
|
||||||
|
</target>
|
||||||
|
<target name="launcher" extends="common">
|
||||||
|
<library name="cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\cgi-safe.ecf"/>
|
||||||
|
<library name="libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\libfcgi-safe.ecf"/>
|
||||||
|
<library name="nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\nino-safe.ecf"/>
|
||||||
|
<library name="standalone" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\standalone-safe.ecf"/>
|
||||||
|
<cluster name="src" location=".\" recursive="false"/>
|
||||||
|
<cluster name="launcher" location=".\any\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
19
launcher/any.ecf
Normal file
19
launcher/any.ecf
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-14-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-14-0 http://www.eiffel.com/developers/xml/configuration-1-14-0.xsd" name="launcher" uuid="6FDCA393-AFC3-436B-A58A-870923967C86" library_target="launcher">
|
||||||
|
<target name="common" abstract="true">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<option void_safety="none" />
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<library name="cms" location="..\cms.ecf"/>
|
||||||
|
<library name="cms_app_env" location="..\library\app_env\app_env.ecf" readonly="false"/>
|
||||||
|
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf.ecf"/>
|
||||||
|
</target>
|
||||||
|
<target name="launcher" extends="common">
|
||||||
|
<library name="cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\cgi.ecf"/>
|
||||||
|
<library name="libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\libfcgi.ecf"/>
|
||||||
|
<library name="nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\nino.ecf"/>
|
||||||
|
<library name="standalone" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\standalone.ecf"/>
|
||||||
|
<cluster name="src" location=".\" recursive="false"/>
|
||||||
|
<cluster name="launcher" location=".\any\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
19
launcher/any/application_launcher.e
Normal file
19
launcher/any/application_launcher.e
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Effective class for APPLICATION_LAUNCHER_I
|
||||||
|
|
||||||
|
You can put modification in this class
|
||||||
|
]"
|
||||||
|
date: "$Date: 2013-06-12 13:55:42 +0200 (mer., 12 juin 2013) $"
|
||||||
|
revision: "$Revision: 36 $"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION_LAUNCHER [G -> WSF_EXECUTION create make end]
|
||||||
|
|
||||||
|
inherit
|
||||||
|
APPLICATION_LAUNCHER_I [G]
|
||||||
|
|
||||||
|
feature -- Custom
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
127
launcher/any/application_launcher_i.e
Normal file
127
launcher/any/application_launcher_i.e
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Specific application launcher
|
||||||
|
|
||||||
|
DO NOT EDIT THIS CLASS
|
||||||
|
|
||||||
|
you can customize APPLICATION_LAUNCHER
|
||||||
|
]"
|
||||||
|
date: "$Date: 2013-06-12 13:55:42 +0200 (mer., 12 juin 2013) $"
|
||||||
|
revision: "$Revision: 36 $"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
APPLICATION_LAUNCHER_I [G -> WSF_EXECUTION create make end]
|
||||||
|
|
||||||
|
inherit
|
||||||
|
SHARED_EXECUTION_ENVIRONMENT
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
nature: like launcher_nature
|
||||||
|
do
|
||||||
|
nature := launcher_nature
|
||||||
|
if nature = Void then
|
||||||
|
launch_standalone (opts)
|
||||||
|
elseif nature = nature_standalone then
|
||||||
|
launch_standalone (opts)
|
||||||
|
elseif nature = nature_nino then
|
||||||
|
launch_nino (opts)
|
||||||
|
elseif nature = nature_cgi then
|
||||||
|
launch_cgi (opts)
|
||||||
|
elseif nature = nature_libfcgi then
|
||||||
|
launch_libfcgi (opts)
|
||||||
|
else
|
||||||
|
-- bye bye
|
||||||
|
(create {EXCEPTIONS}).die (-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Access
|
||||||
|
|
||||||
|
launcher_nature: detachable READABLE_STRING_8
|
||||||
|
-- Initialize the launcher nature
|
||||||
|
-- either cgi, libfcgi, or nino.
|
||||||
|
--| We could extend with more connector if needed.
|
||||||
|
--| and we could use WSF_DEFAULT_SERVICE_LAUNCHER to configure this at compilation time.
|
||||||
|
local
|
||||||
|
p: PATH
|
||||||
|
ext: detachable READABLE_STRING_32
|
||||||
|
do
|
||||||
|
create p.make_from_string (execution_environment.arguments.command_name)
|
||||||
|
if attached p.entry as l_entry then
|
||||||
|
ext := l_entry.extension
|
||||||
|
end
|
||||||
|
if ext /= Void then
|
||||||
|
if ext.same_string (nature_standalone) then
|
||||||
|
Result := nature_standalone
|
||||||
|
end
|
||||||
|
if ext.same_string (nature_nino) then
|
||||||
|
Result := nature_nino
|
||||||
|
end
|
||||||
|
if ext.same_string (nature_cgi) then
|
||||||
|
Result := nature_cgi
|
||||||
|
end
|
||||||
|
if ext.same_string (nature_libfcgi) or else ext.same_string ("fcgi") then
|
||||||
|
Result := nature_libfcgi
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Result := default_nature
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- standalone
|
||||||
|
|
||||||
|
nature_standalone: STRING = "standalone"
|
||||||
|
|
||||||
|
launch_standalone (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
launcher: WSF_STANDALONE_SERVICE_LAUNCHER [G]
|
||||||
|
do
|
||||||
|
create launcher.make_and_launch (opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- nino
|
||||||
|
|
||||||
|
nature_nino: STRING = "nino"
|
||||||
|
|
||||||
|
launch_nino (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
launcher: WSF_NINO_SERVICE_LAUNCHER [G]
|
||||||
|
do
|
||||||
|
create launcher.make_and_launch (opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- cgi
|
||||||
|
|
||||||
|
nature_cgi: STRING = "cgi"
|
||||||
|
|
||||||
|
launch_cgi (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
launcher: WSF_CGI_SERVICE_LAUNCHER [G]
|
||||||
|
do
|
||||||
|
create launcher.make_and_launch (opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- libfcgi
|
||||||
|
|
||||||
|
nature_libfcgi: STRING = "libfcgi"
|
||||||
|
|
||||||
|
launch_libfcgi (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
launcher: WSF_LIBFCGI_SERVICE_LAUNCHER [G]
|
||||||
|
do
|
||||||
|
create launcher.make_and_launch (opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Default
|
||||||
|
|
||||||
|
default_nature: STRING
|
||||||
|
do
|
||||||
|
Result := nature_standalone
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
15
launcher/cgi-safe.ecf
Normal file
15
launcher/cgi-safe.ecf
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?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="cgi_launcher" uuid="0FE4F1D0-BB70-4C7F-A66E-B27F1D718109" library_target="cgi_launcher">
|
||||||
|
<target name="common" abstract="true">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="cms" location="..\cms-safe.ecf"/>
|
||||||
|
<library name="cms_app_env" location="..\library\app_env\app_env-safe.ecf" readonly="false"/>
|
||||||
|
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
|
||||||
|
</target>
|
||||||
|
<target name="cgi_launcher" extends="common">
|
||||||
|
<library name="default_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
|
||||||
|
<cluster name="src" location=".\" recursive="false"/>
|
||||||
|
<cluster name="launcher" location=".\default\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
19
launcher/default/application_launcher.e
Normal file
19
launcher/default/application_launcher.e
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Effective class for APPLICATION_LAUNCHER_I
|
||||||
|
|
||||||
|
You can put modification in this class
|
||||||
|
]"
|
||||||
|
date: "$Date: 2013-06-12 13:55:42 +0200 (mer., 12 juin 2013) $"
|
||||||
|
revision: "$Revision: 36 $"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION_LAUNCHER [G -> WSF_EXECUTION create make end]
|
||||||
|
|
||||||
|
inherit
|
||||||
|
APPLICATION_LAUNCHER_I [G]
|
||||||
|
|
||||||
|
feature -- Custom
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
26
launcher/default/application_launcher_i.e
Normal file
26
launcher/default/application_launcher_i.e
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Specific application launcher
|
||||||
|
|
||||||
|
DO NOT EDIT THIS CLASS
|
||||||
|
|
||||||
|
you can customize APPLICATION_LAUNCHER
|
||||||
|
]"
|
||||||
|
date: "$Date: 2015-02-09 22:29:56 +0100 (lun., 09 févr. 2015) $"
|
||||||
|
revision: "$Revision: 96596 $"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
APPLICATION_LAUNCHER_I [G -> WSF_EXECUTION create make end]
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
launcher: WSF_DEFAULT_SERVICE_LAUNCHER [G]
|
||||||
|
do
|
||||||
|
create launcher.make_and_launch (opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
15
launcher/libfcgi-safe.ecf
Normal file
15
launcher/libfcgi-safe.ecf
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?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="libfcgi_launcher" uuid="04D7D1EA-059B-4024-B0DE-BBB57AB2D00C" library_target="libfcgi_launcher">
|
||||||
|
<target name="common" abstract="true">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="cms" location="..\cms-safe.ecf"/>
|
||||||
|
<library name="cms_app_env" location="..\library\app_env\app_env-safe.ecf" readonly="false"/>
|
||||||
|
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
|
||||||
|
</target>
|
||||||
|
<target name="libfcgi_launcher" extends="common">
|
||||||
|
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
|
||||||
|
<cluster name="src" location=".\" recursive="false"/>
|
||||||
|
<cluster name="launcher" location=".\default\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
16
launcher/libfcgi.ecf
Normal file
16
launcher/libfcgi.ecf
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?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="libfcgi_launcher" uuid="04D7D1EA-059B-4024-B0DE-BBB57AB2D00C" library_target="libfcgi_launcher">
|
||||||
|
<target name="common" abstract="true">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<option void_safety="none" />
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<library name="cms" location="..\cms.ecf"/>
|
||||||
|
<library name="cms_app_env" location="..\library\app_env\app_env.ecf" readonly="false"/>
|
||||||
|
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf.ecf"/>
|
||||||
|
</target>
|
||||||
|
<target name="libfcgi_launcher" extends="common">
|
||||||
|
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi.ecf"/>
|
||||||
|
<cluster name="src" location=".\" recursive="false"/>
|
||||||
|
<cluster name="launcher" location=".\default\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
95
launcher/roc_cms_launcher.e
Normal file
95
launcher/roc_cms_launcher.e
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Reusable ROC CMS launcher.
|
||||||
|
]"
|
||||||
|
date: "$Date: 2015-02-09 22:29:56 +0100 (lun., 09 févr. 2015) $"
|
||||||
|
revision: "$Revision: 96596 $"
|
||||||
|
|
||||||
|
class
|
||||||
|
ROC_CMS_LAUNCHER [G -> CMS_EXECUTION create make end]
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_LAUNCHABLE_SERVICE
|
||||||
|
rename
|
||||||
|
make_and_launch as make_and_launch_service
|
||||||
|
redefine
|
||||||
|
initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
REFACTORING_HELPER
|
||||||
|
|
||||||
|
SHARED_EXECUTION_ENVIRONMENT
|
||||||
|
|
||||||
|
SHARED_LOGGER
|
||||||
|
|
||||||
|
create
|
||||||
|
make_and_launch
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make_and_launch
|
||||||
|
do
|
||||||
|
create launcher
|
||||||
|
make_and_launch_service
|
||||||
|
end
|
||||||
|
|
||||||
|
initialize
|
||||||
|
-- Initialize current service.
|
||||||
|
local
|
||||||
|
env: CMS_ENVIRONMENT
|
||||||
|
l_app_name: detachable READABLE_STRING_32
|
||||||
|
do
|
||||||
|
Precursor
|
||||||
|
create env.make_default
|
||||||
|
l_app_name := optional_application_name
|
||||||
|
if l_app_name = Void then
|
||||||
|
l_app_name := env.name
|
||||||
|
end
|
||||||
|
create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI} service_options.make_from_file (l_app_name + ".ini")
|
||||||
|
initialize_logger (env)
|
||||||
|
end
|
||||||
|
|
||||||
|
optional_application_name: detachable READABLE_STRING_32
|
||||||
|
-- Optional application name.
|
||||||
|
--| Redefine if needed.
|
||||||
|
do
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Launch operation
|
||||||
|
|
||||||
|
launcher: APPLICATION_LAUNCHER [G]
|
||||||
|
|
||||||
|
launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
l_retry: BOOLEAN
|
||||||
|
l_message: STRING
|
||||||
|
do
|
||||||
|
if not l_retry then
|
||||||
|
launcher.launch (opts)
|
||||||
|
else
|
||||||
|
-- error hanling.
|
||||||
|
create l_message.make (1024)
|
||||||
|
if attached ((create {EXCEPTION_MANAGER}).last_exception) as l_exception then
|
||||||
|
if attached l_exception.description as l_description then
|
||||||
|
l_message.append (l_description.as_string_32)
|
||||||
|
l_message.append ("%N%N")
|
||||||
|
elseif attached l_exception.trace as l_trace then
|
||||||
|
l_message.append (l_trace)
|
||||||
|
l_message.append ("%N%N")
|
||||||
|
else
|
||||||
|
l_message.append (l_exception.out)
|
||||||
|
l_message.append ("%N%N")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
l_message.append ("The application crashed without information.")
|
||||||
|
l_message.append ("%N%N")
|
||||||
|
end
|
||||||
|
-- send email shutdown
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
l_retry := True
|
||||||
|
retry
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
16
launcher/standalone-safe.ecf
Normal file
16
launcher/standalone-safe.ecf
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?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="standalone_launcher" uuid="F42660A9-26C2-466B-A63C-C7823C808BE7" library_target="standalone_launcher">
|
||||||
|
<target name="common" abstract="true">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="cms" location="..\cms-safe.ecf"/>
|
||||||
|
<library name="cms_app_env" location="..\library\app_env\app_env-safe.ecf" readonly="false"/>
|
||||||
|
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
|
||||||
|
</target>
|
||||||
|
<target name="standalone_launcher" extends="common">
|
||||||
|
<library name="default_standalone" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\standalone-safe.ecf"/>
|
||||||
|
<library name="standalone" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\standalone-safe.ecf"/>
|
||||||
|
<cluster name="src" location=".\" recursive="false"/>
|
||||||
|
<cluster name="launcher" location=".\default\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
17
launcher/standalone.ecf
Normal file
17
launcher/standalone.ecf
Normal file
@@ -0,0 +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="standalone_launcher" uuid="F42660A9-26C2-466B-A63C-C7823C808BE7" library_target="standalone_launcher">
|
||||||
|
<target name="common" abstract="true">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<option void_safety="none" />
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<library name="cms" location="..\cms.ecf"/>
|
||||||
|
<library name="cms_app_env" location="..\library\app_env\app_env.ecf" readonly="false"/>
|
||||||
|
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf.ecf"/>
|
||||||
|
</target>
|
||||||
|
<target name="standalone_launcher" extends="common">
|
||||||
|
<library name="default_standalone" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\standalone.ecf"/>
|
||||||
|
<library name="standalone" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\connector\standalone.ecf"/>
|
||||||
|
<cluster name="src" location=".\" recursive="false"/>
|
||||||
|
<cluster name="launcher" location=".\default\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
0
library/Readme.md
Normal file
0
library/Readme.md
Normal file
13
library/app_env/Readme.md
Normal file
13
library/app_env/Readme.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Application Environment Library
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Define a generic application environment to be re-used by different applications.
|
||||||
|
|
||||||
|
site/
|
||||||
|
doc/
|
||||||
|
logs/
|
||||||
|
www/
|
||||||
|
assets
|
||||||
|
template
|
||||||
|
theme
|
||||||
|
config/
|
||||||
22
library/app_env/app_env-safe.ecf
Normal file
22
library/app_env/app_env-safe.ecf
Normal 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="app_env" uuid="7AE9E48B-5A15-43F8-B99A-04F4185DED6B" library_target="app_env">
|
||||||
|
<description>Application Environment (layout, configuration, logger, database, ...)</description>
|
||||||
|
<target name="app_env">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<option warning="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="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
|
||||||
|
<library name="logging" location="$ISE_LIBRARY\library\runtime\logging\logging-safe.ecf"/>
|
||||||
|
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true">
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/CVS$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
</cluster>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
22
library/app_env/app_env.ecf
Normal file
22
library/app_env/app_env.ecf
Normal 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="app_env" uuid="7AE9E48B-5A15-43F8-B99A-04F4185DED6B" library_target="app_env">
|
||||||
|
<description>Application Environment (layout, configuration, logger, database, ...)</description>
|
||||||
|
<target name="app_env">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<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="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json.ecf" readonly="false"/>
|
||||||
|
<library name="logging" location="$ISE_LIBRARY\library\runtime\logging\logging.ecf"/>
|
||||||
|
<library name="thread" location="$ISE_LIBRARY\library\thread\thread.ecf"/>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true">
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/CVS$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
</cluster>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
3
library/app_env/license.lic
Normal file
3
library/app_env/license.lic
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
${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)"
|
||||||
211
library/app_env/src/application_environment.e
Normal file
211
library/app_env/src/application_environment.e
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Application environment (layout, ...)
|
||||||
|
Related to file system locations such as
|
||||||
|
- configuration locations
|
||||||
|
- application
|
||||||
|
- log
|
||||||
|
- documentation
|
||||||
|
- www
|
||||||
|
- assets
|
||||||
|
- templates (html, Collection+JSON, ...)
|
||||||
|
- ...
|
||||||
|
]"
|
||||||
|
date: "$Date: 2015-02-05 10:25:53 +0100 (jeu., 05 févr. 2015) $"
|
||||||
|
revision: "$Revision: 96584 $"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION_ENVIRONMENT
|
||||||
|
|
||||||
|
inherit
|
||||||
|
SHARED_EXECUTION_ENVIRONMENT
|
||||||
|
|
||||||
|
create
|
||||||
|
make_default,
|
||||||
|
make_with_path,
|
||||||
|
make_with_directory_name
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make_default
|
||||||
|
-- Create a default layout based on current working directory.
|
||||||
|
local
|
||||||
|
p: PATH
|
||||||
|
do
|
||||||
|
create p.make_current
|
||||||
|
p := p.extended ("site")
|
||||||
|
make_with_path (p)
|
||||||
|
end
|
||||||
|
|
||||||
|
make_with_path (p: PATH)
|
||||||
|
-- Create a layour based on a path `p'.
|
||||||
|
do
|
||||||
|
path := p.absolute_path.canonical_path
|
||||||
|
initialize_name
|
||||||
|
end
|
||||||
|
|
||||||
|
make_with_directory_name (a_dirname: READABLE_STRING_GENERAL)
|
||||||
|
-- Create a layour based on a path `p'.
|
||||||
|
do
|
||||||
|
make_with_path (create {PATH}.make_from_string (a_dirname))
|
||||||
|
end
|
||||||
|
|
||||||
|
initialize_name
|
||||||
|
-- Initialize `name'.
|
||||||
|
local
|
||||||
|
p: PATH
|
||||||
|
s: STRING_32
|
||||||
|
do
|
||||||
|
create p.make_from_string (execution_environment.arguments.command_name)
|
||||||
|
if attached p.entry as e then
|
||||||
|
p := e
|
||||||
|
end
|
||||||
|
create s.make_from_string (p.name)
|
||||||
|
if attached p.extension as l_extension then
|
||||||
|
s.remove_tail (l_extension.count + 1)
|
||||||
|
end
|
||||||
|
if s.is_whitespace then
|
||||||
|
set_name ({STRING_8} "app")
|
||||||
|
else
|
||||||
|
set_name (s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
path: PATH
|
||||||
|
-- Root location.
|
||||||
|
|
||||||
|
name: IMMUTABLE_STRING_32
|
||||||
|
-- Application name, default is "app"
|
||||||
|
|
||||||
|
feature -- Change
|
||||||
|
|
||||||
|
set_name (a_name: READABLE_STRING_GENERAL)
|
||||||
|
-- Set `name' from `a_name'.
|
||||||
|
do
|
||||||
|
create name.make_from_string_general (a_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access: internal
|
||||||
|
|
||||||
|
config_path: PATH
|
||||||
|
-- Configuration file path.
|
||||||
|
local
|
||||||
|
p: detachable PATH
|
||||||
|
do
|
||||||
|
p := internal_config_path
|
||||||
|
if p = Void then
|
||||||
|
p := path.extended ("config")
|
||||||
|
internal_config_path := p
|
||||||
|
end
|
||||||
|
Result := p
|
||||||
|
end
|
||||||
|
|
||||||
|
application_config_path: PATH
|
||||||
|
-- Database Configuration file path.
|
||||||
|
local
|
||||||
|
p: detachable PATH
|
||||||
|
do
|
||||||
|
p := internal_application_config_path
|
||||||
|
if p = Void then
|
||||||
|
p := config_path.extended (name + ".json")
|
||||||
|
internal_application_config_path := p
|
||||||
|
end
|
||||||
|
Result := p
|
||||||
|
end
|
||||||
|
|
||||||
|
logs_path: PATH
|
||||||
|
-- Directory for logs.
|
||||||
|
local
|
||||||
|
p: detachable PATH
|
||||||
|
do
|
||||||
|
p := internal_logs_path
|
||||||
|
if p = Void then
|
||||||
|
p := path.extended ("logs")
|
||||||
|
internal_logs_path := p
|
||||||
|
end
|
||||||
|
Result := p
|
||||||
|
end
|
||||||
|
|
||||||
|
documentation_path: PATH
|
||||||
|
-- Directory for API documentation.
|
||||||
|
local
|
||||||
|
p: detachable PATH
|
||||||
|
do
|
||||||
|
p := internal_documentation_path
|
||||||
|
if p = Void then
|
||||||
|
p := path.extended ("doc")
|
||||||
|
internal_documentation_path := p
|
||||||
|
end
|
||||||
|
Result := p
|
||||||
|
end
|
||||||
|
|
||||||
|
www_path: PATH
|
||||||
|
-- Directory for www.
|
||||||
|
local
|
||||||
|
p: detachable PATH
|
||||||
|
do
|
||||||
|
p := internal_www_path
|
||||||
|
if p = Void then
|
||||||
|
p := path.extended ("www")
|
||||||
|
internal_www_path := p
|
||||||
|
end
|
||||||
|
Result := p
|
||||||
|
end
|
||||||
|
|
||||||
|
assets_path: PATH
|
||||||
|
-- Directory for public assets.
|
||||||
|
-- css, images, js.
|
||||||
|
local
|
||||||
|
p: detachable PATH
|
||||||
|
do
|
||||||
|
p := internal_assets_path
|
||||||
|
if p = Void then
|
||||||
|
p := www_path.extended ("assets")
|
||||||
|
internal_assets_path := p
|
||||||
|
end
|
||||||
|
Result := p
|
||||||
|
end
|
||||||
|
|
||||||
|
template_path: PATH
|
||||||
|
-- Directory for templates (HTML, etc).
|
||||||
|
local
|
||||||
|
p: detachable PATH
|
||||||
|
do
|
||||||
|
p := internal_template_path
|
||||||
|
if p = Void then
|
||||||
|
p := www_path.extended ("template")
|
||||||
|
internal_template_path := p
|
||||||
|
end
|
||||||
|
Result := p
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
internal_config_path: detachable like config_path
|
||||||
|
-- Configuration file path.
|
||||||
|
|
||||||
|
internal_application_config_path: detachable like application_config_path
|
||||||
|
-- Database Configuration file path.
|
||||||
|
|
||||||
|
internal_logs_path: detachable like logs_path
|
||||||
|
-- Directory for logs.
|
||||||
|
|
||||||
|
internal_documentation_path: detachable like documentation_path
|
||||||
|
-- Directory for API documentation.
|
||||||
|
|
||||||
|
internal_www_path: detachable like www_path
|
||||||
|
-- Directory for www.
|
||||||
|
|
||||||
|
internal_assets_path: detachable like assets_path
|
||||||
|
-- Directory for public assets.
|
||||||
|
-- css, images, js.
|
||||||
|
|
||||||
|
internal_template_path: detachable like template_path
|
||||||
|
-- Directory for templates (HTML, etc).
|
||||||
|
|
||||||
|
;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)"
|
||||||
|
end
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user