├── README.md
├── app.js
├── build
├── build.js
├── check-versions.js
├── dev-client.js
├── dev-server.js
├── utils.js
├── vue-loader.conf.js
├── webpack.base.conf.js
├── webpack.dev.conf.js
├── webpack.prod.conf.js
└── webpack.test.conf.js
├── config
├── dev.env.js
├── index.js
├── prod.env.js
└── test.env.js
├── contracts
├── immla.claims.sol
├── immla.deals.sol
├── immla.offers.sol
└── immla.utils.sol
├── dist
├── index.html
└── static
│ ├── css
│ ├── app.2db33b735b267b5d74c48a398e399adc.css
│ └── app.2db33b735b267b5d74c48a398e399adc.css.map
│ ├── immla-bg.png
│ ├── js
│ ├── app.1bfe6787ac5a4568f1a0.js
│ ├── app.1bfe6787ac5a4568f1a0.js.map
│ ├── manifest.82dccd34fac2fc9321cc.js
│ ├── manifest.82dccd34fac2fc9321cc.js.map
│ ├── vendor.824c427e2388497c1c41.js
│ └── vendor.824c427e2388497c1c41.js.map
│ ├── logo-mini.png
│ ├── logo.png
│ └── web3.min.js
├── index.html
├── mongo.js
├── package.json
├── src
├── App.vue
├── app
│ ├── modules
│ │ ├── auth
│ │ │ ├── actions.js
│ │ │ ├── auth.vue
│ │ │ ├── index.js
│ │ │ └── mutations.js
│ │ ├── form
│ │ │ ├── avatar.vue
│ │ │ └── form.vue
│ │ ├── main
│ │ │ └── main.vue
│ │ ├── offers
│ │ │ ├── actions.js
│ │ │ ├── index.js
│ │ │ ├── mutations.js
│ │ │ └── offers.vue
│ │ ├── orders
│ │ │ ├── actions.js
│ │ │ ├── index.js
│ │ │ ├── mutations.js
│ │ │ └── orders.vue
│ │ ├── profile
│ │ │ ├── actions.js
│ │ │ ├── index.js
│ │ │ ├── mutations.js
│ │ │ └── profile.vue
│ │ └── search
│ │ │ ├── actions.js
│ │ │ ├── cities.js
│ │ │ ├── index.js
│ │ │ ├── mutations.js
│ │ │ └── search.vue
│ ├── router
│ │ └── index.js
│ ├── select
│ │ ├── comp
│ │ │ └── Select.vue
│ │ └── mixins
│ │ │ ├── ajax.js
│ │ │ ├── index.js
│ │ │ ├── pointerScroll.js
│ │ │ └── typeAheadPointer.js
│ ├── store
│ │ └── index.js
│ └── uikit
│ │ └── application.scss
└── main.js
├── static
├── .gitkeep
├── immla-bg.png
├── logo-mini.png
├── logo.png
└── web3.min.js
├── test
├── e2e
│ ├── custom-assertions
│ │ └── elementCount.js
│ ├── nightwatch.conf.js
│ ├── runner.js
│ └── specs
│ │ └── test.js
└── unit
│ ├── .eslintrc
│ ├── index.js
│ ├── karma.conf.js
│ └── specs
│ └── Hello.spec.js
└── usersStorage.js
/README.md:
--------------------------------------------------------------------------------
1 | #### Setup of the prototype
2 |
3 | Start in prod mode:
4 |
5 | ```
6 | node app.js
7 | ```
8 |
9 | Dev commands:
10 |
11 | ``` bash
12 | # install dependencies
13 | npm install
14 |
15 | # serve with hot reload at localhost:8080
16 | npm run dev
17 |
18 | # build for production with minification
19 | npm run build
20 |
21 | # build for production and view the bundle analyzer report
22 | npm run build --report
23 |
24 | # run unit tests
25 | npm run unit
26 |
27 | # run e2e tests
28 | npm run e2e
29 |
30 | # run all tests
31 | npm test
32 | ```
33 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | let port = 5005;
2 | let express = require('express');
3 | let app = express();
4 | var http = require('http').Server(app);
5 | let usersStorage = require("./usersStorage");
6 |
7 | let bodyParser = require('body-parser');
8 | app.use(bodyParser.urlencoded({ extended: false }));
9 | app.use(bodyParser.json());
10 | app.use(express.static('dist'));
11 | // app.use(express.static('static'));
12 |
13 | app.use('/test', function root(req, res) {
14 | res.json({ "success": true });
15 | });
16 |
17 | app.use('/auth/register', function root(req, res) {
18 | console.log("Request for register");
19 | let user = {
20 | id: req.body.id,
21 | email: req.body.email,
22 | password: req.body.password,
23 | type: req.body.type,
24 | pubkey: req.body.pubkey
25 | };
26 | usersStorage.saveUser(user).then((result) => {
27 | res.json(result);
28 | });
29 | });
30 |
31 | app.use('/auth/check', function root(req, res) {
32 | let token = req.query.token;
33 | usersStorage.getUserByToken(token).then((answer) => {
34 | if(answer == null) {
35 | return res.json({success: false, message: "token is not valid"});
36 | }
37 | else {
38 | answer.password = "---";
39 | return res.json({success: true, user: answer});
40 | }
41 | });
42 | });
43 |
44 | app.use('/auth/about', function root(req, res) {
45 | let id = req.query.id;
46 | usersStorage.getUserById(id).then((answer) => {
47 | if(answer == null) {
48 | return res.json({success: false, message: "not found"});
49 | }
50 | else {
51 | answer.password = "---";
52 | answer.token = "---";
53 | return res.json({success: true, user: answer});
54 | }
55 | });
56 | });
57 |
58 | app.use('/auth/aboutkeys', function root(req, res) {
59 | let pubkeys = req.body.pubkeys;
60 | console.log("Request for user by keys");
61 | usersStorage.getUsersByPubkeys(pubkeys).then((users) => {
62 | if(users == null) {
63 |
64 | return res.json({success: false, message: "not found anything"});
65 | }
66 | else {
67 | let result = users.map((user) => {
68 | user.password = "---";
69 | user.token = "---";
70 | return user;
71 | });
72 | return res.json({success: true, users: result});
73 | }
74 | });
75 | });
76 |
77 | app.use('/auth/login', function root(req, res) {
78 | console.log('Login request');
79 | usersStorage.login(req.body.id, req.body.password).then((result) => {
80 | res.json(result);
81 | });
82 | });
83 |
84 | http.listen(port, function() {
85 | console.log('listening on *:' + port);
86 | });
87 |
--------------------------------------------------------------------------------
/build/build.js:
--------------------------------------------------------------------------------
1 | require('./check-versions')()
2 |
3 | process.env.NODE_ENV = 'production'
4 |
5 | var ora = require('ora')
6 | var rm = require('rimraf')
7 | var path = require('path')
8 | var chalk = require('chalk')
9 | var webpack = require('webpack')
10 | var config = require('../config')
11 | var webpackConfig = require('./webpack.prod.conf')
12 |
13 | var spinner = ora('building for production...')
14 | spinner.start()
15 |
16 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
17 | if (err) throw err
18 | webpack(webpackConfig, function (err, stats) {
19 | spinner.stop()
20 | if (err) throw err
21 | process.stdout.write(stats.toString({
22 | colors: true,
23 | modules: false,
24 | children: false,
25 | chunks: false,
26 | chunkModules: false
27 | }) + '\n\n')
28 |
29 | console.log(chalk.cyan(' Build complete.\n'))
30 | console.log(chalk.yellow(
31 | ' Tip: built files are meant to be served over an HTTP server.\n' +
32 | ' Opening index.html over file:// won\'t work.\n'
33 | ))
34 | })
35 | })
36 |
--------------------------------------------------------------------------------
/build/check-versions.js:
--------------------------------------------------------------------------------
1 | var chalk = require('chalk')
2 | var semver = require('semver')
3 | var packageConfig = require('../package.json')
4 | var shell = require('shelljs')
5 | function exec (cmd) {
6 | return require('child_process').execSync(cmd).toString().trim()
7 | }
8 |
9 | var versionRequirements = [
10 | {
11 | name: 'node',
12 | currentVersion: semver.clean(process.version),
13 | versionRequirement: packageConfig.engines.node
14 | },
15 | ]
16 |
17 | if (shell.which('npm')) {
18 | versionRequirements.push({
19 | name: 'npm',
20 | currentVersion: exec('npm --version'),
21 | versionRequirement: packageConfig.engines.npm
22 | })
23 | }
24 |
25 | module.exports = function () {
26 | var warnings = []
27 | for (var i = 0; i < versionRequirements.length; i++) {
28 | var mod = versionRequirements[i]
29 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
30 | warnings.push(mod.name + ': ' +
31 | chalk.red(mod.currentVersion) + ' should be ' +
32 | chalk.green(mod.versionRequirement)
33 | )
34 | }
35 | }
36 |
37 | if (warnings.length) {
38 | console.log('')
39 | console.log(chalk.yellow('To use this template, you must update following to modules:'))
40 | console.log()
41 | for (var i = 0; i < warnings.length; i++) {
42 | var warning = warnings[i]
43 | console.log(' ' + warning)
44 | }
45 | console.log()
46 | process.exit(1)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/build/dev-client.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | require('eventsource-polyfill')
3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
4 |
5 | hotClient.subscribe(function (event) {
6 | if (event.action === 'reload') {
7 | window.location.reload()
8 | }
9 | })
10 |
--------------------------------------------------------------------------------
/build/dev-server.js:
--------------------------------------------------------------------------------
1 | require('./check-versions')()
2 |
3 | var config = require('../config')
4 | if (!process.env.NODE_ENV) {
5 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
6 | }
7 |
8 | var opn = require('opn')
9 | var path = require('path')
10 | var express = require('express')
11 | var webpack = require('webpack')
12 | var proxyMiddleware = require('http-proxy-middleware')
13 | var webpackConfig = process.env.NODE_ENV === 'testing'
14 | ? require('./webpack.prod.conf')
15 | : require('./webpack.dev.conf')
16 |
17 | // default port where dev server listens for incoming traffic
18 | var port = process.env.PORT || config.dev.port
19 | // automatically open browser, if not set will be false
20 | var autoOpenBrowser = !!config.dev.autoOpenBrowser
21 | // Define HTTP proxies to your custom API backend
22 | // https://github.com/chimurai/http-proxy-middleware
23 | var proxyTable = config.dev.proxyTable
24 |
25 | var app = express()
26 | var compiler = webpack(webpackConfig)
27 |
28 | var devMiddleware = require('webpack-dev-middleware')(compiler, {
29 | publicPath: webpackConfig.output.publicPath,
30 | quiet: true
31 | })
32 |
33 | var hotMiddleware = require('webpack-hot-middleware')(compiler, {
34 | log: () => {},
35 | heartbeat: 2000
36 | })
37 | // force page reload when html-webpack-plugin template changes
38 | compiler.plugin('compilation', function (compilation) {
39 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
40 | hotMiddleware.publish({ action: 'reload' })
41 | cb()
42 | })
43 | })
44 |
45 | // proxy api requests
46 | Object.keys(proxyTable).forEach(function (context) {
47 | var options = proxyTable[context]
48 | if (typeof options === 'string') {
49 | options = { target: options }
50 | }
51 | app.use(proxyMiddleware(options.filter || context, options))
52 | })
53 |
54 | // handle fallback for HTML5 history API
55 | app.use(require('connect-history-api-fallback')())
56 |
57 | // serve webpack bundle output
58 | app.use(devMiddleware)
59 |
60 | // enable hot-reload and state-preserving
61 | // compilation error display
62 | app.use(hotMiddleware)
63 |
64 | // serve pure static assets
65 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
66 | app.use(staticPath, express.static('./static'))
67 |
68 | var uri = 'http://localhost:' + port
69 |
70 | var _resolve
71 | var readyPromise = new Promise(resolve => {
72 | _resolve = resolve
73 | })
74 |
75 | console.log('> Starting dev server...')
76 | devMiddleware.waitUntilValid(() => {
77 | console.log('> Listening at ' + uri + '\n')
78 | // when env is testing, don't need open it
79 | if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
80 | opn(uri)
81 | }
82 | _resolve()
83 | })
84 |
85 | var server = app.listen(port)
86 |
87 | module.exports = {
88 | ready: readyPromise,
89 | close: () => {
90 | server.close()
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/build/utils.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var config = require('../config')
3 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
4 |
5 | exports.assetsPath = function (_path) {
6 | var assetsSubDirectory = process.env.NODE_ENV === 'production'
7 | ? config.build.assetsSubDirectory
8 | : config.dev.assetsSubDirectory
9 | return path.posix.join(assetsSubDirectory, _path)
10 | }
11 |
12 | exports.cssLoaders = function (options) {
13 | options = options || {}
14 |
15 | var cssLoader = {
16 | loader: 'css-loader',
17 | options: {
18 | minimize: process.env.NODE_ENV === 'production',
19 | sourceMap: options.sourceMap
20 | }
21 | }
22 |
23 | // generate loader string to be used with extract text plugin
24 | function generateLoaders (loader, loaderOptions) {
25 | var loaders = [cssLoader]
26 | if (loader) {
27 | loaders.push({
28 | loader: loader + '-loader',
29 | options: Object.assign({}, loaderOptions, {
30 | sourceMap: options.sourceMap
31 | })
32 | })
33 | }
34 |
35 | // Extract CSS when that option is specified
36 | // (which is the case during production build)
37 | if (options.extract) {
38 | return ExtractTextPlugin.extract({
39 | use: loaders,
40 | fallback: 'vue-style-loader'
41 | })
42 | } else {
43 | return ['vue-style-loader'].concat(loaders)
44 | }
45 | }
46 |
47 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html
48 | return {
49 | css: generateLoaders(),
50 | postcss: generateLoaders(),
51 | less: generateLoaders('less'),
52 | sass: generateLoaders('sass', { indentedSyntax: true }),
53 | scss: generateLoaders('sass'),
54 | stylus: generateLoaders('stylus'),
55 | styl: generateLoaders('stylus')
56 | }
57 | }
58 |
59 | // Generate loaders for standalone style files (outside of .vue)
60 | exports.styleLoaders = function (options) {
61 | var output = []
62 | var loaders = exports.cssLoaders(options)
63 | for (var extension in loaders) {
64 | var loader = loaders[extension]
65 | output.push({
66 | test: new RegExp('\\.' + extension + '$'),
67 | use: loader
68 | })
69 | }
70 | return output
71 | }
72 |
--------------------------------------------------------------------------------
/build/vue-loader.conf.js:
--------------------------------------------------------------------------------
1 | var utils = require('./utils')
2 | var config = require('../config')
3 | var isProduction = process.env.NODE_ENV === 'production'
4 |
5 | module.exports = {
6 | loaders: utils.cssLoaders({
7 | sourceMap: isProduction
8 | ? config.build.productionSourceMap
9 | : config.dev.cssSourceMap,
10 | extract: isProduction
11 | }),
12 | transformToRequire: {
13 | video: 'src',
14 | source: 'src',
15 | img: 'src',
16 | image: 'xlink:href'
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/build/webpack.base.conf.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var utils = require('./utils')
3 | var config = require('../config')
4 | var vueLoaderConfig = require('./vue-loader.conf')
5 |
6 | function resolve (dir) {
7 | return path.join(__dirname, '..', dir)
8 | }
9 |
10 | module.exports = {
11 | entry: {
12 | app: './src/main.js'
13 | },
14 | output: {
15 | path: config.build.assetsRoot,
16 | filename: '[name].js',
17 | publicPath: process.env.NODE_ENV === 'production'
18 | ? config.build.assetsPublicPath
19 | : config.dev.assetsPublicPath
20 | },
21 | resolve: {
22 | extensions: ['.js', '.vue', '.json'],
23 | alias: {
24 | 'vue$': 'vue/dist/vue.esm.js',
25 | '@': resolve('src')
26 | }
27 | },
28 | module: {
29 | rules: [
30 | // {
31 | // test: /\.(js|vue)$/,
32 | // loader: 'eslint-loader',
33 | // enforce: 'pre',
34 | // include: [resolve('src'), resolve('test')],
35 | // options: {
36 | // formatter: require('eslint-friendly-formatter')
37 | // }
38 | // },
39 | {
40 | test: /\.vue$/,
41 | loader: 'vue-loader',
42 | options: vueLoaderConfig
43 | },
44 | {
45 | test: /\.js$/,
46 | loader: 'babel-loader',
47 | include: [resolve('src'), resolve('test')]
48 | },
49 | {
50 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
51 | loader: 'url-loader',
52 | options: {
53 | limit: 10000,
54 | name: utils.assetsPath('img/[name].[hash:7].[ext]')
55 | }
56 | },
57 | {
58 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
59 | loader: 'url-loader',
60 | options: {
61 | limit: 10000,
62 | name: utils.assetsPath('media/[name].[hash:7].[ext]')
63 | }
64 | },
65 | {
66 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
67 | loader: 'url-loader',
68 | options: {
69 | limit: 10000,
70 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
71 | }
72 | }
73 | ]
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/build/webpack.dev.conf.js:
--------------------------------------------------------------------------------
1 | var utils = require('./utils')
2 | var webpack = require('webpack')
3 | var config = require('../config')
4 | var merge = require('webpack-merge')
5 | var baseWebpackConfig = require('./webpack.base.conf')
6 | var HtmlWebpackPlugin = require('html-webpack-plugin')
7 | var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
8 |
9 | // add hot-reload related code to entry chunks
10 | Object.keys(baseWebpackConfig.entry).forEach(function (name) {
11 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
12 | })
13 |
14 | module.exports = merge(baseWebpackConfig, {
15 | module: {
16 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
17 | },
18 | // cheap-module-eval-source-map is faster for development
19 | devtool: '#cheap-module-eval-source-map',
20 | plugins: [
21 | new webpack.DefinePlugin({
22 | 'process.env': config.dev.env
23 | }),
24 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
25 | new webpack.HotModuleReplacementPlugin(),
26 | new webpack.NoEmitOnErrorsPlugin(),
27 | // https://github.com/ampedandwired/html-webpack-plugin
28 | new HtmlWebpackPlugin({
29 | filename: 'index.html',
30 | template: 'index.html',
31 | inject: true
32 | }),
33 | new FriendlyErrorsPlugin()
34 | ]
35 | })
36 |
--------------------------------------------------------------------------------
/build/webpack.prod.conf.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var utils = require('./utils')
3 | var webpack = require('webpack')
4 | var config = require('../config')
5 | var merge = require('webpack-merge')
6 | var baseWebpackConfig = require('./webpack.base.conf')
7 | var CopyWebpackPlugin = require('copy-webpack-plugin')
8 | var HtmlWebpackPlugin = require('html-webpack-plugin')
9 | var ExtractTextPlugin = require('extract-text-webpack-plugin')
10 | var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
11 |
12 | var env = process.env.NODE_ENV === 'testing'
13 | ? require('../config/test.env')
14 | : config.build.env
15 |
16 | var webpackConfig = merge(baseWebpackConfig, {
17 | module: {
18 | rules: utils.styleLoaders({
19 | sourceMap: config.build.productionSourceMap,
20 | extract: true
21 | })
22 | },
23 | devtool: config.build.productionSourceMap ? '#source-map' : false,
24 | output: {
25 | path: config.build.assetsRoot,
26 | filename: utils.assetsPath('js/[name].[chunkhash].js'),
27 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
28 | },
29 | plugins: [
30 | // http://vuejs.github.io/vue-loader/en/workflow/production.html
31 | new webpack.DefinePlugin({
32 | 'process.env': env
33 | }),
34 | new webpack.optimize.UglifyJsPlugin({
35 | compress: {
36 | warnings: false
37 | },
38 | sourceMap: true
39 | }),
40 | // extract css into its own file
41 | new ExtractTextPlugin({
42 | filename: utils.assetsPath('css/[name].[contenthash].css')
43 | }),
44 | // Compress extracted CSS. We are using this plugin so that possible
45 | // duplicated CSS from different components can be deduped.
46 | new OptimizeCSSPlugin({
47 | cssProcessorOptions: {
48 | safe: true
49 | }
50 | }),
51 | // generate dist index.html with correct asset hash for caching.
52 | // you can customize output by editing /index.html
53 | // see https://github.com/ampedandwired/html-webpack-plugin
54 | new HtmlWebpackPlugin({
55 | filename: process.env.NODE_ENV === 'testing'
56 | ? 'index.html'
57 | : config.build.index,
58 | template: 'index.html',
59 | inject: true,
60 | minify: {
61 | removeComments: true,
62 | collapseWhitespace: true,
63 | removeAttributeQuotes: true
64 | // more options:
65 | // https://github.com/kangax/html-minifier#options-quick-reference
66 | },
67 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin
68 | chunksSortMode: 'dependency'
69 | }),
70 | // split vendor js into its own file
71 | new webpack.optimize.CommonsChunkPlugin({
72 | name: 'vendor',
73 | minChunks: function (module, count) {
74 | // any required modules inside node_modules are extracted to vendor
75 | return (
76 | module.resource &&
77 | /\.js$/.test(module.resource) &&
78 | module.resource.indexOf(
79 | path.join(__dirname, '../node_modules')
80 | ) === 0
81 | )
82 | }
83 | }),
84 | // extract webpack runtime and module manifest to its own file in order to
85 | // prevent vendor hash from being updated whenever app bundle is updated
86 | new webpack.optimize.CommonsChunkPlugin({
87 | name: 'manifest',
88 | chunks: ['vendor']
89 | }),
90 | // copy custom static assets
91 | new CopyWebpackPlugin([
92 | {
93 | from: path.resolve(__dirname, '../static'),
94 | to: config.build.assetsSubDirectory,
95 | ignore: ['.*']
96 | }
97 | ])
98 | ]
99 | })
100 |
101 | if (config.build.productionGzip) {
102 | var CompressionWebpackPlugin = require('compression-webpack-plugin')
103 |
104 | webpackConfig.plugins.push(
105 | new CompressionWebpackPlugin({
106 | asset: '[path].gz[query]',
107 | algorithm: 'gzip',
108 | test: new RegExp(
109 | '\\.(' +
110 | config.build.productionGzipExtensions.join('|') +
111 | ')$'
112 | ),
113 | threshold: 10240,
114 | minRatio: 0.8
115 | })
116 | )
117 | }
118 |
119 | if (config.build.bundleAnalyzerReport) {
120 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
121 | webpackConfig.plugins.push(new BundleAnalyzerPlugin())
122 | }
123 |
124 | module.exports = webpackConfig
125 |
--------------------------------------------------------------------------------
/build/webpack.test.conf.js:
--------------------------------------------------------------------------------
1 | // This is the webpack config used for unit tests.
2 |
3 | var utils = require('./utils')
4 | var webpack = require('webpack')
5 | var merge = require('webpack-merge')
6 | var baseConfig = require('./webpack.base.conf')
7 |
8 | var webpackConfig = merge(baseConfig, {
9 | // use inline sourcemap for karma-sourcemap-loader
10 | module: {
11 | rules: utils.styleLoaders()
12 | },
13 | devtool: '#inline-source-map',
14 | resolveLoader: {
15 | alias: {
16 | // necessary to to make lang="scss" work in test when using vue-loader's ?inject option
17 | // see discussion at https://github.com/vuejs/vue-loader/issues/724
18 | 'scss-loader': 'sass-loader'
19 | }
20 | },
21 | plugins: [
22 | new webpack.DefinePlugin({
23 | 'process.env': require('../config/test.env')
24 | })
25 | ]
26 | })
27 |
28 | // no need for app entry during tests
29 | delete webpackConfig.entry
30 |
31 | module.exports = webpackConfig
32 |
--------------------------------------------------------------------------------
/config/dev.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var prodEnv = require('./prod.env')
3 |
4 | module.exports = merge(prodEnv, {
5 | NODE_ENV: '"development"'
6 | })
7 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | // see http://vuejs-templates.github.io/webpack for documentation.
2 | var path = require('path')
3 |
4 | module.exports = {
5 | build: {
6 | env: require('./prod.env'),
7 | index: path.resolve(__dirname, '../dist/index.html'),
8 | assetsRoot: path.resolve(__dirname, '../dist'),
9 | assetsSubDirectory: 'static',
10 | assetsPublicPath: '/',
11 | productionSourceMap: true,
12 | // Gzip off by default as many popular static hosts such as
13 | // Surge or Netlify already gzip all static assets for you.
14 | // Before setting to `true`, make sure to:
15 | // npm install --save-dev compression-webpack-plugin
16 | productionGzip: false,
17 | productionGzipExtensions: ['js', 'css'],
18 | // Run the build command with an extra argument to
19 | // View the bundle analyzer report after build finishes:
20 | // `npm run build --report`
21 | // Set to `true` or `false` to always turn it on or off
22 | bundleAnalyzerReport: process.env.npm_config_report
23 | },
24 | dev: {
25 | env: require('./dev.env'),
26 | port: 8081,
27 | autoOpenBrowser: true,
28 | assetsSubDirectory: 'static',
29 | assetsPublicPath: '/',
30 | proxyTable: {
31 | '/auth': {
32 | target: 'http://localhost:5000'
33 | // changeOrigin: true,
34 | // pathRewrite: {
35 | // '/auth': ''
36 | // }
37 | }
38 | },
39 | // CSS Sourcemaps off by default because relative paths are "buggy"
40 | // with this option, according to the CSS-Loader README
41 | // (https://github.com/webpack/css-loader#sourcemaps)
42 | // In our experience, they generally work as expected,
43 | // just be aware of this issue when enabling this option.
44 | cssSourceMap: false
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/config/prod.env.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | NODE_ENV: '"production"'
3 | }
4 |
--------------------------------------------------------------------------------
/config/test.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var devEnv = require('./dev.env')
3 |
4 | module.exports = merge(devEnv, {
5 | NODE_ENV: '"testing"'
6 | })
7 |
--------------------------------------------------------------------------------
/contracts/immla.claims.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.4.15;
2 |
3 | contract ClaimInterface {
4 |
5 | function getType() constant returns (string _type);
6 | function getDetails() constant returns (string _why);
7 | function getInitiator() constant returns (address _who);
8 | }
9 |
10 | contract DamageClaim is ClaimInterface {
11 |
12 | string private constant CLAIM_TYPE = "DAMAGE";
13 |
14 | address private owned;
15 | string private details;
16 |
17 | function DamageClaim(string _details) {
18 | details = _details;
19 | owned = msg.sender;
20 | }
21 |
22 | function getType() public constant
23 | returns (string _type) {
24 | return CLAIM_TYPE;
25 | }
26 |
27 | function getDetails() public constant
28 | returns (string _why) {
29 | return details;
30 | }
31 |
32 | function getInitiator() public constant
33 | returns (address _who) {
34 | return owned;
35 | }
36 | }
--------------------------------------------------------------------------------
/contracts/immla.deals.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.4.15;
2 |
3 | import "./immla.utils.sol";
4 | import "./immla.offers.sol";
5 |
6 | /* @title - Deal between Client and Supplier */
7 | contract Deal is LiveCycle {
8 |
9 | using Preconditions for *;
10 |
11 | Offer public offer;
12 | address public customer;
13 |
14 | byte constant public SUPPLIER = 0x1;
15 | byte constant public CLIENT = 0x2;
16 |
17 | byte public status = byte(0);
18 |
19 | ClaimInterface private recallClaim;
20 |
21 | /**
22 | * @dev - new deal instance between Client and Supplier
23 | *
24 | * TODO need to change customer to 'Order'
25 | */
26 | function Deal(address _customer, Offer _offer) {
27 | require(!_offer.isInvalidAddr() && _offer.isRunning());
28 | require(!_customer.isInvalidAddr());
29 |
30 | offer = _offer;
31 | customer = _customer;
32 |
33 | // default state is Running
34 | changeState(Running);
35 | }
36 |
37 | /* @dev - get joint Deal content */
38 | function getData() public constant
39 | returns (address, address, bool, byte) {
40 | return (offer, customer, isCompleted(), status);
41 | }
42 |
43 | /* @dev - complete the Order by the Supplier side */
44 | function compete() public
45 | atState(Running)
46 | only(offer.getOwner())
47 | {
48 | status |= SUPPLIER;
49 | if(isCompleted()) {
50 | changeState(Paused);
51 | close();
52 | }
53 | }
54 |
55 | /* @dev - complete the Order by the Client side */
56 | function confirm() public
57 | atState(Running)
58 | only(customer)
59 | {
60 | status |= CLIENT;
61 | if(isCompleted()) {
62 | changeState(Paused);
63 | close();
64 | }
65 | }
66 |
67 | /* @dev - check is Order is completed */
68 | function isCompleted() public constant
69 | returns (bool) {
70 | return (status == (SUPPLIER | CLIENT));
71 | }
72 |
73 | /**
74 | * @dev recall the deal by some reasons
75 | * @param _recallClaim reason why the Deal was closed
76 | */
77 | function recall(ClaimInterface _recallClaim) public
78 | atState(Running|Paused)
79 | anyOfTwo([offer.getOwner(), customer])
80 | {
81 | require(!_recallClaim.isInvalidAddr());
82 | recallClaim = _recallClaim;
83 | interrupt();
84 | }
85 |
86 | /* @dev - Get details why Offer was closed */
87 | function getRecallClaim() public constant
88 | atState(Interrupted)
89 | returns(ClaimInterface) {
90 | return recallClaim;
91 | }
92 |
93 | /* @dev - direct change state is not allowed */
94 | function switchTo(byte _state) public { revert(); }
95 |
96 | // Contact Modifiers
97 | modifier only(address _who) {
98 | require(!_who.isInvalidAddr());
99 | require(msg.sender == _who);
100 | _;
101 | }
102 |
103 | modifier anyOfTwo(address[2] memory _who) {
104 | bool res = false;
105 | for(uint i = 0; i < _who.length; i++) {
106 | require(!_who[i].isInvalidAddr());
107 | if(msg.sender == _who[i]) {
108 | res = true;
109 | break;
110 | }
111 | }
112 | if(!res) revert();
113 | _;
114 | }
115 | }
116 |
117 | /* @title - Registry of the created Deals */
118 | contract DealsRegistry {
119 |
120 | using Preconditions for *;
121 |
122 | mapping(address => Deal[]) private byOwners;
123 | mapping(address => Deal[]) private bySuppliers;
124 |
125 | function DealsRegistry() {}
126 |
127 | function newDeal(Offer _offer) public {
128 | require(!_offer.isInvalidAddr());
129 |
130 | Deal deal = new Deal(msg.sender, _offer);
131 | require(!deal.isInvalidAddr());
132 |
133 | bySuppliers[_offer.getOwner()].push(deal);
134 | byOwners[msg.sender].push(deal);
135 | }
136 |
137 | function getMyOwnedDeal(uint _pos) public constant
138 | returns (Deal) {
139 | require(byOwners[msg.sender].length > _pos);
140 | return byOwners[msg.sender][_pos];
141 | }
142 |
143 | function getMyOwnedDeals() public constant
144 | returns (Deal[]) {
145 | return byOwners[msg.sender];
146 | }
147 |
148 | function getMyOwnedDealCount() public constant
149 | returns (uint) {
150 | return byOwners[msg.sender].length;
151 | }
152 |
153 | function getMySupplyingDeal(uint _pos) public constant
154 | returns (Deal) {
155 | require(bySuppliers[msg.sender].length > _pos);
156 | return bySuppliers[msg.sender][_pos];
157 | }
158 |
159 | function getMySupplyingDeals() public constant
160 | returns (Deal[]) {
161 | return bySuppliers[msg.sender];
162 | }
163 |
164 | function getMySupplyingDealCount() public constant
165 | returns (uint) {
166 | return bySuppliers[msg.sender].length;
167 | }
168 | }
--------------------------------------------------------------------------------
/contracts/immla.offers.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.4.15;
2 |
3 | import './immla.utils.sol';
4 | import './immla.claims.sol';
5 |
6 | contract Offer is AC, LiveCycle {
7 |
8 | address private supplier;
9 |
10 | string public details;
11 | string public from;
12 | string public to;
13 |
14 | /**
15 | * @dev - The new Offer
16 | * @param _supplier Offer's real owner (supplier)
17 | * @param _manager administrative person responsible for the Offer management
18 | * @param _details additional Offer's params (e.g cost, some sort of data)
19 | * @param _from Offer's route source
20 | * @param _to Offer's route destination
21 | *
22 | * NOTE The Offer's owner is a OffersRegistry, it allows to prevet not sync
23 | * data if supplier will be changed by some reasons (e.g lost keys)
24 | */
25 | function Offer(
26 | address _supplier,
27 | address _manager,
28 | string _details,
29 | string _from,
30 | string _to
31 | )
32 | AC(_manager)
33 | {
34 | supplier = _supplier;
35 | details = _details;
36 | from = _from;
37 | to = _to;
38 | state = Running;
39 | }
40 |
41 | /* @dev - get joint Offer content */
42 | function getData() public constant
43 | returns (address, string, string, string, byte) {
44 | return (supplier, details, from, to, state);
45 | }
46 |
47 | /* @dev - get the Offer's owner (supplier) */
48 | function getOwner() public constant
49 | returns (address) {
50 | return supplier;
51 | }
52 |
53 | /* @dev - get the Offer's manager */
54 | function getManager() public constant
55 | returns(address) {
56 | return manager;
57 | }
58 |
59 | /**
60 | * @dev - Update Offer's details.
61 | * Method emits LogUpdated
62 | * @param _details Json with list of the Offer's options
63 | *
64 | * NOTE Method can be invoked only by Offer's Manager at 'Paused' state
65 | */
66 | function update(string _details) public
67 | atState(Paused)
68 | onlyManager
69 | {
70 | details = _details;
71 | LogUpdated(msg.sender, details);
72 | }
73 |
74 | /**
75 | * @dev - change Offer's state.
76 | * list of available states can find in LiveCycle
77 | * @param _state new state
78 | *
79 | * NOTE Method can be invoked only by Offer's Manager at non final states
80 | */
81 | function switchTo(byte _state) public
82 | atState(Running|Paused)
83 | onlyManager
84 | {
85 | changeState(_state);
86 | }
87 |
88 | /* @dev - close the Offer */
89 | function recall() public
90 | atState(Paused)
91 | onlyManager
92 | {
93 | close();
94 | }
95 |
96 | /* @dev - manager changing is not allowed yet */
97 | function changeManager(address _manager) public { revert(); }
98 |
99 | // Contract Events
100 | event LogUpdated(address _who, string _what);
101 | }
102 |
103 | /* @title - cache of the newest Offers */
104 | contract OffersCache {
105 |
106 | using Preconditions for *;
107 |
108 | uint public constant MAX_DEPTH = 20;
109 | uint private top = MAX_DEPTH;
110 | uint private currentDepth = 0;
111 |
112 | Offer[] cache;
113 |
114 | function OffersCache() {
115 | cache = new Offer[](MAX_DEPTH);
116 | }
117 |
118 | function push(Offer _offer) internal {
119 | require(!_offer.isInvalidAddr());
120 |
121 | if(++top >= MAX_DEPTH) {
122 | top = 0;
123 | }
124 | if(currentDepth < MAX_DEPTH)
125 | currentDepth++;
126 | cache[top] = _offer;
127 | }
128 |
129 | function peek(uint _maxDepth) public constant
130 | returns(Offer[]) {
131 | require(currentDepth > 0);
132 | require((_maxDepth <= MAX_DEPTH) && (_maxDepth > 0));
133 |
134 | uint recordsCount = (currentDepth < _maxDepth)
135 | ? currentDepth : _maxDepth;
136 |
137 | Offer[] memory res = new Offer[](recordsCount);
138 | for(uint8 i = 0; i < recordsCount; i++)
139 | res[i] = cache[i];
140 |
141 | return res;
142 | }
143 |
144 | function peekTop() public constant
145 | returns(Offer) {
146 | return cache[top];
147 | }
148 | }
149 |
150 | /* @title - Offers management Contact */
151 | contract OffersRegistry is OffersCache {
152 |
153 | mapping(uint => Offer[]) private byRoute;
154 | mapping(address => Offer[]) private bySupplier;
155 |
156 | function OffersRegistry() {}
157 |
158 | using Preconditions for *;
159 |
160 | /**
161 | * @dev - Create new offers depends where
162 | * src and dst are the keys for further filtering
163 | *
164 | * TODO Contract needs to prevent access to entity other
165 | * than Suppliers
166 | */
167 | function newOffer(
168 | string _details,
169 | string _from,
170 | string _to
171 | )
172 | public
173 | //TODO: add AC
174 | {
175 | require(!_details.isEmpty());
176 | require(!_from.isEmpty() && !_to.isEqual(_from));
177 |
178 | //TODO: supplier ID and manager have to be recieved from the SuppliersRegistry
179 | address supplier = msg.sender;
180 | address manager = msg.sender;
181 |
182 | Offer offer = new Offer(supplier, manager, _details, _from, _to);
183 | require(!offer.isInvalidAddr());
184 |
185 | uint route = uint(keccak256(_from, _to));
186 | byRoute[route].push(offer);
187 | bySupplier[supplier].push(offer);
188 |
189 | push(offer);
190 | LogNewOffer(offer);
191 | }
192 |
193 | function getOffers() public constant
194 | returns (Offer[]) {
195 | return bySupplier[msg.sender];
196 | }
197 |
198 | function getBySupplier(address _supplier) public constant
199 | returns (Offer[]) {
200 | require(!_supplier.isInvalidAddr());
201 | return bySupplier[_supplier];
202 | }
203 |
204 | function getByRoute(string _from, string _to) public constant
205 | returns (Offer[]) {
206 | require(!_from.isEmpty() && !_to.isEqual(_from));
207 |
208 | uint route = uint(keccak256(_from, _to));
209 | return byRoute[route];
210 | }
211 |
212 | // Contract Events
213 | event LogNewOffer(Offer _offer);
214 | }
215 |
--------------------------------------------------------------------------------
/contracts/immla.utils.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.4.15;
2 |
3 |
4 | /* @title - Access control utilities */
5 | contract AC {
6 |
7 | /**
8 | * @dev - Contract provides roles management and access control.
9 | * There are 2 roles: owner - creator of the contract and
10 | * manager - person who is responsible for administrative facilities.
11 | *
12 | * TODO - need to implement multiple managers functionality
13 | */
14 |
15 | using Preconditions for address;
16 |
17 | address internal owner;
18 | address internal manager;
19 |
20 | function AC(address _manager) {
21 | require(!_manager.isInvalidAddr());
22 | owner = msg.sender;
23 | manager = _manager;
24 | }
25 |
26 | function setManager(address _manager) internal {
27 | require(!_manager.isInvalidAddr());
28 | manager = _manager;
29 | }
30 |
31 | function changeManager(address _manager) public;
32 |
33 | modifier onlyOwner { require(msg.sender == owner); _; }
34 | modifier onlyManager { require(msg.sender == manager); _; }
35 | }
36 |
37 |
38 | /* @title - Life Cycle of the Contract */
39 | contract LiveCycle {
40 |
41 | /**
42 | * @dev - There are 4 states of Contract exist:
43 | * Running - contact is avaliable for calling
44 | * Paused - Contract is suspended. Contact is temprorary blocked
45 | * and only administrative functions are available
46 | * Closed - contract is finally closed
47 | * Interrupted - contract is stopped suddenly by some reasons
48 | */
49 |
50 | using Preconditions for byte;
51 |
52 | byte constant internal Paused = 0x1;
53 | byte constant internal Running = 0x2;
54 | byte constant internal Closed = 0x4;
55 | byte constant internal Interrupted = 0x8;
56 |
57 | byte public state = Paused;
58 |
59 | // Paused -> Running
60 | function isRunAvaliable() private constant
61 | returns(bool) {
62 | return (state == Paused);
63 | }
64 |
65 | // Running -> Paused
66 | function isSuspendAvailable() private constant
67 | returns(bool) {
68 | return (state == Running);
69 | }
70 |
71 | // Paused -> Closed
72 | function isCloseAvailable() private constant
73 | returns(bool) {
74 | return (state == Paused);
75 | }
76 |
77 | // Running|Paused -> Interrupted
78 | function isInterruptAvailable() private constant
79 | returns(bool) {
80 | return (state == Running) || (state == Paused);
81 | }
82 |
83 | function changeState(byte _state) internal
84 | returns(byte) {
85 | if(state == _state)
86 | return state;
87 |
88 | if(_state == Running) require(isRunAvaliable());
89 | else if(_state == Paused) require(isSuspendAvailable());
90 | else revert();
91 |
92 | LogChangeState(state, _state);
93 | state = _state;
94 | return state;
95 | }
96 |
97 | function interrupt() internal {
98 | require(isInterruptAvailable());
99 |
100 | LogChangeState(state, Interrupted);
101 | state = Interrupted;
102 | }
103 |
104 | function close() internal {
105 | require(isCloseAvailable());
106 |
107 | LogChangeState(state, Closed);
108 | state = Closed;
109 | }
110 |
111 | function isRunning() public constant
112 | returns(bool) {
113 | return (state == Running);
114 | }
115 |
116 | function switchTo(byte _state) public;
117 |
118 | modifier atState(byte _states) { require(!Preconditions.isEmpty(_states & state)); _; }
119 |
120 | event LogChangeState(byte _from, byte _to);
121 | }
122 |
123 |
124 | /* @title - Preliminary data verifications */
125 | library Preconditions {
126 |
127 | /**
128 | * @dev - Fundamental function to validate different data types
129 | * Functions are not generates exceptions and can be handled
130 | * on the client side
131 | */
132 |
133 | /* @dev - check that byte is null */
134 | function isEmpty(byte _val) constant internal
135 | returns(bool) {
136 | return (byte(0) == _val);
137 | }
138 |
139 | /* @dev - check that string is empty */
140 | function isEmpty(string _val) constant internal
141 | returns(bool) {
142 | return (0 == bytes(_val).length);
143 | }
144 |
145 | /* @dev - are two strings equal */
146 | function isEqual(string _a, string _b) constant internal
147 | returns (bool) {
148 | bytes memory a = bytes(_a);
149 | bytes memory b = bytes(_b);
150 |
151 | if(a.length != b.length)
152 | return false;
153 |
154 | for (uint i = 0; i < b.length; i++)
155 | if(a[i] != b[i])
156 | return false;
157 |
158 | return true;
159 | }
160 |
161 | /* @dev - check the address correctness */
162 | function isInvalidAddr(address _addr) constant internal
163 | returns (bool) {
164 | return (address(0) == _addr);
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
Prototype
--------------------------------------------------------------------------------
/dist/static/immla-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dapps-community/dapp-logistic-sample/058a3f6763fa3681d387b33bdca71e801e6c765f/dist/static/immla-bg.png
--------------------------------------------------------------------------------
/dist/static/js/manifest.82dccd34fac2fc9321cc.js:
--------------------------------------------------------------------------------
1 | !function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,a){for(var i,u,f,s=0,l=[];s
2 |
3 |
4 |
5 | Prototype
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/mongo.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 | let db = mongoose.connection;
4 |
5 | module.exports.mongo = db;
6 |
7 | const connectionString = `mongodb://localhost:27017/immla`;
8 |
9 | const connect = function () {
10 |
11 | if (db.readyState !== 0) {
12 | return;
13 | }
14 |
15 | const opts = {
16 | server: {
17 | "auto_reconnect": true,
18 | poolSize: 10,
19 | socketOptions: {
20 | keepAlive: true
21 | }
22 | },
23 | db: {
24 | numberOfRetries: 5,
25 | retryMiliSeconds: 1000
26 | }
27 | };
28 |
29 | mongoose.connect(connectionString, opts);
30 | };
31 |
32 | db.on('connected', function () {
33 | console.log('Connected to mongo database: ', connectionString);
34 | });
35 |
36 | db.on('disconnected', function () {
37 | console.error('Disconnected from mongo database: ', connectionString);
38 | });
39 |
40 | db.on('error', function (err) {
41 | console.error('Error from mongo db');
42 | console.error(err.stack.toString());
43 | process.exit();
44 | });
45 |
46 | db.on('open', function () {
47 | console.log('Open connection to mongo database: ', connectionString);
48 | });
49 |
50 | connect();
51 |
52 | const userScheme = mongoose.Schema({
53 | id: String,
54 | password: String,
55 | type: {type: String, default: "client"},
56 | email: String,
57 | token: String,
58 | pubkey: String
59 | });
60 |
61 | module.exports.User = mongoose.model('User', userScheme);
62 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "immla-prototype",
3 | "version": "1.0.0",
4 | "description": "A Vue.js project",
5 | "author": "fw",
6 | "private": true,
7 | "scripts": {
8 | "dev": "node build/dev-server.js",
9 | "start": "node build/dev-server.js",
10 | "build": "node build/build.js",
11 | "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run",
12 | "e2e": "node test/e2e/runner.js",
13 | "test": "npm run unit && npm run e2e",
14 | "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs"
15 | },
16 | "dependencies": {
17 | "axios": "^0.16.2",
18 | "babel-preset-es2015": "^6.24.1",
19 | "bootstrap-vue": "^0.18.0",
20 | "mongoose": "^4.11.7",
21 | "tether": "^1.4.0",
22 | "vue": "^2.3.3",
23 | "vue-awesome": "^2.3.1",
24 | "vue-router": "^2.6.0",
25 | "vue-select": "github:sagalbot/vue-select",
26 | "vuex": "^2.3.1"
27 | },
28 | "devDependencies": {
29 | "autoprefixer": "^7.1.2",
30 | "babel-core": "^6.22.1",
31 | "babel-eslint": "^7.1.1",
32 | "babel-loader": "^7.1.1",
33 | "babel-plugin-transform-runtime": "^6.22.0",
34 | "babel-preset-env": "^1.3.2",
35 | "babel-preset-stage-2": "^6.22.0",
36 | "babel-register": "^6.22.0",
37 | "chalk": "^2.0.1",
38 | "connect-history-api-fallback": "^1.3.0",
39 | "copy-webpack-plugin": "^4.0.1",
40 | "css-loader": "^0.28.0",
41 | "cssnano": "^3.10.0",
42 | "eslint": "^3.19.0",
43 | "eslint-friendly-formatter": "^3.0.0",
44 | "eslint-loader": "^1.7.1",
45 | "eslint-plugin-html": "^3.0.0",
46 | "eslint-config-standard": "^6.2.1",
47 | "eslint-plugin-promise": "^3.4.0",
48 | "eslint-plugin-standard": "^2.0.1",
49 | "eventsource-polyfill": "^0.9.6",
50 | "express": "^4.14.1",
51 | "extract-text-webpack-plugin": "^2.0.0",
52 | "file-loader": "^0.11.1",
53 | "friendly-errors-webpack-plugin": "^1.1.3",
54 | "html-webpack-plugin": "^2.28.0",
55 | "http-proxy-middleware": "^0.17.3",
56 | "webpack-bundle-analyzer": "^2.2.1",
57 | "cross-env": "^5.0.1",
58 | "karma": "^1.4.1",
59 | "karma-coverage": "^1.1.1",
60 | "karma-mocha": "^1.3.0",
61 | "karma-phantomjs-launcher": "^1.0.2",
62 | "karma-phantomjs-shim": "^1.4.0",
63 | "karma-sinon-chai": "^1.3.1",
64 | "karma-sourcemap-loader": "^0.3.7",
65 | "karma-spec-reporter": "0.0.31",
66 | "karma-webpack": "^2.0.2",
67 | "lolex": "^1.5.2",
68 | "mocha": "^3.2.0",
69 | "chai": "^3.5.0",
70 | "sinon": "^2.1.0",
71 | "sinon-chai": "^2.8.0",
72 | "inject-loader": "^3.0.0",
73 | "babel-plugin-istanbul": "^4.1.1",
74 | "phantomjs-prebuilt": "^2.1.14",
75 | "chromedriver": "^2.27.2",
76 | "cross-spawn": "^5.0.1",
77 | "nightwatch": "^0.9.12",
78 | "selenium-server": "^3.0.1",
79 | "semver": "^5.3.0",
80 | "shelljs": "^0.7.6",
81 | "opn": "^5.1.0",
82 | "optimize-css-assets-webpack-plugin": "^2.0.0",
83 | "ora": "^1.2.0",
84 | "rimraf": "^2.6.0",
85 | "url-loader": "^0.5.8",
86 | "vue-loader": "^12.1.0",
87 | "vue-style-loader": "^3.0.1",
88 | "vue-template-compiler": "^2.3.3",
89 | "webpack": "^2.6.1",
90 | "webpack-dev-middleware": "^1.10.0",
91 | "webpack-hot-middleware": "^2.18.0",
92 | "webpack-merge": "^4.1.0"
93 | },
94 | "engines": {
95 | "node": ">= 4.0.0",
96 | "npm": ">= 3.0.0"
97 | },
98 | "browserslist": [
99 | "> 1%",
100 | "last 2 versions",
101 | "not ie <= 8"
102 | ]
103 | }
104 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
71 |
--------------------------------------------------------------------------------
/src/app/modules/auth/actions.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | export const CHANGE_TOKEN = 'CHANGE_TOKEN';
4 | export const SET_KEY = 'SET_KEY';
5 | export const auth = (store, {login, password, key}) => {
6 | const {commit} = store;
7 | return axios.post('/auth/login', {
8 | id: login,
9 | password
10 | }).then((res) => {
11 | console.log(res.data);
12 | if (res.data.success) {
13 | window.localStorage.setItem('immla-front-token', res.data.token);
14 | window.localStorage.setItem('immla-network-key', key);
15 | commit(CHANGE_TOKEN, res.data.token);
16 | commit(SET_KEY, key);
17 | }
18 | return res;
19 | });
20 | };
21 |
22 | export const register = (store, {id, password, email, type}) => {
23 | const {commit} = store;
24 | let account = web3.eth.accounts.create();
25 | return axios.post('/auth/register', {
26 | id,
27 | password,
28 | email,
29 | type,
30 | pubkey: account.address
31 | }).then((res) => {
32 | web3.eth.sendTransaction({from:"0x64665166273237b3b74838863dd9f0ff61960300", to: account.address,
33 | value: web3.utils.toWei(5)}).then(console.log);
34 | console.log(res);
35 | if (res.data.success) {
36 | window.localStorage.setItem('immla-front-token', res.data.token);
37 | res.data.key = account.privateKey;
38 | window.localStorage.setItem('immla-network-key', res.data.key);
39 | commit(SET_KEY, res.data.key);
40 | }
41 | return res;
42 | });
43 | };
44 |
45 | export const LOG_OFF = 'LOG_OFF';
46 | export const logOff = (store) => {
47 | const {commit} = store;
48 | window.localStorage.setItem('immla-front-token', null);
49 | window.localStorage.setItem('immla-network-key', null);
50 | return commit(LOG_OFF);
51 | };
52 |
53 | export const getUserInfo = () => {
54 | const token = window.localStorage.getItem('immla-front-token');
55 | return axios.get('/auth/check?token=' + token);
56 | };
57 |
58 | export const GET_USER_INFO = 'GET_USER_INFO';
59 | export const getInfo = (store) => {
60 | return getUserInfo().then(res => {
61 | if (!res.data.success)
62 | store.commit(LOG_OFF);
63 | else store.commit(GET_USER_INFO, res.data.user);
64 | return res;
65 | });
66 | };
67 |
--------------------------------------------------------------------------------
/src/app/modules/auth/auth.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 | Immla DApp Prototype
12 |
13 |
14 |
15 | Incorrect login/password!
16 |
17 |
18 |
19 | Attention: Do not use your private passwords, this prototype is just for testing and does not garant enough security of personal data.
20 |
21 |
22 |
23 | User already exists!
24 |
25 |
26 |
27 |
28 |
Your key is: {{key}}. Save it!
29 |
30 |
31 |
32 |
67 |
68 |
69 | SIGN IN
70 |
71 |
72 |
73 | SIGN UP
74 |
75 |
76 |
80 |
81 |
82 | Have no account yet? Sign up!
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
182 |
183 |
413 |
--------------------------------------------------------------------------------
/src/app/modules/auth/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions';
2 | import { defaultState, mutations } from './mutations';
3 |
4 | const state = defaultState;
5 |
6 | export default {
7 | module: {
8 | actions,
9 | state,
10 | mutations
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/src/app/modules/auth/mutations.js:
--------------------------------------------------------------------------------
1 | import {
2 | CHANGE_TOKEN,
3 | LOG_OFF,
4 | GET_USER_INFO,
5 | SET_FRIENDS,
6 | SET_KEY
7 | } from './actions'
8 |
9 | export const defaultState = {
10 | token: null,
11 | name: '',
12 | type: null,
13 | privateKey: null
14 | }
15 |
16 | export const mutations = {
17 | [CHANGE_TOKEN] (state, token) {
18 | state.token = token
19 | },
20 | [SET_KEY] (state, key) {
21 | state.privateKey = key
22 | },
23 | [LOG_OFF] (state) {
24 | state.token = null;
25 | state.privateKey = null;
26 | },
27 | [GET_USER_INFO] (state, payload) {
28 | state.name = payload.id || '';
29 | state.type = payload.type || [];
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/app/modules/form/avatar.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
23 |
24 |
--------------------------------------------------------------------------------
/src/app/modules/form/form.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
69 |
70 |
71 |
125 |
126 |
281 |
--------------------------------------------------------------------------------
/src/app/modules/main/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
48 |
49 |
74 |
--------------------------------------------------------------------------------
/src/app/modules/offers/actions.js:
--------------------------------------------------------------------------------
1 | export const SET_OFFERS = 'SET_OFFERS';
2 | export const syncOffers = (store) => {
3 | const {commit} = store;
4 | let account = web3.eth.accounts.privateKeyToAccount(store.rootState.auth.privateKey);
5 | let offersregistry = getOffersRegistry(offersRegistryAddress, account);
6 | return offersregistry.getOffers().then((offerIds) => {
7 | console.log(offerIds);
8 | let offerPromises = offerIds.map(offerId => getOffer(offerId, account).methods.getData().call());
9 | return Promise.all(offerPromises).then((offersResults) => {
10 | console.log("Raw offers results: ", offersResults);
11 | let preparedOffers = offersResults.map((offerData, i) => {
12 | return {
13 | id: offerIds[i],
14 | forwarderAddress: offerData['0'],
15 | details: offerData['1'],
16 | from: offerData['2'],
17 | to: offerData['3'],
18 | state: offerData['4']
19 | }
20 | });
21 | commit(SET_OFFERS, preparedOffers);
22 | return preparedOffers;
23 | });
24 | });
25 | };
26 |
27 | export const ADD_OFFER = 'ADD_OFFER';
28 | export const addOffer = (store, offer) => {
29 | console.log(offer);
30 | const {commit} = store;
31 | let account = web3.eth.accounts.privateKeyToAccount(store.rootState.auth.privateKey);
32 | let offersregistry = getOffersRegistry(offersRegistryAddress, account);
33 | return offersregistry.newOffer(offer.details, offer.from, offer.to).then((res) => {
34 | console.log('created offer res: ', res);
35 | });
36 | };
37 |
38 | export const runOffer = (store, offerId) => {
39 | let account = web3.eth.accounts.privateKeyToAccount(store.rootState.auth.privateKey);
40 | return getOffer(offerId, account).switchTo("0x02");
41 | };
42 |
43 | export const closeOffer = (store, offerId) => {
44 | let account = web3.eth.accounts.privateKeyToAccount(store.rootState.auth.privateKey);
45 | return getOffer(offerId, account).close();
46 | };
47 |
48 | export const pauseOffer = (store, offerId) => {
49 | let account = web3.eth.accounts.privateKeyToAccount(store.rootState.auth.privateKey);
50 | return getOffer(offerId, account).switchTo("0x01");
51 | };
--------------------------------------------------------------------------------
/src/app/modules/offers/index.js:
--------------------------------------------------------------------------------
1 |
2 | import * as actions from './actions';
3 | import { defaultState, mutations } from './mutations';
4 |
5 | const state = defaultState;
6 |
7 | export default {
8 | module: {
9 | actions,
10 | state,
11 | mutations
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/src/app/modules/offers/mutations.js:
--------------------------------------------------------------------------------
1 | import {
2 | SET_OFFERS
3 | } from './actions'
4 |
5 | export const defaultState = {
6 | offers: []
7 | };
8 |
9 | export const mutations = {
10 | [SET_OFFERS](state, offers) {
11 | state.offers = offers;
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/src/app/modules/offers/offers.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
My Offers:
10 |
13 |
14 |
15 |
16 |
17 | From |
18 | To |
19 | Cost |
20 | State |
21 |
22 |
23 |
24 |
26 | {{offer['from']}} |
27 | {{offer['to']}} |
28 | {{offer['details']}} |
29 | {{getHumanState(offer['state'])}} |
31 |
32 |
33 |
34 |
35 |
36 | You have no offers now. Maybe it's time to add something?
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
75 |
76 |
77 |
{{offers[selected]['from']}} -> {{offers[selected]['to']}}
78 |
79 |
80 |
{{offers[selected]['details']}}
81 |
82 |
Place for different details of an offer
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
221 |
222 |
352 |
--------------------------------------------------------------------------------
/src/app/modules/orders/actions.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | export const syncOrders = (store) => {
4 | const {commit} = store;
5 | let account = web3.eth.accounts.privateKeyToAccount(store.rootState.auth.privateKey);
6 | let jobcontractregistry = getDealsRegistry(dealsRegistryAddress, account);
7 | if (store.rootState.auth.type === 'client')
8 | return jobcontractregistry.getMyOwnedDeals().then((jobIds) => {
9 | let jobsPromises = jobIds.map(jobId => getDeal(jobId, account).methods.getData().call());
10 | return Promise.all(jobsPromises).then((jobResults) => {
11 | console.log("Raw job results: ", jobResults);
12 | let preparedOrders = jobResults.map((job, i) => {
13 | return {
14 | id: jobIds[i],
15 | offerId: job['0'],
16 | owner: job['1'],
17 | completed: job['2'],
18 | status: job['3']
19 | }
20 | });
21 |
22 | let offerIds = preparedOrders.map(order => order.offerId);
23 | let offerPromises = offerIds.map(offerId => getOffer(offerId, account).methods.getData().call());
24 | let preparedOffers;
25 | return Promise.all(offerPromises).then((offersResults) => {
26 | console.log("Raw offers results: ", offersResults);
27 | preparedOffers = offersResults.map((offerData, i) => {
28 | return {
29 | id: offerIds[i],
30 | forwarderAddress: offerData['0'],
31 | details: offerData['1'],
32 | from: offerData['2'],
33 | to: offerData['3'],
34 | offerState: offerData['4']
35 | }
36 | });
37 | console.log("Prepared offers results: ", preparedOffers);
38 | return preparedOffers;
39 | }).then((offers) => {
40 | return preparedOrders.map((order) => {
41 | let offer = offers.filter(offer => offer.id === order.offerId)[0];
42 | order.from = offer.from;
43 | order.to = offer.to;
44 | order.details = offer.details;
45 | order.forwarderAddress = offer.forwarderAddress;
46 | order.offerState = offer.offerState;
47 | return order;
48 | });
49 | }).then((orders) => {
50 | let forwAddresses = orders.map(order => order.forwarderAddress);
51 | const {commit} = store;
52 | return axios.post('/auth/aboutkeys', {
53 | pubkeys: forwAddresses
54 | }).then((res) => {
55 | return orders.map((order) => {
56 | order.forwarderName = res.data.users.filter(owner => order.forwarderAddress === owner.pubkey)[0].id;
57 | return order;
58 | });
59 | });
60 | });;
61 | });
62 | });
63 | else
64 | return jobcontractregistry.getMySupplyingDeals().then((jobIds) => {
65 | let jobsPromises = jobIds.map(jobId => getDeal(jobId, account).methods.getData().call());
66 | return Promise.all(jobsPromises).then((jobResults) => {
67 | console.log("Raw job results: ", jobResults);
68 | let preparedOrders = jobResults.map((job, i) => {
69 | return {
70 | id: jobIds[i],
71 | offerId: job['0'],
72 | owner: job['1'],
73 | completed: job['2'],
74 | status: job['3']
75 | }
76 | });
77 | let offerIds = preparedOrders.map(order => order.offerId);
78 | let offerPromises = offerIds.map(offerId => getOffer(offerId, account).methods.getData().call());
79 | let preparedOffers;
80 | return Promise.all(offerPromises).then((offersResults) => {
81 | console.log("Raw offers results: ", offersResults);
82 | preparedOffers = offersResults.map((offerData, i) => {
83 | return {
84 | id: offerIds[i],
85 | forwarderAddress: offerData['0'],
86 | details: offerData['1'],
87 | from: offerData['2'],
88 | to: offerData['3'],
89 | offerState: offerData['4']
90 | }
91 | });
92 | return preparedOffers;
93 | }).then((offers) => {
94 | return preparedOrders.map((order) => {
95 | let offer = offers.filter(offer => offer.id === order.offerId)[0];
96 | order.from = offer.from;
97 | order.to = offer.to;
98 | order.details = offer.details;
99 | order.forwarderAddress = offer.forwarderAddress;
100 | order.offerState = offer.offerState;
101 | return order;
102 | });
103 | }).then((orders) => {
104 | let ownerAddresses = orders.map(order => order.owner);
105 | let ownersResults;
106 | const {commit} = store;
107 | return axios.post('/auth/aboutkeys', {
108 | pubkeys: ownerAddresses
109 | }).then((res) => {
110 | ownersResults = res.data.users;
111 | return orders.map((order) => {
112 | console.log(ownersResults.filter(owner => order.owner === owner.pubkey)[0]);
113 | order.ownerName = ownersResults.filter(owner => order.owner === owner.pubkey)[0].id;
114 | return order;
115 | });
116 | });
117 | });
118 | });
119 | });
120 | };
121 |
122 | export const closeOrder = (store, orderId) => {
123 | let account = web3.eth.accounts.privateKeyToAccount(store.rootState.auth.privateKey);
124 | if (store.rootState.auth.type === 'client')
125 | return getDeal(orderId, account).confirm();
126 | else
127 | return getDeal(orderId, account).compete();
128 | };
--------------------------------------------------------------------------------
/src/app/modules/orders/index.js:
--------------------------------------------------------------------------------
1 |
2 | import * as actions from './actions';
3 | import { defaultState, mutations } from './mutations';
4 |
5 | const state = defaultState;
6 |
7 | export default {
8 | module: {
9 | actions,
10 | state,
11 | mutations
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/src/app/modules/orders/mutations.js:
--------------------------------------------------------------------------------
1 | import {
2 | SET_FILES,
3 | ADD_FILE
4 | } from './actions'
5 |
6 | export const defaultState = {
7 | files: []
8 | }
9 |
10 | export const mutations = {
11 | [SET_FILES](state, payload) {
12 | state.files = payload.files;
13 | },
14 | [ADD_FILE](state, payload) {
15 | state.files.push(payload.data);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/app/modules/orders/orders.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
My Orders:
8 |
9 |
10 |
11 |
12 | Offer |
13 | Forwarder |
14 | Client |
15 | Status |
16 |
17 |
18 |
19 |
21 | {{order.from}} -> {{order.to}} |
22 | {{order.forwarderName}} |
23 | {{order.ownerName}} |
24 | Needs for your confirmation! |
25 | Waiting for another side confirmation |
26 | Done |
27 |
28 |
29 |
30 |
31 |
32 |
33 | You have no orders now
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
{{orders[selected].from}} -> {{orders[selected].to}}
43 |
{{orders[selected].ownerName}}
44 |
45 |
Place for order details...
46 |
47 |
48 |
Confirmation:
49 |
If job is done successfully, press button
50 |
51 |
52 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
Status:
62 | Job's waiting for confirmation from another side
63 |
64 |
65 |
66 |
Status:
67 | Job is done and confirmed by both sides!
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
136 |
217 |
--------------------------------------------------------------------------------
/src/app/modules/profile/actions.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/app/modules/profile/index.js:
--------------------------------------------------------------------------------
1 |
2 | import * as actions from './actions';
3 | import { defaultState, mutations } from './mutations';
4 |
5 | const state = defaultState;
6 |
7 | export default {
8 | module: {
9 | actions,
10 | state,
11 | mutations
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/src/app/modules/profile/mutations.js:
--------------------------------------------------------------------------------
1 | import {
2 | SET_FILES,
3 | ADD_FILE
4 | } from './actions'
5 |
6 | export const defaultState = {
7 | files: []
8 | }
9 |
10 | export const mutations = {
11 | [SET_FILES](state, payload) {
12 | state.files = payload.files;
13 | },
14 | [ADD_FILE](state, payload) {
15 | state.files.push(payload.data);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/app/modules/profile/profile.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 | Page's in development stage, sorry
15 |
16 |
17 |
18 |
19 |
46 |
--------------------------------------------------------------------------------
/src/app/modules/search/actions.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | export const search = (store, {from, to}) => {
3 | let account = web3.eth.accounts.privateKeyToAccount(store.rootState.auth.privateKey);
4 | let offersregistry = getOffersRegistry(offersRegistryAddress, account);
5 | return offersregistry.getByRoute(from, to).then(function (offerIds) {
6 | let offerPromises = offerIds.map(offerId => getOffer(offerId, account).methods.getData().call());
7 | return Promise.all(offerPromises).then((offersResults) => {
8 | console.log("Raw search results: ", offersResults);
9 | let preparedOffers = offersResults.map((offerData, i) => {
10 | return {
11 | id: offerIds[i],
12 | forwarderAddress: offerData['0'],
13 | details: offerData['1'],
14 | from: offerData['2'],
15 | to: offerData['3'],
16 | offerState: offerData['4']
17 | }
18 | });
19 | console.log("Prepared search results: ", preparedOffers);
20 | return preparedOffers;
21 | }).then((options) => {
22 | let pubkeys = options.map(option => option.forwarderAddress);
23 | return axios.post('/auth/aboutkeys', {
24 | pubkeys: pubkeys
25 | }).then((res) => {
26 | console.log(res);
27 | return options.map((option) => {
28 | let forw = res.data.users.filter((user) => user.pubkey === option.forwarderAddress)[0];
29 | if (forw) option.forwarderName = forw.id;
30 | return option;
31 | });
32 | });
33 | });
34 | });
35 | };
36 |
37 | export const createOrder = (store, offerId) => {
38 | console.log(offerId);
39 | let account = web3.eth.accounts.privateKeyToAccount(store.rootState.auth.privateKey);
40 | let jobcontractregistry = getDealsRegistry(dealsRegistryAddress, account);
41 | return jobcontractregistry.newDeal(offerId).then((res) => {
42 | console.log(res);
43 | });
44 | };
45 |
46 | export const getRandomOffers = (store, num) => {
47 | let account = web3.eth.accounts.privateKeyToAccount(store.rootState.auth.privateKey);
48 | let offersregistry = getOffersRegistry(offersRegistryAddress, account);
49 | return offersregistry.peek(num).then(function (offerIds) {
50 | let offerPromises = offerIds.map(offerId => getOffer(offerId, account).methods.getData().call());
51 | return Promise.all(offerPromises).then((offersResults) => {
52 | console.log("Raw random search results: ", offersResults);
53 | let preparedOffers = offersResults.map((offerData, i) => {
54 | return {
55 | id: offerIds[i],
56 | forwarderAddress: offerData['0'],
57 | details: offerData['1'],
58 | from: offerData['2'],
59 | to: offerData['3'],
60 | offerState: offerData['4']
61 | }
62 | });
63 | console.log("Prepared random search results: ", preparedOffers);
64 | return preparedOffers;
65 | }).then((options) => {
66 | let pubkeys = options.map(option => option.forwarderAddress);
67 | return axios.post('/auth/aboutkeys', {
68 | pubkeys: pubkeys
69 | }).then((res) => {
70 | console.log(res);
71 | return options.map((option) => {
72 | let forw = res.data.users.filter((user) => user.pubkey === option.forwarderAddress)[0];
73 | if (forw) option.forwarderName = forw.id;
74 | return option;
75 | });
76 | });
77 | });
78 | });
79 | }
--------------------------------------------------------------------------------
/src/app/modules/search/index.js:
--------------------------------------------------------------------------------
1 |
2 | import * as actions from './actions';
3 | import { defaultState, mutations } from './mutations';
4 |
5 | const state = defaultState;
6 |
7 | export default {
8 | module: {
9 | actions,
10 | state,
11 | mutations
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/src/app/modules/search/mutations.js:
--------------------------------------------------------------------------------
1 | import {
2 |
3 | } from './actions'
4 |
5 | export const defaultState = {
6 | files: []
7 | }
8 |
9 | export const mutations = {
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/app/modules/search/search.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
22 |
Results:
23 |
24 |
25 |
26 |
27 | Forwarder |
28 | From |
29 | To |
30 | Cost |
31 | State |
32 |
33 |
34 |
35 |
38 | {{option.forwarderName}} |
39 | {{option.from}} |
40 | {{option.to}} |
41 | {{option.details}} |
42 | {{getHumanState(option['offerState'])}}
44 | |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | There is no any offer for your request :(
53 |
54 |
55 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
212 |
213 |
386 |
--------------------------------------------------------------------------------
/src/app/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueRouter from 'vue-router'
3 |
4 | import store from '../store'
5 | import {CHANGE_TOKEN, SET_KEY} from '../modules/auth/actions'
6 |
7 | import FormPage from '../modules/form/form.vue'
8 | import AuthPage from '../modules/auth/auth.vue'
9 | import Offers from '../modules/offers/offers.vue'
10 | import Orders from '../modules/orders/orders.vue'
11 | import Search from '../modules/search/search.vue'
12 | import Profile from '../modules/profile/profile.vue'
13 |
14 | import {getUserInfo} from '../modules/auth/actions.js'
15 |
16 | Vue.use(VueRouter);
17 |
18 | const Router = new VueRouter({
19 | history: false,
20 | routes: [
21 | {
22 | path: '/',
23 | name: 'start',
24 | redirect: {name: 'form-page'}
25 | },
26 | {
27 | path: '/form',
28 | name: 'form-page',
29 | component: FormPage,
30 | children: [
31 | {
32 | path: 'offers',
33 | name: 'offers',
34 | component: Offers
35 | },
36 | {
37 | path: 'orders',
38 | name: 'orders',
39 | component: Orders
40 | },
41 | {
42 | path: 'search',
43 | name: 'search',
44 | component: Search
45 | },
46 | {
47 | path: 'profile',
48 | name: 'profile',
49 | component: Profile
50 | }
51 | ]
52 | },
53 | {
54 | path: '/login',
55 | name: 'auth-page',
56 | component: AuthPage
57 | }
58 | ]
59 | })
60 |
61 | Router.beforeEach((to, from, next) => {
62 | if (to.name === 'auth-page')
63 | next()
64 | const failure = () => next({
65 | name: 'auth-page',
66 | query: {next: to.path}
67 | })
68 | const token = window.localStorage.getItem('immla-front-token');
69 | const key = window.localStorage.getItem('immla-network-key');
70 | if (!token) {
71 | failure()
72 | return
73 | }
74 | getUserInfo().then((res) => {
75 | if (res.data.success) {
76 | next()
77 | store.commit(CHANGE_TOKEN, token)
78 | store.commit(SET_KEY, key);
79 | return
80 | }
81 | failure()
82 | }).catch(() => {
83 | failure()
84 | })
85 | })
86 | export default Router
87 |
--------------------------------------------------------------------------------
/src/app/select/comp/Select.vue:
--------------------------------------------------------------------------------
1 |
319 |
320 |
321 |
322 |
323 |
324 |
325 | {{ getOptionLabel(option) }}
326 |
329 |
330 |
331 |
349 |
350 |
351 |
352 |
353 | Loading...
354 |
355 |
356 |
357 |
358 |
370 |
371 |
372 |
373 |
374 |
--------------------------------------------------------------------------------
/src/app/select/mixins/ajax.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | props: {
3 | /**
4 | * Toggles the adding of a 'loading' class to the main
5 | * .v-select wrapper. Useful to control UI state when
6 | * results are being processed through AJAX.
7 | */
8 | loading: {
9 | type: Boolean,
10 | default: false
11 | },
12 |
13 | /**
14 | * Accept a callback function that will be
15 | * run when the search text changes.
16 | *
17 | * loading() accepts a boolean value, and can
18 | * be used to toggle a loading class from
19 | * the onSearch callback.
20 | *
21 | * @param {search} String Current search text
22 | * @param {loading} Function(bool) Toggle loading class
23 | */
24 | onSearch: {
25 | type: Function,
26 | default: function(search, loading){}
27 | }
28 | },
29 |
30 | data() {
31 | return {
32 | mutableLoading: false
33 | }
34 | },
35 |
36 | watch: {
37 | /**
38 | * If a callback & search text has been provided,
39 | * invoke the onSearch callback.
40 | */
41 | search() {
42 | if (this.search.length > 0) {
43 | this.onSearch(this.search, this.toggleLoading)
44 | this.$emit('search', this.search, this.toggleLoading)
45 | }
46 | },
47 | /**
48 | * Sync the loading prop with the internal
49 | * mutable loading value.
50 | * @param val
51 | */
52 | loading(val) {
53 | this.mutableLoading = val
54 | }
55 | },
56 |
57 | methods: {
58 | /**
59 | * Toggle this.loading. Optionally pass a boolean
60 | * value. If no value is provided, this.loading
61 | * will be set to the opposite of it's current value.
62 | * @param toggle Boolean
63 | * @returns {*}
64 | */
65 | toggleLoading(toggle = null) {
66 | if (toggle == null) {
67 | return this.mutableLoading = !this.mutableLoading
68 | }
69 | return this.mutableLoading = toggle
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/app/select/mixins/index.js:
--------------------------------------------------------------------------------
1 | import ajax from './ajax'
2 | import pointer from './typeAheadPointer'
3 | import pointerScroll from './pointerScroll'
4 |
5 | export default { ajax, pointer, pointerScroll }
6 |
--------------------------------------------------------------------------------
/src/app/select/mixins/pointerScroll.js:
--------------------------------------------------------------------------------
1 | // flow
2 |
3 | module.exports = {
4 | watch: {
5 | typeAheadPointer() {
6 | this.maybeAdjustScroll()
7 | }
8 | },
9 |
10 | methods: {
11 | /**
12 | * Adjust the scroll position of the dropdown list
13 | * if the current pointer is outside of the
14 | * overflow bounds.
15 | * @returns {*}
16 | */
17 | maybeAdjustScroll() {
18 | let pixelsToPointerTop = this.pixelsToPointerTop()
19 | let pixelsToPointerBottom = this.pixelsToPointerBottom()
20 |
21 | if ( pixelsToPointerTop <= this.viewport().top) {
22 | return this.scrollTo( pixelsToPointerTop )
23 | } else if (pixelsToPointerBottom >= this.viewport().bottom) {
24 | return this.scrollTo( this.viewport().top + this.pointerHeight() )
25 | }
26 | },
27 |
28 | /**
29 | * The distance in pixels from the top of the dropdown
30 | * list to the top of the current pointer element.
31 | * @returns {number}
32 | */
33 | pixelsToPointerTop() {
34 | let pixelsToPointerTop = 0
35 | if( this.$refs.dropdownMenu ) {
36 | for (let i = 0; i < this.typeAheadPointer; i++) {
37 | pixelsToPointerTop += this.$refs.dropdownMenu.children[i].offsetHeight
38 | }
39 | }
40 | return pixelsToPointerTop
41 | },
42 |
43 | /**
44 | * The distance in pixels from the top of the dropdown
45 | * list to the bottom of the current pointer element.
46 | * @returns {*}
47 | */
48 | pixelsToPointerBottom() {
49 | return this.pixelsToPointerTop() + this.pointerHeight()
50 | },
51 |
52 | /**
53 | * The offsetHeight of the current pointer element.
54 | * @returns {number}
55 | */
56 | pointerHeight() {
57 | let element = this.$refs.dropdownMenu ? this.$refs.dropdownMenu.children[this.typeAheadPointer] : false
58 | return element ? element.offsetHeight : 0
59 | },
60 |
61 | /**
62 | * The currently viewable portion of the dropdownMenu.
63 | * @returns {{top: (string|*|number), bottom: *}}
64 | */
65 | viewport() {
66 | return {
67 | top: this.$refs.dropdownMenu ? this.$refs.dropdownMenu.scrollTop: 0,
68 | bottom: this.$refs.dropdownMenu ? this.$refs.dropdownMenu.offsetHeight + this.$refs.dropdownMenu.scrollTop : 0
69 | }
70 | },
71 |
72 | /**
73 | * Scroll the dropdownMenu to a given position.
74 | * @param position
75 | * @returns {*}
76 | */
77 | scrollTo(position) {
78 | return this.$refs.dropdownMenu ? this.$refs.dropdownMenu.scrollTop = position : null
79 | },
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/app/select/mixins/typeAheadPointer.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | data() {
3 | return {
4 | typeAheadPointer: -1
5 | }
6 | },
7 |
8 | watch: {
9 | filteredOptions() {
10 | this.typeAheadPointer = 0
11 | }
12 | },
13 |
14 | methods: {
15 | /**
16 | * Move the typeAheadPointer visually up the list by
17 | * subtracting the current index by one.
18 | * @return {void}
19 | */
20 | typeAheadUp() {
21 | if (this.typeAheadPointer > 0) {
22 | this.typeAheadPointer--
23 | if( this.maybeAdjustScroll ) {
24 | this.maybeAdjustScroll()
25 | }
26 | }
27 | },
28 |
29 | /**
30 | * Move the typeAheadPointer visually down the list by
31 | * adding the current index by one.
32 | * @return {void}
33 | */
34 | typeAheadDown() {
35 | if (this.typeAheadPointer < this.filteredOptions.length - 1) {
36 | this.typeAheadPointer++
37 | if( this.maybeAdjustScroll ) {
38 | this.maybeAdjustScroll()
39 | }
40 | }
41 | },
42 |
43 | /**
44 | * Select the option at the current typeAheadPointer position.
45 | * Optionally clear the search input on selection.
46 | * @return {void}
47 | */
48 | typeAheadSelect() {
49 | if( this.filteredOptions[ this.typeAheadPointer ] ) {
50 | this.select( this.filteredOptions[ this.typeAheadPointer ] );
51 | } else if (this.taggable && this.search.length){
52 | this.select(this.search)
53 | }
54 |
55 | if( this.clearSearchOnSelect ) {
56 | this.search = "";
57 | }
58 | },
59 | }
60 | }
--------------------------------------------------------------------------------
/src/app/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | import auth from '../modules/auth'
5 | import offers from '../modules/offers'
6 | import orders from '../modules/orders'
7 | import search from '../modules/search'
8 | import profile from '../modules/profile'
9 |
10 | Vue.use(Vuex)
11 |
12 | const mutations = {}
13 | const state = {}
14 | const components = {
15 | auth,
16 | offers,
17 | orders,
18 | search,
19 | profile
20 | }
21 | const modules = {}
22 | const getters = {}
23 | const actions = {}
24 |
25 | Object.keys(components).forEach(key => {
26 | if (!components.hasOwnProperty(key))
27 | return
28 | if (components[key].module)
29 | modules[key] = components[key].module
30 | if (components[key].getters) {
31 | Object.keys(components[key].getters).forEach(getter => {
32 | if (!components[key].getters.hasOwnProperty(getter))
33 | return
34 | if (getters[getter])
35 | throw `Getter ${getter} already exist`
36 | getters[getter] = components[key].getters[getter]
37 | })
38 | }
39 | })
40 |
41 | export default new Vuex.Store({
42 | state,
43 | mutations,
44 | modules,
45 | getters,
46 | actions
47 | })
48 |
--------------------------------------------------------------------------------
/src/app/uikit/application.scss:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | width: 100%;
5 | height: 100%;
6 | overflow: hidden;
7 |
8 | #react-root {
9 | height: 100%;
10 | }
11 | }
12 | .booster {
13 | -webkit-backface-visibility: hidden;
14 | -moz-backface-visibility: hidden;
15 | -ms-backface-visibility: hidden;
16 | backface-visibility: hidden;
17 |
18 | -webkit-perspective: 1000;
19 | -moz-perspective: 1000;
20 | -ms-perspective: 1000;
21 | perspective: 1000;
22 | }
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import store from './app/store';
3 | import Router from './app/router';
4 | import App from './App.vue';
5 | import BootstrapVue from 'bootstrap-vue';
6 | import 'bootstrap-vue/dist/bootstrap-vue.css';
7 | import 'bootstrap/dist/css/bootstrap.css';
8 | import vSelect from './app/select/comp/Select.vue';
9 | Vue.component('v-select', vSelect);
10 |
11 |
12 | let ethRpcUrl = "http://91.239.26.64:18545";
13 | window.web3 = new Web3(new Web3.providers.HttpProvider(ethRpcUrl));
14 |
15 | window.Vue = Vue;
16 | // Vue.prototype.$mysock = new sock('http://localhost:8080');
17 | // var vueUI = require('vue-ui');
18 |
19 | // Vue.use(vueUI);
20 |
21 | // import VueSocketio from 'vue-socket.io';
22 | // Vue.use(VueSocketio, 'http://localhost:8000');
23 |
24 | new Vue({
25 | el: '#app',
26 | store,
27 | router: Router,
28 | render: h => h(App)
29 | });
30 |
31 | Vue.use(BootstrapVue);
32 |
33 | window.offersRegistryAddress = "0x627f558d7f1a4c461e7e0126166395b9e63403db";
34 | window.dealsRegistryAddress = "0xf8609f2bedd2f263c28d8084e5c27eab0dfdaeb6";
35 | window.gasLimit = 3000000;
36 |
37 | window.getOffersRegistry = (address, account) => {
38 | var contract = new web3.eth.Contract(
39 | [{"constant":true,"inputs":[],"name":"getOffers","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_supplier","type":"address"}],"name":"getBySupplier","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_maxDepth","type":"uint256"}],"name":"peek","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_from","type":"string"},{"name":"_to","type":"string"}],"name":"getByRoute","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"peekTop","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_DEPTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_details","type":"string"},{"name":"_from","type":"string"},{"name":"_to","type":"string"}],"name":"newOffer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_offer","type":"address"}],"name":"LogNewOffer","type":"event"}]
40 | , address, {"from": account.address});
41 |
42 | contract.getOffers = function () {
43 | return this.methods.getOffers().call();
44 | }
45 |
46 | contract.getByRoute = function (_from, _to) {
47 | return this.methods.getByRoute(_from,_to).call();
48 | }
49 |
50 | contract.peek = function (depth) {
51 | return this.methods.peek(depth).call();
52 | }
53 |
54 | contract.newOffer = function (_details, _from, _to) {
55 | return account.signTransaction({"to": contract._address, "data":this.methods.newOffer(_details, _from, _to).encodeABI(), "gas":gasLimit}).then(function (res){
56 | return web3.eth.sendSignedTransaction(res.rawTransaction);
57 | })
58 | }
59 |
60 | return contract;
61 | }
62 |
63 | window.getOffer = (address, account) => {
64 | var contract = new web3.eth.Contract(
65 | [{"constant":true,"inputs":[],"name":"to","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isRunning","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getData","outputs":[{"name":"","type":"address"},{"name":"","type":"string"},{"name":"","type":"string"},{"name":"","type":"string"},{"name":"","type":"bytes1"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_details","type":"string"}],"name":"update","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"details","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_manager","type":"address"}],"name":"changeManager","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"state","outputs":[{"name":"","type":"bytes1"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"recall","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getManager","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"from","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_state","type":"bytes1"}],"name":"switchTo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_supplier","type":"address"},{"name":"_manager","type":"address"},{"name":"_details","type":"string"},{"name":"_from","type":"string"},{"name":"_to","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_who","type":"address"},{"indexed":false,"name":"_what","type":"string"}],"name":"LogUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_from","type":"bytes1"},{"indexed":false,"name":"_to","type":"bytes1"}],"name":"LogChangeState","type":"event"}]
66 | , address, {"from": account.address});
67 |
68 | contract.switchTo = function (_state) {
69 | return account.signTransaction({"to": contract._address, "data":this.methods.switchTo(_state).encodeABI(), "gas":gasLimit}).then(function (res){
70 | return web3.eth.sendSignedTransaction(res.rawTransaction);
71 | })
72 | }
73 |
74 | contract.close = function () {
75 | return account.signTransaction({"to": contract._address, "data":this.methods.recall().encodeABI(), "gas":gasLimit}).then(function (res){
76 | return web3.eth.sendSignedTransaction(res.rawTransaction);
77 | })
78 | }
79 |
80 | return contract;
81 | };
82 |
83 |
84 | window.getDealsRegistry = (address, account) => {
85 | var contract = new web3.eth.Contract(
86 | [{"constant":true,"inputs":[{"name":"_pos","type":"uint256"}],"name":"getMyOwnedDeal","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getMySupplyingDealCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_pos","type":"uint256"}],"name":"getMySupplyingDeal","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getMyOwnedDealCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_offer","type":"address"}],"name":"newDeal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getMySupplyingDeals","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getMyOwnedDeals","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
87 | , address, {"from": account.address});
88 |
89 | contract.getMySupplyingDeals = function () {
90 | return this.methods.getMySupplyingDeals().call();
91 | }
92 |
93 | contract.getMyOwnedDeals = function () {
94 | return this.methods.getMyOwnedDeals().call();
95 | }
96 |
97 | contract.newDeal = function (_offerAddress) {
98 | return account.signTransaction({"to": contract._address, "data":this.methods.newDeal(_offerAddress).encodeABI(), "gas":gasLimit}).then(function (res){
99 | return web3.eth.sendSignedTransaction(res.rawTransaction);
100 | })
101 | }
102 |
103 | return contract;
104 | }
105 |
106 | window.getDeal = (address, account) => {
107 | var contract = new web3.eth.Contract(
108 | [{"constant":true,"inputs":[],"name":"status","outputs":[{"name":"","type":"bytes1"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isRunning","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"customer","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getData","outputs":[{"name":"","type":"address"},{"name":"","type":"address"},{"name":"","type":"bool"},{"name":"","type":"bytes1"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getRecallClaim","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"compete","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"confirm","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"CLIENT","outputs":[{"name":"","type":"bytes1"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"offer","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"state","outputs":[{"name":"","type":"bytes1"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recallClaim","type":"address"}],"name":"recall","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_state","type":"bytes1"}],"name":"switchTo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"SUPPLIER","outputs":[{"name":"","type":"bytes1"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isCompleted","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_customer","type":"address"},{"name":"_offer","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_from","type":"bytes1"},{"indexed":false,"name":"_to","type":"bytes1"}],"name":"LogChangeState","type":"event"}]
109 | , address, {"from": account.address});
110 |
111 | contract.compete = function () {
112 | return account.signTransaction({"to": contract._address, "data":this.methods.compete().encodeABI(), "gas":gasLimit}).then(function (res){
113 | return web3.eth.sendSignedTransaction(res.rawTransaction);
114 | })
115 | }
116 |
117 | contract.confirm = function () {
118 | return account.signTransaction({"to": contract._address, "data":this.methods.confirm().encodeABI(), "gas":gasLimit}).then(function (res){
119 | return web3.eth.sendSignedTransaction(res.rawTransaction);
120 | })
121 | }
122 |
123 | return contract;
124 | }
125 |
--------------------------------------------------------------------------------
/static/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dapps-community/dapp-logistic-sample/058a3f6763fa3681d387b33bdca71e801e6c765f/static/.gitkeep
--------------------------------------------------------------------------------
/static/immla-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dapps-community/dapp-logistic-sample/058a3f6763fa3681d387b33bdca71e801e6c765f/static/immla-bg.png
--------------------------------------------------------------------------------
/static/logo-mini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dapps-community/dapp-logistic-sample/058a3f6763fa3681d387b33bdca71e801e6c765f/static/logo-mini.png
--------------------------------------------------------------------------------
/static/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dapps-community/dapp-logistic-sample/058a3f6763fa3681d387b33bdca71e801e6c765f/static/logo.png
--------------------------------------------------------------------------------
/test/e2e/custom-assertions/elementCount.js:
--------------------------------------------------------------------------------
1 | // A custom Nightwatch assertion.
2 | // the name of the method is the filename.
3 | // can be used in tests like this:
4 | //
5 | // browser.assert.elementCount(selector, count)
6 | //
7 | // for how to write custom assertions see
8 | // http://nightwatchjs.org/guide#writing-custom-assertions
9 | exports.assertion = function (selector, count) {
10 | this.message = 'Testing if element <' + selector + '> has count: ' + count
11 | this.expected = count
12 | this.pass = function (val) {
13 | return val === this.expected
14 | }
15 | this.value = function (res) {
16 | return res.value
17 | }
18 | this.command = function (cb) {
19 | var self = this
20 | return this.api.execute(function (selector) {
21 | return document.querySelectorAll(selector).length
22 | }, [selector], function (res) {
23 | cb.call(self, res)
24 | })
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/test/e2e/nightwatch.conf.js:
--------------------------------------------------------------------------------
1 | require('babel-register')
2 | var config = require('../../config')
3 |
4 | // http://nightwatchjs.org/gettingstarted#settings-file
5 | module.exports = {
6 | src_folders: ['test/e2e/specs'],
7 | output_folder: 'test/e2e/reports',
8 | custom_assertions_path: ['test/e2e/custom-assertions'],
9 |
10 | selenium: {
11 | start_process: true,
12 | server_path: require('selenium-server').path,
13 | host: '127.0.0.1',
14 | port: 4444,
15 | cli_args: {
16 | 'webdriver.chrome.driver': require('chromedriver').path
17 | }
18 | },
19 |
20 | test_settings: {
21 | default: {
22 | selenium_port: 4444,
23 | selenium_host: 'localhost',
24 | silent: true,
25 | globals: {
26 | devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port)
27 | }
28 | },
29 |
30 | chrome: {
31 | desiredCapabilities: {
32 | browserName: 'chrome',
33 | javascriptEnabled: true,
34 | acceptSslCerts: true
35 | }
36 | },
37 |
38 | firefox: {
39 | desiredCapabilities: {
40 | browserName: 'firefox',
41 | javascriptEnabled: true,
42 | acceptSslCerts: true
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/test/e2e/runner.js:
--------------------------------------------------------------------------------
1 | // 1. start the dev server using production config
2 | process.env.NODE_ENV = 'testing'
3 | var server = require('../../build/dev-server.js')
4 |
5 | server.ready.then(() => {
6 | // 2. run the nightwatch test suite against it
7 | // to run in additional browsers:
8 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings"
9 | // 2. add it to the --env flag below
10 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox`
11 | // For more information on Nightwatch's config file, see
12 | // http://nightwatchjs.org/guide#settings-file
13 | var opts = process.argv.slice(2)
14 | if (opts.indexOf('--config') === -1) {
15 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js'])
16 | }
17 | if (opts.indexOf('--env') === -1) {
18 | opts = opts.concat(['--env', 'chrome'])
19 | }
20 |
21 | var spawn = require('cross-spawn')
22 | var runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' })
23 |
24 | runner.on('exit', function (code) {
25 | server.close()
26 | process.exit(code)
27 | })
28 |
29 | runner.on('error', function (err) {
30 | server.close()
31 | throw err
32 | })
33 | })
34 |
--------------------------------------------------------------------------------
/test/e2e/specs/test.js:
--------------------------------------------------------------------------------
1 | // For authoring Nightwatch tests, see
2 | // http://nightwatchjs.org/guide#usage
3 |
4 | module.exports = {
5 | 'default e2e tests': function (browser) {
6 | // automatically uses dev Server port from /config.index.js
7 | // default: http://localhost:8080
8 | // see nightwatch.conf.js
9 | const devServer = browser.globals.devServerURL
10 |
11 | browser
12 | .url(devServer)
13 | .waitForElementVisible('#app', 5000)
14 | .assert.elementPresent('.hello')
15 | .assert.containsText('h1', 'Welcome to Your Vue.js App')
16 | .assert.elementCount('img', 1)
17 | .end()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/test/unit/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "mocha": true
4 | },
5 | "globals": {
6 | "expect": true,
7 | "sinon": true
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/unit/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | Vue.config.productionTip = false
4 |
5 | // require all test files (files that ends with .spec.js)
6 | const testsContext = require.context('./specs', true, /\.spec$/)
7 | testsContext.keys().forEach(testsContext)
8 |
9 | // require all src files except main.js for coverage.
10 | // you can also change this to match only the subset of files that
11 | // you want coverage for.
12 | const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/)
13 | srcContext.keys().forEach(srcContext)
14 |
--------------------------------------------------------------------------------
/test/unit/karma.conf.js:
--------------------------------------------------------------------------------
1 | // This is a karma config file. For more details see
2 | // http://karma-runner.github.io/0.13/config/configuration-file.html
3 | // we are also using it with karma-webpack
4 | // https://github.com/webpack/karma-webpack
5 |
6 | var webpackConfig = require('../../build/webpack.test.conf')
7 |
8 | module.exports = function (config) {
9 | config.set({
10 | // to run in additional browsers:
11 | // 1. install corresponding karma launcher
12 | // http://karma-runner.github.io/0.13/config/browsers.html
13 | // 2. add it to the `browsers` array below.
14 | browsers: ['PhantomJS'],
15 | frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'],
16 | reporters: ['spec', 'coverage'],
17 | files: ['./index.js'],
18 | preprocessors: {
19 | './index.js': ['webpack', 'sourcemap']
20 | },
21 | webpack: webpackConfig,
22 | webpackMiddleware: {
23 | noInfo: true
24 | },
25 | coverageReporter: {
26 | dir: './coverage',
27 | reporters: [
28 | { type: 'lcov', subdir: '.' },
29 | { type: 'text-summary' }
30 | ]
31 | }
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/test/unit/specs/Hello.spec.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Hello from '@/components/Hello'
3 |
4 | describe('Hello.vue', () => {
5 | it('should render correct contents', () => {
6 | const Constructor = Vue.extend(Hello)
7 | const vm = new Constructor().$mount()
8 | expect(vm.$el.querySelector('.hello h1').textContent)
9 | .to.equal('Welcome to Your Vue.js App')
10 | })
11 | })
12 |
--------------------------------------------------------------------------------
/usersStorage.js:
--------------------------------------------------------------------------------
1 | const mongo = require('./mongo');
2 |
3 | module.exports.registerUser = (user) => {
4 | console.log(user);
5 | };
6 |
7 | module.exports.saveUser = (user) => {
8 | return mongo.User.findOne({"id": user.id}).exec().then((answer) => {
9 | // console.log(answer);
10 | if (answer === null) {
11 | console.log('registering new user');
12 | user.token = Math.random().toString(36).slice(2);
13 | const userModel = new mongo.User(user);
14 | userModel.save();
15 | return {success: true, token: user.token};
16 | }
17 | else {
18 | console.log('already exists');
19 | return {success: false, message: "already exists"};
20 | }
21 | });
22 | };
23 |
24 | module.exports.getUsersByPubkeys = (pubkeys) => {
25 | return mongo.User.find({pubkey: {$in: pubkeys}}).exec();
26 | };
27 |
28 |
29 | module.exports.getUserByToken = (token) => {
30 | return mongo.User.findOne({"token": token}).exec();
31 | };
32 |
33 | module.exports.getUserById = (userId) => {
34 | return mongo.User.findOne({"id": userId}).exec();
35 | };
36 |
37 | module.exports.login = (userId, password) => {
38 | return mongo.User.findOne({"id": userId, "password": password}).exec().then((answer) => {
39 | if(answer === null) {
40 | console.log("User not found");
41 | return {success: false, message: 'Wrong username/password'};
42 | }
43 | else {
44 | console.log('Found user');
45 | return {success: true, token: answer.token}
46 | }
47 | });
48 | };
49 |
50 |
51 |
--------------------------------------------------------------------------------