├── .gitignore
├── .travis.yml
├── Apps.md
├── Hosts.md
├── LICENSE
├── README.md
├── ROADMAP.md
├── apps
├── angular-template
│ ├── .gitignore
│ ├── README.md
│ ├── angular.json
│ ├── ng-add-pug-loader.js
│ ├── package-lock.json
│ ├── package.json
│ ├── prerender.ts
│ ├── scripts
│ │ ├── compare-versions.js
│ │ ├── new-component.js
│ │ ├── new-service.js
│ │ └── update-angular.sh
│ ├── server.ts
│ ├── src
│ │ ├── 404.html
│ │ ├── app
│ │ │ ├── app.component.ts
│ │ │ ├── app.module.ts
│ │ │ ├── app.routing.ts
│ │ │ ├── app.server.module.ts
│ │ │ ├── home
│ │ │ │ ├── home.component.ts
│ │ │ │ └── home.pug
│ │ │ ├── log-in-modal
│ │ │ │ ├── log-in-modal.component.ts
│ │ │ │ └── log-in-modal.pug
│ │ │ ├── navbar
│ │ │ │ ├── navbar.component.ts
│ │ │ │ └── navbar.pug
│ │ │ ├── services
│ │ │ │ ├── onedb.service.ts
│ │ │ │ └── platform.service.ts
│ │ │ └── styles
│ │ │ │ ├── _variables.scss
│ │ │ │ ├── app.scss
│ │ │ │ └── styles.scss
│ │ ├── assets
│ │ │ └── .gitkeep
│ │ ├── environments
│ │ │ ├── environment.prod.ts
│ │ │ └── environment.ts
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── main.server.ts
│ │ ├── main.ts
│ │ ├── polyfills.ts
│ │ ├── tsconfig.app.json
│ │ └── tsconfig.server.json
│ ├── static.paths.js
│ ├── tsconfig.json
│ ├── webpack.cli-additions.js
│ └── webpack.server.config.js
├── chat
│ ├── .gitignore
│ ├── README.md
│ ├── angular.json
│ ├── ng-add-pug-loader.js
│ ├── package-lock.json
│ ├── package.json
│ ├── prerender.ts
│ ├── scripts
│ │ ├── compare-versions.js
│ │ ├── new-component.js
│ │ ├── new-service.js
│ │ └── update-angular.sh
│ ├── server.js
│ ├── server.ts
│ ├── src
│ │ ├── 404.html
│ │ ├── app
│ │ │ ├── app.component.ts
│ │ │ ├── app.module.ts
│ │ │ ├── app.routing.ts
│ │ │ ├── app.server.module.ts
│ │ │ ├── chat
│ │ │ │ ├── chat.component.ts
│ │ │ │ └── chat.pug
│ │ │ ├── home
│ │ │ │ ├── home.component.ts
│ │ │ │ └── home.pug
│ │ │ ├── log-in-modal
│ │ │ │ ├── log-in-modal.component.ts
│ │ │ │ └── log-in-modal.pug
│ │ │ ├── navbar
│ │ │ │ ├── navbar.component.ts
│ │ │ │ └── navbar.pug
│ │ │ ├── rooms
│ │ │ │ ├── rooms.component.ts
│ │ │ │ └── rooms.pug
│ │ │ ├── services
│ │ │ │ ├── onedb.service.ts
│ │ │ │ └── platform.service.ts
│ │ │ └── styles
│ │ │ │ ├── _variables.scss
│ │ │ │ ├── app.scss
│ │ │ │ └── styles.scss
│ │ ├── assets
│ │ │ ├── .gitkeep
│ │ │ └── img
│ │ │ │ ├── Icon.png
│ │ │ │ ├── Logo-white.svg
│ │ │ │ ├── Logo.png
│ │ │ │ └── Logo.svg
│ │ ├── environments
│ │ │ ├── environment.prod.ts
│ │ │ └── environment.ts
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── main.server.ts
│ │ ├── main.ts
│ │ ├── polyfills.ts
│ │ ├── tsconfig.app.json
│ │ └── tsconfig.server.json
│ ├── static.paths.js
│ ├── tsconfig.json
│ ├── types
│ │ ├── conversation.acl.json
│ │ ├── conversation.schema.json
│ │ ├── message.acl.json
│ │ └── message.schema.json
│ ├── webpack.cli-additions.js
│ └── webpack.server.config.js
├── data-explorer
│ ├── .gitignore
│ ├── README.md
│ ├── angular.json
│ ├── ng-add-pug-loader.js
│ ├── package-lock.json
│ ├── package.json
│ ├── prerender.ts
│ ├── scripts
│ │ ├── compare-versions.js
│ │ ├── new-component.js
│ │ ├── new-service.js
│ │ └── update-angular.sh
│ ├── server.js
│ ├── server.ts
│ ├── src
│ │ ├── 404.html
│ │ ├── app
│ │ │ ├── app.component.ts
│ │ │ ├── app.module.ts
│ │ │ ├── app.routing.ts
│ │ │ ├── app.server.module.ts
│ │ │ ├── home
│ │ │ │ ├── home.component.ts
│ │ │ │ └── home.pug
│ │ │ ├── item
│ │ │ │ ├── item.component.ts
│ │ │ │ └── item.pug
│ │ │ ├── json-schema
│ │ │ │ ├── json-schema-editor.component.ts
│ │ │ │ ├── json-schema-editor.pug
│ │ │ │ ├── schema-label.component.ts
│ │ │ │ ├── schema-label.pug
│ │ │ │ └── util.ts
│ │ │ ├── log-in-modal
│ │ │ │ ├── log-in-modal.component.ts
│ │ │ │ └── log-in-modal.pug
│ │ │ ├── namespace
│ │ │ │ ├── namespace.component.ts
│ │ │ │ └── namespace.pug
│ │ │ ├── navbar
│ │ │ │ ├── navbar.component.ts
│ │ │ │ └── navbar.pug
│ │ │ ├── services
│ │ │ │ ├── onedb.service.ts
│ │ │ │ └── platform.service.ts
│ │ │ └── styles
│ │ │ │ ├── _variables.scss
│ │ │ │ ├── app.scss
│ │ │ │ ├── bootswatch.scss
│ │ │ │ └── styles.scss
│ │ ├── assets
│ │ │ ├── .gitkeep
│ │ │ └── img
│ │ │ │ ├── Icon.png
│ │ │ │ ├── Logo-white.svg
│ │ │ │ ├── Logo.png
│ │ │ │ └── Logo.svg
│ │ ├── environments
│ │ │ ├── environment.prod.ts
│ │ │ └── environment.ts
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── main.server.ts
│ │ ├── main.ts
│ │ ├── polyfills.ts
│ │ ├── tsconfig.app.json
│ │ └── tsconfig.server.json
│ ├── static.paths.js
│ ├── tsconfig.json
│ ├── webpack.cli-additions.js
│ └── webpack.server.config.js
├── minimal
│ ├── README.md
│ ├── index.html
│ ├── onedb-client.min.js
│ ├── types
│ │ ├── status.acl.json
│ │ └── status.schema.json
│ └── viewer.html
└── todo
│ ├── .gitignore
│ ├── README.md
│ ├── angular.json
│ ├── ng-add-pug-loader.js
│ ├── package-lock.json
│ ├── package.json
│ ├── prerender.ts
│ ├── scripts
│ ├── compare-versions.js
│ ├── new-component.js
│ ├── new-service.js
│ └── update-angular.sh
│ ├── server.js
│ ├── server.ts
│ ├── src
│ ├── 404.html
│ ├── app
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── app.routing.ts
│ │ ├── app.server.module.ts
│ │ ├── autofocus.directive.ts
│ │ ├── home
│ │ │ ├── home.component.ts
│ │ │ └── home.pug
│ │ ├── list
│ │ │ ├── list.component.ts
│ │ │ └── list.pug
│ │ ├── log-in-modal
│ │ │ ├── log-in-modal.component.ts
│ │ │ └── log-in-modal.pug
│ │ ├── navbar
│ │ │ ├── navbar.component.ts
│ │ │ └── navbar.pug
│ │ ├── services
│ │ │ ├── onedb.service.ts
│ │ │ └── platform.service.ts
│ │ └── styles
│ │ │ ├── _variables.scss
│ │ │ ├── app.scss
│ │ │ └── styles.scss
│ ├── assets
│ │ ├── .gitkeep
│ │ └── img
│ │ │ ├── Icon.png
│ │ │ ├── Logo-white.svg
│ │ │ ├── Logo.png
│ │ │ └── Logo.svg
│ ├── environments
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── main.server.ts
│ ├── main.ts
│ ├── polyfills.ts
│ ├── tsconfig.app.json
│ └── tsconfig.server.json
│ ├── static.paths.js
│ ├── tsconfig.json
│ ├── types
│ ├── item.schema.json
│ └── list.schema.json
│ ├── webpack.cli-additions.js
│ └── webpack.server.config.js
├── client
├── browser.js
├── dist
│ ├── onedb-client.min.js
│ └── onedb-client.min.js.map
├── index.js
├── lib
│ ├── client.js
│ └── login-form.js
├── package-lock.json
├── package.json
├── test
│ ├── client.js
│ └── multiple-instances.js
└── webpack.config.js
├── cmd
├── bin
│ └── onedb
├── cmd.js
├── index.js
├── lib
│ ├── files.js
│ ├── login.js
│ ├── namespace.js
│ └── serve.js
├── package-lock.json
└── package.json
├── package-lock.json
├── package.json
├── server
├── .gitignore
├── index.js
├── lib
│ ├── config.js
│ ├── database.js
│ ├── db-init.js
│ ├── db-util.js
│ ├── error-guard.js
│ ├── fail.js
│ ├── middleware
│ │ ├── authenticate.js
│ │ ├── authorize.js
│ │ ├── checkUsername.js
│ │ └── index.js
│ ├── routes
│ │ ├── crud.js
│ │ ├── index.js
│ │ ├── info.js
│ │ └── users.js
│ ├── server.js
│ ├── util
│ │ ├── index.js
│ │ ├── iterateSchema.js
│ │ ├── randomName.js
│ │ └── scopes.js
│ └── validate.js
├── namespaces
│ ├── core
│ │ ├── acl.js
│ │ ├── info.js
│ │ ├── namespace.js
│ │ └── schema.js
│ └── system
│ │ ├── authorization_token.js
│ │ ├── usage.js
│ │ ├── user.js
│ │ └── user_private.js
├── package-lock.json
├── package.json
├── test
│ ├── database.js
│ ├── db-util.js
│ ├── multiserver.js
│ ├── server.js
│ └── validate.js
└── web
│ └── views
│ ├── authorize.pug
│ ├── layout.pug
│ └── reset_password.pug
└── web
├── docs
├── LucyBot.yml
├── assets
│ └── img
│ │ ├── Icon.png
│ │ ├── Logo-white.svg
│ │ ├── Logo.png
│ │ ├── Logo.svg
│ │ └── quickstart_screenshot.png
├── markdown
│ ├── Authorization.md
│ ├── Client_API.md
│ ├── Data_Schemas.md
│ ├── End_to_End.md
│ ├── HTTP.md
│ ├── Host_an_Instance.md
│ ├── Multiple_Instances.md
│ ├── Overview.md
│ └── Quickstart.md
├── styles
│ ├── bootstrap.scss
│ └── styles.css
└── templates
│ └── navbar.html
├── homepage
├── img
│ ├── Icon.png
│ ├── Logo-white.svg
│ ├── Logo.png
│ ├── Logo.svg
│ └── team
│ │ ├── andrew.jpg
│ │ ├── bob.png
│ │ ├── bobby.jpg
│ │ ├── joe.jpg
│ │ ├── keep
│ │ └── throop.jpg
├── styles.css
└── views
│ └── index.pug
└── img
├── Icon.png
├── Logo-white.svg
├── Logo.png
└── Logo.svg
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | apps/**/dist
3 | web/docs/dist
4 | web/homepage/index.html
5 | OneDB.yml
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "8"
4 | - "10"
5 | script:
6 | - cd server && npm install && cd ..
7 | - cd client && npm install && cd ..
8 | - cd cmd && npm install && cd ..
9 | - npm test
10 | notifications:
11 | email:
12 | recipients:
13 | - bobby@datafire.io
14 | on_success: change
15 | on_failure: always
16 |
17 |
--------------------------------------------------------------------------------
/Apps.md:
--------------------------------------------------------------------------------
1 | # OneDB Apps
2 |
3 | > Have an app you'd like to share? Submit a pull request!
4 |
5 | The following is a list of apps built on OneDB:
6 |
7 | * [OneChat](https://chat.one-db.org) - Public chatrooms on any topic
8 | * [OneToDo](https://todo.one-db.org) - Create to-do lists
9 |
--------------------------------------------------------------------------------
/Hosts.md:
--------------------------------------------------------------------------------
1 | # OneDB Hosts
2 |
3 | > Hosting a public OneDB instance? Submit a pull request to add it here.
4 |
5 | The following hosts are publicly available for new users:
6 | * `https://one-db.datafire.io` - Supports all namespaces, up to 10MB of data per user for free
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Bobby Brennan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/apps/angular-template/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | docs/
3 |
4 | .idea
5 | .DS_Store
6 | morgan.log
7 |
8 | # Built #
9 | /__build__/
10 | /__server_build__/
11 | /node_modules/
12 | /typings/
13 | /tsd_typings/
14 | /dist/
15 | /dist-server/
16 | /compiled/
17 |
18 | # Node #
19 | npm-debug.log
20 | /npm-debug.log.*
21 |
22 | # Webpack #
23 | webpack.records.json
24 |
25 | # Angular #
26 | *.ngfactory.ts
27 | *.css.shim.ts
28 | *.ngsummary.json
29 | *.metadata.json
30 | *.shim.ngstyle.ts
31 |
--------------------------------------------------------------------------------
/apps/angular-template/README.md:
--------------------------------------------------------------------------------
1 | # Angluar 6.0 Template Project
2 | I use this template as a starter for any new Angular projects.
3 |
4 | Check out [the demo](https://bobby-brennan.github.io/angular6-template)
5 |
6 | #### Features
7 | * Angular Universal (prerendering)
8 | * [Pug](https://pugjs.org) templates instead of HTML
9 | * Bootstrap Sass
10 | * Font Awesome
11 | * Angular HTML5 Router
12 | * Standard navbar/body layout
13 |
14 | ## Running the Demo
15 |
16 | #### Install
17 |
18 | ```
19 | npm install
20 | ```
21 |
22 | #### Run (development mode)
23 | Start the server on port 3000:
24 |
25 | ```
26 | npm run start
27 | ```
28 |
29 |
30 | #### Build (production)
31 | Build everything and put it in the `dist/` folder:
32 |
33 | ```
34 | npm run build
35 | ```
36 |
37 | Or build for GitHub pages by copying `dist/browser` to `docs/`.
38 | Be sure to change the settings in your repo to point GitHub pages to
39 | the `docs/` folder on the `master` branch.
40 |
41 | ## Customizing
42 |
43 | ### Base href
44 | The app uses the base href `/` for development builds, and `/angular6-template`
45 | for production builds (to accomodate GitHub pages, which uses the repository
46 | name in the URL's path). You will probably want to change the base href in
47 | `./src/environments/environment.prod.ts`.
48 |
49 | ### Prerendering
50 | Prerendering is a performance optimization - your page's HTML is generated
51 | at build time, so the user sees a near-instant load of the page, while Angular
52 | loads in the background.
53 |
54 | In this build, only the homepage is prerendered - you can add other routes
55 | by editing `./static.paths.ts`.
56 |
57 | ## New Components
58 | A helper script for creating new components is in `./scripts/new-component.js`.
59 |
60 | ```
61 | node ./scripts/new-component.js --name "Widget Viewer"
62 | ```
63 |
--------------------------------------------------------------------------------
/apps/angular-template/ng-add-pug-loader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Adds the pug-loader inside Angular CLI's webpack config, if not there yet.
3 | * @see https://github.com/danguilherme/ng-cli-pug-loader
4 | */
5 | const fs = require('fs');
6 | const commonCliConfig = 'node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/common.js';
7 | const pugRule = '{ test: /.pug$/, use: [ { loader: "apply-loader" }, { loader: "pug-loader" } ] },';
8 |
9 | fs.readFile(commonCliConfig, (err, data) => {
10 | if (err) { throw err; }
11 |
12 | const configText = data.toString();
13 | // make sure we don't add the rule if it already exists
14 | if (configText.indexOf(pugRule) > -1) { return; }
15 |
16 | // Insert the pug webpack rule
17 | const position = configText.indexOf('rules: [') + 8;
18 | const output = [configText.slice(0, position), pugRule, configText.slice(position)].join('');
19 | const file = fs.openSync(commonCliConfig, 'r+');
20 | fs.writeFile(file, output);
21 | fs.close(file);
22 | });
23 |
--------------------------------------------------------------------------------
/apps/angular-template/prerender.ts:
--------------------------------------------------------------------------------
1 | // Load zone.js for the server.
2 | import 'zone.js/dist/zone-node';
3 | import 'reflect-metadata';
4 | import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
5 | import { join } from 'path';
6 | import { chdir } from 'process';
7 |
8 | import { enableProdMode } from '@angular/core';
9 | // Faster server renders w/ Prod mode (dev mode never needed)
10 | enableProdMode();
11 |
12 | // Express Engine
13 | import { ngExpressEngine } from '@nguniversal/express-engine';
14 | // Import module map for lazy loading
15 | import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
16 |
17 | import { renderModuleFactory } from '@angular/platform-server';
18 |
19 | // * NOTE :: leave this as require() since this file is built Dynamically from webpack
20 | const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');
21 |
22 | // Get route paths to prerender only static pages
23 | const PATHS = require('./static.paths');
24 |
25 | const BROWSER_FOLDER = join(process.cwd(), 'browser');
26 |
27 | // Load the index.html file containing referances to your application bundle.
28 | const index = readFileSync(join('browser', 'index.html'), 'utf8');
29 |
30 | let prom = Promise.resolve();
31 |
32 | // Iterate each route path
33 | PATHS.forEach(function (route) {
34 | // Changes current directory to ./dist/browser
35 | chdir(BROWSER_FOLDER);
36 |
37 | // Creates new directories (if not exists) and changes current directory for the nested one
38 | route.split('/').filter(val => val !== '')
39 | .forEach(function (dir) {
40 | if (!existsSync(dir)) {
41 | mkdirSync(dir);
42 | }
43 | chdir(dir);
44 | });
45 |
46 | // Writes rendered HTML to index.html, replacing the file if it already exists.
47 | prom = prom.then(_ => renderModuleFactory(AppServerModuleNgFactory, {
48 | document: index,
49 | url: route,
50 | extraProviders: [
51 | provideModuleMap(LAZY_MODULE_MAP)
52 | ]
53 | })).then(html => writeFileSync(join(BROWSER_FOLDER, route, 'index.html'), html));
54 | });
55 |
--------------------------------------------------------------------------------
/apps/angular-template/scripts/compare-versions.js:
--------------------------------------------------------------------------------
1 | let fs = require('fs');
2 | let path = require('path');
3 | let args = require('yargs').argv;
4 |
5 | function addDirToVersions(dir, versions) {
6 | fs.readdirSync(dir).forEach(d => {
7 | if (d.indexOf('.') === 0) {
8 | return;
9 | }
10 | if (d.indexOf('@') === 0) {
11 | addDirToVersions(dir + '/' + d, versions);
12 | } else {
13 | let pkg = require(dir + '/' + d + '/package.json');
14 | versions[d] = pkg.version;
15 | }
16 | })
17 | }
18 |
19 | let aVersions = {};
20 | addDirToVersions(path.resolve(args.a + '/node_modules'), aVersions);
21 | let bVersions = {};
22 | addDirToVersions(path.resolve(args.b + '/node_modules'), bVersions);
23 |
24 | let keys = Object.keys(aVersions);
25 | for (let key in bVersions) {
26 | if (keys.indexOf(key) === -1) keys.push(key);
27 | }
28 |
29 | keys.forEach(key => {
30 | let v1 = aVersions[key];
31 | let v2 = bVersions[key];
32 | if (v1 !== v2) {
33 | console.log(key + '\t' + aVersions[key] + '\t' + bVersions[key]);
34 | }
35 | })
36 |
--------------------------------------------------------------------------------
/apps/angular-template/scripts/new-component.js:
--------------------------------------------------------------------------------
1 | const args = require('yargs').argv;
2 | const fs = require('fs');
3 |
4 | let componentCode = function(name, filename) {
5 | return `
6 | import {Component} from '@angular/core';
7 |
8 | @Component({
9 | selector: '${filename}',
10 | templateUrl: './${filename}.pug',
11 | })
12 | export class ${name}Component {
13 | constructor() {}
14 | }
15 | `.trim()
16 | }
17 |
18 | let viewCode = function(name) {
19 | return `
20 | h1 ${name}
21 | `.trim();
22 | }
23 |
24 | const APP_DIR = __dirname + '/../src/app/';
25 |
26 | const filename = args.name.toLowerCase().replace(/\s/g, '-');
27 | const componentName = args.name.replace(/\s/g, '');
28 | const componentDir = APP_DIR + filename + '/';
29 | const componentFile = componentDir + filename + '.component.ts';
30 | const viewFile = componentDir + filename + '.pug';
31 | const appFile = APP_DIR + 'app.module.ts';
32 |
33 | let component = componentCode(componentName, filename);
34 | let view = viewCode(args.name);
35 |
36 | fs.mkdirSync(componentDir);
37 | fs.writeFileSync(viewFile, view);
38 | fs.writeFileSync(componentFile, component);
39 |
40 | let app = fs.readFileSync(appFile, 'utf8');
41 | let lines = app.split('\n').reverse();
42 |
43 | let insertImportAt = lines.findIndex(l => l.match(/^import .* from '\.\/.*.component'/));
44 | lines.splice(insertImportAt, 0, `import {${componentName}Component} from './${filename}/${filename}.component'`);
45 |
46 | let insertDeclarationAt = lines.findIndex(l => l.match(/^\s+\w+Component,/));
47 | lines.splice(insertDeclarationAt, 0, ` ${componentName}Component,`)
48 |
49 | lines.reverse();
50 | fs.writeFileSync(appFile, lines.join('\n'));
51 |
--------------------------------------------------------------------------------
/apps/angular-template/scripts/new-service.js:
--------------------------------------------------------------------------------
1 | const args = require('yargs').argv;
2 | const fs = require('fs');
3 |
4 | let serviceCode = function(name, filename) {
5 | return `
6 | import {Injectable} from '@angular/core';
7 |
8 | @Injectable()
9 | export class ${name}Service {
10 | constructor() {}
11 | }
12 | `.trim()
13 | }
14 |
15 | const APP_DIR = __dirname + '/../src/app/';
16 |
17 | const filename = args.name.toLowerCase().replace(/\s/g, '-');
18 | const serviceName = args.name.replace(/\s/g, '');
19 | const serviceDir = APP_DIR + 'services/';
20 | const serviceFile = serviceDir + filename + '.service.ts';
21 | const appFile = APP_DIR + 'app.module.ts';
22 |
23 | let service = serviceCode(serviceName, filename);
24 |
25 | fs.writeFileSync(serviceFile, service);
26 |
27 | let app = fs.readFileSync(appFile, 'utf8');
28 | let lines = app.split('\n').reverse();
29 |
30 | let insertImportAt = lines.findIndex(l => l.match(/^import .* from '\.\/.*.service'/));
31 | lines.splice(insertImportAt, 0, `import {${serviceName}Service} from './services/${filename}.service'`);
32 |
33 | let insertDeclarationAt = lines.findIndex(l => l.match(/^\s+\w+Service,/));
34 | lines.splice(insertDeclarationAt, 0, ` ${serviceName}Service,`)
35 |
36 | lines.reverse();
37 | fs.writeFileSync(appFile, lines.join('\n'));
38 |
--------------------------------------------------------------------------------
/apps/angular-template/scripts/update-angular.sh:
--------------------------------------------------------------------------------
1 | npm i --save @angular/animations@latest @angular/router@latest @angular/common@latest @angular/compiler@latest @angular/core@latest @angular/forms@latest @angular/http@latest @angular/platform-browser@latest @angular/platform-browser-dynamic@latest @angular/platform-server@latest @angular/cli@latest @angular/compiler-cli@latest @angular/language-service@latest @nguniversal/express-engine@latest @nguniversal/module-map-ngfactory-loader@latest rxjs@latest
2 |
--------------------------------------------------------------------------------
/apps/angular-template/server.ts:
--------------------------------------------------------------------------------
1 | import 'zone.js/dist/zone-node';
2 | import 'reflect-metadata';
3 | import { renderModuleFactory } from '@angular/platform-server';
4 | import { enableProdMode } from '@angular/core';
5 |
6 | import * as express from 'express';
7 | import { join } from 'path';
8 | import { readFileSync } from 'fs';
9 |
10 | // Faster server renders w/ Prod mode (dev mode never needed)
11 | enableProdMode();
12 |
13 | // Express server
14 | const app = express();
15 |
16 | const PORT = process.env.PORT || 4000;
17 | const DIST_FOLDER = join(process.cwd(), 'dist');
18 |
19 | // Our index.html we'll use as our template
20 | const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();
21 |
22 | // * NOTE :: leave this as require() since this file is built Dynamically from webpack
23 | const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');
24 |
25 | // Express Engine
26 | import { ngExpressEngine } from '@nguniversal/express-engine';
27 | // Import module map for lazy loading
28 | import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
29 |
30 | // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
31 | app.engine('html', ngExpressEngine({
32 | bootstrap: AppServerModuleNgFactory,
33 | providers: [
34 | provideModuleMap(LAZY_MODULE_MAP)
35 | ]
36 | }));
37 |
38 | app.set('view engine', 'html');
39 | app.set('views', join(DIST_FOLDER, 'browser'));
40 |
41 | /* - Example Express Rest API endpoints -
42 | app.get('/api/**', (req, res) => { });
43 | */
44 |
45 | // Server static files from /browser
46 | app.get('*.*', express.static(join(DIST_FOLDER, 'browser'), {
47 | maxAge: '1y'
48 | }));
49 |
50 | // ALl regular routes use the Universal engine
51 | app.get('*', (req, res) => {
52 | res.render('index', { req });
53 | });
54 |
55 | // Start up the Node server
56 | app.listen(PORT, () => {
57 | console.log(`Node Express server listening on http://localhost:${PORT}`);
58 | });
59 |
--------------------------------------------------------------------------------
/apps/angular-template/src/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/apps/angular-template/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | template: `
6 |
7 |
8 |
9 |
10 | `,
11 | })
12 | export class AppComponent {
13 | constructor() {
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/apps/angular-template/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { BrowserModule } from '@angular/platform-browser';
3 | import { RouterModule } from '@angular/router';
4 | import { FormsModule } from '@angular/forms';
5 | import { HttpModule } from '@angular/http';
6 | import {APP_BASE_HREF} from '@angular/common';
7 |
8 | import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
9 |
10 | import { appRoutes } from './app.routing';
11 | import { AppComponent } from './app.component';
12 | import { HomeComponent } from './home/home.component';
13 | import { NavbarComponent } from './navbar/navbar.component';
14 | import {LogInModalComponent} from './log-in-modal/log-in-modal.component'
15 |
16 | import {PlatformService} from './services/platform.service';
17 | import {OneDBService} from './services/onedb.service'
18 |
19 | import { environment } from '../environments/environment';
20 |
21 | @NgModule({
22 | imports: [
23 | BrowserModule.withServerTransition({appId: 'my-app'}),
24 | RouterModule.forRoot(appRoutes),
25 | HttpModule,
26 | FormsModule,
27 | NgbModule.forRoot(),
28 | ],
29 | providers: [
30 | {provide: APP_BASE_HREF, useValue: environment.baseHref || '/'},
31 | PlatformService,
32 | OneDBService,
33 | ],
34 | declarations: [
35 | AppComponent,
36 | HomeComponent,
37 | NavbarComponent,
38 | LogInModalComponent,
39 | ],
40 | bootstrap: [ AppComponent ],
41 | })
42 | export class AppModule { }
43 |
--------------------------------------------------------------------------------
/apps/angular-template/src/app/app.routing.ts:
--------------------------------------------------------------------------------
1 | import { Routes, RouterModule } from '@angular/router';
2 | import {HomeComponent} from './home/home.component';
3 |
4 | export const appRoutes: Routes = [
5 | { path: '', component: HomeComponent },
6 | { path: '**', redirectTo: '' },
7 | ];
8 |
9 |
--------------------------------------------------------------------------------
/apps/angular-template/src/app/app.server.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {ServerModule} from '@angular/platform-server';
3 | import {ModuleMapLoaderModule} from '@nguniversal/module-map-ngfactory-loader';
4 |
5 | import {AppModule} from './app.module';
6 | import {AppComponent} from './app.component';
7 |
8 | @NgModule({
9 | imports: [
10 | // The AppServerModule should import your AppModule followed
11 | // by the ServerModule from @angular/platform-server.
12 | AppModule,
13 | ServerModule,
14 | ModuleMapLoaderModule,
15 | ],
16 | // Since the bootstrapped component is not inherited from your
17 | // imported AppModule, it needs to be repeated here.
18 | bootstrap: [AppComponent],
19 | })
20 | export class AppServerModule {}
21 |
--------------------------------------------------------------------------------
/apps/angular-template/src/app/home/home.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, ViewChild} from '@angular/core';
2 | import {Router} from '@angular/router';
3 | import {OneDBService} from '../services/onedb.service';
4 |
5 | declare let window:any;
6 | declare let require:any;
7 |
8 | @Component({
9 | selector: 'home',
10 | templateUrl: './home.pug',
11 | })
12 | export class HomeComponent {
13 | @ViewChild('logInModal') logInModal;
14 | error:string;
15 | constructor(public onedb:OneDBService) {
16 | this.onedb.onLogin.subscribe(user => {
17 | console.log(user);
18 | });
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/apps/angular-template/src/app/home/home.pug:
--------------------------------------------------------------------------------
1 | log-in-modal(#logInModal)
2 | h1 Welcome to OneDB!
3 | div(*ngIf="onedb.client.hosts.primary.user")
4 | p You're logged in as {{ onedb.client.hosts.primary.user.$.id }}
5 |
--------------------------------------------------------------------------------
/apps/angular-template/src/app/log-in-modal/log-in-modal.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, ViewChild} from '@angular/core';
2 | import {OneDBService} from '../services/onedb.service';
3 | import {NgbModal, ModalDismissReasons} from '@ng-bootstrap/ng-bootstrap';
4 | import {DomSanitizer, SafeHtml} from '@angular/platform-browser'
5 |
6 | @Component({
7 | selector: 'log-in-modal',
8 | templateUrl: './log-in-modal.pug',
9 | })
10 | export class LogInModalComponent {
11 | @ViewChild('content') content;
12 | formContent:SafeHtml;
13 | modalRef:any;
14 |
15 | constructor(
16 | private onedb:OneDBService,
17 | private modals: NgbModal,
18 | private sanitizer:DomSanitizer) {
19 | this.refreshForm();
20 | this.onedb.onLogin.subscribe(instance => {
21 | this.refreshForm();
22 | if (this.modalRef && instance.user) this.modalRef.close();
23 | })
24 | }
25 |
26 | open() {
27 | this.modalRef = this.modals.open(this.content);
28 | }
29 |
30 | refreshForm() {
31 | this.formContent = this.sanitizer.bypassSecurityTrustHtml(this.onedb.client.loginForm());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/apps/angular-template/src/app/log-in-modal/log-in-modal.pug:
--------------------------------------------------------------------------------
1 | ng-template(#content let-c="close" let-d="dismiss")
2 | .modal-header
3 | h4.modal-title
4 | span(*ngIf="!onedb.client.hosts.primary.user") Log In or Sign Up
5 | span(*ngIf="onedb.client.hosts.primary.user") Log Out or Switch Accounts
6 | button.close(type="button", class="close", aria-label="Close", (click)="d('Cross click')")
7 | span(aria-hidden="true") ×
8 | .modal-body
9 | div([innerHtml]="formContent")
10 |
--------------------------------------------------------------------------------
/apps/angular-template/src/app/navbar/navbar.component.ts:
--------------------------------------------------------------------------------
1 | import {ViewChild, Component} from '@angular/core';
2 | import {Router} from '@angular/router';
3 | import {OneDBService} from '../services/onedb.service';
4 |
5 | @Component({
6 | selector: 'navbar',
7 | templateUrl: './navbar.pug',
8 | })
9 | export class NavbarComponent {
10 | @ViewChild('logInModal') logInModal;
11 | constructor(public router: Router, public onedb:OneDBService) {}
12 | }
13 |
--------------------------------------------------------------------------------
/apps/angular-template/src/app/navbar/navbar.pug:
--------------------------------------------------------------------------------
1 | log-in-modal(#logInModal)
2 | nav.navbar.navbar-expand-lg.navbar-dark.bg-dark
3 | .container
4 | a.navbar-brand(routerLink="/") OneDB Sample App
5 | div
6 | ul.navbar-nav.ml-auto
7 | li
8 | a.nav-link((click)="logInModal.open()")
9 | i.fa.fa-left.fa-users
10 | span([ngSwitch]="!!onedb.client.hosts.primary.user")
11 | span(*ngSwitchCase="true")
12 | span {{onedb.client.hosts.primary.displayName}}
13 | span(*ngSwitchCase="false") Sign In
14 |
15 |
--------------------------------------------------------------------------------
/apps/angular-template/src/app/services/onedb.service.ts:
--------------------------------------------------------------------------------
1 | import {Injectable, NgZone} from '@angular/core';
2 | import {BehaviorSubject} from 'rxjs';
3 |
4 | declare let window:any;
5 | declare let require:any;
6 | const Client = require('onedb-client').Client;
7 | const CORE_HOST = 'https://one-db.datafire.io';
8 |
9 | const STORAGE_KEY = 'onedb_auth';
10 |
11 | @Injectable()
12 | export class OneDBService {
13 | client:any;
14 | user:any;
15 |
16 | onLogin = new BehaviorSubject(null);
17 |
18 | constructor(private zone:NgZone) {
19 | window.onedbService = this;
20 | this.client = new Client({
21 | hosts: {
22 | core: {
23 | location: CORE_HOST,
24 | }
25 | },
26 | onLogin: user => {
27 | this.zone.run(_ => this.onLogin.next(user));
28 | },
29 | });
30 | this.maybeRestore();
31 | this.onLogin.subscribe(user => {
32 | this.user = user;
33 | if (!window.localStorage) return
34 | const toStore = {
35 | hosts: this.client.hosts,
36 | };
37 | window.localStorage.setItem(STORAGE_KEY, JSON.stringify(toStore))
38 | })
39 | }
40 |
41 | async maybeRestore() {
42 | if (!window.localStorage) return;
43 | let existing:any = window.localStorage.getItem(STORAGE_KEY);
44 | if (!existing) return;
45 | existing = JSON.parse(existing);
46 | if (!existing || !existing.hosts) return;
47 | let hosts = Object.assign({}, existing.hosts, {core: {location: CORE_HOST}})
48 | await this.client.setHosts(hosts);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/apps/angular-template/src/app/services/platform.service.ts:
--------------------------------------------------------------------------------
1 | import { Inject, Injectable, PLATFORM_ID } from '@angular/core'
2 | import { isPlatformBrowser, isPlatformServer } from '@angular/common'
3 |
4 | @Injectable()
5 | export class PlatformService {
6 | constructor(@Inject(PLATFORM_ID) private platformId: any) { }
7 |
8 | public isBrowser(): boolean {
9 | return isPlatformBrowser(this.platformId)
10 | }
11 |
12 | public isServer(): boolean {
13 | return isPlatformServer(this.platformId)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/apps/angular-template/src/app/styles/_variables.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/angular-template/src/app/styles/_variables.scss
--------------------------------------------------------------------------------
/apps/angular-template/src/app/styles/app.scss:
--------------------------------------------------------------------------------
1 | a {
2 | cursor: pointer;
3 | }
4 |
5 | .navbar {
6 | border-radius: 0px;
7 | margin-bottom: 30px;
8 | }
9 |
10 | body {
11 | position: relative;
12 | }
13 |
14 | app > .container {
15 | padding-bottom: 72px;
16 | }
17 |
18 | footer {
19 | position: absolute;
20 | bottom: 0;
21 | left: 0;
22 | right: 0;
23 |
24 | background-color: #fff;
25 | padding-top: 20px;
26 | padding-bottom: 20px;
27 | }
28 |
29 | footer, footer a {
30 | color: #3E3F3A;
31 | }
32 |
33 | .fa-left {
34 | margin-right: 8px;
35 | }
36 | .fa-right {
37 | margin-left: 8px;
38 | }
39 |
40 | .btn-min-width {
41 | min-width: 100px;
42 | }
43 |
--------------------------------------------------------------------------------
/apps/angular-template/src/app/styles/styles.scss:
--------------------------------------------------------------------------------
1 | @import 'variables';
2 |
3 | @import '~bootstrap/scss/bootstrap';
4 |
5 | @import './app.scss';
6 |
7 |
--------------------------------------------------------------------------------
/apps/angular-template/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/angular-template/src/assets/.gitkeep
--------------------------------------------------------------------------------
/apps/angular-template/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | baseHref: '/',
4 | };
5 |
--------------------------------------------------------------------------------
/apps/angular-template/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // The file contents for the current environment will overwrite these during build.
2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do
3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead.
4 | // The list of which env maps to which file can be found in `.angular-cli.json`.
5 |
6 | export const environment = {
7 | production: false,
8 | baseHref: '/',
9 | };
10 |
--------------------------------------------------------------------------------
/apps/angular-template/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/angular-template/src/favicon.ico
--------------------------------------------------------------------------------
/apps/angular-template/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | OneDB
7 |
8 |
9 |
10 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/apps/angular-template/src/main.server.ts:
--------------------------------------------------------------------------------
1 | export { AppServerModule } from './app/app.server.module';
2 |
--------------------------------------------------------------------------------
/apps/angular-template/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | document.addEventListener('DOMContentLoaded', () => {
12 | platformBrowserDynamic().bootstrapModule(AppModule);
13 | });
14 |
--------------------------------------------------------------------------------
/apps/angular-template/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/
22 | // import 'core-js/es6/symbol';
23 | // import 'core-js/es6/object';
24 | // import 'core-js/es6/function';
25 | // import 'core-js/es6/parse-int';
26 | // import 'core-js/es6/parse-float';
27 | // import 'core-js/es6/number';
28 | // import 'core-js/es6/math';
29 | // import 'core-js/es6/string';
30 | // import 'core-js/es6/date';
31 | // import 'core-js/es6/array';
32 | // import 'core-js/es6/regexp';
33 | // import 'core-js/es6/map';
34 | // import 'core-js/es6/weak-map';
35 | // import 'core-js/es6/set';
36 |
37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
38 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
39 |
40 | /** Evergreen browsers require these. **/
41 | import 'core-js/es6/reflect';
42 | import 'core-js/es7/reflect';
43 | import 'babel-polyfill';
44 |
45 | /**
46 | * Required to support Web Animations `@angular/animation`.
47 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
48 | **/
49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
50 |
51 |
52 |
53 | /***************************************************************************************************
54 | * Zone JS is required by Angular itself.
55 | */
56 | import 'zone.js/dist/zone'; // Included with Angular CLI.
57 |
58 |
59 |
60 | /***************************************************************************************************
61 | * APPLICATION IMPORTS
62 | */
63 |
64 | /**
65 | * Date, currency, decimal and percent pipes.
66 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
67 | */
68 | // import 'intl'; // Run `npm install --save intl`.
69 | /**
70 | * Need to import at least one locale-data with intl.
71 | */
72 | // import 'intl/locale-data/jsonp/en';
73 |
--------------------------------------------------------------------------------
/apps/angular-template/src/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "baseUrl": "./",
6 | "module": "es2015",
7 | "types": []
8 | },
9 | "exclude": [
10 | "test.ts",
11 | "**/*.spec.ts"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/apps/angular-template/src/tsconfig.server.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "baseUrl": "./",
6 | // Set the module format to "commonjs":
7 | "module": "commonjs",
8 | "types": []
9 | },
10 | "exclude": [
11 | "test.ts",
12 | "**/*.spec.ts"
13 | ],
14 | // Add "angularCompilerOptions" with the AppServerModule you wrote
15 | // set as the "entryModule".
16 | "angularCompilerOptions": {
17 | "entryModule": "app/app.server.module#AppServerModule"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/apps/angular-template/static.paths.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | '/',
3 | ];
4 |
--------------------------------------------------------------------------------
/apps/angular-template/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "outDir": "./dist/out-tsc",
5 | "sourceMap": true,
6 | "declaration": false,
7 | "moduleResolution": "node",
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "target": "es5",
11 | "typeRoots": [
12 | "node_modules/@types",
13 | "typings.d.ts"
14 | ],
15 | "lib": [
16 | "es2017",
17 | "dom"
18 | ],
19 | "types": ["node"],
20 | "module": "es2015",
21 | "baseUrl": "./"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/apps/angular-template/webpack.cli-additions.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const commonCliConfig = 'node_modules/@angular/cli/models/webpack-configs/common.js';
3 | const addition_rules = `
4 | { test: /\.(pug|jade)$/, loader: 'apply-loader' },
5 | { test: /\.(pug|jade)$/,
6 | loader: 'pug-loader',
7 | query: { doctype: 'html', plugins: [require('pug-plugin-ng')] },
8 | }, {
9 | test: /\.json$/,
10 | use: [{
11 | loader: 'json-loader',
12 | }]
13 | },
14 | {
15 | test: /\.js$/,
16 | use: [{
17 | loader: 'babel-loader',
18 | options: {
19 | presets: ['env'],
20 | }
21 | }],
22 | },
23 | { test: /\.md$/, use: [{ loader: 'raw-loader' }, { loader: 'markdown-loader', }] }
24 | ,`; // make sure to have this last comma
25 |
26 | fs.readFile(commonCliConfig, (err, data) => {
27 |
28 | if (err) { throw err; }
29 |
30 | const configText = data.toString();
31 | // make sure we don't include it (if we've already done this)
32 | if (configText.indexOf(addition_rules) > -1) { return; }
33 |
34 | console.log('-- Inserting additional webpack rules to node_modules CLI -- ');
35 |
36 | const position = configText.indexOf('rules: [') + 8;
37 | const output = [configText.slice(0, position), addition_rules, configText.slice(position)].join('');
38 | const file = fs.openSync(commonCliConfig, 'r+');
39 |
40 | fs.writeFile(file, output);
41 | fs.close(file);
42 | });
43 |
44 |
--------------------------------------------------------------------------------
/apps/angular-template/webpack.server.config.js:
--------------------------------------------------------------------------------
1 | // Work around for https://github.com/angular/angular-cli/issues/7200
2 |
3 | const path = require('path');
4 | const webpack = require('webpack');
5 |
6 | module.exports = {
7 | entry: {
8 | // This is our Express server for Dynamic universal
9 | server: './server.ts',
10 | // This is an example of Static prerendering (generative)
11 | prerender: './prerender.ts'
12 | },
13 | target: 'node',
14 | resolve: { extensions: ['.ts', '.js'] },
15 | // Make sure we include all node_modules etc
16 | externals: [/(node_modules|main\..*\.js)/,],
17 | output: {
18 | // Puts the output at the root of the dist folder
19 | path: path.join(__dirname, 'dist'),
20 | filename: '[name].js'
21 | },
22 | module: {
23 | rules: [
24 | { test: /\.ts$/, use: {loader: 'ts-loader', options: {}} }
25 | ]
26 | },
27 | plugins: [
28 | new webpack.ContextReplacementPlugin(
29 | // fixes WARNING Critical dependency: the request of a dependency is an expression
30 | /(.+)?angular(\\|\/)core(.+)?/,
31 | path.join(__dirname, 'src'), // location of your src
32 | {} // a map of your routes
33 | ),
34 | new webpack.ContextReplacementPlugin(
35 | // fixes WARNING Critical dependency: the request of a dependency is an expression
36 | /(.+)?express(\\|\/)(.+)?/,
37 | path.join(__dirname, 'src'),
38 | {}
39 | )
40 | ]
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/apps/chat/.gitignore:
--------------------------------------------------------------------------------
1 | docs/
2 |
3 | .idea
4 | .DS_Store
5 | morgan.log
6 |
7 | # Built #
8 | /__build__/
9 | /__server_build__/
10 | /node_modules/
11 | /typings/
12 | /tsd_typings/
13 | /dist-server/
14 | /compiled/
15 |
16 | # Node #
17 | npm-debug.log
18 | /npm-debug.log.*
19 |
20 | # Webpack #
21 | webpack.records.json
22 |
23 | # Angular #
24 | *.ngfactory.ts
25 | *.css.shim.ts
26 | *.ngsummary.json
27 | *.metadata.json
28 | *.shim.ngstyle.ts
29 |
--------------------------------------------------------------------------------
/apps/chat/README.md:
--------------------------------------------------------------------------------
1 | # Angluar 6.0 Template Project
2 | I use this template as a starter for any new Angular projects.
3 |
4 | Check out [the demo](https://bobby-brennan.github.io/angular6-template)
5 |
6 | #### Features
7 | * Angular Universal (prerendering)
8 | * [Pug](https://pugjs.org) templates instead of HTML
9 | * Bootstrap Sass
10 | * Font Awesome
11 | * Angular HTML5 Router
12 | * Standard navbar/body layout
13 |
14 | ## Running the Demo
15 |
16 | #### Install
17 |
18 | ```
19 | npm install
20 | ```
21 |
22 | #### Run (development mode)
23 | Start the server on port 3000:
24 |
25 | ```
26 | npm run start
27 | ```
28 |
29 |
30 | #### Build (production)
31 | Build everything and put it in the `dist/` folder:
32 |
33 | ```
34 | npm run build
35 | ```
36 |
37 | Or build for GitHub pages by copying `dist/browser` to `docs/`.
38 | Be sure to change the settings in your repo to point GitHub pages to
39 | the `docs/` folder on the `master` branch.
40 |
41 | ## Customizing
42 |
43 | ### Base href
44 | The app uses the base href `/` for development builds, and `/angular6-template`
45 | for production builds (to accomodate GitHub pages, which uses the repository
46 | name in the URL's path). You will probably want to change the base href in
47 | `./src/environments/environment.prod.ts`.
48 |
49 | ### Prerendering
50 | Prerendering is a performance optimization - your page's HTML is generated
51 | at build time, so the user sees a near-instant load of the page, while Angular
52 | loads in the background.
53 |
54 | In this build, only the homepage is prerendered - you can add other routes
55 | by editing `./static.paths.ts`.
56 |
57 | ## New Components
58 | A helper script for creating new components is in `./scripts/new-component.js`.
59 |
60 | ```
61 | node ./scripts/new-component.js --name "Widget Viewer"
62 | ```
63 |
--------------------------------------------------------------------------------
/apps/chat/ng-add-pug-loader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Adds the pug-loader inside Angular CLI's webpack config, if not there yet.
3 | * @see https://github.com/danguilherme/ng-cli-pug-loader
4 | */
5 | const fs = require('fs');
6 | const commonCliConfig = 'node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/common.js';
7 | const pugRule = '{ test: /.pug$/, use: [ { loader: "apply-loader" }, { loader: "pug-loader" } ] },';
8 |
9 | fs.readFile(commonCliConfig, (err, data) => {
10 | if (err) { throw err; }
11 |
12 | const configText = data.toString();
13 | // make sure we don't add the rule if it already exists
14 | if (configText.indexOf(pugRule) > -1) { return; }
15 |
16 | // Insert the pug webpack rule
17 | const position = configText.indexOf('rules: [') + 8;
18 | const output = [configText.slice(0, position), pugRule, configText.slice(position)].join('');
19 | const file = fs.openSync(commonCliConfig, 'r+');
20 | fs.writeFile(file, output);
21 | fs.close(file);
22 | });
23 |
--------------------------------------------------------------------------------
/apps/chat/prerender.ts:
--------------------------------------------------------------------------------
1 | // Load zone.js for the server.
2 | import 'zone.js/dist/zone-node';
3 | import 'reflect-metadata';
4 | import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
5 | import { join } from 'path';
6 | import { chdir } from 'process';
7 |
8 | import { enableProdMode } from '@angular/core';
9 | // Faster server renders w/ Prod mode (dev mode never needed)
10 | enableProdMode();
11 |
12 | // Express Engine
13 | import { ngExpressEngine } from '@nguniversal/express-engine';
14 | // Import module map for lazy loading
15 | import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
16 |
17 | import { renderModuleFactory } from '@angular/platform-server';
18 |
19 | // * NOTE :: leave this as require() since this file is built Dynamically from webpack
20 | const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');
21 |
22 | // Get route paths to prerender only static pages
23 | const PATHS = require('./static.paths');
24 |
25 | const BROWSER_FOLDER = join(process.cwd(), 'browser');
26 |
27 | // Load the index.html file containing referances to your application bundle.
28 | const index = readFileSync(join('browser', 'index.html'), 'utf8');
29 |
30 | let prom = Promise.resolve();
31 |
32 | // Iterate each route path
33 | PATHS.forEach(function (route) {
34 | // Changes current directory to ./dist/browser
35 | chdir(BROWSER_FOLDER);
36 |
37 | // Creates new directories (if not exists) and changes current directory for the nested one
38 | route.split('/').filter(val => val !== '')
39 | .forEach(function (dir) {
40 | if (!existsSync(dir)) {
41 | mkdirSync(dir);
42 | }
43 | chdir(dir);
44 | });
45 |
46 | // Writes rendered HTML to index.html, replacing the file if it already exists.
47 | prom = prom.then(_ => renderModuleFactory(AppServerModuleNgFactory, {
48 | document: index,
49 | url: route,
50 | extraProviders: [
51 | provideModuleMap(LAZY_MODULE_MAP)
52 | ]
53 | })).then(html => writeFileSync(join(BROWSER_FOLDER, route, 'index.html'), html));
54 | });
55 |
--------------------------------------------------------------------------------
/apps/chat/scripts/compare-versions.js:
--------------------------------------------------------------------------------
1 | let fs = require('fs');
2 | let path = require('path');
3 | let args = require('yargs').argv;
4 |
5 | function addDirToVersions(dir, versions) {
6 | fs.readdirSync(dir).forEach(d => {
7 | if (d.indexOf('.') === 0) {
8 | return;
9 | }
10 | if (d.indexOf('@') === 0) {
11 | addDirToVersions(dir + '/' + d, versions);
12 | } else {
13 | let pkg = require(dir + '/' + d + '/package.json');
14 | versions[d] = pkg.version;
15 | }
16 | })
17 | }
18 |
19 | let aVersions = {};
20 | addDirToVersions(path.resolve(args.a + '/node_modules'), aVersions);
21 | let bVersions = {};
22 | addDirToVersions(path.resolve(args.b + '/node_modules'), bVersions);
23 |
24 | let keys = Object.keys(aVersions);
25 | for (let key in bVersions) {
26 | if (keys.indexOf(key) === -1) keys.push(key);
27 | }
28 |
29 | keys.forEach(key => {
30 | let v1 = aVersions[key];
31 | let v2 = bVersions[key];
32 | if (v1 !== v2) {
33 | console.log(key + '\t' + aVersions[key] + '\t' + bVersions[key]);
34 | }
35 | })
36 |
--------------------------------------------------------------------------------
/apps/chat/scripts/new-component.js:
--------------------------------------------------------------------------------
1 | const args = require('yargs').argv;
2 | const fs = require('fs');
3 |
4 | let componentCode = function(name, filename) {
5 | return `
6 | import {Component} from '@angular/core';
7 |
8 | @Component({
9 | selector: '${filename}',
10 | templateUrl: './${filename}.pug',
11 | })
12 | export class ${name}Component {
13 | constructor() {}
14 | }
15 | `.trim()
16 | }
17 |
18 | let viewCode = function(name) {
19 | return `
20 | h1 ${name}
21 | `.trim();
22 | }
23 |
24 | const APP_DIR = __dirname + '/../src/app/';
25 |
26 | const filename = args.name.toLowerCase().replace(/\s/g, '-');
27 | const componentName = args.name.replace(/\s/g, '');
28 | const componentDir = APP_DIR + filename + '/';
29 | const componentFile = componentDir + filename + '.component.ts';
30 | const viewFile = componentDir + filename + '.pug';
31 | const appFile = APP_DIR + 'app.module.ts';
32 |
33 | let component = componentCode(componentName, filename);
34 | let view = viewCode(args.name);
35 |
36 | fs.mkdirSync(componentDir);
37 | fs.writeFileSync(viewFile, view);
38 | fs.writeFileSync(componentFile, component);
39 |
40 | let app = fs.readFileSync(appFile, 'utf8');
41 | let lines = app.split('\n').reverse();
42 |
43 | let insertImportAt = lines.findIndex(l => l.match(/^import .* from '\.\/.*.component'/));
44 | lines.splice(insertImportAt, 0, `import {${componentName}Component} from './${filename}/${filename}.component'`);
45 |
46 | let insertDeclarationAt = lines.findIndex(l => l.match(/^\s+\w+Component,/));
47 | lines.splice(insertDeclarationAt, 0, ` ${componentName}Component,`)
48 |
49 | lines.reverse();
50 | fs.writeFileSync(appFile, lines.join('\n'));
51 |
--------------------------------------------------------------------------------
/apps/chat/scripts/new-service.js:
--------------------------------------------------------------------------------
1 | const args = require('yargs').argv;
2 | const fs = require('fs');
3 |
4 | let serviceCode = function(name, filename) {
5 | return `
6 | import {Injectable} from '@angular/core';
7 |
8 | @Injectable()
9 | export class ${name}Service {
10 | constructor() {}
11 | }
12 | `.trim()
13 | }
14 |
15 | const APP_DIR = __dirname + '/../src/app/';
16 |
17 | const filename = args.name.toLowerCase().replace(/\s/g, '-');
18 | const serviceName = args.name.replace(/\s/g, '');
19 | const serviceDir = APP_DIR + 'services/';
20 | const serviceFile = serviceDir + filename + '.service.ts';
21 | const appFile = APP_DIR + 'app.module.ts';
22 |
23 | let service = serviceCode(serviceName, filename);
24 |
25 | fs.writeFileSync(serviceFile, service);
26 |
27 | let app = fs.readFileSync(appFile, 'utf8');
28 | let lines = app.split('\n').reverse();
29 |
30 | let insertImportAt = lines.findIndex(l => l.match(/^import .* from '\.\/.*.service'/));
31 | lines.splice(insertImportAt, 0, `import {${serviceName}Service} from './services/${filename}.service'`);
32 |
33 | let insertDeclarationAt = lines.findIndex(l => l.match(/^\s+\w+Service,/));
34 | lines.splice(insertDeclarationAt, 0, ` ${serviceName}Service,`)
35 |
36 | lines.reverse();
37 | fs.writeFileSync(appFile, lines.join('\n'));
38 |
--------------------------------------------------------------------------------
/apps/chat/scripts/update-angular.sh:
--------------------------------------------------------------------------------
1 | npm i --save @angular/animations@latest @angular/router@latest @angular/common@latest @angular/compiler@latest @angular/core@latest @angular/forms@latest @angular/http@latest @angular/platform-browser@latest @angular/platform-browser-dynamic@latest @angular/platform-server@latest @angular/cli@latest @angular/compiler-cli@latest @angular/language-service@latest @nguniversal/express-engine@latest @nguniversal/module-map-ngfactory-loader@latest rxjs@latest
2 |
--------------------------------------------------------------------------------
/apps/chat/server.js:
--------------------------------------------------------------------------------
1 | let express = require('express');
2 | let app = express();
3 |
4 | const DIR = __dirname + '/dist/browser';
5 | const INDEX = require('fs').readFileSync(DIR + '/index.html');
6 |
7 | app.use(express.static(__dirname + '/dist/browser'));
8 | app.get('*', (req, res) => {
9 | res.end(INDEX);
10 | })
11 |
12 | app.listen(process.env.PORT || 4030);
13 |
--------------------------------------------------------------------------------
/apps/chat/server.ts:
--------------------------------------------------------------------------------
1 | import 'zone.js/dist/zone-node';
2 | import 'reflect-metadata';
3 | import { renderModuleFactory } from '@angular/platform-server';
4 | import { enableProdMode } from '@angular/core';
5 |
6 | import * as express from 'express';
7 | import { join } from 'path';
8 | import { readFileSync } from 'fs';
9 |
10 | // Faster server renders w/ Prod mode (dev mode never needed)
11 | enableProdMode();
12 |
13 | // Express server
14 | const app = express();
15 |
16 | const PORT = process.env.PORT || 4000;
17 | const DIST_FOLDER = join(process.cwd(), 'dist');
18 |
19 | // Our index.html we'll use as our template
20 | const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();
21 |
22 | // * NOTE :: leave this as require() since this file is built Dynamically from webpack
23 | const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');
24 |
25 | // Express Engine
26 | import { ngExpressEngine } from '@nguniversal/express-engine';
27 | // Import module map for lazy loading
28 | import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
29 |
30 | // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
31 | app.engine('html', ngExpressEngine({
32 | bootstrap: AppServerModuleNgFactory,
33 | providers: [
34 | provideModuleMap(LAZY_MODULE_MAP)
35 | ]
36 | }));
37 |
38 | app.set('view engine', 'html');
39 | app.set('views', join(DIST_FOLDER, 'browser'));
40 |
41 | /* - Example Express Rest API endpoints -
42 | app.get('/api/**', (req, res) => { });
43 | */
44 |
45 | // Server static files from /browser
46 | app.get('*.*', express.static(join(DIST_FOLDER, 'browser'), {
47 | maxAge: '1y'
48 | }));
49 |
50 | // ALl regular routes use the Universal engine
51 | app.get('*', (req, res) => {
52 | res.render('index', { req });
53 | });
54 |
55 | // Start up the Node server
56 | app.listen(PORT, () => {
57 | console.log(`Node Express server listening on http://localhost:${PORT}`);
58 | });
59 |
--------------------------------------------------------------------------------
/apps/chat/src/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/apps/chat/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | template: `
6 |
7 |
8 | `,
9 | })
10 | export class AppComponent {
11 | constructor() {
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/apps/chat/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { BrowserModule } from '@angular/platform-browser';
3 | import { RouterModule } from '@angular/router';
4 | import { FormsModule } from '@angular/forms';
5 | import { HttpModule } from '@angular/http';
6 | import {APP_BASE_HREF} from '@angular/common';
7 |
8 | import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
9 |
10 | import { appRoutes } from './app.routing';
11 | import { AppComponent } from './app.component';
12 | import { HomeComponent } from './home/home.component';
13 | import { NavbarComponent } from './navbar/navbar.component';
14 | import {LogInModalComponent} from './log-in-modal/log-in-modal.component'
15 | import {ChatComponent} from './chat/chat.component'
16 | import {RoomsComponent} from './rooms/rooms.component'
17 |
18 | import {PlatformService} from './services/platform.service';
19 | import {OneDBService} from './services/onedb.service'
20 |
21 | import { environment } from '../environments/environment';
22 |
23 | @NgModule({
24 | imports: [
25 | BrowserModule.withServerTransition({appId: 'my-app'}),
26 | RouterModule.forRoot(appRoutes),
27 | HttpModule,
28 | FormsModule,
29 | NgbModule.forRoot(),
30 | ],
31 | providers: [
32 | {provide: APP_BASE_HREF, useValue: environment.baseHref || '/'},
33 | PlatformService,
34 | OneDBService,
35 | ],
36 | declarations: [
37 | AppComponent,
38 | HomeComponent,
39 | NavbarComponent,
40 | LogInModalComponent,
41 | ChatComponent,
42 | RoomsComponent,
43 | ],
44 | bootstrap: [ AppComponent ],
45 | })
46 | export class AppModule { }
47 |
--------------------------------------------------------------------------------
/apps/chat/src/app/app.routing.ts:
--------------------------------------------------------------------------------
1 | import { Routes, RouterModule } from '@angular/router';
2 | import {HomeComponent} from './home/home.component';
3 | import {ChatComponent} from './chat/chat.component';
4 |
5 | export const appRoutes: Routes = [
6 | { path: '', component: HomeComponent },
7 | { path: 'chat/:chat_id', component: HomeComponent },
8 | { path: '**', redirectTo: '' },
9 | ];
10 |
11 |
--------------------------------------------------------------------------------
/apps/chat/src/app/app.server.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {ServerModule} from '@angular/platform-server';
3 | import {ModuleMapLoaderModule} from '@nguniversal/module-map-ngfactory-loader';
4 |
5 | import {AppModule} from './app.module';
6 | import {AppComponent} from './app.component';
7 |
8 | @NgModule({
9 | imports: [
10 | // The AppServerModule should import your AppModule followed
11 | // by the ServerModule from @angular/platform-server.
12 | AppModule,
13 | ServerModule,
14 | ModuleMapLoaderModule,
15 | ],
16 | // Since the bootstrapped component is not inherited from your
17 | // imported AppModule, it needs to be repeated here.
18 | bootstrap: [AppComponent],
19 | })
20 | export class AppServerModule {}
21 |
--------------------------------------------------------------------------------
/apps/chat/src/app/chat/chat.pug:
--------------------------------------------------------------------------------
1 | .alert.alert-danger(*ngIf="error") {{ error }}
2 | div(*ngIf="!chatID")
3 | h1 Welcome to OneChat!
4 | p.
5 | OneChat is a decentralized chat application. It is built on OneDB, which means
6 | you'll retain control over any messages and conversations you create here.
7 | p.
8 | To get started, pick a OneDB server to host your data (the default is one-db.datafire.io).
9 | When you post a message, the text will be stored on that server. When other users
10 | load the conversation, that's where the data will come from.
11 | p.
12 | At any point, you can use the Data Explorer to review,
13 | modify, and delete data you've created with this app.
14 | h1.text-center(*ngIf="loading")
15 | i.fa.fa-spin.fa-refresh
16 | div(*ngIf="chat && !loading")
17 | h1(*ngIf="!editingTitle")
18 | span {{ chat.title || chat.$.id }}
19 | a.btn.btn-warning.pull-right(*ngIf="acl?.owner === onedb.client.hosts.primary.user?.$.id", (click)="editingTitle = true")
20 | i.fa.fa-edit
21 | .form-group(*ngIf="editingTitle")
22 | .input-group
23 | input.input-lg.form-control(placeholder="Name this conversation...", [(ngModel)]="chat.title")
24 | .input-group-append
25 | button.btn.btn-success((click)="save()", [disabled]="saving")
26 | span(*ngIf="!saving") Save
27 | i.fa.fa-spin.fa-refresh(*ngIf="saving")
28 | .message-list(#messageList, [style.max-height]="maxChatHeight + 'px'")
29 | .text-center(*ngIf="hasEarlierMessages")
30 | button.btn.btn-link((click)="loadEarlierMessages()")
31 | span Load more messages
32 | i.fa.fa-right.fa-arrow-up
33 | .message(*ngFor="let message of messages")
34 | .info
35 | span {{ message.$.info.created_by }}
36 | span {{ prettyDate(message.$.info.created) }}
37 | i(*ngIf="message.$.info.created !== message.$.info.updated") (edited)
38 | div([innerHtml]="marked(message.message)")
39 | hr
40 | .form-group
41 | textarea.form-control(placeholder="Write a new message", [(ngModel)]="message", (keydown)="onKey($event)")
42 | .form-group
43 | button.btn.btn-lg.btn-success((click)="sendMessage()", [disabled]="sendingMessage")
44 | span(*ngIf="!sendingMessage") Send
45 | i.fa.fa-spin.fa-refresh(*ngIf="sendingMessage")
46 |
--------------------------------------------------------------------------------
/apps/chat/src/app/home/home.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | const SMALL_SIDEBAR_WIDTH = 72;
4 | const LARGE_SIDEBAR_WIDTH = 300;
5 |
6 | @Component({
7 | selector: 'home',
8 | templateUrl: './home.pug',
9 | styles: [`
10 | .content {
11 | width: 100%;
12 | position: absolute;
13 | top: 56px;
14 | bottom: 0px;
15 | }
16 | .sidebar, .main-content {
17 | padding: 15px;
18 | }
19 | .sidebar {
20 | position: absolute;
21 | left: 0;
22 | top: 0;
23 | bottom: 0;
24 | border-right: 1px solid #32334a;
25 | }
26 | .main-content {
27 | min-width: 300px;
28 | }
29 | `]
30 | })
31 | export class HomeComponent {
32 | public collapsed:boolean;
33 | public sidebarWidth:number;
34 |
35 | constructor() {
36 | if (typeof window !== 'undefined' && window.innerWidth < 600) {
37 | this.collapse();
38 | } else {
39 | this.expand();
40 | }
41 | }
42 |
43 | collapse() {
44 | this.collapsed = true;
45 | this.sidebarWidth = SMALL_SIDEBAR_WIDTH;
46 | }
47 |
48 | expand() {
49 | this.collapsed = false;
50 | this.sidebarWidth = LARGE_SIDEBAR_WIDTH;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/apps/chat/src/app/home/home.pug:
--------------------------------------------------------------------------------
1 | .content
2 | .sidebar([style.width]="sidebarWidth + 'px'")
3 | .form-group
4 | button.btn.btn-dark((click)="collapsed ? expand() : collapse()")
5 | i.fa([class.fa-bars]="collapsed", [class.fa-times]="!collapsed")
6 | rooms([hidden]="collapsed")
7 | .main-content([style.margin-left]="sidebarWidth + 'px'")
8 | chat
9 |
--------------------------------------------------------------------------------
/apps/chat/src/app/log-in-modal/log-in-modal.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, ViewChild} from '@angular/core';
2 | import {OneDBService} from '../services/onedb.service';
3 | import {NgbModal, ModalDismissReasons} from '@ng-bootstrap/ng-bootstrap';
4 | import {DomSanitizer, SafeHtml} from '@angular/platform-browser'
5 |
6 | @Component({
7 | selector: 'log-in-modal',
8 | templateUrl: './log-in-modal.pug',
9 | })
10 | export class LogInModalComponent {
11 | @ViewChild('content') content;
12 | formContent:SafeHtml;
13 | modalRef:any;
14 |
15 | constructor(
16 | private onedb:OneDBService,
17 | private modals: NgbModal,
18 | private sanitizer:DomSanitizer) {
19 | this.refreshForm();
20 | this.onedb.onLogin.subscribe(instance => {
21 | this.refreshForm();
22 | if (this.modalRef && instance.user) this.modalRef.close();
23 | })
24 | }
25 |
26 | open() {
27 | this.modalRef = this.modals.open(this.content);
28 | }
29 |
30 | refreshForm() {
31 | this.formContent = this.sanitizer.bypassSecurityTrustHtml(this.onedb.client.loginForm());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/apps/chat/src/app/log-in-modal/log-in-modal.pug:
--------------------------------------------------------------------------------
1 | ng-template(#content let-c="close" let-d="dismiss")
2 | .modal-header
3 | h4.modal-title
4 | span(*ngIf="!onedb.client.hosts.primary.user") Log In or Sign Up
5 | span(*ngIf="onedb.client.hosts.primary.user") Log Out or Switch Accounts
6 | button.close(type="button", class="close", aria-label="Close", (click)="d('Cross click')")
7 | span(aria-hidden="true") ×
8 | .modal-body
9 | p OneChat uses OneDB, so you get to decide where your data is stored.
10 | p.
11 | You can create a free account on one-db.datafire.io
12 |
13 | host your own instance
14 | , or choose another provider.
15 | div([innerHtml]="formContent")
16 |
--------------------------------------------------------------------------------
/apps/chat/src/app/navbar/navbar.component.ts:
--------------------------------------------------------------------------------
1 | import {ViewChild, Component} from '@angular/core';
2 | import {Router} from '@angular/router';
3 | import {OneDBService} from '../services/onedb.service';
4 |
5 | @Component({
6 | selector: 'navbar',
7 | templateUrl: './navbar.pug',
8 | styles: [`
9 | nav {
10 | display: block;
11 | }
12 | `]
13 | })
14 | export class NavbarComponent {
15 | @ViewChild('logInModal') logInModal;
16 | constructor(public router: Router, public onedb:OneDBService) {}
17 | }
18 |
--------------------------------------------------------------------------------
/apps/chat/src/app/navbar/navbar.pug:
--------------------------------------------------------------------------------
1 | log-in-modal(#logInModal)
2 | nav.navbar.navbar-expand-lg.navbar-dark.bg-dark
3 | a.navbar-brand(routerLink="/") OneChat
4 | .float-right
5 | ul.navbar-nav.ml-auto
6 | li
7 | a.nav-link((click)="logInModal.open()")
8 | i.fa.fa-left.fa-users
9 | span([ngSwitch]="!!onedb.client.hosts.primary.user")
10 | span(*ngSwitchCase="true")
11 | span.d-sm-none.d-md-inline-block {{onedb.client.hosts.primary.displayName}}
12 | span(*ngSwitchCase="false") Sign In
13 |
14 |
--------------------------------------------------------------------------------
/apps/chat/src/app/rooms/rooms.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, ViewChild} from '@angular/core';
2 | import {Router} from '@angular/router';
3 | import {OneDBService} from '../services/onedb.service';
4 |
5 | declare let window:any;
6 | declare let require:any;
7 |
8 | @Component({
9 | selector: 'rooms',
10 | templateUrl: './rooms.pug',
11 | styles: [`
12 | .btn-success {
13 | width: 100%;
14 | }
15 | `]
16 | })
17 | export class RoomsComponent {
18 | @ViewChild('logInModal') logInModal;
19 | listingChats:boolean;
20 | error:string;
21 | chatRoomName:string;
22 |
23 | userChats:any[];
24 | ownedChats:any[];
25 | publicChats:any[];
26 |
27 | constructor(public onedb:OneDBService, private router:Router) {
28 | this.onedb.onLogin.subscribe(instance => {
29 | if (instance === this.onedb.client.hosts.primary && instance.user) {
30 | this.listChats();
31 | }
32 | });
33 | if (this.onedb.client.hosts.primary.user) {
34 | this.listChats();
35 | }
36 | }
37 |
38 | async listChats() {
39 | if (this.listingChats) return setTimeout(this.listChats.bind(this), 100);
40 | this.listingChats = true;
41 | const userID = this.onedb.client.hosts.primary.user.$.id;
42 | this.publicChats = (await this.onedb.client.list('chat', 'conversation')).items;
43 | this.ownedChats = (await this.onedb.client.list('chat', 'conversation', {owner: userID})).items;
44 | let userMessages = await this.onedb.client.list('chat', 'message', {owner: userID});
45 | let chatIDs = [];
46 | for (let message of userMessages.items) {
47 | if (chatIDs.indexOf(message.conversationID) === -1) {
48 | chatIDs.push(message.conversationID);
49 | }
50 | }
51 | this.userChats = await Promise.all(chatIDs.map(id => this.onedb.client.get('chat', 'conversation', id)))
52 | this.listingChats = false;
53 | }
54 |
55 | async startChat() {
56 | this.error = null;
57 | let chatID = this.chatRoomName ? this.chatRoomName.replace(/\W+/g, '_') : undefined;
58 | try {
59 | const chat = {title: this.chatRoomName || ''};
60 | chatID = await this.onedb.client.create('chat', 'conversation', chatID, chat);
61 | } catch (e) {
62 | this.error = e.message;
63 | return;
64 | }
65 | this.router.navigate(['/chat', chatID])
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/apps/chat/src/app/rooms/rooms.pug:
--------------------------------------------------------------------------------
1 | log-in-modal(#logInModal)
2 | .alert.alert-danger(*ngIf="error") {{ error }}
3 | div(*ngIf="onedb.client.hosts.primary.user")
4 | form((submit)="startChat()")
5 | .form-group
6 | button.btn.btn-success(type="submit") Start a new chat
7 | hr
8 | mixin rooms(title, arr)
9 | h4(*ngIf=arr)= title
10 | p(*ngIf=arr + "&& !" + arr + ".length")
11 | i None found
12 | .chat(*ngFor="let chat of " + arr)
13 | a([routerLink]="['/chat', chat.$.id]") {{ chat.title || chat.$.id }}
14 | +rooms('Chats you own', 'ownedChats')
15 | hr
16 | +rooms('Chats you participate in', 'userChats')
17 | hr
18 | +rooms('Public chats', 'publicChats')
19 | div(*ngIf="!onedb.client.hosts.primary.user")
20 | p
21 | a((click)="logInModal.open()") Sign in to get started
22 |
--------------------------------------------------------------------------------
/apps/chat/src/app/services/onedb.service.ts:
--------------------------------------------------------------------------------
1 | import {Injectable, NgZone} from '@angular/core';
2 | import {BehaviorSubject} from 'rxjs';
3 |
4 | declare let window:any;
5 | declare let require:any;
6 | const Client = require('onedb-client').Client;
7 | const CORE_HOST = 'https://one-db.datafire.io';
8 |
9 | const STORAGE_KEY = 'onedb_auth';
10 |
11 | @Injectable()
12 | export class OneDBService {
13 | client:any;
14 | user:any;
15 |
16 | onLogin = new BehaviorSubject(null);
17 |
18 | constructor(private zone:NgZone) {
19 | window.onedbService = this;
20 | this.client = new Client({
21 | hosts: {
22 | core: {
23 | location: CORE_HOST,
24 | }
25 | },
26 | onLogin: user => {
27 | this.zone.run(_ => this.onLogin.next(user));
28 | },
29 | scope: ['chat:read', 'chat:create', 'chat:write', 'chat:delete', 'chat:modify_acl', 'chat:append'],
30 | });
31 | this.maybeRestore();
32 | this.onLogin.subscribe(user => {
33 | this.user = user;
34 | if (!window.localStorage) return
35 | const toStore = {
36 | hosts: this.client.hosts,
37 | };
38 | window.localStorage.setItem(STORAGE_KEY, JSON.stringify(toStore))
39 | })
40 | }
41 |
42 | async maybeRestore() {
43 | if (!window.localStorage) return;
44 | let existing:any = window.localStorage.getItem(STORAGE_KEY);
45 | if (!existing) return;
46 | existing = JSON.parse(existing);
47 | if (!existing || !existing.hosts) return;
48 | let hosts = Object.assign({}, existing.hosts, {core: {location: CORE_HOST}})
49 | await this.client.setHosts(hosts);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/apps/chat/src/app/services/platform.service.ts:
--------------------------------------------------------------------------------
1 | import { Inject, Injectable, PLATFORM_ID } from '@angular/core'
2 | import { isPlatformBrowser, isPlatformServer } from '@angular/common'
3 |
4 | @Injectable()
5 | export class PlatformService {
6 | constructor(@Inject(PLATFORM_ID) private platformId: any) { }
7 |
8 | public isBrowser(): boolean {
9 | return isPlatformBrowser(this.platformId)
10 | }
11 |
12 | public isServer(): boolean {
13 | return isPlatformServer(this.platformId)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/apps/chat/src/app/styles/app.scss:
--------------------------------------------------------------------------------
1 | html, body {
2 | height: 100%;
3 | }
4 |
5 | a {
6 | cursor: pointer;
7 | }
8 |
9 | nav {
10 | margin-bottom: 0px;
11 | }
12 |
13 | body {
14 | position: relative;
15 | }
16 |
17 | app > .container {
18 | padding-bottom: 72px;
19 | }
20 |
21 | footer {
22 | position: absolute;
23 | bottom: 0;
24 | left: 0;
25 | right: 0;
26 |
27 | background-color: #fff;
28 | padding-top: 20px;
29 | padding-bottom: 20px;
30 | }
31 |
32 | footer, footer a {
33 | color: #3E3F3A;
34 | }
35 |
36 | .fa-left {
37 | margin-right: 8px;
38 | }
39 | .fa-right {
40 | margin-left: 8px;
41 | }
42 |
43 | .btn-min-width {
44 | min-width: 100px;
45 | }
46 |
--------------------------------------------------------------------------------
/apps/chat/src/app/styles/styles.scss:
--------------------------------------------------------------------------------
1 | @import 'variables';
2 |
3 | @import '~bootstrap/scss/bootstrap';
4 |
5 | @import './app.scss';
6 |
7 |
--------------------------------------------------------------------------------
/apps/chat/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/chat/src/assets/.gitkeep
--------------------------------------------------------------------------------
/apps/chat/src/assets/img/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/chat/src/assets/img/Icon.png
--------------------------------------------------------------------------------
/apps/chat/src/assets/img/Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/chat/src/assets/img/Logo.png
--------------------------------------------------------------------------------
/apps/chat/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | baseHref: '/',
4 | };
5 |
--------------------------------------------------------------------------------
/apps/chat/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // The file contents for the current environment will overwrite these during build.
2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do
3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead.
4 | // The list of which env maps to which file can be found in `.angular-cli.json`.
5 |
6 | export const environment = {
7 | production: false,
8 | baseHref: '/',
9 | };
10 |
--------------------------------------------------------------------------------
/apps/chat/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/chat/src/favicon.ico
--------------------------------------------------------------------------------
/apps/chat/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | OneChat - a OneDB chat application
7 |
8 |
9 |
10 |
11 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/apps/chat/src/main.server.ts:
--------------------------------------------------------------------------------
1 | export { AppServerModule } from './app/app.server.module';
2 |
--------------------------------------------------------------------------------
/apps/chat/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | document.addEventListener('DOMContentLoaded', () => {
12 | platformBrowserDynamic().bootstrapModule(AppModule);
13 | });
14 |
--------------------------------------------------------------------------------
/apps/chat/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/
22 | // import 'core-js/es6/symbol';
23 | // import 'core-js/es6/object';
24 | // import 'core-js/es6/function';
25 | // import 'core-js/es6/parse-int';
26 | // import 'core-js/es6/parse-float';
27 | // import 'core-js/es6/number';
28 | // import 'core-js/es6/math';
29 | // import 'core-js/es6/string';
30 | // import 'core-js/es6/date';
31 | // import 'core-js/es6/array';
32 | // import 'core-js/es6/regexp';
33 | // import 'core-js/es6/map';
34 | // import 'core-js/es6/weak-map';
35 | // import 'core-js/es6/set';
36 |
37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
38 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
39 |
40 | /** Evergreen browsers require these. **/
41 | import 'core-js/es6/reflect';
42 | import 'core-js/es7/reflect';
43 | import 'babel-polyfill';
44 |
45 | /**
46 | * Required to support Web Animations `@angular/animation`.
47 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
48 | **/
49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
50 |
51 |
52 |
53 | /***************************************************************************************************
54 | * Zone JS is required by Angular itself.
55 | */
56 | import 'zone.js/dist/zone'; // Included with Angular CLI.
57 |
58 |
59 |
60 | /***************************************************************************************************
61 | * APPLICATION IMPORTS
62 | */
63 |
64 | /**
65 | * Date, currency, decimal and percent pipes.
66 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
67 | */
68 | // import 'intl'; // Run `npm install --save intl`.
69 | /**
70 | * Need to import at least one locale-data with intl.
71 | */
72 | // import 'intl/locale-data/jsonp/en';
73 |
--------------------------------------------------------------------------------
/apps/chat/src/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "baseUrl": "./",
6 | "module": "es2015",
7 | "types": []
8 | },
9 | "exclude": [
10 | "test.ts",
11 | "**/*.spec.ts"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/apps/chat/src/tsconfig.server.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "baseUrl": "./",
6 | // Set the module format to "commonjs":
7 | "module": "commonjs",
8 | "types": []
9 | },
10 | "exclude": [
11 | "test.ts",
12 | "**/*.spec.ts"
13 | ],
14 | // Add "angularCompilerOptions" with the AppServerModule you wrote
15 | // set as the "entryModule".
16 | "angularCompilerOptions": {
17 | "entryModule": "app/app.server.module#AppServerModule"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/apps/chat/static.paths.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | '/',
3 | ];
4 |
--------------------------------------------------------------------------------
/apps/chat/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "outDir": "./dist/out-tsc",
5 | "sourceMap": true,
6 | "declaration": false,
7 | "moduleResolution": "node",
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "target": "es5",
11 | "typeRoots": [
12 | "node_modules/@types",
13 | "typings.d.ts"
14 | ],
15 | "lib": [
16 | "es2017",
17 | "dom"
18 | ],
19 | "types": ["node"],
20 | "module": "es2015",
21 | "baseUrl": "./"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/apps/chat/types/conversation.acl.json:
--------------------------------------------------------------------------------
1 | {
2 | "allow": {
3 | "read": ["_all"],
4 | "write": ["_owner"]
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/apps/chat/types/conversation.schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "object",
3 | "additionalProperties": false,
4 | "properties": {
5 | "title": {"type": "string", "maxLength": 500},
6 | "description": {"type": "string", "maxLength": 10000},
7 | "banned": {
8 | "type": "array",
9 | "items": {"type": "string"}
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/apps/chat/types/message.acl.json:
--------------------------------------------------------------------------------
1 | {
2 | "allow": {
3 | "read": ["_all"]
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/apps/chat/types/message.schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "object",
3 | "additionalProperties": false,
4 | "required": ["conversationID", "message"],
5 | "properties": {
6 | "conversationID": {"type": "string"},
7 | "message": {"type": "string", "maxLength": 10000}
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/apps/chat/webpack.cli-additions.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const commonCliConfig = 'node_modules/@angular/cli/models/webpack-configs/common.js';
3 | const addition_rules = `
4 | { test: /\.(pug|jade)$/, loader: 'apply-loader' },
5 | { test: /\.(pug|jade)$/,
6 | loader: 'pug-loader',
7 | query: { doctype: 'html', plugins: [require('pug-plugin-ng')] },
8 | }, {
9 | test: /\.json$/,
10 | use: [{
11 | loader: 'json-loader',
12 | }]
13 | },
14 | {
15 | test: /\.js$/,
16 | use: [{
17 | loader: 'babel-loader',
18 | options: {
19 | presets: ['env'],
20 | }
21 | }],
22 | },
23 | { test: /\.md$/, use: [{ loader: 'raw-loader' }, { loader: 'markdown-loader', }] }
24 | ,`; // make sure to have this last comma
25 |
26 | fs.readFile(commonCliConfig, (err, data) => {
27 |
28 | if (err) { throw err; }
29 |
30 | const configText = data.toString();
31 | // make sure we don't include it (if we've already done this)
32 | if (configText.indexOf(addition_rules) > -1) { return; }
33 |
34 | console.log('-- Inserting additional webpack rules to node_modules CLI -- ');
35 |
36 | const position = configText.indexOf('rules: [') + 8;
37 | const output = [configText.slice(0, position), addition_rules, configText.slice(position)].join('');
38 | const file = fs.openSync(commonCliConfig, 'r+');
39 |
40 | fs.writeFile(file, output);
41 | fs.close(file);
42 | });
43 |
44 |
--------------------------------------------------------------------------------
/apps/chat/webpack.server.config.js:
--------------------------------------------------------------------------------
1 | // Work around for https://github.com/angular/angular-cli/issues/7200
2 |
3 | const path = require('path');
4 | const webpack = require('webpack');
5 |
6 | module.exports = {
7 | entry: {
8 | // This is our Express server for Dynamic universal
9 | server: './server.ts',
10 | // This is an example of Static prerendering (generative)
11 | prerender: './prerender.ts'
12 | },
13 | target: 'node',
14 | resolve: { extensions: ['.ts', '.js'] },
15 | // Make sure we include all node_modules etc
16 | externals: [/(node_modules|main\..*\.js)/,],
17 | output: {
18 | // Puts the output at the root of the dist folder
19 | path: path.join(__dirname, 'dist'),
20 | filename: '[name].js'
21 | },
22 | module: {
23 | rules: [
24 | { test: /\.ts$/, use: {loader: 'ts-loader', options: {}} }
25 | ]
26 | },
27 | plugins: [
28 | new webpack.ContextReplacementPlugin(
29 | // fixes WARNING Critical dependency: the request of a dependency is an expression
30 | /(.+)?angular(\\|\/)core(.+)?/,
31 | path.join(__dirname, 'src'), // location of your src
32 | {} // a map of your routes
33 | ),
34 | new webpack.ContextReplacementPlugin(
35 | // fixes WARNING Critical dependency: the request of a dependency is an expression
36 | /(.+)?express(\\|\/)(.+)?/,
37 | path.join(__dirname, 'src'),
38 | {}
39 | )
40 | ]
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/apps/data-explorer/.gitignore:
--------------------------------------------------------------------------------
1 | docs/
2 |
3 | .idea
4 | .DS_Store
5 | morgan.log
6 |
7 | # Built #
8 | /__build__/
9 | /__server_build__/
10 | /node_modules/
11 | /typings/
12 | /tsd_typings/
13 | /dist-server/
14 | /compiled/
15 |
16 | # Node #
17 | npm-debug.log
18 | /npm-debug.log.*
19 |
20 | # Webpack #
21 | webpack.records.json
22 |
23 | # Angular #
24 | *.ngfactory.ts
25 | *.css.shim.ts
26 | *.ngsummary.json
27 | *.metadata.json
28 | *.shim.ngstyle.ts
29 |
--------------------------------------------------------------------------------
/apps/data-explorer/README.md:
--------------------------------------------------------------------------------
1 | # Angluar 6.0 Template Project
2 | I use this template as a starter for any new Angular projects.
3 |
4 | Check out [the demo](https://bobby-brennan.github.io/angular6-template)
5 |
6 | #### Features
7 | * Angular Universal (prerendering)
8 | * [Pug](https://pugjs.org) templates instead of HTML
9 | * Bootstrap Sass
10 | * Font Awesome
11 | * Angular HTML5 Router
12 | * Standard navbar/body layout
13 |
14 | ## Running the Demo
15 |
16 | #### Install
17 |
18 | ```
19 | npm install
20 | ```
21 |
22 | #### Run (development mode)
23 | Start the server on port 3000:
24 |
25 | ```
26 | npm run start
27 | ```
28 |
29 |
30 | #### Build (production)
31 | Build everything and put it in the `dist/` folder:
32 |
33 | ```
34 | npm run build
35 | ```
36 |
37 | Or build for GitHub pages by copying `dist/browser` to `docs/`.
38 | Be sure to change the settings in your repo to point GitHub pages to
39 | the `docs/` folder on the `master` branch.
40 |
41 | ## Customizing
42 |
43 | ### Base href
44 | The app uses the base href `/` for development builds, and `/angular6-template`
45 | for production builds (to accomodate GitHub pages, which uses the repository
46 | name in the URL's path). You will probably want to change the base href in
47 | `./src/environments/environment.prod.ts`.
48 |
49 | ### Prerendering
50 | Prerendering is a performance optimization - your page's HTML is generated
51 | at build time, so the user sees a near-instant load of the page, while Angular
52 | loads in the background.
53 |
54 | In this build, only the homepage is prerendered - you can add other routes
55 | by editing `./static.paths.ts`.
56 |
57 | ## New Components
58 | A helper script for creating new components is in `./scripts/new-component.js`.
59 |
60 | ```
61 | node ./scripts/new-component.js --name "Widget Viewer"
62 | ```
63 |
--------------------------------------------------------------------------------
/apps/data-explorer/ng-add-pug-loader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Adds the pug-loader inside Angular CLI's webpack config, if not there yet.
3 | * @see https://github.com/danguilherme/ng-cli-pug-loader
4 | */
5 | const fs = require('fs');
6 | const commonCliConfig = 'node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/common.js';
7 | const pugRule = '{ test: /.pug$/, use: [ { loader: "apply-loader" }, { loader: "pug-loader" } ] },';
8 |
9 | fs.readFile(commonCliConfig, (err, data) => {
10 | if (err) { throw err; }
11 |
12 | const configText = data.toString();
13 | // make sure we don't add the rule if it already exists
14 | if (configText.indexOf(pugRule) > -1) { return; }
15 |
16 | // Insert the pug webpack rule
17 | const position = configText.indexOf('rules: [') + 8;
18 | const output = [configText.slice(0, position), pugRule, configText.slice(position)].join('');
19 | const file = fs.openSync(commonCliConfig, 'r+');
20 | fs.writeFile(file, output);
21 | fs.close(file);
22 | });
23 |
--------------------------------------------------------------------------------
/apps/data-explorer/prerender.ts:
--------------------------------------------------------------------------------
1 | // Load zone.js for the server.
2 | import 'zone.js/dist/zone-node';
3 | import 'reflect-metadata';
4 | import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
5 | import { join } from 'path';
6 | import { chdir } from 'process';
7 |
8 | import { enableProdMode } from '@angular/core';
9 | // Faster server renders w/ Prod mode (dev mode never needed)
10 | enableProdMode();
11 |
12 | // Express Engine
13 | import { ngExpressEngine } from '@nguniversal/express-engine';
14 | // Import module map for lazy loading
15 | import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
16 |
17 | import { renderModuleFactory } from '@angular/platform-server';
18 |
19 | // * NOTE :: leave this as require() since this file is built Dynamically from webpack
20 | const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');
21 |
22 | // Get route paths to prerender only static pages
23 | const PATHS = require('./static.paths');
24 |
25 | const BROWSER_FOLDER = join(process.cwd(), 'browser');
26 |
27 | // Load the index.html file containing referances to your application bundle.
28 | const index = readFileSync(join('browser', 'index.html'), 'utf8');
29 |
30 | let prom = Promise.resolve();
31 |
32 | // Iterate each route path
33 | PATHS.forEach(function (route) {
34 | // Changes current directory to ./dist/browser
35 | chdir(BROWSER_FOLDER);
36 |
37 | // Creates new directories (if not exists) and changes current directory for the nested one
38 | route.split('/').filter(val => val !== '')
39 | .forEach(function (dir) {
40 | if (!existsSync(dir)) {
41 | mkdirSync(dir);
42 | }
43 | chdir(dir);
44 | });
45 |
46 | // Writes rendered HTML to index.html, replacing the file if it already exists.
47 | prom = prom.then(_ => renderModuleFactory(AppServerModuleNgFactory, {
48 | document: index,
49 | url: route,
50 | extraProviders: [
51 | provideModuleMap(LAZY_MODULE_MAP)
52 | ]
53 | })).then(html => writeFileSync(join(BROWSER_FOLDER, route, 'index.html'), html));
54 | });
55 |
--------------------------------------------------------------------------------
/apps/data-explorer/scripts/compare-versions.js:
--------------------------------------------------------------------------------
1 | let fs = require('fs');
2 | let path = require('path');
3 | let args = require('yargs').argv;
4 |
5 | function addDirToVersions(dir, versions) {
6 | fs.readdirSync(dir).forEach(d => {
7 | if (d.indexOf('.') === 0) {
8 | return;
9 | }
10 | if (d.indexOf('@') === 0) {
11 | addDirToVersions(dir + '/' + d, versions);
12 | } else {
13 | let pkg = require(dir + '/' + d + '/package.json');
14 | versions[d] = pkg.version;
15 | }
16 | })
17 | }
18 |
19 | let aVersions = {};
20 | addDirToVersions(path.resolve(args.a + '/node_modules'), aVersions);
21 | let bVersions = {};
22 | addDirToVersions(path.resolve(args.b + '/node_modules'), bVersions);
23 |
24 | let keys = Object.keys(aVersions);
25 | for (let key in bVersions) {
26 | if (keys.indexOf(key) === -1) keys.push(key);
27 | }
28 |
29 | keys.forEach(key => {
30 | let v1 = aVersions[key];
31 | let v2 = bVersions[key];
32 | if (v1 !== v2) {
33 | console.log(key + '\t' + aVersions[key] + '\t' + bVersions[key]);
34 | }
35 | })
36 |
--------------------------------------------------------------------------------
/apps/data-explorer/scripts/new-component.js:
--------------------------------------------------------------------------------
1 | const args = require('yargs').argv;
2 | const fs = require('fs');
3 |
4 | let componentCode = function(name, filename) {
5 | return `
6 | import {Component} from '@angular/core';
7 |
8 | @Component({
9 | selector: '${filename}',
10 | templateUrl: './${filename}.pug',
11 | })
12 | export class ${name}Component {
13 | constructor() {}
14 | }
15 | `.trim()
16 | }
17 |
18 | let viewCode = function(name) {
19 | return `
20 | h1 ${name}
21 | `.trim();
22 | }
23 |
24 | const APP_DIR = __dirname + '/../src/app/';
25 |
26 | const filename = args.name.toLowerCase().replace(/\s/g, '-');
27 | const componentName = args.name.replace(/\s/g, '');
28 | const componentDir = APP_DIR + filename + '/';
29 | const componentFile = componentDir + filename + '.component.ts';
30 | const viewFile = componentDir + filename + '.pug';
31 | const appFile = APP_DIR + 'app.module.ts';
32 |
33 | let component = componentCode(componentName, filename);
34 | let view = viewCode(args.name);
35 |
36 | fs.mkdirSync(componentDir);
37 | fs.writeFileSync(viewFile, view);
38 | fs.writeFileSync(componentFile, component);
39 |
40 | let app = fs.readFileSync(appFile, 'utf8');
41 | let lines = app.split('\n').reverse();
42 |
43 | let insertImportAt = lines.findIndex(l => l.match(/^import .* from '\.\/.*.component'/));
44 | lines.splice(insertImportAt, 0, `import {${componentName}Component} from './${filename}/${filename}.component'`);
45 |
46 | let insertDeclarationAt = lines.findIndex(l => l.match(/^\s+\w+Component,/));
47 | lines.splice(insertDeclarationAt, 0, ` ${componentName}Component,`)
48 |
49 | lines.reverse();
50 | fs.writeFileSync(appFile, lines.join('\n'));
51 |
--------------------------------------------------------------------------------
/apps/data-explorer/scripts/new-service.js:
--------------------------------------------------------------------------------
1 | const args = require('yargs').argv;
2 | const fs = require('fs');
3 |
4 | let serviceCode = function(name, filename) {
5 | return `
6 | import {Injectable} from '@angular/core';
7 |
8 | @Injectable()
9 | export class ${name}Service {
10 | constructor() {}
11 | }
12 | `.trim()
13 | }
14 |
15 | const APP_DIR = __dirname + '/../src/app/';
16 |
17 | const filename = args.name.toLowerCase().replace(/\s/g, '-');
18 | const serviceName = args.name.replace(/\s/g, '');
19 | const serviceDir = APP_DIR + 'services/';
20 | const serviceFile = serviceDir + filename + '.service.ts';
21 | const appFile = APP_DIR + 'app.module.ts';
22 |
23 | let service = serviceCode(serviceName, filename);
24 |
25 | fs.writeFileSync(serviceFile, service);
26 |
27 | let app = fs.readFileSync(appFile, 'utf8');
28 | let lines = app.split('\n').reverse();
29 |
30 | let insertImportAt = lines.findIndex(l => l.match(/^import .* from '\.\/.*.service'/));
31 | lines.splice(insertImportAt, 0, `import {${serviceName}Service} from './services/${filename}.service'`);
32 |
33 | let insertDeclarationAt = lines.findIndex(l => l.match(/^\s+\w+Service,/));
34 | lines.splice(insertDeclarationAt, 0, ` ${serviceName}Service,`)
35 |
36 | lines.reverse();
37 | fs.writeFileSync(appFile, lines.join('\n'));
38 |
--------------------------------------------------------------------------------
/apps/data-explorer/scripts/update-angular.sh:
--------------------------------------------------------------------------------
1 | npm i --save @angular/animations@latest @angular/router@latest @angular/common@latest @angular/compiler@latest @angular/core@latest @angular/forms@latest @angular/http@latest @angular/platform-browser@latest @angular/platform-browser-dynamic@latest @angular/platform-server@latest @angular/cli@latest @angular/compiler-cli@latest @angular/language-service@latest @nguniversal/express-engine@latest @nguniversal/module-map-ngfactory-loader@latest rxjs@latest
2 |
--------------------------------------------------------------------------------
/apps/data-explorer/server.js:
--------------------------------------------------------------------------------
1 | let express = require('express');
2 | let app = express();
3 |
4 | const DIR = __dirname + '/dist/browser';
5 | const INDEX = require('fs').readFileSync(DIR + '/index.html');
6 |
7 | app.use(express.static(__dirname + '/dist/browser'));
8 | app.get('*', (req, res) => {
9 | res.end(INDEX);
10 | })
11 |
12 | app.listen(process.env.PORT || 4020);
13 |
--------------------------------------------------------------------------------
/apps/data-explorer/server.ts:
--------------------------------------------------------------------------------
1 | import 'zone.js/dist/zone-node';
2 | import 'reflect-metadata';
3 | import { renderModuleFactory } from '@angular/platform-server';
4 | import { enableProdMode } from '@angular/core';
5 |
6 | import * as express from 'express';
7 | import { join } from 'path';
8 | import { readFileSync } from 'fs';
9 |
10 | // Faster server renders w/ Prod mode (dev mode never needed)
11 | enableProdMode();
12 |
13 | // Express server
14 | const app = express();
15 |
16 | const PORT = process.env.PORT || 4000;
17 | const DIST_FOLDER = join(process.cwd(), 'dist');
18 |
19 | // Our index.html we'll use as our template
20 | const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();
21 |
22 | // * NOTE :: leave this as require() since this file is built Dynamically from webpack
23 | const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');
24 |
25 | // Express Engine
26 | import { ngExpressEngine } from '@nguniversal/express-engine';
27 | // Import module map for lazy loading
28 | import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
29 |
30 | // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
31 | app.engine('html', ngExpressEngine({
32 | bootstrap: AppServerModuleNgFactory,
33 | providers: [
34 | provideModuleMap(LAZY_MODULE_MAP)
35 | ]
36 | }));
37 |
38 | app.set('view engine', 'html');
39 | app.set('views', join(DIST_FOLDER, 'browser'));
40 |
41 | /* - Example Express Rest API endpoints -
42 | app.get('/api/**', (req, res) => { });
43 | */
44 |
45 | // Server static files from /browser
46 | app.get('*.*', express.static(join(DIST_FOLDER, 'browser'), {
47 | maxAge: '1y'
48 | }));
49 |
50 | // ALl regular routes use the Universal engine
51 | app.get('*', (req, res) => {
52 | res.render('index', { req });
53 | });
54 |
55 | // Start up the Node server
56 | app.listen(PORT, () => {
57 | console.log(`Node Express server listening on http://localhost:${PORT}`);
58 | });
59 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | template: `
6 |
7 |
8 |
9 |
10 | `,
11 | })
12 | export class AppComponent {
13 | constructor() {
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { BrowserModule } from '@angular/platform-browser';
3 | import { RouterModule } from '@angular/router';
4 | import { FormsModule } from '@angular/forms';
5 | import { HttpModule } from '@angular/http';
6 | import {APP_BASE_HREF} from '@angular/common';
7 |
8 | import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
9 |
10 | import { appRoutes } from './app.routing';
11 | import { AppComponent } from './app.component';
12 | import { HomeComponent } from './home/home.component';
13 | import { NavbarComponent } from './navbar/navbar.component';
14 | import {LogInModalComponent} from './log-in-modal/log-in-modal.component'
15 | import {NamespaceComponent} from './namespace/namespace.component'
16 | import {ItemComponent} from './item/item.component'
17 | import {JSONSchemaEditorComponent} from './json-schema/json-schema-editor.component'
18 | import {SchemaLabelComponent} from './json-schema/schema-label.component'
19 |
20 | import {PlatformService} from './services/platform.service';
21 | import {OneDBService} from './services/onedb.service'
22 |
23 | import { environment } from '../environments/environment';
24 |
25 | @NgModule({
26 | imports: [
27 | BrowserModule.withServerTransition({appId: 'my-app'}),
28 | RouterModule.forRoot(appRoutes),
29 | HttpModule,
30 | FormsModule,
31 | NgbModule.forRoot(),
32 | ],
33 | providers: [
34 | {provide: APP_BASE_HREF, useValue: environment.baseHref || '/'},
35 | PlatformService,
36 | OneDBService,
37 | ],
38 | declarations: [
39 | AppComponent,
40 | HomeComponent,
41 | NavbarComponent,
42 | LogInModalComponent,
43 | NamespaceComponent,
44 | ItemComponent,
45 | JSONSchemaEditorComponent,
46 | SchemaLabelComponent,
47 | ],
48 | bootstrap: [ AppComponent ],
49 | })
50 | export class AppModule { }
51 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/app.routing.ts:
--------------------------------------------------------------------------------
1 | import { Routes, RouterModule } from '@angular/router';
2 | import {HomeComponent} from './home/home.component';
3 | import {NamespaceComponent} from './namespace/namespace.component'
4 | import {ItemComponent} from './item/item.component'
5 |
6 | export const appRoutes: Routes = [
7 | { path: '', component: HomeComponent },
8 | { path: 'data/:namespace', component: NamespaceComponent },
9 | { path: 'data/:namespace/:type', component: ItemComponent },
10 | { path: 'data/:namespace/:type/:item_id', component: ItemComponent },
11 | { path: '**', redirectTo: '' },
12 | ];
13 |
14 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/app.server.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {ServerModule} from '@angular/platform-server';
3 | import {ModuleMapLoaderModule} from '@nguniversal/module-map-ngfactory-loader';
4 |
5 | import {AppModule} from './app.module';
6 | import {AppComponent} from './app.component';
7 |
8 | @NgModule({
9 | imports: [
10 | // The AppServerModule should import your AppModule followed
11 | // by the ServerModule from @angular/platform-server.
12 | AppModule,
13 | ServerModule,
14 | ModuleMapLoaderModule,
15 | ],
16 | // Since the bootstrapped component is not inherited from your
17 | // imported AppModule, it needs to be repeated here.
18 | bootstrap: [AppComponent],
19 | })
20 | export class AppServerModule {}
21 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/home/home.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, ViewChild} from '@angular/core';
2 | import {Router} from '@angular/router';
3 | import {OneDBService} from '../services/onedb.service';
4 |
5 | declare let window:any;
6 | declare let require:any;
7 |
8 | @Component({
9 | selector: 'home',
10 | templateUrl: './home.pug',
11 | styles: [`
12 | ul {
13 | padding-left: 0px;
14 | list-style: none;
15 | }
16 | .col {
17 | min-width: 250px;
18 | }
19 | `]
20 | })
21 | export class HomeComponent {
22 | @ViewChild('logInModal') logInModal;
23 | error:string;
24 | usage:any;
25 | allNamespaces:any[];
26 |
27 | constructor(public onedb:OneDBService) {
28 | this.loadNamespaces();
29 | onedb.onLogin.subscribe(instance => {
30 | this.loadUsage();
31 | })
32 | }
33 |
34 | async loadUsage() {
35 | if (!this.onedb.client.hosts.primary.user) {
36 | this.usage = null;
37 | return;
38 | }
39 | this.usage = await this.onedb.client.get('system', 'usage', this.onedb.client.hosts.primary.user.$.id);
40 |
41 | // TODO: remove this block - just for a few legacy users
42 | if (!this.usage && this.onedb.client.hosts.primary.user.namespaces) {
43 | this.usage = this.onedb.client.hosts.primary.user;
44 | }
45 | }
46 |
47 | async loadNamespaces() {
48 | this.allNamespaces = (await this.onedb.client.list('core', 'namespace')).items;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/home/home.pug:
--------------------------------------------------------------------------------
1 | log-in-modal(#logInModal)
2 | h1 OneDB Data Explorer
3 | p.
4 | This site allows you to browse, modify, and delete data on your OneDB accounts.
5 | p.
6 | Below are the datasets currently available in OneDB.
7 | Developers may be interested in
8 |
9 | creating a new dataset
10 | .
11 | .row
12 | .col
13 | h4 My Data
14 | div(*ngIf="!usage || !usage.namespaces?.length")
15 | p(*ngIf="!onedb.client.hosts.primary.user")
16 | a((click)="logInModal.open()" href="javascript:void(0)") Sign in to see your data
17 | p(*ngIf="onedb.client.hosts.primary.user")
18 | i You haven't added any data to this OneDB instance yet.
19 | div(*ngIf="usage && usage.namespaces?.length")
20 | p Below are the datasets that contain information you've created while using OneDB apps.
21 | ul
22 | li(*ngFor="let namespace of usage.namespaces")
23 | a([routerLink]="['/data', namespace]") {{namespace}}
24 | .col
25 | h4 All Data
26 | p Below are all the datasets currently available on OneDB.
27 | //.form-group
28 | .input-group
29 | input.form-control(type="text", [(ngModel)]="query")
30 | .input-group-append
31 | a.btn.btn-success([routerLink]="['/data', query]") View Data
32 | div(*ngIf="allNamespaces")
33 | ul
34 | li(*ngFor="let namespace of allNamespaces")
35 | a([routerLink]="['/data', namespace.$.id]") {{ namespace.$.id }}
36 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/item/item.pug:
--------------------------------------------------------------------------------
1 | h1
2 | a([routerLink]="['/data', namespace]") {{ namespace }}
3 | span /{{ type }}/{{item_id || '<new>' }}
4 | div(*ngIf="item")
5 | ul.info(*ngIf="info")
6 | li
7 | span.info-label Owned by
8 | span.info-data {{ acl.owner }}
9 | li
10 | span.info-label Created by
11 | span.info-data {{ info.created_by }}
12 | li
13 | span.info-label Created on
14 | span.info-data {{ datestr(info.created) }}
15 | li
16 | span.info-label Last updated
17 | span.info-data {{ datestr(info.updated) }}
18 | .form-group
19 | h2(*ngIf="loading")
20 | i.fa.fa-spin.fa-refresh
21 | .btn-toolbar(*ngIf="!loading")
22 | button.btn.btn-success.mr-3((click)="wrapAsync('save')")
23 | span(*ngIf="item_id") Save
24 | span(*ngIf="!item_id") Create
25 | i.fa.fa-right.fa-cloud-upload
26 | button.btn.btn-danger(*ngIf="item_id", (click)="confirmDelete = true")
27 | span Delete
28 | i.fa.fa-right.fa-trash
29 | .alert.alert-danger(*ngIf="error")
30 | span {{error}}
31 | .alert.alert-warning(*ngIf="confirmDelete")
32 | p Are you sure? This action cannot be undone.
33 | .btn-toolbar
34 | a.btn.btn-danger((click)="wrapAsync('delete')") Delete this item
35 | a.btn.btn-link((click)="confirmDelete = false") Cancel
36 | .form-group(*ngIf="acl")
37 | a((click)="expandACL = !expandACL" href="javascript:void(0)")
38 | i.fa.fa-left([class.fa-plus-square-o]="!expandACL", [class.fa-minus-square-o]="expandACL")
39 | span {{ expandACL ? 'Hide' : 'Show' }} Access Control
40 | div(*ngIf="expandACL")
41 | p Use these fields to control who has access to read, write, append to, and delete your data.
42 | ul
43 | li The allow field is a whitelist of users who can perform the given action.
44 | li The disallow field is a blacklist of users who cannot perform the given action.
45 | li The modify field is a whitelist of users who can change the allow and disallow fields.
46 | li The user _owner refers to the owner of this item.
47 | li The user _all refers to everyone.
48 | .form-group(*ngFor="let accessType of ACCESS_TYPES")
49 | h4.text-capitalize {{ accessType }}
50 | .row
51 | .col(*ngFor="let aclType of ACL_TYPES")
52 | label.text-capitalize {{ aclType }}
53 | input.form-control(
54 | [value]="(acl[aclType][accessType] || []).join(', ')",
55 | (input)="setACLString($event.target.value, aclType, accessType)")
56 | a((click)="toggleEditMode()", href="javascript:void(0)")
57 | span {{ editMode === 'json' ? 'View form editor' : 'Edit as JSON' }}
58 | json-schema-editor(
59 | *ngIf="editMode === 'form'",
60 | [schema]="schema",
61 | [refBase]="schema",
62 | [depth]="3",
63 | [value]="item")
64 | textarea.form-control(*ngIf="editMode === 'json'", rows="20", [(ngModel)]="itemString")
65 |
66 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/json-schema/schema-label.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, Input, Output, EventEmitter, ViewChild} from '@angular/core';
2 |
3 | import {util} from './util';
4 |
5 | @Component({
6 | selector: 'schema-label',
7 | templateUrl: './schema-label.pug',
8 | styles: [`
9 | .type-choice.dropdown {
10 | display: inline-block;
11 | margin-left: 5px;
12 | }
13 | `]
14 | })
15 | export class SchemaLabelComponent {
16 | @Input('schema') inputSchema:any;
17 | schema:any;
18 | @Input() refBase;
19 | @Input() label:string;
20 | @Input() required:boolean;
21 | @Input() expand:boolean;
22 | @Input() showRemove:boolean = false;
23 | @Input() showExpand:boolean;
24 | @Output() typeChange = new EventEmitter();
25 | @Output() expandChange = new EventEmitter();
26 | @Output() schemaChange = new EventEmitter();
27 | @Output() onRemoved = new EventEmitter();
28 | @ViewChild('descriptionTooltip') descriptionTooltip;
29 | type:string;
30 | typeChoices:string[];
31 | description:string;
32 |
33 | constructor() {}
34 |
35 | clickRemove() {
36 | this.onRemoved.emit();
37 | }
38 |
39 | ngOnChanges() {
40 | if (!this.inputSchema) return
41 | this.setSchema(this.inputSchema);
42 | if (this.expand) this.maybeResolveRef();
43 | }
44 |
45 | setSchema(schema) {
46 | if (schema === this.schema) return;
47 | this.schema = schema;
48 | let resolved = schema.$ref ? util.resolveReference(schema.$ref, this.refBase) : schema;
49 | this.label = this.label || resolved.title;
50 | this.description = resolved.description;
51 | this.typeChoices = null;
52 | let type = util.getTypeForSchema(resolved, this.refBase);
53 | if (Array.isArray(type)) {
54 | if (resolved.type.length > 1) {
55 | this.typeChoices = resolved.type;
56 | }
57 | this.type = type.filter(t => t !== 'null')[0] || type[0];
58 | } else {
59 | this.type = type;
60 | }
61 | if (this.type !== 'object' && this.type !== 'array' && !this.expand) {
62 | this.toggleExpand();
63 | }
64 | setTimeout(() => {
65 | this.typeChange.emit(this.type);
66 | this.schemaChange.emit(this.schema);
67 | });
68 | }
69 |
70 | toggleExpand() {
71 | this.expand = !this.expand;
72 | this.maybeResolveRef();
73 | this.expandChange.emit(this.expand);
74 | }
75 |
76 | maybeResolveRef() {
77 | if (!this.schema.$ref) return;
78 | this.setSchema(util.resolveReference(this.schema.$ref, this.refBase));
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/json-schema/schema-label.pug:
--------------------------------------------------------------------------------
1 | label.monospace
2 | a(*ngIf="showRemove", (click)="clickRemove()")
3 | i.fa.fa-left.fa-times.text-danger
4 | span.text-primary(*ngIf="required") *
5 | span {{label}}
6 | span(*ngIf="label") :
7 | span.hl-key(*ngIf="!typeChoices") {{type}}
8 | .type-choice.dropdown(*ngIf="typeChoices", ngbDropdown)
9 | a.btn.btn-xs.btn-default.dropdown-toggle(data-toggle="dropdown", ngbDropdownToggle)
10 | span {{type}}
11 | .dropdown-menu(ngbDropdownMenu)
12 | a.dropdown-item(*ngFor="let t of typeChoices", (click)="type = t; typeChange.emit(type)")
13 | span {{t}}
14 | a(*ngIf="(showExpand && (type === 'object' || type === 'array')) || schema.$ref",
15 | (click)="toggleExpand()")
16 | i.fa.fa-right([class.fa-plus-square-o]="!expand", [class.fa-minus-square-o]="expand")
17 | p.text-danger(*ngIf="!schema") Unknown schema
18 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/log-in-modal/log-in-modal.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, ViewChild} from '@angular/core';
2 | import {OneDBService} from '../services/onedb.service';
3 | import {NgbModal, ModalDismissReasons} from '@ng-bootstrap/ng-bootstrap';
4 | import {DomSanitizer, SafeHtml} from '@angular/platform-browser'
5 |
6 | @Component({
7 | selector: 'log-in-modal',
8 | templateUrl: './log-in-modal.pug',
9 | })
10 | export class LogInModalComponent {
11 | @ViewChild('content') content;
12 | formContent:SafeHtml;
13 | modalRef:any;
14 |
15 | constructor(
16 | private onedb:OneDBService,
17 | private modals: NgbModal,
18 | private sanitizer:DomSanitizer) {
19 | this.refreshForm();
20 | this.onedb.onLogin.subscribe(instance => {
21 | this.refreshForm();
22 | if (this.modalRef && instance.user) this.modalRef.close();
23 | })
24 | }
25 |
26 | open() {
27 | this.modalRef = this.modals.open(this.content);
28 | }
29 |
30 | refreshForm() {
31 | this.formContent = this.sanitizer.bypassSecurityTrustHtml(this.onedb.client.loginForm());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/log-in-modal/log-in-modal.pug:
--------------------------------------------------------------------------------
1 | ng-template(#content let-c="close" let-d="dismiss")
2 | .modal-header
3 | h4.modal-title
4 | span(*ngIf="!onedb.client.hosts.primary.user") Log In or Sign Up
5 | span(*ngIf="onedb.client.hosts.primary.user") Log Out or Switch Accounts
6 | button.close(type="button", class="close", aria-label="Close", (click)="d('Cross click')")
7 | span(aria-hidden="true") ×
8 | .modal-body
9 | div([innerHtml]="formContent")
10 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/namespace/namespace.pug:
--------------------------------------------------------------------------------
1 | .alert.alert-danger(*ngIf="error")
2 | p {{error}}
3 | p Check the namespace ID and refresh the page to try again.
4 | div(*ngIf="namespace")
5 | h1 {{ namespace.$.id }}
6 | .form-group.view-all-form-group
7 | label Viewing:
8 | .btn-group
9 | button.btn.btn-dark([class.active]="!viewAllData", (click)="setViewAllData(false)")
10 | span My Data
11 | button.btn.btn-dark([class.active]="viewAllData", (click)="setViewAllData(true)")
12 | span All Data
13 | p
14 | span Below is all the data
15 | b {{ !viewAllData ? 'you own ' : 'you have permission to see'}}
16 | span in the {{ namespace.$.id }} namespace
17 | .row
18 | .col.namespace(*ngFor="let type of types; let idx = index;")
19 | h2 {{ type.id }}
20 | a.btn.btn-success([routerLink]="['/data', namespace.$.id, type.id]")
21 | i.fa.fa-left.fa-plus
22 | span Create a new {{ type.id }}
23 | div([ngSwitch]="!viewAllData && !onedb.client.hosts.primary.user")
24 | div(*ngSwitchCase="true")
25 | p Please sign in to view your data
26 | div(*ngSwitchCase="false")
27 | p(*ngIf="!data[type.id]")
28 | i.fa.fa-spin.fa-refresh
29 | p(*ngIf="data[type.id] && !data[type.id].items.length")
30 | span No items found
31 | table(*ngIf="data[type.id] && data[type.id].items.length")
32 | thead
33 | tr
34 | th ID
35 | th(*ngIf="viewAllData") Owner
36 | th(*ngFor="let prop of type.properties") {{ prop }}
37 | tbody
38 | tr.item(*ngFor="let item of data[type.id].items")
39 | td
40 | .cell-content
41 | a([routerLink]="['/data', namespace.$.id, type.id, item.$.id]")
42 | span {{ item.$.id }}
43 | td(*ngIf="viewAllData")
44 | .cell-content
45 | span {{ item.$.owner }}
46 | td(*ngFor="let prop of type.properties")
47 | .cell-content
48 | span {{ item[prop] }}
49 | ul.pagination(*ngIf="data[type.id] && data[type.id].pages")
50 | li.page-item(*ngFor="let page of data[type.id].pages", [class.active]="page.active")
51 | button.page-link((click)="goToPage(type.id, page.skip)", [disabled]="page.disabled") {{ page.label }}
52 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/navbar/navbar.component.ts:
--------------------------------------------------------------------------------
1 | import {ViewChild, Component} from '@angular/core';
2 | import {Router} from '@angular/router';
3 | import {OneDBService} from '../services/onedb.service';
4 |
5 | @Component({
6 | selector: 'navbar',
7 | templateUrl: './navbar.pug',
8 | })
9 | export class NavbarComponent {
10 | @ViewChild('logInModal') logInModal;
11 | constructor(public router: Router, public onedb:OneDBService) {}
12 | }
13 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/navbar/navbar.pug:
--------------------------------------------------------------------------------
1 | log-in-modal(#logInModal)
2 | nav.navbar.navbar-expand-lg.navbar-dark.bg-dark
3 | .container
4 | a.navbar-brand(routerLink="/") OneDB Data Explorer
5 | div
6 | ul.navbar-nav.ml-auto
7 | li
8 | a.nav-link((click)="logInModal.open()")
9 | i.fa.fa-left.fa-users
10 | span([ngSwitch]="!!onedb.client.hosts.primary.user")
11 | span(*ngSwitchCase="true")
12 | span {{onedb.client.hosts.primary.displayName}}
13 | span(*ngSwitchCase="false") Sign In
14 |
15 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/services/onedb.service.ts:
--------------------------------------------------------------------------------
1 | import {Injectable, NgZone} from '@angular/core';
2 | import {BehaviorSubject} from 'rxjs';
3 |
4 | declare let window:any;
5 | declare let require:any;
6 | const Client = require('onedb-client').Client;
7 | const CORE_HOST = 'https://one-db.datafire.io';
8 |
9 | const STORAGE_KEY = 'onedb_auth';
10 |
11 | @Injectable()
12 | export class OneDBService {
13 | client:any;
14 |
15 | onLogin = new BehaviorSubject(null);
16 |
17 | constructor(private zone:NgZone) {
18 | window.onedbService = this;
19 | this.client = new Client({
20 | hosts: {
21 | core: {
22 | location: CORE_HOST,
23 | }
24 | },
25 | onLogin: instance => {
26 | this.zone.run(_ => this.onLogin.next(instance));
27 | },
28 | });
29 | this.maybeRestore();
30 | this.onLogin.subscribe(instance => {
31 | if (!window.localStorage) return
32 | const toStore = {
33 | hosts: this.client.hosts,
34 | };
35 | window.localStorage.setItem(STORAGE_KEY, JSON.stringify(toStore))
36 | })
37 | }
38 |
39 | async maybeRestore() {
40 | if (!window.localStorage) return;
41 | let existing:any = window.localStorage.getItem(STORAGE_KEY);
42 | if (!existing) return;
43 | existing = JSON.parse(existing);
44 | if (!existing || !existing.hosts) return;
45 | let hosts = Object.assign({}, existing.hosts, {core: {location: CORE_HOST}})
46 | await this.client.setHosts(hosts);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/services/platform.service.ts:
--------------------------------------------------------------------------------
1 | import { Inject, Injectable, PLATFORM_ID } from '@angular/core'
2 | import { isPlatformBrowser, isPlatformServer } from '@angular/common'
3 |
4 | @Injectable()
5 | export class PlatformService {
6 | constructor(@Inject(PLATFORM_ID) private platformId: any) { }
7 |
8 | public isBrowser(): boolean {
9 | return isPlatformBrowser(this.platformId)
10 | }
11 |
12 | public isServer(): boolean {
13 | return isPlatformServer(this.platformId)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/styles/app.scss:
--------------------------------------------------------------------------------
1 | body {
2 | padding-bottom: 50px;
3 | }
4 |
5 | a {
6 | cursor: pointer;
7 | }
8 |
9 | .navbar {
10 | border-radius: 0px;
11 | margin-bottom: 30px;
12 | }
13 |
14 | body {
15 | position: relative;
16 | }
17 |
18 | app > .container {
19 | padding-bottom: 72px;
20 | }
21 |
22 | footer {
23 | position: absolute;
24 | bottom: 0;
25 | left: 0;
26 | right: 0;
27 |
28 | background-color: #fff;
29 | padding-top: 20px;
30 | padding-bottom: 20px;
31 | }
32 |
33 | footer, footer a {
34 | color: #3E3F3A;
35 | }
36 |
37 | .fa-left {
38 | margin-right: 8px;
39 | }
40 | .fa-right {
41 | margin-left: 8px;
42 | }
43 |
44 | .btn-min-width {
45 | min-width: 100px;
46 | }
47 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/app/styles/styles.scss:
--------------------------------------------------------------------------------
1 | @import 'variables';
2 |
3 | @import '~bootstrap/scss/bootstrap';
4 |
5 | @import './app.scss';
6 | @import './bootswatch.scss';
7 |
8 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/data-explorer/src/assets/.gitkeep
--------------------------------------------------------------------------------
/apps/data-explorer/src/assets/img/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/data-explorer/src/assets/img/Icon.png
--------------------------------------------------------------------------------
/apps/data-explorer/src/assets/img/Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/data-explorer/src/assets/img/Logo.png
--------------------------------------------------------------------------------
/apps/data-explorer/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | baseHref: '/',
4 | };
5 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // The file contents for the current environment will overwrite these during build.
2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do
3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead.
4 | // The list of which env maps to which file can be found in `.angular-cli.json`.
5 |
6 | export const environment = {
7 | production: false,
8 | baseHref: '/',
9 | };
10 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/data-explorer/src/favicon.ico
--------------------------------------------------------------------------------
/apps/data-explorer/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | OneDB Data Explorer
7 |
8 |
9 |
10 |
11 |
12 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/main.server.ts:
--------------------------------------------------------------------------------
1 | export { AppServerModule } from './app/app.server.module';
2 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | document.addEventListener('DOMContentLoaded', () => {
12 | platformBrowserDynamic().bootstrapModule(AppModule);
13 | });
14 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/
22 | // import 'core-js/es6/symbol';
23 | // import 'core-js/es6/object';
24 | // import 'core-js/es6/function';
25 | // import 'core-js/es6/parse-int';
26 | // import 'core-js/es6/parse-float';
27 | // import 'core-js/es6/number';
28 | // import 'core-js/es6/math';
29 | // import 'core-js/es6/string';
30 | // import 'core-js/es6/date';
31 | // import 'core-js/es6/array';
32 | // import 'core-js/es6/regexp';
33 | // import 'core-js/es6/map';
34 | // import 'core-js/es6/weak-map';
35 | // import 'core-js/es6/set';
36 |
37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
38 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
39 |
40 | /** Evergreen browsers require these. **/
41 | import 'core-js/es6/reflect';
42 | import 'core-js/es7/reflect';
43 | import 'babel-polyfill';
44 |
45 | /**
46 | * Required to support Web Animations `@angular/animation`.
47 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
48 | **/
49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
50 |
51 |
52 |
53 | /***************************************************************************************************
54 | * Zone JS is required by Angular itself.
55 | */
56 | import 'zone.js/dist/zone'; // Included with Angular CLI.
57 |
58 |
59 |
60 | /***************************************************************************************************
61 | * APPLICATION IMPORTS
62 | */
63 |
64 | /**
65 | * Date, currency, decimal and percent pipes.
66 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
67 | */
68 | // import 'intl'; // Run `npm install --save intl`.
69 | /**
70 | * Need to import at least one locale-data with intl.
71 | */
72 | // import 'intl/locale-data/jsonp/en';
73 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "baseUrl": "./",
6 | "module": "es2015",
7 | "types": []
8 | },
9 | "exclude": [
10 | "test.ts",
11 | "**/*.spec.ts"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/apps/data-explorer/src/tsconfig.server.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "baseUrl": "./",
6 | // Set the module format to "commonjs":
7 | "module": "commonjs",
8 | "types": []
9 | },
10 | "exclude": [
11 | "test.ts",
12 | "**/*.spec.ts"
13 | ],
14 | // Add "angularCompilerOptions" with the AppServerModule you wrote
15 | // set as the "entryModule".
16 | "angularCompilerOptions": {
17 | "entryModule": "app/app.server.module#AppServerModule"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/apps/data-explorer/static.paths.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | '/',
3 | ];
4 |
--------------------------------------------------------------------------------
/apps/data-explorer/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "outDir": "./dist/out-tsc",
5 | "sourceMap": true,
6 | "declaration": false,
7 | "moduleResolution": "node",
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "target": "es5",
11 | "typeRoots": [
12 | "node_modules/@types",
13 | "typings.d.ts"
14 | ],
15 | "lib": [
16 | "es2017",
17 | "dom"
18 | ],
19 | "types": ["node"],
20 | "module": "es2015",
21 | "baseUrl": "./"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/apps/data-explorer/webpack.cli-additions.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const commonCliConfig = 'node_modules/@angular/cli/models/webpack-configs/common.js';
3 | const addition_rules = `
4 | { test: /\.(pug|jade)$/, loader: 'apply-loader' },
5 | { test: /\.(pug|jade)$/,
6 | loader: 'pug-loader',
7 | query: { doctype: 'html', plugins: [require('pug-plugin-ng')] },
8 | }, {
9 | test: /\.json$/,
10 | use: [{
11 | loader: 'json-loader',
12 | }]
13 | },
14 | {
15 | test: /\.js$/,
16 | use: [{
17 | loader: 'babel-loader',
18 | options: {
19 | presets: ['env'],
20 | }
21 | }],
22 | },
23 | { test: /\.md$/, use: [{ loader: 'raw-loader' }, { loader: 'markdown-loader', }] }
24 | ,`; // make sure to have this last comma
25 |
26 | fs.readFile(commonCliConfig, (err, data) => {
27 |
28 | if (err) { throw err; }
29 |
30 | const configText = data.toString();
31 | // make sure we don't include it (if we've already done this)
32 | if (configText.indexOf(addition_rules) > -1) { return; }
33 |
34 | console.log('-- Inserting additional webpack rules to node_modules CLI -- ');
35 |
36 | const position = configText.indexOf('rules: [') + 8;
37 | const output = [configText.slice(0, position), addition_rules, configText.slice(position)].join('');
38 | const file = fs.openSync(commonCliConfig, 'r+');
39 |
40 | fs.writeFile(file, output);
41 | fs.close(file);
42 | });
43 |
44 |
--------------------------------------------------------------------------------
/apps/data-explorer/webpack.server.config.js:
--------------------------------------------------------------------------------
1 | // Work around for https://github.com/angular/angular-cli/issues/7200
2 |
3 | const path = require('path');
4 | const webpack = require('webpack');
5 |
6 | module.exports = {
7 | entry: {
8 | // This is our Express server for Dynamic universal
9 | server: './server.ts',
10 | // This is an example of Static prerendering (generative)
11 | prerender: './prerender.ts'
12 | },
13 | target: 'node',
14 | resolve: { extensions: ['.ts', '.js'] },
15 | // Make sure we include all node_modules etc
16 | externals: [/(node_modules|main\..*\.js)/,],
17 | output: {
18 | // Puts the output at the root of the dist folder
19 | path: path.join(__dirname, 'dist'),
20 | filename: '[name].js'
21 | },
22 | module: {
23 | rules: [
24 | { test: /\.ts$/, use: {loader: 'ts-loader', options: {}} }
25 | ]
26 | },
27 | plugins: [
28 | new webpack.ContextReplacementPlugin(
29 | // fixes WARNING Critical dependency: the request of a dependency is an expression
30 | /(.+)?angular(\\|\/)core(.+)?/,
31 | path.join(__dirname, 'src'), // location of your src
32 | {} // a map of your routes
33 | ),
34 | new webpack.ContextReplacementPlugin(
35 | // fixes WARNING Critical dependency: the request of a dependency is an expression
36 | /(.+)?express(\\|\/)(.+)?/,
37 | path.join(__dirname, 'src'),
38 | {}
39 | )
40 | ]
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/apps/minimal/README.md:
--------------------------------------------------------------------------------
1 | # OneDB minimal app
2 |
3 | This app contains two pages:
4 | * index.html allows you to set your status
5 | * viewer.html allows you to see all status updates
6 |
7 | Additionally, the schemas for the `status` namespace are contained in the directory `./types`.
8 |
--------------------------------------------------------------------------------
/apps/minimal/types/status.acl.json:
--------------------------------------------------------------------------------
1 | {
2 | "allow": {
3 | "read": ["_all"]
4 | }
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/apps/minimal/types/status.schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "object",
3 | "properties": {
4 | "status": {
5 | "type": "string",
6 | "maxLength": 280,
7 | "minLength": 1
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/apps/minimal/viewer.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 | Latest status updates
14 |
15 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/apps/todo/.gitignore:
--------------------------------------------------------------------------------
1 | docs/
2 |
3 | .idea
4 | .DS_Store
5 | morgan.log
6 |
7 | # Built #
8 | /__build__/
9 | /__server_build__/
10 | /node_modules/
11 | /typings/
12 | /tsd_typings/
13 | /dist-server/
14 | /compiled/
15 |
16 | # Node #
17 | npm-debug.log
18 | /npm-debug.log.*
19 |
20 | # Webpack #
21 | webpack.records.json
22 |
23 | # Angular #
24 | *.ngfactory.ts
25 | *.css.shim.ts
26 | *.ngsummary.json
27 | *.metadata.json
28 | *.shim.ngstyle.ts
29 |
--------------------------------------------------------------------------------
/apps/todo/README.md:
--------------------------------------------------------------------------------
1 | # Angluar 6.0 Template Project
2 | I use this template as a starter for any new Angular projects.
3 |
4 | Check out [the demo](https://bobby-brennan.github.io/angular6-template)
5 |
6 | #### Features
7 | * Angular Universal (prerendering)
8 | * [Pug](https://pugjs.org) templates instead of HTML
9 | * Bootstrap Sass
10 | * Font Awesome
11 | * Angular HTML5 Router
12 | * Standard navbar/body layout
13 |
14 | ## Running the Demo
15 |
16 | #### Install
17 |
18 | ```
19 | npm install
20 | ```
21 |
22 | #### Run (development mode)
23 | Start the server on port 3000:
24 |
25 | ```
26 | npm run start
27 | ```
28 |
29 |
30 | #### Build (production)
31 | Build everything and put it in the `dist/` folder:
32 |
33 | ```
34 | npm run build
35 | ```
36 |
37 | Or build for GitHub pages by copying `dist/browser` to `docs/`.
38 | Be sure to change the settings in your repo to point GitHub pages to
39 | the `docs/` folder on the `master` branch.
40 |
41 | ## Customizing
42 |
43 | ### Base href
44 | The app uses the base href `/` for development builds, and `/angular6-template`
45 | for production builds (to accomodate GitHub pages, which uses the repository
46 | name in the URL's path). You will probably want to change the base href in
47 | `./src/environments/environment.prod.ts`.
48 |
49 | ### Prerendering
50 | Prerendering is a performance optimization - your page's HTML is generated
51 | at build time, so the user sees a near-instant load of the page, while Angular
52 | loads in the background.
53 |
54 | In this build, only the homepage is prerendered - you can add other routes
55 | by editing `./static.paths.ts`.
56 |
57 | ## New Components
58 | A helper script for creating new components is in `./scripts/new-component.js`.
59 |
60 | ```
61 | node ./scripts/new-component.js --name "Widget Viewer"
62 | ```
63 |
--------------------------------------------------------------------------------
/apps/todo/ng-add-pug-loader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Adds the pug-loader inside Angular CLI's webpack config, if not there yet.
3 | * @see https://github.com/danguilherme/ng-cli-pug-loader
4 | */
5 | const fs = require('fs');
6 | const commonCliConfig = 'node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/common.js';
7 | const pugRule = '{ test: /.pug$/, use: [ { loader: "apply-loader" }, { loader: "pug-loader" } ] },';
8 |
9 | fs.readFile(commonCliConfig, (err, data) => {
10 | if (err) { throw err; }
11 |
12 | const configText = data.toString();
13 | // make sure we don't add the rule if it already exists
14 | if (configText.indexOf(pugRule) > -1) { return; }
15 |
16 | // Insert the pug webpack rule
17 | const position = configText.indexOf('rules: [') + 8;
18 | const output = [configText.slice(0, position), pugRule, configText.slice(position)].join('');
19 | const file = fs.openSync(commonCliConfig, 'r+');
20 | fs.writeFile(file, output);
21 | fs.close(file);
22 | });
23 |
--------------------------------------------------------------------------------
/apps/todo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular4-template",
3 | "version": "0.0.0",
4 | "license": "MIT",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/bobby-brennan/angular4-template.git"
8 | },
9 | "scripts": {
10 | "ng": "ng",
11 | "start": "ng serve --port 3000 --host 0.0.0.0",
12 | "clean": "rm -rf dist",
13 | "build": "npm run clean && npm run build:static",
14 | "build:gh-pages": "npm run build && rm -rf ./docs && cp -r ./dist/browser ./docs",
15 | "build:client": "ng build browser --prod",
16 | "build:server": "ng run browser:server",
17 | "build:static": "npm run build:client && npm run build:server && npm run webpack:server",
18 | "build:prerender": "npm run build:client && npm run build:server && npm run webpack:server && npm run prerender",
19 | "build:dynamic": "npm run build:client && npm run build:server && npm run webpack:server",
20 | "webpack:server": "webpack --config webpack.server.config.js --progress --colors --mode development",
21 | "prerender": "cd dist && node prerender",
22 | "serve:static": "cd dist/browser && http-server",
23 | "serve:dynamic": "node dist/server",
24 | "postinstall": "node ./ng-add-pug-loader.js"
25 | },
26 | "private": true,
27 | "dependencies": {
28 | "@angular/animations": "^6.1.0",
29 | "@angular/common": "^6.1.0",
30 | "@angular/compiler": "^6.1.0",
31 | "@angular/core": "^6.1.0",
32 | "@angular/forms": "^6.1.0",
33 | "@angular/http": "^6.1.0",
34 | "@angular/platform-browser": "^6.1.0",
35 | "@angular/platform-browser-dynamic": "^6.1.0",
36 | "@angular/platform-server": "^6.1.0",
37 | "@angular/router": "^6.1.0",
38 | "@ng-bootstrap/ng-bootstrap": "^2.2.0",
39 | "@nguniversal/express-engine": "^6.0.0",
40 | "@nguniversal/module-map-ngfactory-loader": "^6.0.0",
41 | "bootstrap": "^4.1.3",
42 | "core-js": "^2.4.1",
43 | "express": "^4.16.3",
44 | "marked": "^0.4.0",
45 | "ng-cli-pug-loader": "^0.1.3",
46 | "ngx-markdown": "^6.1.0",
47 | "rxjs": "^6.2.2",
48 | "zone.js": "^0.8.14"
49 | },
50 | "devDependencies": {
51 | "@angular-devkit/build-angular": "~0.7.0",
52 | "@angular/cli": "^6.1.1",
53 | "@angular/compiler-cli": "^6.1.0",
54 | "@angular/language-service": "^6.1.0",
55 | "@types/node": "^10.5.3",
56 | "apply-loader": "^2.0.0",
57 | "babel-core": "^6.26.0",
58 | "babel-loader": "^7.1.2",
59 | "babel-polyfill": "^6.26.0",
60 | "babel-preset-env": "^1.6.1",
61 | "cpy-cli": "^1.0.1",
62 | "font-awesome": "^4.7.0",
63 | "http-server": "^0.10.0",
64 | "jquery": "^3.2.1",
65 | "json-loader": "^0.5.7",
66 | "markdown-loader": "^2.0.1",
67 | "onedb-client": "0.0.3",
68 | "pug": "^2.0.3",
69 | "pug-html-loader": "^1.1.5",
70 | "pug-loader": "^2.4.0",
71 | "pug-plugin-ng": "0.0.2",
72 | "reflect-metadata": "^0.1.10",
73 | "ts-loader": "^4.4.2",
74 | "typescript": "^2.9.2",
75 | "webpack-cli": "^3.1.0"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/apps/todo/prerender.ts:
--------------------------------------------------------------------------------
1 | // Load zone.js for the server.
2 | import 'zone.js/dist/zone-node';
3 | import 'reflect-metadata';
4 | import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
5 | import { join } from 'path';
6 | import { chdir } from 'process';
7 |
8 | import { enableProdMode } from '@angular/core';
9 | // Faster server renders w/ Prod mode (dev mode never needed)
10 | enableProdMode();
11 |
12 | // Express Engine
13 | import { ngExpressEngine } from '@nguniversal/express-engine';
14 | // Import module map for lazy loading
15 | import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
16 |
17 | import { renderModuleFactory } from '@angular/platform-server';
18 |
19 | // * NOTE :: leave this as require() since this file is built Dynamically from webpack
20 | const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');
21 |
22 | // Get route paths to prerender only static pages
23 | const PATHS = require('./static.paths');
24 |
25 | const BROWSER_FOLDER = join(process.cwd(), 'browser');
26 |
27 | // Load the index.html file containing referances to your application bundle.
28 | const index = readFileSync(join('browser', 'index.html'), 'utf8');
29 |
30 | let prom = Promise.resolve();
31 |
32 | // Iterate each route path
33 | PATHS.forEach(function (route) {
34 | // Changes current directory to ./dist/browser
35 | chdir(BROWSER_FOLDER);
36 |
37 | // Creates new directories (if not exists) and changes current directory for the nested one
38 | route.split('/').filter(val => val !== '')
39 | .forEach(function (dir) {
40 | if (!existsSync(dir)) {
41 | mkdirSync(dir);
42 | }
43 | chdir(dir);
44 | });
45 |
46 | // Writes rendered HTML to index.html, replacing the file if it already exists.
47 | prom = prom.then(_ => renderModuleFactory(AppServerModuleNgFactory, {
48 | document: index,
49 | url: route,
50 | extraProviders: [
51 | provideModuleMap(LAZY_MODULE_MAP)
52 | ]
53 | })).then(html => writeFileSync(join(BROWSER_FOLDER, route, 'index.html'), html));
54 | });
55 |
--------------------------------------------------------------------------------
/apps/todo/scripts/compare-versions.js:
--------------------------------------------------------------------------------
1 | let fs = require('fs');
2 | let path = require('path');
3 | let args = require('yargs').argv;
4 |
5 | function addDirToVersions(dir, versions) {
6 | fs.readdirSync(dir).forEach(d => {
7 | if (d.indexOf('.') === 0) {
8 | return;
9 | }
10 | if (d.indexOf('@') === 0) {
11 | addDirToVersions(dir + '/' + d, versions);
12 | } else {
13 | let pkg = require(dir + '/' + d + '/package.json');
14 | versions[d] = pkg.version;
15 | }
16 | })
17 | }
18 |
19 | let aVersions = {};
20 | addDirToVersions(path.resolve(args.a + '/node_modules'), aVersions);
21 | let bVersions = {};
22 | addDirToVersions(path.resolve(args.b + '/node_modules'), bVersions);
23 |
24 | let keys = Object.keys(aVersions);
25 | for (let key in bVersions) {
26 | if (keys.indexOf(key) === -1) keys.push(key);
27 | }
28 |
29 | keys.forEach(key => {
30 | let v1 = aVersions[key];
31 | let v2 = bVersions[key];
32 | if (v1 !== v2) {
33 | console.log(key + '\t' + aVersions[key] + '\t' + bVersions[key]);
34 | }
35 | })
36 |
--------------------------------------------------------------------------------
/apps/todo/scripts/new-component.js:
--------------------------------------------------------------------------------
1 | const args = require('yargs').argv;
2 | const fs = require('fs');
3 |
4 | let componentCode = function(name, filename) {
5 | return `
6 | import {Component} from '@angular/core';
7 |
8 | @Component({
9 | selector: '${filename}',
10 | templateUrl: './${filename}.pug',
11 | })
12 | export class ${name}Component {
13 | constructor() {}
14 | }
15 | `.trim()
16 | }
17 |
18 | let viewCode = function(name) {
19 | return `
20 | h1 ${name}
21 | `.trim();
22 | }
23 |
24 | const APP_DIR = __dirname + '/../src/app/';
25 |
26 | const filename = args.name.toLowerCase().replace(/\s/g, '-');
27 | const componentName = args.name.replace(/\s/g, '');
28 | const componentDir = APP_DIR + filename + '/';
29 | const componentFile = componentDir + filename + '.component.ts';
30 | const viewFile = componentDir + filename + '.pug';
31 | const appFile = APP_DIR + 'app.module.ts';
32 |
33 | let component = componentCode(componentName, filename);
34 | let view = viewCode(args.name);
35 |
36 | fs.mkdirSync(componentDir);
37 | fs.writeFileSync(viewFile, view);
38 | fs.writeFileSync(componentFile, component);
39 |
40 | let app = fs.readFileSync(appFile, 'utf8');
41 | let lines = app.split('\n').reverse();
42 |
43 | let insertImportAt = lines.findIndex(l => l.match(/^import .* from '\.\/.*.component'/));
44 | lines.splice(insertImportAt, 0, `import {${componentName}Component} from './${filename}/${filename}.component'`);
45 |
46 | let insertDeclarationAt = lines.findIndex(l => l.match(/^\s+\w+Component,/));
47 | lines.splice(insertDeclarationAt, 0, ` ${componentName}Component,`)
48 |
49 | lines.reverse();
50 | fs.writeFileSync(appFile, lines.join('\n'));
51 |
--------------------------------------------------------------------------------
/apps/todo/scripts/new-service.js:
--------------------------------------------------------------------------------
1 | const args = require('yargs').argv;
2 | const fs = require('fs');
3 |
4 | let serviceCode = function(name, filename) {
5 | return `
6 | import {Injectable} from '@angular/core';
7 |
8 | @Injectable()
9 | export class ${name}Service {
10 | constructor() {}
11 | }
12 | `.trim()
13 | }
14 |
15 | const APP_DIR = __dirname + '/../src/app/';
16 |
17 | const filename = args.name.toLowerCase().replace(/\s/g, '-');
18 | const serviceName = args.name.replace(/\s/g, '');
19 | const serviceDir = APP_DIR + 'services/';
20 | const serviceFile = serviceDir + filename + '.service.ts';
21 | const appFile = APP_DIR + 'app.module.ts';
22 |
23 | let service = serviceCode(serviceName, filename);
24 |
25 | fs.writeFileSync(serviceFile, service);
26 |
27 | let app = fs.readFileSync(appFile, 'utf8');
28 | let lines = app.split('\n').reverse();
29 |
30 | let insertImportAt = lines.findIndex(l => l.match(/^import .* from '\.\/.*.service'/));
31 | lines.splice(insertImportAt, 0, `import {${serviceName}Service} from './services/${filename}.service'`);
32 |
33 | let insertDeclarationAt = lines.findIndex(l => l.match(/^\s+\w+Service,/));
34 | lines.splice(insertDeclarationAt, 0, ` ${serviceName}Service,`)
35 |
36 | lines.reverse();
37 | fs.writeFileSync(appFile, lines.join('\n'));
38 |
--------------------------------------------------------------------------------
/apps/todo/scripts/update-angular.sh:
--------------------------------------------------------------------------------
1 | npm i --save @angular/animations@latest @angular/router@latest @angular/common@latest @angular/compiler@latest @angular/core@latest @angular/forms@latest @angular/http@latest @angular/platform-browser@latest @angular/platform-browser-dynamic@latest @angular/platform-server@latest @angular/cli@latest @angular/compiler-cli@latest @angular/language-service@latest @nguniversal/express-engine@latest @nguniversal/module-map-ngfactory-loader@latest rxjs@latest
2 |
--------------------------------------------------------------------------------
/apps/todo/server.js:
--------------------------------------------------------------------------------
1 | let express = require('express');
2 | let app = express();
3 |
4 | const DIR = __dirname + '/dist/browser';
5 | const INDEX = require('fs').readFileSync(DIR + '/index.html');
6 |
7 | app.use(express.static(__dirname + '/dist/browser'));
8 | app.get('*', (req, res) => {
9 | res.end(INDEX);
10 | })
11 |
12 | app.listen(process.env.PORT || 4010);
13 |
--------------------------------------------------------------------------------
/apps/todo/server.ts:
--------------------------------------------------------------------------------
1 | import 'zone.js/dist/zone-node';
2 | import 'reflect-metadata';
3 | import { renderModuleFactory } from '@angular/platform-server';
4 | import { enableProdMode } from '@angular/core';
5 |
6 | import * as express from 'express';
7 | import { join } from 'path';
8 | import { readFileSync } from 'fs';
9 |
10 | // Faster server renders w/ Prod mode (dev mode never needed)
11 | enableProdMode();
12 |
13 | // Express server
14 | const app = express();
15 |
16 | const PORT = process.env.PORT || 4000;
17 | const DIST_FOLDER = join(process.cwd(), 'dist');
18 |
19 | // Our index.html we'll use as our template
20 | const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();
21 |
22 | // * NOTE :: leave this as require() since this file is built Dynamically from webpack
23 | const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main');
24 |
25 | // Express Engine
26 | import { ngExpressEngine } from '@nguniversal/express-engine';
27 | // Import module map for lazy loading
28 | import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
29 |
30 | // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
31 | app.engine('html', ngExpressEngine({
32 | bootstrap: AppServerModuleNgFactory,
33 | providers: [
34 | provideModuleMap(LAZY_MODULE_MAP)
35 | ]
36 | }));
37 |
38 | app.set('view engine', 'html');
39 | app.set('views', join(DIST_FOLDER, 'browser'));
40 |
41 | /* - Example Express Rest API endpoints -
42 | app.get('/api/**', (req, res) => { });
43 | */
44 |
45 | // Server static files from /browser
46 | app.get('*.*', express.static(join(DIST_FOLDER, 'browser'), {
47 | maxAge: '1y'
48 | }));
49 |
50 | // ALl regular routes use the Universal engine
51 | app.get('*', (req, res) => {
52 | res.render('index', { req });
53 | });
54 |
55 | // Start up the Node server
56 | app.listen(PORT, () => {
57 | console.log(`Node Express server listening on http://localhost:${PORT}`);
58 | });
59 |
--------------------------------------------------------------------------------
/apps/todo/src/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/apps/todo/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | template: `
6 |
7 |
8 |
9 |
10 | `,
11 | })
12 | export class AppComponent {
13 | constructor() {
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/apps/todo/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { BrowserModule } from '@angular/platform-browser';
3 | import { RouterModule } from '@angular/router';
4 | import { FormsModule } from '@angular/forms';
5 | import { HttpModule } from '@angular/http';
6 | import {APP_BASE_HREF} from '@angular/common';
7 |
8 | import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
9 |
10 | import { appRoutes } from './app.routing';
11 | import { AppComponent } from './app.component';
12 | import { HomeComponent } from './home/home.component';
13 | import { NavbarComponent } from './navbar/navbar.component';
14 | import {ListComponent} from './list/list.component'
15 | import {LogInModalComponent} from './log-in-modal/log-in-modal.component'
16 |
17 | import {PlatformService} from './services/platform.service';
18 | import {OneDBService} from './services/onedb.service'
19 |
20 | import { environment } from '../environments/environment';
21 | import { AutofocusDirective } from './autofocus.directive';
22 |
23 | @NgModule({
24 | imports: [
25 | BrowserModule.withServerTransition({appId: 'my-app'}),
26 | RouterModule.forRoot(appRoutes),
27 | HttpModule,
28 | FormsModule,
29 | NgbModule.forRoot(),
30 | ],
31 | providers: [
32 | {provide: APP_BASE_HREF, useValue: environment.baseHref || '/'},
33 | PlatformService,
34 | OneDBService,
35 | ],
36 | declarations: [
37 | AppComponent,
38 | HomeComponent,
39 | NavbarComponent,
40 | ListComponent,
41 | LogInModalComponent,
42 | AutofocusDirective,
43 | ],
44 | bootstrap: [ AppComponent ],
45 | })
46 | export class AppModule { }
47 |
--------------------------------------------------------------------------------
/apps/todo/src/app/app.routing.ts:
--------------------------------------------------------------------------------
1 | import { Routes, RouterModule } from '@angular/router';
2 | import {HomeComponent} from './home/home.component';
3 | import {ListComponent} from './list/list.component';
4 |
5 | export const appRoutes: Routes = [
6 | { path: '', component: HomeComponent },
7 | { path: 'new-list', component: ListComponent },
8 | { path: 'list/:list_id', component: ListComponent },
9 | { path: '**', redirectTo: '' },
10 | ];
11 |
12 |
--------------------------------------------------------------------------------
/apps/todo/src/app/app.server.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {ServerModule} from '@angular/platform-server';
3 | import {ModuleMapLoaderModule} from '@nguniversal/module-map-ngfactory-loader';
4 |
5 | import {AppModule} from './app.module';
6 | import {AppComponent} from './app.component';
7 |
8 | @NgModule({
9 | imports: [
10 | // The AppServerModule should import your AppModule followed
11 | // by the ServerModule from @angular/platform-server.
12 | AppModule,
13 | ServerModule,
14 | ModuleMapLoaderModule,
15 | ],
16 | // Since the bootstrapped component is not inherited from your
17 | // imported AppModule, it needs to be repeated here.
18 | bootstrap: [AppComponent],
19 | })
20 | export class AppServerModule {}
21 |
--------------------------------------------------------------------------------
/apps/todo/src/app/autofocus.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, AfterViewInit, ElementRef } from '@angular/core';
2 |
3 | @Directive({
4 | selector: '[autofocus]'
5 | })
6 | export class AutofocusDirective implements AfterViewInit {
7 | constructor(private el: ElementRef) {}
8 |
9 | ngAfterViewInit() {
10 | this.el.nativeElement.focus();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/apps/todo/src/app/home/home.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, ViewChild} from '@angular/core';
2 | import {Router} from '@angular/router';
3 | import {OneDBService} from '../services/onedb.service';
4 |
5 | declare let window:any;
6 | declare let require:any;
7 |
8 | @Component({
9 | selector: 'home',
10 | templateUrl: './home.pug',
11 | })
12 | export class HomeComponent {
13 | @ViewChild('logInModal') logInModal;
14 | lists:any[];
15 | error:string;
16 | constructor(public onedb:OneDBService) {
17 | this.onedb.onLogin.subscribe(host => {
18 | if (host === this.onedb.client.hosts.primary) {
19 | if (host.user) {
20 | this.loadTodoLists();
21 | } else {
22 | this.lists = [];
23 | }
24 | }
25 | });
26 | this.initialize();
27 | }
28 |
29 | async initialize() {
30 | if (this.onedb.user) this.loadTodoLists();
31 | }
32 |
33 | async loadTodoLists() {
34 | this.error = null;
35 | try {
36 | this.lists = (await this.onedb.client.list('todo', 'list')).items;
37 | } catch (e) {
38 | this.error = e.message;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/apps/todo/src/app/home/home.pug:
--------------------------------------------------------------------------------
1 | log-in-modal(#logInModal)
2 | h1 Hey there!
3 | p.
4 | OneToDo is a free and open source tool for creating to-do lists.
5 | p.
6 | OneToDo uses OneDB
7 | for cloud storage, which means you get to decide where your data is stored -
8 | in the cloud, or on your company's servers, or on your local hard drive.
9 | p(*ngIf="!onedb.client.hosts.primary.user")
10 | a((click)="logInModal.open()" href="javascript:void(0)") Sign in
11 | span or
12 | a((click)="logInModal.open()" href="javascript:void(0)") get a free account
13 |
14 | .alert.alert-danger(*ngIf="error" role="alert") {{ error }}
15 | div(*ngIf="onedb.client.hosts.primary.user")
16 | hr
17 | h2.text-center Your To-Do Lists
18 | h2(*ngIf="!lists")
19 | i.fa.fa-spin.fa-refresh
20 | div(*ngIf="lists")
21 | div(*ngIf="!lists.length")
22 | h1.text-center
23 | i.fa.fa-4x.fa-list-ul
24 | p.text-center
25 | span You haven't made any to-do lists.
26 | a(routerLink="/new-list") Start one now
27 | div(*ngIf="lists.length")
28 | .list(*ngFor="let list of lists")
29 | h4
30 | a([routerLink]="['/list', list.$.id]") {{ list.title }}
31 | a.btn.btn-min-width.btn-success(routerLink="/new-list") Create a new to-do list
32 |
--------------------------------------------------------------------------------
/apps/todo/src/app/list/list.pug:
--------------------------------------------------------------------------------
1 | div(*ngIf="!list && !error")
2 | h1.text-center
3 | i.fa.fa-spin.fa-refresh
4 | div(*ngIf="list")
5 | h1 Editing {{ list.title }}
6 | .form-group
7 | input.form-control.form-control-lg(type="text", [(ngModel)]="list.title" autofocus)
8 | .item(*ngFor="let item of list.items")
9 | a.checkbox((click)="item.done = !item.$ref && !item.done")
10 | i.fa.fa-2x.fa-left([class.fa-square-o]="!item.done", [class.fa-check-square]="item.done")
11 | .item-title
12 | .input-group
13 | input.form-control(
14 | type="text",
15 | [(ngModel)]="item.$ref ? 'Item ' + item.$ref + ' not found' : item.title",
16 | [class.missing]="item.$ref", [class.done]="item.done",
17 | [disabled]="item.$ref", autofocus)
18 | .input-group-append
19 | button.btn.btn-danger(type="button", (click)="deleteItem(item)")
20 | i.fa.fa-times
21 | .form-group
22 | .row
23 | .col
24 | button.btn.btn-min-width.btn-secondary((click)="list.items.push(newItem())") Add a new item
25 | .col
26 | .btn-toolbar.float-right
27 | button.btn.btn-min-width.btn-success.mr-4((click)="save()")
28 | span(*ngIf="!saving") Save
29 | i.fa.fa-spin.fa-refresh(*ngIf="saving")
30 | button.btn.btn-min-width.btn-danger((click)="delete()")
31 | span Delete
32 | .alert.alert-danger(*ngIf="error" role="alert") {{ error }}
33 |
--------------------------------------------------------------------------------
/apps/todo/src/app/log-in-modal/log-in-modal.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, ViewChild} from '@angular/core';
2 | import {OneDBService} from '../services/onedb.service';
3 | import {NgbModal, ModalDismissReasons} from '@ng-bootstrap/ng-bootstrap';
4 | import {DomSanitizer, SafeHtml} from '@angular/platform-browser'
5 |
6 | @Component({
7 | selector: 'log-in-modal',
8 | templateUrl: './log-in-modal.pug',
9 | })
10 | export class LogInModalComponent {
11 | @ViewChild('content') content;
12 | formContent:SafeHtml;
13 | modalRef:any;
14 |
15 | constructor(
16 | private onedb:OneDBService,
17 | private modals: NgbModal,
18 | private sanitizer:DomSanitizer) {
19 | this.refreshForm();
20 | this.onedb.onLogin.subscribe(instance => {
21 | this.refreshForm();
22 | if (this.modalRef && instance.user) this.modalRef.close();
23 | })
24 | }
25 |
26 | open() {
27 | this.modalRef = this.modals.open(this.content);
28 | }
29 |
30 | refreshForm() {
31 | this.formContent = this.sanitizer.bypassSecurityTrustHtml(this.onedb.client.loginForm());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/apps/todo/src/app/log-in-modal/log-in-modal.pug:
--------------------------------------------------------------------------------
1 | ng-template(#content let-c="close" let-d="dismiss")
2 | .modal-header
3 | h4.modal-title
4 | span(*ngIf="!onedb.client.hosts.primary.user") Log In or Sign Up
5 | span(*ngIf="onedb.client.hosts.primary.user") Log Out or Switch Accounts
6 | button.close(type="button", class="close", aria-label="Close", (click)="d('Cross click')")
7 | span(aria-hidden="true") ×
8 | .modal-body
9 | p Open Todo uses OneDB, so you get to decide where your data is stored.
10 | p.
11 | You can create a free account on one-db.datafire.io
12 |
13 | host your own instance
14 | , or choose another provider.
15 | div([innerHtml]="formContent")
16 |
--------------------------------------------------------------------------------
/apps/todo/src/app/navbar/navbar.component.ts:
--------------------------------------------------------------------------------
1 | import {ViewChild, Component} from '@angular/core';
2 | import {Router} from '@angular/router';
3 | import {OneDBService} from '../services/onedb.service';
4 |
5 | @Component({
6 | selector: 'navbar',
7 | templateUrl: './navbar.pug',
8 | })
9 | export class NavbarComponent {
10 | @ViewChild('logInModal') logInModal;
11 | constructor(public router: Router, public onedb:OneDBService) {}
12 | }
13 |
--------------------------------------------------------------------------------
/apps/todo/src/app/navbar/navbar.pug:
--------------------------------------------------------------------------------
1 | log-in-modal(#logInModal)
2 | nav.navbar.navbar-expand-lg.navbar-dark.bg-dark
3 | .container
4 | a.navbar-brand(routerLink="/") OneToDo
5 | div
6 | ul.navbar-nav.ml-auto
7 | li
8 | a.nav-link((click)="logInModal.open()")
9 | i.fa.fa-left.fa-users
10 | span([ngSwitch]="!!onedb.client.hosts.primary.user")
11 | span(*ngSwitchCase="true")
12 | span {{onedb.client.hosts.primary.displayName}}
13 | span(*ngSwitchCase="false") Sign In
14 |
15 |
--------------------------------------------------------------------------------
/apps/todo/src/app/services/onedb.service.ts:
--------------------------------------------------------------------------------
1 | import {Injectable, NgZone} from '@angular/core';
2 | import {BehaviorSubject} from 'rxjs';
3 |
4 | declare let window:any;
5 | declare let require:any;
6 | const Client = require('onedb-client').Client;
7 | const CORE_HOST = 'https://one-db.datafire.io';
8 |
9 | const STORAGE_KEY = 'onedb_auth';
10 |
11 | @Injectable()
12 | export class OneDBService {
13 | client:any;
14 | user:any;
15 |
16 | onLogin = new BehaviorSubject(null);
17 |
18 | constructor(private zone:NgZone) {
19 | window.onedbService = this;
20 | this.client = new Client({
21 | hosts: {
22 | core: {
23 | location: CORE_HOST,
24 | }
25 | },
26 | onLogin: user => {
27 | this.zone.run(_ => this.onLogin.next(user));
28 | },
29 | scope: ['todo:read', 'todo:create', 'todo:write', 'todo:delete', 'todo:modify_acl', 'todo:append'],
30 | });
31 | this.maybeRestore();
32 | this.onLogin.subscribe(user => {
33 | this.user = user;
34 | if (!window.localStorage) return
35 | const toStore = {
36 | hosts: this.client.hosts,
37 | };
38 | window.localStorage.setItem(STORAGE_KEY, JSON.stringify(toStore))
39 | })
40 | }
41 |
42 | async maybeRestore() {
43 | if (!window.localStorage) return;
44 | let existing:any = window.localStorage.getItem(STORAGE_KEY);
45 | if (!existing) return;
46 | existing = JSON.parse(existing);
47 | if (!existing || !existing.hosts) return;
48 | let hosts = Object.assign({}, existing.hosts, {core: {location: CORE_HOST}})
49 | await this.client.setHosts(hosts);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/apps/todo/src/app/services/platform.service.ts:
--------------------------------------------------------------------------------
1 | import { Inject, Injectable, PLATFORM_ID } from '@angular/core'
2 | import { isPlatformBrowser, isPlatformServer } from '@angular/common'
3 |
4 | @Injectable()
5 | export class PlatformService {
6 | constructor(@Inject(PLATFORM_ID) private platformId: any) { }
7 |
8 | public isBrowser(): boolean {
9 | return isPlatformBrowser(this.platformId)
10 | }
11 |
12 | public isServer(): boolean {
13 | return isPlatformServer(this.platformId)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/apps/todo/src/app/styles/_variables.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/todo/src/app/styles/_variables.scss
--------------------------------------------------------------------------------
/apps/todo/src/app/styles/app.scss:
--------------------------------------------------------------------------------
1 | a {
2 | cursor: pointer;
3 | }
4 |
5 | .navbar {
6 | border-radius: 0px;
7 | margin-bottom: 30px;
8 | }
9 |
10 | body {
11 | position: relative;
12 | }
13 |
14 | app > .container {
15 | padding-bottom: 72px;
16 | }
17 |
18 | footer {
19 | position: absolute;
20 | bottom: 0;
21 | left: 0;
22 | right: 0;
23 |
24 | background-color: #fff;
25 | padding-top: 20px;
26 | padding-bottom: 20px;
27 | }
28 |
29 | footer, footer a {
30 | color: #3E3F3A;
31 | }
32 |
33 | .fa-left {
34 | margin-right: 8px;
35 | }
36 | .fa-right {
37 | margin-left: 8px;
38 | }
39 |
40 | .btn-min-width {
41 | min-width: 100px;
42 | }
43 |
--------------------------------------------------------------------------------
/apps/todo/src/app/styles/styles.scss:
--------------------------------------------------------------------------------
1 | @import 'variables';
2 |
3 | @import '~bootstrap/scss/bootstrap';
4 |
5 | @import './app.scss';
6 |
7 |
--------------------------------------------------------------------------------
/apps/todo/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/todo/src/assets/.gitkeep
--------------------------------------------------------------------------------
/apps/todo/src/assets/img/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/todo/src/assets/img/Icon.png
--------------------------------------------------------------------------------
/apps/todo/src/assets/img/Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/todo/src/assets/img/Logo.png
--------------------------------------------------------------------------------
/apps/todo/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | baseHref: '/',
4 | };
5 |
--------------------------------------------------------------------------------
/apps/todo/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // The file contents for the current environment will overwrite these during build.
2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do
3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead.
4 | // The list of which env maps to which file can be found in `.angular-cli.json`.
5 |
6 | export const environment = {
7 | production: false,
8 | baseHref: '/',
9 | };
10 |
--------------------------------------------------------------------------------
/apps/todo/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/apps/todo/src/favicon.ico
--------------------------------------------------------------------------------
/apps/todo/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | OneToDo
7 |
8 |
9 |
10 |
11 |
12 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/apps/todo/src/main.server.ts:
--------------------------------------------------------------------------------
1 | export { AppServerModule } from './app/app.server.module';
2 |
--------------------------------------------------------------------------------
/apps/todo/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | document.addEventListener('DOMContentLoaded', () => {
12 | platformBrowserDynamic().bootstrapModule(AppModule);
13 | });
14 |
--------------------------------------------------------------------------------
/apps/todo/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/
22 | // import 'core-js/es6/symbol';
23 | // import 'core-js/es6/object';
24 | // import 'core-js/es6/function';
25 | // import 'core-js/es6/parse-int';
26 | // import 'core-js/es6/parse-float';
27 | // import 'core-js/es6/number';
28 | // import 'core-js/es6/math';
29 | // import 'core-js/es6/string';
30 | // import 'core-js/es6/date';
31 | // import 'core-js/es6/array';
32 | // import 'core-js/es6/regexp';
33 | // import 'core-js/es6/map';
34 | // import 'core-js/es6/weak-map';
35 | // import 'core-js/es6/set';
36 |
37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
38 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
39 |
40 | /** Evergreen browsers require these. **/
41 | import 'core-js/es6/reflect';
42 | import 'core-js/es7/reflect';
43 | import 'babel-polyfill';
44 |
45 | /**
46 | * Required to support Web Animations `@angular/animation`.
47 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
48 | **/
49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
50 |
51 |
52 |
53 | /***************************************************************************************************
54 | * Zone JS is required by Angular itself.
55 | */
56 | import 'zone.js/dist/zone'; // Included with Angular CLI.
57 |
58 |
59 |
60 | /***************************************************************************************************
61 | * APPLICATION IMPORTS
62 | */
63 |
64 | /**
65 | * Date, currency, decimal and percent pipes.
66 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
67 | */
68 | // import 'intl'; // Run `npm install --save intl`.
69 | /**
70 | * Need to import at least one locale-data with intl.
71 | */
72 | // import 'intl/locale-data/jsonp/en';
73 |
--------------------------------------------------------------------------------
/apps/todo/src/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "baseUrl": "./",
6 | "module": "es2015",
7 | "types": []
8 | },
9 | "exclude": [
10 | "test.ts",
11 | "**/*.spec.ts"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/apps/todo/src/tsconfig.server.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "baseUrl": "./",
6 | // Set the module format to "commonjs":
7 | "module": "commonjs",
8 | "types": []
9 | },
10 | "exclude": [
11 | "test.ts",
12 | "**/*.spec.ts"
13 | ],
14 | // Add "angularCompilerOptions" with the AppServerModule you wrote
15 | // set as the "entryModule".
16 | "angularCompilerOptions": {
17 | "entryModule": "app/app.server.module#AppServerModule"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/apps/todo/static.paths.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | '/',
3 | ];
4 |
--------------------------------------------------------------------------------
/apps/todo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "outDir": "./dist/out-tsc",
5 | "sourceMap": true,
6 | "declaration": false,
7 | "moduleResolution": "node",
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "target": "es5",
11 | "typeRoots": [
12 | "node_modules/@types",
13 | "typings.d.ts"
14 | ],
15 | "lib": [
16 | "es2017",
17 | "dom"
18 | ],
19 | "types": ["node"],
20 | "module": "es2015",
21 | "baseUrl": "./"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/apps/todo/types/item.schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "object",
3 | "properties": {
4 | "title": {"type": "string", "maxLength": 100, "minLength": 1},
5 | "description": {"type": "string", "maxLength": 1000, "minLength": 1},
6 | "done": {"type": "boolean", "default": false}
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/apps/todo/types/list.schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "object",
3 | "properties": {
4 | "title": {"type": "string", "maxLength": 100, "minLength": 1},
5 | "items": {
6 | "type": "array",
7 | "items": {"$ref": "#/definitions/item"}
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/apps/todo/webpack.cli-additions.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const commonCliConfig = 'node_modules/@angular/cli/models/webpack-configs/common.js';
3 | const addition_rules = `
4 | { test: /\.(pug|jade)$/, loader: 'apply-loader' },
5 | { test: /\.(pug|jade)$/,
6 | loader: 'pug-loader',
7 | query: { doctype: 'html', plugins: [require('pug-plugin-ng')] },
8 | }, {
9 | test: /\.json$/,
10 | use: [{
11 | loader: 'json-loader',
12 | }]
13 | },
14 | {
15 | test: /\.js$/,
16 | use: [{
17 | loader: 'babel-loader',
18 | options: {
19 | presets: ['env'],
20 | }
21 | }],
22 | },
23 | { test: /\.md$/, use: [{ loader: 'raw-loader' }, { loader: 'markdown-loader', }] }
24 | ,`; // make sure to have this last comma
25 |
26 | fs.readFile(commonCliConfig, (err, data) => {
27 |
28 | if (err) { throw err; }
29 |
30 | const configText = data.toString();
31 | // make sure we don't include it (if we've already done this)
32 | if (configText.indexOf(addition_rules) > -1) { return; }
33 |
34 | console.log('-- Inserting additional webpack rules to node_modules CLI -- ');
35 |
36 | const position = configText.indexOf('rules: [') + 8;
37 | const output = [configText.slice(0, position), addition_rules, configText.slice(position)].join('');
38 | const file = fs.openSync(commonCliConfig, 'r+');
39 |
40 | fs.writeFile(file, output);
41 | fs.close(file);
42 | });
43 |
44 |
--------------------------------------------------------------------------------
/apps/todo/webpack.server.config.js:
--------------------------------------------------------------------------------
1 | // Work around for https://github.com/angular/angular-cli/issues/7200
2 |
3 | const path = require('path');
4 | const webpack = require('webpack');
5 |
6 | module.exports = {
7 | entry: {
8 | // This is our Express server for Dynamic universal
9 | server: './server.ts',
10 | // This is an example of Static prerendering (generative)
11 | prerender: './prerender.ts'
12 | },
13 | target: 'node',
14 | resolve: { extensions: ['.ts', '.js'] },
15 | // Make sure we include all node_modules etc
16 | externals: [/(node_modules|main\..*\.js)/,],
17 | output: {
18 | // Puts the output at the root of the dist folder
19 | path: path.join(__dirname, 'dist'),
20 | filename: '[name].js'
21 | },
22 | module: {
23 | rules: [
24 | { test: /\.ts$/, use: {loader: 'ts-loader', options: {}} }
25 | ]
26 | },
27 | plugins: [
28 | new webpack.ContextReplacementPlugin(
29 | // fixes WARNING Critical dependency: the request of a dependency is an expression
30 | /(.+)?angular(\\|\/)core(.+)?/,
31 | path.join(__dirname, 'src'), // location of your src
32 | {} // a map of your routes
33 | ),
34 | new webpack.ContextReplacementPlugin(
35 | // fixes WARNING Critical dependency: the request of a dependency is an expression
36 | /(.+)?express(\\|\/)(.+)?/,
37 | path.join(__dirname, 'src'),
38 | {}
39 | )
40 | ]
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/client/browser.js:
--------------------------------------------------------------------------------
1 | require('babel-polyfill')
2 | window.OneDBClient = require('./lib/client');
3 |
--------------------------------------------------------------------------------
/client/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | Client: require('./lib/client'),
3 | }
4 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "onedb-client",
3 | "version": "0.4.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "mocha --exit",
8 | "build": "webpack -p"
9 | },
10 | "author": "",
11 | "license": "MIT",
12 | "devDependencies": {
13 | "babel-core": "^6.26.0",
14 | "babel-loader": "^7.1.2",
15 | "babel-polyfill": "^6.26.0",
16 | "babel-preset-env": "^1.6.1",
17 | "chai": "^4.1.2",
18 | "mocha": "^5.2.0",
19 | "mongodb-memory-server": "^1.9.0",
20 | "webpack": "^3.5.5"
21 | },
22 | "dependencies": {
23 | "ajv": "^6.5.2",
24 | "axios": "^0.18.0"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/client/webpack.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require("webpack");
2 | module.exports = {
3 | entry: {
4 | "onedb-client": "./browser.js"
5 | },
6 | output: {
7 | path: __dirname,
8 | filename: "dist/[name].min.js"
9 | },
10 | resolve: {
11 | extensions: ['.js']
12 | },
13 | devtool: 'source-map',
14 | module: {
15 | loaders: [{
16 | test: /\.js$/,
17 | loader: 'babel-loader?presets[]=env',
18 | }]
19 | },
20 | node: {
21 | fs: "empty"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/cmd/bin/onedb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict';
3 |
4 | require('../cmd.js');
5 |
--------------------------------------------------------------------------------
/cmd/cmd.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const DEFAULT_HOST = "https://one-db.datafire.io";
4 |
5 | const commands = require('./index');
6 |
7 | let args = require('yargs')
8 | .option('v', {alias: 'verbose'})
9 | .global('v')
10 | .recommendCommands();
11 |
12 | function attempt(fn) {
13 | return async function(args) {
14 | // TODO: why are these not set by yargs defaults?
15 | args.host = args.host || DEFAULT_HOST;
16 | args.directory = args.directory || process.cwd();
17 | try {
18 | await commands[fn](args);
19 | } catch (e) {
20 | console.log(e.message);
21 | }
22 | }
23 | }
24 |
25 | args = args.command(
26 | 'login',
27 | "Start a OneDB session",
28 | yargs => {
29 | return yargs.option('host', {
30 | alias: 'h',
31 | default: DEFAULT_HOST,
32 | describe: "The OneDB instance to log into",
33 | })
34 | },
35 | attempt('login'));
36 |
37 | args = args.command(
38 | 'serve',
39 | "Start a OneDB server",
40 | yargs => {
41 | return yargs.option('port', {
42 | alias: 'p',
43 | describe: 'The port to listen on',
44 | default: 3000,
45 | })
46 | },
47 | attempt('serve'),
48 | );
49 | args = args.command(
50 | 'namespace',
51 | "Create or update a namespace",
52 | yargs => {
53 | yargs = yargs.option('name', {
54 | alias: 'n',
55 | describe: "The ID of the namespace",
56 | demand: true,
57 | })
58 | yargs = yargs.option('directory', {
59 | alias: 'd',
60 | describe: "The directory containing schema and ACL files",
61 | default: process.cwd(),
62 | });
63 | yargs = yargs.option('host', {
64 | alias: 'h',
65 | describe: "The OneDB host to send the namespace to",
66 | default: DEFAULT_HOST,
67 | type: 'string',
68 | })
69 | yargs = yargs.option('username', {
70 | alias: 'u',
71 | describe: "Your username",
72 | })
73 | yargs = yargs.option('password', {
74 | alias: 'p',
75 | describe: "Your password",
76 | })
77 | return yargs;
78 | },
79 | attempt('namespace'),
80 | )
81 |
82 | args = args.demandCommand(1);
83 | args = args.help('h').alias('h', 'help').strict().argv;
84 |
--------------------------------------------------------------------------------
/cmd/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | serve: require('./lib/serve'),
3 | namespace: require('./lib/namespace'),
4 | login: require('./lib/login'),
5 | }
6 |
--------------------------------------------------------------------------------
/cmd/lib/files.js:
--------------------------------------------------------------------------------
1 | const homedir = require('os').homedir();
2 | const npath = require('path');
3 | module.exports.ONEDB_DIR = npath.join(homedir, '.onedb');
4 | module.exports.CREDENTIALS_FILE = npath.join(module.exports.ONEDB_DIR, 'credentials.json');
5 |
6 |
--------------------------------------------------------------------------------
/cmd/lib/login.js:
--------------------------------------------------------------------------------
1 | const inquirer = require('inquirer');
2 | const files = require('./files');
3 | const fs = require('fs');
4 | const Client = require('onedb-client').Client;
5 |
6 | const USERNAME_QUESTION = {type: 'string', name: 'username', message: "Your OneDB username or email address"};
7 | const PASSWORD_QUESTION = {type: 'password', name: 'password', message: "Your OneDB password"};
8 |
9 | module.exports = async function(args) {
10 | if (!fs.existsSync(files.ONEDB_DIR)) {
11 | fs.mkdirSync(files.ONEDB_DIR);
12 | }
13 | if (!fs.existsSync(files.CREDENTIALS_FILE)) {
14 | fs.writeFileSync(files.CREDENTIALS_FILE, '{}');
15 | }
16 | const creds = require(files.CREDENTIALS_FILE);
17 | const prompt = inquirer.createPromptModule();
18 | const answers = await prompt([USERNAME_QUESTION, PASSWORD_QUESTION]);
19 | const client = new Client({hosts: {primary: {
20 | location: args.host,
21 | username: answers.username,
22 | password: answers.password,
23 | }}});
24 | const token = await client.generateToken(client.hosts.primary);
25 | creds[args.host] = {token, username: answers.username};
26 | fs.writeFileSync(files.CREDENTIALS_FILE, JSON.stringify(creds, null, 2));
27 | }
28 |
--------------------------------------------------------------------------------
/cmd/lib/namespace.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 |
3 | const npath = require('path');
4 | const Client = require('onedb-client').Client;
5 | const CREDS_FILE = require('./files').CREDENTIALS_FILE;
6 |
7 | module.exports = async function(args) {
8 | let creds = {};
9 | if (fs.existsSync(CREDS_FILE)) {
10 | creds = require(CREDS_FILE);
11 | creds = creds[args.host] || {};
12 | }
13 | const host = {location: args.host};
14 | if (args.username) {
15 | host.username = args.username;
16 | host.password = args.password;
17 | } else if (process.env.ONEDB_USERNAME) {
18 | host.username = process.env.ONEDB_USERNAME;
19 | host.password = process.env.ONEDB_PASSWORD;
20 | } else if (creds.token || creds.password) {
21 | host.username = creds.username;
22 | host.password = creds.password;
23 | host.token = creds.token;
24 | } else {
25 | throw new Error("No credentials found. Please run:\nonedb login");
26 | }
27 | const client = new Client({
28 | hosts: {
29 | primary: host,
30 | core: host,
31 | }
32 | });
33 |
34 | const DIR = npath.join(process.cwd(), args.directory);
35 |
36 | const files = fs.readdirSync(DIR).filter(f => f.endsWith('.schema.json'));
37 | const types = {}
38 | for (let file of files) {
39 | const name = file.replace(/\.schema\.json$/, '');
40 | const schema = require(npath.join(DIR, file));
41 | types[name] = {schema}
42 | }
43 | for (let type in types) {
44 | const aclFile = npath.join(DIR, type + '.acl.json');
45 | if (fs.existsSync(aclFile)) {
46 | types[type].initial_acl = require(aclFile);
47 | }
48 | }
49 | const ns = {
50 | versions: [{types}]
51 | }
52 | let existing = null;
53 | try {
54 | existing = await client.get('core', 'namespace', args.name);
55 | } catch (e) {
56 | if (e.statusCode !== 404) throw e;
57 | }
58 | if (existing) {
59 | await client.append('core', 'namespace', args.name, ns);
60 | console.log("Updated namespace " + args.name);
61 | } else {
62 | await client.create('core', 'namespace', args.name, ns);
63 | console.log("Created namespace " + args.name);
64 | }
65 | process.exit(0);
66 | }
67 |
68 | ;(async () => {
69 | if (require.main === module) {
70 | try {
71 | await module.exports({})
72 | } catch (e) {
73 | console.error(e.message);
74 | }
75 | }
76 | })();
77 |
--------------------------------------------------------------------------------
/cmd/lib/serve.js:
--------------------------------------------------------------------------------
1 | const Server = require('onedb-server').Server;
2 | const fs = require('fs');
3 | const npath = require('path');
4 | const YAML = require('yamljs');
5 |
6 | const CONFIG_FILE = npath.join(process.cwd(), 'OneDB.yml');
7 | const DEFAULT_CORE_HOST = "https://one-db.datafire.io";
8 |
9 | module.exports = function(opts) {
10 | if (fs.existsSync(CONFIG_FILE)) {
11 | opts = Object.assign({}, YAML.load(CONFIG_FILE), opts);
12 | }
13 | opts.namespaces = opts.namespaces || {};
14 | opts.namespaces.proxy = opts.namespaces.proxy || {};
15 | if (opts.namespaces.proxy.core === undefined) {
16 | opts.namespaces.proxy.core = DEFAULT_CORE_HOST;
17 | }
18 | let server = new Server(opts);
19 | return server.listen(opts.port);
20 | }
21 |
22 | ;(async () => {
23 | if (require.main === module) {
24 | let opts = require('yargs').argv;
25 | try {
26 | await module.exports(opts);
27 | console.log('OneDB listening on port ' + opts.port);
28 | } catch (e) {
29 | console.log(e.message);
30 | console.log(e.stack);
31 | throw e;
32 | }
33 | }
34 | })();
35 |
--------------------------------------------------------------------------------
/cmd/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "onedb-cli",
3 | "version": "0.2.0",
4 | "description": "",
5 | "main": "index.js",
6 | "engines": {
7 | "node": ">=8.0.0"
8 | },
9 | "scripts": {
10 | "test": "mocha --exit",
11 | "build": "webpack -p"
12 | },
13 | "bin": {
14 | "onedb": "./bin/onedb"
15 | },
16 | "author": "",
17 | "license": "MIT",
18 | "devDependencies": {},
19 | "dependencies": {
20 | "inquirer": "^6.2.0",
21 | "onedb-client": "^0.4.0",
22 | "onedb-server": "0.1.0",
23 | "yamljs": "^0.3.0",
24 | "yargs": "^12.0.2"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "onedb",
3 | "version": "1.0.0",
4 | "description": "OneDB is a decentralized backend-as-a-service.",
5 | "main": "index.js",
6 | "dependencies": {},
7 | "devDependencies": {
8 | "pug-cli": "^1.0.0-alpha6"
9 | },
10 | "scripts": {
11 | "test": "cd server && npm test ; cd ../client && npm test",
12 | "build": "npm run build:client && npm run build:apps && npm run build:docs && npm run build:homepage",
13 | "build:client": "cd client && npm run build",
14 | "build:apps": "cp client/dist/onedb-client.min.js apps/minimal/ ; cd apps/todo && npm run build ; cd ../data-explorer && npm run build ; cd ../chat && npm run build",
15 | "build:docs": "lucybot build --directory ./web/docs --destination ./web/docs/dist",
16 | "build:homepage": "pug < web/homepage/views/index.pug > web/homepage/index.html"
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/bobby-brennan/OneDB.git"
21 | },
22 | "author": "",
23 | "license": "MIT",
24 | "bugs": {
25 | "url": "https://github.com/bobby-brennan/OneDB/issues"
26 | },
27 | "homepage": "https://github.com/bobby-brennan/OneDB#readme"
28 | }
29 |
--------------------------------------------------------------------------------
/server/.gitignore:
--------------------------------------------------------------------------------
1 | plugins/
2 |
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | Server: require('./lib/server'),
3 | }
4 |
--------------------------------------------------------------------------------
/server/lib/config.js:
--------------------------------------------------------------------------------
1 | const ONE_MIN = 60 * 1000;
2 | const FIVE_MIN = 5 * ONE_MIN;
3 | const FIFTEEN_MIN = 15 * ONE_MIN;
4 |
5 | module.exports = {
6 | maxBytesPerItem: 100 * 1000, // 100 kiB
7 | maxItemsPerUser: 10 * 1000, // 1 GiB total
8 | host: 'http://localhost:3000',
9 | namespaces: {},
10 | rateLimit: {
11 | all: {
12 | windowMs: FIFTEEN_MIN,
13 | max: 900,
14 | delayMs: 0,
15 | },
16 | users: {
17 | windowMs: FIFTEEN_MIN,
18 | max: 900,
19 | delayMs: 0,
20 | },
21 | createUser: {
22 | windowMs: FIFTEEN_MIN,
23 | max: 15,
24 | delayMs: 3 * 1000,
25 | delayAfter: 10,
26 | },
27 | getData: { // 1 qps
28 | windowMs: FIFTEEN_MIN,
29 | max: 900,
30 | delayMs: 0,
31 | },
32 | mutateData: { // .25 qps
33 | windowMs: FIFTEEN_MIN,
34 | max: 225,
35 | delayMs: 500,
36 | delayAfter: 100,
37 | },
38 | }
39 | }
40 |
41 |
--------------------------------------------------------------------------------
/server/lib/error-guard.js:
--------------------------------------------------------------------------------
1 | const errorGuard = module.exports = function(fn) {
2 | return async function(req, res, next) {
3 | try {
4 | await fn(req, res, next);
5 | } catch (err) {
6 | res.status(err.statusCode || 500);
7 | res.json({message: err.message || "Unknown error"});
8 | }
9 | }
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/server/lib/fail.js:
--------------------------------------------------------------------------------
1 | const fail = module.exports = function(message, statusCode) {
2 | let err = new Error(message);
3 | if (statusCode) err.statusCode = statusCode;
4 | throw err;
5 | }
6 |
7 |
8 |
--------------------------------------------------------------------------------
/server/lib/middleware/authenticate.js:
--------------------------------------------------------------------------------
1 | const jwt = require('jsonwebtoken');
2 | const fail = require('../fail');
3 | const errorGuard = require('../error-guard');
4 |
5 | module.exports = function(config) {
6 | return errorGuard(async (req, res, next) => {
7 | let auth = req.get('authorization');
8 | if (!auth) {
9 | req.db = await req.systemDB.user('_all');
10 | return next();
11 | }
12 | let parts = auth.split(' ');
13 | if (parts[0] === 'Basic') {
14 | let creds = (new Buffer(parts[1], 'base64')).toString().split(':');
15 | if (creds.length !== 2) return fail("Invalid authorization header", 401);
16 | email = creds[0];
17 | password = creds[1];
18 | req.user = await req.systemDB.signIn(email, password);
19 | req.db = await req.systemDB.user(req.user);
20 | next();
21 | } else if (parts[0] === 'Bearer') {
22 | let token = parts[1];
23 | try {
24 | jwt.verify(token, config.jwtSecret);
25 | } catch (e) {
26 | return fail("Invalid Bearer token", 401);
27 | }
28 | const {id, permissions} = await req.systemDB.signInWithToken(token);
29 | req.user = id;
30 | req.db = await req.systemDB.user(id, permissions);
31 | next();
32 | } else {
33 | return fail("Invalid authorization header", 401);
34 | }
35 | })
36 | }
37 |
--------------------------------------------------------------------------------
/server/lib/middleware/authorize.js:
--------------------------------------------------------------------------------
1 | const jwt = require('jsonwebtoken');
2 | const fail = require('../fail');
3 | const errorGuard = require('../error-guard');
4 | const validate = require('../validate');
5 | const util = require('../util');
6 |
7 | module.exports = function(config) {
8 | return errorGuard(async (req, res, next) => {
9 | const auth = req.get('authorization');
10 | if (!auth) {
11 | return fail("No authorization header", 401)
12 | }
13 |
14 | // TODO: disallow empty scope
15 | req.query.scope = req.query.scope || '';
16 | const err = validate.validators.scope(req.query.scope);
17 | if (err) {
18 | return res.status(400).send(err);
19 | }
20 | const permissionsToGrant = req.query.scope ? util.scopes(req.query.scope) : null;
21 | const expiration = req.query.expires_in ? parseInt(req.query.expires_in) : undefined;
22 |
23 | function getToken(email) {
24 | const data = {email, permissionsToGrant};
25 | const opts = {expiresIn: '1d'};
26 | return jwt.sign(data, config.jwtSecret, opts);
27 | }
28 |
29 | const parts = auth.split(' ');
30 | if (parts[0] === 'Basic') {
31 | const creds = (new Buffer(parts[1], 'base64')).toString().split(':');
32 | if (creds.length !== 2) return fail("Invalid authorization header", 401);
33 | const email = creds[0];
34 | const password = creds[1];
35 | const token = getToken(email);
36 | await req.systemDB.addToken(email, token, permissionsToGrant, expiration);
37 | res.json(token);
38 | } else if (parts[0] === 'Bearer') {
39 | const currentToken = parts[1];
40 | try {
41 | jwt.verify(currentToken, config.jwtSecret);
42 | } catch (e) {
43 | return fail("Invalid Bearer token, JWT failed", 401);
44 | }
45 | const {id, email, permissions} = await req.systemDB.signInWithToken(currentToken);
46 | if (permissions === null) {
47 | const token = getToken(email);
48 | await req.systemDB.addToken(email, token, permissionsToGrant, expiration);
49 | res.json(token);
50 | } else {
51 | return fail("Selected token does not have permission to create new auth tokens", 401);
52 | }
53 | } else {
54 | return fail("Invalid authorization header", 401);
55 | }
56 | })
57 | }
58 |
--------------------------------------------------------------------------------
/server/lib/middleware/checkUsername.js:
--------------------------------------------------------------------------------
1 | const errorGuard = require('../error-guard');
2 |
3 | module.exports = errorGuard(async (req, res, next) => {
4 | let available = await req.systemDB.getAvailableUsername(req.params.username);
5 | res.json(available);
6 | });
7 |
--------------------------------------------------------------------------------
/server/lib/middleware/index.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | fs.readdirSync(__dirname).forEach(file => {
3 | if (file === 'index.js') return;
4 | module.exports[file.replace('.js', '')] = require('./' + file);
5 | })
6 |
--------------------------------------------------------------------------------
/server/lib/routes/index.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | fs.readdirSync(__dirname).forEach(file => {
3 | if (file === 'index.js') return;
4 | module.exports[file.replace('.js', '')] = require('./' + file);
5 | })
6 |
--------------------------------------------------------------------------------
/server/lib/routes/info.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const packageInfo = require('../../package.json');
3 |
4 | const router = module.exports = new express.Router();
5 | router.get('/ping', (req, res) => {
6 | res.json('pong');
7 | });
8 | router.get('/info', (req, res) => {
9 | res.json({version: packageInfo.version});
10 | });
11 |
--------------------------------------------------------------------------------
/server/lib/util/index.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | fs.readdirSync(__dirname).forEach(file => {
3 | if (file === 'index.js') return;
4 | module.exports[file.replace('.js', '')] = require('./' + file);
5 | })
6 |
--------------------------------------------------------------------------------
/server/lib/util/iterateSchema.js:
--------------------------------------------------------------------------------
1 | const iterateSchema = module.exports = function(schema, fn) {
2 | fn(schema);
3 | if (schema.items) iterateSchema(schema.items, fn);
4 | for (let key in schema.properties) {
5 | iterateSchema(schema.properties[key], fn);
6 | }
7 | if (typeof schema.additionalProperties === 'object') {
8 | iterateSchema(schema.additionalProperties, fn);
9 | }
10 | if (schema.not) iterateSchema(schema.not, fn);
11 | for (let sub of schema.oneOf || []) {
12 | iterateSchema(sub, fn);
13 | }
14 | for (let sub of schema.anyOf || []) {
15 | iterateSchema(sub, fn);
16 | }
17 | for (let sub of schema.allOf || []) {
18 | iterateSchema(sub, fn);
19 | }
20 | for (let key in schema.definitions || {}) {
21 | iterateSchema(schema.definitions[key], fn);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/server/lib/util/scopes.js:
--------------------------------------------------------------------------------
1 | const SCOPE_ORDER = ['read', 'create', 'write', 'append', 'delete', 'modify_acl'];
2 |
3 | module.exports = function(scopeString) {
4 | const permissions = {};
5 | scopeString.split(' ').forEach(perm => {
6 | let [namespace, access] = perm.split(':');
7 | permissions[namespace] = permissions[namespace] || [];
8 | if (!permissions[namespace].includes(access)) {
9 | permissions[namespace].push(access);
10 | }
11 | });
12 | for (let namespace in permissions) {
13 | permissions[namespace].sort((a1, a2) => {
14 | return SCOPE_ORDER.indexOf(a1) < SCOPE_ORDER.indexOf(a2) ? -1 : 1;
15 | })
16 | }
17 | return permissions;
18 | }
19 |
--------------------------------------------------------------------------------
/server/namespaces/core/acl.js:
--------------------------------------------------------------------------------
1 | const IDENTITY_SCHEMA = {
2 | type: 'string',
3 | minLength: 2,
4 | maxLength: 100,
5 | }
6 |
7 | const ACL_LIST_SCHEMA = {
8 | type: 'array',
9 | items: IDENTITY_SCHEMA,
10 | }
11 |
12 | const ACL_LIST_WITH_DEFAULT_SCHEMA = Object.assign({}, ACL_LIST_SCHEMA, {default: ['_owner']});
13 |
14 | const ACL_SET_SCHEMA = {
15 | type: 'object',
16 | default: {},
17 | additionalProperties: false,
18 | properties: {
19 | read: ACL_LIST_SCHEMA,
20 | write: ACL_LIST_SCHEMA,
21 | append: ACL_LIST_SCHEMA,
22 | delete: ACL_LIST_SCHEMA,
23 | }
24 | }
25 | const ACL_SET_WITH_DEFAULT_SCHEMA = {
26 | type: 'object',
27 | default: {},
28 | additionalProperties: false,
29 | properties: {
30 | read: ACL_LIST_WITH_DEFAULT_SCHEMA,
31 | write: ACL_LIST_WITH_DEFAULT_SCHEMA,
32 | append: ACL_LIST_WITH_DEFAULT_SCHEMA,
33 | delete: ACL_LIST_WITH_DEFAULT_SCHEMA,
34 | }
35 | }
36 |
37 | const ACL_SCHEMA = module.exports = {
38 | type: 'object',
39 | additionalProperties: false,
40 | properties: {
41 | owner: IDENTITY_SCHEMA,
42 | allow: ACL_SET_WITH_DEFAULT_SCHEMA,
43 | disallow: ACL_SET_SCHEMA,
44 | modify: ACL_SET_WITH_DEFAULT_SCHEMA,
45 | },
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/server/namespaces/core/info.js:
--------------------------------------------------------------------------------
1 | const INFO_SCHEMA = module.exports = {
2 | type: 'object',
3 | required: ['created', 'updated', 'created_by'],
4 | additionalProperties: false,
5 | properties: {
6 | created: {type: 'string'},
7 | updated: {type: 'string'},
8 | created_by: {type: 'string'},
9 | },
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/server/namespaces/core/namespace.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | type: 'object',
3 | additionalProperties: false,
4 | properties: {
5 | versions: {
6 | type: 'array',
7 | minItems: 1,
8 | items: {
9 | type: 'object',
10 | additionalProperties: false,
11 | properties: {
12 | version: {type: 'string'},
13 | types: {
14 | type: 'object',
15 | additionalProperties: {
16 | type: 'object',
17 | required: ['schema'],
18 | additionalProperties: false,
19 | properties: {
20 | schema: {$ref: '#/definitions/schema'},
21 | initial_acl: require('./acl'),
22 | }
23 | }
24 | }
25 | }
26 | }
27 | },
28 | },
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/server/namespaces/system/authorization_token.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | type: 'object',
3 | additionalProperties: false,
4 | properties: {
5 | username: {type: 'string'},
6 | token: {type: 'string'},
7 | expires: {type: 'string', format: 'date-time'},
8 | permissions: {
9 | type: 'object',
10 | additionalProperties: {
11 | type: 'array',
12 | items: {
13 | type: 'string',
14 | enum: ['read', 'write', 'append', 'delete', 'modify_acl', 'create'],
15 | }
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/server/namespaces/system/usage.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | type: 'object',
3 | additionalProperties: false,
4 | properties: {
5 | items: {type: 'integer', minimum: 0},
6 | namespaces: {
7 | type: 'array',
8 | items: {type: 'string'},
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/server/namespaces/system/user.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | type: 'object',
3 | properties: {
4 | publicKey: {type: 'string'},
5 | },
6 | additionalProperties: false,
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/server/namespaces/system/user_private.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | type: 'object',
3 | additionalProperties: false,
4 | properties: {
5 | id: {type: 'string'},
6 | email: {type: 'string'},
7 | hash: {type: 'string'},
8 | salt: {type: 'string'},
9 | email_confirmation: {
10 | type: 'object',
11 | additionalProperties: false,
12 | properties: {
13 | confirmed: {type: 'boolean'},
14 | code: {type: 'string'},
15 | expires: {type: 'string', format: 'date-time'},
16 | }
17 | },
18 | password_reset: {
19 | type: 'object',
20 | additionalProperties: false,
21 | properties: {
22 | code: {type: 'string'},
23 | expires: {type: 'string', format: 'date-time'},
24 | }
25 | },
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "onedb-server",
3 | "version": "0.3.3",
4 | "description": "",
5 | "main": "index.js",
6 | "engines": {
7 | "node": ">=8.0.0"
8 | },
9 | "scripts": {
10 | "test": "mocha --exit"
11 | },
12 | "author": "",
13 | "license": "MIT",
14 | "dependencies": {
15 | "ajv": "^6.5.1",
16 | "aws-sdk": "^2.292.0",
17 | "axios": "^0.18.0",
18 | "body-parser": "^1.18.3",
19 | "cors": "^2.8.4",
20 | "express": "^4.16.3",
21 | "express-rate-limit": "^2.11.0",
22 | "jsonwebtoken": "^8.3.0",
23 | "moment": "^2.22.2",
24 | "mongodb": "^3.1.6",
25 | "nodemailer": "^4.6.7",
26 | "pug": "^2.0.3",
27 | "randomstring": "^1.1.5",
28 | "redos": "^1.0.1",
29 | "validator": "^10.4.0",
30 | "yargs": "^12.0.1"
31 | },
32 | "devDependencies": {
33 | "chai": "^4.1.2",
34 | "chai-as-promised": "^7.1.1",
35 | "mocha": "^5.2.0",
36 | "mongodb-memory-server": "^1.9.3"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/server/test/db-util.js:
--------------------------------------------------------------------------------
1 | const expect = require('chai').expect;
2 | const util = require('../lib/db-util');
3 |
4 | describe('Util', () => {
5 | it('should encode document', () => {
6 | const schema = {
7 | foo: 'bar',
8 | $ref: 'abc',
9 | nested: {
10 | $ref: 'qux',
11 | },
12 | array: [{
13 | $ref: 'def',
14 | }]
15 | };
16 | const encoded = util.encodeDocument(schema);
17 | expect(encoded).to.deep.equal({
18 | foo: 'bar',
19 | '\uFF04ref': 'abc',
20 | nested: {
21 | '\uFF04ref': 'qux',
22 | },
23 | array: [{
24 | '\uFF04ref': 'def',
25 | }]
26 | });
27 | const decoded = util.decodeDocument(encoded);
28 | expect(decoded).to.deep.equal(schema);
29 | })
30 | })
31 |
--------------------------------------------------------------------------------
/server/web/views/layout.pug:
--------------------------------------------------------------------------------
1 | doctype html
2 | html
3 | head
4 | link(rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css")
5 | link(rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css")
6 | style.
7 | body {
8 | background-color: #eee;
9 | padding-top: 25px;
10 | }
11 | .btn {
12 | min-width: 150px;
13 | }
14 | .form {
15 | background-color: #fff;
16 | }
17 | script(
18 | src="https://code.jquery.com/jquery-3.3.1.min.js"
19 | integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
20 | crossorigin="anonymous")
21 | script(src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.bundle.min.js")
22 | block head
23 |
24 | body
25 | .container
26 | block body
27 |
--------------------------------------------------------------------------------
/server/web/views/reset_password.pug:
--------------------------------------------------------------------------------
1 | extends layout.pug
2 | block head
3 | script.
4 | var CODE = !{JSON.stringify(code || '')};
5 |
6 | function showError(msg) {
7 | $('.alert.alert-danger').text(msg).css('opacity', 1);
8 | }
9 |
10 | function hideError() {
11 | $('.alert.alert-danger').css('opacity', 0);
12 | }
13 |
14 | function showLoading() {
15 | $('button.btn-success').attr('disabled', true);
16 | $('button.btn-success span').hide();
17 | $('button.btn-success i.fa').show();
18 | }
19 |
20 | function hideLoading() {
21 | $('button.btn-success').attr('disabled', false);
22 | $('button.btn-success span').show();
23 | $('button.btn-success i.fa').hide();
24 | }
25 |
26 | function resetPassword() {
27 | hideError();
28 | var data = {code: CODE, newPassword: $('input[name="password"]').val()};
29 | var confirmPassword = $('input[name="confirmPassword"]').val();
30 | if (data.newPassword !== confirmPassword) {
31 | showError("Passwords don't match");
32 | return false;
33 | }
34 | showLoading();
35 | $.ajax({
36 | type: 'POST',
37 | url: '/users/reset_password',
38 | headers: {'Content-Type': 'application/json'},
39 | data: JSON.stringify(data),
40 | success: function(data) {
41 | hideLoading();
42 | $('.card').replaceWith('Your password has been successfully reset.
')
43 | },
44 | error: function(req, textStatus, error) {
45 | hideLoading();
46 | var message = textStatus;
47 | try {
48 | message = JSON.parse(req.responseText).message || message;
49 | } catch (e) {}
50 | showError(message);
51 | },
52 | })
53 | return false;
54 | }
55 |
56 | block body
57 | .row
58 | .col-12.col-md-6.offset-md-3
59 | .alert.alert-danger(style="opacity: 0")
60 | span
61 | .card
62 | .card-body
63 | h2.card-title Reset your password
64 | form(onsubmit="resetPassword(); return false")
65 | .form-group
66 | label New Password
67 | input.form-control(type="password" name="password")
68 | .form-group
69 | label Confirm Password
70 | input.form-control(type="password" name="confirmPassword")
71 | .form-group
72 | button.btn.btn-success(type="submit")
73 | i.fa.fa-spin.fa-refresh(style="display: none")
74 | span Reset Password
75 |
--------------------------------------------------------------------------------
/web/docs/LucyBot.yml:
--------------------------------------------------------------------------------
1 | favicon: assets/img/Icon.png
2 |
3 | routes:
4 | /:
5 | ui: documentation
6 | title: OneDB
7 | meta:
8 | title: OneDB Documentation
9 | description: Documentation for OneDB, an open source, decentralized backend-as-a-service
10 | keywords:
11 | - OneDB
12 | - documentation
13 | - open source
14 | - federated
15 | - decentralized
16 | - backend
17 | - frontend
18 | - backend as a service
19 | - BaaS
20 | navigation:
21 | - title: Introduction
22 | markdownFile: markdown/Overview.md
23 | - title: Create an App
24 | expand: true
25 | autoselect: true
26 | children:
27 | - title: Quickstart
28 | markdownFile: markdown/Quickstart.md
29 | - title: End-to-end Example
30 | markdownFile: markdown/End_to_End.md
31 | - markdownFile: markdown/Client_API.md
32 | - markdownFile: markdown/Data_Schemas.md
33 | - title: Authorization
34 | markdownFile: markdown/Authorization.md
35 | - title: Multiple Instances
36 | markdownFile: markdown/Multiple_Instances.md
37 | - title: Host an Instance
38 | markdownFile: markdown/Host_an_Instance.md
39 | - title: HTTP API
40 | markdownFile: markdown/HTTP.md
41 |
--------------------------------------------------------------------------------
/web/docs/assets/img/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/web/docs/assets/img/Icon.png
--------------------------------------------------------------------------------
/web/docs/assets/img/Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/web/docs/assets/img/Logo.png
--------------------------------------------------------------------------------
/web/docs/assets/img/quickstart_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/web/docs/assets/img/quickstart_screenshot.png
--------------------------------------------------------------------------------
/web/docs/markdown/Overview.md:
--------------------------------------------------------------------------------
1 | # OneDB
2 |
3 |
4 | 
5 |
6 |
Connect your frontend to the cloud. For free, forever.
7 |
8 |
9 | OneDB is an open source decentralized backend - it handles user authentication, data storage, and validation,
10 | so **you can focus on creating a beautiful user interface**.
11 |
12 | Anyone can host a OneDB instance, and end-users can decide where they want to store their data.
13 | This means **end-users have complete control and ownership** over their data. And by utilizing
14 | the existing network of OneDB instances, you can **deploy your app for free**, forever.
15 |
16 | We provide a OneDB instance at `one-db.datafire.io` which is free for developers. End-users can
17 | store up to 10MB of data before getting charged.
18 |
19 | For troubleshooting, comments, and ideas, [reach out to us on GitHub](https://github.com/DataFire/OneDB)
20 |
21 | ## Ready to get started?
22 |
23 | Check out [the Quickstart page](/Create_an_App/Quickstart) to learn how to create a minimal OneDB app,
24 | or head to [the End-to-end example](/Create_an_App/End_to_end_Example) for a more in-depth look at OneDB.
25 |
--------------------------------------------------------------------------------
/web/docs/styles/styles.css:
--------------------------------------------------------------------------------
1 | .main-container {
2 | padding-top: 50px;
3 | }
4 | @media(min-width:768px) {
5 | .side-menu {
6 | position: fixed;
7 | top: 50px;
8 | left: 15px;
9 | width: inherit;
10 | max-height: 90%;
11 | overflow-y: scroll;
12 | }
13 | .side-menu-col + .col-xs-12 {
14 | padding-left: 30px;
15 | }
16 | }
17 |
18 | .docs-contents {
19 | font-size: 16px;
20 | color: #555;
21 | }
22 |
23 | .docs-contents h1,
24 | .docs-contents h2,
25 | .docs-children h4 {
26 | margin-top: 60px;
27 | }
28 | .docs-contents h2:first-of-type {
29 | margin-top: 30px;
30 | }
31 |
32 | .docs-contents h1:first-of-type {
33 | display: none;
34 | }
35 |
36 | side-menu .btn {
37 | border-color: #ddd;
38 | }
39 |
40 | nav .navbar-brand {
41 | padding-top: 3px;
42 | }
43 |
44 | nav img {
45 | height: 36px;
46 | padding-top: 10px;
47 | float: left;
48 | margin-right: 10px;
49 | }
50 |
51 | thead {
52 | display: none;
53 | }
54 |
55 | pre {
56 | margin-bottom: 15px;
57 | }
58 |
--------------------------------------------------------------------------------
/web/docs/templates/navbar.html:
--------------------------------------------------------------------------------
1 |
10 |
16 |
30 |
--------------------------------------------------------------------------------
/web/homepage/img/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/web/homepage/img/Icon.png
--------------------------------------------------------------------------------
/web/homepage/img/Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/web/homepage/img/Logo.png
--------------------------------------------------------------------------------
/web/homepage/img/team/andrew.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/web/homepage/img/team/andrew.jpg
--------------------------------------------------------------------------------
/web/homepage/img/team/bob.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/web/homepage/img/team/bob.png
--------------------------------------------------------------------------------
/web/homepage/img/team/bobby.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/web/homepage/img/team/bobby.jpg
--------------------------------------------------------------------------------
/web/homepage/img/team/joe.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/web/homepage/img/team/joe.jpg
--------------------------------------------------------------------------------
/web/homepage/img/team/keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/web/homepage/img/team/keep
--------------------------------------------------------------------------------
/web/homepage/img/team/throop.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/web/homepage/img/team/throop.jpg
--------------------------------------------------------------------------------
/web/img/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/web/img/Icon.png
--------------------------------------------------------------------------------
/web/img/Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataFire/OneDB/18ac8a50ebd6345e348045cda791813b705aba30/web/img/Logo.png
--------------------------------------------------------------------------------