Initial commit from Gomix.
This commit is contained in:
parent
3603695e3f
commit
50b0188343
111
.bashrc
Normal file
111
.bashrc
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
# ~/.bashrc: executed by bash(1) for non-login shells.
|
||||||
|
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
|
||||||
|
# for examples
|
||||||
|
|
||||||
|
# If not running interactively, don't do anything
|
||||||
|
case $- in
|
||||||
|
*i*) ;;
|
||||||
|
*) return;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# don't put duplicate lines or lines starting with space in the history.
|
||||||
|
# See bash(1) for more options
|
||||||
|
HISTCONTROL=ignoreboth
|
||||||
|
|
||||||
|
# append to the history file, don't overwrite it
|
||||||
|
shopt -s histappend
|
||||||
|
|
||||||
|
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
|
||||||
|
HISTSIZE=1000
|
||||||
|
HISTFILESIZE=2000
|
||||||
|
|
||||||
|
# check the window size after each command and, if necessary,
|
||||||
|
# update the values of LINES and COLUMNS.
|
||||||
|
shopt -s checkwinsize
|
||||||
|
|
||||||
|
# If set, the pattern "**" used in a pathname expansion context will
|
||||||
|
# match all files and zero or more directories and subdirectories.
|
||||||
|
#shopt -s globstar
|
||||||
|
|
||||||
|
# make less more friendly for non-text input files, see lesspipe(1)
|
||||||
|
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
|
||||||
|
|
||||||
|
# set variable identifying the chroot you work in (used in the prompt below)
|
||||||
|
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
|
||||||
|
debian_chroot=$(cat /etc/debian_chroot)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set a fancy prompt (non-color, unless we know we "want" color)
|
||||||
|
case "$TERM" in
|
||||||
|
xterm-color|*-256color) color_prompt=yes;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# uncomment for a colored prompt, if the terminal has the capability; turned
|
||||||
|
# off by default to not distract the user: the focus in a terminal window
|
||||||
|
# should be on the output of commands, not on the prompt
|
||||||
|
#force_color_prompt=yes
|
||||||
|
|
||||||
|
if [ -n "$force_color_prompt" ]; then
|
||||||
|
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
|
||||||
|
# We have color support; assume it's compliant with Ecma-48
|
||||||
|
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
|
||||||
|
# a case would tend to support setf rather than setaf.)
|
||||||
|
color_prompt=yes
|
||||||
|
else
|
||||||
|
color_prompt=
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ "$color_prompt" = yes ]; then
|
||||||
|
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@${PROJECT_NAME}\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
|
||||||
|
else
|
||||||
|
PS1='${debian_chroot:+($debian_chroot)}\u@${PROJECT_NAME}:\w\$ '
|
||||||
|
fi
|
||||||
|
unset color_prompt force_color_prompt
|
||||||
|
# If this is an xterm set the title to user@host:dir
|
||||||
|
case "$TERM" in
|
||||||
|
xterm*|rxvt*)
|
||||||
|
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
# enable color support of ls and also add handy aliases
|
||||||
|
if [ -x /usr/bin/dircolors ]; then
|
||||||
|
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
|
||||||
|
alias ls='ls --color=auto'
|
||||||
|
#alias dir='dir --color=auto'
|
||||||
|
#alias vdir='vdir --color=auto'
|
||||||
|
alias grep='grep --color=auto'
|
||||||
|
alias fgrep='fgrep --color=auto'
|
||||||
|
alias egrep='egrep --color=auto'
|
||||||
|
fi
|
||||||
|
# colored GCC warnings and errors
|
||||||
|
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
|
||||||
|
# some more ls aliases
|
||||||
|
alias ll='ls -alF'
|
||||||
|
alias la='ls -A'
|
||||||
|
alias l='ls -CF'
|
||||||
|
# Add an "alert" alias for long running commands. Use like so:
|
||||||
|
# sleep 10; alert
|
||||||
|
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s
|
||||||
|
/[;&|]\s*alert$//'\'')"'
|
||||||
|
# Alias definitions.
|
||||||
|
# You may want to put all your additions into a separate file like
|
||||||
|
# ~/.bash_aliases, instead of adding them here directly.
|
||||||
|
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
|
||||||
|
if [ -f ~/.bash_aliases ]; then
|
||||||
|
. ~/.bash_aliases
|
||||||
|
fi
|
||||||
|
# enable programmable completion features (you don't need to enable
|
||||||
|
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
|
||||||
|
# sources /etc/bash.bashrc).
|
||||||
|
if ! shopt -oq posix; then
|
||||||
|
if [ -f /usr/share/bash-completion/bash_completion ]; then
|
||||||
|
. /usr/share/bash-completion/bash_completion
|
||||||
|
elif [ -f /etc/bash_completion ]; then
|
||||||
|
. /etc/bash_completion
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
export NVM_DIR="/home/nvm/.nvm"
|
||||||
|
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm
|
2
.gitconfig
Normal file
2
.gitconfig
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[core]
|
||||||
|
excludesfile = /etc/.gitignore-global
|
5
.hyperdev-assets
Normal file
5
.hyperdev-assets
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{"name":"drag-in-files.svg","date":"2016-10-22T16:17:49.954Z","url":"https://cdn.hyperdev.com/drag-in-files.svg","type":"image/svg","size":7646,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/drag-in-files.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(102, 153, 205)","uuid":"adSBq97hhhpFNUna"}
|
||||||
|
{"name":"click-me.svg","date":"2016-10-23T16:17:49.954Z","url":"https://cdn.hyperdev.com/click-me.svg","type":"image/svg","size":7116,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/click-me.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(243, 185, 186)","uuid":"adSBq97hhhpFNUnb"}
|
||||||
|
{"name":"paste-me.svg","date":"2016-10-24T16:17:49.954Z","url":"https://cdn.hyperdev.com/paste-me.svg","type":"image/svg","size":7242,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/paste-me.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(42, 179, 185)","uuid":"adSBq97hhhpFNUnc"}
|
||||||
|
{"name":"Screen Shot 2016-12-16 at 1.35.56 AM.png","date":"2016-12-16T06:36:32.934Z","url":"https://cdn.gomix.com/d7932c52-287f-4dae-b175-631fef453000%2FScreen%20Shot%202016-12-16%20at%201.35.56%20AM.png","type":"image/png","size":18223,"imageWidth":499,"imageHeight":80,"thumbnail":"https://cdn.gomix.com/d7932c52-287f-4dae-b175-631fef453000%2Fthumbnails%2FScreen%20Shot%202016-12-16%20at%201.35.56%20AM.png","thumbnailWidth":330,"thumbnailHeight":53,"dominantColor":"rgb(236,236,236)","uuid":"IHJDL7lzupnoDep4"}
|
||||||
|
{"uuid":"IHJDL7lzupnoDep4","deleted":true}
|
17
.profile
Normal file
17
.profile
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# ~/.profile: executed by the command interpreter for login shells.
|
||||||
|
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
|
||||||
|
# exists.
|
||||||
|
# see /usr/share/doc/bash/examples/startup-files for examples.
|
||||||
|
# the files are located in the bash-doc package.
|
||||||
|
# the default umask is set in /etc/profile; for setting the umask
|
||||||
|
# for ssh logins, install and configure the libpam-umask package.
|
||||||
|
#umask 022
|
||||||
|
# if running bash
|
||||||
|
if [ -n "$BASH_VERSION" ]; then
|
||||||
|
# include .bashrc if it exists
|
||||||
|
if [ -f "$HOME/.bashrc" ]; then
|
||||||
|
. "$HOME/.bashrc"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# set PATH so it includes user's private bin directories
|
||||||
|
PATH="$HOME/bin:$HOME/.local/bin:$HOME/node_modules/.bin:$PATH"
|
13
README.md
13
README.md
@ -1,2 +1,11 @@
|
|||||||
# boilerplate-project-issuetracker
|
**FreeCodeCamp**- Information Security and Quality Assurance
|
||||||
A boilerplate for a freeCodeCamp project.
|
------
|
||||||
|
|
||||||
|
Project Issue Tracker
|
||||||
|
|
||||||
|
1) SET NODE_ENV to `test` without quotes and set DB to your mongo connection string in .env file
|
||||||
|
2) Complete the project in `routes/api.js` or by creating a handler/controller
|
||||||
|
3) You will add any security features to `server.js`
|
||||||
|
4) You will create all of the functional tests in `tests/2_functional-tests.js`
|
||||||
|
|
||||||
|
|
||||||
|
131
assertion-analyser.js
Normal file
131
assertion-analyser.js
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DO NOT EDIT THIS FILE
|
||||||
|
* For FCC testing purposes!
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function objParser(str, init) {
|
||||||
|
// finds objects, arrays, strings, and function arguments
|
||||||
|
// between parens, because they may contain ','
|
||||||
|
var openSym = ['[', '{', '"', "'", '('];
|
||||||
|
var closeSym = [']', '}', '"', "'", ')'];
|
||||||
|
var type;
|
||||||
|
for(var i = (init || 0); i < str.length; i++ ) {
|
||||||
|
type = openSym.indexOf(str[i]);
|
||||||
|
if( type !== -1) break;
|
||||||
|
}
|
||||||
|
if (type === -1) return null;
|
||||||
|
var open = openSym[type];
|
||||||
|
var close = closeSym[type];
|
||||||
|
var count = 1;
|
||||||
|
for(var k = i+1; k < str.length; k++) {
|
||||||
|
if(open === '"' || open === "'") {
|
||||||
|
if(str[k] === close) count--;
|
||||||
|
if(str[k] === '\\') k++;
|
||||||
|
} else {
|
||||||
|
if(str[k] === open) count++;
|
||||||
|
if(str[k] === close) count--;
|
||||||
|
}
|
||||||
|
if(count === 0) break;
|
||||||
|
}
|
||||||
|
if(count !== 0) return null;
|
||||||
|
var obj = str.slice(i, k+1);
|
||||||
|
return {
|
||||||
|
start : i,
|
||||||
|
end: k,
|
||||||
|
obj: obj
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function replacer(str) {
|
||||||
|
// replace objects with a symbol ( __#n)
|
||||||
|
var obj;
|
||||||
|
var cnt = 0;
|
||||||
|
var data = [];
|
||||||
|
while(obj = objParser(str)) {
|
||||||
|
data[cnt] = obj.obj;
|
||||||
|
str = str.substring(0, obj.start) + '__#' + cnt++ + str.substring(obj.end+1)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
str : str,
|
||||||
|
dictionary : data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function splitter(str) {
|
||||||
|
// split on commas, then restore the objects
|
||||||
|
var strObj = replacer(str);
|
||||||
|
var args = strObj.str.split(',');
|
||||||
|
args = args.map(function(a){
|
||||||
|
var m = a.match(/__#(\d+)/);
|
||||||
|
while (m) {
|
||||||
|
a = a.replace(/__#(\d+)/, strObj.dictionary[m[1]]);
|
||||||
|
m = a.match(/__#(\d+)/);
|
||||||
|
}
|
||||||
|
return a.trim();
|
||||||
|
})
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertionAnalyser(body) {
|
||||||
|
|
||||||
|
// already filtered in the test runner
|
||||||
|
// // remove comments
|
||||||
|
// body = body.replace(/\/\/.*\n|\/\*.*\*\//g, '');
|
||||||
|
// // get test function body
|
||||||
|
// body = body.match(/\{\s*([\s\S]*)\}\s*$/)[1];
|
||||||
|
|
||||||
|
if(!body) return "invalid assertion";
|
||||||
|
// replace assertions bodies, so that they cannot
|
||||||
|
// contain the word 'assertion'
|
||||||
|
|
||||||
|
var body = body.match(/(?:browser\s*\.\s*)?assert\s*\.\s*\w*\([\s\S]*\)/)[0];
|
||||||
|
var s = replacer(body);
|
||||||
|
// split on 'assertion'
|
||||||
|
var splittedAssertions = s.str.split('assert');
|
||||||
|
var assertions = splittedAssertions.slice(1);
|
||||||
|
// match the METHODS
|
||||||
|
|
||||||
|
var assertionBodies = [];
|
||||||
|
var methods = assertions.map(function(a, i){
|
||||||
|
var m = a.match(/^\s*\.\s*(\w+)__#(\d+)/);
|
||||||
|
assertionBodies.push(parseInt(m[2]));
|
||||||
|
var pre = splittedAssertions[i].match(/browser\s*\.\s*/) ? 'browser.' : '';
|
||||||
|
return pre + m[1];
|
||||||
|
});
|
||||||
|
if(methods.some(function(m){ return !m })) return "invalid assertion";
|
||||||
|
// remove parens from the assertions bodies
|
||||||
|
var bodies = assertionBodies.map(function(b){
|
||||||
|
return s.dictionary[b].slice(1,-1).trim();
|
||||||
|
});
|
||||||
|
assertions = methods.map(function(m, i) {
|
||||||
|
return {
|
||||||
|
method: m,
|
||||||
|
args: splitter(bodies[i]) //replace objects, split on ',' ,then restore objects
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return assertions;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = assertionAnalyser;
|
33
package.json
Normal file
33
package.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "my-hyperdev-app",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "What am I about?",
|
||||||
|
"main": "server.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node server.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.14.0",
|
||||||
|
"cors": "^2.8.1",
|
||||||
|
"body-parser": "^1.15.2",
|
||||||
|
"chai": "^3.5.0",
|
||||||
|
"mongodb": "^2.2.16",
|
||||||
|
"chai-http": "^3.0.0",
|
||||||
|
"mocha": "^3.2.0",
|
||||||
|
"zombie": "^5.0.5",
|
||||||
|
"helmet": "^3.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "4.4.3"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://hyperdev.com/#!/project/welcome-project"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"node",
|
||||||
|
"hyperdev",
|
||||||
|
"express"
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
23
public/style.css
Normal file
23
public/style.css
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
* {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.issue {
|
||||||
|
margin: 20px;
|
||||||
|
padding: 5px;
|
||||||
|
width: 60%;
|
||||||
|
border: 2px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.closed {
|
||||||
|
background-color: lightgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.id {
|
||||||
|
font-size: 10.5px;
|
||||||
|
}
|
41
routes/api.js
Normal file
41
routes/api.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Complete the API routing below
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var expect = require('chai').expect;
|
||||||
|
var MongoClient = require('mongodb');
|
||||||
|
var ObjectId = require('mongodb').ObjectID;
|
||||||
|
|
||||||
|
const CONNECTION_STRING = process.env.DB; //MongoClient.connect(CONNECTION_STRING, function(err, db) {});
|
||||||
|
|
||||||
|
module.exports = function (app) {
|
||||||
|
|
||||||
|
app.route('/api/issues/:project')
|
||||||
|
|
||||||
|
.get(function (req, res){
|
||||||
|
var project = req.params.project;
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
.post(function (req, res){
|
||||||
|
var project = req.params.project;
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
.put(function (req, res){
|
||||||
|
var project = req.params.project;
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
.delete(function (req, res){
|
||||||
|
var project = req.params.project;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
103
routes/fcctesting.js
Normal file
103
routes/fcctesting.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DO NOT EDIT THIS FILE
|
||||||
|
* For FCC testing purposes!
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var cors = require('cors');
|
||||||
|
var fs = require('fs');
|
||||||
|
var runner = require('../test-runner');
|
||||||
|
|
||||||
|
module.exports = function (app) {
|
||||||
|
|
||||||
|
app.route('/_api/server.js')
|
||||||
|
.get(function(req, res, next) {
|
||||||
|
console.log('requested');
|
||||||
|
fs.readFile(__dirname + '/server.js', function(err, data) {
|
||||||
|
if(err) return next(err);
|
||||||
|
res.send(data.toString());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
app.route('/_api/routes/api.js')
|
||||||
|
.get(function(req, res, next) {
|
||||||
|
console.log('requested');
|
||||||
|
fs.readFile(__dirname + '/routes/api.js', function(err, data) {
|
||||||
|
if(err) return next(err);
|
||||||
|
res.type('txt').send(data.toString());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
app.route('/_api/controllers/convertHandler.js')
|
||||||
|
.get(function(req, res, next) {
|
||||||
|
console.log('requested');
|
||||||
|
fs.readFile(__dirname + '/controllers/convertHandler.js', function(err, data) {
|
||||||
|
if(err) return next(err);
|
||||||
|
res.type('txt').send(data.toString());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var error;
|
||||||
|
app.get('/_api/get-tests', cors(), function(req, res, next){
|
||||||
|
console.log(error);
|
||||||
|
if(!error && process.env.NODE_ENV === 'test') return next();
|
||||||
|
res.json({status: 'unavailable'});
|
||||||
|
},
|
||||||
|
function(req, res, next){
|
||||||
|
if(!runner.report) return next();
|
||||||
|
res.json(testFilter(runner.report, req.query.type, req.query.n));
|
||||||
|
},
|
||||||
|
function(req, res){
|
||||||
|
runner.on('done', function(report){
|
||||||
|
process.nextTick(() => res.json(testFilter(runner.report, req.query.type, req.query.n)));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
app.get('/_api/app-info', function(req, res) {
|
||||||
|
var hs = Object.keys(res._headers)
|
||||||
|
.filter(h => !h.match(/^access-control-\w+/));
|
||||||
|
var hObj = {};
|
||||||
|
hs.forEach(h => {hObj[h] = res._headers[h]});
|
||||||
|
delete res._headers['strict-transport-security'];
|
||||||
|
res.json({headers: hObj});
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function testFilter(tests, type, n) {
|
||||||
|
var out;
|
||||||
|
switch (type) {
|
||||||
|
case 'unit' :
|
||||||
|
out = tests.filter(t => t.context.match('Unit Tests'));
|
||||||
|
break;
|
||||||
|
case 'functional':
|
||||||
|
out = tests.filter(t => t.context.match('Functional Tests') && !t.title.match('#example'));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out = tests;
|
||||||
|
}
|
||||||
|
if(n !== undefined) {
|
||||||
|
return out[n] || out;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
65
server.js
Normal file
65
server.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var express = require('express');
|
||||||
|
var bodyParser = require('body-parser');
|
||||||
|
var expect = require('chai').expect;
|
||||||
|
var cors = require('cors');
|
||||||
|
|
||||||
|
var apiRoutes = require('./routes/api.js');
|
||||||
|
var fccTestingRoutes = require('./routes/fcctesting.js');
|
||||||
|
var runner = require('./test-runner');
|
||||||
|
|
||||||
|
var app = express();
|
||||||
|
|
||||||
|
app.use('/public', express.static(process.cwd() + '/public'));
|
||||||
|
|
||||||
|
app.use(cors({origin: '*'})); //For FCC testing purposes only
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
app.use(bodyParser.json());
|
||||||
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
|
|
||||||
|
//Sample front-end
|
||||||
|
app.route('/:project/')
|
||||||
|
.get(function (req, res) {
|
||||||
|
res.sendFile(process.cwd() + '/views/issue.html');
|
||||||
|
});
|
||||||
|
|
||||||
|
//Index page (static HTML)
|
||||||
|
app.route('/')
|
||||||
|
.get(function (req, res) {
|
||||||
|
res.sendFile(process.cwd() + '/views/index.html');
|
||||||
|
});
|
||||||
|
|
||||||
|
//For FCC testing purposes
|
||||||
|
fccTestingRoutes(app);
|
||||||
|
|
||||||
|
//Routing for API
|
||||||
|
apiRoutes(app);
|
||||||
|
|
||||||
|
//404 Not Found Middleware
|
||||||
|
app.use(function(req, res, next) {
|
||||||
|
res.status(404)
|
||||||
|
.type('text')
|
||||||
|
.send('Not Found');
|
||||||
|
});
|
||||||
|
|
||||||
|
//Start our server and tests!
|
||||||
|
app.listen(process.env.PORT || 3000, function () {
|
||||||
|
console.log("Listening on port " + process.env.PORT);
|
||||||
|
if(process.env.NODE_ENV==='test') {
|
||||||
|
console.log('Running Tests...');
|
||||||
|
setTimeout(function () {
|
||||||
|
try {
|
||||||
|
runner.run();
|
||||||
|
} catch(e) {
|
||||||
|
var error = e;
|
||||||
|
console.log('Tests are not valid:');
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}, 3500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = app; //for testing
|
106
test-runner.js
Normal file
106
test-runner.js
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* DO NOT EDIT THIS FILE
|
||||||
|
* For FCC testing purposes!
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
var analyser = require('./assertion-analyser');
|
||||||
|
var EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
|
var Mocha = require('mocha'),
|
||||||
|
fs = require('fs'),
|
||||||
|
path = require('path');
|
||||||
|
|
||||||
|
var mocha = new Mocha();
|
||||||
|
var testDir = './tests'
|
||||||
|
|
||||||
|
|
||||||
|
// Add each .js file to the mocha instance
|
||||||
|
fs.readdirSync(testDir).filter(function(file){
|
||||||
|
// Only keep the .js files
|
||||||
|
return file.substr(-3) === '.js';
|
||||||
|
|
||||||
|
}).forEach(function(file){
|
||||||
|
mocha.addFile(
|
||||||
|
path.join(testDir, file)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
var emitter = new EventEmitter();
|
||||||
|
emitter.run = function() {
|
||||||
|
|
||||||
|
var tests = [];
|
||||||
|
var context = "";
|
||||||
|
var separator = ' -> ';
|
||||||
|
// Run the tests.
|
||||||
|
try {
|
||||||
|
var runner = mocha.ui('tdd').run()
|
||||||
|
.on('test end', function(test) {
|
||||||
|
// remove comments
|
||||||
|
var body = test.body.replace(/\/\/.*\n|\/\*.*\*\//g, '');
|
||||||
|
// collapse spaces
|
||||||
|
body = body.replace(/\s+/g,' ');
|
||||||
|
var obj = {
|
||||||
|
title: test.title,
|
||||||
|
context: context.slice(0, -separator.length),
|
||||||
|
state: test.state,
|
||||||
|
// body: body,
|
||||||
|
assertions: analyser(body)
|
||||||
|
};
|
||||||
|
tests.push(obj);
|
||||||
|
})
|
||||||
|
.on('end', function() {
|
||||||
|
emitter.report = tests;
|
||||||
|
emitter.emit('done', tests)
|
||||||
|
})
|
||||||
|
.on('suite', function(s) {
|
||||||
|
context += (s.title + separator);
|
||||||
|
|
||||||
|
})
|
||||||
|
.on('suite end', function(s) {
|
||||||
|
context = context.slice(0, -(s.title.length + separator.length))
|
||||||
|
})
|
||||||
|
} catch(e) {
|
||||||
|
throw(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = emitter;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mocha.runner Events:
|
||||||
|
* can be used to build a better custom report
|
||||||
|
*
|
||||||
|
* - `start` execution started
|
||||||
|
* - `end` execution complete
|
||||||
|
* - `suite` (suite) test suite execution started
|
||||||
|
* - `suite end` (suite) all tests (and sub-suites) have finished
|
||||||
|
* - `test` (test) test execution started
|
||||||
|
* - `test end` (test) test completed
|
||||||
|
* - `hook` (hook) hook execution started
|
||||||
|
* - `hook end` (hook) hook complete
|
||||||
|
* - `pass` (test) test passed
|
||||||
|
* - `fail` (test, err) test failed
|
||||||
|
* - `pending` (test) test pending
|
||||||
|
*/
|
15
tests/1_unit-tests.js
Normal file
15
tests/1_unit-tests.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* FILL IN EACH UNIT TEST BELOW COMPLETELY
|
||||||
|
* -----[Keep the tests in the same order!]----
|
||||||
|
* (if additional are added, keep them at the very end!)
|
||||||
|
*/
|
||||||
|
|
||||||
|
var chai = require('chai');
|
||||||
|
|
||||||
|
suite('Unit Tests', function(){
|
||||||
|
|
||||||
|
//none requiered
|
||||||
|
|
||||||
|
});
|
109
tests/2_functional-tests.js
Normal file
109
tests/2_functional-tests.js
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* FILL IN EACH FUNCTIONAL TEST BELOW COMPLETELY
|
||||||
|
* -----[Keep the tests in the same order!]-----
|
||||||
|
* (if additional are added, keep them at the very end!)
|
||||||
|
*/
|
||||||
|
|
||||||
|
var chaiHttp = require('chai-http');
|
||||||
|
var chai = require('chai');
|
||||||
|
var assert = chai.assert;
|
||||||
|
var server = require('../server');
|
||||||
|
|
||||||
|
chai.use(chaiHttp);
|
||||||
|
|
||||||
|
suite('Functional Tests', function() {
|
||||||
|
|
||||||
|
suite('POST /api/issues/{project} => object with issue data', function() {
|
||||||
|
|
||||||
|
test('Every field filled in', function(done) {
|
||||||
|
chai.request(server)
|
||||||
|
.post('/api/issues/test')
|
||||||
|
.send({
|
||||||
|
issue_title: 'Title',
|
||||||
|
issue_text: 'text',
|
||||||
|
created_by: 'Functional Test - Every field filled in',
|
||||||
|
assigned_to: 'Chai and Mocha',
|
||||||
|
status_text: 'In QA'
|
||||||
|
})
|
||||||
|
.end(function(err, res){
|
||||||
|
assert.equal(res.status, 200);
|
||||||
|
|
||||||
|
//fill me in too!
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Required fields filled in', function(done) {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Missing required fields', function(done) {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
suite('PUT /api/issues/{project} => text', function() {
|
||||||
|
|
||||||
|
test('No body', function(done) {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test('One field to update', function(done) {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Multiple fields to update', function(done) {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
suite('GET /api/issues/{project} => Array of objects with issue data', function() {
|
||||||
|
|
||||||
|
test('No filter', function(done) {
|
||||||
|
chai.request(server)
|
||||||
|
.get('/api/issues/test')
|
||||||
|
.query({})
|
||||||
|
.end(function(err, res){
|
||||||
|
assert.equal(res.status, 200);
|
||||||
|
assert.isArray(res.body);
|
||||||
|
assert.property(res.body[0], 'issue_title');
|
||||||
|
assert.property(res.body[0], 'issue_text');
|
||||||
|
assert.property(res.body[0], 'created_on');
|
||||||
|
assert.property(res.body[0], 'updated_on');
|
||||||
|
assert.property(res.body[0], 'created_by');
|
||||||
|
assert.property(res.body[0], 'assigned_to');
|
||||||
|
assert.property(res.body[0], 'open');
|
||||||
|
assert.property(res.body[0], 'status_text');
|
||||||
|
assert.property(res.body[0], '_id');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('One filter', function(done) {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Multiple filters (test for multiple fields you know will be in the db for a return)', function(done) {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
suite('DELETE /api/issues/{project} => text', function() {
|
||||||
|
|
||||||
|
test('No _id', function(done) {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Valid _id', function(done) {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
111
views/index.html
Normal file
111
views/index.html
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Welcome to HyperDev!</title>
|
||||||
|
<meta name="description" content="A cool thing made with HyperDev">
|
||||||
|
<link id="favicon" rel="icon" href="https://hyperdev.com/favicon-app.ico" type="image/x-icon">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>
|
||||||
|
ISQA_4 - Issue Tracker
|
||||||
|
</h1>
|
||||||
|
</header>
|
||||||
|
<div id='userstories' style='margin-left: 5%; margin-top: 5%'>
|
||||||
|
<h3>User Stories</h3>
|
||||||
|
<ol>
|
||||||
|
<li>Prevent cross site scripting(XSS attack).</li>
|
||||||
|
<li>I can <b>POST</b> <code>/api/issues/{projectname}</code> with form data containing required <i>issue_title</i>, <i>issue_text</i>, <i>created_by</i>, and optional <i>assigned_to</i> and <i>status_text</i>.</li>
|
||||||
|
<li>The object saved (and returned) will include all of those fields (blank for optional no input) and also include <i>created_on</i>(date/time), <i>updated_on</i>(date/time), <i>open</i>(boolean, true for open, false for closed), and <i>_id</i>.</li>
|
||||||
|
<li>I can <b>PUT</b> <code>/api/issues/{projectname}</code> with a <i>_id</i> and any fields in the object with a value to object said object. Returned will be 'successfully updated' or 'could not update '+_id. This should always update <i>updated_on</i>. If no fields are sent return 'no updated field sent'.</li>
|
||||||
|
<li>I can <b>DELETE</b> <code>/api/issues/{projectname}</code> with a <i>_id</i> to completely delete an issue. If no _id is sent return '_id error', success: 'deleted '+_id, failed: 'could not delete '+_id.</li>
|
||||||
|
<li>I can <b>GET</b> <code>/api/issues/{projectname}</code> for an array of all issues on that specific project with all the information for each issue as was returned when posted.</li>
|
||||||
|
<li>I can filter my get request by also passing along any field and value in the query(ie. <code>/api/issues/{project}?open=false</code>). I can pass along as many fields/values as I want.</li>
|
||||||
|
<li>All 11 functional tests are complete and passing.</li>
|
||||||
|
</ol>
|
||||||
|
<br>
|
||||||
|
<h3>Example get usage:</h3>
|
||||||
|
<code>/api/issues/{project}</code><br>
|
||||||
|
<code>/api/issues/{project}?open=true&assigned_to=Joe</code><br>
|
||||||
|
<h3>Example return:</h3>
|
||||||
|
<code>[{"_id":"5871dda29faedc3491ff93bb","issue_title":"Fix error in posting data","issue_text":"When we post data it has an error.","created_on":"2017-01-08T06:35:14.240Z","updated_on":"2017-01-08T06:35:14.240Z","created_by":"Joe","assigned_to":"Joe","open":true,"status_text":"In QA"},...]</code>
|
||||||
|
<br><br>
|
||||||
|
<h2><a href='/apitest/'>EXAMPLE: Go to <i>/apitest/</i> project issues</a></h2>
|
||||||
|
</div>
|
||||||
|
<hr style='margin: 50px'>
|
||||||
|
<div id='testui' style='margin-left: 5%'>
|
||||||
|
<h2 style="text-align: left">API Tests:</h2>
|
||||||
|
<h3>Submit issue on <i>apitest</i></h3>
|
||||||
|
<form id="testForm" class="border">
|
||||||
|
<input type="text" name="issue_title" placeholder="*Title" style="width: 100px" required=''><br>
|
||||||
|
<textarea type="text" name="issue_text" placeholder="*Text" style="width: 100px" required=''></textarea><br>
|
||||||
|
<input type="text" name="created_by" placeholder="*Created by" style="width: 100px" required=''><br>
|
||||||
|
<input type="text" name="assigned_to" placeholder="(opt)Assigned to" style="width: 100px"><br>
|
||||||
|
<input type="text" name="status_text" placeholder="(opt)Status text" style="width: 100px"><br>
|
||||||
|
<button type="submit">Submit Issue</button>
|
||||||
|
</form><br>
|
||||||
|
<h3>Update issue on <i>apitest</i> (Change any or all to update issue on the _id supplied)</h3>
|
||||||
|
<form id="testForm2" class="border">
|
||||||
|
<input type="text" name="_id" placeholder="*_id" style="width: 100px" required=''><br>
|
||||||
|
<input type="text" name="issue_title" placeholder="(opt)Title" style="width: 100px"><br>
|
||||||
|
<textarea type="text" name="issue_text" placeholder="(opt)Text" style="width: 100px"></textarea><br>
|
||||||
|
<input type="text" name="created_by" placeholder="(opt)Created by" style="width: 100px"><br>
|
||||||
|
<input type="text" name="assigned_to" placeholder="(opt)Assigned to" style="width: 100px"><br>
|
||||||
|
<input type="text" name="status_text" placeholder="(opt)Status text" style="width: 100px"><br>
|
||||||
|
<label><input type="checkbox" name="open" value=false> Check to close issue</label><br>
|
||||||
|
<button type="submit">Submit Issue</button>
|
||||||
|
</form><br>
|
||||||
|
<h3>Delete issue on <i>apitest</i></h3>
|
||||||
|
<form id="testForm2" class="border">
|
||||||
|
<input type="text" name="_id" placeholder="_id" style="width: 100px" required=''><br>
|
||||||
|
<button type="submit">Delete Issue</button>
|
||||||
|
</form>
|
||||||
|
<code id='jsonResult'></code>
|
||||||
|
</div>
|
||||||
|
<hr style='margin: 50px; margin-top: 200px'>
|
||||||
|
<!-- Your web-app is https, so your scripts need to be too -->
|
||||||
|
<script src="https://code.jquery.com/jquery-2.2.1.min.js"
|
||||||
|
integrity="sha256-gvQgAFzTH6trSrAWoH1iPo9Xc96QxSZ3feW6kem+O00="
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$('#testForm').submit(function(e) {
|
||||||
|
$.ajax({
|
||||||
|
url: '/api/issues/apitest',
|
||||||
|
type: 'post',
|
||||||
|
data: $('#testForm').serialize(),
|
||||||
|
success: function(data) {
|
||||||
|
$('#jsonResult').text(JSON.stringify(data));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
$('#testForm2').submit(function(e) {
|
||||||
|
$.ajax({
|
||||||
|
url: '/api/issues/apitest',
|
||||||
|
type: 'put',
|
||||||
|
data: $('#testForm2').serialize(),
|
||||||
|
success: function(data) {
|
||||||
|
$('#jsonResult').text(JSON.stringify(data));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
$('#testForm3').submit(function(e) {
|
||||||
|
$.ajax({
|
||||||
|
url: '/api/issues/apitest',
|
||||||
|
type: 'delete',
|
||||||
|
data: $('#testForm3').serialize(),
|
||||||
|
success: function(data) {
|
||||||
|
$('#jsonResult').text(JSON.stringify(data));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
107
views/issue.html
Normal file
107
views/issue.html
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Welcome to HyperDev!</title>
|
||||||
|
<meta name="description" content="A cool thing made with HyperDev">
|
||||||
|
<link id="favicon" rel="icon" href="https://hyperdev.com/favicon-app.ico" type="image/x-icon">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="/public/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1 id='projectTitle'></h1>
|
||||||
|
</header>
|
||||||
|
<center>
|
||||||
|
<div id='submitNewIssue'>
|
||||||
|
<br>
|
||||||
|
<h3>Submit a new issue:</h3>
|
||||||
|
<form id="newIssue" method="post" action="/api/">
|
||||||
|
<input type="text" name="issue_title" placeholder="*Title" style="width: 320px; margin-bottom: 3px;" required=''><br>
|
||||||
|
<textarea type="text" name="issue_text" placeholder="*Text" style="width: 320px; height: 100px;" required=''></textarea><br>
|
||||||
|
<input type="text" name="created_by" placeholder="*Created by" style="width: 100px" required=''>
|
||||||
|
<input type="text" name="assigned_to" placeholder="(opt)Assigned to" style="width: 100px">
|
||||||
|
<input type="text" name="status_text" placeholder="(opt)Status text" style="width: 100px"><br>
|
||||||
|
<button type="submit">Submit Issue</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id='issueDisplay'></div>
|
||||||
|
|
||||||
|
<hr style='margin: 50px; margin-top: 200px'>
|
||||||
|
</center>
|
||||||
|
|
||||||
|
<script src="https://code.jquery.com/jquery-2.2.1.min.js"
|
||||||
|
integrity="sha256-gvQgAFzTH6trSrAWoH1iPo9Xc96QxSZ3feW6kem+O00="
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
var currentProject = window.location.pathname.replace(/\//g, "");;
|
||||||
|
var url = "/api/issues/"+currentProject;
|
||||||
|
$('#projectTitle').text('All issues for: '+currentProject)
|
||||||
|
$.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: url,
|
||||||
|
success: function(data)
|
||||||
|
{
|
||||||
|
var issues= [];
|
||||||
|
data.forEach(function(ele) {
|
||||||
|
console.log(ele);
|
||||||
|
var openstatus;
|
||||||
|
(ele.open) ? openstatus = 'open' : openstatus = 'closed';
|
||||||
|
var single = [
|
||||||
|
'<div class="issue '+openstatus+'">',
|
||||||
|
'<p class="id">id: '+ele._id+'</p>',
|
||||||
|
'<h3>'+ele.issue_title+' - ('+openstatus+')</h3>',
|
||||||
|
'<br>',
|
||||||
|
'<p>'+ele.issue_text+'</p>',
|
||||||
|
'<p>'+ele.status_text+'</p>',
|
||||||
|
'<br>',
|
||||||
|
'<p class="id"><b>Created by:</b> '+ele.created_by+' <b>Assigned to:</b> '+ele.assigned_to,
|
||||||
|
'<p class="id"><b>Created on:</b> '+ele.created_on+' <b>Last updated:</b> '+ele.updated_on,
|
||||||
|
'<br><a href="#" class="closeIssue" id="'+ele._id+'">close?</a> <a href="#" class="deleteIssue" id="'+ele._id+'">delete?</a>',
|
||||||
|
'</div>'
|
||||||
|
|
||||||
|
];
|
||||||
|
issues.push(single.join(''));
|
||||||
|
});
|
||||||
|
$('#issueDisplay').html(issues.join(''));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#newIssue').submit(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
$(this).attr('action', "/api/issues/" + currentProject);
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: url,
|
||||||
|
data: $(this).serialize(),
|
||||||
|
success: function(data) { window.location.reload(true); }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#issueDisplay').on('click','.closeIssue', function(e) {
|
||||||
|
var url = "/api/issues/"+currentProject;
|
||||||
|
$.ajax({
|
||||||
|
type: "PUT",
|
||||||
|
url: url,
|
||||||
|
data: {_id: $(this).attr('id'), open: false},
|
||||||
|
success: function(data) { alert(data); window.location.reload(true); }
|
||||||
|
});
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
$('#issueDisplay').on('click','.deleteIssue', function(e) {
|
||||||
|
var url = "/api/issues/"+currentProject;
|
||||||
|
$.ajax({
|
||||||
|
type: "DELETE",
|
||||||
|
url: url,
|
||||||
|
data: {_id: $(this).attr('id')},
|
||||||
|
success: function(data) { alert(data); window.location.reload(true); }
|
||||||
|
});
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user