Nick is a headless CMS built with Node.js that is compatible with Plone's REST API (Volto). It aims to address some issues with Plone like legacy code, complex deployment, and maintenance burden. Nick uses a Postgres database with Knex.js and Objection.js for modeling content types and behaviors. Content is managed through a REST API and initial content, types, and profiles are seeded through migration scripts.
3. What is Nick?
Why?
Architecture
Getting started
Documentation
Database
Contenttypes
Security
Catalog & Search
Vocabularies
Security
Utility calls
i18n
Logging
Database schema
Roadmap
WHAT WILL WE COVER?
4. WHAT IS NICK?
Headless CMS
Build with Node.js
RESTfull API compatible with plone.restapi (Volto)
5. WHY?
Fun to build!
Plone has a great architecture, great way to learn the
internals
Plone has a great Rest API
Started as a proof of concept on Ploneconf 2018 in
Tokyo
Frontend and backend using the same language
13. GETTING STARTED
CREATE DATABASE nick;
CREATE USER nick WITH ENCRYPTED PASSWORD 'nick';
GRANT ALL PRIVILEGES ON DATABASE nick TO nick;
$ yarn bootstrap
$ yarn start
14. YEOMAN GENERATOR
$ npm install -g yo
$ npm install -g @robgietema/generator-nick
$ yo @robgietema/nick my-project
CREATE DATABASE my-project;
CREATE USER nick WITH ENCRYPTED PASSWORD 'my-project';
GRANT ALL PRIVILEGES ON DATABASE my-project TO my-project;
$ cd my-project
$ yarn bootstrap
$ yarn start
28. OBJECTION.JS (MODELS)
/**
* Permission Model.
* @module models/permission/permission
*/
import { Model } from '../../models';
/**
* A model for Permission.
* @class Permission
* @extends Model
*/
export class Permission extends Model {
// Set relation mappings
static get relationMappings() {
29. OBJECTION.JS (BASE MODEL)
/**
* Objection Model.
* @module helpers/base-model/base-model
*/
import { mixin, Model as ObjectionModel } from 'objection';
import TableName from 'objection-table-name';
import _, {
difference,
isArray,
isEmpty,
isObject,
isString,
keys,
map,
44. ID_FROM_TITLE.JS
/**
* Id from title behavior.
* @module behaviors/id_from_title/id_from_title
*/
import slugify from 'slugify';
import { uniqueId } from '../../helpers';
/**
* Id from title behavior.
* @constant id_from_title
*/
export const id_from_title = {
/**
57. GET VERSION
GET /news/@history/0 HTTP/1.1
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ
HTTP/1.1 200 OK
Content-Type: application/json
{
"title": "Old News",
"blocks": {
"79ba8858-1dd3-4719-b731-5951e32fbf79": {
"@type": "title"
}
},
"description": "News Items",
"blocks_layout": {
"items": [
"79ba8858-1dd3-4719-b731-5951e32fbf79"
]
58. REVERT TO VERSION
PATCH /news/my-news-item/@history HTTP/1.1
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ
Content-Type: application/json
{
"version": 0
}
HTTP/1.1 200 OK
Content-Type: application/json
{
"message": "My News Item has been reverted to revision 0."
}
72. PERMISSION SYSTEM
Permissions
Roles (have permissions)
Groups (have roles)
Users (have roles, groups)
Local roles (user/group has a role on an object)
Local role permissions are inherited from the parent
Local role inheritence can be disabled per object
Workflows (have states and transitions)
States (have permissions per role)
Transitions (have permissions)