Skip to content

Commit

Permalink
Merge pull request #26 from domapic/release-1.0.0-alpha.6
Browse files Browse the repository at this point in the history
Release 1.0.0 alpha.6
  • Loading branch information
javierbrea committed Nov 1, 2018
2 parents d1cc677 + 2ba4580 commit ef1d072
Show file tree
Hide file tree
Showing 37 changed files with 1,046 additions and 29 deletions.
17 changes: 17 additions & 0 deletions .narval.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,23 @@ suites:
specs:
- test/functional/specs/ability-state-api.specs.js
coverage: *base-coverage
- name: ability-event
describe: Ability event api should work as expected
before: *base-before
services: *base-services
test:
<<: *base-test
specs:
- test/functional/specs/ability-event-api.specs.js
coverage: *base-coverage
- name: logs
describe: Logs api should work as expected
services: *base-services
test:
<<: *base-test
specs:
- test/functional/specs/logs-api.specs.js
coverage: *base-coverage
- name: users-cli
describe: Users cli should be able to add and remove users
before: *base-before
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Fixed
### Removed

## [1.0.0-alpha.6] - 2018-11-1
### Added
- Add ability events api
- Save abilities actions and events as logs into database
- Add logs api

## [1.0.0-alpha.5] - 2018-10-15
### Added
- Add ability state api
Expand Down
7 changes: 5 additions & 2 deletions lib/Api.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@ const users = require('./api/users')
const securityTokens = require('./api/securityTokens')
const services = require('./api/services')
const abilities = require('./api/abilities')
const logs = require('./api/logs')

const Api = (service, commands) => ({
openapis: [
...users.openapi(),
...securityTokens.openapi(),
...services.openapi(),
...abilities.openapi()
...abilities.openapi(),
...logs.openapi()
],
operations: {
...users.Operations(service, commands),
...securityTokens.Operations(service, commands),
...services.Operations(service, commands),
...abilities.Operations(service, commands)
...abilities.Operations(service, commands),
...logs.Operations(service, commands)
}
})

Expand Down
4 changes: 3 additions & 1 deletion lib/Commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ const securityToken = require('./commands/securityToken')
const composed = require('./commands/composed')
const serviceCommand = require('./commands/service')
const abilityCommand = require('./commands/ability')
const logCommand = require('./commands/log')

const Commands = (service, models, client) => {
const commands = {
user: user.Commands(service, models, client),
securityToken: securityToken.Commands(service, models, client),
service: serviceCommand.Commands(service, models, client),
ability: abilityCommand.Commands(service, models, client)
ability: abilityCommand.Commands(service, models, client),
log: logCommand.Commands(service, models, client)
}

return {
Expand Down
4 changes: 3 additions & 1 deletion lib/Models.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ const user = require('./models/user')
const securityToken = require('./models/securityToken')
const serviceModel = require('./models/service')
const ability = require('./models/ability')
const log = require('./models/log')

const Models = service => ({
User: user.Model(service),
SecurityToken: securityToken.Model(service),
Service: serviceModel.Model(service),
Ability: ability.Model(service)
Ability: ability.Model(service),
Log: log.Model(service)
})

module.exports = Models
17 changes: 14 additions & 3 deletions lib/api/abilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ const { omitBy, isUndefined } = require('lodash')
const definition = require('./abilities.json')
const { roles } = require('../security/utils')

const LOCATION = 'location'
const LOCATION_ROOT = '/api/abilities/'

const Operations = (service, commands) => {
const onlyOwner = (userData, params, body) => {
return commands.ability.getById(params.path.id).then(abilityData => {
Expand All @@ -31,15 +34,15 @@ const Operations = (service, commands) => {
auth: onlyOwner,
handler: (params, body, res) => commands.ability.update(params.path.id, body).then(abilityData => {
res.status(204)
res.header('location', `/api/abilities/${abilityData._id}`)
res.header(LOCATION, `${LOCATION_ROOT}${abilityData._id}`)
return Promise.resolve()
})
},
addAbility: {
auth: (userData) => userData.role === roles.SERVICE,
handler: (params, body, res, userData) => commands.ability.add(userData, body).then(abilityData => {
res.status(201)
res.header('location', `/api/abilities/${abilityData._id}`)
res.header(LOCATION, `${LOCATION_ROOT}${abilityData._id}`)
return Promise.resolve()
})
},
Expand All @@ -53,12 +56,20 @@ const Operations = (service, commands) => {
abilityAction: {
handler: (params, body, res) => commands.composed.dispatchAbilityAction(params.path.id, body).then(serviceResponse => {
res.status(201)
res.header('location', `/api/abilities/${params.path.id}/state`)
res.header(LOCATION, `${LOCATION_ROOT}${params.path.id}/state`)
return Promise.resolve()
})
},
abilityState: {
handler: (params, body, res) => commands.composed.getAbilityState(params.path.id)
},
abilityEvent: {
auth: onlyOwner,
handler: (params, body, res) => commands.composed.triggerAbilityEvent(params.path.id, body).then(() => {
res.status(201)
res.header(LOCATION, `${LOCATION_ROOT}${params.path.id}/state`)
return Promise.resolve()
})
}
}
}
Expand Down
60 changes: 57 additions & 3 deletions lib/api/abilities.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
{
"tags": [{
"name": "ability",
"description": "Domapic service ability"
"description": "Service ability"
},{
"name": "action",
"description": "Domapic service ability action"
"description": "Service ability action"
},{
"name": "state",
"description": "Domapic service ability state"
"description": "Service ability state"
},{
"name": "event",
"description": "Service ability event"
}],
"components": {
"schemas": {
Expand Down Expand Up @@ -324,6 +327,14 @@
}
}
},
"AbilityEvent": {
"description": "Ability event successfully triggered",
"headers": {
"location": {
"$ref": "#/components/headers/ContentLocation"
}
}
},
"Deleted": {
"description": "Entity deleted"
},
Expand Down Expand Up @@ -607,6 +618,49 @@
"apiKey": []
}]
}
},
"/abilities/{id}/event": {
"post": {
"parameters": [
{
"in": "path",
"name": "id",
"schema": {
"type": "string"
},
"required": true,
"description": "Ability id"
}
],
"tags": ["ability", "event"],
"summary": "Triggers an ability event",
"description": "Used to inform that an ability event was triggered. Intended to be used only by services",
"operationId": "abilityEvent",
"requestBody": {
"description": "Data of the event",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AbilityData"
}
}
}
},
"responses": {
"201": {
"$ref": "#/components/responses/AbilityEvent"
},
"404": {
"$ref": "#/components/responses/NotFoundError"
}
},
"security": [{
"jwt": []
}, {
"apiKey": []
}]
}
}
}
}
16 changes: 16 additions & 0 deletions lib/api/logs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict'

const definition = require('./logs.json')

const Operations = (service, commands) => ({
getLogs: {
handler: () => commands.log.getAll()
}
})

const openapi = () => [definition]

module.exports = {
Operations,
openapi
}
83 changes: 83 additions & 0 deletions lib/api/logs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
"tags": [{
"name": "log",
"description": "Controller events and actions logs"
}],
"components": {
"schemas": {
"Log": {
"description": "Log data",
"type": "object",
"properties": {
"_id": {
"description": "Unique id of the log",
"type": "string"
},
"_ability": {
"description": "Ability id",
"type": "string"
},
"data": {
"oneOf": [{
"type": "string"
}, {
"type": "boolean"
}, {
"type": "number"
}]
},
"type": {
"description": "Type of event",
"type": "string",
"enum": ["action", "event"]
},
"createdAt": {
"description": "Creation date timestamp",
"type": "string"
}
},
"additionalProperties": false,
"example": {
"_id": "1223123",
"_ability": "131231342334234",
"type": "event",
"data": "foo-data",
"createdAt": "2018-07-28T17:13:08.718Z"
}
},
"Logs": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Log"
}
}
}
},
"paths": {
"/logs": {
"get": {
"tags": ["log", "action", "event", "ability"],
"summary": "Return logs",
"description": "Returns an array with all events and actions logs",
"operationId": "getLogs",
"responses": {
"200": {
"description": "Logs response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Logs"
}
}
}
}
},
"security": [{
"jwt": []
}, {
"apiKey": []
}]
}
}
}
}
9 changes: 9 additions & 0 deletions lib/commands/ability.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ const Commands = (service, models, client) => {
return validateData(ability, data)
})

const validateEvent = (_id, data) => getById(_id)
.then(ability => {
if (!ability.event) {
return Promise.reject(new service.errors.NotFound(templates.abilityEventNotDefined()))
}
return validateData(ability, data)
})

const validateState = (_id, data) => getById(_id)
.then(ability => {
if (!ability.state) {
Expand All @@ -97,6 +105,7 @@ const Commands = (service, models, client) => {
update,
remove,
validateAction,
validateEvent,
validateState
}
}
Expand Down
25 changes: 24 additions & 1 deletion lib/commands/composed.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,39 @@ const Commands = (service, models, client, commands) => {
const dispatchAbilityAction = (abilityId, data) => commands.ability.validateAction(abilityId, data)
.then(ability => commands.service.getById(ability._service, {
allFields: true
}).then(service => client.sendAction(service, ability, data)))
}).then(service => client.sendAction(service, ability, data).then(() => commands.log.add({
_ability: ability._id,
type: 'action',
data: data.data
}))))

const getAbilityState = abilityId => commands.ability.validateState(abilityId)
.then(ability => commands.service.getById(ability._service, {
allFields: true
}).then(service => client.getState(service, ability)))

const triggerAbilityEvent = (abilityId, data) => commands.ability.validateEvent(abilityId, data)
.then(ability => commands.service.getById(ability._service, {
allFields: true
}).then(serviceData => {
return Promise.all([
commands.log.add({
_ability: ability._id,
type: 'event',
data: data.data
}),
service.tracer.debug(templates.receivedAbilityEvent({
_service: serviceData._id,
_ability: ability._id,
data: data.data
}))
])
}))

return {
initUsers,
dispatchAbilityAction,
triggerAbilityEvent,
getAbilityState
}
}
Expand Down
Loading

0 comments on commit ef1d072

Please sign in to comment.