11 |
12 |
13 |
14 |
Type full SQL command below
15 |
Table Name
16 |
WHERE clause
17 |
18 |
19 |
20 |
21 |
Column Name
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
Column Name
30 |
31 |
Value
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
Entries to be added
42 |
Columns to be created
43 |
{{key}} : {{value}}
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/test/client/dbControllerTest.js:
--------------------------------------------------------------------------------
1 |
2 | describe('DbController', function () {
3 | var homeController, httpBackend, dbService, tableService, location;
4 |
5 | // load the required modules to run these tests
6 | beforeEach(module('Dbview.DbController'));
7 | beforeEach(module('Dbview.dbService'));
8 | beforeEach(module('Dbview.tableService'));
9 |
10 |
11 | // inject the controller and services we will need to run tests
12 | beforeEach(inject(function ($controller, $rootScope, $httpBackend, $location, _dbService_, _tableService_) {
13 | dbService = _dbService_; // karma accesses our own services by padding with underscores
14 | tableService = _tableService_
15 | scope = $rootScope.$new();
16 | httpBackend = $httpBackend;
17 | location = $location;
18 | dbController = $controller('DbController', {
19 | $scope: scope,
20 | $httpBackend: $httpBackend
21 | });
22 | }));
23 |
24 | // actual tests
25 | describe('requestTable', function () {
26 | it('should send credentials and a table name in a post request', function () {
27 | dbService.creds = { username: 'Gregor' }
28 | httpBackend.expectPOST('/requestTable', {
29 | creds: { username: 'Gregor' },
30 | table: 'Gregor\'s SQL Table'
31 | }).respond(201);
32 | scope.requestTable('Gregor\'s SQL Table');
33 | httpBackend.flush();
34 | })
35 |
36 | it('should call activateTable with scope, tableName, and tableService after a succesful request', function () {
37 | httpBackend.whenPOST('/requestTable').respond(200, { table: 'Gregor\'s Table' });
38 | sinon.spy(scope, 'activateTable');
39 | scope.requestTable('Gregor\'s SQL Table');
40 | httpBackend.flush();
41 | expect(scope.activateTable.calledWith(scope, 'Gregor\'s SQL Table', tableService)).to.be.ok;
42 | })
43 |
44 | it('should call addTable data to save the table data in the tableService', function () {
45 | httpBackend.whenPOST('/requestTable').respond(200, { data: '{Datas: 0}' });
46 | sinon.spy(tableService, 'addTableData');
47 | scope.requestTable('Gregor\'s SQL Table');
48 | httpBackend.flush();
49 | expect((tableService.addTableData).calledWith('Gregor\'s SQL Table', { data: '{Datas: 0}' })).to.be.ok;
50 | })
51 | })
52 |
53 | describe('activateTable', function () {
54 | it('should call activate table if table is not activated yet', function () {
55 | sinon.spy(tableService, 'activateTable')
56 | scope.activateTable(scope, 'myTable', tableService);
57 | expect((tableService.activateTable).calledWith('myTable')).to.be.ok;
58 | })
59 |
60 | it('should not call activate table if table is already activated', function () {
61 | sinon.spy(tableService, 'activateTable')
62 | scope.onlineTables = ['myTable']
63 | scope.activateTable(scope, 'myTable', tableService);
64 | expect((tableService.activateTable).called).to.not.be.ok;
65 | })
66 | })
67 | });
--------------------------------------------------------------------------------
/src/client/controllers/tableController.js:
--------------------------------------------------------------------------------
1 |
2 | /*jshint esversion: 6 */
3 | angular
4 | .module('Dbview.TableController', ['ui.router','ngSanitize', 'ngCsv'])
5 | .controller('TableController', ['$scope', 'tableService', '$stateParams', 'dbService', '$http', '$state', '$timeout', tableController]);
6 |
7 | function tableController($scope, tableService, $stateParams, dbService, $http, $state, $timeout) {
8 | //scope.name is the name of the table currently on display
9 | $scope.name = tableService.currentTable;
10 | $scope.displayName = tableService.currentTable;
11 | $scope.dataToDisplay = tableService.getData($scope.name);
12 |
13 | // reference the data that will be rendered to a table format
14 | $scope.gridData = {
15 | data: $scope.dataToDisplay,
16 | enableFiltering: true,
17 | };
18 | $scope.queryOptions = ['Text Query', 'Create Table', 'Insert Rows', 'Update Rows', 'Delete Rows', 'Drop Table'];
19 | $scope.dataTypes = ['Integer', 'Varchar', 'Serial', 'Date', 'Time'];
20 | $scope.rowsToAdd = {};
21 | $scope.saveEntry = (column, value) => {
22 | $scope.rowsToAdd[column] = value;
23 | $scope.columnName = '';
24 | $scope.entryValue = '';
25 | };
26 | $scope.removeEntry = (column) => delete $scope.rowsToAdd[column];
27 |
28 | $scope.queryData = {};
29 |
30 | $scope.exportFile = function (){
31 | let columns = {};
32 |
33 | for (let key in tableService.tableData[tableService.currentTable][0]){
34 | if(!columns[key]) columns[key] = key;
35 | }
36 |
37 | tableService.tableData[tableService.currentTable].unshift(columns);
38 |
39 | return tableService.tableData[tableService.currentTable];
40 | }
41 |
42 | // execute a raw query and update displayed table
43 | $scope.executeQuery = function (query) {
44 | let route;
45 | let tableName = $scope.name;
46 | switch($scope.queryType) {
47 | case 'Create Table': route = '/createTable'; break;
48 | case 'Insert Rows': route = '/insert'; break;
49 | case 'Update Rows': route = '/update'; break;
50 | case 'Delete Rows': route = '/delete'; break;
51 | case 'Drop Table': route = '/dropTable'; break;
52 | case 'Text Query': route = '/query'; break;
53 | default: return;
54 | }
55 |
56 | $http({
57 | method: 'POST',
58 | url: route,
59 | headers: {
60 | 'Content-Type': 'application/json'
61 | },
62 | data: { creds: dbService.creds, where: tableName, valuesToInsert: $scope.rowsToAdd, table: tableName }
63 | })
64 | .then((response) => {
65 | const columns = Object.keys(response.data[0]).map( (colname) => {
66 | console.log(colname);
67 | return { field: colname };
68 | });
69 |
70 | // save the data in table service and update grid data
71 |
72 | tableService.addTableData($scope.name, response.data)
73 |
74 | $scope.dataToDisplay = tableService.getData($scope.name);
75 | $scope.gridData = {
76 | columnDefs: columns,
77 | data: $scope.dataToDisplay,
78 | enableFiltering: true,
79 | };
80 | $scope.displayName = 'Query Result';
81 | });
82 | };
83 | }
84 |
--------------------------------------------------------------------------------
/bower_components/angular-csv-import/examples/app/styles/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 20px;
3 | padding-bottom: 20px;
4 | background: #2c3e50;
5 | }
6 |
7 | div.container {
8 | width: 80%;
9 | margin: 0 auto;
10 | text-align: center;
11 | }
12 |
13 | div.block.row {
14 | width: 100%;
15 | margin: 10px 0px;
16 | }
17 |
18 | div.block.row > div {
19 | display: inline-block;
20 | vertical-align: middle;
21 | }
22 |
23 | div.block.row > div.title {
24 | width: 30%;
25 | color: white;
26 | }
27 |
28 | div.import>div>div.label {
29 | display: inline-block;
30 | width: 30%;
31 | text-align: left;
32 | color: white;
33 | font-family: 'Verdana';
34 | font-size: 14px;
35 | }
36 |
37 | div.import > div {
38 | margin: 15px 0px;
39 | }
40 |
41 | div.import > div > span {
42 | color: white;
43 | }
44 |
45 | div.import > div> span > input[type="text"] {
46 | font-size: 18px;
47 | color: #d6492f;
48 | font-weight: bold;
49 | border-radius: none;
50 | outline: none;
51 | }
52 |
53 | div.import>div>div>input[type="file"] {
54 | color: transparent;
55 | padding: 0;
56 | }
57 |
58 | div.import>div>div>input[type="file"]::-webkit-file-upload-button {
59 | visibility: hidden;
60 | }
61 |
62 | div.import>div>div>input[type="file"]::before {
63 | content: attr(upload-button-label);
64 | display: inline-block;
65 | background-image: linear-gradient(to top, #f9f9f9 0px, #f9f9f9 50%, #e3e3e3 50%, #e3e3e3 100% );
66 | color: #444;
67 | border: 1px solid #999;
68 | border-radius: 3px;
69 | padding: 5px 8px;
70 | outline: none;
71 | white-space: nowrap;
72 | -webkit-user-select: none;
73 | cursor: pointer;
74 | text-shadow: 1px 1px #fff;
75 | font-weight: 700;
76 | font-size: 14px;
77 | }
78 | div.import>div>div>input[type="file"]:hover::before {
79 | border-color: black;
80 | }
81 | div.import>div>div>input[type="file"]:active::before {
82 | background: -webkit-linear-gradient(top, #e3e3e3, #f9f9f9);
83 | }
84 |
85 | div.block {
86 | display: inline-block;
87 | vertical-align: middle;
88 | text-align: left;
89 | }
90 |
91 | div.block.left {
92 | }
93 |
94 | div.block>div.content {
95 | border: 5px dashed #d6492f;
96 | background: none;
97 | padding: 0px;
98 | border-radius: 3px;
99 | }
100 |
101 | div.block>div.content>pre {
102 | font-size: 15px;
103 | font-family: 'Courier';
104 | background: #F0F0F0;
105 | padding: 10px;
106 | margin: 0;
107 | }
108 |
109 | footer {
110 | }
111 |
112 | footer>div {
113 | color: white;
114 | bottom: 40px;
115 | display: inline-block;
116 | margin: 0px 50px;
117 | }
118 |
119 | footer>div a {
120 | color: white;
121 | text-decoration: none;
122 | font-size: 18px;
123 | }
124 |
125 | footer>div a:hover {
126 | text-decoration: underline;
127 | vertical-align: bottom;
128 | }
129 |
130 | footer>div.twitter {
131 | left: 40px;
132 | }
133 |
134 | footer>div.twitter>div {
135 | display: inline-block;
136 | vertical-align: middle;
137 | }
138 |
139 | footer>div.twitter>div.avatar {
140 | margin: 0px 5px 0px 0px;
141 | background: url("https://avatars1.githubusercontent.com/u/820299?v=3&s=460");
142 | background-size: contain;
143 | border: solid 3px white;
144 | width: 40px;
145 | height: 40px;
146 | border-radius: 100px;
147 | }
148 |
149 | footer>div.github {
150 | right: 40px;
151 | }
152 |
153 | footer>div.github>div {
154 | display: inline-block;
155 | vertical-align: middle;
156 | }
157 |
158 | footer>div.github>div.icon {
159 | font-size: 35px;
160 | margin: 0px 5px 0px 0px;
161 | }
162 |
163 |
--------------------------------------------------------------------------------
/bower_components/angular-csv-import/dist/angular-csv-import.min.js:
--------------------------------------------------------------------------------
1 | /*! angular-csv-import - v0.0.36 - 2016-11-01
2 | * Copyright (c) 2016 ; Licensed */
3 | "use strict";var csvImport=angular.module("ngCsvImport",[]);csvImport.directive("ngCsvImport",function(){return{restrict:"E",transclude:!0,replace:!0,scope:{content:"=?",header:"=?",headerVisible:"=?",separator:"=?",separatorVisible:"=?",result:"=?",encoding:"=?",encodingVisible:"=?",accept:"=?",acceptSize:"=?",acceptSizeExceedCallback:"=?",callback:"=?",mdButtonClass:"@?",mdInputClass:"@?",mdButtonTitle:"@?",mdSvgIcon:"@?",uploadButtonLabel:"="},template:function(a,b){var c=angular.isDefined(b.material),d=angular.isDefined(b.multiple);return'
"},link:function(a,b,c){if(a.separatorVisible=!!a.separatorVisible,a.headerVisible=!!a.headerVisible,a.acceptSize=a.acceptSize||Number.POSITIVE_INFINITY,a.material=angular.isDefined(c.material),a.multiple=angular.isDefined(c.multiple),a.multiple)throw new Error("Multiple attribute is not supported yet.");var d=angular.element(b[0].querySelector('input[type="file"]')),e=angular.element(b[0].querySelector("md-input-container"));if(a.material&&d){if(d.removeClass("ng-show"),d.addClass("ng-hide"),e){var f=angular.element(e[0].querySelector("div.md-errors-spacer"));f&&f.remove()}a.onClick=function(){d.click()}}angular.element(b[0].querySelector(".separator-input")).on("keyup",function(b){if(null!=a.content){var c={csv:a.content,header:a.header,separator:b.target.value,encoding:a.encoding};a.result=g(c),a.$apply(),"function"==typeof a.callback&&a.callback(b)}}),b.on("change",function(b){if(b.target.files.length){if(b.target.files[0].size>a.acceptSize)return void("function"==typeof a.acceptSizeExceedCallback&&a.acceptSizeExceedCallback(b.target.files[0]));a.filename=b.target.files[0].name;var c=new FileReader;if(c.onload=function(c){a.$apply(function(){var d={csv:c.target.result.replace(/\r\n|\r/g,"\n"),header:a.header,separator:a.separator};a.content=d.csv,a.result=g(d),a.result.filename=a.filename,a.$$postDigest(function(){"function"==typeof a.callback&&a.callback(b)})})},"file"!==b.target.type||null==b.target.files&&null==b.srcElement.files){if(null!=a.content){var d={csv:a.content,header:!a.header,separator:a.separator};a.result=g(d),a.$$postDigest(function(){"function"==typeof a.callback&&a.callback(b)})}}else c.readAsText((b.srcElement||b.target).files[0],a.encoding)}});var g=function(a){var b=a.csv.split(new RegExp('\n(?![^"]*"(?:(?:[^"]*"){2})*[^"]*$)')),c=[],d=0,e=b[0].split(a.separator).length,f=[];a.header&&(f=b[0].split(a.separator),d=1);for(var g=d;g
- v<%= pkg.version %> - ' +
16 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
17 | '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
18 | '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
19 | ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
20 | // Task configuration.
21 | concat: {
22 | options: {
23 | banner: '<%= banner %>',
24 | stripBanners: true
25 | },
26 | dist: {
27 | src: ['lib/<%= pkg.name %>.js'],
28 | dest: 'dist/<%= pkg.name %>.js'
29 | },
30 | examples: {
31 | src: ['lib/<%= pkg.name %>.js'],
32 | dest: 'examples/app/bower_components/angular-csv-import/dist/<%= pkg.name %>.js'
33 | }
34 | },
35 | bump: {
36 | options: {
37 | files: ['package.json', 'bower.json'],
38 | updateConfigs: [],
39 | commit: true,
40 | commitMessage: 'Release v%VERSION%',
41 | commitFiles: ['package.json', 'bower.json'],
42 | createTag: true,
43 | tagName: 'v%VERSION%',
44 | tagMessage: 'Version %VERSION%',
45 | push: true,
46 | pushTo: 'origin',
47 | gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d'
48 | }
49 | },
50 | uglify: {
51 | options: {
52 | banner: '<%= banner %>'
53 | },
54 | dist: {
55 | src: '<%= concat.dist.dest %>',
56 | dest: 'dist/<%= pkg.name %>.min.js'
57 | },
58 | examples: {
59 | src: '<%= concat.dist.dest %>',
60 | dest: 'examples/app/bower_components/angular-csv-import/dist/<%= pkg.name %>.min.js'
61 | }
62 | },
63 | jshint: {
64 | options: {
65 | curly: true,
66 | eqeqeq: true,
67 | immed: true,
68 | latedef: true,
69 | newcap: true,
70 | noarg: true,
71 | sub: true,
72 | undef: true,
73 | unused: true,
74 | boss: true,
75 | eqnull: true,
76 | browser: true,
77 | globalstrict: true,
78 | globals: {
79 | jQuery: true,
80 | angular: false,
81 | Odometer: false
82 | }
83 | },
84 | gruntfile: {
85 | src: 'Gruntfile.js'
86 | },
87 | lib_test: {
88 | src: ['lib/**/*.js', 'test/**/*.js']
89 | }
90 | },
91 | qunit: {
92 | files: ['test/**/*.html']
93 | },
94 | watch: {
95 | gruntfile: {
96 | files: '<%= jshint.gruntfile.src %>',
97 | tasks: ['jshint:gruntfile']
98 | },
99 | lib_test: {
100 | files: '<%= jshint.lib_test.src %>',
101 | tasks: ['jshint:lib_test', 'qunit']
102 | }
103 | },
104 | cssmin: {
105 | minify: {
106 | expand: true,
107 | cwd: 'lib/',
108 | src: ['*.css', '!*.min.css'],
109 | dest: 'dist/',
110 | ext: '.min.css'
111 | }
112 | },
113 | 'gh-pages': {
114 | options: {
115 | base: 'examples/dist'
116 | },
117 | src: '**/*'
118 | }
119 | });
120 |
121 | // Default task.
122 | grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'cssmin']);
123 |
124 | grunt.registerTask('pages', ['gh-pages']);
125 |
126 | };
127 |
--------------------------------------------------------------------------------
/bower_components/angular-csv-import/examples/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Angular CSV Import
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
33 |
36 |
37 |
38 |
39 |
48 |
49 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/bower_components/angular-csv-import/examples/app/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Page Not Found :(
6 |
141 |
142 |
143 |
144 |
Not found :(
145 |
Sorry, but the page you were trying to view does not exist.
146 |
It looks like this was the result of either:
147 |
148 | - a mistyped address
149 | - an out-of-date link
150 |
151 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/test/client/tableControllerTest.js:
--------------------------------------------------------------------------------
1 |
2 | describe('TableController', function () {
3 | var tableController, httpBackend, dbService, location;
4 |
5 | // load the required modules to run these tests
6 | beforeEach(module('Dbview.TableController'));
7 | beforeEach(module('Dbview.dbService'));
8 | beforeEach(module('Dbview.tableService'));
9 |
10 | // inject the controller and services we will need to run tests
11 | beforeEach(inject(function ($controller, $rootScope, $httpBackend, $location, _dbService_, _tableService_) {
12 | dbService = _dbService_; // karma accesses our own services by padding with underscores
13 | tableService = _tableService_
14 | scope = $rootScope.$new();
15 | httpBackend = $httpBackend;
16 | location = $location;
17 | tableController = $controller('TableController', {
18 | $scope: scope,
19 | $httpBackend: $httpBackend
20 | });
21 | }));
22 |
23 | // actual tests
24 | describe('saveEntry', function () {
25 | it('should save column and value in scope', function () {
26 | scope.saveEntry('Gregor\'s Column', 'Gregor\'s Value');
27 | expect(scope.rowsToAdd).to.deep.equal({ 'Gregor\'s Column': 'Gregor\'s Value' });
28 | })
29 |
30 | it('should clear column name and entry value forms', function () {
31 | scope.saveEntry('Gregor\'s Column', 'Gregor\'s Value');
32 | expect(scope.columnName).to.equal('');
33 | expect(scope.entryValue).to.equal('');
34 | })
35 | });
36 |
37 | describe('executeQuery', function () {
38 | it('makes a post request to the correct route', function () {
39 | scope.queryType = 'Create Table';
40 | httpBackend.expectPOST('/createTable', { "where": "query", "valuesToInsert": {}, "table": "" }).respond(200, [{ a: 3 }]);
41 | scope.executeQuery('query');
42 |
43 | scope.queryType = 'Insert Rows';
44 | httpBackend.expectPOST('/insert', { "where": "query", "valuesToInsert": {}, "table": "" }).respond(200, [{ a: 3 }]);
45 | scope.executeQuery('query');
46 |
47 | scope.queryType = 'Update Rows';
48 | httpBackend.expectPOST('/update', { "where": "query", "valuesToInsert": {}, "table": "" }).respond(200, [{ a: 3 }]);
49 | scope.executeQuery('query');
50 |
51 | scope.queryType = 'Delete Rows';
52 | httpBackend.expectPOST('/delete', { "where": "query", "valuesToInsert": {}, "table": "" }).respond(200, [{ a: 3 }]);
53 | scope.executeQuery('query');
54 |
55 | scope.queryType = 'Drop Table';
56 | httpBackend.expectPOST('/dropTable', { "where": "query", "valuesToInsert": {}, "table": "" }).respond(200, [{ a: 3 }]);
57 | scope.executeQuery('query');
58 |
59 | scope.queryType = 'Text Query';
60 | httpBackend.expectPOST('/query', { "where": "query", "valuesToInsert": {}, "table": "" }).respond(200, [{ a: 3 }]);
61 | scope.executeQuery('query');
62 | httpBackend.flush();
63 | })
64 |
65 | it('sends object with creds, where clause, values to insert, and tablename', function () {
66 | scope.queryType = 'Insert Rows';
67 | scope.rowsToAdd = { 'Gregor\'s Column': 'Gregor\'s Value' }
68 | scope.name = 'Gregor\'s Table';
69 | httpBackend.expectPOST('/insert', {
70 | where: "query",
71 | valuesToInsert: { 'Gregor\'s Column': 'Gregor\'s Value' },
72 | table: "Gregor\'s Table"
73 | }).respond(200, [{ a: 3 }]);
74 | scope.executeQuery('query');
75 | httpBackend.flush();
76 | });
77 |
78 | it('should call add table data method of table service to save response data', function () {
79 | sinon.spy(tableService, 'addTableData');
80 | scope.name = 'Gregor\'s Table';
81 | scope.queryType = 'Update Rows';
82 | httpBackend.whenPOST('/update').respond(200, [{ b: 3 }]);
83 | scope.executeQuery('query');
84 | httpBackend.flush();
85 | expect((tableService.addTableData).calledWith('Gregor\'s Table', [{ b: 3 }])).to.be.ok;
86 | });
87 |
88 | it('should update grid data', function () {
89 | var stub = sinon.stub(tableService, 'getData')
90 | scope.gridData = {};
91 | stub.returns([{ 'column 1': 'val' }]);
92 | scope.name = 'Gregor\'s Table';
93 | scope.queryType = 'Update Rows';
94 | httpBackend.whenPOST('/update').respond(200, [{ b: 3 }]);
95 | scope.executeQuery('query');
96 | httpBackend.flush();
97 | expect(scope.gridData.data).to.deep.equal([{ 'column 1': 'val' }])
98 | });
99 |
100 | });
101 | });
--------------------------------------------------------------------------------
/test/supertest.js:
--------------------------------------------------------------------------------
1 | const request = require('supertest');
2 | // Start server
3 | const path = require('path');
4 | const fs = require('fs');
5 | const assert = require('assert');
6 |
7 | const app = require('../src/server/server.js');
8 |
9 | const PORT = process.env.PORT || 3000;
10 | const HOST = `http://localhost:${PORT}`;
11 |
12 | const testLogin = {
13 | host: 'ec2-54-243-212-72.compute-1.amazonaws.com',
14 | database: 'd7ctrh5hg6aadj',
15 | user: 'dxrwecviorvrto',
16 | port: 5432,
17 | password: 'BDyJHAElIeyxjSLNxI1NBYu3Z4',
18 | dialect: 'postgres'
19 | }
20 | const testTable = 'users';
21 | let testConnection;
22 |
23 | /**
24 | * include an assertion library here so that you can make assertions other than those
25 | * provided by supertest. Choose whichever assertion library suits you.
26 | */
27 | // const expect = require('expect');
28 | // const expect = require('chai').expect;
29 | // const assert = require('chai').assert;
30 |
31 | describe('Route integration', () => {
32 | //test to get index.html
33 | describe('/', () => {
34 | describe('GET', () => {
35 | it('responds to page load with 200 status and text/html content type', done => {
36 | request(HOST)
37 | .get('/')
38 | .expect('Content-Type', /text\/html/)
39 | .expect(200, done);
40 | });
41 | });
42 | });
43 | //all tests for data validation and database interactivity are detailed below
44 | describe('database interaction', () => {
45 | describe('POST', () => {
46 | it('sending DB login info responds with list of tables', done => {
47 | request(HOST)
48 | .post('/requestDB')
49 | .send({ creds: testLogin })
50 | .expect('Content-Type', /application\/json/)
51 | .end( (err, res) => {
52 | assert.equal(typeof res.body[0], 'string');
53 | done();
54 | });
55 | });
56 | it('sending a table name returns that table', done => {
57 | request(HOST)
58 | .post('/requestTable')
59 | .send({ creds: testLogin, table: 'users' })
60 | .expect('Content-Type', /application\/json/)
61 | .end( (err, res) => {
62 | assert.equal(typeof res.body[0].id, 'number');
63 | done();
64 | });
65 | });
66 | //still need column name parameters
67 | it('creating a table creates a new table in the database', done => {
68 | request(HOST)
69 | .post('/createTable')
70 | .send({ creds: testLogin, table: 'users2', valuesToInsert: { id: 'serial', name: 'varchar', games: 'integer', createdAt: 'time', updatedAt: 'time'} })
71 | .expect('Content-Type', /application\/json/)
72 | .end( (err, res) => {
73 | assert.equal(res.body instanceof Array, true);
74 | done();
75 | });
76 | });
77 | it('can insert new rows into a table', done => {
78 | request(HOST)
79 | .post('/insert')
80 | .send({ creds: testLogin, table: 'users2', valuesToInsert: { name: 'Clegane', games: '8' }})
81 | .expect('Content-Type', /application\/json/)
82 | .end( (err, res) => {
83 | assert.equal(res.body[0].name, 'Clegane');
84 | done();
85 | });
86 | });
87 | //go from here
88 | it('can update a row in a table', done => {
89 | request(HOST)
90 | .post('/update')
91 | .send({ creds: testLogin, table: 'users2', where: `name='Clegane'`, valuesToInsert: {'games': 8 } })
92 | .expect('Content-Type', /application\/json/)
93 | .end( (err, res) => {
94 | assert.equal(res.body[0].games, 8);
95 | done();
96 | });
97 | });
98 | it('can delete a row in a table', done => {
99 | request(HOST)
100 | .post('/delete')
101 | .send({ creds: testLogin, table: 'users2', where: `name='Clegane'` })
102 | .expect('Content-Type', /application\/json/)
103 | .end( (err, res) => {
104 | console.log(res.body);
105 | assert.equal(res.body.length, 0);
106 | done();
107 | });
108 | });
109 | it('can drop a table', done => {
110 | request(HOST)
111 | .post('/dropTable')
112 | .send({ creds: testLogin, where: 'users2' })
113 | .expect('Content-Type', /application\/json/)
114 | .end( (err, res) => {
115 | console.log(res.body);
116 |
117 | done();
118 | });
119 | });
120 | });
121 | });
122 | });
123 |
--------------------------------------------------------------------------------
/bower_components/angular-csv-import/lib/angular-csv-import.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var csvImport = angular.module('ngCsvImport', []);
4 |
5 | csvImport.directive('ngCsvImport', function() {
6 | return {
7 | restrict: 'E',
8 | transclude: true,
9 | replace: true,
10 | scope:{
11 | content:'=?',
12 | header: '=?',
13 | headerVisible: '=?',
14 | separator: '=?',
15 | separatorVisible: '=?',
16 | result: '=?',
17 | encoding: '=?',
18 | encodingVisible: '=?',
19 | accept: '=?',
20 | acceptSize: '=?',
21 | acceptSizeExceedCallback: '=?',
22 | callback: '=?',
23 | mdButtonClass: '@?',
24 | mdInputClass: '@?',
25 | mdButtonTitle: '@?',
26 | mdSvgIcon: '@?',
27 | uploadButtonLabel: '='
28 | },
29 | template: function(element, attrs) {
30 | var material = angular.isDefined(attrs.material);
31 | var multiple = angular.isDefined(attrs.multiple);
32 | return ''+
33 | '
' :
35 | '') +
36 | '
'+
37 | '
'+
38 | '
Seperator
'+
39 | '
'+
40 | ''+
41 | '
' +
42 | '' +
43 | (material ? ' {{mdButtonTitle}}' : '') +
44 | '
'+
45 | '
';
46 | },
47 | link: function(scope, element, attrs) {
48 | scope.separatorVisible = !!scope.separatorVisible;
49 | scope.headerVisible = !!scope.headerVisible;
50 | scope.acceptSize = scope.acceptSize || Number.POSITIVE_INFINITY;
51 | scope.material = angular.isDefined(attrs.material);
52 | scope.multiple = angular.isDefined(attrs.multiple);
53 | if (scope.multiple) {
54 | throw new Error("Multiple attribute is not supported yet.");
55 | }
56 | var input = angular.element(element[0].querySelector('input[type="file"]'));
57 | var inputContainer = angular.element(element[0].querySelector('md-input-container'));
58 |
59 | if (scope.material && input) {
60 | input.removeClass("ng-show");
61 | input.addClass("ng-hide");
62 | if (inputContainer) {
63 | var errorSpacer = angular.element(inputContainer[0].querySelector('div.md-errors-spacer'));
64 | if (errorSpacer) {
65 | errorSpacer.remove();
66 | }
67 | }
68 | scope.onClick = function() {
69 | input.click();
70 | };
71 | }
72 |
73 | angular.element(element[0].querySelector('.separator-input')).on('keyup', function(e) {
74 | if ( scope.content != null ) {
75 | var content = {
76 | csv: scope.content,
77 | header: scope.header,
78 | separator: e.target.value,
79 | encoding: scope.encoding
80 | };
81 | scope.result = csvToJSON(content);
82 | scope.$apply();
83 | if ( typeof scope.callback === 'function' ) {
84 | scope.callback(e);
85 | }
86 | }
87 | });
88 |
89 | element.on('change', function(onChangeEvent) {
90 | if (!onChangeEvent.target.files.length){
91 | return;
92 | }
93 |
94 | if (onChangeEvent.target.files[0].size > scope.acceptSize){
95 | if ( typeof scope.acceptSizeExceedCallback === 'function' ) {
96 | scope.acceptSizeExceedCallback(onChangeEvent.target.files[0]);
97 | }
98 | return;
99 | }
100 |
101 | scope.filename = onChangeEvent.target.files[0].name;
102 | var reader = new FileReader();
103 | reader.onload = function(onLoadEvent) {
104 | scope.$apply(function() {
105 | var content = {
106 | csv: onLoadEvent.target.result.replace(/\r\n|\r/g,'\n'),
107 | header: scope.header,
108 | separator: scope.separator
109 | };
110 | scope.content = content.csv;
111 | scope.result = csvToJSON(content);
112 | scope.result.filename = scope.filename;
113 | scope.$$postDigest(function(){
114 | if ( typeof scope.callback === 'function' ) {
115 | scope.callback(onChangeEvent);
116 | }
117 | });
118 | });
119 | };
120 |
121 | if ( (onChangeEvent.target.type === "file") && (onChangeEvent.target.files != null || onChangeEvent.srcElement.files != null) ) {
122 | reader.readAsText((onChangeEvent.srcElement || onChangeEvent.target).files[0], scope.encoding);
123 | } else {
124 | if ( scope.content != null ) {
125 | var content = {
126 | csv: scope.content,
127 | header: !scope.header,
128 | separator: scope.separator
129 | };
130 | scope.result = csvToJSON(content);
131 | scope.$$postDigest(function(){
132 | if ( typeof scope.callback === 'function' ) {
133 | scope.callback(onChangeEvent);
134 | }
135 | });
136 | }
137 | }
138 | });
139 |
140 | var csvToJSON = function(content) {
141 | var lines=content.csv.split(new RegExp('\n(?![^"]*"(?:(?:[^"]*"){2})*[^"]*$)'));
142 | var result = [];
143 | var start = 0;
144 | var columnCount = lines[0].split(content.separator).length;
145 |
146 | var headers = [];
147 | if (content.header) {
148 | headers=lines[0].split(content.separator);
149 | start = 1;
150 | }
151 |
152 | for (var i=start; i'+
35 | '' :
37 | '') +
38 | ''+
39 | ''+
40 | '
Seperator
'+
41 | '
'+
42 | ' '+
43 | '' +
44 | '' +
45 | (material ? ' {{mdButtonTitle}}' : '') +
46 | '
'+
47 | ' ';
48 | },
49 | link: function(scope, element, attrs) {
50 | scope.separatorVisible = !!scope.separatorVisible;
51 | scope.headerVisible = !!scope.headerVisible;
52 | scope.acceptSize = scope.acceptSize || Number.POSITIVE_INFINITY;
53 | scope.material = angular.isDefined(attrs.material);
54 | scope.multiple = angular.isDefined(attrs.multiple);
55 | if (scope.multiple) {
56 | throw new Error("Multiple attribute is not supported yet.");
57 | }
58 | var input = angular.element(element[0].querySelector('input[type="file"]'));
59 | var inputContainer = angular.element(element[0].querySelector('md-input-container'));
60 |
61 | if (scope.material && input) {
62 | input.removeClass("ng-show");
63 | input.addClass("ng-hide");
64 | if (inputContainer) {
65 | var errorSpacer = angular.element(inputContainer[0].querySelector('div.md-errors-spacer'));
66 | if (errorSpacer) {
67 | errorSpacer.remove();
68 | }
69 | }
70 | scope.onClick = function() {
71 | input.click();
72 | };
73 | }
74 |
75 | angular.element(element[0].querySelector('.separator-input')).on('keyup', function(e) {
76 | if ( scope.content != null ) {
77 | var content = {
78 | csv: scope.content,
79 | header: scope.header,
80 | separator: e.target.value,
81 | encoding: scope.encoding
82 | };
83 | scope.result = csvToJSON(content);
84 | scope.$apply();
85 | if ( typeof scope.callback === 'function' ) {
86 | scope.callback(e);
87 | }
88 | }
89 | });
90 |
91 | element.on('change', function(onChangeEvent) {
92 | if (!onChangeEvent.target.files.length){
93 | return;
94 | }
95 |
96 | if (onChangeEvent.target.files[0].size > scope.acceptSize){
97 | if ( typeof scope.acceptSizeExceedCallback === 'function' ) {
98 | scope.acceptSizeExceedCallback(onChangeEvent.target.files[0]);
99 | }
100 | return;
101 | }
102 |
103 | scope.filename = onChangeEvent.target.files[0].name;
104 | var reader = new FileReader();
105 | reader.onload = function(onLoadEvent) {
106 | scope.$apply(function() {
107 | var content = {
108 | csv: onLoadEvent.target.result.replace(/\r\n|\r/g,'\n'),
109 | header: scope.header,
110 | separator: scope.separator
111 | };
112 | scope.content = content.csv;
113 | scope.result = csvToJSON(content);
114 | scope.result.filename = scope.filename;
115 | scope.$$postDigest(function(){
116 | if ( typeof scope.callback === 'function' ) {
117 | scope.callback(onChangeEvent);
118 | }
119 | });
120 | });
121 | };
122 |
123 | if ( (onChangeEvent.target.type === "file") && (onChangeEvent.target.files != null || onChangeEvent.srcElement.files != null) ) {
124 | reader.readAsText((onChangeEvent.srcElement || onChangeEvent.target).files[0], scope.encoding);
125 | } else {
126 | if ( scope.content != null ) {
127 | var content = {
128 | csv: scope.content,
129 | header: !scope.header,
130 | separator: scope.separator
131 | };
132 | scope.result = csvToJSON(content);
133 | scope.$$postDigest(function(){
134 | if ( typeof scope.callback === 'function' ) {
135 | scope.callback(onChangeEvent);
136 | }
137 | });
138 | }
139 | }
140 | });
141 |
142 | var csvToJSON = function(content) {
143 | var lines=content.csv.split(new RegExp('\n(?![^"]*"(?:(?:[^"]*"){2})*[^"]*$)'));
144 | var result = [];
145 | var start = 0;
146 | var columnCount = lines[0].split(content.separator).length;
147 |
148 | var headers = [];
149 | if (content.header) {
150 | headers=lines[0].split(content.separator);
151 | start = 1;
152 | }
153 |
154 | for (var i=start; i