├── tsconfig.json
├── ui-automation
├── cypress.json
├── cypress
│ ├── fixtures
│ │ └── example.json
│ ├── integration
│ │ └── example_spec.js
│ ├── screenshots
│ │ └── This section describes how to manage your Holochat profile -- Fill out the required fields marked with an and click Register.png
│ ├── plugins
│ │ └── index.js
│ └── support
│ │ ├── index.js
│ │ └── commands.js
└── package.json
├── test
├── backnforth
│ ├── _config.json
│ ├── person2.json
│ └── person1.json
├── coustom_room
│ ├── _config.json
│ ├── person2.json
│ └── person1.json
├── private_backnforth
│ ├── _config.json
│ ├── person2.json
│ └── person1.json
├── rooms_public.json
├── rooms_private.json
├── rooms_private_membership.json
├── rooms_exceptions.json
├── profiles.json
├── messages_exceptions.json
├── coustom_room.json
├── messages.json
└── rooms_private_messaging.json
├── ui-src
├── public
│ ├── Flag.png
│ ├── Info.png
│ ├── Pin.png
│ ├── Settings.png
│ ├── favicon.ico
│ ├── holo-logo.png
│ ├── j-avatar.png
│ ├── GitHub-Mark.png
│ ├── art-brock-avatar.png
│ ├── followers-mockup.png
│ ├── holochain-circle.png
│ ├── keith-swann-avatar.png
│ ├── mark-finnern-avatar.png
│ ├── adam-thompson-avatar.png
│ ├── connor-turland-avatar.png
│ ├── philip-beadle-avatar.png
│ ├── manifest.json
│ ├── manifest0.json
│ ├── index.html
│ └── hc.js
├── copy-to-ui.js
├── src
│ ├── stories
│ │ └── index.js
│ ├── actions.js
│ ├── reducers
│ │ └── index.js
│ ├── root.js
│ ├── containers
│ │ └── profileContainer.js
│ ├── index.js
│ ├── components
│ │ ├── profile.story.js
│ │ ├── lists
│ │ │ ├── message-list.js
│ │ │ ├── channel-list.story.js
│ │ │ ├── channel-list.js
│ │ │ └── message-list.story.js
│ │ ├── idea-card.story.js
│ │ ├── profile.js
│ │ ├── message.story.js
│ │ ├── message.js
│ │ └── idea-card.js
│ ├── withRoot.js
│ └── layouts
│ │ ├── profile.js
│ │ ├── index.js
│ │ └── messages.js
├── .storybook
│ ├── addons.js
│ └── config.js
├── copy-release.js
└── package.json
├── dna
├── @types
│ ├── holochat
│ │ └── holochat.d.ts
│ └── holochain
│ │ ├── index.d.ts
│ │ └── holochain.d.ts
├── anchors
│ ├── anchor.json
│ └── anchors.js
├── rooms
│ ├── room.json
│ └── rooms.js
├── coustom_room
│ ├── coustom_room_details.json
│ ├── cr_message.json
│ ├── coustom_room.js
│ └── coustom_room.ts
├── properties_schema.json
├── hashtag
│ ├── tag_post.json
│ └── hashtag.js
├── messages
│ ├── message.json
│ └── messages.js
├── profiles
│ ├── profile.json
│ └── profiles.js
├── identity
│ └── identity.js
├── membership
│ └── membership.js
└── dna.json
├── .gitignore
├── ui
├── holo_chat.css
├── index.html
└── holo_chat.js
├── .travis.yml
├── docker-compose.yml
├── README.md
├── docs
└── post_functions.md
└── hack.md
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": true
3 | }
4 |
--------------------------------------------------------------------------------
/ui-automation/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "chromeWebSecurity": false
3 | }
4 |
--------------------------------------------------------------------------------
/test/backnforth/_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "GossipInterval":500,
3 | "Duration":3
4 | }
5 |
--------------------------------------------------------------------------------
/test/coustom_room/_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "GossipInterval":500,
3 | "Duration":5
4 | }
5 |
--------------------------------------------------------------------------------
/ui-src/public/Flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/Flag.png
--------------------------------------------------------------------------------
/ui-src/public/Info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/Info.png
--------------------------------------------------------------------------------
/ui-src/public/Pin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/Pin.png
--------------------------------------------------------------------------------
/test/private_backnforth/_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "GossipInterval":500,
3 | "Duration":5
4 | }
5 |
--------------------------------------------------------------------------------
/ui-src/public/Settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/Settings.png
--------------------------------------------------------------------------------
/ui-src/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/favicon.ico
--------------------------------------------------------------------------------
/ui-src/public/holo-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/holo-logo.png
--------------------------------------------------------------------------------
/ui-src/public/j-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/j-avatar.png
--------------------------------------------------------------------------------
/ui-src/public/GitHub-Mark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/GitHub-Mark.png
--------------------------------------------------------------------------------
/ui-src/public/art-brock-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/art-brock-avatar.png
--------------------------------------------------------------------------------
/ui-src/public/followers-mockup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/followers-mockup.png
--------------------------------------------------------------------------------
/ui-src/public/holochain-circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/holochain-circle.png
--------------------------------------------------------------------------------
/ui-src/public/keith-swann-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/keith-swann-avatar.png
--------------------------------------------------------------------------------
/ui-src/public/mark-finnern-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/mark-finnern-avatar.png
--------------------------------------------------------------------------------
/ui-src/public/adam-thompson-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/adam-thompson-avatar.png
--------------------------------------------------------------------------------
/ui-src/public/connor-turland-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/connor-turland-avatar.png
--------------------------------------------------------------------------------
/ui-src/public/philip-beadle-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-src/public/philip-beadle-avatar.png
--------------------------------------------------------------------------------
/ui-src/copy-to-ui.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | var rimraf = require('rimraf')
3 | rimraf.sync('../ui')
4 | fs.renameSync('build', '../ui')
5 |
--------------------------------------------------------------------------------
/ui-src/src/stories/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { action } from '@storybook/addon-actions';
4 |
--------------------------------------------------------------------------------
/ui-src/.storybook/addons.js:
--------------------------------------------------------------------------------
1 | import '@storybook/addon-actions/register'
2 | import '@storybook/addon-links/register'
3 | import 'storybook-addon-specifications/register'
4 |
--------------------------------------------------------------------------------
/ui-automation/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io",
4 | "body": "Fixtures are a great way to mock data for responses to routes"
5 | }
--------------------------------------------------------------------------------
/dna/@types/holochat/holochat.d.ts:
--------------------------------------------------------------------------------
1 | type UUID = string;
2 |
3 | interface message {
4 | uuid : UUID;
5 | message : any;
6 | }
7 |
8 | interface updateMessage {
9 | new_message: any;
10 | old_hash : Hash;
11 | }
12 |
--------------------------------------------------------------------------------
/dna/anchors/anchor.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Anchor Schema",
3 | "type": "object",
4 | "properties": {
5 | "anchorType": {
6 | "type": "string"
7 | },
8 | "anchorText": {
9 | "type": "string"
10 | }
11 | },
12 | "required": ["anchorType"]
13 | }
14 |
--------------------------------------------------------------------------------
/ui-src/copy-release.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path')
3 | var rimraf = require('rimraf')
4 | rimraf.sync('../release')
5 | fs.mkdirSync(path.join(__dirname, '../release'))
6 | fs.renameSync('../ui', '../release/ui')
7 | fs.renameSync('../dna', '../release/dna')
8 |
--------------------------------------------------------------------------------
/dna/rooms/room.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Room Schema",
3 | "type": "object",
4 | "properties": {
5 | "name": {
6 | "type": "string"
7 | },
8 | "access": {
9 | "type": "string"
10 | },
11 | "purpose": {
12 | "type": "string"
13 | }
14 | },
15 | "required": ["name","access"]
16 | }
17 |
--------------------------------------------------------------------------------
/dna/coustom_room/coustom_room_details.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Room Schema",
3 | "type": "object",
4 | "properties": {
5 | "name": {
6 | "type": "string"
7 | },
8 | "access": {
9 | "type": "string"
10 | },
11 | "purpose": {
12 | "type": "string"
13 | }
14 | },
15 | "required": ["name"]
16 | }
17 |
--------------------------------------------------------------------------------
/ui-src/src/actions.js:
--------------------------------------------------------------------------------
1 | // Holochain actions
2 | export const REGISTER = 'register'
3 |
4 | export function register (profile, then) {
5 | return {
6 | type: REGISTER,
7 | meta: {
8 | isHc: true,
9 | namespace: 'profiles',
10 | data: profile,
11 | then
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/dna/properties_schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Properties Schema",
3 | "type": "object",
4 | "properties": {
5 | "name": {
6 | "type": "string"
7 | },
8 | "purpose": {
9 | "type": "string"
10 | },
11 | "language": {
12 | "type": "string"
13 | },
14 | "initial_admin": {
15 | "type": "string"
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ui-automation/cypress/integration/example_spec.js:
--------------------------------------------------------------------------------
1 | describe('This section describes how to manage your Holochat handle', function () {
2 | it('Let\'s check that all 3 instances of Clutter are running.)', function () {
3 | cy.visit('http://localhost:3141')
4 | cy.request('http://localhost:4141')
5 | cy.request('http://localhost:5141')
6 | })
7 | })
8 |
--------------------------------------------------------------------------------
/ui-automation/cypress/screenshots/This section describes how to manage your Holochat profile -- Fill out the required fields marked with an and click Register.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/holochain/holochat/HEAD/ui-automation/cypress/screenshots/This section describes how to manage your Holochat profile -- Fill out the required fields marked with an and click Register.png
--------------------------------------------------------------------------------
/ui-src/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64",
8 | "type": "image/png"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/ui-src/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import * as A from '../actions'
2 |
3 | const initialState = {
4 | key: 10
5 | }
6 |
7 | export default function holochatApp (state = initialState, action) {
8 | const { type, meta, payload } = action
9 | switch (type) {
10 | case A.REGISTER:
11 | console.log(payload)
12 | return state
13 | default:
14 | return state
15 | }
16 | }
--------------------------------------------------------------------------------
/dna/hashtag/tag_post.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Hash Tag posts Schema",
3 | "type": "object",
4 | "properties": {
5 | "content": {
6 | "type": "string"
7 | },
8 | "timestamp": {
9 | "type": "string"
10 | },
11 | "room": {
12 | "type": "string"
13 | },
14 | "inReplyTo": {
15 | "type": "string"
16 | }
17 | },
18 | "required": ["content", "timestamp", "room"]
19 | }
20 |
--------------------------------------------------------------------------------
/ui-src/public/manifest0.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/ui-src/.storybook/config.js:
--------------------------------------------------------------------------------
1 | import { configure } from '@storybook/react'
2 | const componentStories = require.context('../src/components', true, /story\.js$/)
3 | const listStories = require.context('../src/components/lists', true, /story\.js$/)
4 | function loadStories () {
5 | componentStories.keys().forEach(componentStories)
6 | listStories.keys().forEach(listStories)
7 | }
8 |
9 | configure(loadStories, module)
10 |
--------------------------------------------------------------------------------
/ui-src/src/root.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { Provider } from 'react-redux'
4 | import { BrowserRouter as Router, Route } from 'react-router-dom'
5 | import Index from './layouts/index'
6 |
7 | const Root = ({ store }) => (
8 |
9 |
10 |
11 |
12 |
13 | )
14 |
15 | export default Root
16 |
--------------------------------------------------------------------------------
/dna/coustom_room/cr_message.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Message Schema",
3 | "type": "object",
4 | "properties": {
5 | "author":{
6 | "type": "string"
7 | },
8 | "timestamp": {
9 | "type": "string"
10 | },
11 | "content": {
12 | "properties":{
13 | "text":{
14 | "type": "string"
15 | },
16 | "mediaLink":{
17 | "type": "string"
18 | }
19 | }
20 | }
21 | },
22 | "required": ["author","timestamp","content"]
23 | }
24 |
--------------------------------------------------------------------------------
/dna/messages/message.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Message Schema",
3 | "type": "object",
4 | "properties": {
5 | "author":{
6 | "type": "string"
7 | },
8 | "content": {
9 | "properties":{
10 | "text":{
11 | "type": "string"
12 | },
13 | "mediaLink":{
14 | "type": "string"
15 | }
16 | }
17 | },
18 | "timestamp": {
19 | "type": "string"
20 | },
21 | "room_name": {
22 | "type": "string"
23 | }
24 | },
25 | "required": ["author","room_name","content", "timestamp"]
26 | }
27 |
--------------------------------------------------------------------------------
/test/coustom_room/person2.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests": [{
3 | "Time": 0,
4 | "Convey": "0. Gets Keys and initialize",
5 | "Zome": "coustom_room",
6 | "FnName": "getKey",
7 | "Input": "",
8 | "Output": "%key%"
9 | },
10 | {
11 | "Time": 3000,
12 | "Convey": "1. Get the rooms|chats you are part of (UUID)",
13 | "Zome": "coustom_room",
14 | "FnName": "getMyRooms",
15 | "Input": "",
16 | "RegExp":"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/ui-src/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Holo Chat
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/dna/profiles/profile.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Profile Schema",
3 | "type": "object",
4 | "properties": {
5 | "agent_id": {
6 | "type": "string"
7 | },
8 | "agent_hash": {
9 | "type": "string"
10 | },
11 | "username": {
12 | "type": "string"
13 | },
14 | "firstName": {
15 | "type": "string"
16 | },
17 | "lastName": {
18 | "type": "string"
19 | },
20 | "email": {
21 | "type": "string"
22 | },
23 | "avatar": {
24 | "type": "string"
25 | }
26 | },
27 | "required": ["agent_id", "username", "firstName", "lastName", "email"]
28 | }
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .txt
2 | .key
3 | agent.txt
4 | restart.sh
5 |
6 | # See https://help.github.com/ignore-files/ for more about ignoring files.
7 | .DS_Store
8 | # dependencies
9 | ui-src/node_modules
10 | ui-automation/cypress/screenshots
11 | ui-automation/cypress/videos
12 | ui-automation/node_modules
13 | ui
14 |
15 | # testing
16 | /coverage
17 |
18 | # production
19 | /build
20 |
21 | # misc
22 | .DS_Store
23 | .env.local
24 | .env.development.local
25 | .env.test.local
26 | .env.production.local
27 |
28 | npm-debug.log*
29 | yarn-debug.log*
30 | yarn-error.log*
31 |
32 | yarn.lock
33 | package-lock.json*
34 |
--------------------------------------------------------------------------------
/test/coustom_room/person1.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests": [
3 | {
4 | "Time":0,
5 | "Convey": "0. Gets Keys and initialize",
6 | "Zome": "coustom_room",
7 | "FnName": "getKey",
8 | "Input": "",
9 | "Output": "%key%"
10 | },
11 | {
12 | "Time":10,
13 | "Convey": "1. Create new Room",
14 | "Zome": "coustom_room",
15 | "FnName": "createCoustomRoom",
16 | "Input": ["QmcWesmzNkvv2jSKo1msv8xNo5h7NxoyPJL8KCtm7cfzzx"],
17 | "RegExp": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
18 | "Err": ""
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/ui/holo_chat.css:
--------------------------------------------------------------------------------
1 | .rooms {
2 | width: 300px;
3 | cursor: pointer;
4 | }
5 | #room-name-input, #room-name-button {
6 | width: 100%;
7 | }
8 |
9 | .rooms ul {
10 |
11 | }
12 |
13 | #messages {
14 | width: 100%;
15 | height: 300px;
16 | border: 1px solid grey;
17 | border-radius: 2px;
18 | overflow: scroll;
19 | padding-left: 10px;
20 | }
21 |
22 | #messages .username {
23 | display: block;
24 | font-size: 12px;
25 | font-weight: bold;
26 | }
27 |
28 | #messages .timestamp {
29 | float: right;
30 | font-size: 10px;
31 | color: light-grey;
32 | }
33 |
34 | #messages .message {
35 | padding-left: 5px;
36 | }
37 |
38 | .selected-room {
39 | border: 1px solid grey;
40 | border-radius: 4px;
41 | }
42 |
--------------------------------------------------------------------------------
/ui-src/src/containers/profileContainer.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux'
2 | import Profile from '../components/profile'
3 | import {
4 | register
5 | } from '../actions'
6 |
7 | const mapStateToProps = state => {
8 | return {
9 | ...state
10 | }
11 | }
12 |
13 | const mapDispatchToProps = (dispatch) => {
14 | return {
15 | register: (profile) => {
16 | console.log('registering!')
17 | const prof = {
18 | username: 'Hi',
19 | firstName: 'Jim',
20 | lastName: 'Roberts',
21 | email: '123@email.com'
22 | }
23 | dispatch(register(prof))
24 | }
25 | }
26 | }
27 |
28 | export default connect(
29 | mapStateToProps,
30 | mapDispatchToProps
31 | )(Profile)
--------------------------------------------------------------------------------
/ui-automation/cypress/plugins/index.js:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example plugins/index.js can be used to load plugins
3 | //
4 | // You can change the location of this file or turn off loading
5 | // the plugins file with the 'pluginsFile' configuration option.
6 | //
7 | // You can read more here:
8 | // https://on.cypress.io/plugins-guide
9 | // ***********************************************************
10 |
11 | // This function is called when a project is opened or re-opened (e.g. due to
12 | // the project's config changing)
13 |
14 | module.exports = (on, config) => {
15 | // `on` is used to hook into various events Cypress emits
16 | // `config` is the resolved Cypress config
17 | }
18 |
--------------------------------------------------------------------------------
/ui-automation/cypress/support/index.js:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/index.js is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.js using ES2015 syntax:
17 | import './commands'
18 |
19 | // Alternatively you can use CommonJS syntax:
20 | // require('./commands')
21 |
--------------------------------------------------------------------------------
/ui-src/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import { compact } from 'lodash'
4 | import { applyMiddleware, compose, createStore } from 'redux'
5 | import promiseMiddleware from 'redux-promise'
6 | import { requestSendingMiddleware, hcMiddleware } from 'hc-redux-middleware'
7 | import holochatApp from './reducers'
8 | import Root from './root'
9 |
10 | const middleware = compact([
11 | hcMiddleware,
12 | requestSendingMiddleware,
13 | promiseMiddleware
14 | ])
15 |
16 | const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
17 | let store = createStore(holochatApp, undefined, composeEnhancers(applyMiddleware(...middleware)))
18 |
19 | ReactDOM.render(, document.querySelector('#root'))
20 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | language: node_js
3 | node_js:
4 | - '8'
5 | env:
6 | matrix:
7 | - DOCKER_COMPOSE_VERSION=1.18.0
8 |
9 | services:
10 | - docker
11 | before_install:
12 | - cd ui-src
13 | - npm install
14 | - npm run build
15 | - npm run start &
16 | - cd ..
17 | - sudo rm /usr/local/bin/docker-compose
18 | - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname
19 | -s`-`uname -m` > docker-compose
20 | - chmod +x docker-compose
21 | - sudo mv docker-compose /usr/local/bin
22 | - TARGETDIR=$(pwd) docker-compose up -d
23 | script:
24 | - cd ui-automation
25 | - npm install
26 | - npm test
27 | - docker-compose kill
28 | - docker-compose down
29 | cache:
30 | directories:
31 | - ui-automation/node_modules
32 |
--------------------------------------------------------------------------------
/ui-automation/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ui-automation",
3 | "version": "0.0.1",
4 | "description": "e2e tests for holochat",
5 | "main": "index.js",
6 | "repository": "https://github.com/Holochain/holochat",
7 | "author": "Philip Beadle",
8 | "license": "MIT",
9 | "scripts": {
10 | "test": "CYPRESS_baseUrl=http://localhost:3000 cypress run",
11 | "cypress:open": "CYPRESS_baseUrl=http://localhost:3000 cypress open",
12 | "cypress:docker": "CYPRESS_baseUrl=http://localhost:4141 cypress open"
13 | },
14 | "dependencies": {
15 | "cypress": "^1.4.1"
16 | },
17 | "standard": {
18 | "globals": [
19 | "describe",
20 | "context",
21 | "before",
22 | "beforeEach",
23 | "after",
24 | "afterEach",
25 | "it",
26 | "expect",
27 | "cy"
28 | ]
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/ui-automation/cypress/support/commands.js:
--------------------------------------------------------------------------------
1 | // ***********************************************
2 | // This example commands.js shows you how to
3 | // create various custom commands and overwrite
4 | // existing commands.
5 | //
6 | // For more comprehensive examples of custom
7 | // commands please read more here:
8 | // https://on.cypress.io/custom-commands
9 | // ***********************************************
10 | //
11 | //
12 | // -- This is a parent command --
13 | // Cypress.Commands.add("login", (email, password) => { ... })
14 | //
15 | //
16 | // -- This is a child command --
17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
18 | //
19 | //
20 | // -- This is a dual command --
21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
22 | //
23 | //
24 | // -- This is will overwrite an existing command --
25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
26 |
--------------------------------------------------------------------------------
/ui-src/src/components/profile.story.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import { action } from '@storybook/addon-actions'
4 | import { specs, describe, it } from 'storybook-addon-specifications'
5 | import { configure, mount } from 'enzyme'
6 | import Adapter from 'enzyme-adapter-react-16'
7 | import Profile from './profile'
8 | import expect from 'expect'
9 |
10 | configure({ adapter: new Adapter() })
11 |
12 | storiesOf('Profile', module)
13 | .add('Registering a new person', () => {
14 | // const following = [
15 | // {'handle': 'philt3r', 'userHash': 'wegwtrwrt'},
16 | // {'handle': 'Test 2', 'userHash': 'dddd'}
17 | // ]
18 | specs(() => describe('The Follow Form with followed entities', function () {
19 | it('You can see the list of entities you are following, if you are following any.', () => {
20 | expect(true)
21 | })
22 | }))
23 |
24 | return getProfile()
25 | })
26 |
27 | function getProfile () {
28 | return (
29 |
30 | )
31 | }
32 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 |
3 | services:
4 |
5 | bootstrap:
6 | image: holochain/holochain-proto:develop
7 | ports:
8 | - "3142:3142"
9 | command: bs
10 |
11 | holochat1:
12 | image: holochain/holochain-proto:develop
13 | ports:
14 | - "3141:3141"
15 | depends_on:
16 | - bootstrap
17 | volumes:
18 | - "${TARGETDIR}:/holochat"
19 | command: bash -c "cd /holochat; hcdev -port=6001 -agentID=lucy -bootstrapServer=bootstrap:3142 web 3141"
20 |
21 | holochat2:
22 | image: holochain/holochain-proto:develop
23 | ports:
24 | - "4141:4141"
25 | depends_on:
26 | - bootstrap
27 | volumes:
28 | - "${TARGETDIR}:/holochat"
29 | command: bash -c "cd /holochat; hcdev -port=6002 -agentID=phil -bootstrapServer=bootstrap:3142 web 4141"
30 |
31 | holochat3:
32 | image: holochain/holochain-proto:develop
33 | ports:
34 | - "5141:5141"
35 | depends_on:
36 | - bootstrap
37 | volumes:
38 | - "${TARGETDIR}:/holochat"
39 | command: bash -c "cd /holochat; hcdev -port=6003 -agentID=clarence -bootstrapServer=bootstrap:3142 web 5141"
40 |
--------------------------------------------------------------------------------
/test/rooms_public.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests":[
3 | {
4 | "Convey":"0. Register User ",
5 | "Zome":"profiles",
6 | "FnName":"register",
7 | "Input":{"username":"cnorris", "firstName":"Chuck", "lastName":"Norris", "email":"chuck@norris.com"},
8 | "Output":"%h6%",
9 | "Err":""
10 | },{
11 | "Convey":"1. Check if hes registered",
12 | "Zome":"profiles",
13 | "FnName":"isRegistered",
14 | "Input":"",
15 | "Output":true,
16 | "Err":""
17 | },
18 | {
19 | "Convey":"2. newRoom should return the room's hash",
20 | "Zome":"rooms",
21 | "FnName":"newRoom",
22 | "Input":{"name":"general", "access":"public"},
23 | "Output":"%h5%",
24 | "Err":""
25 | },
26 | {
27 | "Convey":"3. getPublicRooms should return a list of rooms",
28 | "Zome":"rooms",
29 | "FnName":"getPublicRooms",
30 | "Input":"",
31 | "Output":[{"id":"%r1%","name":"general","access":"public"}],
32 | "Err":""
33 | }
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/ui-src/src/withRoot.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles'
3 | import CssBaseline from 'material-ui/CssBaseline'
4 |
5 | // A theme with custom primary and secondary color.
6 | // It's optional.
7 | const theme = createMuiTheme({
8 | palette: {
9 | primary: {
10 | light: '#d05ce3',
11 | main: '#9c27b0',
12 | dark: '#6a0080'
13 | },
14 | secondary: {
15 | light: '#6ff9ff',
16 | main: '#26cd6a',
17 | dark: '#0095a8'
18 | }
19 | }
20 | })
21 |
22 | // Expose the theme as a global variable so people can play with it.
23 | if (process.browser) {
24 | window.theme = theme
25 | }
26 |
27 | function withRoot (Component) {
28 | function WithRoot (props) {
29 | // MuiThemeProvider makes the theme available down the React tree
30 | // thanks to React context.
31 | return (
32 |
33 | {/* Reboot kickstart an elegant, consistent, and simple baseline to build upon. >> Reboot renamed CssBaseline. */}
34 |
35 |
36 |
37 | )
38 | }
39 |
40 | return WithRoot
41 | }
42 |
43 | export default withRoot
44 |
--------------------------------------------------------------------------------
/ui-src/public/hc.js:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2013-2017, The MetaCurrency Project (Eric Harris-Braun & Arthur Brock)
2 | // Use of this source code is governed by GPLv3 found in the LICENSE file
3 | //---------------------------------------------------------------------------------------
4 |
5 | // Holochain UI library
6 |
7 | // use send to make an ajax call to your exposed functions
8 | function send(fn,data,resultFn) {
9 | if (Clutter.debug) console.log("calling: " + fn+" with "+JSON.stringify(data));
10 |
11 | eval(Clutter.getHook(fn, "preSendHook"));
12 | $.post(
13 | "/fn/clutter/"+fn,
14 | data,
15 | function(response) {
16 | if (Clutter.debug) console.log("response: " + response);
17 | eval(Clutter.getHook(fn, "successPreResult"));
18 | resultFn(response);
19 | eval(Clutter.getHook(fn, "successPostResult"));
20 | }
21 | ).error(function(response) {
22 | console.log("response failed: " + response.responseText);
23 | $(".error").html("" + response.responseText + "").toggleClass("show", true)
24 | setTimeout
25 | ( () =>
26 | { $(".error") .toggleClass("show", false);
27 | eval(Clutter.getHook(fn, "errorTimeoutComplete"));
28 | },
29 | 2000
30 | );
31 | })
32 | ;
33 | };
34 |
--------------------------------------------------------------------------------
/dna/identity/identity.js:
--------------------------------------------------------------------------------
1 | function genesis(){return true}
2 |
3 | function bridgeGenesis(side,dna,appData){
4 | appDNAHash=getDpkiDNA()
5 | data=bridge(appDNAHash, "dpkiLib", "registerDpkiTo", App.Agent.Hash)
6 | debug("data = "+data)
7 | return true
8 | }
9 |
10 | function registerDpkiKeyTo(){
11 | appDNAHash=getDpkiDNA();
12 | debug("registerDpkiKeyTo = "+appDNAHash)
13 | data = bridge(appDNAHash, "dpkiLib", "registerDpkiKeyTo", App.Agent.Hash)
14 | debug("data = "+JSON.stringify(data))
15 | return data
16 | }
17 |
18 | function hasRegisteredKey(app_agent_id){
19 | debug("AGENT : "+app_agent_id)
20 | appDNAHash=getDpkiDNA();
21 | debug("hasRegisteredKey = "+appDNAHash)
22 | data = bridge(appDNAHash, "dpkiLib", "hasRegisteredKey",app_agent_id)
23 | debug("data = "+JSON.stringify(data))
24 | return data
25 | }
26 |
27 | function getUserDetails(app_agent_id){
28 | appDNAHash=getDpkiDNA();
29 | debug("getUserDetails = "+appDNAHash)
30 | data = bridge(appDNAHash, "dpkiLib", "getUserDetails", app_agent_id)
31 | debug("data = "+JSON.stringify(data))
32 | return data
33 | }
34 |
35 |
36 | /////////////////
37 | // DPKI DNA Hash
38 | ////////////////
39 | function getDpkiDNA(){
40 | bridges = getBridges();
41 | if (bridges[0] != undefined) {
42 | return bridges[0].ToApp
43 | } else {
44 | debug("identityZome: No bridge found!")
45 | }
46 | return ""
47 | }
48 |
--------------------------------------------------------------------------------
/dna/@types/holochain/index.d.ts:
--------------------------------------------------------------------------------
1 | // holochain ambient type defs for API
2 |
3 | ///
4 |
5 | declare function property(name: string): string;
6 | declare function makeHash (entryType: string, entryData: any): Hash;
7 | declare function debug(value: any): void;
8 | declare function call(zomeName: string, functionName: string, arguments: string | object): any;
9 | declare function bridge(appDNAHash: Hash, zomeName: string, functionName: string, arguments: string | object): any;
10 | declare function getBridges(): BridgeStatus[];
11 | declare function sign(doc: string): string;
12 | declare function verifySignature(signature: string, data: string, pubKey: string): boolean;
13 | declare function commit(entryType: string, entryData: string | object): Hash;
14 | declare function get(hash: Hash, options?: object): GetResponse | any;
15 | declare function getLinks(base: Hash, tag: string, options?: object): GetLinksResponse[];
16 | declare function update(entryType: string, entryData: string | object, replaces: Hash) : Hash;
17 | declare function updateAgent(options: object): Hash;
18 | declare function remove(entryHash: Hash, message: string): Hash;
19 | declare function query(options?: object): QueryResponse[] | any[];
20 | declare function send(to: Hash, message: object, options?: object): any;
21 | declare function bundleStart(timeout: number, userParam: any): void;
22 | declare function bundleClose(commit: boolean): void;
23 |
24 | declare var HC: HolochainSystemGlobals;
25 | declare var App: HolochainAppGlobals;
--------------------------------------------------------------------------------
/ui-src/src/components/lists/message-list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classNames from 'classnames'
3 | import PropTypes from 'prop-types'
4 | import withRoot from '../../withRoot'
5 | import { withStyles } from 'material-ui/styles'
6 | import List, { ListItem, ListItemText } from 'material-ui/List'
7 | import Message from '../message'
8 |
9 | const styles = theme => ({
10 | listItemMessage: {
11 | position: 'relative'
12 | }
13 | })
14 |
15 | class MessageList extends React.Component {
16 | render () {
17 | const { classes, messages } = this.props
18 | return (
19 |
20 | {messages.map((messageByDate, messageDateIndex) => (
21 |
22 |
23 |
24 |
25 |
26 |
27 | {messageByDate.messages.map((message, index) => (
28 |
29 |
30 |
31 | ))}
32 |
33 |
34 |
35 | ))}
36 |
37 | )
38 | }
39 | }
40 |
41 | MessageList.propTypes = {
42 | classes: PropTypes.object.isRequired,
43 | messages: PropTypes.object.isRequired
44 |
45 | }
46 |
47 | export default withRoot(withStyles(styles)(MessageList))
48 |
--------------------------------------------------------------------------------
/dna/@types/holochain/holochain.d.ts:
--------------------------------------------------------------------------------
1 | // holochain type definitions
2 |
3 |
4 | type Hash = string;
5 | type Signature = string;
6 | type HolochainError = object;
7 | type PackageRequest = object;
8 |
9 | /*============================================
10 | = Holochain Data Types =
11 | ============================================*/
12 |
13 | interface Header {
14 | Type: string;
15 | Time: string;
16 | HeaderLink: Hash;
17 | EntryLink: Hash;
18 | TypeLink: Hash;
19 | Sig: Signature;
20 | Change: Hash;
21 | }
22 |
23 | interface GetResponse {
24 | Entry?: any;
25 | EntryType?: string;
26 | Sources?: Hash[];
27 | }
28 |
29 | interface GetLinksResponse {
30 | Hash: Hash;
31 | Entry?: any;
32 | EntryType?: string;
33 | Tag?: string;
34 | Source?: Hash;
35 | }
36 |
37 | interface QueryResponse {
38 | Hash?: string
39 | Entry?: any
40 | Header?: Header
41 | }
42 |
43 | interface BridgeStatus {
44 | Side: number;
45 | CalleeName?: string;
46 | CalleeApp?: Hash;
47 | Token?: string;
48 | }
49 |
50 |
51 | /*===== End of Holochain Data Types ======*/
52 |
53 |
54 | interface HolochainSystemGlobals {
55 | Version: string;
56 | HashNotFound: any;
57 | Status: any;
58 | GetMask: any;
59 | LinkAction: any;
60 | PkgReq: any;
61 | Bridge: any;
62 | SysEntryType: any;
63 | BundleCancel: any;
64 | }
65 |
66 | interface HolochainAppGlobals {
67 | Name: string;
68 | DNA: {
69 | Hash: Hash;
70 | };
71 | Key: {
72 | Hash: Hash;
73 | }
74 | Agent: {
75 | Hash: Hash;
76 | TopHash: Hash;
77 | String: string;
78 | }
79 | }
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/ui-src/src/components/idea-card.story.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | // import { action } from '@storybook/addon-actions'
4 | import { specs, describe, it } from 'storybook-addon-specifications'
5 | import { configure, mount } from 'enzyme'
6 | import Adapter from 'enzyme-adapter-react-16'
7 | import IdeaCard from './idea-card'
8 | import expect from 'expect'
9 |
10 | configure({ adapter: new Adapter() })
11 |
12 | storiesOf('Top Idea Card', module)
13 | .add('Display an idea', () => {
14 | const idea = {
15 | title: 'Poll Integration',
16 | productOwner: 'joatu-jamie',
17 | avatar: 'j-avatar.png',
18 | date: 'January 25, 2018 - Lead Time 6 weeks',
19 | description: 'To make it easier to gauge community support for an idea being able to attach a Poll to an idea would be cool.',
20 | up: 9,
21 | down: 0
22 | }
23 | specs(() => describe('Idea', function () {
24 | it('Clicking the Thumbs Up increases the votes shown in the Thumbs Up badge', () => {
25 | const wrapper = mount()
26 | wrapper.find('#thumbsUp').simulate('click')
27 | expect(wrapper.find('#thumbsUpBadge').value).toEqual(1)
28 | })
29 | it('Clicking the Thumbs Down increases the votes shown in the Thumbs Down badge', () => {
30 | const wrapper = mount()
31 | wrapper.find('#thumbsDown').simulate('click')
32 | expect(wrapper.find('#thumbsDownBadge').value).toEqual(1)
33 | })
34 | }))
35 |
36 | return getIdeaCard(idea)
37 | })
38 | function getIdeaCard (idea) {
39 | return (
40 |
41 | )
42 | }
43 |
--------------------------------------------------------------------------------
/test/rooms_private.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests":[
3 | {
4 | "Convey":"0. Register User ",
5 | "Zome":"profiles",
6 | "FnName":"register",
7 | "Input":{"username":"cnorris", "firstName":"Chuck", "lastName":"Norris", "email":"chuck@norris.com"},
8 | "Output":"%h6%",
9 | "Err":""
10 | },{
11 | "Convey":"1. Check if hes registered",
12 | "Zome":"profiles",
13 | "FnName":"isRegistered",
14 | "Input":"",
15 | "Output":true,
16 | "Err":""
17 | },
18 | {
19 | "Convey":"2. PRIVATE newRoom should return the room's hash",
20 | "Zome":"rooms",
21 | "FnName":"newRoom",
22 | "Input":{"name":"general", "access":"private"},
23 | "Output":"%h13%",
24 | "Err":""
25 | },
26 | {
27 | "Convey":"3. get Agent Hash for testing ",
28 | "Zome":"profiles",
29 | "FnName":"getMyAgentHash",
30 | "Input":"",
31 | "Output":"%agent%",
32 | "Err":""
33 | },
34 | {
35 | "Convey":"4. get admin of the private room ",
36 | "Zome":"rooms",
37 | "FnName":"getRoomAdmin",
38 | "Input":{"room_name":"general"},
39 | "Output":"%r1%",
40 | "Err":""
41 | },
42 | {
43 | "Convey":"5. get admin of the private room ",
44 | "Zome":"rooms",
45 | "FnName":"getRoomAdmin",
46 | "Input":{"room_name":"fake"},
47 | "Output":"ERROR: invalid PRIVATE Room name",
48 | "Err":""
49 | }
50 | ]
51 | }
52 |
--------------------------------------------------------------------------------
/test/rooms_private_membership.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests":[
3 | {
4 | "Convey":"0. Register User ",
5 | "Zome":"profiles",
6 | "FnName":"register",
7 | "Input":{"username":"cnorris", "firstName":"Chuck", "lastName":"Norris", "email":"chuck@norris.com"},
8 | "Output":"%h6%",
9 | "Err":""
10 | },{
11 | "Convey":"1. Check if hes registered",
12 | "Zome":"profiles",
13 | "FnName":"isRegistered",
14 | "Input":"",
15 | "Output":true,
16 | "Err":""
17 | },
18 | {
19 | "Convey":"2. PRIVATE newRoom should return the room's hash",
20 | "Zome":"rooms",
21 | "FnName":"newRoom",
22 | "Input":{"name":"general", "access":"private"},
23 | "Output":"%h13%",
24 | "Err":""
25 | },
26 | {
27 | "Convey":"3. add Someone to the private room ",
28 | "Zome":"membership",
29 | "FnName":"addMember",
30 | "Input":{"room_name":"general","agent_key":"%key%","agent_hash":"%agent%"},
31 | "Output":"%h2%",
32 | "Err":""
33 | },
34 | {
35 | "Convey":"4. Get the added members to the private room ",
36 | "Zome":"membership",
37 | "FnName":"getMembers",
38 | "Input":{"room_name":"general"},
39 | "Output":"%agent%",
40 | "Err":""
41 | },
42 | {
43 | "Convey":"5. Get my Private Rooms",
44 | "Zome":"rooms",
45 | "FnName":"getMyPrivateRooms",
46 | "Input":"",
47 | "Output":"general",
48 | "Err":""
49 | }
50 | ]
51 | }
52 |
--------------------------------------------------------------------------------
/ui-src/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "clutter",
3 | "version": "0.2.0",
4 | "private": true,
5 | "proxy": "http://localhost:4141",
6 | "dependencies": {
7 | "axios": "^0.17.1",
8 | "enzyme": "^3.3.0",
9 | "enzyme-adapter-react-16": "^1.1.1",
10 | "hc-redux-middleware": "^1.0.3",
11 | "jest": "^22.1.1",
12 | "lodash": "^4.17.5",
13 | "material-ui": "next",
14 | "material-ui-icons": "latest",
15 | "prop-types": "latest",
16 | "react": "latest",
17 | "react-dom": "latest",
18 | "react-redux": "latest",
19 | "react-router": "latest",
20 | "react-router-dom": "latest",
21 | "react-scripts": "latest",
22 | "redux": "^3.7.2",
23 | "redux-logger": "^3.0.6",
24 | "redux-promise": "^0.5.3",
25 | "storybook-addon-specifications": "^2.1.1"
26 | },
27 | "scripts": {
28 | "start": "react-scripts start",
29 | "build": "react-scripts build && node copy-to-ui.js",
30 | "test": "react-scripts test --env=jsdom",
31 | "eject": "react-scripts eject",
32 | "standard": "standard --fix",
33 | "release:files": "node copy-release.js",
34 | "deploy-storybook": "storybook-to-ghpages",
35 | "storybook": "start-storybook -p 9009 -s public",
36 | "build-storybook": "build-storybook -s public"
37 | },
38 | "standard": {
39 | "parser": "babel-eslint",
40 | "globals": [
41 | "describe",
42 | "context",
43 | "before",
44 | "beforeEach",
45 | "after",
46 | "afterEach",
47 | "it",
48 | "expect"
49 | ]
50 | },
51 | "devDependencies": {
52 | "@storybook/addon-actions": "^3.3.11",
53 | "@storybook/addon-links": "^3.3.11",
54 | "@storybook/react": "^3.3.11",
55 | "babel-core": "^6.26.0",
56 | "babel-eslint": "^8.2.1",
57 | "rimraf": "^2.6.2",
58 | "standard": "^10.0.3"
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/ui-src/src/layouts/profile.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import Grid from 'material-ui/Grid'
4 | import { withStyles } from 'material-ui/styles'
5 | import withRoot from '../withRoot'
6 | import Profile from '../containers/profileContainer'
7 |
8 | const styles = theme => ({
9 | root: {
10 | width: '100%',
11 | marginTop: 0,
12 | flexGrow: 1
13 | },
14 | flex: {
15 | flex: 1
16 | },
17 | demo: {
18 | height: 800
19 | },
20 | paper: {
21 | padding: 16,
22 | textAlign: 'center',
23 | color: theme.palette.text.secondary,
24 | height: '100%'
25 | },
26 | suggestions: {
27 | padding: 5,
28 | margin: 15,
29 | textAlign: 'left',
30 | color: theme.palette.text.secondary,
31 | flex: 1,
32 | height: 40
33 | },
34 | menuButton: {
35 | marginLeft: -12,
36 | marginRight: 20
37 | }
38 | })
39 |
40 | class Index extends React.Component {
41 | state = {
42 | open: false,
43 | spacing: '16',
44 | auth: true,
45 | anchorEl: null,
46 | direction: 'row',
47 | justify: 'center',
48 | alignItems: 'stretch'
49 | };
50 |
51 | handleChange = (event, checked) => {
52 | this.setState({ auth: checked })
53 | };
54 |
55 | handleMenu = event => {
56 | this.setState({ anchorEl: event.currentTarget })
57 | };
58 |
59 | handleClose = () => {
60 | this.setState({ anchorEl: null })
61 | };
62 |
63 | render () {
64 | const { classes } = this.props
65 | const { auth, anchorEl } = this.state
66 | const open = Boolean(anchorEl)
67 | const { alignItems, direction, justify } = this.state
68 | return (
69 |
70 |
71 |
72 |
73 |
74 | )
75 | }
76 | }
77 |
78 | Index.propTypes = {
79 | classes: PropTypes.object.isRequired
80 | }
81 |
82 | export default withRoot(withStyles(styles)(Index))
83 |
--------------------------------------------------------------------------------
/ui-src/src/components/lists/channel-list.story.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | // import { action } from '@storybook/addon-actions'
4 | import { specs, describe, it } from 'storybook-addon-specifications'
5 | import { configure, mount } from 'enzyme'
6 | import Adapter from 'enzyme-adapter-react-16'
7 | import ChannelList from './channel-list'
8 | import expect from 'expect'
9 | import { MemoryRouter } from 'react-router';
10 |
11 | configure({ adapter: new Adapter() })
12 |
13 | storiesOf('Channel List', module)
14 | .addDecorator(story => (
15 | {story()}
16 | ))
17 | .add('Display a list of different types of messages', () => {
18 | const channels = [
19 | {group: 'Private',
20 | channels: [
21 | {
22 | title: 'DevLife Do-op',
23 | alerts: 5
24 | },
25 | {
26 | title: 'Documentation',
27 | alerts: 0
28 | },
29 | {
30 | title: 'Governance',
31 | alerts: 1
32 | }
33 | ]},
34 | {group: 'Public',
35 | channels: [
36 | {
37 | title: 'App:HoloChat',
38 | alerts: 5
39 | },
40 | {
41 | title: 'App:Clutter',
42 | alerts: 0
43 | },
44 | {
45 | title: 'HC Core',
46 | alerts: 1
47 | }
48 | ]},
49 | {group: 'Direct Message',
50 | channels: [
51 | {
52 | title: '@artbrock',
53 | alerts: 5,
54 | status: 'online'
55 | },
56 | {
57 | title: '@jonathanhaber',
58 | alerts: 0,
59 | status: 'away'
60 | },
61 | {
62 | title: '@lucksus',
63 | alerts: 1,
64 | status: 'offline'
65 | }
66 | ]}
67 | ]
68 | return getChannelList(channels)
69 | })
70 | function getChannelList (channels) {
71 | return (
72 |
73 | )
74 | }
75 |
--------------------------------------------------------------------------------
/ui-src/src/components/profile.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { withStyles } from 'material-ui/styles'
3 | import withRoot from '../withRoot'
4 | import PropTypes from 'prop-types'
5 | import TextField from 'material-ui/TextField'
6 | import Button from 'material-ui/Button'
7 |
8 | const styles = theme => ({
9 | container: {
10 | display: 'flex',
11 | flexWrap: 'wrap'
12 | },
13 | button: {
14 | margin: theme.spacing.unit
15 | },
16 | textField: {
17 | marginLeft: theme.spacing.unit,
18 | marginRight: theme.spacing.unit,
19 | width: '100%'
20 | }
21 | })
22 |
23 | class Profile extends Component {
24 | render () {
25 | const { classes } = this.props
26 | return (
27 |
64 | )
65 | }
66 | }
67 |
68 | Profile.propTypes = {
69 | classes: PropTypes.object.isRequired
70 | }
71 |
72 | export default withRoot(withStyles(styles)(Profile))
73 |
--------------------------------------------------------------------------------
/test/backnforth/person2.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests": [
3 | {
4 | "Time": 500,
5 | "Convey":"0. Register you user Chuck",
6 | "Zome":"profiles",
7 | "FnName":"register",
8 | "Input":{"username":"PinkHair",
9 | "firstName":"Sakura",
10 | "lastName":"Haruno",
11 | "email":"Sakura@Haruno.com",
12 | "avatar":""},
13 | "Output":"%h6%",
14 | "Err":""
15 | },
16 | {
17 | "Time": 900,
18 | "Convey":"1. newRoom should return the room's hash",
19 | "Zome":"rooms",
20 | "FnName":"newRoom",
21 | "Input":{"name":"Medical",
22 | "access":"public"},
23 | "Output":"%h5%",
24 | "Err":""
25 | },
26 | {
27 | "Time": 1500,
28 | "Convey":"2. Adding message to the room ",
29 | "Zome":"messages",
30 | "FnName":"newMessage",
31 | "Input":{"access":"public",
32 | "message":{
33 | "author":"%agent%",
34 | "content":{
35 | "text":"Hi I am Sakura"
36 | },
37 | "room_name":"Medical"}
38 | },
39 | "Output":"%h1%",
40 | "Err":""
41 | },
42 | {
43 | "Time": 1700,
44 | "Convey":"3. Adding message to the room created by the other person",
45 | "Zome":"messages",
46 | "FnName":"newMessage",
47 | "Input":{"access":"public",
48 | "message":{
49 | "author":"%agent%",
50 | "content":{
51 | "text":"Hi Kakashi, I am Sakura"
52 | },
53 | "room_name":"Hatake_clan"}
54 | },
55 | "Output":"%h1%",
56 | "Err":""
57 | },
58 | {
59 | "Time": 3000,
60 | "Convey":"3. Get all the messages of the room by using the hash of the room as ID ",
61 | "Zome":"messages",
62 | "FnName":"getMessages",
63 | "Input":{"room_name":"Medical",
64 | "access":"public"},
65 | "Regexp":"{\"Entry\":{\"author\":\"%agent%\",\"content\":{\"text\":\"Hi I am Sakura\"},\"room_name\":\"Medical\",\"timestamp\":\"[^\"]*\"},\"Hash\":\"[^\"]*\"}",
66 | "Err":""
67 | }
68 | ]
69 | }
70 |
--------------------------------------------------------------------------------
/test/backnforth/person1.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests": [
3 | {
4 | "Time": 500,
5 | "Convey":"0. Register you user Chuck",
6 | "Zome":"profiles",
7 | "FnName":"register",
8 | "Input":{"username":"WhiteFang",
9 | "firstName":"Kakashi",
10 | "lastName":"Hatake",
11 | "email":"Kakashi@Hatake.com",
12 | "avatar":""},
13 | "Output":"%h6%",
14 | "Err":""
15 | },
16 | {
17 | "Time": 1000,
18 | "Convey":"1. newRoom should return the room's hash",
19 | "Zome":"rooms",
20 | "FnName":"newRoom",
21 | "Input":{"name":"Hatake_clan",
22 | "access":"public"},
23 | "Output":"%h3%",
24 | "Err":""
25 | },
26 | {
27 | "Time": 1500,
28 | "Convey":"2. Adding message to the room",
29 | "Zome":"messages",
30 | "FnName":"newMessage",
31 | "Input":{"access":"public",
32 | "message":{
33 | "author":"%agent%",
34 | "content":{
35 | "text":"Hi I am Kakashi"
36 | },
37 | "room_name":"Hatake_clan"}
38 | },
39 | "Output":"%h1%",
40 | "Err":""
41 | },
42 | {
43 | "Time": 1700,
44 | "Convey":"3. Adding message to the room created by the other person",
45 | "Zome":"messages",
46 | "FnName":"newMessage",
47 | "Input":{"access":"public",
48 | "message":{
49 | "author":"%agent%",
50 | "content":{
51 | "text":"Hi,Sakura, I am Kakashi"
52 | },
53 | "room_name":"Medical"}
54 | },
55 | "Output":"%h1%",
56 | "Err":""
57 | },
58 | {
59 | "Time": 3000,
60 | "Convey":"3. Get all the messages of the room by using the hash of the room as ID ",
61 | "Zome":"messages",
62 | "FnName":"getMessages",
63 | "Input":{"room_name":"Hatake_clan",
64 | "access":"public"},
65 | "Regexp":"{\"Entry\":{\"author\":\"%agent%\",\"content\":{\"text\":\"Hi I am Kakashi\"},\"room_name\":\"Hatake_clan\",\"timestamp\":\"[^\"]*\"},\"Hash\":\"[^\"]*\"}",
66 | "Err":""
67 | }
68 | ]
69 | }
70 |
--------------------------------------------------------------------------------
/test/rooms_exceptions.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests":[
3 | {
4 | "Convey":"0. newRoom should fail when room schema not fulfilled",
5 | "Zome":"rooms",
6 | "FnName":"newRoom",
7 | "Input":{"name":"asdf"},
8 | "Regexp":"INVALID ACCESS:undefined",
9 | "Err":""
10 | },
11 | {
12 | "Convey":"1. getPublicRooms should return an empty list of rooms when there are none",
13 | "Zome":"rooms",
14 | "FnName":"getPublicRooms",
15 | "Input":"",
16 | "Output":[],
17 | "Err":""
18 | },
19 | {
20 | "Convey":"2. newRoom should fail when not created by a registered user",
21 | "Zome":"rooms",
22 | "FnName":"newRoom",
23 | "Input":{"name":"general", "access":"public"},
24 | "Regexp":"{\"errorMessage\":\"Validation Failed\",\"function\":\"commit\",\"name\":\"HolochainError\",\"source\":{\"column\":\"[^\"]*\",\"functionName\":\"newRoom\",\"line\":\"[^\"]*\"}}"
25 | },
26 | {
27 | "Convey":"3. Register User ",
28 | "Zome":"profiles",
29 | "FnName":"register",
30 | "Input":{"username":"cnorris", "firstName":"Chuck", "lastName":"Norris", "email":"chuck@norris.com"},
31 | "Output":"%h1%",
32 | "Err":""
33 | },{
34 | "Convey":"4. Check if hes registered",
35 | "Zome":"profiles",
36 | "FnName":"isRegistered",
37 | "Input":"",
38 | "Output":true,
39 | "Err":""
40 | },
41 | {
42 | "Convey":"5. newRoom should return the room's hash",
43 | "Zome":"rooms",
44 | "FnName":"newRoom",
45 | "Input":{"name":"general", "access":"public"},
46 | "Output":"%h3%",
47 | "Err":""
48 | },
49 | {
50 | "Convey":"6. getPublicRooms should return a list of rooms",
51 | "Zome":"rooms",
52 | "FnName":"getPublicRooms",
53 | "Input":"",
54 | "Output":[{"id":"%r1%","name":"general","access":"public"}],
55 | "Err":""
56 | }
57 | ]
58 | }
59 |
--------------------------------------------------------------------------------
/test/private_backnforth/person2.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests": [
3 | {
4 | "Time": 500,
5 | "Convey":"0. Register you user Chuck",
6 | "Zome":"profiles",
7 | "FnName":"register",
8 | "Input":{"username":"PinkHair",
9 | "firstName":"Sakura",
10 | "lastName":"Haruno",
11 | "email":"Sakura@Haruno.com",
12 | "avatar":""},
13 | "Output":"%h6%",
14 | "Err":""
15 | },
16 | {
17 | "Time": 900,
18 | "Convey":"1. newRoom should return the room's hash",
19 | "Zome":"rooms",
20 | "FnName":"newRoom",
21 | "Input":{"name":"Medical_private",
22 | "access":"private"},
23 | "Output":"%h13%",
24 | "Err":""
25 | },
26 | {
27 | "Time": 1500,
28 | "Convey":"2. Adding message to the room ",
29 | "Zome":"messages",
30 | "FnName":"newMessage",
31 | "Input":{"access":"private",
32 | "message":{
33 | "author":"%agent%",
34 | "content":{
35 | "text":"Hi I am Sakura"
36 | },
37 | "room_name":"Medical_private"}
38 | },
39 | "Output":"%h%",
40 | "Err":""
41 | },
42 | {
43 | "Time": 3900,
44 | "Convey":"3. Adding message to the room created by the other person",
45 | "Zome":"messages",
46 | "FnName":"newMessage",
47 | "Input":{"access":"private",
48 | "message":{
49 | "author":"%agent%",
50 | "content":{
51 | "text":"Hi Kakashi, I am Sakura"
52 | },
53 | "room_name":"Hatake_clan_private"}
54 | },
55 | "Output":"",
56 | "Err":{"errorMessage":"Validation Failed","function":"commit","name":"HolochainError","source":{"column":"16","functionName":"postPrivateMessage","line":"55"}}
57 | },
58 | {
59 | "Time": 4600,
60 | "Convey":"4. Get all the messages of the room by using the hash of the room as ID ",
61 | "Zome":"messages",
62 | "FnName":"getMessages",
63 | "Input":{"room_name":"Medical_private",
64 | "access":"private"},
65 | "Output":"",
66 | "Regexp":"{\"Entry\":{\"author\":\"%agent%\",\"content\":{\"text\":\"Hi I am Sakura\"},\"room_name\":\"Medical_private\",\"timestamp\":\"[^\"]*\"},\"Hash\":\"[^\"]*\"}",
67 | "Err":""
68 | }
69 | ]
70 | }
71 |
--------------------------------------------------------------------------------
/test/private_backnforth/person1.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests": [
3 | {
4 | "Time": 200,
5 | "Convey":"0. Register you user Chuck",
6 | "Zome":"profiles",
7 | "FnName":"register",
8 | "Input":{"username":"WhiteFang",
9 | "firstName":"Kakashi",
10 | "lastName":"Hatake",
11 | "email":"Kakashi@Hatake.com",
12 | "avatar":""},
13 | "Output":"%h6%",
14 | "Err":""
15 | },
16 | {
17 | "Time": 1000,
18 | "Convey":"1. newRoom should return the room's hash",
19 | "Zome":"rooms",
20 | "FnName":"newRoom",
21 | "Input":{"name":"Hatake_clan_private",
22 | "access":"private"},
23 | "Output":"%h7%",
24 | "Err":""
25 | },
26 | {
27 | "Time": 1200,
28 | "Convey":"2. Adding message to the room",
29 | "Zome":"messages",
30 | "FnName":"newMessage",
31 | "Input":{"access":"private",
32 | "message":{
33 | "author":"%agent%",
34 | "content":{
35 | "text":"Hi I am Kakashi"
36 | },
37 | "room_name":"Hatake_clan_private"}
38 | },
39 | "Output":"%h%",
40 | "Err":""
41 | },
42 | {
43 | "Time": 4000,
44 | "Convey":"3. Adding message to the room created by the other person",
45 | "Zome":"messages",
46 | "FnName":"newMessage",
47 | "Input":{"access":"private",
48 | "message":{
49 | "author":"%agent%",
50 | "content":{
51 | "text":"Hi,Sakura, I am Kakashi"
52 | },
53 | "room_name":"Medical_private"}
54 | },
55 | "Output":"",
56 | "Err":{"errorMessage":"Validation Failed","function":"commit","name":"HolochainError","source":{"column":"16","functionName":"postPrivateMessage","line":"55"}}
57 | },
58 | {
59 | "Time": 4500,
60 | "Convey":"4. Get all the messages of the room by using the hash of the room as ID ",
61 | "Zome":"messages",
62 | "FnName":"getMessages",
63 | "Input":{"room_name":"Hatake_clan_private",
64 | "access":"private"},
65 | "Output":"",
66 | "Regexp":"{\"Entry\":{\"author\":\"%agent%\",\"content\":{\"text\":\"Hi I am Kakashi\"},\"room_name\":\"Hatake_clan_private\",\"timestamp\":\"[^\"]*\"},\"Hash\":\"[^\"]*\"}",
67 | "Err":""
68 | }
69 | ]
70 | }
71 |
--------------------------------------------------------------------------------
/test/profiles.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests":[
3 | {
4 | "Convey":"0. Check if registered initially",
5 | "Zome":"profiles",
6 | "FnName":"isRegistered",
7 | "Input":"",
8 | "Output":false,
9 | "Err":""
10 | },
11 | {
12 | "Convey":"1. Not able to get Profile eather",
13 | "Zome":"profiles",
14 | "FnName":"getProfile",
15 | "Input":"%agent%",
16 | "Output":false,
17 | "Err":""
18 | },
19 | {
20 | "Convey":"2. Register you user Chuck",
21 | "Zome":"profiles",
22 | "FnName":"register",
23 | "Input":{"username":"cnorris", "firstName":"Chuck", "lastName":"Norris", "email":"chuck@norris.com","avatar":""},
24 | "Output":"%h1%",
25 | "Err":""
26 | },
27 | {
28 | "Convey":"3. Check if hes registered",
29 | "Zome":"profiles",
30 | "FnName":"isRegistered",
31 | "Input":"",
32 | "Output":true,
33 | "Err":""
34 | },
35 | {
36 | "Convey":"4. Get the profile info",
37 | "Zome":"profiles",
38 | "FnName":"getProfile",
39 | "Input":"%agent%",
40 | "Regexp":"^\\{\"agent_hash\":\"[^\"]*\",\"agent_id\":\"[^\"]*\",\"avatar\":\"\",\"email\":\"chuck@norris.com\",\"firstName\":\"Chuck\",\"lastName\":\"Norris\",\"username\":\"cnorris\"\\}$",
41 | "Err":""
42 | },
43 | {
44 | "Convey":"5. Updating the profile",
45 | "Zome":"profiles",
46 | "FnName":"updateProfile",
47 | "Input":{"username":"darK_V", "firstName":"dark", "lastName":"vader", "email":"dark@vader.com","avatar":""},
48 | "Output":"%h%",
49 | "Err":""
50 | },
51 | {
52 | "Convey":"6. Get my agent_id",
53 | "Zome":"profiles",
54 | "FnName":"getMyAgentHash",
55 | "Input":"",
56 | "Output":"%agent%",
57 | "Err":""
58 | },
59 | {
60 | "Convey":"7. Get the updated Profile",
61 | "Zome":"profiles",
62 | "FnName":"getProfile",
63 | "Input":"%r1%",
64 | "Regexp":"^\\{\"agent_hash\":\"[^\"]*\",\"agent_id\":\"[^\"]*\",\"avatar\":\"\",\"email\":\"dark@vader.com\",\"firstName\":\"dark\",\"lastName\":\"vader\",\"username\":\"darK_V\"\\}$",
65 | "Err":""
66 | }
67 | ]
68 | }
69 |
--------------------------------------------------------------------------------
/test/messages_exceptions.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests":[
3 | {
4 | "Convey":"0. Adding New messages without any room",
5 | "Zome":"messages",
6 | "FnName":"newMessage",
7 | "Input":{"access":"public","message":{"author":"%agent%","content":{"text":"Cheers!!"}}},
8 | "Output":"ERROR: Room undefined doesn't exist",
9 | "Err":""
10 | },
11 | {
12 | "Convey":"1. Adding message without creating room",
13 | "Zome":"messages",
14 | "FnName":"newMessage",
15 | "Input":{"access":"public","message":{"author":"%agent%","content":{"text":"Cheers!!"}, "room_name":"Asdf"}},
16 | "Output":"ERROR: Room Asdf doesn't exist"
17 | },
18 | {
19 | "Convey":"2. Register User **Needs more testing**",
20 | "Zome":"profiles",
21 | "FnName":"register",
22 | "Input":{"username":"cnorris", "firstName":"Chuck", "lastName":"Norris", "email":"chuck@norris.com"},
23 | "Output":"%h6%",
24 | "Err":""
25 | },
26 | {
27 | "Convey":"3. Get Profile of the user. ",
28 | "Zome":"profiles",
29 | "FnName":"getProfile",
30 | "Input":"%agent%",
31 | "Output":{"agent_hash":"%agent%","agent_id":"%key%","email":"chuck@norris.com","firstName":"Chuck","lastName":"Norris","username":"cnorris"},
32 | "Err":""
33 | },
34 | {
35 | "Convey":"4. Creting new room **Needs More testing**",
36 | "Zome":"rooms",
37 | "FnName":"newRoom",
38 | "Input":{"name":"general", "access":"public"},
39 | "Output":"%h5%",
40 | "Err":""
41 | },
42 | {
43 | "Convey":"5. Adding message to the room using the hash of the of the room ",
44 | "Zome":"messages",
45 | "FnName":"newMessage",
46 | "Input":{"access":"public","message":{"author":"%agent%","content":{"text":"Cheers!!"}, "room_name":"general"}},
47 | "Output":"%h1%",
48 | "Err":""
49 | },
50 | {
51 | "Convey":"6. Get all the messages of the room by using the hash of the room as ID ",
52 | "Zome":"messages",
53 | "FnName":"getMessages",
54 | "Input":{"room_name":"general","access":"public"},
55 | "Regexp":"{\"Entry\":{\"author\":\"QmNU6Gynfi33qknXvKn19NqLzRHEvb3Wea14rpJc7En1xK\",\"content\":{\"text\":\"Cheers!!\"},\"room_name\":\"general\",\"timestamp\":\"[^\"]*\"},\"Hash\":\"[^\"]*\"}",
56 | "Err":""
57 | }
58 | ]
59 | }
60 |
--------------------------------------------------------------------------------
/test/coustom_room.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests": [{
3 | "Convey": "0. Create new Room",
4 | "Zome": "coustom_room",
5 | "FnName": "createCoustomRoom",
6 | "Input": [],
7 | "RegExp": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
8 | "Err": ""
9 | },
10 | {
11 | "Convey": "1. Get the rooms|chats you are part of (UUID)",
12 | "Zome": "coustom_room",
13 | "FnName": "getMyRooms",
14 | "Input": "",
15 | "Output": "%r1%"
16 | },
17 | {
18 | "Convey": "2. Get member for the room (UUID)",
19 | "Zome": "coustom_room",
20 | "FnName": "getMembers",
21 | "Input": "%r2%",
22 | "RegExp": "(?s).*"
23 | },
24 | {
25 | "Convey": "3. Get the room details by UUID",
26 | "Zome": "coustom_room",
27 | "FnName": "getRoomDetails",
28 | "Input": "%r3%",
29 | "RegExp": "(?s).*"
30 | },
31 | {
32 | "Convey": "4. post message to the room",
33 | "Zome": "coustom_room",
34 | "FnName": "postMessage",
35 | "Input": {"uuid":"%r3%","message":{"content":{"text":"Testing out the First message!!"}}},
36 | "Output": "%h1%"
37 | },
38 | {
39 | "Convey": "5. 'REDUNDANTE' Again Get the rooms|chats you are part of (UUID)",
40 | "Zome": "coustom_room",
41 | "FnName": "getMyRooms",
42 | "Input": "",
43 | "RegExp": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
44 |
45 | },
46 | {
47 | "Convey": "6. get message of the room",
48 | "Zome": "coustom_room",
49 | "FnName": "getMessages",
50 | "Input": "%r1%",
51 | "RegExp": "[{\"Entry\":{\"author\":\"QmUAfnSCvwhgHhrJ71YswaXgfPcheNicft4BHXPnp1UzGb\",\"content\":{\"text\":\"Testing out the First message!!\"},\"timestamp\":\"[^\"]*\"},\"EntryType\":\"cr_message\",\"Hash\":\"[^\"]*\",\"Source\":\"QmUAfnSCvwhgHhrJ71YswaXgfPcheNicft4BHXPnp1UzGb\"}]"
52 | },
53 | {
54 | "Convey": "7. update message of the room",
55 | "Zome": "coustom_room",
56 | "FnName": "updateMessage",
57 | "Input": {"old_hash":"%r3%","new_message":{"content":{"text":"Testing out the First message Update !!"}}},
58 | "RegExp": "%h%"
59 | },
60 | {
61 | "Convey": "8. 'REDUNDANTE' Again Get the rooms|chats you are part of (UUID)",
62 | "Zome": "coustom_room",
63 | "FnName": "getMyRooms",
64 | "Input": "",
65 | "RegExp": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
66 |
67 | },
68 | {
69 | "Convey": "9. get message of the room",
70 | "Zome": "coustom_room",
71 | "FnName": "getMessages",
72 | "Input": "%r1%",
73 | "RegExp": "[{\"Entry\":{\"author\":\"QmUAfnSCvwhgHhrJ71YswaXgfPcheNicft4BHXPnp1UzGb\",\"content\":{\"text\":\"Testing out the First message Update !!\"},\"timestamp\":\"[^\"]*\"},\"EntryType\":\"cr_message\",\"Hash\":\"[^\"]*\",\"Source\":\"QmUAfnSCvwhgHhrJ71YswaXgfPcheNicft4BHXPnp1UzGb\"}]"
74 | }
75 | ]
76 | }
77 |
--------------------------------------------------------------------------------
/test/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests":[
3 | {
4 | "Convey":"0. Register User **Needs more testing**",
5 | "Zome":"profiles",
6 | "FnName":"register",
7 | "Input":{"username":"cnorris", "firstName":"Chuck", "lastName":"Norris", "email":"chuck@norris.com"},
8 | "Output":"%h6%",
9 | "Err":""
10 | },
11 | {
12 | "Convey":"1. Get Profile of the user. ",
13 | "Zome":"profiles",
14 | "FnName":"getProfile",
15 | "Input":"%agent%",
16 | "Output":{"agent_hash":"%agent%","agent_id":"%key%","email":"chuck@norris.com","firstName":"Chuck","lastName":"Norris","username":"cnorris"},
17 | "Err":""
18 | },
19 | {
20 | "Convey":"2. Creting new room **Needs More testing** ",
21 | "Zome":"rooms",
22 | "FnName":"newRoom",
23 | "Input":{"name":"general", "access":"public"},
24 | "Output":"%h5%",
25 | "Err":""
26 | },
27 | {
28 | "Convey":"3. Creting new room ",
29 | "Zome":"rooms",
30 | "FnName":"newRoom",
31 | "Input":{"name":"SecondRoom", "access":"public"},
32 | "Output":"%h3%",
33 | "Err":""
34 | },
35 | {
36 | "Convey":"4. Adding message to the room using the hash of the of the room ",
37 | "Zome":"messages",
38 | "FnName":"newMessage",
39 | "Input":{"access":"public","message":{"author":"%agent%","content":{"text":"Cheers!!"}, "room_name":"general"}},
40 | "Output":"%h1%",
41 | "Err":""
42 | },
43 | {
44 | "Convey":"5. Get all the messages of the room by using the hash of the room as name ",
45 | "Zome":"messages",
46 | "FnName":"getMessages",
47 | "Input":{"room_name":"general","access":"public"},
48 | "Output":"",
49 | "Regexp":"{\"Entry\":{\"author\":\"QmNU6Gynfi33qknXvKn19NqLzRHEvb3Wea14rpJc7En1xK\",\"content\":{\"text\":\"Cheers!!\"},\"room_name\":\"general\",\"timestamp\":\"[^\"]*\"},\"Hash\":\"[^\"]*\"}",
50 | "Err":""
51 | },
52 | {
53 | "Convey":"6. Update the messages of the room",
54 | "Zome":"messages",
55 | "FnName":"updateMessage",
56 | "Input":{"new_message":{"author":"%agent%","content":{"text":"Updated Cheers!!"}, "room_name":"general"},"old_Hash":"%r2%"},
57 | "Output":"%h%",
58 | "Err":""
59 | },
60 | {
61 | "Convey":"7. Get all the messages of the room by using the hash of the room as name ",
62 | "Zome":"messages",
63 | "FnName":"getMessages",
64 | "Input":{"room_name":"general","access":"public"},
65 | "Output":"",
66 | "Regexp":"{\"Entry\":{\"author\":\"QmNU6Gynfi33qknXvKn19NqLzRHEvb3Wea14rpJc7En1xK\",\"content\":{\"text\":\"Updated Cheers!!\"},\"room_name\":\"general\",\"timestamp\":\"[^\"]*\"},\"Hash\":\"[^\"]*\"}",
67 | "Err":""
68 | }
69 | ]
70 | }
71 |
--------------------------------------------------------------------------------
/ui-src/src/components/lists/channel-list.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classNames from 'classnames'
3 | import PropTypes from 'prop-types'
4 | import withRoot from '../../withRoot'
5 | import { withStyles } from 'material-ui/styles'
6 | import List, { ListItem, ListItemText } from 'material-ui/List'
7 | import { Link } from 'react-router-dom'
8 | import Typography from 'material-ui/Typography'
9 | import Badge from 'material-ui/Badge'
10 |
11 | const styles = theme => ({
12 | listItemMessage: {
13 | position: 'relative'
14 | },
15 | group: {
16 |
17 | },
18 | badge: {
19 |
20 | }
21 | })
22 |
23 | function BadgedLink (props) {
24 | if (props.channel.alerts > 0) {
25 | return (
26 |
27 | {props.channel.title}
28 |
29 | )
30 | } else {
31 | return (
32 | {props.channel.title}
33 | )
34 | }
35 | }
36 |
37 | class ChannelList extends React.Component {
38 | render () {
39 | const { classes, channels } = this.props
40 | return (
41 |
42 |
43 |
44 | {channels[0].group}
45 |
46 |
47 |
48 | {channels[0].channels.map((channel, index) => (
49 |
50 |
51 |
52 | ))}
53 |
54 |
55 |
56 |
57 |
58 | {channels[1].group}
59 |
60 |
61 |
62 | {channels[1].channels.map((channel, index) => (
63 |
64 |
65 |
66 | ))}
67 |
68 |
69 |
70 |
71 |
72 | {channels[2].group}
73 |
74 |
75 |
76 | {channels[2].channels.map((channel, index) => (
77 |
78 |
79 |
80 | ))}
81 |
82 |
83 |
84 |
85 | )
86 | }
87 | }
88 |
89 | ChannelList.propTypes = {
90 | classes: PropTypes.object.isRequired,
91 | channels: PropTypes.object.isRequired
92 |
93 | }
94 |
95 | export default withRoot(withStyles(styles)(ChannelList))
96 |
--------------------------------------------------------------------------------
/ui-src/src/components/lists/message-list.story.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | // import { action } from '@storybook/addon-actions'
4 | import { specs, describe, it } from 'storybook-addon-specifications'
5 | import { configure, mount } from 'enzyme'
6 | import Adapter from 'enzyme-adapter-react-16'
7 | import MessageList from './message-list'
8 | import expect from 'expect'
9 |
10 | configure({ adapter: new Adapter() })
11 |
12 | storiesOf('Message List', module)
13 | .add('Display a list of different types of messages', () => {
14 | const messages = [
15 | {date: 'January 25th 2018',
16 | messages: [
17 | {
18 | type: 'Message',
19 | author: 'Art Brock',
20 | avatar: 'art-brock-avatar.png',
21 | time: '5.04pm',
22 | content: {
23 | text: 'Text message with an imageText message with an imageText message with an imageText message with an image',
24 | image: 'art-brock-avatar.png'},
25 | replies: [],
26 | idea: false,
27 | up: 7,
28 | down: 0
29 | },
30 | {
31 | type: 'Message',
32 | author: 'Art Brock',
33 | avatar: 'art-brock-avatar.png',
34 | time: '5.04pm',
35 | content: {
36 | text: 'Text message with no image',
37 | image: ''},
38 | replies: [],
39 | idea: false,
40 | up: 7,
41 | down: 0
42 | },
43 | {
44 | type: 'IdeaCard',
45 | author: 'Philip Beadle',
46 | avatar: 'philip-beadle-avatar.png',
47 | time: '7.04pm',
48 | content: {idea: {
49 | title: 'Display both FOLLOWERS and FOLLOWING',
50 | productOwner: 'Art Brock',
51 | avatar: 'art-brock-avatar.png',
52 | date: 'January 30, 2018 - Lead Time 3 weeks',
53 | description: 'When clicking on Follow Someone, let\'s include a list of who is following you, not just who you are following. Either that or we add number/summary displays: Mews, Following, Followers under profile pic.',
54 | up: 37,
55 | down: 1
56 | }
57 | },
58 | replies: [],
59 | idea: false,
60 | up: 9,
61 | down: 0
62 | }
63 | ]},
64 | {date: 'January 26th 2018',
65 | messages: [
66 | {
67 | type: 'Message',
68 | author: 'Art Brock',
69 | avatar: 'art-brock-avatar.png',
70 | time: '5.04pm',
71 | content: {
72 | text: 'Text message with an imageText message with an imageText message with an imageText message with an image',
73 | image: 'art-brock-avatar.png'},
74 | replies: [],
75 | idea: false,
76 | up: 7,
77 | down: 0
78 | },
79 | {
80 | type: 'Message',
81 | author: 'Art Brock',
82 | avatar: 'art-brock-avatar.png',
83 | time: '5.04pm',
84 | content: {
85 | text: 'Text message with no image',
86 | image: ''},
87 | replies: [],
88 | idea: false,
89 | up: 7,
90 | down: 0
91 | }
92 | ]}
93 | ]
94 | return getMessageList(messages)
95 | })
96 | function getMessageList (messages) {
97 | return (
98 |
99 | )
100 | }
101 |
--------------------------------------------------------------------------------
/ui-src/src/components/message.story.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | import { action } from '@storybook/addon-actions'
4 | import { specs, describe, it } from 'storybook-addon-specifications'
5 | import { configure, mount } from 'enzyme'
6 | import Adapter from 'enzyme-adapter-react-16'
7 | import Message from './message'
8 | import expect from 'expect'
9 |
10 | configure({ adapter: new Adapter() })
11 |
12 | storiesOf('Message', module)
13 | .add('Display a message with no replies', () => {
14 | const message = {
15 | type: 'Message',
16 | author: 'Philip Beadle',
17 | avatar: 'philip-beadle-avatar.png',
18 | time: '7.04pm',
19 | content: {text: 'New release of Clutter using React as the UI - https://github.com/Holochain/clutter/releases'},
20 | replies: [],
21 | up: 9,
22 | down: 0
23 | }
24 |
25 | return getMessage(message)
26 | })
27 | .add('Display a message with 2 replies', () => {
28 | const message = {
29 | type: 'Message',
30 | author: 'Art Brock',
31 | avatar: 'art-brock-avatar.png',
32 | time: '5.04pm',
33 | content: {text: 'So, we\'re establishing two-way DHT links for following/followers... I think we should make them more visible. How about we put some counts below the profile pic for Mews / Following / Following ?'},
34 | replies: [
35 | {
36 | type: 'Message',
37 | author: 'Philip Beadle',
38 | avatar: 'philip-beadle-avatar.png',
39 | time: '7.04pm',
40 | content: {text: 'I was thinking the same thing. Since I saw @connorturland\'s new way of selecting someone to follow I thought we should show Followers too.'},
41 | up: 9,
42 | down: 0
43 | },
44 | {
45 | type: 'Message',
46 | author: 'Philip Beadle',
47 | avatar: 'philip-beadle-avatar.png',
48 | time: '7.04pm',
49 | content: {text: 'And now that I\'ve drawn a simple update to the page we should probably add in the ability to Block people as well'},
50 | up: 9,
51 | down: 0
52 | }
53 | ],
54 | up: 7,
55 | down: 0
56 | }
57 | return getMessage(message)
58 | })
59 | .add('Display a message with 2 replies and has enough interest to be an idea', () => {
60 | const message = {
61 | type: 'Message',
62 | author: 'Art Brock',
63 | avatar: 'art-brock-avatar.png',
64 | time: '5.04pm',
65 | content: {text: 'So, we\'re establishing two-way DHT links for following/followers... I think we should make them more visible. How about we put some counts below the profile pic for Mews / Following / Following ?'},
66 | replies: [
67 | {
68 | type: 'Message',
69 | author: 'Philip Beadle',
70 | avatar: 'philip-beadle-avatar.png',
71 | time: '7.04pm',
72 | content: {text: 'I was thinking the same thing. Since I saw @connorturland\'s new way of selecting someone to follow I thought we should show Followers too.'},
73 | up: 9,
74 | down: 0
75 | },
76 | {
77 | type: 'Message',
78 | author: 'Philip Beadle',
79 | avatar: 'philip-beadle-avatar.png',
80 | time: '7.04pm',
81 | content: {text: 'And now that I\'ve drawn a simple update to the page we should probably add in the ability to Block people as well'},
82 | up: 9,
83 | down: 0
84 | }
85 | ],
86 | idea: true,
87 | up: 7,
88 | down: 0
89 | }
90 | return getMessage(message)
91 | })
92 | function getMessage (message) {
93 | return (
94 |
95 | )
96 | }
97 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # holochat - [ in favor of holochain-basic-chat](https://github.com/holochain/holochain-basic-chat)
2 |
3 | This chat app was developed for the proto version of holochain and is kept for archival purposes only
4 |
5 | [](https://travis-ci.org/Holochain/holochat)
6 | [](https://github.com/Holochain/holochat#feature-roadmap-and-current-progress)
7 | [](http://waffle.io/Holochain/holochat)
8 | [](https://gitter.im/metacurrency/holochain?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge)
9 | [](http://www.gnu.org/licenses/gpl-3.0)
10 |
11 | ***Multi-room P2P chat on holochain**
12 |
13 | **[Code Status:](https://github.com/metacurrency/holochain/milestones?direction=asc&sort=completeness&state=all)** Pre-alpha. Not for production use. This application has not been audited for any security validation.
14 |
15 | ## Docker
16 |
17 | ```
18 | TARGETDIR=$(pwd) docker-compose up
19 |
20 | ```
21 | Now you can open browsers to
22 | ```
23 | http://localhost:3142 - Bootstrap
24 | http://localhost:3141 - Holochat
25 | http://localhost:4141 - Holochat
26 | http://localhost:5141 - Holochat
27 | ```
28 |
29 | ## Installation native
30 |
31 | Prerequiste: [Install holochain](https://github.com/metacurrency/holochain/#installation) on your machine.
32 | You can install holochat very simply with this:
33 |
34 | ``` shell
35 | hcdev init -cloneExample=holochat
36 |
37 | ```
38 |
39 | ## Usage
40 |
41 | To do a test run of holochat simply type
42 |
43 | ``` shell
44 | cd holochat
45 | hcdev web
46 | ```
47 | you should see something like:
48 |
49 | ``` shell
50 | Copying chain to: /home/bootstrap/.holochaindev
51 | ...
52 | Serving holochain with DNA hash:QmdFv5XcG6YZgMYQ9hPJfn6xkhMhDK99rjiHJHH9zorUad on port:4141
53 | ```
54 | Then simply point your browser to http://localhost:4141 access the holochat UI.
55 |
56 | ### Tests
57 | To run all the stand alone tests:
58 |
59 | ``` shell
60 | hcdev test
61 | ```
62 |
63 | Currently there is one scenario test:
64 |
65 | #### backnforth
66 | ``` shell
67 | hcdev -mdns=true scenario backnforth
68 | ```
69 | This test spins up two nodes `person1` and `person` and tests that they can send messages back and forth
70 |
71 | ``` shell
72 | hcdev -mdns=true -debug scenario backnforth
73 | ```
74 |
75 | ### Run e2e tests
76 | ```
77 | cd ui-automation
78 | yarn test
79 | ```
80 |
81 | ## Feature Roadmap and Current Progress
82 |
83 |
84 | ## Contribute
85 | We welcome pull requests and issue tickets. Find us on [gitter](https://gitter.im/metacurrency/holochain) to chat.
86 |
87 | Contributors to this project are expected to follow our [development protocols & practices](https://github.com/metacurrency/holochain/wiki/Development-Protocols).
88 |
89 | ## License
90 | [](http://www.gnu.org/licenses/gpl-3.0)
91 |
92 | Copyright (C) 2017, The MetaCurrency Project (Eric Harris-Braun, Arthur Brock, et. al.)
93 |
94 | This program is free software: you can redistribute it and/or modify it under the terms of the license provided in the LICENSE file (GPLv3). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
95 |
96 | **Note:** We are considering other 'looser' licensing options (like MIT license) but at this stage are using GPL while we're getting the matter sorted out.
97 |
--------------------------------------------------------------------------------
/test/rooms_private_messaging.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests":[
3 | {
4 | "Convey":"0. Register User ",
5 | "Zome":"profiles",
6 | "FnName":"register",
7 | "Input":{"username":"cnorris", "firstName":"Chuck", "lastName":"Norris", "email":"chuck@norris.com"},
8 | "Output":"%h6%",
9 | "Err":""
10 | },
11 | {
12 | "Convey":"1. PRIVATE newRoom should return the room's hash",
13 | "Zome":"rooms",
14 | "FnName":"newRoom",
15 | "Input":{"name":"general", "access":"private"},
16 | "Output":"%h13%",
17 | "Err":""
18 | },
19 | {
20 | "Convey":"2. Get the added members to the private room ",
21 | "Zome":"membership",
22 | "FnName":"getMembers",
23 | "Input":{"room_name":"general"},
24 | "Output":"%agent%",
25 | "Err":""
26 | },
27 | {
28 | "Convey":"3. Get my Private Rooms",
29 | "Zome":"rooms",
30 | "FnName":"getMyPrivateRooms",
31 | "Input":"",
32 | "Output":"general",
33 | "Err":""
34 | },
35 | {
36 | "Convey":"4. Adding message to the room thats not created ",
37 | "Zome":"messages",
38 | "FnName":"newMessage",
39 | "Input":{"access":"public","message":{"author":"%agent%","content":{"text":"Cheers!!"}, "room_name":"general"}},
40 | "Output":"ERROR: Room general doesn't exist",
41 | "Err":""
42 | },
43 | {
44 | "Convey":"5. Adding message to the room with wrong access ",
45 | "Zome":"messages",
46 | "FnName":"newMessage",
47 | "Input":{"access":"WrongAccess","message":{"author":"%agent%","content":{"text":"Cheers!!"}, "room_name":"general"}},
48 | "Output":"ERROR Invalid Access: WrongAccess",
49 | "Err":""
50 | },
51 | {
52 | "Convey":"6. Adding message to the room thats not created ",
53 | "Zome":"messages",
54 | "FnName":"newMessage",
55 | "Input":{"access":"private","message":{"author":"%agent%","content":{"text":"Cheers!!"}, "room_name":"general"}},
56 | "Output":"%h1%",
57 | "Err":""
58 | },
59 | {
60 | "Convey":"7. if private room uses access : public returns nothing",
61 | "Zome":"messages",
62 | "FnName":"getMessages",
63 | "Input":{"room_name":"general","access":"public"},
64 | "Output":[],
65 | "Err":""
66 | },
67 | {
68 | "Convey":"8. get Private room messages",
69 | "Zome":"messages",
70 | "FnName":"getMessages",
71 | "Input":{"room_name":"general","access":"private"},
72 | "Regexp":"{\"Entry\":{\"author\":\"%agent%\",\"content\":{\"text\":\"Cheers!!\"},\"room_name\":\"general\",\"timestamp\":\"[^\"]*\"},\"Hash\":\"[^\"]*\"}",
73 | "Err":""
74 | },
75 | {
76 | "Convey":"9. Update the messages of the room",
77 | "Zome":"messages",
78 | "FnName":"updateMessage",
79 | "Input":{"new_message":{"author":"%agent%","content":{"text":"Updated Cheers!!"}, "room_name":"general"},"old_Hash":"%r3%"},
80 | "Output":"%h%",
81 | "Err":""
82 | },
83 | {
84 | "Convey":"10. get updated Private room messages",
85 | "Zome":"messages",
86 | "FnName":"getMessages",
87 | "Input":{"room_name":"general","access":"private"},
88 | "Regexp":"{\"Entry\":{\"author\":\"%agent%\",\"content\":{\"text\":\"Updated Cheers!!\"},\"room_name\":\"general\",\"timestamp\":\"[^\"]*\"},\"Hash\":\"[^\"]*\"}",
89 | "Err":""
90 | }
91 | ]
92 | }
93 |
--------------------------------------------------------------------------------
/dna/profiles/profiles.js:
--------------------------------------------------------------------------------
1 | //Register users
2 | //@param x={}
3 | function register(x) {
4 | x.agent_id = App.Key.Hash
5 | x.agent_hash=App.Agent.Hash
6 | var key = commit("profile", x);
7 | var reg=commit("registration_link", {Links:[{Base:anchor("Profiles",""),Link:key,Tag:"registered_users"}]});
8 | return key;
9 | }
10 |
11 | // Find out if users is registered
12 | function isRegistered() {
13 | var registered_users = getLinks(anchor("Profiles",""), 'registered_users',{Load:true})
14 | debug("Registered users are: "+JSON.stringify(registered_users));
15 | if( registered_users instanceof Error) return false;
16 | for(var i=0; i < registered_users.length; i++) {
17 | var profile = registered_users[i].Entry
18 | debug("Registered user "+i+" is " + profile.username)
19 | if( profile.agent_id == App.Key.Hash) return true;
20 | }
21 | return false;
22 | }
23 |
24 | //Returns your agent Hash
25 | function getMyAgentHash(){
26 | debug("App.Agent.Hash : "+App.Agent.Hash)
27 | return App.Agent.Hash;
28 | }
29 |
30 | // Get profile information for a user
31 | function getProfile(agent_hash) {
32 | var registered_users = getLinks(anchor("Profiles",""), "registered_users",{Load:true});
33 | debug("registration entry:"+JSON.stringify(registered_users));
34 | if( registered_users instanceof Error ) return false
35 | for(var i=0; i < registered_users.length; i++) {
36 | var profile = registered_users[i].Entry
37 | debug("Registered user "+i+" is " + profile.username)
38 | if( profile.agent_hash == agent_hash) return profile;
39 | }
40 | return false;
41 | }
42 |
43 | // Update profile information for an agent_id
44 | function updateProfile(x) {
45 | x.agent_id = App.Key.Hash
46 | x.agent_hash=App.Agent.Hash
47 | var oldHash = makeHash("profile",getProfile(x.agent_hash));
48 | if(oldHash==false){
49 | return "NotRegistered";
50 | }
51 | var key = update("profile", x, oldHash);
52 | return key;
53 | }
54 |
55 | /*---------- Anchor API ----------*/
56 |
57 | function anchor(anchorType, anchorText) {
58 | return call('anchors', 'anchor', {
59 | anchorType: anchorType,
60 | anchorText: anchorText
61 | }).replace(/"/g, '');
62 | }
63 |
64 | function anchorExists(anchorType, anchorText) {
65 | return call('anchors', 'exists', {
66 | anchorType: anchorType,
67 | anchorText: anchorText
68 | });
69 | }
70 |
71 |
72 | /*----------- Validation Functions---------------*/
73 |
74 | function isSourcesOwnProfile(entry, sources) {
75 | return sources[0] == entry.agent_id;
76 | }
77 |
78 | function isRegistrationOnDNA(registration_entry) {
79 | debug("registration entry:"+JSON.stringify(registration_entry));
80 | var links = registration_entry.Links;
81 | for(var i=0; i < links.length; i++) {
82 | var l = links[i]
83 | debug("link: "+JSON.stringify(l))
84 | var ActualBase=anchor("Profiles","");
85 | if (l.Base != ActualBase) {
86 | debug("validation failed, expected reg base to be: "+ActualBase+" but was: "+l.Base)
87 | return false;
88 | }
89 | }
90 | return true;
91 | }
92 |
93 | function genesis() {
94 | return true;
95 | }
96 |
97 | function validatePut(entry_type,entry,header,pkg,sources) {
98 | return validateCommit(entry_type,entry,header,pkg,sources)
99 | }
100 | function validateCommit(entry_type,entry,header,pkg,sources) {
101 | // registration_link all must happen on the DNA
102 | if (entry_type == "registration_link") {
103 | return isRegistrationOnDNA(entry)
104 | }
105 |
106 | // nobody can add somebody elses profile
107 | return isSourcesOwnProfile(entry, sources);
108 | }
109 |
110 | function validateLink(linkingEntryType,baseHash,linkHash,pkg,sources){
111 | // registration_link all must happen on the DNA
112 | if (linkingEntryType == "registration_link") {
113 | return baseHash == anchor("Profiles","")
114 | }
115 |
116 | return true
117 | }
118 | function validateMod(entry_type,hash,newHash,pkg,sources) {return true;}
119 | function validateDel(entry_type,hash,pkg,sources) {return true;}
120 | function validatePutPkg(entry_type) {return null}
121 | function validateModPkg(entry_type) { return null}
122 | function validateDelPkg(entry_type) { return null}
123 | function validateLinkPkg(entry_type) { return null}
124 |
--------------------------------------------------------------------------------
/docs/post_functions.md:
--------------------------------------------------------------------------------
1 | # Post Function for UI of the HoloChat
2 |
3 | ## ZomeName: profiles
4 |
5 | ### register(User_details)
6 | **Details: ** Call to register a user
7 | **Input:**
8 | User_details:
9 | > {{
10 | "agent_id": {"type": "string"},
11 | "agent_hash": {"type": "string"},
12 | "username": {"type": "string"},
13 | "firstName": {"type": "string"},
14 | "lastName": {"type": "string"},
15 | "email": {"type": "string"},
16 | "avatar": {"type": "string"}
17 | },
18 | "required": ["agent_id", "username", "firstName", "lastName", "email"]
19 | }
20 |
21 | **Returns:** Hash of the profile
22 |
23 |
24 | ### isRegistered()
25 | **Detail**: Check if the user is registered
26 | **Input :** None
27 | **Return**: true - > if User is register | false - > if User is not-register
28 |
29 | ### getMyAgentHash()
30 | **Details**: Get App.Agent.Hash of the User
31 | **Input :** None
32 | **Return**: Agent_Hash
33 |
34 |
35 | ### getProfile(agent_hash)
36 | **Detail**: Get the users profile details
37 | **Input :** App.Agent.Hash
38 | **Return**:
39 | > {{
40 | "agent_id": {"type": "string"},
41 | "agent_hash": {"type": "string"},
42 | "username": {"type": "string"},
43 | "firstName": {"type": "string"},
44 | "lastName": {"type": "string"},
45 | "email": {"type": "string"},
46 | "avatar": {"type": "string"}
47 | },
48 | "required": ["agent_id", "username", "firstName", "lastName", "email"]
49 | }
50 |
51 |
52 | ### updateProfile(user_details)
53 | **Detail**: If the user needs to update the profile details
54 | **Input:**
55 | User_details:
56 | > {{
57 | "agent_id": {"type": "string"},
58 | "agent_hash": {"type": "string"},
59 | "username": {"type": "string"},
60 | "firstName": {"type": "string"},
61 | "lastName": {"type": "string"},
62 | "email": {"type": "string"},
63 | "avatar": {"type": "string"}
64 | },
65 | "required": ["agent_id", "username", "firstName", "lastName", "email"]
66 | }
67 |
68 | **Return**: hash -> if succesfully updated
69 | "NotRegistered" -> if the user is not registered
70 |
71 |
72 | ## ZomeName: rooms
73 |
74 | ### getPublicRooms()
75 | **Details**: Returns all the rooms on the App
76 | **Input :** None
77 | **Returns**:
78 | > {"id":"Hash of the Room",
79 | "name":"Name of the Room",
80 | "purpose":"The Purpose of the Room"}
81 |
82 | ### newRoom(room)
83 | **Details**: Call to create new Rooms (public|private)
84 | **Input :**
85 | > {"name":"Name of the Room",
86 | "access":"public|private"}
87 |
88 | **Returns**: Hash of the room that can be used as an ID
89 |
90 | ### getRoomAdmin()
91 | **Details:** Gets you the admin of the room
92 | **Input:**
93 | >{room_name:""}
94 |
95 | **Returns:** Hash of the Admin Agent
96 |
97 |
98 | ### getMyPrivateRooms()
99 | **Details:** Gets the private rooms you a member of, that is stored locally.
100 | **Input:** None
101 |
102 | **Returns:** names of the private rooms that the user is a member of
103 |
104 |
105 |
106 | ## ZomeName: messages
107 |
108 | ### newMessage()
109 | **Details:** used to post messages (Note: timestamp is applied from the back end)
110 | **Input:**
111 | message.json: {"access":"public | private",
112 | "message":{{"author":{"type": "string"},
113 | "content": {
114 | "text":{"type": "string"},
115 | "mediaLink":{"type": "string"}
116 | },
117 | "timestamp": {"type": "string"},
118 | "room_name": {"type": "string"}
119 | },
120 | "required": ["author","room_name","content"]
121 | }}
122 | >
123 |
124 | **Returns:** Hash of the entry --> us as ID of the message
125 |
126 | ### getMessage()
127 | **Details:** get messages for a specific Room
128 | **Input:**
129 | > {room_name:"","access":"public|privated"}
130 |
131 | **Returns:** Array of messages in this format [{Entry:{},Hash:""},{Entry:{},Hash:""},...]
132 |
133 |
134 | ### updateMessage()
135 | **Details:** update messages for a specific Room
136 | **Input:**
137 | >{new_message:"",old_Hash:""}
138 |
139 | (Note: the old_Hash is the ID that the messaged used & new Message has the same message.json format as above)
140 |
141 | **Returns:** Hash of the entry --> us as ID of the message
142 |
143 |
144 | ## ZomeName: membership
145 |
146 | ### addMember()
147 | **Details:** add members to a private room
148 | **Input:**
149 | > {room_name:"","agent_key":"%key%","agent_hash":"%agent%"}
150 |
151 | **Returns:** Hash
152 |
153 | ### getMembers()
154 | **Details:** get members of the private room
155 | **Input:**
156 | > {room_name:""}
157 |
158 | **Returns:** List Of members
159 |
--------------------------------------------------------------------------------
/dna/membership/membership.js:
--------------------------------------------------------------------------------
1 | // Authorize a new agent_id to participate in this holochain
2 | // agent_id must match the string they use to "hc init" their holochain, and is currently their email by convention
3 | //@param : {room_name:"",agent_hash:"",agent_key:""}
4 | function addMember(x) {
5 | key = commit("membership_link",{Links:[{Base:anchor("Private_Room",x.room_name),Link:x.agent_hash,Tag:"members"}]});
6 | send(x.agent_key,{"type":"add_private_rooms","room_name":x.room_name});
7 | return key;
8 | }
9 |
10 |
11 | //@param : {room_name:""}
12 | function getMembers(x){
13 | if(anchorExists("Private_Room",x.room_name)){
14 | members = getLinks(anchor("Private_Room",x.room_name), "members",{Load:true});
15 | var return_members;
16 | var i_Am_A_Member=false;
17 | members.forEach(function (element){
18 | if(element.Hash==App.Agent.Hash)
19 | i_Am_A_Member=true;
20 | return_members=element.Hash;
21 | });
22 | if(i_Am_A_Member){
23 | return return_members;
24 | }else{
25 | return "ERROR: You are not a Member of "+x.room_name;
26 | }
27 |
28 | }else{
29 | return "ERROR: invalid PRIVATE Room name "+x.room_name;
30 | }
31 | }
32 |
33 |
34 | function receive(from, msg) {
35 | var type = msg.type;
36 | if (type=="add_private_rooms") {
37 | return addRoomToMembersLocalChain({"room_name":msg.room_name});
38 | }
39 | return "unknown type"
40 | }
41 |
42 | // TODO: Needs validation - Check if uses is a member of the room
43 | //@param : room_name:"
44 | function addRoomToMembersLocalChain(x){
45 | debug("Addign Private Room to Local Chain: "+x.room_name)
46 | key=commit("local_private_room",x.room_name);
47 | commit("local_membership_link",{Links:[{Base:App.Agent.Hash,Link:key,Tag:"my_private_rooms"}]});
48 | return key;
49 | }
50 |
51 |
52 |
53 | /*---------- Anchor API ----------*/
54 |
55 | function anchor(anchorType, anchorText) {
56 | return call('anchors', 'anchor', {
57 | anchorType: anchorType,
58 | anchorText: anchorText
59 | }).replace(/"/g, '');
60 | }
61 |
62 | function anchorExists(anchorType, anchorText) {
63 | return call('anchors', 'exists', {
64 | anchorType: anchorType,
65 | anchorText: anchorText
66 | });
67 | }
68 |
69 | /*----------Validation Functions-----------*/
70 |
71 | function isRegisteredAdmin(entry_type,entry,header,sources){
72 |
73 | admins=getLinks(entry.Links[0].Base,"admin",{Load:true});
74 | for(i=0;i
2 |
3 | Holo Chat
4 |
5 |
6 |
7 |
8 |
9 | dna-to-openapi
10 |
11 |
12 |
13 | I 's Holo-Chat ?
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
Rooms
24 |
25 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
81 |
105 |
106 |