├── .gitignore ├── CODE_OF_CONDUCT.md ├── Git-Configuration.md ├── ISSUE_TEMPLATE.md ├── LICENSE ├── NOTICE.md ├── README.md ├── api ├── .babelrc ├── .dockerignore ├── .eslintrc.json ├── .gitignore ├── .npmignore ├── Dockerfile ├── README.md ├── lib │ ├── .hc.js │ ├── categories │ │ ├── calculator │ │ │ └── info.json │ │ ├── currency │ │ │ └── info.json │ │ ├── github │ │ │ ├── actions.json │ │ │ ├── info.json │ │ │ ├── keywords.json │ │ │ └── sayings.json │ │ ├── index.js │ │ ├── music │ │ │ └── info.json │ │ ├── news │ │ │ ├── actions.json │ │ │ ├── info.json │ │ │ ├── keywords.json │ │ │ └── sayings.json │ │ ├── small-talk │ │ │ ├── actions.json │ │ │ ├── info.json │ │ │ ├── keywords.json │ │ │ └── sayings.json │ │ └── weather │ │ │ ├── actions.json │ │ │ ├── info.json │ │ │ ├── keywords.json │ │ │ └── sayings.json │ ├── channels │ │ ├── chat-widget │ │ │ ├── get.js │ │ │ ├── info.json │ │ │ ├── init.js │ │ │ ├── post.js │ │ │ ├── reply.js │ │ │ └── validate.js │ │ ├── facebook │ │ │ ├── README.MD │ │ │ ├── get.js │ │ │ ├── hash.js │ │ │ ├── info.json │ │ │ ├── init.js │ │ │ ├── post.js │ │ │ ├── reply.js │ │ │ ├── screenshots │ │ │ │ ├── 01 - App Dashboard.png │ │ │ │ ├── 02 - Products + Set UP.png │ │ │ │ ├── 03 - Page Selection.png │ │ │ │ ├── 04 - Permissons.png │ │ │ │ ├── 05 - Articulate Page Access Token.png │ │ │ │ ├── 06 - App Secret.png │ │ │ │ ├── 07 - Connection Saved.png │ │ │ │ ├── 08 - Subscribe To Events.png │ │ │ │ ├── 09 - Verify and Save.png │ │ │ │ ├── 10 - Page subscription.png │ │ │ │ └── 11 - Page subscribed.png │ │ │ └── validate.js │ │ ├── google-home │ │ │ ├── README.MD │ │ │ ├── get.js │ │ │ ├── hash.js │ │ │ ├── info.json │ │ │ ├── init.js │ │ │ ├── post.js │ │ │ ├── reply.js │ │ │ ├── screenshots │ │ │ │ ├── 01 - Google Actions Console.png │ │ │ │ ├── 02 - New Project.png │ │ │ │ ├── 03 - New Project Screen.png │ │ │ │ ├── 04 - Copy command.png │ │ │ │ ├── 05 - Decide display name.png │ │ │ │ ├── 06 - Set display name.png │ │ │ │ ├── 07 - New Google Home Connection.png │ │ │ │ ├── 08 - Query Patterns.png │ │ │ │ ├── 09 - Download Actions Package.png │ │ │ │ ├── 10 - Actions Package.png │ │ │ │ ├── 11 - Project ID.png │ │ │ │ └── 12 - Close Google Action.png │ │ │ └── validate.js │ │ ├── index.js │ │ ├── mattermost │ │ │ ├── README.MD │ │ │ ├── get.js │ │ │ ├── hash.js │ │ │ ├── info.json │ │ │ ├── init.js │ │ │ ├── post.js │ │ │ ├── reply.js │ │ │ ├── screenshots │ │ │ │ ├── 1 - 5 - 10 Integrations Screen.png │ │ │ │ ├── 11 - Slash Command Create.png │ │ │ │ ├── 12 - Slash Command Information 1.png │ │ │ │ ├── 13 - Slash Command Information 2.png │ │ │ │ ├── 14 - Slash Command Created.png │ │ │ │ ├── 15 - Articulate Connection Create.png │ │ │ │ ├── 16 - Articulate Mattermost Icon.png │ │ │ │ ├── 17 - Articulate Mattermost Information.png │ │ │ │ ├── 18 - Articulate Callback URL Placeholder.png │ │ │ │ ├── 19 - Articulate OW Edit.png │ │ │ │ ├── 2 - Incoming Webhook Create.png │ │ │ │ ├── 20 - Articulate OW placeholder change.png │ │ │ │ ├── 21 - Articulate SC Edit.png │ │ │ │ ├── 22 - Articulate SC placeholder change.png │ │ │ │ ├── 23 - Articulate Mattermost Use.png │ │ │ │ ├── 3 - Incoming Webhook Information.png │ │ │ │ ├── 4 - Incoming Webhook Created.png │ │ │ │ ├── 6 - Outgoing Webhook Create.png │ │ │ │ ├── 7 - Outgoing Webhook Information 1.png │ │ │ │ ├── 8 - Outgoing Webhook Information 2.png │ │ │ │ └── 9 - Outgoing Webhook Created.png │ │ │ └── validate.js │ │ ├── rocketchat │ │ │ ├── README.MD │ │ │ ├── get.js │ │ │ ├── hash.js │ │ │ ├── info.json │ │ │ ├── init.js │ │ │ ├── post.js │ │ │ ├── reply.js │ │ │ ├── screenshots │ │ │ │ ├── 01 - Connection Details.png │ │ │ │ ├── 02 - Integration Settings 01.png │ │ │ │ └── 03 - Integration Settings 02.png │ │ │ └── validate.js │ │ ├── slack │ │ │ ├── get.js │ │ │ ├── hash.js │ │ │ ├── info.json │ │ │ ├── init.js │ │ │ ├── post.js │ │ │ ├── reply.js │ │ │ └── validate.js │ │ ├── twilio │ │ │ ├── get.js │ │ │ ├── hash.js │ │ │ ├── info.json │ │ │ ├── init.js │ │ │ ├── post.js │ │ │ ├── reply.js │ │ │ └── validate.js │ │ └── web-demo │ │ │ ├── README.MD │ │ │ ├── get.js │ │ │ ├── info.json │ │ │ ├── init.js │ │ │ ├── post.js │ │ │ ├── reply.js │ │ │ ├── screenshots │ │ │ ├── 01 - Share icon.png │ │ │ ├── 02 - Web demo channel.png │ │ │ └── 03 - Agent custom message.png │ │ │ └── validate.js │ ├── errors │ │ ├── es.error-handler.js │ │ ├── global.default-error.js │ │ ├── global.invalid-actions-from-agent.js │ │ ├── global.invalid-actions-sayings-count.js │ │ ├── global.invalid-agent-train.js │ │ ├── global.invalid-keywords-from-agent.js │ │ ├── global.not-found-error.js │ │ ├── global.over-limit.js │ │ ├── global.parse-error.js │ │ ├── redis.error-handler.js │ │ ├── redis.not-linked-error.js │ │ └── redis.only-one-linked-error.js │ ├── index.js │ ├── init │ │ ├── default-group-policy.init.js │ │ ├── default-settings.init.js │ │ ├── default-user.init.js │ │ └── server-status.init.js │ ├── models │ │ ├── access-control.model.js │ │ ├── action.model.js │ │ ├── action.response.model.js │ │ ├── action.response.rich-response.model.js │ │ ├── agent.model.js │ │ ├── category.model.js │ │ ├── connection.model.js │ │ ├── context.model.js │ │ ├── document.model.js │ │ ├── keyword-example.model.js │ │ ├── keyword.model.js │ │ ├── log.model.js │ │ ├── modifier.model.js │ │ ├── modifier.saying.model.js │ │ ├── parse.model.js │ │ ├── postFormat.model.js │ │ ├── saying.keyword.model.js │ │ ├── saying.model.js │ │ ├── server.model.js │ │ ├── settings.model.js │ │ ├── slot.model.js │ │ ├── user-account.model.js │ │ ├── user-identity.model.js │ │ └── webhook.model.js │ ├── rich-responses │ │ ├── audio │ │ │ └── info.json │ │ ├── button │ │ │ └── info.json │ │ ├── card │ │ │ └── info.json │ │ ├── chart │ │ │ └── info.json │ │ ├── collapsible │ │ │ └── info.json │ │ ├── image │ │ │ └── info.json │ │ ├── index.js │ │ ├── location │ │ │ └── info.json │ │ ├── quick-response │ │ │ └── info.json │ │ ├── rich-text │ │ │ └── info.json │ │ └── video │ │ │ └── info.json │ ├── routes │ │ ├── access-control.routes.js │ │ ├── access-control │ │ │ ├── access-control.bulk-update-group.route.js │ │ │ ├── access-control.create-group.route.js │ │ │ ├── access-control.find-group-by-name.route.js │ │ │ ├── access-control.remove-group.route.js │ │ │ ├── access-control.update-group.route.js │ │ │ └── access-control.validate.route.js │ │ ├── agent.routes.js │ │ ├── agent │ │ │ ├── agent.converse.route.js │ │ │ ├── agent.create-action.route.js │ │ │ ├── agent.create-agent-version.route.js │ │ │ ├── agent.create-category.route.js │ │ │ ├── agent.create-keyword.route.js │ │ │ ├── agent.create-post-format.route.js │ │ │ ├── agent.create-saying-in-domain.route.js │ │ │ ├── agent.create-webhook-in-action.route.js │ │ │ ├── agent.create-webhook.route.js │ │ │ ├── agent.create.route.js │ │ │ ├── agent.export.route.js │ │ │ ├── agent.find-all-agent-versions.route.js │ │ │ ├── agent.find-all-documents.route.js │ │ │ ├── agent.find-all-sayings.route.js │ │ │ ├── agent.find-all-sessions.route.js │ │ │ ├── agent.find-all-settings.route.js │ │ │ ├── agent.find-all-training-tests.route.js │ │ │ ├── agent.find-setting-by-name.route.js │ │ │ ├── agent.identify-keywords.route.js │ │ │ ├── agent.import-category.route.js │ │ │ ├── agent.import.route.js │ │ │ ├── agent.load-agent-version-into-agent.route.js │ │ │ ├── agent.parse-get.route.js │ │ │ ├── agent.parse-post.route.js │ │ │ ├── agent.recognize-updated-keywords.route.js │ │ │ ├── agent.remove-action.route.js │ │ │ ├── agent.remove-agent-version.route.js │ │ │ ├── agent.remove-category.route.js │ │ │ ├── agent.remove-keyword.route.js │ │ │ ├── agent.remove-post-format-in-action.route.js │ │ │ ├── agent.remove-post-format.route.js │ │ │ ├── agent.remove-saying-in-domain.route.js │ │ │ ├── agent.remove-webhook-in-action.route.js │ │ │ ├── agent.remove-webhook.route.js │ │ │ ├── agent.remove.route.js │ │ │ ├── agent.test-train.route.js │ │ │ ├── agent.train-category.route.js │ │ │ ├── agent.train.route.js │ │ │ ├── agent.update-action.route.js │ │ │ ├── agent.update-agent-version.route.js │ │ │ ├── agent.update-all-settings.route.js │ │ │ ├── agent.update-by-id.route.js │ │ │ ├── agent.update-category.route.js │ │ │ ├── agent.update-keyword.route.js │ │ │ ├── agent.update-post-format.route.js │ │ │ ├── agent.update-saying-in-category.route.js │ │ │ ├── agent.update-webhook-in-action.route.js │ │ │ ├── agent.update-webhook.route.js │ │ │ └── agent.upsert-post-format-in-action.route.js │ │ ├── auth.routes.js │ │ ├── category.routes.js │ │ ├── category │ │ │ └── category.list-prebuilt.route.js │ │ ├── channel.route.js │ │ ├── channels │ │ │ └── channel.list.route.js │ │ ├── connection.route.js │ │ ├── connections │ │ │ ├── connection.create.route.js │ │ │ ├── connection.delete.route.js │ │ │ ├── connection.get.route.js │ │ │ ├── connection.post.route.js │ │ │ └── connection.update-by-id.route.js │ │ ├── context.routes.js │ │ ├── context │ │ │ ├── context.create.route.js │ │ │ ├── context.find-by-session.route.js │ │ │ ├── context.find-docs-by-session.route.js │ │ │ ├── context.remove.route.js │ │ │ └── context.update.route.js │ │ ├── document.routes.js │ │ ├── document │ │ │ ├── document.create.route.js │ │ │ ├── document.delete-by-query.route.js │ │ │ ├── document.find-by-id.route.js │ │ │ ├── document.remove.route.js │ │ │ ├── document.search.route.js │ │ │ └── document.update.route.js │ │ ├── global │ │ │ ├── global.find-all.route.js │ │ │ ├── global.find-by-id.route.js │ │ │ ├── global.find-in-model-path.route.js │ │ │ └── global.search-by-field.route.js │ │ ├── log.routes.js │ │ ├── log │ │ │ ├── log.find-all-logs.route.js │ │ │ └── log.search.route.js │ │ ├── rich-responses.route.js │ │ ├── rich-responses │ │ │ └── rich-response.list.route.js │ │ ├── server.routes.js │ │ ├── server │ │ │ └── server.get-info.route.js │ │ ├── settings.routes.js │ │ ├── settings │ │ │ ├── settings.bulk-create-settings.route.js │ │ │ ├── settings.bulk-update-settings.route.js │ │ │ ├── settings.create.route.js │ │ │ ├── settings.find-all.route.js │ │ │ ├── settings.find-by-name.route.js │ │ │ └── settings.update-by-name.route.js │ │ ├── user.routes.js │ │ └── user │ │ │ ├── user.add-identity.route.js │ │ │ ├── user.create.route.js │ │ │ ├── user.current.route.js │ │ │ ├── user.find-all.route.js │ │ │ ├── user.find-by-id.route.js │ │ │ ├── user.remove.route.js │ │ │ ├── user.update-by-id.route.js │ │ │ └── user.validate.route.js │ ├── services │ │ ├── access-control.services.js │ │ ├── access-controll │ │ │ ├── access-control.bulk-update.service.js │ │ │ ├── access-control.find-by-name.service.js │ │ │ ├── access-control.remove.service.js │ │ │ ├── access-control.upsert.service.js │ │ │ └── access-control.validate.service.js │ │ ├── action.services.js │ │ ├── action │ │ │ ├── action.remove.service.js │ │ │ ├── action.split-added-old-removed-ids.service.js │ │ │ ├── action.update-webhook.service.js │ │ │ └── action.upsert.service.js │ │ ├── agent-version.services.js │ │ ├── agent-version │ │ │ ├── agent-version.create.service.js │ │ │ └── agent-version.delete.service.js │ │ ├── agent.services.js │ │ ├── agent │ │ │ ├── agent.converse-call-webhook.service.js │ │ │ ├── agent.converse-compile-response-templates.service.js │ │ │ ├── agent.converse-compile-rich-responses-templates.service.js │ │ │ ├── agent.converse-fill-action-slots.service.js │ │ │ ├── agent.converse-fulfill-empty-slots-with-saved-values.service.js │ │ │ ├── agent.converse-generate-automatic-actions-quick-responses.service.js │ │ │ ├── agent.converse-generate-automatic-missing-slot-quick-responses.service.js │ │ │ ├── agent.converse-generate-response-fallback.service.js │ │ │ ├── agent.converse-generate-response-welcome.service.js │ │ │ ├── agent.converse-generate-response.service.js │ │ │ ├── agent.converse-get-best-rasa-result.service.js │ │ │ ├── agent.converse-get-keywords-from-rasa-results.js │ │ │ ├── agent.converse-most-recent-action-should-be-ignored.service.js │ │ │ ├── agent.converse-process-post-format.js │ │ │ ├── agent.converse-send-response-to-ubiquity.js │ │ │ ├── agent.converse.service.js │ │ │ ├── agent.create-action.service.js │ │ │ ├── agent.create-agent-version.service.js │ │ │ ├── agent.create-category.service.js │ │ │ ├── agent.create-keyword.service.js │ │ │ ├── agent.create-post-format.service.js │ │ │ ├── agent.create-webhook.service.js │ │ │ ├── agent.create.service.js │ │ │ ├── agent.export.service.js │ │ │ ├── agent.find-all-agent-versions.service.js │ │ │ ├── agent.find-all-documents.service.js │ │ │ ├── agent.find-all-sayings.service.js │ │ │ ├── agent.find-all-sessions.service.js │ │ │ ├── agent.find-all-settings.service.js │ │ │ ├── agent.find-all-training-tests.service.js │ │ │ ├── agent.find-setting-by-name.service.js │ │ │ ├── agent.get-trained-categories.service.js │ │ │ ├── agent.identify-keywords.service.js │ │ │ ├── agent.import-category.service.js │ │ │ ├── agent.import.service.js │ │ │ ├── agent.is-model-unique.service.js │ │ │ ├── agent.load-agent-version-into-agent.service.js │ │ │ ├── agent.parse-duckling-keywords.service.js │ │ │ ├── agent.parse-rasa-keywords.service.js │ │ │ ├── agent.parse-regex-keywords.service.js │ │ │ ├── agent.parse.service.js │ │ │ ├── agent.recognize-updated-keywords.service.js │ │ │ ├── agent.remove-action.service.js │ │ │ ├── agent.remove-agent-version.service.js │ │ │ ├── agent.remove-category.service.js │ │ │ ├── agent.remove-keyword.service.js │ │ │ ├── agent.remove-post-format-in-action.service.js │ │ │ ├── agent.remove-post-format.service.js │ │ │ ├── agent.remove-saying-in-category.service.js │ │ │ ├── agent.remove-webhook-in-action.service.js │ │ │ ├── agent.remove-webhook.service.js │ │ │ ├── agent.remove.service.js │ │ │ ├── agent.test.train.service.js │ │ │ ├── agent.train-category.service.js │ │ │ ├── agent.train.service.js │ │ │ ├── agent.update-action.service.js │ │ │ ├── agent.update-agent-version.service.js │ │ │ ├── agent.update-all-settings.service.js │ │ │ ├── agent.update-by-id.service.js │ │ │ ├── agent.update-category.service.js │ │ │ ├── agent.update-keyword.service.js │ │ │ ├── agent.update-post-format.service.js │ │ │ ├── agent.update-webhook.service.js │ │ │ ├── agent.upsert-post-format-in-action.service.js │ │ │ ├── agent.upsert-saying-in-category.service.js │ │ │ └── agent.upsert-webhook-in-action.service.js │ │ ├── category.services.js │ │ ├── category │ │ │ ├── category.create.service.js │ │ │ ├── category.find-all-by-ids.service.js │ │ │ ├── category.find-by-id.service.js │ │ │ ├── category.generate-training-data.service.js │ │ │ ├── category.info.service.js │ │ │ ├── category.link-keywords.service.js │ │ │ ├── category.remove.service.js │ │ │ ├── category.train.service.js │ │ │ └── category.unlink-keywords.service.js │ │ ├── channel.services.js │ │ ├── channel │ │ │ ├── channel.get.service.js │ │ │ ├── channel.hash.service.js │ │ │ ├── channel.info.service.js │ │ │ ├── channel.init.service.js │ │ │ ├── channel.post.service.js │ │ │ ├── channel.reply.service.js │ │ │ └── channel.validate.service.js │ │ ├── connection.services.js │ │ ├── connections │ │ │ ├── connection.create.service.js │ │ │ ├── connection.delete.service.js │ │ │ ├── connection.get.service.js │ │ │ ├── connection.post.service.js │ │ │ └── connection.update-by-id.service.js │ │ ├── context.services.js │ │ ├── context │ │ │ ├── context.create.service.js │ │ │ ├── context.find-by-session.service.js │ │ │ ├── context.find-docs-by-session.service.js │ │ │ ├── context.find-or-create-session.service.js │ │ │ ├── context.remove-by-session.service.js │ │ │ └── context.update.service.js │ │ ├── document.services.js │ │ ├── document │ │ │ ├── document.create.service.js │ │ │ ├── document.delete-by-query.service.js │ │ │ ├── document.find-all-sessions.js │ │ │ ├── document.find-by-agent-id.service.js │ │ │ ├── document.find-by-id.service.js │ │ │ ├── document.remove.service.js │ │ │ ├── document.search.service.js │ │ │ └── document.update.service.js │ │ ├── duckling.services.js │ │ ├── duckling │ │ │ ├── duckling.convert-interval.service.js │ │ │ └── duckling.parse.service.js │ │ ├── global.services.js │ │ ├── global │ │ │ ├── global.find-all.service.js │ │ │ ├── global.find-by-id.service.js │ │ │ ├── global.find-in-model-path.service.js │ │ │ ├── global.get-all-model-in-path.service.js │ │ │ ├── global.load-all-by-ids.service.js │ │ │ ├── global.load-all-linked.service.js │ │ │ ├── global.load-first-linked.service.js │ │ │ ├── global.load-with-includes.service.js │ │ │ ├── global.search-by-field.service.js │ │ │ └── global.tool-cartesian-product.service.js │ │ ├── keyword.services.js │ │ ├── keyword │ │ │ ├── keyword.combinations-from-sayings.service.js │ │ │ ├── keyword.create.service.js │ │ │ ├── keyword.parse-sys-value.service.js │ │ │ ├── keyword.parse-system-keywords-duckling.service.js │ │ │ ├── keyword.parse-system-keywords-regex.service.js │ │ │ ├── keyword.parse-system-keywords.service.js │ │ │ ├── keyword.remove.service.js │ │ │ └── keyword.split-added-old-removed-ids.service.js │ │ ├── log.services.js │ │ ├── log │ │ │ ├── log.find-all.service.js │ │ │ └── log.search.service.js │ │ ├── post-format.services.js │ │ ├── post-format │ │ │ ├── post-format.create.service.js │ │ │ ├── post-format.find-all-by-ids.service.js │ │ │ ├── post-format.remove.service.js │ │ │ └── post-format.update-by-id.service.js │ │ ├── rasa-nlu.services.js │ │ ├── rasa-nlu │ │ │ ├── rasa-nlu.parse.service.js │ │ │ └── rasa-nlu.train.service.js │ │ ├── rich-response.services.js │ │ ├── rich-response │ │ │ └── rich-response.info.service.js │ │ ├── saying.services.js │ │ ├── saying │ │ │ └── saying.remove.service.js │ │ ├── security.services.js │ │ ├── server.services.js │ │ ├── server │ │ │ ├── server.create.service.js │ │ │ ├── server.get.service.js │ │ │ └── server.update.service.js │ │ ├── settings.services.js │ │ ├── settings │ │ │ ├── settings.bulk-create-settings.service.js │ │ │ ├── settings.bulk-update-settings.service.js │ │ │ ├── settings.create.service.js │ │ │ ├── settings.find-all.service.js │ │ │ ├── settings.find-by-name.service.js │ │ │ └── settings.update-by-name.service.js │ │ ├── training-test.services.js │ │ ├── training-test │ │ │ ├── training-test.create.service.js │ │ │ └── training-test.find-by-agent-id.service.js │ │ ├── user.services.js │ │ ├── user │ │ │ ├── user.add-identity.service.js │ │ │ ├── user.authorize-oauth.service.js │ │ │ ├── user.create-account.service.js │ │ │ ├── user.find-all-identities.service.js │ │ │ ├── user.find-by-id.service.js │ │ │ ├── user.no-auth-user.service.js │ │ │ ├── user.remove-by-id.service.js │ │ │ ├── user.update-by-id.service.js │ │ │ └── user.validate.service.js │ │ ├── webhook.services.js │ │ └── webhook │ │ │ ├── webhook.create.service.js │ │ │ ├── webhook.remove.service.js │ │ │ └── webhook.update.service.js │ ├── validators │ │ ├── access-control.validator.js │ │ ├── action.validator.js │ │ ├── agent.validator.js │ │ ├── connection.validator.js │ │ ├── context.validator.js │ │ ├── document.validator.js │ │ ├── global.validator.js │ │ ├── keyword.validator.js │ │ ├── log.validator.js │ │ ├── server.validator.js │ │ ├── settings.validator.js │ │ └── user.validator.js │ └── websocket │ │ ├── agent.ws.js │ │ ├── connection.chatWidgetAndDemo.ws.js │ │ ├── connection.ws.js │ │ ├── doc.stats.ws.js │ │ ├── doc.ws.js │ │ ├── index.js │ │ ├── response.ws.js │ │ ├── server.ws.js │ │ └── session.ws.js ├── package.json ├── server │ ├── .env-keep │ ├── index.js │ ├── manifest.js │ └── plugins │ │ ├── authentication │ │ ├── index.js │ │ └── strategies │ │ │ ├── azuread.js │ │ │ ├── github.js │ │ │ ├── index.js │ │ │ ├── session.js │ │ │ ├── simple.js │ │ │ └── twitter.js │ │ ├── duckling │ │ ├── index.js │ │ ├── lib │ │ │ └── initialize-models.js │ │ └── models │ │ │ ├── index.js │ │ │ └── parse.duckling-model.js │ │ ├── es │ │ ├── index.js │ │ ├── lib │ │ │ ├── base-model.js │ │ │ └── initialize-models.js │ │ └── models │ │ │ ├── document.es-model.js │ │ │ ├── index.js │ │ │ ├── log.es-model.js │ │ │ └── trainingtest.es.js │ │ ├── gbac │ │ └── index.js │ │ ├── handlebars │ │ ├── helpers │ │ │ ├── and-or-list.handlebars-helper.js │ │ │ ├── date-time-format.handlebars-helper.js │ │ │ ├── index.js │ │ │ ├── intl.handlebars-helper.js │ │ │ ├── json-path.handlebars-helper.js │ │ │ ├── md5.handlebars-helper.js │ │ │ ├── misc.handlebars-helper.js │ │ │ ├── moment.handlebars-helper.js │ │ │ ├── nearest-date.handlebars-helper.js │ │ │ ├── numeral.handlebars-helper.js │ │ │ └── to-xml.handlebars-helper.js │ │ ├── index.js │ │ └── lib │ │ │ └── initialize-helpers.js │ │ ├── hapi-abac │ │ └── index.js │ │ ├── hapi-gbac │ │ └── index.js │ │ ├── rasa-nlu │ │ ├── index.js │ │ ├── lib │ │ │ └── initialize-models.js │ │ └── models │ │ │ ├── index.js │ │ │ ├── models.rasa-nlu-model.js │ │ │ ├── parse.rasa-nlu-model.js │ │ │ ├── status.rasa-nlu-model.js │ │ │ └── train.rasa-nlu-model.js │ │ ├── redis-messaging │ │ └── index.js │ │ ├── redis │ │ ├── index.js │ │ ├── lib │ │ │ ├── base-model.js │ │ │ └── initialize-models.js │ │ └── models │ │ │ ├── access-policy-group.redis-model.js │ │ │ ├── action.redis-model.js │ │ │ ├── agent.redis-model.js │ │ │ ├── agentVersion.redis-model.js │ │ │ ├── category.redis-model.js │ │ │ ├── connection.redis-model.js │ │ │ ├── context.redis-model.js │ │ │ ├── index.js │ │ │ ├── keyword.redis-model.js │ │ │ ├── postFormat.redis-model.js │ │ │ ├── saying.redis-model.js │ │ │ ├── server.redis-model.js │ │ │ ├── settings.redis-model.js │ │ │ ├── shared-schemas │ │ │ └── agent-schema.js │ │ │ ├── userAccount.redis-model.js │ │ │ ├── userIdentity.redis-model.js │ │ │ └── webhook.redis-model.js │ │ └── swagger.js ├── test │ ├── 01 - api.test.js │ ├── 02 - agent.test.js │ ├── 03 - train.converse.test.js │ ├── 04 - category.test.js │ ├── 05 - channel.test.js │ ├── 06 - connection.test.js │ └── data │ │ ├── importAgent.json │ │ ├── importAgentConverse.json │ │ ├── postAction.json │ │ ├── postAgent.json │ │ ├── postCategory.json │ │ └── postKeyword.json ├── util │ ├── constants.js │ ├── default-settings.json │ ├── env.js │ ├── logger.js │ ├── server-info.json │ └── service-timing-wrapper.js └── yarn.lock ├── compose ├── basic-auth-compose.yml ├── build-compose.yml ├── develop-compose.yml ├── gateway-compose.yml ├── kibana-compose.yml ├── ssl-compose.yml └── test-compose.yml ├── docker-compose.override.yml ├── docker-compose.yml ├── docs ├── README.md ├── concepts │ ├── action-chains.md │ ├── action-tags.md │ ├── modifiers.md │ └── ubiquity.md ├── developer │ ├── docker.md │ └── getting-started.md ├── getting-started │ ├── advanced-installation.md │ ├── authentication.md │ ├── basic-installation.md │ └── first-5-minutes.md ├── img │ ├── articulate-logo.png │ ├── chains │ │ └── offer-help.PNG │ ├── diagram.png │ ├── getting-started │ │ ├── action-dropdown-empty.PNG │ │ ├── category-dropdown-empty.PNG │ │ ├── copy-modal.PNG │ │ ├── create-action-main.PNG │ │ ├── create-action-response.PNG │ │ ├── create-agent.PNG │ │ ├── create-category.PNG │ │ ├── cya.PNG │ │ ├── hello-world.PNG │ │ ├── home.PNG │ │ ├── play.PNG │ │ ├── review.PNG │ │ ├── sayings-copy.PNG │ │ ├── sayings-empty.PNG │ │ ├── sayings-more.PNG │ │ ├── sayings-multi-action.PNG │ │ ├── sayings.PNG │ │ └── training-complete.PNG │ ├── laptop-mockup.png │ ├── main-ilus.png │ └── screens │ │ ├── createAgent.png │ │ ├── createDomain.png │ │ ├── createEntity.png │ │ ├── createIntent1.png │ │ ├── createIntent2.png │ │ ├── domainList.png │ │ ├── entityList.png │ │ ├── intentList.png │ │ └── welcome.png ├── index.html ├── reference │ ├── faq.md │ └── terms.md ├── screens │ └── agent.md └── style.css ├── duckling ├── Dockerfile └── README.md ├── init-letsencrypt.sh ├── local-storage ├── elasticsearch │ ├── config │ │ └── elasticsearch.yml │ ├── data │ │ └── .gitignore │ └── docker-healthcheck.sh ├── filebeat │ ├── data │ │ └── .gitignore │ └── filebeat.yml ├── nginx │ ├── nginx-http.conf │ ├── nginx.conf │ ├── nginx.dev.conf │ └── nginx.ssl.conf ├── rasa │ ├── nlu-model │ │ └── .gitignore │ ├── rasa-config-tf.yml │ └── rasa-config.yml └── redis-data │ └── .gitignore ├── package.sh ├── rasa ├── Dockerfile └── README.md └── ui ├── .dockerignore ├── .editorconfig ├── .env.example ├── .eslintrc.js ├── .gitattributes ├── .github └── lock.yml ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .stylelintrc ├── .travis.yml ├── .yarnrc ├── Dockerfile ├── LICENSE.md ├── README.md ├── app ├── .htaccess ├── .nginx.conf ├── app.js ├── components │ ├── AccessControl │ │ └── index.js │ ├── AppContent │ │ ├── index.js │ │ └── messages.js │ ├── AppHeader │ │ ├── index.js │ │ └── messages.js │ ├── AutoComplete │ │ └── index.js │ ├── CategoriesLogos │ │ └── index.js │ ├── ChannelsColors │ │ └── index.js │ ├── ChannelsLogos │ │ └── index.js │ ├── ChipInput │ │ └── index.js │ ├── CodeModal │ │ ├── index.js │ │ └── messages.js │ ├── ColorPicker │ │ └── index.js │ ├── ContentHeader │ │ └── index.js │ ├── ConversationBar │ │ ├── Loadable.js │ │ ├── components │ │ │ ├── Notifications.js │ │ │ └── TestTrainNotification.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── DeleteFooter │ │ ├── index.js │ │ └── messages.js │ ├── DucklingSettings │ │ ├── index.js │ │ └── messages.js │ ├── ExitModal │ │ ├── index.js │ │ └── messages.js │ ├── FilterSelect │ │ ├── index.js │ │ └── messages.js │ ├── Gravatar │ │ ├── Gravatar1.js │ │ ├── Gravatar10.js │ │ ├── Gravatar11.js │ │ ├── Gravatar12.js │ │ ├── Gravatar13.js │ │ ├── Gravatar14.js │ │ ├── Gravatar15.js │ │ ├── Gravatar16.js │ │ ├── Gravatar17.js │ │ ├── Gravatar2.js │ │ ├── Gravatar3.js │ │ ├── Gravatar4.js │ │ ├── Gravatar5.js │ │ ├── Gravatar6.js │ │ ├── Gravatar7.js │ │ ├── Gravatar8.js │ │ ├── Gravatar9.js │ │ └── index.js │ ├── LanguageSelect │ │ └── index.js │ ├── LoadingWave │ │ └── index.js │ ├── MainTab │ │ ├── index.js │ │ └── messages.js │ ├── PopoverFilter │ │ ├── components │ │ │ └── ChipGroup.js │ │ ├── index.js │ │ └── messages.js │ ├── PrivateRoute │ │ └── index.js │ ├── RasaSettings │ │ ├── index.js │ │ └── messages.js │ ├── ResponseSettings │ │ ├── index.js │ │ └── messages.js │ ├── RichResponsesIcons │ │ └── index.js │ ├── SaveButton │ │ └── index.js │ ├── Star │ │ └── index.js │ ├── StyledTable │ │ ├── components │ │ │ ├── CopyImageCell.js │ │ │ ├── CopyToClipboardImageCell.js │ │ │ ├── DeleteImageCell.js │ │ │ ├── DropdownCell.js │ │ │ ├── ImageCell.js │ │ │ ├── PercentCell.js │ │ │ ├── PlayImageCell.js │ │ │ ├── StyledRow.js │ │ │ ├── TextCell.js │ │ │ └── TryImageCell.js │ │ └── index.js │ ├── TrainButton │ │ ├── index.js │ │ └── messages.js │ ├── VersionsModal │ │ ├── index.js │ │ └── messages.js │ └── WebhookSettings │ │ ├── index.js │ │ └── messages.js ├── configureStore.js ├── containers │ ├── ActionPage │ │ ├── Components │ │ │ ├── ActionForm.js │ │ │ ├── MainTab.js │ │ │ ├── ResponseForm.js │ │ │ ├── ResponseRow.js │ │ │ ├── SingleHighlightedSaying.js │ │ │ ├── SlotForm.js │ │ │ ├── SlotsForm.js │ │ │ ├── SortableSlotTab.js │ │ │ ├── SortableSlotsTabs.js │ │ │ ├── TextPromptRow.js │ │ │ └── WebhookForm.js │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── AddCategoryPage │ │ ├── Components │ │ │ ├── ActionButtons.js │ │ │ ├── CategoryCard.js │ │ │ ├── CategoryDataForm.js │ │ │ └── Form.js │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── AgentPage │ │ ├── Components │ │ │ ├── AgentAccessControlSettings.js │ │ │ ├── AgentDataForm.js │ │ │ ├── AgentParametersForm.js │ │ │ ├── AgentSettingsForm.js │ │ │ ├── AgentVersionsSettings.js │ │ │ ├── AutomaticQuickRepliesSettings.js │ │ │ ├── Form.js │ │ │ └── TrainingSettings.js │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── AgentsPage │ │ ├── Components │ │ │ ├── AgentsCards.js │ │ │ ├── ConnectionsCards.js │ │ │ ├── GetStarted.js │ │ │ └── MainContentHeader.js │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── AnalyticsPage │ │ ├── Components │ │ │ └── Form.js │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── App │ │ ├── actions.js │ │ ├── constants.js │ │ ├── index.js │ │ ├── reducer.js │ │ ├── saga.js │ │ ├── selectors.js │ │ └── tests │ │ │ ├── __snapshots__ │ │ │ └── index.test.js.snap │ │ │ ├── actions.test.js │ │ │ ├── index.test.js │ │ │ ├── reducer.test.js │ │ │ └── selectors.test.js │ ├── CategoryPage │ │ ├── Components │ │ │ ├── ActionButtons.js │ │ │ ├── CategoryDataForm.js │ │ │ ├── CategoryParametersForm.js │ │ │ └── Form.js │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── CheatSheetPage │ │ ├── Loadable.js │ │ ├── components │ │ │ └── NotEnabledAgent.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── ConnectionPage │ │ ├── Components │ │ │ ├── ChannelCard.js │ │ │ ├── ConnectionForm.js │ │ │ ├── DetailsForm.js │ │ │ ├── MainTab.js │ │ │ └── actions.json │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── DialoguePage │ │ ├── Components │ │ │ ├── ActionsDataForm.js │ │ │ ├── Form.js │ │ │ ├── HighlightedSaying.js │ │ │ ├── KeywordsDataForm.js │ │ │ ├── SayingRow.js │ │ │ └── SayingsDataForm.js │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── KeywordsEditPage │ │ ├── Components │ │ │ ├── HighlightedSaying.js │ │ │ ├── KeywordForm.js │ │ │ ├── MainTab.js │ │ │ ├── ModifierForm.js │ │ │ ├── ModifierSayingRow.js │ │ │ ├── ModifiersForm.js │ │ │ ├── SortableModifierTab.js │ │ │ ├── SortableModifiersTabs.js │ │ │ └── ValuesForm.js │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── LanguageProvider │ │ ├── actions.js │ │ ├── constants.js │ │ ├── index.js │ │ ├── reducer.js │ │ ├── selectors.js │ │ └── tests │ │ │ ├── actions.test.js │ │ │ ├── index.test.js │ │ │ ├── reducer.test.js │ │ │ └── selectors.test.js │ ├── MissingAPIPage │ │ ├── Loadable.js │ │ ├── index.js │ │ └── messages.js │ ├── NotFoundPage │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── tests │ │ │ └── index.test.js │ ├── ReviewPage │ │ ├── Components │ │ │ ├── Form.js │ │ │ ├── HighlightedSaying.js │ │ │ ├── Logs.js │ │ │ ├── SayingRow.js │ │ │ ├── SayingsDataForm.js │ │ │ ├── SessionRow.js │ │ │ ├── SessionsDataForm.js │ │ │ ├── Trainings.js │ │ │ └── TrainingsRow.js │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── SayingsInfoPage │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── SettingsPage │ │ ├── Components │ │ │ ├── ActionButtons.js │ │ │ ├── Form.js │ │ │ ├── GeneralSettings.js │ │ │ ├── GroupAndUsersForm.js │ │ │ ├── GroupPolicyTabs.js │ │ │ └── SettingsDataForm.js │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── SharedChatPage │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── TrainingTestSummaryPage │ │ ├── Components │ │ │ ├── Form.js │ │ │ └── MainTab.js │ │ ├── Loadable.js │ │ ├── index.js │ │ └── messages.js │ ├── UserAuthPage │ │ ├── Loadable.js │ │ ├── components │ │ │ ├── LoginForm.js │ │ │ └── SignUpForm.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ ├── UserPage │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js │ └── UsersPage │ │ ├── Components │ │ ├── ActionButtons.js │ │ ├── Form.js │ │ └── UsersListForm.js │ │ ├── Loadable.js │ │ ├── index.js │ │ ├── messages.js │ │ └── saga.js ├── global-styles.js ├── i18n.js ├── images │ ├── 404-img.svg │ ├── add-action-icon.svg │ ├── add-pipeline-icon.svg │ ├── agents-icon.svg │ ├── apply-to-chat-icon.svg │ ├── audio-icon.svg │ ├── broken-connection-icon.svg │ ├── button-icon.svg │ ├── calculator.svg │ ├── cancel-icon.svg │ ├── card-carousel-icon.svg │ ├── chart-icon.svg │ ├── chat-icon.svg │ ├── chat-widget.svg │ ├── check-save-icon.svg │ ├── checkbox-checked-icon.svg │ ├── checkbox-unchecked-icon.svg │ ├── circle-disabled-icon.svg │ ├── circle-enabled-icon.svg │ ├── clear-icon.svg │ ├── closing-quotes.svg │ ├── collapsible-icon.svg │ ├── connection-arrow.svg │ ├── connection-icon.svg │ ├── currency.svg │ ├── download-icon-gray-success.svg │ ├── eraser-icon.svg │ ├── expand-enabled-icon.svg │ ├── expand-enabled-opened-icon.svg │ ├── expand-not-enabled-icon.svg │ ├── expand-not-enabled-opened-icon.svg │ ├── expand-single-icon.svg │ ├── expand-single-opened-icon.svg │ ├── expand-trimmed-single-icon.svg │ ├── export-icon-gray-fail.svg │ ├── export-icon-gray.svg │ ├── favicon.ico │ ├── fb-messenger.png │ ├── filter-black-icon.svg │ ├── filter-icon.svg │ ├── github.svg │ ├── google-assistant.png │ ├── grab-icon.svg │ ├── help-button-icon.svg │ ├── hyphen-icon.svg │ ├── icon-512x512.png │ ├── icon-analytics.svg │ ├── icon-copy.svg │ ├── icon-error-try.svg │ ├── icon-eye.svg │ ├── icon-goto.svg │ ├── icon-organize-outline.svg │ ├── icon-organize.svg │ ├── icon-review.svg │ ├── icon-try.svg │ ├── icon_search.svg │ ├── image-icon.svg │ ├── import-icon-gray-fail.svg │ ├── import-icon-gray-success.svg │ ├── import-icon-gray.svg │ ├── import-icon-green.svg │ ├── keywords-icon.svg │ ├── location-icon.svg │ ├── logo.svg │ ├── logout-icon.svg │ ├── mattermost.png │ ├── menu-icon.svg │ ├── missing-api.svg │ ├── multimedia-icon.svg │ ├── music.svg │ ├── news.svg │ ├── opening-quotes.svg │ ├── pencil-icon.svg │ ├── play-help-icon.svg │ ├── quick-response-icon.svg │ ├── refresh-icon.svg │ ├── rich-responses-icon.svg │ ├── rich-text-icon.svg │ ├── right-arrow-icon.svg │ ├── rocketchat.png │ ├── sayings-icon.svg │ ├── search-icon.svg │ ├── select-version.svg │ ├── settings-icon.svg │ ├── share-icon.svg │ ├── single-quotes-icon.svg │ ├── slack.png │ ├── small-talk.svg │ ├── training.svg │ ├── trash-icon.svg │ ├── twilio.png │ ├── user-icon-gray.svg │ ├── user-list-icon.svg │ ├── v-divider.svg │ ├── weather.svg │ ├── web-demo.png │ ├── x-icon.svg │ └── x-icon2.svg ├── index.html ├── reducers.js ├── tests │ ├── i18n.test.js │ └── store.test.js ├── translations │ ├── en.json │ ├── es.json │ ├── fr.json │ ├── pl.json │ └── pt.json └── utils │ ├── accessControl.js │ ├── apiMiddleware.js │ ├── checkStore.js │ ├── constants.js │ ├── cookies.js │ ├── extractTokensFromString.js │ ├── history.js │ ├── injectReducer.js │ ├── injectSaga.js │ ├── loadable.js │ ├── locationResolver.js │ ├── reducerInjectors.js │ ├── request.js │ ├── sagaInjectors.js │ ├── tests │ ├── checkStore.test.js │ ├── injectReducer.test.js │ ├── injectSaga.test.js │ ├── reducerInjectors.test.js │ ├── request.test.js │ └── sagaInjectors.test.js │ ├── theme.js │ └── video-react.css ├── appveyor.yml ├── babel.config.js ├── common ├── constants.js └── env.js ├── docker ├── auth.Dockerfile └── dev.Dockerfile ├── internals ├── generators │ ├── component │ │ ├── index.js │ │ ├── index.js.hbs │ │ ├── loadable.js.hbs │ │ ├── messages.js.hbs │ │ └── test.js.hbs │ ├── container │ │ ├── actions.js.hbs │ │ ├── actions.test.js.hbs │ │ ├── constants.js.hbs │ │ ├── index.js │ │ ├── index.js.hbs │ │ ├── messages.js.hbs │ │ ├── reducer.js.hbs │ │ ├── reducer.test.js.hbs │ │ ├── saga.js.hbs │ │ ├── saga.test.js.hbs │ │ ├── selectors.js.hbs │ │ ├── selectors.test.js.hbs │ │ └── test.js.hbs │ ├── index.js │ ├── language │ │ ├── add-locale-data.hbs │ │ ├── app-locale.hbs │ │ ├── format-translation-messages.hbs │ │ ├── index.js │ │ ├── intl-locale-data.hbs │ │ ├── polyfill-intl-locale.hbs │ │ ├── translation-messages.hbs │ │ └── translations-json.hbs │ └── utils │ │ └── componentExists.js ├── mocks │ ├── cssModule.js │ └── image.js ├── scripts │ ├── analyze.js │ ├── clean.js │ ├── extract-intl.js │ ├── generate-templates-for-linting.js │ ├── helpers │ │ ├── checkmark.js │ │ ├── get-npm-config.js │ │ ├── progress.js │ │ └── xmark.js │ ├── npmcheckversion.js │ └── setup.js ├── templates │ ├── app.js │ ├── configureStore.js │ ├── containers │ │ ├── App │ │ │ ├── constants.js │ │ │ ├── index.js │ │ │ ├── selectors.js │ │ │ └── tests │ │ │ │ ├── __snapshots__ │ │ │ │ └── index.test.js.snap │ │ │ │ ├── index.test.js │ │ │ │ └── selectors.test.js │ │ ├── HomePage │ │ │ ├── Loadable.js │ │ │ ├── index.js │ │ │ ├── messages.js │ │ │ └── tests │ │ │ │ ├── __snapshots__ │ │ │ │ └── index.test.js.snap │ │ │ │ └── index.test.js │ │ ├── LanguageProvider │ │ │ ├── actions.js │ │ │ ├── constants.js │ │ │ ├── index.js │ │ │ ├── reducer.js │ │ │ └── selectors.js │ │ └── NotFoundPage │ │ │ ├── Loadable.js │ │ │ ├── index.js │ │ │ ├── messages.js │ │ │ └── tests │ │ │ ├── __snapshots__ │ │ │ └── index.test.js.snap │ │ │ └── index.test.js │ ├── global-styles.js │ ├── i18n.js │ ├── index.html │ ├── reducers.js │ ├── tests │ │ ├── i18n.test.js │ │ └── store.test.js │ ├── translations │ │ └── en.json │ └── utils │ │ ├── checkStore.js │ │ ├── constants.js │ │ ├── history.js │ │ ├── injectReducer.js │ │ ├── injectSaga.js │ │ ├── loadable.js │ │ ├── reducerInjectors.js │ │ ├── sagaInjectors.js │ │ └── tests │ │ ├── checkStore.test.js │ │ ├── injectReducer.test.js │ │ ├── injectSaga.test.js │ │ ├── reducerInjectors.test.js │ │ └── sagaInjectors.test.js ├── testing │ └── test-bundler.js └── webpack │ ├── webpack.base.babel.js │ ├── webpack.dev.babel.js │ └── webpack.prod.babel.js ├── jest.config.js ├── package.json ├── server ├── argv.js ├── index.js ├── logger.js ├── middlewares │ ├── addDevMiddlewares.js │ ├── addProdMiddlewares.js │ └── frontendMiddleware.js └── port.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Cruft 2 | .DS_Store 3 | npm-debug.log 4 | .idea 5 | .vscode 6 | *.iml 7 | .env 8 | performance-timing.csv 9 | *.swp 10 | *.swo 11 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Issues 2 | > *If you're having trouble with Articulate we definitely want to help you. If you can provide a little bit of information it will make our troubleshooting job easier.* 3 | 4 | Please describe the issue you are having here and answer the question below. 5 | 6 | - Did you download a release or pull from Master? Which release? 7 | - What operating system are you running? 8 | - Are you running locally or in the cloud? 9 | - Which browser are you using? 10 | 11 | ---- 12 | 13 | ### Feature Request 14 | > *If you've got a feature request we want to hear it* 15 | 16 | Please desribe the feature you would like us to add. 17 | 18 | If possible provide the use case for the feature and how you would use it. 19 | -------------------------------------------------------------------------------- /api/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "esmodules": true 8 | } 9 | } 10 | ] 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /api/.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | # the .env settings are projected through the docker-compose environment block. 3 | # Lots of unexpected behavor will happen if you let the .env get pulled into 4 | # the build, so HIGHLY recommened .env is listed (blocked) on the following line: 5 | .env 6 | .git 7 | #es-* 8 | docker-compose.yml 9 | node_modules 10 | .vscode 11 | .idea 12 | -------------------------------------------------------------------------------- /api/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-hapi", 3 | "parserOptions": { 4 | "sourceType": "module", 5 | "ecmaVersion": 8, 6 | "ecmaFeatures": { 7 | "experimentalObjectRestSpread": true 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /api/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .tmp 3 | server/.env 4 | /.idea/ 5 | .compiled 6 | /dist/ 7 | /.vscode/ 8 | -------------------------------------------------------------------------------- /api/.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !lib/** 3 | -------------------------------------------------------------------------------- /api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:lts-jessie 2 | 3 | RUN apt-get update && apt-get install -y wget 4 | 5 | ENV DOCKERIZE_VERSION v0.6.1 6 | RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ 7 | && tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ 8 | && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz 9 | 10 | # Create app directory 11 | RUN mkdir -p /usr/src/app 12 | 13 | WORKDIR /usr/src/app 14 | RUN npm install -g yarn 15 | COPY package.json yarn.lock ./ 16 | RUN yarn install 17 | 18 | # Bundle app source 19 | COPY . /usr/src/app/ 20 | 21 | # Install app dependencies 22 | 23 | #EXPOSE 7500 24 | 25 | CMD dockerize -wait http://elasticsearch:9200 -timeout 5m yarn start:prod 26 | -------------------------------------------------------------------------------- /api/lib/.hc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | remove: ['models'], 3 | add: [ 4 | { 5 | place: 'init', 6 | list: true, 7 | method: 'services', 8 | after: ['plugins', 'register'] 9 | }, 10 | { 11 | place: 'websocket', 12 | list: true, 13 | method: 'services', 14 | after: ['plugins', 'register'] 15 | }] 16 | }; 17 | -------------------------------------------------------------------------------- /api/lib/categories/calculator/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Calculator", 3 | "uiColor": "#4A4A4A", 4 | "description": "Morning comes wheter you set the alarm or not", 5 | "documentation": "", 6 | "enabled": false, 7 | "data": { 8 | "categoryName": "calculator", 9 | "enabled": true, 10 | "actionThreshold": 0.5, 11 | "model": "", 12 | "extraTrainingData": true, 13 | "parameters": {} 14 | } 15 | } -------------------------------------------------------------------------------- /api/lib/categories/currency/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Currency", 3 | "uiColor": "#E38D25", 4 | "description": "Dollar, Euro, Pound, Yen. You name it.", 5 | "documentation": "", 6 | "enabled": false, 7 | "data": { 8 | "categoryName": "currency", 9 | "enabled": true, 10 | "actionThreshold": 0.5, 11 | "model": "", 12 | "extraTrainingData": true, 13 | "parameters": {} 14 | } 15 | } -------------------------------------------------------------------------------- /api/lib/categories/github/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Github", 3 | "uiColor": "#7a7a78", 4 | "description": "Handle github interactions", 5 | "documentation": "", 6 | "enabled": true, 7 | "data": { 8 | "categoryName": "github", 9 | "enabled": true, 10 | "actionThreshold": 0.5, 11 | "model": "", 12 | "extraTrainingData": true, 13 | "parameters": { 14 | "token": "", 15 | "repoPath": "" 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /api/lib/categories/index.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | const RequireDir = require('require-dir'); 4 | const dir = RequireDir('.', { recurse: true}); 5 | 6 | module.exports = dir 7 | -------------------------------------------------------------------------------- /api/lib/categories/music/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Music", 3 | "uiColor": "#303f9f", 4 | "description": "Get real control of your music", 5 | "documentation": "", 6 | "enabled": false, 7 | "data": { 8 | "categoryName": "music", 9 | "enabled": true, 10 | "actionThreshold": 0.5, 11 | "model": "", 12 | "extraTrainingData": true, 13 | "parameters": {} 14 | } 15 | } -------------------------------------------------------------------------------- /api/lib/categories/news/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "News", 3 | "uiColor": "#7a7a78", 4 | "description": "Search for news", 5 | "documentation": "", 6 | "enabled": true, 7 | "data": { 8 | "categoryName": "news", 9 | "enabled": true, 10 | "actionThreshold": 0.5, 11 | "model": "", 12 | "extraTrainingData": true, 13 | "parameters": { 14 | "token": "", 15 | "fetchedNewsNumber": "" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /api/lib/categories/small-talk/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Small Talk", 3 | "uiColor": "#00BD6F", 4 | "description": "Handling some common chit chat Items.", 5 | "documentation": "", 6 | "enabled": true, 7 | "data": { 8 | "categoryName": "small-talk", 9 | "enabled": true, 10 | "actionThreshold": 0.5, 11 | "model": "", 12 | "extraTrainingData": true, 13 | "parameters": {} 14 | } 15 | } -------------------------------------------------------------------------------- /api/lib/categories/weather/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Weather", 3 | "uiColor": "#44C3D8", 4 | "description": "Most common requests from users regarding weather (fulfilled by OpenWeatherMap)", 5 | "documentation": "", 6 | "enabled": true, 7 | "data": { 8 | "categoryName": "weather", 9 | "enabled": true, 10 | "actionThreshold": 0.5, 11 | "model": "", 12 | "extraTrainingData": true, 13 | "parameters": { 14 | "apiKey": "" 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /api/lib/channels/chat-widget/get.js: -------------------------------------------------------------------------------- 1 | module.exports = async function ({ connection, request }) { 2 | 3 | return { 4 | statusCode: 404 5 | } 6 | } -------------------------------------------------------------------------------- /api/lib/channels/chat-widget/init.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ data }) => { 2 | 3 | return data; 4 | } -------------------------------------------------------------------------------- /api/lib/channels/chat-widget/reply.js: -------------------------------------------------------------------------------- 1 | import { 2 | ROUTE_EXTERNAL, 3 | ROUTE_CONNECTION 4 | } from '../../../util/constants'; 5 | 6 | module.exports = async function ({ connection, event, response }) { 7 | event.server.publish(`/${ROUTE_CONNECTION}/${connection.id}/${ROUTE_EXTERNAL}/${event.sessionId}`, response); 8 | } 9 | -------------------------------------------------------------------------------- /api/lib/channels/chat-widget/validate.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | module.exports = { 4 | create: (details) => { 5 | const schema = { 6 | title: Joi.string().required(), 7 | subtitle: Joi.string().required(), 8 | senderPlaceHolder: Joi.string().required(), 9 | outgoingMessages: Joi.boolean(), 10 | waitTimeBetweenMessages: Joi.number(), 11 | useAgentWelcomeAction: Joi.boolean() 12 | }; 13 | 14 | return Joi.validate(details, schema) 15 | } 16 | }; -------------------------------------------------------------------------------- /api/lib/channels/facebook/get.js: -------------------------------------------------------------------------------- 1 | import Crypto from 'crypto'; 2 | 3 | module.exports = async function ({ connection, request }) { 4 | 5 | const data = request.query; 6 | 7 | const { 8 | verifyToken 9 | } = connection.details 10 | 11 | const mode = data['hub.mode'], 12 | token = data['hub.verify_token'], 13 | challenge = data['hub.challenge'] 14 | 15 | // Checks if a token and mode is in the query string of the request 16 | if (mode && token) { 17 | 18 | // Checks the mode and token sent is correct 19 | if (mode === 'subscribe' && token === verifyToken) { 20 | 21 | // TODO: Update model status 22 | return challenge 23 | // }) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /api/lib/channels/facebook/hash.js: -------------------------------------------------------------------------------- 1 | import Crypto from 'crypto'; 2 | 3 | module.exports = async function ({ event }) { 4 | 5 | const secret = { 6 | channel: event.sender.id 7 | } 8 | const hash = Crypto.createHmac('sha256', JSON.stringify(secret)).digest('hex');; 9 | 10 | return hash 11 | 12 | } -------------------------------------------------------------------------------- /api/lib/channels/facebook/init.js: -------------------------------------------------------------------------------- 1 | import Crypto from 'crypto'; 2 | 3 | module.exports = async function ({ data }) { 4 | 5 | data.details.verifyToken = Crypto.createHmac('sha256', JSON.stringify(data.agent + '-' + data.channel)).digest('hex'); 6 | data.status = 'created' 7 | 8 | return data; 9 | } -------------------------------------------------------------------------------- /api/lib/channels/facebook/screenshots/01 - App Dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/facebook/screenshots/01 - App Dashboard.png -------------------------------------------------------------------------------- /api/lib/channels/facebook/screenshots/02 - Products + Set UP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/facebook/screenshots/02 - Products + Set UP.png -------------------------------------------------------------------------------- /api/lib/channels/facebook/screenshots/03 - Page Selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/facebook/screenshots/03 - Page Selection.png -------------------------------------------------------------------------------- /api/lib/channels/facebook/screenshots/04 - Permissons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/facebook/screenshots/04 - Permissons.png -------------------------------------------------------------------------------- /api/lib/channels/facebook/screenshots/05 - Articulate Page Access Token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/facebook/screenshots/05 - Articulate Page Access Token.png -------------------------------------------------------------------------------- /api/lib/channels/facebook/screenshots/06 - App Secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/facebook/screenshots/06 - App Secret.png -------------------------------------------------------------------------------- /api/lib/channels/facebook/screenshots/07 - Connection Saved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/facebook/screenshots/07 - Connection Saved.png -------------------------------------------------------------------------------- /api/lib/channels/facebook/screenshots/08 - Subscribe To Events.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/facebook/screenshots/08 - Subscribe To Events.png -------------------------------------------------------------------------------- /api/lib/channels/facebook/screenshots/09 - Verify and Save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/facebook/screenshots/09 - Verify and Save.png -------------------------------------------------------------------------------- /api/lib/channels/facebook/screenshots/10 - Page subscription.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/facebook/screenshots/10 - Page subscription.png -------------------------------------------------------------------------------- /api/lib/channels/facebook/screenshots/11 - Page subscribed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/facebook/screenshots/11 - Page subscribed.png -------------------------------------------------------------------------------- /api/lib/channels/facebook/validate.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | module.exports = { 4 | create: (details) => { 5 | const schema = { 6 | pageAccessToken: Joi.string().required(), 7 | appSecret: Joi.string(), 8 | outgoingMessages: Joi.boolean(), 9 | waitTimeBetweenMessages: Joi.number(), 10 | useAgentWelcomeAction: Joi.boolean(), 11 | messageBeforeButtonResponse: Joi.string.required(), 12 | } 13 | 14 | return Joi.validate(details, schema) 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /api/lib/channels/google-home/get.js: -------------------------------------------------------------------------------- 1 | module.exports = async function ({ connection, request }) { 2 | 3 | return { 4 | statusCode: 404 5 | } 6 | } -------------------------------------------------------------------------------- /api/lib/channels/google-home/hash.js: -------------------------------------------------------------------------------- 1 | import Crypto from 'crypto'; 2 | 3 | module.exports = async function ({ event }) { 4 | 5 | const secret = { 6 | conversationId: event.conversation.conversationId 7 | } 8 | const hash = Crypto.createHmac('sha256', JSON.stringify(secret)).digest('hex');; 9 | 10 | return hash 11 | 12 | } -------------------------------------------------------------------------------- /api/lib/channels/google-home/init.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ data }) => { 2 | 3 | return data; 4 | } -------------------------------------------------------------------------------- /api/lib/channels/google-home/reply.js: -------------------------------------------------------------------------------- 1 | import { actionssdk } from 'actions-on-google'; 2 | 3 | module.exports = async function ({ event, response }) { 4 | 5 | const app = actionssdk(); 6 | 7 | app.intent('actions.intent.MAIN', conv => { 8 | conv.ask(response.textResponse); 9 | }); 10 | 11 | app.intent('actions.intent.TEXT', (conv, input) => { 12 | if (response.closeGoogleActions){ 13 | conv.close(response.textResponse); 14 | } 15 | else { 16 | conv.ask(response.textResponse); 17 | } 18 | }); 19 | 20 | return await app.handler(event, {}); 21 | } -------------------------------------------------------------------------------- /api/lib/channels/google-home/screenshots/01 - Google Actions Console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/google-home/screenshots/01 - Google Actions Console.png -------------------------------------------------------------------------------- /api/lib/channels/google-home/screenshots/02 - New Project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/google-home/screenshots/02 - New Project.png -------------------------------------------------------------------------------- /api/lib/channels/google-home/screenshots/03 - New Project Screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/google-home/screenshots/03 - New Project Screen.png -------------------------------------------------------------------------------- /api/lib/channels/google-home/screenshots/04 - Copy command.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/google-home/screenshots/04 - Copy command.png -------------------------------------------------------------------------------- /api/lib/channels/google-home/screenshots/05 - Decide display name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/google-home/screenshots/05 - Decide display name.png -------------------------------------------------------------------------------- /api/lib/channels/google-home/screenshots/06 - Set display name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/google-home/screenshots/06 - Set display name.png -------------------------------------------------------------------------------- /api/lib/channels/google-home/screenshots/07 - New Google Home Connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/google-home/screenshots/07 - New Google Home Connection.png -------------------------------------------------------------------------------- /api/lib/channels/google-home/screenshots/08 - Query Patterns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/google-home/screenshots/08 - Query Patterns.png -------------------------------------------------------------------------------- /api/lib/channels/google-home/screenshots/09 - Download Actions Package.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/google-home/screenshots/09 - Download Actions Package.png -------------------------------------------------------------------------------- /api/lib/channels/google-home/screenshots/10 - Actions Package.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/google-home/screenshots/10 - Actions Package.png -------------------------------------------------------------------------------- /api/lib/channels/google-home/screenshots/11 - Project ID.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/google-home/screenshots/11 - Project ID.png -------------------------------------------------------------------------------- /api/lib/channels/google-home/screenshots/12 - Close Google Action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/google-home/screenshots/12 - Close Google Action.png -------------------------------------------------------------------------------- /api/lib/channels/google-home/validate.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | module.exports = { 4 | create: ( details ) => { 5 | const schema = { 6 | queryPatterns: Joi.array().items(Joi.string()), 7 | useAgentWelcomeAction: Joi.boolean() 8 | }; 9 | return Joi.validate(details, schema) 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /api/lib/channels/index.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | const RequireDir = require('require-dir'); 4 | const dir = RequireDir('.', { recurse: true}); 5 | 6 | module.exports = dir 7 | -------------------------------------------------------------------------------- /api/lib/channels/mattermost/get.js: -------------------------------------------------------------------------------- 1 | module.exports = async function ({ connection, request }) { 2 | 3 | return { 4 | statusCode: 404 5 | } 6 | } -------------------------------------------------------------------------------- /api/lib/channels/mattermost/hash.js: -------------------------------------------------------------------------------- 1 | import Crypto from 'crypto'; 2 | 3 | module.exports = async function ({ event }) { 4 | 5 | const secret = { 6 | channel: event.channel_id, 7 | user: event.user_id 8 | }; 9 | 10 | const hash = Crypto.createHmac("sha256", JSON.stringify(secret)).digest("hex"); 11 | 12 | return hash; 13 | 14 | } -------------------------------------------------------------------------------- /api/lib/channels/mattermost/init.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ data }) => { 2 | 3 | return data; 4 | } -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/1 - 5 - 10 Integrations Screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/1 - 5 - 10 Integrations Screen.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/11 - Slash Command Create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/11 - Slash Command Create.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/12 - Slash Command Information 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/12 - Slash Command Information 1.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/13 - Slash Command Information 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/13 - Slash Command Information 2.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/14 - Slash Command Created.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/14 - Slash Command Created.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/15 - Articulate Connection Create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/15 - Articulate Connection Create.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/16 - Articulate Mattermost Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/16 - Articulate Mattermost Icon.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/17 - Articulate Mattermost Information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/17 - Articulate Mattermost Information.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/18 - Articulate Callback URL Placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/18 - Articulate Callback URL Placeholder.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/19 - Articulate OW Edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/19 - Articulate OW Edit.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/2 - Incoming Webhook Create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/2 - Incoming Webhook Create.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/20 - Articulate OW placeholder change.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/20 - Articulate OW placeholder change.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/21 - Articulate SC Edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/21 - Articulate SC Edit.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/22 - Articulate SC placeholder change.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/22 - Articulate SC placeholder change.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/23 - Articulate Mattermost Use.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/23 - Articulate Mattermost Use.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/3 - Incoming Webhook Information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/3 - Incoming Webhook Information.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/4 - Incoming Webhook Created.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/4 - Incoming Webhook Created.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/6 - Outgoing Webhook Create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/6 - Outgoing Webhook Create.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/7 - Outgoing Webhook Information 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/7 - Outgoing Webhook Information 1.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/8 - Outgoing Webhook Information 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/8 - Outgoing Webhook Information 2.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/screenshots/9 - Outgoing Webhook Created.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/mattermost/screenshots/9 - Outgoing Webhook Created.png -------------------------------------------------------------------------------- /api/lib/channels/mattermost/validate.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | module.exports = { 4 | create: ( details ) => { 5 | const schema = { 6 | userName: Joi.string().required(), 7 | userSelectionsPrefix: Joi.string(), 8 | incomingWebhookURL: Joi.string().required(), 9 | botAccessTokenOutgoingWebhook: Joi.string().required(), 10 | botAccessTokenSlashCommand: Joi.string().required(), 11 | outgoingMessages: Joi.boolean(), 12 | waitTimeBetweenMessages: Joi.number(), 13 | useAgentWelcomeAction: Joi.boolean() 14 | } 15 | 16 | return Joi.validate(details, schema) 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /api/lib/channels/rocketchat/get.js: -------------------------------------------------------------------------------- 1 | module.exports = async function ({ connection, request }) { 2 | 3 | return { 4 | statusCode: 404 5 | } 6 | } -------------------------------------------------------------------------------- /api/lib/channels/rocketchat/hash.js: -------------------------------------------------------------------------------- 1 | import Crypto from 'crypto'; 2 | 3 | module.exports = async function ({ event }) { 4 | 5 | const secret = { 6 | user_id: event.user_id, 7 | channel_id: event.channel_id 8 | }; 9 | 10 | const hash = Crypto.createHmac("sha256", JSON.stringify(secret)).digest("hex"); 11 | 12 | return hash; 13 | 14 | } -------------------------------------------------------------------------------- /api/lib/channels/rocketchat/init.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ data }) => { 2 | 3 | return data; 4 | } -------------------------------------------------------------------------------- /api/lib/channels/rocketchat/screenshots/01 - Connection Details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/rocketchat/screenshots/01 - Connection Details.png -------------------------------------------------------------------------------- /api/lib/channels/rocketchat/screenshots/02 - Integration Settings 01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/rocketchat/screenshots/02 - Integration Settings 01.png -------------------------------------------------------------------------------- /api/lib/channels/rocketchat/screenshots/03 - Integration Settings 02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/rocketchat/screenshots/03 - Integration Settings 02.png -------------------------------------------------------------------------------- /api/lib/channels/rocketchat/validate.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | module.exports = { 4 | create: ( details ) => { 5 | const schema = { 6 | rocketchatURL: Joi.string().required(), 7 | rocketchatUser: Joi.string().required(), 8 | rocketchatPassword: Joi.string().required(), 9 | outgoingMessages: Joi.boolean(), 10 | waitTimeBetweenMessages: Joi.number(), 11 | useAgentWelcomeAction: Joi.boolean() 12 | }; 13 | 14 | return Joi.validate(details, schema) 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /api/lib/channels/slack/get.js: -------------------------------------------------------------------------------- 1 | module.exports = async function ({ connection, request }) { 2 | 3 | return { 4 | statusCode: 404 5 | } 6 | } -------------------------------------------------------------------------------- /api/lib/channels/slack/hash.js: -------------------------------------------------------------------------------- 1 | import Crypto from 'crypto'; 2 | 3 | module.exports = async function ({ event }) { 4 | 5 | const secret = { 6 | app: event.api_app_id, 7 | channel: event.event.channel, 8 | user: event.event.user 9 | }; 10 | 11 | const hash = Crypto.createHmac("sha256", JSON.stringify(secret)).digest("hex"); 12 | 13 | return hash; 14 | 15 | } -------------------------------------------------------------------------------- /api/lib/channels/slack/init.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ data }) => { 2 | 3 | return data; 4 | } -------------------------------------------------------------------------------- /api/lib/channels/slack/validate.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | module.exports = { 4 | create: ( details ) => { 5 | const schema = { 6 | signingSecret: Joi.string().required(), 7 | botAccessToken: Joi.string().required(), 8 | outgoingMessages: Joi.boolean(), 9 | waitTimeBetweenMessages: Joi.number(), 10 | useAgentWelcomeAction: Joi.boolean() 11 | } 12 | 13 | return Joi.validate(details, schema) 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/channels/twilio/get.js: -------------------------------------------------------------------------------- 1 | module.exports = async function ({ connection, request }) { 2 | 3 | return { 4 | statusCode: 404 5 | } 6 | } -------------------------------------------------------------------------------- /api/lib/channels/twilio/hash.js: -------------------------------------------------------------------------------- 1 | import Crypto from 'crypto'; 2 | 3 | module.exports = async function ({ event }) { 4 | 5 | var secret = { 6 | phoneNumber: event['From'] 7 | } 8 | var hash = Crypto.createHmac('sha256', JSON.stringify(secret)).digest('hex');; 9 | 10 | return hash; 11 | } -------------------------------------------------------------------------------- /api/lib/channels/twilio/init.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ data }) => { 2 | 3 | return data; 4 | } -------------------------------------------------------------------------------- /api/lib/channels/twilio/reply.js: -------------------------------------------------------------------------------- 1 | module.exports = async function({ connection, event, response }) { 2 | const client = require('twilio')(connection.details.accountId, connection.details.authToken); 3 | 4 | client.messages 5 | .create({from: event.To, body: response.textResponse, to: event.From}) 6 | 7 | //TODO Implement StatusCallbacks 8 | } -------------------------------------------------------------------------------- /api/lib/channels/web-demo/get.js: -------------------------------------------------------------------------------- 1 | module.exports = async function ({ connection, request }) { 2 | 3 | return { 4 | statusCode: 404 5 | } 6 | } -------------------------------------------------------------------------------- /api/lib/channels/web-demo/init.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ data }) => { 2 | 3 | return data; 4 | } -------------------------------------------------------------------------------- /api/lib/channels/web-demo/reply.js: -------------------------------------------------------------------------------- 1 | import { 2 | ROUTE_EXTERNAL, 3 | ROUTE_CONNECTION 4 | } from '../../../util/constants'; 5 | 6 | module.exports = async function ({ connection, event, response }) { 7 | 8 | event.server.publish(`/${ROUTE_CONNECTION}/${connection.id}/${ROUTE_EXTERNAL}/${event.sessionId}`, response); 9 | } 10 | -------------------------------------------------------------------------------- /api/lib/channels/web-demo/screenshots/01 - Share icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/web-demo/screenshots/01 - Share icon.png -------------------------------------------------------------------------------- /api/lib/channels/web-demo/screenshots/02 - Web demo channel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/web-demo/screenshots/02 - Web demo channel.png -------------------------------------------------------------------------------- /api/lib/channels/web-demo/screenshots/03 - Agent custom message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/api/lib/channels/web-demo/screenshots/03 - Agent custom message.png -------------------------------------------------------------------------------- /api/lib/channels/web-demo/validate.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | module.exports = { 4 | create: (details) => { 5 | const schema = { 6 | messageTitle: Joi.string().required(), 7 | message: Joi.string().required(), 8 | outgoingMessages: Joi.boolean(), 9 | waitTimeBetweenMessages: Joi.number(), 10 | useAgentWelcomeAction: Joi.boolean(), 11 | }; 12 | 13 | return Joi.validate(details, schema) 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/errors/es.error-handler.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ error, message = null }) => { 2 | 3 | console.error({ error, message }); 4 | if (error.isHandled) { 5 | return error; 6 | } 7 | const response = { isHandled: true, statusCode: 500 }; 8 | if (!error) { 9 | return response; 10 | } 11 | const errorMessage = error instanceof Error ? error.message : error; 12 | message = message ? message : errorMessage; 13 | switch (error.status) { 14 | case 404: 15 | return { ...response, message, statusCode: 404 }; //NotFound 16 | default: 17 | return { ...response, message: errorMessage }; //BadImplementation 18 | } 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /api/lib/errors/global.default-error.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ statusCode = 500, message }) => { 2 | 3 | return { isHandled: true, statusCode, message }; 4 | }; 5 | -------------------------------------------------------------------------------- /api/lib/errors/global.invalid-actions-from-agent.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ statusCode = 404, actionIds, agentId }) => { 2 | 3 | return { 4 | isHandled: true, 5 | statusCode, 6 | message: `Action(s) [${actionIds.join()}] not found for the current Agent id=[${agentId}]` 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /api/lib/errors/global.invalid-actions-sayings-count.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ statusCode = 400, actions }) => { 2 | 3 | return { 4 | isHandled: true, 5 | statusCode, 6 | message: `Action(s) '${actions.join(', ')}' has only 1 training example! Minimum is 2. Please fix this before training the agent.` 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /api/lib/errors/global.invalid-agent-train.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ statusCode = 400, agent, message }) => { 2 | 3 | const errorMessage = message ? message : `Nothing to train in agent '${agent}'. Please add sayings or keywords to your agent before starting the training process`; 4 | return { 5 | isHandled: true, 6 | statusCode, 7 | message: errorMessage 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /api/lib/errors/global.invalid-keywords-from-agent.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ statusCode = 404, keywordIds, agentId }) => { 2 | 3 | return { 4 | isHandled: true, 5 | statusCode, 6 | message: `Keyword(s) [${keywordIds.join()}] not found for the current Agent id=[${agentId}]` 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /api/lib/errors/global.not-found-error.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ model, id }) => { 2 | 3 | const message = `${model}${id ? `id=[${id}]` : ''} not found`; 4 | return { isHandled: true, statusCode: 404, message }; 5 | }; 6 | -------------------------------------------------------------------------------- /api/lib/errors/global.over-limit.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ statusCode = 403, level, limit, type }) => { 2 | 3 | return { 4 | isHandled: true, 5 | statusCode, 6 | message: `This instance is already using ${level} of ${limit} allowed ${type}.` 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /api/lib/errors/global.parse-error.js: -------------------------------------------------------------------------------- 1 | module.exports = (params) => { 2 | 3 | const { 4 | statusCode, 5 | message, 6 | ...rest 7 | } = params; 8 | return { isHandled: true, isParseError: true, statusCode, message, ...rest }; 9 | }; 10 | -------------------------------------------------------------------------------- /api/lib/errors/redis.not-linked-error.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ mainType, subType, mainId, subId }) => { 2 | 3 | const message = `${subType} id=[${subId}] is not linked to ${mainType} id=[${mainId}]`; 4 | return { isHandled: true, statusCode: 404, message }; 5 | }; 6 | -------------------------------------------------------------------------------- /api/lib/errors/redis.only-one-linked-error.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ mainType, subType, mainId }) => { 2 | 3 | const message = `${mainType} id=[${mainId}] already have a ${subType} linked.`; 4 | return { isHandled: true, statusCode: 400, message }; 5 | }; 6 | -------------------------------------------------------------------------------- /api/lib/index.js: -------------------------------------------------------------------------------- 1 | const HauteCouture = require('haute-couture'); 2 | const Package = require('../package.json'); 3 | const logger = require('../util/logger')({ name: `plugin:lib` }); 4 | 5 | exports.plugin = { 6 | pkg: Package, 7 | register: async (server, options) => { 8 | 9 | // Custom plugin code can go here 10 | server.dependency(['schmervice', 'redis', 'nes']); 11 | await HauteCouture.using()(server, options); 12 | logger.info('registered'); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /api/lib/init/server-status.init.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { MODEL_SERVER } from '../../util/constants'; 3 | import serverInfo from '../../util/server-info'; 4 | import Package from '../../package.json'; 5 | 6 | module.exports = async (server) => { 7 | 8 | const { redis } = server.app; 9 | const { serverService, } = await server.services(); 10 | 11 | const ServerModel = await serverService.get({ returnModel: true }); 12 | 13 | serverInfo.version = Package.version; 14 | 15 | if (ServerModel && ServerModel.inDb){ 16 | await serverService.update({ data: serverInfo }); 17 | } 18 | else { 19 | await serverService.create({ data: serverInfo }); 20 | 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /api/lib/models/access-control.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | class AccessControlGroupModel { 4 | static get schema() { 5 | 6 | return { 7 | id: Joi.number(), 8 | name: Joi.string().trim().description('Name'), 9 | rules: Joi.object().description('Rules') 10 | }; 11 | }; 12 | } 13 | 14 | module.exports = AccessControlGroupModel; 15 | -------------------------------------------------------------------------------- /api/lib/models/action.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | import SlotModel from './slot.model'; 3 | import ActionResponseModel from './action.response.model'; 4 | 5 | class ActionModel { 6 | static get schema() { 7 | 8 | return { 9 | id: Joi.number(), 10 | actionName: Joi.string().trim(), 11 | slots: Joi.array().items(SlotModel.schema), 12 | responses: Joi.array().items(ActionResponseModel.schema), 13 | useWebhook: Joi.boolean(), 14 | usePostFormat: Joi.boolean(), 15 | creationDate: Joi.string(), 16 | modificationDate: Joi.date() 17 | }; 18 | }; 19 | } 20 | 21 | module.exports = ActionModel; 22 | -------------------------------------------------------------------------------- /api/lib/models/action.response.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | import ActionResponseRichResponseModel from './action.response.rich-response.model'; 3 | 4 | 5 | class ActionResponseModel { 6 | static get schema() { 7 | 8 | return { 9 | richResponses: Joi.array().items(ActionResponseRichResponseModel.schema), 10 | textResponse: Joi.string().trim(), 11 | actions: Joi.array().items(Joi.string().trim()), 12 | disableTextResponse: Joi.boolean().default(false) 13 | }; 14 | }; 15 | } 16 | 17 | module.exports = ActionResponseModel; 18 | -------------------------------------------------------------------------------- /api/lib/models/action.response.rich-response.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | class ActionResponseRichResponseModel { 4 | static get schema() { 5 | 6 | return { 7 | type: Joi.string().trim(), 8 | data: Joi.any() 9 | }; 10 | }; 11 | } 12 | 13 | module.exports = ActionResponseRichResponseModel; 14 | -------------------------------------------------------------------------------- /api/lib/models/connection.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | import Channels from '../channels'; 3 | import _ from 'lodash'; 4 | 5 | class AgentModel { 6 | static get schema() { 7 | 8 | return { 9 | id: Joi.string(), 10 | channel: Joi.string().valid(_.keys(Channels)), 11 | enabled: Joi.boolean(), 12 | agent: Joi.number(), 13 | details: Joi.object(), 14 | creationDate: Joi.string(), 15 | modificationDate: Joi.string(), 16 | status: Joi.string().allow(''), 17 | payload: Joi.object() 18 | }; 19 | }; 20 | } 21 | 22 | module.exports = AgentModel; 23 | -------------------------------------------------------------------------------- /api/lib/models/context.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | class ScenarioModel { 4 | static get schema() { 5 | 6 | return { 7 | id: Joi.number(), 8 | sessionId: Joi 9 | .string() 10 | .description('Session') 11 | .trim(), 12 | savedSlots: Joi 13 | .object(), 14 | actionQueue: Joi 15 | .array(), 16 | docIds: Joi 17 | .array(), 18 | creationDate: Joi 19 | .string(), 20 | modificationDate: Joi 21 | .string(), 22 | listenFreeText: Joi 23 | .boolean().default(false) 24 | }; 25 | }; 26 | } 27 | 28 | module.exports = ScenarioModel; 29 | -------------------------------------------------------------------------------- /api/lib/models/keyword-example.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | class ExampleModel { 4 | static get schema() { 5 | 6 | return { 7 | value: Joi.string().trim(), 8 | synonyms: Joi.array().items(Joi.string().trim()) 9 | }; 10 | }; 11 | } 12 | 13 | module.exports = ExampleModel; 14 | -------------------------------------------------------------------------------- /api/lib/models/modifier.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | import ModifierSayingSchema from '../models/modifier.saying.model'; 3 | 4 | class ModifierModel { 5 | static get schema() { 6 | 7 | return { 8 | modifierName: Joi.string().trim(), 9 | action: Joi.string().trim(), 10 | valueSource: Joi.string().trim(), 11 | staticValue: Joi.string().trim().allow(''), 12 | sayings: Joi.array().items(ModifierSayingSchema.schema) 13 | }; 14 | }; 15 | } 16 | 17 | module.exports = ModifierModel; 18 | -------------------------------------------------------------------------------- /api/lib/models/modifier.saying.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | import SayingKeywordModel from './saying.keyword.model'; 4 | 5 | class ModifierSayingModel { 6 | static get schema() { 7 | 8 | return { 9 | userSays: Joi.string().trim(), 10 | keywords: Joi.array().items(SayingKeywordModel.schema) 11 | }; 12 | }; 13 | } 14 | 15 | module.exports = ModifierSayingModel; 16 | -------------------------------------------------------------------------------- /api/lib/models/parse.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | class ParseModel { 4 | static get schema() { 5 | 6 | return { 7 | text: Joi.string().description('Text to parse'), 8 | timezone: Joi.string().description('Timezone for duckling parse. Default UTC') 9 | }; 10 | }; 11 | } 12 | 13 | module.exports = ParseModel; 14 | -------------------------------------------------------------------------------- /api/lib/models/postFormat.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | class PostFormat { 4 | static get schema() { 5 | 6 | return { 7 | id: Joi.number(), 8 | postFormatPayload: Joi.string().trim(), 9 | creationDate: Joi 10 | .string(), 11 | modificationDate: Joi 12 | .string() 13 | }; 14 | }; 15 | } 16 | 17 | module.exports = PostFormat; 18 | -------------------------------------------------------------------------------- /api/lib/models/saying.keyword.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | class SayingKeywordModel { 4 | static get schema() { 5 | 6 | return { 7 | start: Joi.number(), 8 | end: Joi.number(), 9 | value: Joi.string().trim(), 10 | keyword: Joi.string().trim(), 11 | keywordId: Joi.number(), 12 | extractor: Joi.string().trim() 13 | }; 14 | }; 15 | } 16 | 17 | module.exports = SayingKeywordModel; 18 | -------------------------------------------------------------------------------- /api/lib/models/server.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | class ServerModel { 4 | static get schema() { 5 | 6 | return { 7 | status: Joi.string() 8 | }; 9 | }; 10 | } 11 | 12 | module.exports = ServerModel; 13 | -------------------------------------------------------------------------------- /api/lib/models/settings.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | class SettingsModel { 4 | static get schema() { 5 | 6 | return { 7 | id: Joi.number(), 8 | name: Joi.string().trim().description('Setting Name'), 9 | value: Joi.alternatives().try(Joi.array(), Joi.string(), Joi.object(), Joi.number(), Joi.boolean()).description('Setting Value (string|object|array|boolean)') 10 | }; 11 | }; 12 | } 13 | 14 | module.exports = SettingsModel; 15 | -------------------------------------------------------------------------------- /api/lib/models/user-identity.model.js: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | class UserIdentityModel { 4 | static get schema() { 5 | 6 | return { 7 | id: Joi.number(), 8 | provider: Joi.string().trim().description('Provider'), 9 | token: Joi.string().trim().description('Token'), 10 | secret: Joi.string().trim().description('Secret'), 11 | profile: Joi.object().description('Profile') 12 | }; 13 | }; 14 | } 15 | 16 | module.exports = UserIdentityModel; 17 | -------------------------------------------------------------------------------- /api/lib/rich-responses/audio/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Audio", 3 | "type": "audio", 4 | "enabled": true, 5 | "description": "Audio message that will be playable by the user.", 6 | "documentation": "https://github.com/samtecspg/articulate/blob/master/api/lib/rich-responses/audio/README.MD", 7 | "defaultPayload": { 8 | "audio": "http://example/audio.mp3" 9 | } 10 | } -------------------------------------------------------------------------------- /api/lib/rich-responses/button/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Button", 3 | "type": "buttons", 4 | "enabled": true, 5 | "description": "Button that will have a payload to execute an action", 6 | "documentation": "https://github.com/samtecspg/articulate/blob/master/api/lib/rich-responses/button/README.MD", 7 | "defaultPayload": [ 8 | { 9 | "label": "Button 1", 10 | "linkURL": "" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /api/lib/rich-responses/card/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Card Carousel", 3 | "type": "cardsCarousel", 4 | "enabled": true, 5 | "description": "Clickable cards to display relevant information to the user", 6 | "documentation": "https://github.com/samtecspg/articulate/blob/master/api/lib/rich-responses/collapsible/README.MD", 7 | "defaultPayload": [ 8 | { 9 | "title": "Card 1", 10 | "description": "This is a card", 11 | "imageURL": "", 12 | "linkURL": "" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /api/lib/rich-responses/image/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Image", 3 | "type": "image", 4 | "enabled": true, 5 | "description": "A link to an image that will be displayed as a message", 6 | "documentation": "https://github.com/samtecspg/articulate/blob/master/api/lib/rich-responses/image/README.MD", 7 | "defaultPayload": { 8 | "imageURL": "http://example.com/image.jpg" 9 | } 10 | } -------------------------------------------------------------------------------- /api/lib/rich-responses/index.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | const RequireDir = require('require-dir'); 4 | const dir = RequireDir('.', { recurse: true}); 5 | 6 | module.exports = dir 7 | -------------------------------------------------------------------------------- /api/lib/rich-responses/location/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Location", 3 | "type": "location", 4 | "enabled": false, 5 | "description": "A special type of response that will request user location.", 6 | "documentation": "https://github.com/samtecspg/articulate/blob/master/api/lib/rich-responses/location/README.MD", 7 | "defaultPayload": null 8 | } -------------------------------------------------------------------------------- /api/lib/rich-responses/quick-response/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Quick Responses", 3 | "type": "quickResponses", 4 | "enabled": true, 5 | "description": "Array of strings that will show as clickable buttons to let the user quickly answer to the agent", 6 | "documentation": "https://github.com/samtecspg/articulate/blob/master/api/lib/rich-responses/quick-response/README.MD", 7 | "defaultPayload": { 8 | "quickResponses": ["Quick response 1", "Quick Response 2", "Quick Response 3"] 9 | } 10 | } -------------------------------------------------------------------------------- /api/lib/rich-responses/rich-text/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Rich Text", 3 | "type": "richText", 4 | "enabled": true, 5 | "description": "Rich text to enable text format and embeddings.", 6 | "documentation": "https://github.com/samtecspg/articulate/blob/master/api/lib/rich-responses/rich-text/README.MD", 7 | "defaultPayload": { 8 | "text": "

This is a title

This is text

This is a link" 9 | } 10 | } -------------------------------------------------------------------------------- /api/lib/rich-responses/video/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Video", 3 | "type": "video", 4 | "enabled": true, 5 | "description": "Video message that will be playable by the user.", 6 | "documentation": "https://github.com/samtecspg/articulate/blob/master/api/lib/rich-responses/video/README.MD", 7 | "defaultPayload": { 8 | "video": "http://example/video.mp4" 9 | } 10 | } -------------------------------------------------------------------------------- /api/lib/routes/access-control.routes.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { ROUTE_ACCESS_CONTROL } from '../../util/constants'; 3 | import GlobalFindAll from './global/global.find-all.route'; 4 | 5 | const Routes = require('require-dir')('./access-control'); 6 | 7 | module.exports = [ 8 | ..._.values(Routes), 9 | GlobalFindAll({ ROUTE: ROUTE_ACCESS_CONTROL }) 10 | ]; 11 | -------------------------------------------------------------------------------- /api/lib/routes/category.routes.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | const Routes = require('require-dir')('./category'); 4 | 5 | module.exports = [ 6 | ..._.values(Routes) 7 | ]; 8 | -------------------------------------------------------------------------------- /api/lib/routes/category/category.list-prebuilt.route.js: -------------------------------------------------------------------------------- 1 | import Boom from 'boom'; 2 | import { 3 | ROUTE_CATEGORY 4 | } from '../../../util/constants'; 5 | 6 | module.exports = { 7 | method: 'get', 8 | path: `/${ROUTE_CATEGORY}`, 9 | options: { 10 | tags: ['api'], 11 | handler: async (request) => { 12 | 13 | const { categoryService } = await request.services(); 14 | 15 | try { 16 | return await categoryService.info() 17 | } 18 | catch ({ message, statusCode }) { 19 | return new Boom(message, { statusCode }); 20 | } 21 | } 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /api/lib/routes/channel.route.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | const Routes = require('require-dir')('./channels'); 4 | 5 | module.exports = [ 6 | ..._.values(Routes) 7 | ]; 8 | -------------------------------------------------------------------------------- /api/lib/routes/channels/channel.list.route.js: -------------------------------------------------------------------------------- 1 | import Boom from 'boom'; 2 | import { 3 | ROUTE_CHANNEL 4 | } from '../../../util/constants'; 5 | 6 | module.exports = { 7 | method: 'get', 8 | path: `/${ROUTE_CHANNEL}`, 9 | options: { 10 | tags: ['api'], 11 | handler: async (request) => { 12 | 13 | const { channelService } = await request.services(); 14 | 15 | try { 16 | return await channelService.info() 17 | } 18 | catch ({ message, statusCode }) { 19 | return new Boom(message, { statusCode }); 20 | } 21 | } 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /api/lib/routes/connection.route.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { 3 | ROUTE_CONNECTION 4 | } from '../../util/constants'; 5 | import GlobalFindAll from './global/global.find-all.route'; 6 | import GlobalFindById from './global/global.find-by-id.route'; 7 | 8 | const Routes = require('require-dir')('./connections'); 9 | 10 | module.exports = [ 11 | ..._.values(Routes), 12 | GlobalFindAll({ ROUTE: ROUTE_CONNECTION }), 13 | GlobalFindById({ ROUTE: ROUTE_CONNECTION }), 14 | ]; 15 | -------------------------------------------------------------------------------- /api/lib/routes/context.routes.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | const Routes = require('require-dir')('./context'); 4 | 5 | module.exports = [ 6 | ..._.values(Routes) 7 | ]; 8 | -------------------------------------------------------------------------------- /api/lib/routes/document.routes.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | const Routes = require('require-dir')('./document'); 4 | 5 | module.exports = [ 6 | ..._.values(Routes) 7 | ]; 8 | -------------------------------------------------------------------------------- /api/lib/routes/log.routes.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | const Routes = require('require-dir')('./log'); 3 | 4 | module.exports = [ 5 | ..._.values(Routes) 6 | ]; 7 | -------------------------------------------------------------------------------- /api/lib/routes/rich-responses.route.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | const Routes = require('require-dir')('./rich-responses'); 4 | 5 | module.exports = [ 6 | ..._.values(Routes) 7 | ]; 8 | -------------------------------------------------------------------------------- /api/lib/routes/rich-responses/rich-response.list.route.js: -------------------------------------------------------------------------------- 1 | import Boom from 'boom'; 2 | import { 3 | ROUTE_RICH_RESPONSE 4 | } from '../../../util/constants'; 5 | 6 | module.exports = { 7 | method: 'get', 8 | path: `/${ROUTE_RICH_RESPONSE}`, 9 | options: { 10 | tags: ['api'], 11 | handler: async (request) => { 12 | 13 | const { richResponseService } = await request.services(); 14 | 15 | try { 16 | return await richResponseService.info() 17 | } 18 | catch ({ message, statusCode }) { 19 | return new Boom(message, { statusCode }); 20 | } 21 | } 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /api/lib/routes/server.routes.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | const Routes = require('require-dir')('./server'); 4 | 5 | module.exports = [ 6 | ..._.values(Routes) 7 | ]; 8 | -------------------------------------------------------------------------------- /api/lib/routes/server/server.get-info.route.js: -------------------------------------------------------------------------------- 1 | import Boom from 'boom'; 2 | import ServerValidator from '../../validators/server.validator'; 3 | 4 | module.exports = { 5 | method: 'get', 6 | path: '/', 7 | options: { 8 | tags: ['api'], 9 | validate: ServerValidator.get, 10 | handler: async (request) => { 11 | 12 | const { serverService } = await request.services(); 13 | try { 14 | return await serverService.get({ }); 15 | } 16 | catch ({ message, statusCode }) { 17 | 18 | return new Boom(message, { statusCode }); 19 | } 20 | } 21 | } 22 | }; -------------------------------------------------------------------------------- /api/lib/routes/settings.routes.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | const Routes = require('require-dir')('./settings'); 4 | 5 | module.exports = [ 6 | ..._.values(Routes) 7 | ]; 8 | -------------------------------------------------------------------------------- /api/lib/routes/user.routes.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { 3 | MODEL_USER_ACCOUNT, 4 | MODEL_USER_IDENTITY, 5 | ROUTE_USER_ACCOUNT 6 | } from '../../util/constants'; 7 | import GlobalFindAll from './global/global.find-all.route'; 8 | import GlobalFindInModelPath from './global/global.find-in-model-path.route'; 9 | import GlobalSearchByField from './global/global.search-by-field.route'; 10 | 11 | const Routes = require('require-dir')('./user'); 12 | 13 | module.exports = [ 14 | ..._.values(Routes), 15 | GlobalSearchByField({ ROUTE: ROUTE_USER_ACCOUNT }), 16 | GlobalFindInModelPath({ models: [MODEL_USER_ACCOUNT, MODEL_USER_IDENTITY] }) 17 | ]; 18 | -------------------------------------------------------------------------------- /api/lib/services/access-controll/access-control.validate.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_ACCESS_POLICY } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ data, returnModel = false }) { 5 | 6 | const { redis } = this.server.app; 7 | const AccessPolicy = await redis.factory(MODEL_ACCESS_POLICY); 8 | try { 9 | await AccessPolicy.createInstance({ data }); 10 | return returnModel ? AccessPolicy : AccessPolicy.allProperties(); 11 | } 12 | catch (error) { 13 | throw RedisErrorHandler({ error }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/services/agent-version.services.js: -------------------------------------------------------------------------------- 1 | import Schmervice from 'schmervice'; 2 | import TimingWrapper from '../../util/service-timing-wrapper'; 3 | import Create from './agent-version/agent-version.create.service'; 4 | import Delete from './agent-version/agent-version.delete.service'; 5 | 6 | module.exports = class AgentVersionService extends Schmervice.Service { 7 | 8 | async create() { 9 | return await TimingWrapper({ cls: this, fn: Create, name: 'Create' }).apply(this, arguments); 10 | } 11 | 12 | async delete() { 13 | return await TimingWrapper({ cls: this, fn: Delete, name: 'Delete' }).apply(this, arguments); 14 | } 15 | }; 16 | 17 | 18 | -------------------------------------------------------------------------------- /api/lib/services/agent-version/agent-version.delete.service.js: -------------------------------------------------------------------------------- 1 | import { 2 | MODEL_AGENT_VERSION 3 | } from '../../../util/constants'; 4 | import RedisErrorHandler from '../../errors/redis.error-handler'; 5 | 6 | module.exports = async function ({ id }) { 7 | 8 | const { redis } = this.server.app; 9 | 10 | try { 11 | const Agent = await redis.factory(MODEL_AGENT_VERSION); 12 | await Agent.findById({ id }); 13 | return await Agent.removeInstance({ id }); 14 | } 15 | catch (error) { 16 | throw RedisErrorHandler({ error }); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /api/lib/services/agent/agent.converse-get-keywords-from-rasa-results.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | module.exports = async function ({ rasaResults }) { 4 | 5 | //Iterate over each rasa result and return an array of all the keywords in all the rasa results 6 | return _.flatMap(rasaResults, (category) => { 7 | 8 | //Iterate over each keyword in a rasa result (which is a category on a multimodel agent) 9 | category.keywords = _.map(category.keywords, (keyword) => { 10 | 11 | //MARK: assigns category name to keyword 12 | keyword.category = category.category; 13 | return keyword; 14 | }); 15 | return category.keywords; 16 | }); 17 | }; -------------------------------------------------------------------------------- /api/lib/services/agent/agent.create-agent-version.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_AGENT, MODEL_KEYWORD } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | import GlobalDefaultError from '../../errors/global.default-error'; 4 | 5 | module.exports = async function ( 6 | { 7 | id, 8 | returnModel = false 9 | } 10 | ) { 11 | const { agentVersionService } = await this.server.services(); 12 | try { 13 | return await agentVersionService.create({ id, returnModel }); 14 | } 15 | catch (error) { 16 | throw RedisErrorHandler({ error }); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /api/lib/services/agent/agent.find-all-agent-versions.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_AGENT_VERSION } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ id, direction, skip, limit, field }) { 5 | 6 | const { globalService } = await this.server.services(); 7 | let filter = { 8 | originalAgentVersionId: id 9 | } 10 | try { 11 | return await globalService.findAll({ skip, limit, direction, field, model: MODEL_AGENT_VERSION, filter }); 12 | } 13 | catch (error) { 14 | throw RedisErrorHandler({ error }); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /api/lib/services/agent/agent.find-all-documents.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_AGENT } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ id, direction, skip, limit, field, dateRange, filter }) { 5 | 6 | const { globalService, documentService } = await this.server.services(); 7 | 8 | try { 9 | await globalService.findById({ id, model: MODEL_AGENT, returnModel: true }); 10 | return await documentService.findByAgentId({ agentId: id, direction, skip, limit, field, dateRange, filter }); 11 | } 12 | catch (error) { 13 | throw RedisErrorHandler({ error }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/services/agent/agent.find-all-settings.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_AGENT } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ id }) { 5 | 6 | const { globalService } = await this.server.services(); 7 | try { 8 | 9 | const agent = await globalService.findById({ id, model: MODEL_AGENT }); 10 | return await agent.settings; 11 | } 12 | catch (error) { 13 | throw RedisErrorHandler({ error }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/services/agent/agent.find-all-training-tests.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_AGENT } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ id, direction, skip, limit, field, filter }) { 5 | 6 | const { globalService, trainingTestService } = await this.server.services(); 7 | 8 | try { 9 | await globalService.findById({ id, model: MODEL_AGENT, returnModel: true }); 10 | return await trainingTestService.findByAgentId({ agentId: id, direction, skip, limit, field, filter }); 11 | } 12 | catch (error) { 13 | throw RedisErrorHandler({ error }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/services/agent/agent.find-setting-by-name.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_AGENT } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ id, name }) { 5 | 6 | const { globalService } = await this.server.services(); 7 | try { 8 | 9 | const agent = await globalService.findById({ id, model: MODEL_AGENT }); 10 | return await agent.settings[name]; 11 | } 12 | catch (error) { 13 | throw RedisErrorHandler({ error }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/services/agent/agent.remove-agent-version.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_AGENT, MODEL_KEYWORD } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | import GlobalDefaultError from '../../errors/global.default-error'; 4 | 5 | module.exports = async function ( 6 | { id } 7 | ) { 8 | const { agentVersionService } = await this.server.services(); 9 | try { 10 | return await agentVersionService.delete({ id }); 11 | } 12 | catch (error) { 13 | throw RedisErrorHandler({ error }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/services/category/category.find-all-by-ids.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_CATEGORY } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ ids }) { 5 | 6 | const { redis } = this.server.app; 7 | 8 | try { 9 | const CategoryModel = await redis.factory(MODEL_CATEGORY); 10 | return await CategoryModel.findAllByIds({ ids }); 11 | } 12 | catch (error) { 13 | throw RedisErrorHandler({ error }); 14 | } 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /api/lib/services/category/category.find-by-id.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_CATEGORY } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ id, returnModel = false }) { 5 | 6 | const { redis } = this.server.app; 7 | 8 | try { 9 | const CategoryModel = await redis.factory(MODEL_CATEGORY, id); 10 | return returnModel ? CategoryModel : CategoryModel.allProperties(); 11 | } 12 | catch (error) { 13 | throw RedisErrorHandler({ error, message: `Category id=[${id}]` }); 14 | } 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /api/lib/services/category/category.info.service.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import Categories from '../../categories'; 3 | 4 | module.exports = async function () { 5 | 6 | const categories = {} 7 | Object.keys(Categories).forEach((category) => { 8 | 9 | const info = Categories[category].info; 10 | const samples = _.take(_.map(Categories[category].sayings, 'userSays'), 10); 11 | if (Categories[category].info.enabled){ 12 | categories[category] = { ...info, samples }; 13 | } 14 | }); 15 | return categories; 16 | }; 17 | -------------------------------------------------------------------------------- /api/lib/services/channel/channel.get.service.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import Boom from 'boom'; 3 | 4 | import Channels from '../../channels'; 5 | 6 | module.exports = async function ({ connection, request }) { 7 | 8 | try { 9 | return Channels[connection.channel].get({ connection, request }) 10 | } 11 | catch ({ message, statusCode }) { 12 | 13 | return new Boom(message, { statusCode }); 14 | } 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /api/lib/services/channel/channel.hash.service.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import Boom from 'boom'; 3 | 4 | import Channels from '../../channels'; 5 | 6 | module.exports = async function ({ connection, event }) { 7 | 8 | try { 9 | return Channels[connection.channel].hash({ event }) 10 | } 11 | catch ({ message, statusCode }) { 12 | 13 | return new Boom(message, { statusCode }); 14 | } 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /api/lib/services/channel/channel.info.service.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import Channels from '../../channels'; 3 | 4 | module.exports = async function () { 5 | 6 | return _.mapValues(Channels, 'info') 7 | }; 8 | -------------------------------------------------------------------------------- /api/lib/services/channel/channel.init.service.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import Channels from '../../channels'; 3 | 4 | module.exports = async function ({ data }) { 5 | 6 | return Channels[data.channel].init({ data }) 7 | }; 8 | -------------------------------------------------------------------------------- /api/lib/services/channel/channel.post.service.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import Boom from 'boom'; 3 | import Channels from '../../channels'; 4 | 5 | module.exports = async function ({ connection, request, h }) { 6 | 7 | try { 8 | const url = request.server.info.protocol 9 | + '://' 10 | + request.server.info.host 11 | + ':' 12 | + request.server.info.port; 13 | connection.requestURL = url; 14 | return Channels[connection.channel].post({ connection, request, h }) 15 | } 16 | catch ({ message, statusCode }) { 17 | 18 | return new Boom(message, { statusCode }); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /api/lib/services/channel/channel.validate.service.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import Channels from '../../channels'; 3 | 4 | module.exports = async function ({ method, data }) { 5 | 6 | return Channels[data.channel].validate[method]( data.details ) 7 | }; 8 | -------------------------------------------------------------------------------- /api/lib/services/connections/connection.post.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_CONNECTION } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../../lib/errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ id, request, h, returnModel = false }) { 5 | 6 | const { globalService, channelService } = await this.server.services(); 7 | 8 | try { 9 | const ConnectionModel = await globalService.findById({ id: id, model: MODEL_CONNECTION, returnModel: true }); 10 | 11 | return await channelService.post({ connection: ConnectionModel.allProperties(), request, h }); 12 | } 13 | catch (error) { 14 | throw RedisErrorHandler({ error }); 15 | } 16 | 17 | 18 | }; 19 | -------------------------------------------------------------------------------- /api/lib/services/context/context.create.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_CONTEXT } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ data, returnModel = false }) { 5 | 6 | const { redis } = this.server.app; 7 | const Model = await redis.factory(MODEL_CONTEXT); 8 | try { 9 | data.actionQueue = []; 10 | data.docIds = []; 11 | data.savedSlots = {}; 12 | data.listenFreeText = false; 13 | await Model.createInstance({ data }); 14 | return returnModel ? Model : Model.allProperties(); 15 | } 16 | catch (error) { 17 | throw RedisErrorHandler({ error }); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /api/lib/services/document/document.delete-by-query.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_DOCUMENT } from '../../../util/constants'; 2 | import ESErrorHandler from '../../errors/es.error-handler'; 3 | 4 | module.exports = async function ({ body }) { 5 | 6 | const { es } = this.server.app; 7 | const DocumentModel = es.models[MODEL_DOCUMENT]; 8 | try { 9 | return await DocumentModel.deleteByQuery({ body }); 10 | } 11 | catch (error) { 12 | throw ESErrorHandler({ error }); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /api/lib/services/document/document.remove.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_DOCUMENT } from '../../../util/constants'; 2 | import ESErrorHandler from '../../errors/es.error-handler'; 3 | 4 | module.exports = async function ({ id, indexId }) { 5 | 6 | const { es } = this.server.app; 7 | const DocumentModel = es.models[MODEL_DOCUMENT]; 8 | try { 9 | await DocumentModel.removeInstance({ id, indexId }); 10 | } 11 | catch (error) { 12 | throw ESErrorHandler({ error }); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /api/lib/services/document/document.search.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_DOCUMENT } from '../../../util/constants'; 2 | import ESErrorHandler from '../../errors/es.error-handler'; 3 | 4 | module.exports = async function ({ bodyParam }) { 5 | 6 | const { es } = this.server.app; 7 | const DocumentModel = es.models[MODEL_DOCUMENT]; 8 | try { 9 | var res = await DocumentModel.search({ bodyParam }); 10 | return res; 11 | } 12 | catch (error) { 13 | throw ESErrorHandler({ error }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/services/duckling.services.js: -------------------------------------------------------------------------------- 1 | import Schmervice from 'schmervice'; 2 | import TimingWrapper from '../../util/service-timing-wrapper'; 3 | import ConvertToInterval from './duckling/duckling.convert-interval.service'; 4 | import Parse from './duckling/duckling.parse.service'; 5 | 6 | module.exports = class DucklingService extends Schmervice.Service { 7 | 8 | async convertToInterval() { 9 | return await TimingWrapper({ cls: this, fn: ConvertToInterval, name: 'ConvertToInterval' }).apply(this, arguments); 10 | } 11 | 12 | async parse() { 13 | return await TimingWrapper({ cls: this, fn: Parse, name: 'Parse' }).apply(this, arguments); 14 | } 15 | }; 16 | 17 | 18 | -------------------------------------------------------------------------------- /api/lib/services/duckling/duckling.parse.service.js: -------------------------------------------------------------------------------- 1 | module.exports = async function ( 2 | { 3 | text, 4 | timezone, 5 | language, 6 | baseURL = null 7 | }) { 8 | 9 | const { duckling } = this.server.app; 10 | const { ducklingService } = await this.server.services(); 11 | 12 | const result = await duckling.Parse({ 13 | payload: { 14 | text, 15 | lang: language, 16 | tz: timezone 17 | }, 18 | baseURL 19 | }); 20 | return ducklingService.convertToInterval({ ducklingOutput: result, timezone }); 21 | }; 22 | -------------------------------------------------------------------------------- /api/lib/services/global/global.find-by-id.service.js: -------------------------------------------------------------------------------- 1 | import RedisErrorHandler from '../../errors/redis.error-handler'; 2 | 3 | module.exports = async function ({ id, model, returnModel = false }) { 4 | 5 | const { redis } = this.server.app; 6 | 7 | try { 8 | const Model = await redis.factory(model, id); 9 | return returnModel ? Model : Model.allProperties(); 10 | } 11 | catch (error) { 12 | throw RedisErrorHandler({ error, message: `${model} id=[${id}]` }); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /api/lib/services/global/global.load-all-by-ids.service.js: -------------------------------------------------------------------------------- 1 | import RedisErrorHandler from '../../errors/redis.error-handler'; 2 | 3 | module.exports = async function ({ ids, model, returnModel = false }) { 4 | 5 | const { redis } = this.server.app; 6 | 7 | try { 8 | const Model = await redis.factory(model); 9 | const results = await Model.loadAllByIds({ ids }); 10 | if (returnModel) { 11 | return results; 12 | } 13 | return results.map((resultModel) => resultModel.allProperties()); 14 | } 15 | catch (error) { 16 | throw RedisErrorHandler({ error, message: `${model} ids=[${ids.join(',')}]` }); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /api/lib/services/global/global.load-all-linked.service.js: -------------------------------------------------------------------------------- 1 | import RedisErrorHandler from '../../errors/redis.error-handler'; 2 | 3 | module.exports = async function ({ parentModel, model, relationName = model, returnModel = false }) { 4 | 5 | const { redis } = this.server.app; 6 | 7 | try { 8 | const ids = await parentModel.getAll(model, relationName); 9 | const Model = await redis.factory(model); 10 | const results = await Model.loadAllByIds({ ids }); 11 | if (returnModel) { 12 | return results; 13 | } 14 | return results.map((resultModel) => resultModel.allProperties()); 15 | } 16 | catch (error) { 17 | throw RedisErrorHandler({ error, message: `${model} error loading linked models` }); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /api/lib/services/global/global.load-first-linked.service.js: -------------------------------------------------------------------------------- 1 | import RedisErrorHandler from '../../errors/redis.error-handler'; 2 | 3 | module.exports = async function ({ parentModel, model, relationName = model, returnModel = false }) { 4 | 5 | const { redis } = this.server.app; 6 | 7 | try { 8 | const ids = await parentModel.getAll(model, relationName); 9 | const Model = await redis.factory(model, ids[0]); 10 | return returnModel ? Model : Model.allProperties(); 11 | } 12 | catch (error) { 13 | throw RedisErrorHandler({ error, message: `${model} error loading linked models` }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/services/global/global.search-by-field.service.js: -------------------------------------------------------------------------------- 1 | import RedisErrorHandler from '../../errors/redis.error-handler'; 2 | 3 | module.exports = async function ({ field, value, model }) { 4 | 5 | const { redis } = this.server.app; 6 | 7 | try { 8 | const Model = await redis.factory(model); 9 | return await Model.searchByField({ field, value }); 10 | } 11 | catch (error) { 12 | throw RedisErrorHandler({ error, message: `${model} ${field}=[${value}]` }); 13 | } 14 | 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/services/global/global.tool-cartesian-product.service.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | const cartesianProductOf = async function (entitiesList) { 4 | 5 | return await _.reduce(entitiesList, (a, b) => { 6 | 7 | return _.flatten(_.map(a, (x) => { 8 | 9 | return _.map(b, (y) => { 10 | 11 | return x.concat([y]); 12 | }); 13 | }), true); 14 | }, [[]]); 15 | }; 16 | 17 | module.exports = cartesianProductOf; 18 | -------------------------------------------------------------------------------- /api/lib/services/keyword/keyword.create.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_KEYWORD } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ data, agent = null, returnModel = false }) { 5 | 6 | const { redis } = this.server.app; 7 | const KeywordModel = await redis.factory(MODEL_KEYWORD); 8 | try { 9 | await KeywordModel.createInstance({ data }); 10 | if (agent) { 11 | await agent.link(KeywordModel, MODEL_KEYWORD); 12 | await agent.save(); 13 | } 14 | return returnModel ? KeywordModel : KeywordModel.allProperties(); 15 | } 16 | catch (error) { 17 | throw RedisErrorHandler({ error }); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /api/lib/services/log.services.js: -------------------------------------------------------------------------------- 1 | import Schmervice from 'schmervice'; 2 | import TimingWrapper from '../../util/service-timing-wrapper'; 3 | import FindAllLogs from './log/log.find-all.service'; 4 | import Search from './log/log.search.service'; 5 | 6 | module.exports = class LogService extends Schmervice.Service { 7 | 8 | async search() { 9 | return await TimingWrapper({ cls: this, fn: Search, name: 'Search' }).apply(this, arguments); 10 | } 11 | 12 | async findAllLogs() { 13 | return await TimingWrapper({ cls: this, fn: FindAllLogs, name: 'FindAllLogs' }).apply(this, arguments); 14 | } 15 | }; 16 | 17 | 18 | -------------------------------------------------------------------------------- /api/lib/services/log/log.search.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_LOG } from '../../../util/constants'; 2 | import ESErrorHandler from '../../errors/es.error-handler'; 3 | 4 | module.exports = async function ({ bodyParam }) { 5 | 6 | const { es } = this.server.app; 7 | const LogModel = es.models[MODEL_LOG]; 8 | try { 9 | return await LogModel.search({ bodyParam }); 10 | } 11 | catch (error) { 12 | throw ESErrorHandler({ error }); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /api/lib/services/post-format/post-format.create.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_POST_FORMAT } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ data, parent = null, returnModel = false }) { 5 | 6 | const { redis } = this.server.app; 7 | 8 | const PostFormatModel = await redis.factory(MODEL_POST_FORMAT); 9 | try { 10 | await PostFormatModel.createInstance({ data }); 11 | await parent.link(PostFormatModel, MODEL_POST_FORMAT); 12 | await parent.save(); 13 | return returnModel ? PostFormatModel : PostFormatModel.allProperties(); 14 | } 15 | catch (error) { 16 | throw RedisErrorHandler({ error }); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /api/lib/services/post-format/post-format.find-all-by-ids.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_POST_FORMAT } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ ids }) { 5 | 6 | const { redis } = this.server.app; 7 | 8 | try { 9 | const Model = await redis.factory(MODEL_POST_FORMAT); 10 | return await Model.findAllByIds({ ids }); 11 | } 12 | catch (error) { 13 | throw RedisErrorHandler({ error }); 14 | } 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /api/lib/services/post-format/post-format.remove.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_POST_FORMAT } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ id }) { 5 | 6 | const { redis } = this.server.app; 7 | try { 8 | const PostFormatModel = await redis.factory(MODEL_POST_FORMAT, id); 9 | return PostFormatModel.removeInstance({ id }); 10 | } 11 | catch (error) { 12 | throw RedisErrorHandler({ error, message: `${MODEL_POST_FORMAT} id=[${id}]` }); 13 | } 14 | 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/services/post-format/post-format.update-by-id.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_POST_FORMAT } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ id, data, returnModel = false }) { 5 | 6 | const { redis } = this.server.app; 7 | const Model = await redis.factory(MODEL_POST_FORMAT); 8 | try { 9 | await Model.updateInstance({ id, data }); 10 | return returnModel ? Model : Model.allProperties(); 11 | } 12 | catch (error) { 13 | throw RedisErrorHandler({ error }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/services/rasa-nlu.services.js: -------------------------------------------------------------------------------- 1 | import Schmervice from 'schmervice'; 2 | import TimingWrapper from '../../util/service-timing-wrapper'; 3 | import Parse from './rasa-nlu/rasa-nlu.parse.service'; 4 | import Train from './rasa-nlu/rasa-nlu.train.service'; 5 | 6 | module.exports = class RasaNLUService extends Schmervice.Service { 7 | 8 | async train() { 9 | return await TimingWrapper({ cls: this, fn: Train, name: 'Train' }).apply(this, arguments); 10 | } 11 | 12 | async parse() { 13 | return await TimingWrapper({ cls: this, fn: Parse, name: 'Parse' }).apply(this, arguments); 14 | } 15 | }; 16 | 17 | 18 | -------------------------------------------------------------------------------- /api/lib/services/rich-response.services.js: -------------------------------------------------------------------------------- 1 | import Schmervice from 'schmervice'; 2 | import TimingWrapper from '../../util/service-timing-wrapper'; 3 | import Info from './rich-response/rich-response.info.service'; 4 | 5 | module.exports = class RichResponseService extends Schmervice.Service { 6 | 7 | async info() { 8 | return await TimingWrapper({ cls: this, fn: Info, name: 'Info' }).apply(this, arguments); 9 | } 10 | 11 | }; 12 | 13 | 14 | -------------------------------------------------------------------------------- /api/lib/services/rich-response/rich-response.info.service.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import RichResponses from '../../rich-responses'; 3 | 4 | module.exports = async function () { 5 | 6 | return _.mapValues(RichResponses, 'info') 7 | }; 8 | -------------------------------------------------------------------------------- /api/lib/services/saying.services.js: -------------------------------------------------------------------------------- 1 | import Schmervice from 'schmervice'; 2 | import TimingWrapper from '../../util/service-timing-wrapper'; 3 | import Remove from './saying/saying.remove.service'; 4 | 5 | module.exports = class SayingService extends Schmervice.Service { 6 | async remove() { 7 | return await TimingWrapper({ cls: this, fn: Remove, name: 'Remove' }).apply(this, arguments); 8 | } 9 | }; 10 | 11 | 12 | -------------------------------------------------------------------------------- /api/lib/services/server/server.create.service.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { 3 | MODEL_SERVER, 4 | } from '../../../util/constants'; 5 | import RedisErrorHandler from '../../errors/redis.error-handler'; 6 | 7 | module.exports = async function ({ data, returnModel = false }) { 8 | 9 | const { redis } = this.server.app; 10 | const ServerModel = await redis.factory(MODEL_SERVER); 11 | try { 12 | 13 | await ServerModel.createInstance({ data }); 14 | return returnModel ? ServerModel : ServerModel.allProperties(); 15 | } 16 | catch (error) { 17 | throw RedisErrorHandler({ error }); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /api/lib/services/server/server.get.service.js: -------------------------------------------------------------------------------- 1 | import RedisErrorHandler from '../../errors/redis.error-handler'; 2 | import { MODEL_SERVER } from '../../../util/constants'; 3 | 4 | module.exports = async function ({ returnModel = false }) { 5 | 6 | const { redis } = this.server.app; 7 | 8 | try { 9 | const Model = await redis.factory(MODEL_SERVER); 10 | const serverId = await Model.findServerId(); 11 | const ServerModel = await redis.factory(MODEL_SERVER, serverId); 12 | return returnModel ? ServerModel : ServerModel.allProperties(); 13 | } 14 | catch (error) { 15 | throw RedisErrorHandler({ error, message: `model: ${MODEL_SERVER}` }); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /api/lib/services/server/server.update.service.js: -------------------------------------------------------------------------------- 1 | import RedisErrorHandler from '../../errors/redis.error-handler'; 2 | 3 | module.exports = async function ({ data, returnModel = false }) { 4 | 5 | const { serverService } = await this.server.services(); 6 | try { 7 | const ServerModel = await serverService.get({ returnModel: true }); 8 | 9 | await ServerModel.updateInstance({ data }); 10 | return returnModel ? ServerModel : ServerModel.allProperties(); 11 | } 12 | catch (error) { 13 | throw RedisErrorHandler({ error }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/services/settings/settings.create.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_SETTINGS } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ data, returnModel = false }) { 5 | 6 | const { redis } = this.server.app; 7 | const SettingsModel = await redis.factory(MODEL_SETTINGS); 8 | try { 9 | await SettingsModel.createInstance({ data }); 10 | return returnModel ? SettingsModel : SettingsModel.allProperties(); 11 | } 12 | catch (error) { 13 | throw RedisErrorHandler({ error }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/services/settings/settings.find-by-name.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_SETTINGS } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ name, returnModel = false }) { 5 | 6 | const { redis } = this.server.app; 7 | const Model = await redis.factory(MODEL_SETTINGS); 8 | 9 | try { 10 | await Model.findByName({ name }); 11 | return returnModel ? Model : Model.allProperties(); 12 | } 13 | catch (error) { 14 | throw RedisErrorHandler({ error }); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /api/lib/services/training-test.services.js: -------------------------------------------------------------------------------- 1 | import Schmervice from 'schmervice'; 2 | import Create from './training-test/training-test.create.service'; 3 | import FindByAgentId from './training-test/training-test.find-by-agent-id.service'; 4 | 5 | module.exports = class TrainingTestService extends Schmervice.Service { 6 | 7 | async create() { 8 | 9 | return await Create.apply(this, arguments); 10 | } 11 | 12 | async findByAgentId() { 13 | 14 | return await FindByAgentId.apply(this, arguments); 15 | } 16 | 17 | }; 18 | 19 | 20 | -------------------------------------------------------------------------------- /api/lib/services/training-test/training-test.create.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_TRAINING_TEST, ROUTE_DOCUMENT, ROUTE_AGENT } from '../../../util/constants'; 2 | import ESErrorHandler from '../../errors/es.error-handler'; 3 | 4 | module.exports = async function ({ data }) { 5 | 6 | const { es } = this.server.app; 7 | const { documentService } = await this.server.services(); 8 | 9 | const TrainingTestModel = es.models[MODEL_TRAINING_TEST]; 10 | try { 11 | const result = await TrainingTestModel.createInstance({ data, refresh: true }); 12 | return data; 13 | } 14 | catch (error) { 15 | throw ESErrorHandler({ error }); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /api/lib/services/user/user.remove-by-id.service.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { 3 | MODEL_USER_ACCOUNT, 4 | PARAM_PASSWORD, 5 | PARAM_SALT 6 | } from '../../../util/constants'; 7 | import RedisErrorHandler from '../../errors/redis.error-handler'; 8 | 9 | module.exports = async function ({ id }) { 10 | 11 | const { redis } = this.server.app; 12 | try { 13 | const UserModel = await redis.factory(MODEL_USER_ACCOUNT, id); 14 | 15 | return UserModel.removeInstance({ id }); 16 | } 17 | catch (error) { 18 | throw RedisErrorHandler({ error }); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /api/lib/services/webhook/webhook.create.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_WEBHOOK } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ data, parent = null, returnModel = false }) { 5 | 6 | const { redis } = this.server.app; 7 | 8 | const model = await redis.factory(MODEL_WEBHOOK); 9 | try { 10 | await model.createInstance({ data }); 11 | await parent.link(model, MODEL_WEBHOOK); 12 | await parent.save(); 13 | return returnModel ? model : model.allProperties(); 14 | } 15 | catch (error) { 16 | throw RedisErrorHandler({ error }); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /api/lib/services/webhook/webhook.remove.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_WEBHOOK } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ id }) { 5 | 6 | const { redis } = this.server.app; 7 | try { 8 | const Model = await redis.factory(MODEL_WEBHOOK, id); 9 | return await Model.removeInstance(); 10 | } 11 | catch (error) { 12 | throw RedisErrorHandler({ error }); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /api/lib/services/webhook/webhook.update.service.js: -------------------------------------------------------------------------------- 1 | import { MODEL_WEBHOOK } from '../../../util/constants'; 2 | import RedisErrorHandler from '../../errors/redis.error-handler'; 3 | 4 | module.exports = async function ({ id, data, returnModel = false }) { 5 | 6 | const { redis } = this.server.app; 7 | try { 8 | const Model = await redis.factory(MODEL_WEBHOOK, id); 9 | await Model.updateInstance({ data }); 10 | return returnModel ? Model : Model.allProperties(); 11 | } 12 | catch (error) { 13 | throw RedisErrorHandler({ error }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /api/lib/validators/server.validator.js: -------------------------------------------------------------------------------- 1 | 2 | class ServerValidate { 3 | constructor() { 4 | 5 | this.get = { }; 6 | 7 | } 8 | } 9 | 10 | const serverValidate = new ServerValidate(); 11 | module.exports = serverValidate; 12 | -------------------------------------------------------------------------------- /api/lib/websocket/agent.ws.js: -------------------------------------------------------------------------------- 1 | import { 2 | MODEL_AGENT, 3 | NOHM_SUB_SAVE, 4 | PARAM_AGENT_ID, 5 | ROUTE_AGENT 6 | } from '../../util/constants'; 7 | 8 | module.exports = { 9 | model: MODEL_AGENT, 10 | subscribePath: `/${ROUTE_AGENT}/{${PARAM_AGENT_ID}}`, 11 | publishPath: ({ properties }) => `/${ROUTE_AGENT}/${properties.id}`, 12 | actions: [NOHM_SUB_SAVE] 13 | }; 14 | -------------------------------------------------------------------------------- /api/lib/websocket/connection.chatWidgetAndDemo.ws.js: -------------------------------------------------------------------------------- 1 | import { 2 | ROUTE_EXTERNAL, 3 | ROUTE_CONNECTION 4 | } from '../../util/constants'; 5 | 6 | module.exports = { 7 | subscribePath: `/${ROUTE_CONNECTION}/{id}/${ROUTE_EXTERNAL}/{sessionId}`, 8 | isConnection: true 9 | }; 10 | -------------------------------------------------------------------------------- /api/lib/websocket/connection.ws.js: -------------------------------------------------------------------------------- 1 | import { 2 | ROUTE_EXTERNAL, 3 | ROUTE_CONNECTION 4 | } from '../../util/constants'; 5 | 6 | module.exports = { 7 | subscribePath: `/${ROUTE_CONNECTION}/{id}/${ROUTE_EXTERNAL}`, 8 | isConnection: true 9 | }; 10 | -------------------------------------------------------------------------------- /api/lib/websocket/doc.stats.ws.js: -------------------------------------------------------------------------------- 1 | import { 2 | NOHM_SUB_SAVE, 3 | MODEL_DOCUMENT, 4 | ROUTE_DOCUMENT, 5 | ROUTE_AGENT, 6 | PARAM_SEARCH 7 | } from '../../util/constants'; 8 | 9 | module.exports = { 10 | subscribePath: `/${ROUTE_AGENT}/{id}/${ROUTE_DOCUMENT}/${PARAM_SEARCH}`, 11 | isESModel: true 12 | }; 13 | -------------------------------------------------------------------------------- /api/lib/websocket/doc.ws.js: -------------------------------------------------------------------------------- 1 | import { 2 | NOHM_SUB_SAVE, 3 | MODEL_DOCUMENT, 4 | ROUTE_DOCUMENT, 5 | ROUTE_AGENT 6 | } from '../../util/constants'; 7 | 8 | module.exports = { 9 | subscribePath: `/${ROUTE_AGENT}/{id}/${ROUTE_DOCUMENT}`, 10 | isESModel: true 11 | }; 12 | -------------------------------------------------------------------------------- /api/lib/websocket/response.ws.js: -------------------------------------------------------------------------------- 1 | import { 2 | ROUTE_AGENT, 3 | ROUTE_CONVERSE 4 | } from '../../util/constants'; 5 | 6 | module.exports = { 7 | subscribePath: `/${ROUTE_AGENT}/{id}/${ROUTE_CONVERSE}`, 8 | isResponse: true 9 | }; 10 | -------------------------------------------------------------------------------- /api/lib/websocket/server.ws.js: -------------------------------------------------------------------------------- 1 | import { 2 | NOHM_SUB_SAVE, 3 | MODEL_SERVER 4 | } from '../../util/constants'; 5 | 6 | module.exports = { 7 | model: MODEL_SERVER, 8 | subscribePath: '/', 9 | publishPath: () => '/', 10 | actions: [NOHM_SUB_SAVE] 11 | }; 12 | -------------------------------------------------------------------------------- /api/lib/websocket/session.ws.js: -------------------------------------------------------------------------------- 1 | import { 2 | MODEL_CONTEXT, 3 | NOHM_SUB_SAVE, 4 | ROUTE_CONTEXT, 5 | PARAM_SESSION, 6 | } from '../../util/constants'; 7 | 8 | module.exports = { 9 | model: MODEL_CONTEXT, 10 | subscribePath: `/${ROUTE_CONTEXT}`, 11 | publishPath: () => `/${ROUTE_CONTEXT}`, 12 | actions: [NOHM_SUB_SAVE] 13 | }; 14 | -------------------------------------------------------------------------------- /api/server/plugins/authentication/strategies/azuread.js: -------------------------------------------------------------------------------- 1 | import Logger from '../../../../util/logger'; 2 | 3 | const log = Logger('plugin:auth:azure'); 4 | module.exports = { 5 | name: 'azuread', 6 | scheme: 'bell', 7 | profileParser: ['raw.given_name', 'raw.family_name', 'email'], 8 | options: { 9 | provider: 'azuread', 10 | password: process.env.SESSION_SECRET, 11 | clientId: process.env.AUTH_AZURE_KEY, 12 | clientSecret: process.env.AUTH_AZURE_SECRET, 13 | isSecure: false, 14 | config: { tenant: process.env.AUTH_AZURE_TENANT_ID } 15 | } 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /api/server/plugins/authentication/strategies/session.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'session', 3 | scheme: 'cookie', 4 | options: { 5 | password: process.env.SESSION_SECRET, 6 | isSecure: false, 7 | isHttpOnly: false, 8 | clearInvalid: true, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /api/server/plugins/authentication/strategies/simple.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'simple', 3 | scheme: 'basic', 4 | options: { 5 | validate: async (request, email, password, h) => { 6 | const { userService } = await request.server.services(); 7 | const { isValid, user } = await userService.validate({ email, password, returnUser: true }); 8 | 9 | if (!isValid) { 10 | return { credentials: null, isValid: false }; 11 | } 12 | 13 | const credentials = { id: user.id, name: user.name, email: user.email }; 14 | return { isValid, credentials }; 15 | } 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /api/server/plugins/duckling/index.js: -------------------------------------------------------------------------------- 1 | import Axios from 'axios'; 2 | import Package from '../../../package.json'; 3 | import InitializeModels from './lib/initialize-models'; 4 | 5 | const name = 'duckling'; 6 | const logger = require('../../../util/logger')({ name: `plugin:${name}` }); 7 | 8 | module.exports = { 9 | name, 10 | pkg: Package, 11 | async register(server, options) { 12 | 13 | // Set config defaults when creating the instance 14 | const axios = Axios.create(options); 15 | server.app[name] = await InitializeModels({ http: axios, path: `${__dirname}/models` }); 16 | logger.info('registered'); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /api/server/plugins/duckling/models/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('require-dir')(); 2 | -------------------------------------------------------------------------------- /api/server/plugins/duckling/models/parse.duckling-model.js: -------------------------------------------------------------------------------- 1 | import qs from 'querystring'; 2 | 3 | const config = { 4 | headers: { 5 | 'Content-Type': 'application/x-www-form-urlencoded' 6 | }, 7 | json: 'force' 8 | }; 9 | export const name = 'Parse'; 10 | export const path = '/parse'; 11 | 12 | export default ({ http }) => { 13 | 14 | return async ({ payload, baseURL = null }) => { 15 | 16 | const response = await http.post(path, qs.stringify(payload), 17 | { 18 | ...config, 19 | ...{ baseURL } 20 | }); 21 | return response.data; 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /api/server/plugins/es/models/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('require-dir')(); 2 | -------------------------------------------------------------------------------- /api/server/plugins/es/models/log.es-model.js: -------------------------------------------------------------------------------- 1 | import { MODEL_LOG } from '../../../../util/constants'; 2 | import BaseModel from '../lib/base-model'; 3 | 4 | const getNameForCreate = (name) => { 5 | return name; 6 | } 7 | const getNameForSearch = (name) => { 8 | return name; 9 | } 10 | 11 | module.exports = class LogEsModel extends BaseModel { 12 | constructor({ client }) { 13 | 14 | super({ 15 | name: MODEL_LOG, 16 | mappings: {}, 17 | settings: {}, 18 | client, 19 | registerConfiguration: false, 20 | isMappingTemplate: false, 21 | getNameForCreate, 22 | getNameForSearch 23 | }); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /api/server/plugins/handlebars/helpers/date-time-format.handlebars-helper.js: -------------------------------------------------------------------------------- 1 | const Moment = require('moment'); 2 | export const name = 'Date Time Format (Moment)'; 3 | 4 | export default ({ Handlebars }) => { 5 | 6 | Handlebars.registerHelper('dateTimeFormat', (datetime, format, timezone = null) => { 7 | if (!timezone || !(typeof timezone === 'string' || timezone instanceof String)) { 8 | return Moment(datetime).format(format) 9 | } else { 10 | return Moment(datetime).tz(timezone).format(format) 11 | } 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /api/server/plugins/handlebars/helpers/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('require-dir')(); 2 | -------------------------------------------------------------------------------- /api/server/plugins/handlebars/helpers/intl.handlebars-helper.js: -------------------------------------------------------------------------------- 1 | import HandlebarsIntl from 'handlebars-intl'; 2 | 3 | export const name = 'Handlebars internationalization'; 4 | 5 | export default ({ Handlebars }) => { 6 | 7 | HandlebarsIntl.registerWith(Handlebars); 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /api/server/plugins/handlebars/helpers/json-path.handlebars-helper.js: -------------------------------------------------------------------------------- 1 | const { JSONPath } = require('jsonpath-plus'); 2 | 3 | export const name = 'JSONPath'; 4 | 5 | export default ({ Handlebars }) => { 6 | 7 | Handlebars.registerHelper('JSONPath', (json, path) => { 8 | return JSONPath({ path, json }); 9 | }); 10 | }; 11 | -------------------------------------------------------------------------------- /api/server/plugins/handlebars/helpers/md5.handlebars-helper.js: -------------------------------------------------------------------------------- 1 | const Crypto = require('crypto'); 2 | export const name = 'Date Time Format (Moment)'; 3 | 4 | export default ({ Handlebars }) => { 5 | 6 | Handlebars.registerHelper('md5', (string) => Crypto.createHash('md5').update(string).digest("hex")); 7 | }; 8 | -------------------------------------------------------------------------------- /api/server/plugins/handlebars/helpers/misc.handlebars-helper.js: -------------------------------------------------------------------------------- 1 | import Helpers from 'handlebars-helpers'; 2 | 3 | export const name = 'Misc Handlebars (handlebars-helpers)'; 4 | 5 | const helpers = [ 6 | 'array', 7 | 'collection', 8 | 'comparison', 9 | 'inflection', 10 | 'math', 11 | 'misc', 12 | 'number', 13 | 'object', 14 | 'string', 15 | 'url' 16 | ]; 17 | export default ({ Handlebars }) => { 18 | 19 | Helpers(helpers, { 20 | handlebars: Handlebars 21 | }); 22 | }; 23 | -------------------------------------------------------------------------------- /api/server/plugins/handlebars/helpers/moment.handlebars-helper.js: -------------------------------------------------------------------------------- 1 | import MomentHandler from 'handlebars.moment'; 2 | 3 | export const name = 'Handlebars moment'; 4 | 5 | export default ({ Handlebars }) => { 6 | 7 | MomentHandler.registerHelpers(Handlebars); 8 | }; 9 | -------------------------------------------------------------------------------- /api/server/plugins/handlebars/helpers/numeral.handlebars-helper.js: -------------------------------------------------------------------------------- 1 | const Numeral = require('numeral'); 2 | import _ from 'lodash'; 3 | 4 | export const name = 'Numeral'; 5 | 6 | _.assign(Numeral.localeData('en'), { 7 | abbreviations: { 8 | thousand: "K", 9 | million: "M", 10 | billion: "B", 11 | trillion: "T" 12 | } 13 | }); 14 | 15 | export default ({ Handlebars }) => { 16 | 17 | Handlebars.registerHelper('numeral', (number, format) => { 18 | return Numeral(number).format(format); 19 | }); 20 | 21 | }; 22 | -------------------------------------------------------------------------------- /api/server/plugins/handlebars/helpers/to-xml.handlebars-helper.js: -------------------------------------------------------------------------------- 1 | import Json2Xml from 'json2xml'; 2 | 3 | export const name = 'To XML (json2xml)'; 4 | 5 | export default ({ Handlebars }) => { 6 | 7 | Handlebars.registerHelper('toXML', (obj) => Json2Xml(obj)); 8 | }; 9 | -------------------------------------------------------------------------------- /api/server/plugins/handlebars/index.js: -------------------------------------------------------------------------------- 1 | import Handlebars from 'handlebars'; 2 | import Package from '../../../package.json'; 3 | import InitializeHelpers from './lib/initialize-helpers'; 4 | 5 | const name = 'handlebars'; 6 | const logger = require('../../../util/logger')({ name: `plugin:${name}` }); 7 | 8 | module.exports = { 9 | name, 10 | pkg: Package, 11 | async register(server) { 12 | 13 | await InitializeHelpers({ Handlebars, path: `${__dirname}/helpers` }); 14 | server.app[name] = Handlebars; 15 | logger.info('registered'); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /api/server/plugins/handlebars/lib/initialize-helpers.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | const logger = require('../../../../util/logger')({ name: `plugin:handlebars:initialize-helpers` }); 4 | 5 | module.exports = async ({ Handlebars, path }) => { 6 | 7 | const Models = require(path); 8 | const initializedModels = {}; 9 | await _.each(Models, (model) => { 10 | 11 | model.default({ Handlebars }); 12 | logger.debug(model.name); 13 | }); 14 | return initializedModels; 15 | }; 16 | -------------------------------------------------------------------------------- /api/server/plugins/rasa-nlu/index.js: -------------------------------------------------------------------------------- 1 | import Axios from 'axios'; 2 | import Package from '../../../package.json'; 3 | import InitializeModels from './lib/initialize-models'; 4 | 5 | const name = 'rasa-nlu'; 6 | const logger = require('../../../util/logger')({ name: `plugin:${name}` }); 7 | 8 | module.exports = { 9 | name, 10 | pkg: Package, 11 | async register(server, options) { 12 | 13 | // Set config defaults when creating the instance 14 | const axios = Axios.create(options); 15 | server.app[name] = await InitializeModels({ http: axios, path: `${__dirname}/models` }); 16 | logger.info('registered'); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /api/server/plugins/rasa-nlu/models/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('require-dir')(); 2 | -------------------------------------------------------------------------------- /api/server/plugins/rasa-nlu/models/parse.rasa-nlu-model.js: -------------------------------------------------------------------------------- 1 | export const name = 'Parse'; 2 | export const path = '/parse'; 3 | 4 | export default ({ http }) => { 5 | 6 | return async ({ q, project, model, baseURL = null }) => { 7 | 8 | const response = await http.post(path, { q, project, model }, { baseURL }); 9 | return response.data; 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /api/server/plugins/rasa-nlu/models/status.rasa-nlu-model.js: -------------------------------------------------------------------------------- 1 | export const name = 'Status'; 2 | export const path = '/status'; 3 | 4 | export default ({ http }) => { 5 | 6 | return async ({ baseURL = null }) => { 7 | 8 | const response = await http.get(path, { baseURL }); 9 | return response.data; 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /api/server/plugins/redis/lib/initialize-models.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import Nohm from 'nohm'; 3 | 4 | const logger = require('../../../../util/logger')({ name: `plugin:redis:initialize-model` }); 5 | 6 | module.exports = async ({ redis, path, prefix }) => { 7 | 8 | Nohm.setPrefix(prefix); 9 | Nohm.setClient(redis); 10 | Nohm.setPublish(true); 11 | const Mods = require(path); 12 | await _.each(Mods, (model) => { 13 | 14 | logger.debug(model.modelName); 15 | Nohm.register(model); 16 | }); 17 | return Nohm; 18 | }; 19 | -------------------------------------------------------------------------------- /api/server/plugins/redis/models/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('require-dir')(); 2 | -------------------------------------------------------------------------------- /api/test/01 - api.test.js: -------------------------------------------------------------------------------- 1 | import Code from 'code'; 2 | import Lab from 'lab'; 3 | import Package from '../package.json'; 4 | import * as Server from '../server'; 5 | 6 | // Test shortcuts 7 | const { describe, it, before } = exports.lab = Lab.script(); 8 | const { expect } = Code; 9 | 10 | describe('Deployment', () => { 11 | 12 | before(async ({ context }) => { 13 | 14 | context.server = await Server.deployment(true); 15 | }); 16 | 17 | it('registers the main plugin.', ({ context }) => { 18 | 19 | const { server } = context; 20 | 21 | expect(server.registrations[Package.name]).to.exist(); 22 | }); 23 | }); 24 | 25 | -------------------------------------------------------------------------------- /api/test/04 - category.test.js: -------------------------------------------------------------------------------- 1 | import Code from 'code'; 2 | import Lab from 'lab'; 3 | import * as Server from '../server'; 4 | 5 | import { 6 | ROUTE_CATEGORY 7 | } from '../util/constants'; 8 | 9 | // Test shortcuts 10 | const { describe, it, before } = exports.lab = Lab.script(); 11 | const { expect } = Code; 12 | 13 | describe('Category', () => { 14 | 15 | it('get /category', async () => { 16 | 17 | const server = await Server.deployment(); 18 | 19 | const response = await server.inject({ 20 | url: `/${ROUTE_CATEGORY}`, 21 | method: 'GET' 22 | }); 23 | 24 | expect(response.statusCode).to.equal(200); 25 | expect(response.result).to.be.an.object(); 26 | }); 27 | }); -------------------------------------------------------------------------------- /api/test/05 - channel.test.js: -------------------------------------------------------------------------------- 1 | import Code from 'code'; 2 | import Lab from 'lab'; 3 | import * as Server from '../server'; 4 | 5 | import { 6 | ROUTE_CHANNEL 7 | } from '../util/constants'; 8 | 9 | // Test shortcuts 10 | const { describe, it, before } = exports.lab = Lab.script(); 11 | const { expect } = Code; 12 | 13 | describe('Channel', () => { 14 | 15 | it('get /channel', async () => { 16 | 17 | const server = await Server.deployment(); 18 | 19 | const response = await server.inject({ 20 | url: `/${ROUTE_CHANNEL}`, 21 | method: 'GET' 22 | }); 23 | 24 | expect(response.statusCode).to.equal(200); 25 | expect(response.result).to.be.an.object(); 26 | }); 27 | }); -------------------------------------------------------------------------------- /api/test/data/postAction.json: -------------------------------------------------------------------------------- 1 | { 2 | "actionName": "testAction", 3 | "useWebhook": true, 4 | "usePostFormat": true, 5 | "responses": [ 6 | { 7 | "textResponse": "Hi, I'm a test action", 8 | "actions": [] 9 | } 10 | ], 11 | "slots": [ 12 | { 13 | "slotName": "time", 14 | "uiColor": "#adf123", 15 | "keyword": "sys.duckling_time", 16 | "isList": false, 17 | "isRequired": true, 18 | "keywordId": 0, 19 | "textPrompts": [ 20 | "please specify a date for your test" 21 | ], 22 | "remainingLife": null 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /api/test/data/postAgent.json: -------------------------------------------------------------------------------- 1 | { 2 | "gravatar": 5, 3 | "uiColor": "#6EB5FF", 4 | "agentName": "37d0d070-bcdd-11e8-bd42-d7dd09e07ed3", 5 | "description": "Test post endpoint", 6 | "language": "en", 7 | "timezone": "UTC", 8 | "useWebhook": false, 9 | "usePostFormat": false, 10 | "multiCategory": false, 11 | "categoryClassifierThreshold": 0.5, 12 | "fallbackAction": "Default Fallback Action", 13 | "extraTrainingData": false, 14 | "enableModelsPerCategory": false, 15 | "parameters": { 16 | "name": "NomNom", 17 | "webmaster": "webmaster@nomnom.com" 18 | }, 19 | "categoryRecognizer": true, 20 | "modifiersRecognizer": true, 21 | "modifiersRecognizerJustER": "" 22 | } -------------------------------------------------------------------------------- /api/test/data/postCategory.json: -------------------------------------------------------------------------------- 1 | { 2 | "categoryName": "string", 3 | "enabled": true, 4 | "actionThreshold": 0, 5 | "extraTrainingData": true, 6 | "parameters": { 7 | "name": "NomNom", 8 | "webmaster": "webmaster@nomnom.com" 9 | } 10 | } -------------------------------------------------------------------------------- /api/util/server-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Articulate API", 3 | "status": "Ready" 4 | } 5 | -------------------------------------------------------------------------------- /compose/basic-auth-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | api: 5 | environment: 6 | - SESSION_SECRET=${SESSION_SECRET:-_super_secret_session_secret_needs_to_be_long_} 7 | - AUTH_ENABLED=true 8 | - AUTH_USER=${AUTH_USER:-arty} 9 | - AUTH_PASSWORD=${AUTH_PASSWORD:-changeme} 10 | - AUTH_FORCE_DEFAULT_USER=${AUTH_FORCE_DEFAULT_USER:-false} 11 | ui: 12 | image: samtecspg/articulate-ui:repo-head-basic-auth 13 | -------------------------------------------------------------------------------- /compose/build-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | api: 5 | build: './api/.' 6 | ui: 7 | build: 8 | context: './ui/.' 9 | rasa: 10 | build: 11 | context: './rasa/.' 12 | duckling: 13 | build: 14 | context: './duckling/.' 15 | -------------------------------------------------------------------------------- /compose/develop-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | api: 5 | build: './api/.' 6 | ui: 7 | build: 8 | context: './ui/.' 9 | dockerfile: docker/dev.Dockerfile 10 | rasa: 11 | build: 12 | context: './rasa/.' 13 | duckling: 14 | build: 15 | context: './duckling/.' 16 | redis: 17 | elasticsearch: 18 | -------------------------------------------------------------------------------- /compose/gateway-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | nginx: 5 | volumes: 6 | - ./local-storage/nginx/nginx.dev.conf:/etc/nginx/conf.d/default.conf 7 | -------------------------------------------------------------------------------- /compose/kibana-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | kibana: 5 | image: docker.elastic.co/kibana/kibana:${ELASTIC_TAG:-6.5.1} 6 | ports: 7 | - '0.0.0.0:5601:5601' 8 | depends_on: 9 | - elasticsearch 10 | -------------------------------------------------------------------------------- /compose/ssl-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | nginx: 5 | ports: 6 | - '80:80' 7 | - '443:443' 8 | volumes: 9 | - ./local-storage/nginx/nginx.ssl.conf:/etc/nginx/conf.d/default.conf 10 | - ./local-storage/certbot/conf:/etc/letsencrypt 11 | - ./local-storage/certbot/www:/var/www/certbot 12 | command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'" 13 | certbot: 14 | image: certbot/certbot 15 | volumes: 16 | - ./local-storage/certbot/conf:/etc/letsencrypt 17 | - ./local-storage/certbot/www:/var/www/certbot 18 | entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'" -------------------------------------------------------------------------------- /compose/test-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | api: 5 | build: './api/.' 6 | command: 'yarn test' 7 | ui: 8 | build: 9 | context: './ui/.' 10 | dockerfile: Dockerfile.dev.yml 11 | args: 12 | - API_URL=${API_URL:-http://localhost:7500} # Needed for running yarn build in Dockerfile 13 | rasa: 14 | build: 15 | context: './rasa/.' 16 | duckling: 17 | build: 18 | context: './duckling/.' 19 | -------------------------------------------------------------------------------- /docker-compose.override.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | nginx: 5 | ports: ['${PORT:-8080}:80'] 6 | api: 7 | ports: ['${API_PORT:-7500}:7500'] 8 | ui: 9 | ports: ['3000'] 10 | rasa: 11 | ports: ['5000:5000'] 12 | duckling: 13 | ports: ['8000:8000'] 14 | redis: 15 | ports: ['6379:6379'] 16 | elasticsearch: 17 | ports: ['9200:9200'] -------------------------------------------------------------------------------- /docs/concepts/modifiers.md: -------------------------------------------------------------------------------- 1 | # Modifiers 2 | 3 | Actions have slots and slots are filled with keywords. Modifiers are special types of actions that are used to interact with slots and their values. For example if you were building a pizza bot modifiers could allow your user to add or remove toppings. Or if you had already gather the information for an order modifierscould allow you to confirm the order before placing it. 4 | 5 | ## Creating a Modifier 6 | 7 | Modifiers are attached to their respective keywords. 8 | 9 | ## Modifiers for Confirmation 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/concepts/ubiquity.md: -------------------------------------------------------------------------------- 1 | # Ubiquity 2 | 3 | > appearing everywhere 4 | 5 | Ubiquity is Articulate's way of connecting the same agent to multiple services and tracking user interactions across those platforms. 6 | 7 | ## Channels 8 | 9 | 10 | ## Connections -------------------------------------------------------------------------------- /docs/getting-started/advanced-installation.md: -------------------------------------------------------------------------------- 1 | # Advanced Installation 2 | 3 | Nothing here yet, as our infrastructure is changing too rapidly to document. Once we've released a stable 1.0 we will document some advanced installation practices. -------------------------------------------------------------------------------- /docs/img/articulate-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/articulate-logo.png -------------------------------------------------------------------------------- /docs/img/chains/offer-help.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/chains/offer-help.PNG -------------------------------------------------------------------------------- /docs/img/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/diagram.png -------------------------------------------------------------------------------- /docs/img/getting-started/action-dropdown-empty.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/action-dropdown-empty.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/category-dropdown-empty.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/category-dropdown-empty.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/copy-modal.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/copy-modal.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/create-action-main.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/create-action-main.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/create-action-response.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/create-action-response.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/create-agent.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/create-agent.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/create-category.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/create-category.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/cya.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/cya.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/hello-world.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/hello-world.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/home.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/home.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/play.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/play.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/review.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/review.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/sayings-copy.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/sayings-copy.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/sayings-empty.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/sayings-empty.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/sayings-more.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/sayings-more.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/sayings-multi-action.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/sayings-multi-action.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/sayings.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/sayings.PNG -------------------------------------------------------------------------------- /docs/img/getting-started/training-complete.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/getting-started/training-complete.PNG -------------------------------------------------------------------------------- /docs/img/laptop-mockup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/laptop-mockup.png -------------------------------------------------------------------------------- /docs/img/main-ilus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/main-ilus.png -------------------------------------------------------------------------------- /docs/img/screens/createAgent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/screens/createAgent.png -------------------------------------------------------------------------------- /docs/img/screens/createDomain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/screens/createDomain.png -------------------------------------------------------------------------------- /docs/img/screens/createEntity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/screens/createEntity.png -------------------------------------------------------------------------------- /docs/img/screens/createIntent1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/screens/createIntent1.png -------------------------------------------------------------------------------- /docs/img/screens/createIntent2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/screens/createIntent2.png -------------------------------------------------------------------------------- /docs/img/screens/domainList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/screens/domainList.png -------------------------------------------------------------------------------- /docs/img/screens/entityList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/screens/entityList.png -------------------------------------------------------------------------------- /docs/img/screens/intentList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/screens/intentList.png -------------------------------------------------------------------------------- /docs/img/screens/welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/docs/img/screens/welcome.png -------------------------------------------------------------------------------- /docs/screens/agent.md: -------------------------------------------------------------------------------- 1 | # Agent Screen -------------------------------------------------------------------------------- /docs/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --border-color: #54b976; 3 | } 4 | 5 | .page-content h2 { 6 | margin-top: 2rem; 7 | border-bottom-width: 3px 8 | } 9 | 10 | .tut img { 11 | margin-bottom: 2rem; 12 | border-radius: 8px; 13 | box-shadow: 0 0 10px; 14 | } 15 | 16 | .ItemLink.active { 17 | border-right: 6px solid #54b976; 18 | } -------------------------------------------------------------------------------- /duckling/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM samtecspg/duckling:0.1.6.0 2 | EXPOSE 8000 3 | -------------------------------------------------------------------------------- /duckling/README.md: -------------------------------------------------------------------------------- 1 | # Articulate's custom duckling build 2 | 3 | This directory contains the configurations to customize (and version lock) the duckling container that Articulate uses. 4 | -------------------------------------------------------------------------------- /local-storage/elasticsearch/data/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /local-storage/filebeat/data/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /local-storage/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name localhost; 4 | 5 | location /api { 6 | proxy_pass http://api:7500; 7 | proxy_http_version 1.1; 8 | proxy_set_header Host $http_host; 9 | proxy_set_header X-scheme $scheme; 10 | proxy_set_header X-request-uri $request_uri; 11 | proxy_set_header X-real-ip $remote_addr; 12 | proxy_set_header Upgrade $http_upgrade; 13 | proxy_set_header Connection "upgrade"; 14 | rewrite ^/api(.*)$ $1 break; 15 | } 16 | 17 | location / { 18 | proxy_pass http://ui:3000; 19 | proxy_set_header Host $http_host; 20 | proxy_set_header X-Forwarded-Proto $scheme; 21 | proxy_set_header X-Real-IP $remote_addr; 22 | } 23 | } -------------------------------------------------------------------------------- /local-storage/rasa/nlu-model/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /local-storage/rasa/rasa-config-tf.yml: -------------------------------------------------------------------------------- 1 | pipeline: 2 | - name: "intent_featurizer_count_vectors" 3 | - name: "intent_classifier_tensorflow_embedding" 4 | intent_tokenization_flag: true 5 | intent_split_symbol: "+__+" 6 | - name: "nlp_spacy" 7 | - name: "tokenizer_spacy" 8 | - name: "ner_crf" 9 | - name: "ner_synonyms" 10 | - name: "ner_spacy" -------------------------------------------------------------------------------- /local-storage/rasa/rasa-config.yml: -------------------------------------------------------------------------------- 1 | language: en 2 | 3 | pipeline: 4 | - name: "nlp_spacy" 5 | - name: "tokenizer_spacy" 6 | - name: "intent_featurizer_spacy" 7 | - name: "ner_crf" 8 | - name: "ner_synonyms" 9 | - name: "intent_classifier_sklearn" 10 | - name: "ner_spacy" -------------------------------------------------------------------------------- /local-storage/redis-data/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /rasa/README.md: -------------------------------------------------------------------------------- 1 | # Articulate's custom RASA build 2 | 3 | This directory contains the configurations to customize (and version lock) the RASA NLU container that Articulate uses. 4 | -------------------------------------------------------------------------------- /ui/.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | node_modules 3 | .vscode 4 | .idea 5 | -------------------------------------------------------------------------------- /ui/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | insert_final_newline = true 9 | indent_style = space 10 | indent_size = 2 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /ui/.env.example: -------------------------------------------------------------------------------- 1 | #NODE_ENV=development 2 | #DEBUG=*,-babel,-babel:*,-nohm:*,-follow-redirects,redis,-nodemon,-nodemon:*,-snapdragon:* 3 | #DEBUG_ROUTES=true 4 | #AUTH_ENABLED=true 5 | -------------------------------------------------------------------------------- /ui/.nvmrc: -------------------------------------------------------------------------------- 1 | lts/carbon 2 | -------------------------------------------------------------------------------- /ui/.prettierignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules/ 3 | internals/generators/ 4 | internals/scripts/ 5 | package-lock.json 6 | yarn.lock 7 | package.json 8 | -------------------------------------------------------------------------------- /ui/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 160, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": true, 7 | "trailingComma": "all" 8 | } 9 | -------------------------------------------------------------------------------- /ui/.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "processors": ["stylelint-processor-styled-components"], 3 | "extends": [ 4 | "stylelint-config-recommended", 5 | "stylelint-config-styled-components" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /ui/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 9 5 | - 8 6 | 7 | script: 8 | - node ./internals/scripts/generate-templates-for-linting 9 | - npm test -- --maxWorkers=4 10 | - npm run build 11 | 12 | before_install: 13 | - export CHROME_BIN=chromium-browser 14 | - export DISPLAY=:99.0 15 | - sh -e /etc/init.d/xvfb start 16 | 17 | notifications: 18 | email: 19 | on_failure: change 20 | 21 | after_success: 'npm run coveralls' 22 | 23 | cache: 24 | yarn: true 25 | directories: 26 | - node_modules 27 | -------------------------------------------------------------------------------- /ui/.yarnrc: -------------------------------------------------------------------------------- 1 | network-timeout 6000000 2 | -------------------------------------------------------------------------------- /ui/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10.5.0 2 | # Needed for running yarn build 3 | # ENV API_HOST=$API_HOST 4 | 5 | WORKDIR /reactapp 6 | 7 | RUN npm install -g yarn 8 | COPY package.json yarn.lock ./ 9 | COPY internals ./internals 10 | 11 | RUN yarn install 12 | ADD . . 13 | 14 | # read the arg from docker-compose and set the env for building AND runtime 15 | ARG AUTH_ENABLED 16 | ENV AUTH_ENABLED=${AUTH_ENABLED:-false} 17 | RUN yarn build 18 | CMD ["yarn", "start:prod"] 19 | #CMD ["yarn", "start"] 20 | -------------------------------------------------------------------------------- /ui/app/components/ChannelsColors/index.js: -------------------------------------------------------------------------------- 1 | const colors = { 2 | 'chat-widget': '#01aaea', 3 | 'google-home': '#4285F4', 4 | facebook: '#4489ff', 5 | rocketchat: '#bc272c', 6 | twilio: '#f12f46', 7 | slack: '#000000', 8 | 'web-demo': '#00bd6f', 9 | }; 10 | 11 | export default colors; 12 | -------------------------------------------------------------------------------- /ui/app/components/CodeModal/messages.js: -------------------------------------------------------------------------------- 1 | /* 2 | * CodeModal Messages 3 | * 4 | * This contains all the text for the CodeModal component. 5 | */ 6 | import { defineMessages } from 'react-intl'; 7 | 8 | export default defineMessages({ 9 | rasaParseResults: { 10 | id: 'app.components.CodeModal.rasaParseResults', 11 | defaultMessage: 'Rasa Parse Results', 12 | }, 13 | context: { 14 | id: 'app.components.CodeModal.context', 15 | defaultMessage: 'Context', 16 | }, 17 | currentAction: { 18 | id: 'app.components.CodeModal.currentAction', 19 | defaultMessage: 'Current Action', 20 | }, 21 | webhooks: { 22 | id: 'app.components.CodeModal.webhooks', 23 | defaultMessage: 'Webhook Responses', 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /ui/app/components/ConversationBar/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Asynchronously loads the component for AgentsPage 3 | */ 4 | import Loadable from 'react-loadable'; 5 | 6 | export default Loadable({ 7 | loader: () => import('./index'), 8 | loading: () => null, 9 | }); 10 | -------------------------------------------------------------------------------- /ui/app/components/PopoverFilter/messages.js: -------------------------------------------------------------------------------- 1 | import { defineMessages } from 'react-intl'; 2 | 3 | export default defineMessages({ 4 | applyFilter: { 5 | id: 'app.components.PopOverFilter.ApplyFilter', 6 | defaultMessage: 'Apply Filter:', 7 | }, 8 | filterApplied: { 9 | id: 'app.components.PopOverFilter.FilterApplied', 10 | defaultMessage: 'Filter Applied:', 11 | }, 12 | filter: { 13 | id: 'app.components.PopOverFilter.Filter', 14 | defaultMessage: 'Filter', 15 | }, 16 | filters: { 17 | id: 'app.components.PopOverFilter.Filters', 18 | defaultMessage: 'Filters', 19 | }, 20 | clearAllFilters: { 21 | id: 'app.components.PopOverFilter.clearAllFilters', 22 | defaultMessage: 'Clear all filters', 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /ui/app/components/ResponseSettings/messages.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ResponseSettings Messages 3 | * 4 | * This contains all the text for the ResponseSettings component. 5 | */ 6 | import { defineMessages } from 'react-intl'; 7 | 8 | export default defineMessages({ 9 | payloadError: { 10 | id: 'app.components.ResponseSettings.payloadError', 11 | defaultMessage: 12 | 'Please specify the payload value. It should be a JSON object.', 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /ui/app/components/StyledTable/components/StyledRow.js: -------------------------------------------------------------------------------- 1 | import { TableRow } from '@material-ui/core'; 2 | import { withStyles } from '@material-ui/core/styles'; 3 | import PropTypes from 'prop-types'; 4 | import React from 'react'; 5 | 6 | // import PropTypes from 'prop-types'; 7 | const styles = { 8 | root: {}, 9 | }; 10 | 11 | function StyledRow(props) { 12 | const { classes, children, ...rest } = props; 13 | return {children}; 14 | } 15 | 16 | StyledRow.propTypes = { 17 | classes: PropTypes.object.isRequired, 18 | }; 19 | 20 | export default withStyles(styles)(StyledRow); 21 | -------------------------------------------------------------------------------- /ui/app/components/StyledTable/components/TextCell.js: -------------------------------------------------------------------------------- 1 | import { TableCell } from '@material-ui/core'; 2 | import { withStyles } from '@material-ui/core/styles'; 3 | import PropTypes from 'prop-types'; 4 | import React from 'react'; 5 | 6 | const styles = {}; 7 | 8 | function TextCell(props) { 9 | const { children, ...rest } = props; 10 | return {children}; 11 | } 12 | 13 | TextCell.propTypes = { 14 | children: PropTypes.element.isRequired, 15 | }; 16 | 17 | TextCell.defaultProps = {}; 18 | 19 | export default withStyles(styles)(TextCell); 20 | -------------------------------------------------------------------------------- /ui/app/containers/ActionPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for ActionPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/containers/AddCategoryPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for AddCategoryPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/containers/AgentPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for AgentPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/containers/AgentsPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Asynchronously loads the component for AgentsPage 3 | */ 4 | import Loadable from 'react-loadable'; 5 | 6 | export default Loadable({ 7 | loader: () => import('./index'), 8 | loading: () => null, 9 | }); 10 | -------------------------------------------------------------------------------- /ui/app/containers/AnalyticsPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for AnalyticsPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/containers/App/tests/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ShallowRenderer from 'react-test-renderer/shallow'; 3 | 4 | import App from '../index'; 5 | 6 | const renderer = new ShallowRenderer(); 7 | 8 | describe('', () => { 9 | it('should render and match the snapshot', () => { 10 | renderer.render(); 11 | const renderedOutput = renderer.getRenderOutput(); 12 | expect(renderedOutput).toMatchSnapshot(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /ui/app/containers/CategoryPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for CategoriesEditPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/containers/CheatSheetPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Asynchronously loads the component for CheatSheetPage 3 | */ 4 | import Loadable from 'react-loadable'; 5 | 6 | export default Loadable({ 7 | loader: () => import('./index'), 8 | loading: () => null, 9 | }); 10 | -------------------------------------------------------------------------------- /ui/app/containers/ConnectionPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for KeywordsEditPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/containers/DialoguePage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for AgentPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/containers/KeywordsEditPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for KeywordsEditPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/containers/LanguageProvider/actions.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * LanguageProvider actions 4 | * 5 | */ 6 | 7 | import { CHANGE_LOCALE } from './constants'; 8 | 9 | export function changeLocale(languageLocale) { 10 | return { 11 | type: CHANGE_LOCALE, 12 | locale: languageLocale, 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /ui/app/containers/LanguageProvider/constants.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * LanguageProvider constants 4 | * 5 | */ 6 | 7 | export const CHANGE_LOCALE = 'app/LanguageToggle/CHANGE_LOCALE'; 8 | -------------------------------------------------------------------------------- /ui/app/containers/LanguageProvider/reducer.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * LanguageProvider reducer 4 | * 5 | */ 6 | 7 | import produce from 'immer'; 8 | 9 | import { CHANGE_LOCALE } from './constants'; 10 | import { DEFAULT_LOCALE } from '../../i18n'; 11 | 12 | export const initialState = { 13 | locale: DEFAULT_LOCALE, 14 | }; 15 | 16 | /* eslint-disable default-case, no-param-reassign */ 17 | const languageProviderReducer = (state = initialState, action) => 18 | produce(state, draft => { 19 | switch (action.type) { 20 | case CHANGE_LOCALE: 21 | draft.locale = action.locale; 22 | break; 23 | } 24 | }); 25 | 26 | export default languageProviderReducer; 27 | -------------------------------------------------------------------------------- /ui/app/containers/LanguageProvider/selectors.js: -------------------------------------------------------------------------------- 1 | import { createSelector } from 'reselect'; 2 | import { initialState } from './reducer'; 3 | 4 | /** 5 | * Direct selector to the language domain 6 | */ 7 | 8 | const selectLanguage = state => state.language || initialState; 9 | 10 | /** 11 | * Select the language locale 12 | */ 13 | 14 | const makeSelectLocale = () => 15 | createSelector( 16 | selectLanguage, 17 | languageState => languageState.locale, 18 | ); 19 | 20 | export { selectLanguage, makeSelectLocale }; 21 | -------------------------------------------------------------------------------- /ui/app/containers/LanguageProvider/tests/actions.test.js: -------------------------------------------------------------------------------- 1 | import { changeLocale } from '../actions'; 2 | 3 | import { CHANGE_LOCALE } from '../constants'; 4 | 5 | describe('LanguageProvider actions', () => { 6 | describe('Change Local Action', () => { 7 | it('has a type of CHANGE_LOCALE', () => { 8 | const expected = { 9 | type: CHANGE_LOCALE, 10 | locale: 'de', 11 | }; 12 | expect(changeLocale('de')).toEqual(expected); 13 | }); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /ui/app/containers/LanguageProvider/tests/reducer.test.js: -------------------------------------------------------------------------------- 1 | import languageProviderReducer from '../reducer'; 2 | import { CHANGE_LOCALE } from '../constants'; 3 | 4 | /* eslint-disable default-case, no-param-reassign */ 5 | describe('languageProviderReducer', () => { 6 | it('returns the initial state', () => { 7 | expect(languageProviderReducer(undefined, {})).toEqual({ 8 | locale: 'en', 9 | }); 10 | }); 11 | 12 | it('changes the locale', () => { 13 | expect( 14 | languageProviderReducer(undefined, { 15 | type: CHANGE_LOCALE, 16 | locale: 'de', 17 | }), 18 | ).toEqual({ 19 | locale: 'de', 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /ui/app/containers/LanguageProvider/tests/selectors.test.js: -------------------------------------------------------------------------------- 1 | import { selectLanguage } from '../selectors'; 2 | 3 | describe('selectLanguage', () => { 4 | it('should select the global state', () => { 5 | const globalState = {}; 6 | const mockedState = { 7 | language: globalState, 8 | }; 9 | expect(selectLanguage(mockedState)).toEqual(globalState); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /ui/app/containers/MissingAPIPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for MissingAPIPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/containers/MissingAPIPage/messages.js: -------------------------------------------------------------------------------- 1 | import { defineMessages } from 'react-intl'; 2 | 3 | export default defineMessages({ 4 | missingAPITitle: { 5 | id: 'app.components.MissingAPIPage.title', 6 | defaultMessage: 'Error: missing API', 7 | }, 8 | missingAPIParagraph: { 9 | id: 'app.components.MissingAPIPage.missing_api_paragraph', 10 | defaultMessage: 11 | "We couldn't connect to the API. This could be because the API ports aren't configured properly in your environment. For configuration instruction go to here:", 12 | }, 13 | needHelp: { 14 | id: 'app.components.MissingAPIPage.needHelp', 15 | defaultMessage: 'Need Help?', 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /ui/app/containers/NotFoundPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Asynchronously loads the component for NotFoundPage 3 | */ 4 | import Loadable from 'react-loadable'; 5 | 6 | export default Loadable({ 7 | loader: () => import('./index'), 8 | loading: () => null, 9 | }); 10 | -------------------------------------------------------------------------------- /ui/app/containers/NotFoundPage/tests/index.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Testing the NotFoundPage 3 | */ 4 | 5 | import React from 'react'; 6 | import { render } from 'react-testing-library'; 7 | import { IntlProvider } from 'react-intl'; 8 | 9 | import NotFound from '../index'; 10 | import messages from '../messages'; 11 | 12 | describe('', () => { 13 | it('should render the Page Not Found text', () => { 14 | const { queryByText } = render( 15 | 16 | 17 | , 18 | ); 19 | expect(queryByText(messages.header.defaultMessage)).not.toBeNull(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /ui/app/containers/ReviewPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for ReviewPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/containers/SayingsInfoPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Asynchronously loads the component for SayingsInfoPage 3 | */ 4 | import Loadable from 'react-loadable'; 5 | 6 | export default Loadable({ 7 | loader: () => import('./index'), 8 | loading: () => null, 9 | }); 10 | -------------------------------------------------------------------------------- /ui/app/containers/SettingsPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for SettingsPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/containers/SharedChatPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for SharedChatPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/containers/SharedChatPage/messages.js: -------------------------------------------------------------------------------- 1 | /* 2 | * SharedChatPage Messages 3 | * 4 | * This contains all the text for the SharedChatPage component. 5 | */ 6 | 7 | import { defineMessages } from 'react-intl'; 8 | 9 | export default defineMessages({ 10 | agentDescription: { 11 | id: 'app.containers.SharedChatPage.agentDescription', 12 | defaultMessage: 'Agent Description', 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /ui/app/containers/TrainingTestSummaryPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for AgentPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/containers/UserAuthPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Asynchronously loads the component for RegisterPage 3 | */ 4 | import Loadable from 'react-loadable'; 5 | 6 | export default Loadable({ 7 | loader: () => import('./index'), 8 | loading: () => null, 9 | }); 10 | -------------------------------------------------------------------------------- /ui/app/containers/UserPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for UsersPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/containers/UsersPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for UsersPage 4 | * 5 | */ 6 | 7 | import Loadable from 'react-loadable'; 8 | 9 | export default Loadable({ 10 | loader: () => import('./index'), 11 | loading: () => null, 12 | }); 13 | -------------------------------------------------------------------------------- /ui/app/global-styles.js: -------------------------------------------------------------------------------- 1 | const GlobalStyle = {}; 2 | export default GlobalStyle; 3 | -------------------------------------------------------------------------------- /ui/app/images/audio-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ui/app/images/cancel-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ui/app/images/card-carousel-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | card-carousel-icon 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ui/app/images/check-save-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Path 16 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ui/app/images/checkbox-unchecked-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Rectangle 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ui/app/images/circle-disabled-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ui/app/images/circle-enabled-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ui/app/images/collapsible-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | collapsible-icon 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ui/app/images/connection-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Path 38 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ui/app/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/ui/app/images/favicon.ico -------------------------------------------------------------------------------- /ui/app/images/fb-messenger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/ui/app/images/fb-messenger.png -------------------------------------------------------------------------------- /ui/app/images/google-assistant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/ui/app/images/google-assistant.png -------------------------------------------------------------------------------- /ui/app/images/hyphen-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Path 40 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ui/app/images/icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/ui/app/images/icon-512x512.png -------------------------------------------------------------------------------- /ui/app/images/icon-eye.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /ui/app/images/icon-goto.svg: -------------------------------------------------------------------------------- 1 | icon-goto -------------------------------------------------------------------------------- /ui/app/images/icon-organize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | icon-organize 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ui/app/images/icon-try.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | icon-try 14 | 15 | 16 | -------------------------------------------------------------------------------- /ui/app/images/icon_search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ui/app/images/image-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | image-icon 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /ui/app/images/mattermost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/ui/app/images/mattermost.png -------------------------------------------------------------------------------- /ui/app/images/multimedia-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | play-icon 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ui/app/images/rocketchat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/ui/app/images/rocketchat.png -------------------------------------------------------------------------------- /ui/app/images/share-icon.svg: -------------------------------------------------------------------------------- 1 | share-icon -------------------------------------------------------------------------------- /ui/app/images/slack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/ui/app/images/slack.png -------------------------------------------------------------------------------- /ui/app/images/twilio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/ui/app/images/twilio.png -------------------------------------------------------------------------------- /ui/app/images/v-divider.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | v-divider 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /ui/app/images/web-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samtecspg/articulate/b7925c191f6e9065384d5e04796a4d3303f2ee9b/ui/app/images/web-demo.png -------------------------------------------------------------------------------- /ui/app/utils/accessControl.js: -------------------------------------------------------------------------------- 1 | const internals = {}; 2 | const defaults = {}; 3 | 4 | defaults.options = {}; 5 | 6 | internals.validate = ({ userPolicies = {}, requiredPolicies = [] }, cb = null) => { 7 | const isAllowedReducer = (accumulator, policy) => { 8 | const currentValue = userPolicies[policy]; 9 | if (accumulator === undefined) { 10 | return currentValue === undefined ? undefined : currentValue; 11 | } 12 | return accumulator || currentValue; 13 | }; 14 | const isAllowed = requiredPolicies.reduce(isAllowedReducer, undefined); 15 | if (isAllowed) { 16 | return cb ? cb() : isAllowed; 17 | } 18 | return isAllowed; 19 | }; 20 | 21 | module.exports = internals; 22 | -------------------------------------------------------------------------------- /ui/app/utils/apiMiddleware.js: -------------------------------------------------------------------------------- 1 | // Based on https://github.com/noh4ck/redux-swagger-client/blob/master/src/index.js 2 | import Axios from 'axios'; 3 | 4 | const api = Axios.create(); 5 | api.interceptors.response.use( 6 | response => response.data, 7 | error => Promise.reject(error), 8 | ); 9 | export default function apiMiddleware() { 10 | return () => next => action => { 11 | if (!action.apiCall) { 12 | return next(action); 13 | } 14 | const { apiCall, ...rest } = action; 15 | return next({ ...rest, api }); 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /ui/app/utils/checkStore.js: -------------------------------------------------------------------------------- 1 | import { conformsTo, isFunction, isObject } from 'lodash'; 2 | import invariant from 'invariant'; 3 | 4 | /** 5 | * Validate the shape of redux store 6 | */ 7 | export default function checkStore(store) { 8 | const shape = { 9 | dispatch: isFunction, 10 | subscribe: isFunction, 11 | getState: isFunction, 12 | replaceReducer: isFunction, 13 | runSaga: isFunction, 14 | injectedReducers: isObject, 15 | injectedSagas: isObject, 16 | }; 17 | invariant( 18 | conformsTo(store, shape), 19 | '(app/utils...) injectors: Expected a valid redux store', 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /ui/app/utils/constants.js: -------------------------------------------------------------------------------- 1 | export const RESTART_ON_REMOUNT = '@@saga-injector/restart-on-remount'; 2 | export const DAEMON = '@@saga-injector/daemon'; 3 | export const ONCE_TILL_UNMOUNT = '@@saga-injector/once-till-unmount'; 4 | -------------------------------------------------------------------------------- /ui/app/utils/history.js: -------------------------------------------------------------------------------- 1 | import { createBrowserHistory } from 'history'; 2 | const history = createBrowserHistory(); 3 | export default history; 4 | -------------------------------------------------------------------------------- /ui/app/utils/loadable.js: -------------------------------------------------------------------------------- 1 | import React, { lazy, Suspense } from 'react'; 2 | 3 | const loadable = (importFunc, { fallback = null } = { fallback: null }) => { 4 | const LazyComponent = lazy(importFunc); 5 | 6 | return props => ( 7 | 8 | 9 | 10 | ); 11 | }; 12 | 13 | export default loadable; 14 | -------------------------------------------------------------------------------- /ui/app/utils/locationResolver.js: -------------------------------------------------------------------------------- 1 | import { PROXY_ROUTE_PREFIX } from '../../common/constants'; 2 | 3 | let WS_URL = null; 4 | 5 | export function getWS() { 6 | if (WS_URL) { 7 | return WS_URL; 8 | } 9 | const loc = window.location; 10 | if (loc.protocol === 'https:') { 11 | WS_URL = 'wss:'; 12 | } else { 13 | WS_URL = 'ws:'; 14 | } 15 | WS_URL += `//${loc.host}/api/`; 16 | 17 | return WS_URL; 18 | } 19 | 20 | export function toAPIPath(paths) { 21 | return `${PROXY_ROUTE_PREFIX}/${paths.join('/')}`; 22 | } 23 | -------------------------------------------------------------------------------- /ui/common/env.js: -------------------------------------------------------------------------------- 1 | const _auth = (() => { 2 | return process.env.AUTH_ENABLED === undefined 3 | ? false 4 | : process.env.AUTH_ENABLED === "true"; 5 | })(); 6 | 7 | const env = { 8 | AUTH_ENABLED: _auth 9 | }; 10 | 11 | export default env; 12 | 13 | export const { 14 | AUTH_ENABLED 15 | } = env; 16 | -------------------------------------------------------------------------------- /ui/docker/auth.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10.5.0 2 | # Needed for running yarn build 3 | # ENV API_HOST=$API_HOST 4 | 5 | WORKDIR /reactapp 6 | 7 | RUN npm install -g yarn 8 | COPY package.json yarn.lock ./ 9 | COPY internals ./internals 10 | 11 | RUN yarn install 12 | ADD . . 13 | # run yarn build when running yarn start:prod 14 | # RUN yarn build 15 | 16 | EXPOSE 3000 17 | 18 | ENV AUTH_ENABLED=true 19 | 20 | #CMD ["yarn", "start:prod"] 21 | CMD ["yarn", "start"] 22 | -------------------------------------------------------------------------------- /ui/docker/dev.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10.5.0 2 | # Needed for running yarn build 3 | # ENV API_HOST=$API_HOST 4 | 5 | WORKDIR /reactapp 6 | 7 | RUN npm install -g yarn 8 | COPY package.json yarn.lock ./ 9 | COPY internals ./internals 10 | 11 | RUN yarn install 12 | ADD . . 13 | # run yarn build when running yarn start:prod 14 | # RUN yarn build 15 | 16 | EXPOSE 3000 17 | 18 | # read the arg from docker-compose and set the env for building AND runtime 19 | ARG AUTH_ENABLED 20 | ENV AUTH_ENABLED=${AUTH_ENABLED:-false} 21 | 22 | #CMD ["yarn", "start:prod"] 23 | CMD ["yarn", "start"] 24 | -------------------------------------------------------------------------------- /ui/internals/generators/component/loadable.js.hbs: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Asynchronously loads the component for {{ properCase name }} 4 | * 5 | */ 6 | 7 | import loadable from 'utils/loadable'; 8 | 9 | export default loadable(() => import('./index')); 10 | -------------------------------------------------------------------------------- /ui/internals/generators/component/messages.js.hbs: -------------------------------------------------------------------------------- 1 | /* 2 | * {{ properCase name }} Messages 3 | * 4 | * This contains all the text for the {{ properCase name }} component. 5 | */ 6 | 7 | import { defineMessages } from 'react-intl'; 8 | 9 | export const scope = 'app.components.{{ properCase name }}'; 10 | 11 | export default defineMessages({ 12 | header: { 13 | id: `${scope}.header`, 14 | defaultMessage: 'This is the {{ properCase name }} component!', 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /ui/internals/generators/container/actions.js.hbs: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * {{ properCase name }} actions 4 | * 5 | */ 6 | 7 | import { DEFAULT_ACTION } from './constants'; 8 | 9 | export function defaultAction() { 10 | return { 11 | type: DEFAULT_ACTION, 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /ui/internals/generators/container/actions.test.js.hbs: -------------------------------------------------------------------------------- 1 | import { defaultAction } from '../actions'; 2 | import { DEFAULT_ACTION } from '../constants'; 3 | 4 | describe('{{ properCase name }} actions', () => { 5 | describe('Default Action', () => { 6 | it('has a type of DEFAULT_ACTION', () => { 7 | const expected = { 8 | type: DEFAULT_ACTION, 9 | }; 10 | expect(defaultAction()).toEqual(expected); 11 | }); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /ui/internals/generators/container/constants.js.hbs: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * {{ properCase name }} constants 4 | * 5 | */ 6 | 7 | export const DEFAULT_ACTION = 'app/{{ properCase name }}/DEFAULT_ACTION'; 8 | -------------------------------------------------------------------------------- /ui/internals/generators/container/messages.js.hbs: -------------------------------------------------------------------------------- 1 | /* 2 | * {{ properCase name }} Messages 3 | * 4 | * This contains all the text for the {{ properCase name }} container. 5 | */ 6 | 7 | import { defineMessages } from 'react-intl'; 8 | 9 | export const scope = 'app.containers.{{ properCase name }}'; 10 | 11 | export default defineMessages({ 12 | header: { 13 | id: `${scope}.header`, 14 | defaultMessage: 'This is the {{ properCase name }} container!', 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /ui/internals/generators/container/reducer.js.hbs: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * {{ properCase name }} reducer 4 | * 5 | */ 6 | import produce from 'immer'; 7 | import { DEFAULT_ACTION } from './constants'; 8 | 9 | export const initialState = {}; 10 | 11 | /* eslint-disable default-case, no-param-reassign */ 12 | const {{ camelCase name }}Reducer = (state = initialState, action) => 13 | produce(state, (/* draft */) => { 14 | switch (action.type) { 15 | case DEFAULT_ACTION: 16 | break; 17 | } 18 | }); 19 | 20 | export default {{ camelCase name }}Reducer; 21 | -------------------------------------------------------------------------------- /ui/internals/generators/container/saga.js.hbs: -------------------------------------------------------------------------------- 1 | // import { take, call, put, select } from 'redux-saga/effects'; 2 | 3 | // Individual exports for testing 4 | export default function* {{ camelCase name }}Saga() { 5 | // See example in containers/HomePage/saga.js 6 | } 7 | -------------------------------------------------------------------------------- /ui/internals/generators/container/saga.test.js.hbs: -------------------------------------------------------------------------------- 1 | /** 2 | * Test sagas 3 | */ 4 | 5 | /* eslint-disable redux-saga/yield-effects */ 6 | // import { take, call, put, select } from 'redux-saga/effects'; 7 | // import {{ camelCase name }}Saga from '../saga'; 8 | 9 | // const generator = {{ camelCase name }}Saga(); 10 | 11 | describe('{{ camelCase name }}Saga Saga', () => { 12 | it('Expect to have unit tests specified', () => { 13 | expect(true).toEqual(false); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /ui/internals/generators/container/selectors.js.hbs: -------------------------------------------------------------------------------- 1 | import { createSelector } from 'reselect'; 2 | import { initialState } from './reducer'; 3 | 4 | /** 5 | * Direct selector to the {{ camelCase name }} state domain 6 | */ 7 | 8 | const select{{ properCase name }}Domain = state => state.{{ camelCase name }} || initialState; 9 | 10 | /** 11 | * Other specific selectors 12 | */ 13 | 14 | /** 15 | * Default selector used by {{ properCase name }} 16 | */ 17 | 18 | const makeSelect{{ properCase name }} = () => 19 | createSelector(select{{ properCase name }}Domain, substate => substate); 20 | 21 | export default makeSelect{{ properCase name }}; 22 | export { select{{ properCase name }}Domain }; 23 | -------------------------------------------------------------------------------- /ui/internals/generators/container/selectors.test.js.hbs: -------------------------------------------------------------------------------- 1 | // import { select{{ properCase name }}Domain } from '../selectors'; 2 | 3 | describe('select{{ properCase name }}Domain', () => { 4 | it('Expect to have unit tests specified', () => { 5 | expect(true).toEqual(false); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /ui/internals/generators/language/add-locale-data.hbs: -------------------------------------------------------------------------------- 1 | $1addLocaleData({{language}}LocaleData); 2 | -------------------------------------------------------------------------------- /ui/internals/generators/language/app-locale.hbs: -------------------------------------------------------------------------------- 1 | $1 '{{language}}', 2 | -------------------------------------------------------------------------------- /ui/internals/generators/language/format-translation-messages.hbs: -------------------------------------------------------------------------------- 1 | $1 {{language}}: formatTranslationMessages('{{language}}', {{language}}TranslationMessages), 2 | -------------------------------------------------------------------------------- /ui/internals/generators/language/intl-locale-data.hbs: -------------------------------------------------------------------------------- 1 | $&const {{language}}LocaleData = require('react-intl/locale-data/{{language}}'); 2 | -------------------------------------------------------------------------------- /ui/internals/generators/language/polyfill-intl-locale.hbs: -------------------------------------------------------------------------------- 1 | $1 import('intl/locale-data/jsonp/{{language}}.js'), 2 | -------------------------------------------------------------------------------- /ui/internals/generators/language/translation-messages.hbs: -------------------------------------------------------------------------------- 1 | $1const {{language}}TranslationMessages = require('./translations/{{language}}.json'); 2 | -------------------------------------------------------------------------------- /ui/internals/generators/language/translations-json.hbs: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /ui/internals/generators/utils/componentExists.js: -------------------------------------------------------------------------------- 1 | /** 2 | * componentExists 3 | * 4 | * Check whether the given component exist in either the components or containers directory 5 | */ 6 | 7 | const fs = require('fs'); 8 | const path = require('path'); 9 | const pageComponents = fs.readdirSync( 10 | path.join(__dirname, '../../../app/components'), 11 | ); 12 | const pageContainers = fs.readdirSync( 13 | path.join(__dirname, '../../../app/containers'), 14 | ); 15 | const components = pageComponents.concat(pageContainers); 16 | 17 | function componentExists(comp) { 18 | return components.indexOf(comp) >= 0; 19 | } 20 | 21 | module.exports = componentExists; 22 | -------------------------------------------------------------------------------- /ui/internals/mocks/cssModule.js: -------------------------------------------------------------------------------- 1 | module.exports = 'CSS_MODULE'; 2 | -------------------------------------------------------------------------------- /ui/internals/mocks/image.js: -------------------------------------------------------------------------------- 1 | module.exports = 'IMAGE_MOCK'; 2 | -------------------------------------------------------------------------------- /ui/internals/scripts/helpers/checkmark.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | 3 | /** 4 | * Adds mark check symbol 5 | */ 6 | function addCheckMark(callback) { 7 | process.stdout.write(chalk.green(' ✓')); 8 | if (callback) callback(); 9 | } 10 | 11 | module.exports = addCheckMark; 12 | -------------------------------------------------------------------------------- /ui/internals/scripts/helpers/get-npm-config.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | module.exports = JSON.parse(fs.readFileSync('package.json', 'utf8')); 4 | -------------------------------------------------------------------------------- /ui/internals/scripts/helpers/progress.js: -------------------------------------------------------------------------------- 1 | const readline = require('readline'); 2 | 3 | /** 4 | * Adds an animated progress indicator 5 | * 6 | * @param {string} message The message to write next to the indicator 7 | * @param {number} [amountOfDots=3] The amount of dots you want to animate 8 | */ 9 | function animateProgress(message, amountOfDots = 3) { 10 | let i = 0; 11 | return setInterval(() => { 12 | readline.cursorTo(process.stdout, 0); 13 | i = (i + 1) % (amountOfDots + 1); 14 | const dots = new Array(i + 1).join('.'); 15 | process.stdout.write(message + dots); 16 | }, 500); 17 | } 18 | 19 | module.exports = animateProgress; 20 | -------------------------------------------------------------------------------- /ui/internals/scripts/helpers/xmark.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | 3 | /** 4 | * Adds mark cross symbol 5 | */ 6 | function addXMark(callback) { 7 | process.stdout.write(chalk.red(' ✘')); 8 | if (callback) callback(); 9 | } 10 | 11 | module.exports = addXMark; 12 | -------------------------------------------------------------------------------- /ui/internals/scripts/npmcheckversion.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process'); 2 | exec('npm -v', (err, stdout) => { 3 | if (err) throw err; 4 | if (parseFloat(stdout) < 5) { 5 | // NOTE: This can happen if you have a dependency which lists an old version of npm in its own dependencies. 6 | throw new Error(`[ERROR] You need npm version @>=5 but you have ${stdout}`); 7 | } 8 | }); 9 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/App/constants.js: -------------------------------------------------------------------------------- 1 | /* 2 | * AppConstants 3 | * Each action has a corresponding type, which the reducer knows and picks up on. 4 | * To avoid weird typos between the reducer and the actions, we save them as 5 | * constants here. We prefix them with 'yourproject/YourComponent' so we avoid 6 | * reducers accidentally picking up actions they shouldn't. 7 | * 8 | * Follow this format: 9 | * export const YOUR_ACTION_CONSTANT = 'yourproject/YourContainer/YOUR_ACTION_CONSTANT'; 10 | */ 11 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/App/selectors.js: -------------------------------------------------------------------------------- 1 | import { createSelector } from 'reselect'; 2 | 3 | const selectRouter = state => state.router; 4 | 5 | const makeSelectLocation = () => 6 | createSelector( 7 | selectRouter, 8 | routerState => routerState.location, 9 | ); 10 | 11 | export { makeSelectLocation }; 12 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/App/tests/__snapshots__/index.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[` should render and match the snapshot 1`] = ` 4 |
5 | 6 | 11 | 14 | 15 | 16 |
17 | `; 18 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/App/tests/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ShallowRenderer from 'react-test-renderer/shallow'; 3 | 4 | import App from '../index'; 5 | 6 | const renderer = new ShallowRenderer(); 7 | 8 | describe('', () => { 9 | it('should render and match the snapshot', () => { 10 | renderer.render(); 11 | const renderedOutput = renderer.getRenderOutput(); 12 | expect(renderedOutput).toMatchSnapshot(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/App/tests/selectors.test.js: -------------------------------------------------------------------------------- 1 | import { makeSelectLocation } from 'containers/App/selectors'; 2 | 3 | describe('makeSelectLocation', () => { 4 | it('should select the location', () => { 5 | const router = { 6 | location: { pathname: '/foo' }, 7 | }; 8 | const mockedState = { 9 | router, 10 | }; 11 | expect(makeSelectLocation()(mockedState)).toEqual(router.location); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/HomePage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Asynchronously loads the component for HomePage 3 | */ 4 | 5 | import loadable from 'utils/loadable'; 6 | 7 | export default loadable(() => import('./index')); 8 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/HomePage/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * HomePage 3 | * 4 | * This is the first thing users see of our App, at the '/' route 5 | * 6 | */ 7 | 8 | import React from 'react'; 9 | import { FormattedMessage } from 'react-intl'; 10 | import messages from './messages'; 11 | 12 | export default function HomePage() { 13 | return ( 14 |

15 | 16 |

17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/HomePage/messages.js: -------------------------------------------------------------------------------- 1 | /* 2 | * HomePage Messages 3 | * 4 | * This contains all the text for the HomePage container. 5 | */ 6 | import { defineMessages } from 'react-intl'; 7 | 8 | export const scope = 'app.containers.HomePage'; 9 | 10 | export default defineMessages({ 11 | header: { 12 | id: `${scope}.header`, 13 | defaultMessage: 'This is the HomePage container!', 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/HomePage/tests/__snapshots__/index.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[` should render and match the snapshot 1`] = ` 4 |

5 | 6 | This is the HomePage container! 7 | 8 |

9 | `; 10 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/HomePage/tests/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-testing-library'; 3 | import { IntlProvider } from 'react-intl'; 4 | 5 | import HomePage from '../index'; 6 | 7 | describe('', () => { 8 | it('should render and match the snapshot', () => { 9 | const { 10 | container: { firstChild }, 11 | } = render( 12 | 13 | 14 | , 15 | ); 16 | expect(firstChild).toMatchSnapshot(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/LanguageProvider/actions.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * LanguageProvider actions 4 | * 5 | */ 6 | 7 | import { CHANGE_LOCALE } from './constants'; 8 | 9 | export function changeLocale(languageLocale) { 10 | return { 11 | type: CHANGE_LOCALE, 12 | locale: languageLocale, 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/LanguageProvider/constants.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * LanguageProvider constants 4 | * 5 | */ 6 | 7 | export const CHANGE_LOCALE = 'app/LanguageToggle/CHANGE_LOCALE'; 8 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/LanguageProvider/reducer.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * LanguageProvider reducer 4 | * 5 | */ 6 | import produce from 'immer'; 7 | 8 | import { CHANGE_LOCALE } from './constants'; 9 | import { DEFAULT_LOCALE } from '../../i18n'; 10 | 11 | export const initialState = { 12 | locale: DEFAULT_LOCALE, 13 | }; 14 | 15 | /* eslint-disable default-case, no-param-reassign */ 16 | const languageProviderReducer = (state = initialState, action) => 17 | produce(state, draft => { 18 | switch (action.type) { 19 | case CHANGE_LOCALE: 20 | draft.locale = action.locale; 21 | break; 22 | } 23 | }); 24 | 25 | export default languageProviderReducer; 26 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/LanguageProvider/selectors.js: -------------------------------------------------------------------------------- 1 | import { createSelector } from 'reselect'; 2 | import { initialState } from './reducer'; 3 | 4 | /** 5 | * Direct selector to the languageToggle state domain 6 | */ 7 | const selectLanguage = state => state.language || initialState; 8 | 9 | /** 10 | * Select the language locale 11 | */ 12 | 13 | const makeSelectLocale = () => 14 | createSelector( 15 | selectLanguage, 16 | languageState => languageState.locale, 17 | ); 18 | 19 | export { selectLanguage, makeSelectLocale }; 20 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/NotFoundPage/Loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Asynchronously loads the component for NotFoundPage 3 | */ 4 | 5 | import loadable from 'utils/loadable'; 6 | 7 | export default loadable(() => import('./index')); 8 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/NotFoundPage/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * NotFoundPage 3 | * 4 | * This is the page we show when the user visits a url that doesn't have a route 5 | * 6 | */ 7 | 8 | import React from 'react'; 9 | import { FormattedMessage } from 'react-intl'; 10 | 11 | import messages from './messages'; 12 | 13 | export default function NotFound() { 14 | return ( 15 |

16 | 17 |

18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/NotFoundPage/messages.js: -------------------------------------------------------------------------------- 1 | /* 2 | * NotFoundPage Messages 3 | * 4 | * This contains all the text for the NotFoundPage container. 5 | */ 6 | import { defineMessages } from 'react-intl'; 7 | 8 | export const scope = 'app.containers.NotFoundPage'; 9 | 10 | export default defineMessages({ 11 | header: { 12 | id: `${scope}.header`, 13 | defaultMessage: 'This is the NotFoundPage container!', 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/NotFoundPage/tests/__snapshots__/index.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[` should render and match the snapshot 1`] = ` 4 |

5 | 6 | This is the NotFoundPage container! 7 | 8 |

9 | `; 10 | -------------------------------------------------------------------------------- /ui/internals/templates/containers/NotFoundPage/tests/index.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-testing-library'; 3 | import { IntlProvider } from 'react-intl'; 4 | 5 | import NotFoundPage from '../index'; 6 | 7 | describe('', () => { 8 | it('should render and match the snapshot', () => { 9 | const { 10 | container: { firstChild }, 11 | } = render( 12 | 13 | 14 | , 15 | ); 16 | expect(firstChild).toMatchSnapshot(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /ui/internals/templates/global-styles.js: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components'; 2 | 3 | const GlobalStyle = createGlobalStyle` 4 | html, 5 | body { 6 | height: 100%; 7 | width: 100%; 8 | } 9 | 10 | body { 11 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 12 | } 13 | 14 | body.fontLoaded { 15 | font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 16 | } 17 | 18 | #app { 19 | background-color: #fafafa; 20 | min-height: 100%; 21 | min-width: 100%; 22 | } 23 | 24 | p, 25 | label { 26 | font-family: Georgia, Times, 'Times New Roman', serif; 27 | line-height: 1.5em; 28 | } 29 | `; 30 | 31 | export default GlobalStyle; 32 | -------------------------------------------------------------------------------- /ui/internals/templates/reducers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Combine all reducers in this file and export the combined reducers. 3 | */ 4 | 5 | import { combineReducers } from 'redux'; 6 | import { connectRouter } from 'connected-react-router'; 7 | 8 | import history from 'utils/history'; 9 | import languageProviderReducer from 'containers/LanguageProvider/reducer'; 10 | 11 | /** 12 | * Merges the main reducer with the router state and dynamically injected reducers 13 | */ 14 | export default function createReducer(injectedReducers = {}) { 15 | const rootReducer = combineReducers({ 16 | language: languageProviderReducer, 17 | router: connectRouter(history), 18 | ...injectedReducers, 19 | }); 20 | 21 | return rootReducer; 22 | } 23 | -------------------------------------------------------------------------------- /ui/internals/templates/translations/en.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /ui/internals/templates/utils/checkStore.js: -------------------------------------------------------------------------------- 1 | import { conformsTo, isFunction, isObject } from 'lodash'; 2 | import invariant from 'invariant'; 3 | 4 | /** 5 | * Validate the shape of redux store 6 | */ 7 | export default function checkStore(store) { 8 | const shape = { 9 | dispatch: isFunction, 10 | subscribe: isFunction, 11 | getState: isFunction, 12 | replaceReducer: isFunction, 13 | runSaga: isFunction, 14 | injectedReducers: isObject, 15 | injectedSagas: isObject, 16 | }; 17 | invariant( 18 | conformsTo(store, shape), 19 | '(app/utils...) injectors: Expected a valid redux store', 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /ui/internals/templates/utils/constants.js: -------------------------------------------------------------------------------- 1 | export const RESTART_ON_REMOUNT = '@@saga-injector/restart-on-remount'; 2 | export const DAEMON = '@@saga-injector/daemon'; 3 | export const ONCE_TILL_UNMOUNT = '@@saga-injector/once-till-unmount'; 4 | -------------------------------------------------------------------------------- /ui/internals/templates/utils/history.js: -------------------------------------------------------------------------------- 1 | import { createBrowserHistory } from 'history'; 2 | const history = createBrowserHistory(); 3 | export default history; 4 | -------------------------------------------------------------------------------- /ui/internals/templates/utils/loadable.js: -------------------------------------------------------------------------------- 1 | import React, { lazy, Suspense } from 'react'; 2 | 3 | const loadable = (importFunc, { fallback = null } = { fallback: null }) => { 4 | const LazyComponent = lazy(importFunc); 5 | 6 | return props => ( 7 | 8 | 9 | 10 | ); 11 | }; 12 | 13 | export default loadable; 14 | -------------------------------------------------------------------------------- /ui/internals/testing/test-bundler.js: -------------------------------------------------------------------------------- 1 | // needed for regenerator-runtime 2 | // (ES7 generator support is required by redux-saga) 3 | import '@babel/polyfill'; 4 | -------------------------------------------------------------------------------- /ui/server/argv.js: -------------------------------------------------------------------------------- 1 | module.exports = require('minimist')(process.argv.slice(2)); 2 | -------------------------------------------------------------------------------- /ui/server/middlewares/frontendMiddleware.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 3 | /** 4 | * Front-end middleware 5 | */ 6 | module.exports = (app, options) => { 7 | const isProd = process.env.NODE_ENV === 'production'; 8 | 9 | if (isProd) { 10 | const addProdMiddlewares = require('./addProdMiddlewares'); 11 | addProdMiddlewares(app, options); 12 | } else { 13 | const webpackConfig = require('../../internals/webpack/webpack.dev.babel'); 14 | const addDevMiddlewares = require('./addDevMiddlewares'); 15 | addDevMiddlewares(app, webpackConfig); 16 | } 17 | 18 | return app; 19 | }; 20 | -------------------------------------------------------------------------------- /ui/server/port.js: -------------------------------------------------------------------------------- 1 | const argv = require('./argv'); 2 | 3 | module.exports = parseInt(argv.port || process.env.PORT || '3000', 10); 4 | --------------------------------------------------------------------------------