Build should pass again

This commit is contained in:
Matthew Ross 2020-01-16 15:05:31 -05:00
parent e6233405ff
commit 515765e296
44 changed files with 5270 additions and 5205 deletions

1
.gitignore vendored
View File

@ -34,6 +34,7 @@ npm-debug.log
yarn-error.log
testem.log
/typings
.phpunit.result.cache
# e2e
/e2e/*.js

570
package-lock.json generated
View File

@ -5,12 +5,12 @@
"requires": true,
"dependencies": {
"@angular-devkit/architect": {
"version": "0.803.21",
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.803.21.tgz",
"integrity": "sha512-E2K/YexIWVyKM/xmyxvDjkJf+wX9u4c8YYpNaK4htsRzA06juc7N1MhlL/jURZiRl5b/K9sapYeq3tMX76saxA==",
"version": "0.803.22",
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.803.22.tgz",
"integrity": "sha512-5Gr0LH+Hjd/NLdmi660VBoo3WbzQM7/yeG+ziktb7hbeVaYK4Mejtcg/DJnCoZ3hzlZuZokWVwvpdFo+A9xKbg==",
"dev": true,
"requires": {
"@angular-devkit/core": "8.3.21",
"@angular-devkit/core": "8.3.22",
"rxjs": "6.4.0"
},
"dependencies": {
@ -26,23 +26,23 @@
}
},
"@angular-devkit/build-angular": {
"version": "0.803.21",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.803.21.tgz",
"integrity": "sha512-flfgflvfpwdsm3x/U7QnfbtyZPEbsVipzQAoao1Zo58Beq1a+NsKsWbjrF/x4TSoI2czt0OVWXNytlfXM7LMhg==",
"version": "0.803.22",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.803.22.tgz",
"integrity": "sha512-2q9qLsD52D4GACUAuQhvkgQ7vLAhZzdU0jzfs74RTxqUZ3PS6Ltrrwpdg2kp9RlQ53+nSCYjWBDLk1CxoEt4pg==",
"dev": true,
"requires": {
"@angular-devkit/architect": "0.803.21",
"@angular-devkit/build-optimizer": "0.803.21",
"@angular-devkit/build-webpack": "0.803.21",
"@angular-devkit/core": "8.3.21",
"@angular-devkit/architect": "0.803.22",
"@angular-devkit/build-optimizer": "0.803.22",
"@angular-devkit/build-webpack": "0.803.22",
"@angular-devkit/core": "8.3.22",
"@babel/core": "7.7.5",
"@babel/preset-env": "7.7.6",
"@ngtools/webpack": "8.3.21",
"@ngtools/webpack": "8.3.22",
"ajv": "6.10.2",
"autoprefixer": "9.6.1",
"browserslist": "4.6.6",
"browserslist": "4.8.3",
"cacache": "12.0.2",
"caniuse-lite": "1.0.30000989",
"caniuse-lite": "1.0.30001019",
"circular-dependency-plugin": "5.2.0",
"clean-css": "4.2.1",
"copy-webpack-plugin": "5.1.1",
@ -119,9 +119,9 @@
}
},
"@angular-devkit/build-optimizer": {
"version": "0.803.21",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.803.21.tgz",
"integrity": "sha512-gNN6kPaF4phZco3TmsrNr9tIEKXYsoSeoaUiDUfgmCYwa7fAqM8Ojh7HX6IQuB2PpVmEwKGlCcSh6xDtB33NjA==",
"version": "0.803.22",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.803.22.tgz",
"integrity": "sha512-VIDeQcBn88PjHBTen3BRVA7DJiKEJdDwukx61mUvUDOcY7S5Ot5WqG0nrZifRjha17Z+fl3XuwS9TZNYmlF7WQ==",
"dev": true,
"requires": {
"loader-utils": "1.2.3",
@ -146,13 +146,13 @@
}
},
"@angular-devkit/build-webpack": {
"version": "0.803.21",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.803.21.tgz",
"integrity": "sha512-zCFVla/Xdk8qGVybvnHtoKml2h0/ShasSjT55VNZO1XaTCMqYkQEwwqSGEiVajpauafWjKrKxxBhsmWoI4efAA==",
"version": "0.803.22",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.803.22.tgz",
"integrity": "sha512-RDLAhKHfTFzthzeawHEefYB1MxHiU2I32QzXI3XTCpR2XySw5JG9jIVIcsyDHQH1JtIfpHGq8vgfiTsE3r0YWA==",
"dev": true,
"requires": {
"@angular-devkit/architect": "0.803.21",
"@angular-devkit/core": "8.3.21",
"@angular-devkit/architect": "0.803.22",
"@angular-devkit/core": "8.3.22",
"rxjs": "6.4.0"
},
"dependencies": {
@ -168,9 +168,9 @@
}
},
"@angular-devkit/core": {
"version": "8.3.21",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.21.tgz",
"integrity": "sha512-BYyVbrbys535FplX0+GVOlYBg/cyk1U5SRhSxRRFZYi9epVlEBBPk8/6wV4cQPGb6EwXkVj7YtPWXjXcGfzWmA==",
"version": "8.3.22",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.22.tgz",
"integrity": "sha512-lOEYcvK3MktjR9YZT/cUjiQE5dZxl8rZ/vgWgwDiL7RtzfXTt8lPapoJe7YKS53gLbUYiBNPCtTyTAqnslWgGA==",
"dev": true,
"requires": {
"ajv": "6.10.2",
@ -198,28 +198,15 @@
}
},
"@angular-devkit/schematics": {
"version": "8.3.21",
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.3.21.tgz",
"integrity": "sha512-+wH0362CRr/SijVX4w2baY2ANZ4scQ1k2xO8lT+NMeZQkw3IJQPOfwk1IaqiAs2xuBJZcSDH1Gn80+Jh4Dit7w==",
"version": "8.3.22",
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.3.22.tgz",
"integrity": "sha512-ETLdV1ftT+ZuuiHl6FjFQ4XLQznWMcxWognX+qgByn+DQOXsYRRvZK1L5eG/SG8CKJ8NL5oteTDloDnghARHFw==",
"dev": true,
"requires": {
"@angular-devkit/core": "8.3.21",
"@angular-devkit/core": "8.3.22",
"rxjs": "6.4.0"
},
"dependencies": {
"@angular-devkit/core": {
"version": "8.3.21",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.21.tgz",
"integrity": "sha512-BYyVbrbys535FplX0+GVOlYBg/cyk1U5SRhSxRRFZYi9epVlEBBPk8/6wV4cQPGb6EwXkVj7YtPWXjXcGfzWmA==",
"dev": true,
"requires": {
"ajv": "6.10.2",
"fast-json-stable-stringify": "2.0.0",
"magic-string": "0.25.3",
"rxjs": "6.4.0",
"source-map": "0.7.3"
}
},
"rxjs": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
@ -228,12 +215,6 @@
"requires": {
"tslib": "^1.9.0"
}
},
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"dev": true
}
}
},
@ -246,16 +227,16 @@
}
},
"@angular/cli": {
"version": "8.3.21",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-8.3.21.tgz",
"integrity": "sha512-ZZpA7mMfIobFT06rBNxm8vucAh8W2s0huJZ4iL0BPujnhIr71PL+gDwssySWDEz2q6i4CkH9QRH76DHhtL6VSQ==",
"version": "8.3.22",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-8.3.22.tgz",
"integrity": "sha512-OT2rzwnxwI0ETP7rXCxjxsIAZEYo9wHP/5rRbu3m15GlQ3Bclq34ZDRwC/bRxXL5+1DfmhAs9AjtYNoFoDM4Tg==",
"dev": true,
"requires": {
"@angular-devkit/architect": "0.803.21",
"@angular-devkit/core": "8.3.21",
"@angular-devkit/schematics": "8.3.21",
"@schematics/angular": "8.3.21",
"@schematics/update": "0.803.21",
"@angular-devkit/architect": "0.803.22",
"@angular-devkit/core": "8.3.22",
"@angular-devkit/schematics": "8.3.22",
"@schematics/angular": "8.3.22",
"@schematics/update": "0.803.22",
"@yarnpkg/lockfile": "1.1.0",
"ansi-colors": "4.1.1",
"debug": "^4.1.1",
@ -273,29 +254,6 @@
"uuid": "^3.3.2"
},
"dependencies": {
"@angular-devkit/architect": {
"version": "0.803.21",
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.803.21.tgz",
"integrity": "sha512-E2K/YexIWVyKM/xmyxvDjkJf+wX9u4c8YYpNaK4htsRzA06juc7N1MhlL/jURZiRl5b/K9sapYeq3tMX76saxA==",
"dev": true,
"requires": {
"@angular-devkit/core": "8.3.21",
"rxjs": "6.4.0"
}
},
"@angular-devkit/core": {
"version": "8.3.21",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.21.tgz",
"integrity": "sha512-BYyVbrbys535FplX0+GVOlYBg/cyk1U5SRhSxRRFZYi9epVlEBBPk8/6wV4cQPGb6EwXkVj7YtPWXjXcGfzWmA==",
"dev": true,
"requires": {
"ajv": "6.10.2",
"fast-json-stable-stringify": "2.0.0",
"magic-string": "0.25.3",
"rxjs": "6.4.0",
"source-map": "0.7.3"
}
},
"ansi-colors": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
@ -326,26 +284,11 @@
"glob": "^7.1.3"
}
},
"rxjs": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
"integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
},
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"dev": true
}
}
},
@ -2187,12 +2130,12 @@
}
},
"@ngtools/webpack": {
"version": "8.3.21",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-8.3.21.tgz",
"integrity": "sha512-DGqmFQ52sV4uB3y3spQTNLa69oU5cwd1yIqMB4GSM+Qp+hozdzrPA2gVH90N2DDhWe8icsSQHAtZQiR9+BDL8g==",
"version": "8.3.22",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-8.3.22.tgz",
"integrity": "sha512-MES7Q0k6GpQEY74cxElUVy7jIaDBSLvY+eOUN2GKL5CznvBSp3+U5px6X7ZjPGzCp7no1L1JkV9g2e0hPatlcw==",
"dev": true,
"requires": {
"@angular-devkit/core": "8.3.21",
"@angular-devkit/core": "8.3.22",
"enhanced-resolve": "4.1.0",
"rxjs": "6.4.0",
"tree-kill": "1.2.1",
@ -2211,53 +2154,23 @@
}
},
"@schematics/angular": {
"version": "8.3.21",
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-8.3.21.tgz",
"integrity": "sha512-KahQ+dHvTsGOZwY6IdzqJZLDEn0G89rrK3OY+7okZujoaLM+LXhxlPoznW1udnZJVTa3VNxYGx11fkgLtRJRqA==",
"version": "8.3.22",
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-8.3.22.tgz",
"integrity": "sha512-vD+UgPdbEoFPOH6xe2laFpHn/MC9R5C4A/+J9yQ6HBg5kt1YdyIBakvPOcXQCyWr5VZzDmTyMO76rd3zaef3DQ==",
"dev": true,
"requires": {
"@angular-devkit/core": "8.3.21",
"@angular-devkit/schematics": "8.3.21"
},
"dependencies": {
"@angular-devkit/core": {
"version": "8.3.21",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.21.tgz",
"integrity": "sha512-BYyVbrbys535FplX0+GVOlYBg/cyk1U5SRhSxRRFZYi9epVlEBBPk8/6wV4cQPGb6EwXkVj7YtPWXjXcGfzWmA==",
"dev": true,
"requires": {
"ajv": "6.10.2",
"fast-json-stable-stringify": "2.0.0",
"magic-string": "0.25.3",
"rxjs": "6.4.0",
"source-map": "0.7.3"
}
},
"rxjs": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
"integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
},
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"dev": true
}
"@angular-devkit/core": "8.3.22",
"@angular-devkit/schematics": "8.3.22"
}
},
"@schematics/update": {
"version": "0.803.21",
"resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.803.21.tgz",
"integrity": "sha512-D3BRvEBF2cJEgogvFaNOfqtTFHHv/ctSRfOeAYWjUxILtb+2DpuZ9h5QYDFhN9MPgz/vRaOqFORa3sEZCRkX4g==",
"version": "0.803.22",
"resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.803.22.tgz",
"integrity": "sha512-X+1sJ7YadcYxDqcLX7l7MEAIL3SHIXpCqToQdAZbAE06NdTFvg5eqiKreSdmm7ZdfL0dBe6oXi/yCDVMoL2zcw==",
"dev": true,
"requires": {
"@angular-devkit/core": "8.3.21",
"@angular-devkit/schematics": "8.3.21",
"@angular-devkit/core": "8.3.22",
"@angular-devkit/schematics": "8.3.22",
"@yarnpkg/lockfile": "1.1.0",
"ini": "1.3.5",
"pacote": "9.5.5",
@ -2266,19 +2179,6 @@
"semver-intersect": "1.4.0"
},
"dependencies": {
"@angular-devkit/core": {
"version": "8.3.21",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.21.tgz",
"integrity": "sha512-BYyVbrbys535FplX0+GVOlYBg/cyk1U5SRhSxRRFZYi9epVlEBBPk8/6wV4cQPGb6EwXkVj7YtPWXjXcGfzWmA==",
"dev": true,
"requires": {
"ajv": "6.10.2",
"fast-json-stable-stringify": "2.0.0",
"magic-string": "0.25.3",
"rxjs": "6.4.0",
"source-map": "0.7.3"
}
},
"rxjs": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
@ -2293,12 +2193,6 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
},
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"dev": true
}
}
},
@ -2364,9 +2258,9 @@
"dev": true
},
"@types/node": {
"version": "12.12.22",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.22.tgz",
"integrity": "sha512-r5i93jqbPWGXYXxianGATOxTelkp6ih/U0WVnvaqAvTqM+0U6J3kw6Xk6uq/dWNRkEVw/0SLcO5ORXbVNz4FMQ==",
"version": "13.1.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.6.tgz",
"integrity": "sha512-Jg1F+bmxcpENHP23sVKkNuU3uaxPnsBMW0cLjleiikFKomJQbsn0Cqk2yDvQArqzZN6ABfBkZ0To7pQ8sLdWDg==",
"dev": true
},
"@types/q": {
@ -2753,14 +2647,6 @@
"dev": true,
"requires": {
"type-fest": "^0.8.1"
},
"dependencies": {
"type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true
}
}
},
"ansi-html": {
@ -3650,14 +3536,14 @@
}
},
"browserslist": {
"version": "4.6.6",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.6.tgz",
"integrity": "sha512-D2Nk3W9JL9Fp/gIcWei8LrERCS+eXu9AM5cfXA8WEZ84lFks+ARnZ0q/R69m2SV3Wjma83QDDPxsNKXUwdIsyA==",
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.3.tgz",
"integrity": "sha512-iU43cMMknxG1ClEZ2MDKeonKE1CCrFVkQK2AqO2YWFmvIrx4JWrvQ4w4hQez6EpVI8rHTtqh/ruHHDHSOKxvUg==",
"dev": true,
"requires": {
"caniuse-lite": "^1.0.30000984",
"electron-to-chromium": "^1.3.191",
"node-releases": "^1.1.25"
"caniuse-lite": "^1.0.30001017",
"electron-to-chromium": "^1.3.322",
"node-releases": "^1.1.44"
}
},
"browserstack": {
@ -3858,9 +3744,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30000989",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz",
"integrity": "sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==",
"version": "1.0.30001019",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001019.tgz",
"integrity": "sha512-6ljkLtF1KM5fQ+5ZN0wuyVvvebJxgJPTmScOMaFuQN2QuOzvRJnWSKfzQskQU5IOU4Gap3zasYPIinzwUjoj/g==",
"dev": true
},
"canonical-path": {
@ -3925,9 +3811,9 @@
}
},
"chownr": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz",
"integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==",
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz",
"integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==",
"dev": true
},
"chrome-trace-event": {
@ -4162,18 +4048,18 @@
"dev": true
},
"compressible": {
"version": "2.0.17",
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz",
"integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==",
"version": "2.0.18",
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
"integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
"dev": true,
"requires": {
"mime-db": ">= 1.40.0 < 2"
"mime-db": ">= 1.43.0 < 2"
},
"dependencies": {
"mime-db": {
"version": "1.42.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz",
"integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==",
"version": "1.43.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
"integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==",
"dev": true
}
}
@ -4454,37 +4340,20 @@
}
},
"core-js": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.1.tgz",
"integrity": "sha512-186WjSik2iTGfDjfdCZAxv2ormxtKgemjC3SI6PL31qOA0j5LhTDVjHChccoc7brwLvpvLPiMyRlcO88C4l1QQ=="
"version": "3.6.3",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.3.tgz",
"integrity": "sha512-DOO9b18YHR+Wk5kJ/c5YFbXuUETreD4TrvXb6edzqZE3aAEd0eJIAWghZ9HttMuiON8SVCnU3fqA4rPxRDD1HQ=="
},
"core-js-compat": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.0.tgz",
"integrity": "sha512-Z3eCNjGgoYluH89Jt4wVkfYsc/VdLrA2/woX5lm0isO/pCT+P+Y+o65bOuEnjDJLthdwTBxbCVzptTXtc18fJg==",
"version": "3.6.3",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.3.tgz",
"integrity": "sha512-Y3YNGU3bU1yrnzVodop23ghArbKv4IqkZg9MMOWv/h7KT6NRk1/SzHhWDDlubg2+tlcUzAqgj1/GyeJ9fUKMeg==",
"dev": true,
"requires": {
"browserslist": "^4.8.2",
"browserslist": "^4.8.3",
"semver": "7.0.0"
},
"dependencies": {
"browserslist": {
"version": "4.8.2",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.2.tgz",
"integrity": "sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA==",
"dev": true,
"requires": {
"caniuse-lite": "^1.0.30001015",
"electron-to-chromium": "^1.3.322",
"node-releases": "^1.1.42"
}
},
"caniuse-lite": {
"version": "1.0.30001016",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001016.tgz",
"integrity": "sha512-yYQ2QfotceRiH4U+h1Us86WJXtVHDmy3nEKIdYPsZCYnOV5/tMgGbmoIlrMzmh2VXlproqYtVaKeGDBkMZifFA==",
"dev": true
},
"semver": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
@ -4690,9 +4559,9 @@
"integrity": "sha1-LkYovhncSyFLXAJjDFlx6BFhgGI="
},
"cyclist": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz",
"integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
"integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
"dev": true
},
"damerau-levenshtein": {
@ -5090,9 +4959,9 @@
"dev": true
},
"electron-to-chromium": {
"version": "1.3.322",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz",
"integrity": "sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA==",
"version": "1.3.331",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.331.tgz",
"integrity": "sha512-GuDv5gkxwRROYnmIVFUohoyrNapWCKLNn80L7Pa+9WRF/oY4t7XLH7wBMsYBgIRwi8BvEvsGKLKh8kOciOp6kA==",
"dev": true
},
"elliptic": {
@ -5355,9 +5224,9 @@
"dev": true
},
"events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz",
"integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz",
"integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==",
"dev": true
},
"eventsource": {
@ -5924,12 +5793,12 @@
}
},
"fs-minipass": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.6.tgz",
"integrity": "sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==",
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
"integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
"dev": true,
"requires": {
"minipass": "^2.2.1"
"minipass": "^2.6.0"
}
},
"fs-write-stream-atomic": {
@ -6540,9 +6409,9 @@
"dev": true
},
"ignore-walk": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz",
"integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==",
"dev": true,
"requires": {
"minimatch": "^3.0.4"
@ -7550,12 +7419,12 @@
}
},
"karma-jasmine": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-2.0.1.tgz",
"integrity": "sha512-iuC0hmr9b+SNn1DaUD2QEYtUxkS1J+bSJSn7ejdEexs7P8EYvA1CWkEdrDQ+8jVH3AgWlCNwjYsT1chjcNW9lA==",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-3.1.0.tgz",
"integrity": "sha512-IVGbC8gap5x5NNCEOsAE77ic8rZtHDt6wmO0fFC5yT5FeB8qKnGTeud2mtKyQ41xl7vZkZ7ZxKr4wMGR6tWN+A==",
"dev": true,
"requires": {
"jasmine-core": "^3.3"
"jasmine-core": "^3.5.0"
}
},
"karma-jasmine-html-reporter": {
@ -7827,16 +7696,16 @@
"dev": true
},
"make-fetch-happen": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.0.tgz",
"integrity": "sha512-nFr/vpL1Jc60etMVKeaLOqfGjMMb3tAHFVJWxHOFCFS04Zmd7kGlMxo0l1tzfhoQje0/UPnd0X8OeGUiXXnfPA==",
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz",
"integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==",
"dev": true,
"requires": {
"agentkeepalive": "^3.4.1",
"cacache": "^12.0.0",
"http-cache-semantics": "^3.8.1",
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^2.2.1",
"https-proxy-agent": "^2.2.3",
"lru-cache": "^5.1.1",
"mississippi": "^3.0.0",
"node-fetch-npm": "^2.0.2",
@ -7845,35 +7714,6 @@
"ssri": "^6.0.0"
},
"dependencies": {
"cacache": {
"version": "12.0.3",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz",
"integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==",
"dev": true,
"requires": {
"bluebird": "^3.5.5",
"chownr": "^1.1.1",
"figgy-pudding": "^3.5.1",
"glob": "^7.1.4",
"graceful-fs": "^4.1.15",
"infer-owner": "^1.0.3",
"lru-cache": "^5.1.1",
"mississippi": "^3.0.0",
"mkdirp": "^0.5.1",
"move-concurrently": "^1.0.1",
"promise-inflight": "^1.0.1",
"rimraf": "^2.6.3",
"ssri": "^6.0.1",
"unique-filename": "^1.1.1",
"y18n": "^4.0.0"
}
},
"graceful-fs": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz",
"integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==",
"dev": true
},
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@ -7883,16 +7723,10 @@
"yallist": "^3.0.2"
}
},
"y18n": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
"dev": true
},
"yallist": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true
}
}
@ -8194,9 +8028,9 @@
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"minipass": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
"dev": true,
"requires": {
"safe-buffer": "^5.1.2",
@ -8204,20 +8038,20 @@
},
"dependencies": {
"yallist": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true
}
}
},
"minizlib": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
"integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
"dev": true,
"requires": {
"minipass": "^2.2.1"
"minipass": "^2.9.0"
}
},
"mississippi": {
@ -8441,9 +8275,9 @@
}
},
"node-releases": {
"version": "1.1.43",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.43.tgz",
"integrity": "sha512-Rmfnj52WNhvr83MvuAWHEqXVoZXCcDQssSOffU4n4XOL9sPrP61mSZ88g25NqmABDvH7PiAlFCzoSCSdzA293w==",
"version": "1.1.45",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.45.tgz",
"integrity": "sha512-cXvGSfhITKI8qsV116u2FTzH5EWZJfgG7d4cpqwF8I8+1tWpD6AsvvGRKq2onR0DNj1jfqsjkXZsm14JMS7Cyg==",
"dev": true,
"requires": {
"semver": "^6.3.0"
@ -8658,10 +8492,13 @@
}
},
"npm-bundled": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
"integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
"dev": true
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz",
"integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==",
"dev": true,
"requires": {
"npm-normalize-package-bin": "^1.0.1"
}
},
"npm-normalize-package-bin": {
"version": "1.0.1",
@ -8682,9 +8519,9 @@
}
},
"npm-packlist": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.4.tgz",
"integrity": "sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==",
"version": "1.4.7",
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.7.tgz",
"integrity": "sha512-vAj7dIkp5NhieaGZxBJB8fF4R0078rqsmhJcAfXZ6O7JJhjhPK96n5Ry1oZcfLXgfun0GWTZPOxaEyqv8GBykQ==",
"dev": true,
"requires": {
"ignore-walk": "^3.0.1",
@ -8703,9 +8540,9 @@
}
},
"npm-registry-fetch": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.0.tgz",
"integrity": "sha512-Jllq35Jag8dtv0M17ue74XtdQTyqKzuAYGiX9mAjOhkmNjib3bBUgK6mUY61+AHnXeSRobQkpY3/xIOS/omptw==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.2.tgz",
"integrity": "sha512-Z0IFtPEozNdeZRPh3aHHxdG+ZRpzcbQaJLthsm3VhNf6DScicTFRHZzK82u8RsJUsUHkX+QH/zcB/5pmd20H4A==",
"dev": true,
"requires": {
"JSONStream": "^1.3.4",
@ -8713,7 +8550,8 @@
"figgy-pudding": "^3.4.1",
"lru-cache": "^5.1.1",
"make-fetch-happen": "^5.0.0",
"npm-package-arg": "^6.1.0"
"npm-package-arg": "^6.1.0",
"safe-buffer": "^5.2.0"
},
"dependencies": {
"lru-cache": {
@ -8725,10 +8563,16 @@
"yallist": "^3.0.2"
}
},
"safe-buffer": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
"dev": true
},
"yallist": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true
}
}
@ -8976,22 +8820,22 @@
},
"dependencies": {
"es-abstract": {
"version": "1.17.0-next.1",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0-next.1.tgz",
"integrity": "sha512-7MmGr03N7Rnuid6+wyhD9sHNE2n4tFSwExnU2lQl3lIo2ShXWGePY80zYaoMOmILWv57H0amMjZGHNzzGG70Rw==",
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz",
"integrity": "sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.1.4",
"is-regex": "^1.0.4",
"is-callable": "^1.1.5",
"is-regex": "^1.0.5",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimleft": "^2.1.0",
"string.prototype.trimright": "^2.1.0"
"string.prototype.trimleft": "^2.1.1",
"string.prototype.trimright": "^2.1.1"
}
},
"es-to-primitive": {
@ -9010,6 +8854,21 @@
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
"dev": true
},
"is-callable": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
"dev": true
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
}
}
},
@ -9274,18 +9133,6 @@
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.3"
},
"dependencies": {
"minipass": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
"dev": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
}
}
}
},
"yallist": {
@ -9303,12 +9150,12 @@
"dev": true
},
"parallel-transform": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz",
"integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
"integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==",
"dev": true,
"requires": {
"cyclist": "~0.2.2",
"cyclist": "^1.0.1",
"inherits": "^2.0.3",
"readable-stream": "^2.1.5"
}
@ -10261,22 +10108,22 @@
},
"dependencies": {
"es-abstract": {
"version": "1.17.0-next.1",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0-next.1.tgz",
"integrity": "sha512-7MmGr03N7Rnuid6+wyhD9sHNE2n4tFSwExnU2lQl3lIo2ShXWGePY80zYaoMOmILWv57H0amMjZGHNzzGG70Rw==",
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz",
"integrity": "sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.1.4",
"is-regex": "^1.0.4",
"is-callable": "^1.1.5",
"is-regex": "^1.0.5",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimleft": "^2.1.0",
"string.prototype.trimright": "^2.1.0"
"string.prototype.trimleft": "^2.1.1",
"string.prototype.trimright": "^2.1.1"
}
},
"es-to-primitive": {
@ -10295,6 +10142,21 @@
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
"dev": true
},
"is-callable": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
"dev": true
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
}
}
},
@ -10338,9 +10200,9 @@
"dev": true
},
"regjsparser": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.1.tgz",
"integrity": "sha512-7LutE94sz/NKSYegK+/4E77+8DipxF+Qn2Tmu362AcmsF2NYq/wx3+ObvU90TKEhjf7hQoFXo23ajjrXP7eUgg==",
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.2.tgz",
"integrity": "sha512-E9ghzUtoLwDekPT0DYCp+c4h+bvuUpe6rRHCTYn6eGoqj1LgKXxT6I0Il4WbjhQkOghzi/V+y03bPKvbllL93Q==",
"dev": true,
"requires": {
"jsesc": "~0.5.0"
@ -10897,9 +10759,9 @@
"dev": true
},
"smart-buffer": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.2.tgz",
"integrity": "sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==",
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz",
"integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==",
"dev": true
},
"snapdragon": {
@ -11158,13 +11020,13 @@
}
},
"socks": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.3.2.tgz",
"integrity": "sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ==",
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz",
"integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==",
"dev": true,
"requires": {
"ip": "^1.1.5",
"smart-buffer": "4.0.2"
"ip": "1.1.5",
"smart-buffer": "^4.1.0"
}
},
"socks-proxy-agent": {
@ -11502,9 +11364,9 @@
}
},
"stream-shift": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
"integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
"dev": true
},
"streamroller": {
@ -12001,16 +11863,16 @@
}
},
"ts-node": {
"version": "8.5.4",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.5.4.tgz",
"integrity": "sha512-izbVCRV68EasEPQ8MSIGBNK9dc/4sYJJKYA+IarMQct1RtEot6Xp0bXuClsbUSnKpg50ho+aOAx8en5c+y4OFw==",
"version": "8.6.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.6.1.tgz",
"integrity": "sha512-KqPbO7/UuOPE4ANAOV9geZjk6tet6rK2K+DFeEJq6kIXUi0nLkrOMksozGkIlFopOorkStlwar3DdWYrdl7zCw==",
"dev": true,
"requires": {
"arg": "^4.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"source-map-support": "^0.5.6",
"yn": "^3.0.0"
"yn": "^4.0.0"
}
},
"tslib": {
@ -12099,6 +11961,12 @@
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"optional": true
},
"type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true
},
"type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
@ -14615,9 +14483,9 @@
"dev": true
},
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yn/-/yn-4.0.0.tgz",
"integrity": "sha512-huWiiCS4TxKc4SfgmTwW1K7JmXPPAmuXWYy4j9qjQo4+27Kni8mGhAAi1cloRWmBe2EqcLgt3IGqQoRL/MtPgg==",
"dev": true
},
"zone.js": {

View File

@ -34,7 +34,7 @@
"test": "npm-run-all test:app test:api",
"test:app": "ng test --code-coverage --watch=false",
"test:api": "./src/api/vendor/phpunit/phpunit/phpunit -c test/api/phpunit.xml",
"test:api-single": "./src/api/vendor/phpunit/phpunit/phpunit -c test/api/phpunit.xml -g single",
"test:api-single": "./src/api/vendor/phpunit/phpunit/phpunit -c test/api/phpunit.xml --group single",
"test:watch": "ng test --code-coverage --watch",
"lint": "ng lint",
"postinstall": "cd src/api/ && composer update && composer install --optimize-autoloader && cd ../../"
@ -52,7 +52,7 @@
"chartist": "^0.11.4",
"chartist-plugin-tooltips": "^0.0.17",
"classlist.js": "^1.1.20150312",
"core-js": "^3.6.1",
"core-js": "^3.6.3",
"dragula": "^3.7.2",
"highlight.js": "^9.17.1",
"marked": "^0.8.0",
@ -63,8 +63,8 @@
"zone.js": "^0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^0.803.21",
"@angular/cli": "^8.3.21",
"@angular-devkit/build-angular": "^0.803.22",
"@angular/cli": "^8.3.22",
"@angular/compiler-cli": "^8.2.14",
"@angular/language-service": "^8.2.14",
"@types/chartist": "^0.9.46",
@ -72,7 +72,7 @@
"@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.8",
"@types/marked": "^0.7.2",
"@types/node": "^12.12.22",
"@types/node": "^13.1.6",
"bourbon": "6.0.0",
"bourbon-neat": "4.0.0",
"codelyzer": "^5.2.1",
@ -82,13 +82,13 @@
"karma": "^4.4.1",
"karma-chrome-launcher": "^3.1.0",
"karma-coverage-istanbul-reporter": "^2.1.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine": "~3.1.0",
"karma-jasmine-html-reporter": "^1.5.1",
"nodemon": "^2.0.2",
"npm-run-all": "^4.1.5",
"protractor": "~5.4.2",
"puppeteer": "^2.0.0",
"ts-node": "^8.5.4",
"ts-node": "^8.6.1",
"tslint": "~5.20.1",
"typescript": "^3.5.3"
}

View File

@ -2,60 +2,60 @@
$container = $app->getContainer();
// Inject a Monolog logger into the dependency container
$container['logger'] = function($c) {
$logger = new Monolog\Logger('API');
$fileHandler = new Monolog\Handler\StreamHandler('logs/api.log');
$container['logger'] = function() {
$logger = new Monolog\Logger('API');
$fileHandler = new Monolog\Handler\StreamHandler('logs/api.log');
$logger->pushHandler($fileHandler);
$logger->pushHandler($fileHandler);
return $logger;
return $logger;
};
// Replace notFoundHandler to use an API response
$container['notFoundHandler'] = function($c) {
return function($request, $response) use ($c) {
return $c['response']
->withHeader('Content-Type', 'application/json')
->write('{ message: "Matching API call not found." }');
};
return function() use ($c) {
return $c['response']
->withHeader('Content-Type', 'application/json')
->write('{ message: "Matching API call not found." }');
};
};
// Replace the errorHandler to use an API response
$container['errorHandler'] = function ($c) {
return function ($request, $response, $exception) use ($c) {
$c['logger']->addError('Server error', $exception->getTrace());
return function ($exception) use ($c) {
$c['logger']->addError('Server error', $exception->getTrace());
return $c['response']->withStatus(500)
->withHeader('Content-Type', 'application/json')
->write('{ message: "Internal Server Error", error: "' .
$exception->getMessage() . '" }');
};
return $c['response']->withStatus(500)
->withHeader('Content-Type', 'application/json')
->write('{ message: "Internal Server Error", error: "' .
$exception->getMessage() . '" }');
};
};
$container['phpErrorHandler'] = function ($c) {
return function ($request, $response, $exception) use ($c) {
$c['logger']->addError('Server error', $exception->getTrace());
return function ($exception) use ($c) {
$c['logger']->addError('Server error', $exception->getTrace());
return $c['response']->withStatus(500)
->withHeader('Content-Type', 'application/json')
->write('{ message: "Internal Server Error", error: "' .
$exception->getMessage() . '" }');
};
return $c['response']->withStatus(500)
->withHeader('Content-Type', 'application/json')
->write('{ message: "Internal Server Error", error: "' .
$exception->getMessage() . '" }');
};
};
// Routes ending in '/' use route without '/'
$app->add(function($request, $response, $next) {
$uri = $request->getUri();
$path = $uri->getPath();
$uri = $request->getUri();
$path = $uri->getPath();
if (strlen($path) > 1 && substr($path, -1) === '/') {
$path = substr($path, 0, -1);
}
if (strlen($path) > 1 && substr($path, -1) === '/') {
$path = substr($path, 0, -1);
}
if ($uri->getPath() !== $path) {
return $next($request->withUri($uri->withPath($path)), $response);
}
if ($uri->getPath() !== $path) {
return $next($request->withUri($uri->withPath($path)), $response);
}
return $next($request, $response);
return $next($request, $response);
});

View File

@ -1,23 +1,23 @@
{
"require": {
"monolog/monolog": "^1.18",
"gabordemooij/redbean": "^5.1",
"slim/slim": "^3.3",
"firebase/php-jwt": "^5.0",
"phpmailer/phpmailer": "^6.0",
"phpunit/phpunit": "^6.0",
"myclabs/php-enum": "^1.5"
},
"license": "MIT",
"authors": [
{
"name": "Matthew Ross",
"email": "root@matthewross.me",
"homepage": "https://matthewross.me",
"role": "Developer"
}
],
"autoload": {
"classmap": [ "controllers", "helpers" ]
"require": {
"monolog/monolog": "^2.0",
"gabordemooij/redbean": "^5.4",
"slim/slim": "^4.3",
"firebase/php-jwt": "^5.0",
"phpmailer/phpmailer": "^6.1",
"phpunit/phpunit": "^8.5",
"myclabs/php-enum": "^1.7"
},
"license": "MIT",
"authors": [
{
"name": "Matthew Ross",
"email": "root@matthewross.me",
"homepage": "https://matthewross.me",
"role": "Developer"
}
],
"autoload": {
"classmap": [ "controllers", "helpers" ]
}
}

681
src/api/composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -3,88 +3,88 @@ use RedBeanPHP\R;
class Activity extends BaseController {
public function getActivity($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::BOARD_ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$activity = [];
// TODO: More activity types
if ($args['type'] === 'task') {
if (!$this->checkBoardAccess($this->getBoardId((int)$args['id']),
$request)) {
return $this->jsonResponse($response, 403);
}
$activity = $this->getTaskActivity((int)$args['id']);
}
$this->apiJson->setSuccess();
$this->apiJson->addData($activity);
return $this->jsonResponse($response);
public function getActivity($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::BOARD_ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
private function getBoardId($taskId) {
$task = R::load('task', $taskId);
$column = R::load('column', $task->column_id);
$activity = [];
return $column->board_id;
// TODO: More activity types
if ($args['type'] === 'task') {
if (!$this->checkBoardAccess($this->getBoardId((int)$args['id']),
$request)) {
return $this->jsonResponse($response, 403);
}
$activity = $this->getTaskActivity((int)$args['id']);
}
private function sortLogs($a, $b) {
if ($a->timestamp === $b->timestamp) {
return 0; // @codeCoverageIgnore
}
$this->apiJson->setSuccess();
$this->apiJson->addData($activity);
return $a->timestamp > $b->timestamp ? -1 : 1;
return $this->jsonResponse($response);
}
private function getBoardId($taskId) {
$task = R::load('task', $taskId);
$column = R::load('column', $task->column_id);
return $column->board_id;
}
private function sortLogs($a, $b) {
if ($a->timestamp === $b->timestamp) {
return 0; // @codeCoverageIgnore
}
private function getTaskActivity($taskId) {
$task = R::load('task', $taskId);
$logs = [];
$commentIds = [];
$attachmentIds = [];
return $a->timestamp > $b->timestamp ? -1 : 1;
}
foreach ($task->ownComment as $comment) {
$commentIds[] = (int)$comment->id;
}
private function getTaskActivity($taskId) {
$task = R::load('task', $taskId);
$logs = [];
$commentIds = [];
$attachmentIds = [];
foreach ($task->ownAttachment as $attachment) {
$attachmentIds[] = (int)$attachment->id;
}
$taskActivity = R::find('activity',
'item_type="task" AND item_id=?',
[$taskId]);
$this->addLogItems($logs, $taskActivity);
$commentActivity =
R::find('activity', 'item_type="comment" AND '.
'item_id IN(' . R::genSlots($commentIds) . ')',
$commentIds);
$this->addLogItems($logs, $commentActivity);
$attachmentActivity =
R::find('activity', 'item_type="attachment" AND '.
'item_id IN(' . R::genSlots($attachmentIds) . ')',
$attachmentIds);
$this->addLogItems($logs, $attachmentActivity);
usort($logs, array("Activity", "sortLogs"));
return $logs;
foreach ($task->ownComment as $comment) {
$commentIds[] = (int)$comment->id;
}
private function addLogItems(&$logs, $items) {
foreach ($items as $logItem) {
$logs[] = (object)array('text'=>$logItem->log_text,
'timestamp'=>$logItem->timestamp);
}
foreach ($task->ownAttachment as $attachment) {
$attachmentIds[] = (int)$attachment->id;
}
$taskActivity = R::find('activity',
'item_type="task" AND item_id=?',
[$taskId]);
$this->addLogItems($logs, $taskActivity);
$commentActivity =
R::find('activity', 'item_type="comment" AND '.
'item_id IN(' . R::genSlots($commentIds) . ')',
$commentIds);
$this->addLogItems($logs, $commentActivity);
$attachmentActivity =
R::find('activity', 'item_type="attachment" AND '.
'item_id IN(' . R::genSlots($attachmentIds) . ')',
$attachmentIds);
$this->addLogItems($logs, $attachmentActivity);
usort($logs, array("Activity", "sortLogs"));
return $logs;
}
private function addLogItems(&$logs, $items) {
foreach ($items as $logItem) {
$logs[] = (object)array('text'=>$logItem->log_text,
'timestamp'=>$logItem->timestamp);
}
}
}

View File

@ -3,131 +3,131 @@ use RedBeanPHP\R;
class Attachments extends BaseController {
public function getAttachment($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
public function getAttachment($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$attachment = R::load('attachment', (int)$args['id']);
$attachment = R::load('attachment', (int)$args['id']);
if ($attachment->id === 0) {
$this->logger->addError('Attempt to load attachment ' .
$args['id'] . ' failed.');
$this->apiJson->addAlert('error', 'No attachment found for ID ' .
$args['id'] . '.');
if ($attachment->id === 0) {
$this->logger->addError('Attempt to load attachment ' .
$args['id'] . ' failed.');
$this->apiJson->addAlert('error', 'No attachment found for ID ' .
$args['id'] . '.');
return $this->jsonResponse($response);
}
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($this->getBoardId($attachment->task_id),
$request)) {
return $this->jsonResponse($response, 403);
}
if (!$this->checkBoardAccess($this->getBoardId($attachment->task_id),
$request)) {
return $this->jsonResponse($response, 403);
}
$this->apiJson->setSuccess();
$this->apiJson->addData($attachment);
$this->apiJson->setSuccess();
$this->apiJson->addData($attachment);
return $this->jsonResponse($response);
}
public function addAttachment($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$attachment = R::dispense('attachment');
if (!BeanLoader::LoadAttachment($attachment, $request->getBody())) {
$attachment->task_id = 0;
}
$task = R::load('task', $attachment->task_id);
if ($task->id === 0) {
$this->logger->addError('Add Attachment: ', [$attachment]);
$this->apiJson->addAlert('error', 'Error adding attachment. ' .
'Please try again.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($this->getBoardId($task->id), $request)) {
return $this->jsonResponse($response, 403);
}
R::store($attachment);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' added attachment.', '', json_encode($attachment),
'attachment', $attachment->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Attachment added.');
return $this->jsonResponse($response);
}
public function removeAttachment($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$actor = R::load('user', Auth::GetUserId($request));
$id = (int)$args['id'];
$attachment = R::load('attachment', $id);
// If User level, only the user that created the attachment
// may delete it. If higher level, delete is allowed.
if ((int)$actor->security_level === SecurityLevel::USER) {
if ($actor->id !== $attachment->user_id) {
$this->apiJson->addAlert('error',
'You do not have sufficient permissions ' .
'to remove this attachment.');
return $this->jsonResponse($response);
}
} // @codeCoverageIgnore
if ((int)$attachment->id !== $id) {
$this->logger->addError('Remove Attachment: ', [$attachment]);
$this->apiJson->addAlert('error', 'Error removing attachment. ' .
'No attachment found for ID ' . $id . '.');
return $this->jsonResponse($response);
}
public function addAttachment($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$attachment = R::dispense('attachment');
if (!BeanLoader::LoadAttachment($attachment, $request->getBody())) {
$attachment->task_id = 0;
}
$task = R::load('task', $attachment->task_id);
if ($task->id === 0) {
$this->logger->addError('Add Attachment: ', [$attachment]);
$this->apiJson->addAlert('error', 'Error adding attachment. ' .
'Please try again.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($this->getBoardId($task->id), $request)) {
return $this->jsonResponse($response, 403);
}
R::store($attachment);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' added attachment.', '', json_encode($attachment),
'attachment', $attachment->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Attachment added.');
return $this->jsonResponse($response);
if (!$this->checkBoardAccess($this->getBoardId($attachment->task_id),
$request)) {
return $this->jsonResponse($response, 403);
}
public function removeAttachment($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$before = $attachment;
$attachment->delete();
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username .' removed attachment ' . $before->name,
json_encode($before), '', 'attachment', $id);
$id = (int)$args['id'];
$attachment = R::load('attachment', $id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'Attachment ' . $before->name . ' removed.');
// If User level, only the user that created the attachment
// may delete it. If higher level, delete is allowed.
if ((int)$actor->security_level === SecurityLevel::USER) {
if ($actor->id !== $attachment->user_id) {
$this->apiJson->addAlert('error',
'You do not have sufficient permissions ' .
'to remove this attachment.');
return $this->jsonResponse($response);
}
return $this->jsonResponse($response);
}
} // @codeCoverageIgnore
private function getBoardId($taskId) {
$task = R::load('task', $taskId);
$column = R::load('column', $task->column_id);
if ((int)$attachment->id !== $id) {
$this->logger->addError('Remove Attachment: ', [$attachment]);
$this->apiJson->addAlert('error', 'Error removing attachment. ' .
'No attachment found for ID ' . $id . '.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($this->getBoardId($attachment->task_id),
$request)) {
return $this->jsonResponse($response, 403);
}
$before = $attachment;
$attachment->delete();
$this->dbLogger->logChange($actor->id,
$actor->username .' removed attachment ' . $before->name,
json_encode($before), '', 'attachment', $id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'Attachment ' . $before->name . ' removed.');
return $this->jsonResponse($response);
}
private function getBoardId($taskId) {
$task = R::load('task', $taskId);
$column = R::load('column', $task->column_id);
return $column->board_id;
}
return $column->board_id;
}
}

View File

@ -4,292 +4,292 @@ use Firebase\JWT\JWT;
class Auth extends BaseController {
public static function HasBoardAccess($request, $boardId, $userId = null) {
$hasAccess = false;
public static function HasBoardAccess($request, $boardId, $userId = null) {
$hasAccess = false;
if ($userId === null) {
$userId = self::GetUserId($request);
}
$user = R::load('user', $userId);
if ((int)$user->security_level === SecurityLevel::ADMIN) {
return true;
}
$board = R::load('board', $boardId);
foreach ($board->sharedUserList as $check) {
if ((int)$check->id === $userId) {
$hasAccess = true;
break;
}
}
return $hasAccess;
if ($userId === null) {
$userId = self::GetUserId($request);
}
public static function CreateInitialAdmin() {
$admin = R::load('user', 1);
// Don't create more than one admin
if ($admin->id) {
return;
}
$admin->security_level = SecurityLevel::ADMIN()->getValue();
$admin->username = 'admin';
$admin->password_hash = password_hash('admin', PASSWORD_BCRYPT);
$admin->email = '';
$admin->default_board_id = 0;
$admin->user_option_id = 0;
$admin->last_login = 0;
$admin->active_token = '';
$opts = R::dispense('useroption');
$opts->new_tasks_at_bottom = true;
$opts->show_animations = true;
$opts->show_assignee = true;
$opts->multiple_tasks_per_row = false;
$opts->language = 'en';
R::store($opts);
$admin->user_option_id = $opts->id;
R::store($admin);
$user = R::load('user', $userId);
if ((int)$user->security_level === SecurityLevel::ADMIN) {
return true;
}
public static function CreateJwtSigningKey() {
$key = R::load('jwt', 1);
$board = R::load('board', $boardId);
// Don't create more than one secret key
if ($key->id) {
return;
}
// Generate a JWT signing key by hashing the current time.
$key->secret = hash('sha512', strval(time()));
R::store($key);
foreach ($board->sharedUserList as $check) {
if ((int)$check->id === $userId) {
$hasAccess = true;
break;
}
}
public static function ValidateToken($request, $response) {
if (!$request->hasHeader('Authorization')) {
return $response->withStatus(400);
}
return $hasAccess;
}
$jwt = $request->getHeader('Authorization')[0];
$payload = self::getJwtPayload($jwt);
public static function CreateInitialAdmin() {
$admin = R::load('user', 1);
if ($payload === null) {
return $response->withStatus(401);
}
$user = R::load('user', $payload->uid);
if ($user->active_token !== $jwt) {
$user->active_token = '';
R::store($user);
return $response->withStatus(401);
}
$response->getBody()->write($jwt);
return $response;
// Don't create more than one admin
if ($admin->id) {
return;
}
public static function GetUserId($request) {
$uid = -1;
$admin->security_level = SecurityLevel::ADMIN()->getValue();
$admin->username = 'admin';
$admin->password_hash = password_hash('admin', PASSWORD_BCRYPT);
$admin->email = '';
$admin->default_board_id = 0;
$admin->user_option_id = 0;
$admin->last_login = 0;
$admin->active_token = '';
try {
$jwt = $request->getHeader('Authorization')[0];
} catch (Exception $ex) {
return $uid;
}
$opts = R::dispense('useroption');
$opts->new_tasks_at_bottom = true;
$opts->show_animations = true;
$opts->show_assignee = true;
$opts->multiple_tasks_per_row = false;
$opts->language = 'en';
$payload = self::getJwtPayload($jwt);
R::store($opts);
$admin->user_option_id = $opts->id;
R::store($admin);
}
if ($payload !== null) {
$uid = $payload->uid;
}
public static function CreateJwtSigningKey() {
$key = R::load('jwt', 1);
return $uid;
// Don't create more than one secret key
if ($key->id) {
return;
}
public function login($request, $response) {
$data = json_decode($request->getBody());
$user = R::findOne('user', 'username = ?', [$data->username]);
// Generate a JWT signing key by hashing the current time.
$key->secret = hash('sha512', strval(time()));
if ($user === null) {
$this->logger->addError('Login: ', [$data]);
$this->apiJson->addAlert('error', 'Invalid username or password.');
R::store($key);
}
return $this->jsonResponse($response, 401);
}
if (!password_verify($data->password, $user->password_hash)) {
$this->logger->addError('Login: ', [$data]);
$this->apiJson->addAlert('error', 'Invalid username or password.');
return $this->jsonResponse($response, 401);
}
$jwt = self::createJwt($user->id, ($data->remember ? 200 : 1));
$user = R::load('user', $user->id);
if ($user->username === 'admin' && (int)$user->last_login === 0) {
$this->apiJson->addAlert('warn',
'This is your first login, go to Settings ' .
'to change your password.');
$this->apiJson->addAlert('success',
'Go to Settings to create your first board.');
}
$user->active_token = $jwt;
$user->last_login = time();
R::store($user);
$this->dbLogger->logChange($user->id, $user->username . ' logged in',
null, null, 'user', $user->id);
$this->apiJson->setSuccess();
$this->apiJson->addData($jwt);
$this->apiJson->addData($this->sanitizeUser($user));
return $this->jsonResponse($response);
public static function ValidateToken($request, $response) {
if (!$request->hasHeader('Authorization')) {
return $response->withStatus(400);
}
public function logout($request, $response) {
if (!$request->hasHeader('Authorization')) {
return $this->jsonResponse($response, 400);
}
$jwt = $request->getHeader('Authorization')[0];
$payload = self::getJwtPayload($jwt);
$jwt = $request->getHeader('Authorization')[0];
$payload = self::getJwtPayload($jwt);
if ($payload === null) {
$this->apiJson->addAlert('error', 'Invalid access token.');
return $this->jsonResponse($response, 401);
}
$user = R::load('user', $payload->uid);
if ($user->id) {
$user->active_token = '';
R::store($user);
}
$this->dbLogger->logChange($user->id, $user->username . ' logged out',
null, null, 'user', $user->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'You have been logged out.');
return $this->jsonResponse($response);
if ($payload === null) {
return $response->withStatus(401);
}
public function authenticate($request, $response) {
$response = self::ValidateToken($request, $response);
$status = $response->getStatusCode();
$user = R::load('user', $payload->uid);
if ($status !== 200) {
if ($status === 400) {
$this->apiJson->addAlert('error',
'Authorization header missing.');
return $this->jsonResponse($response, $status);
}
if ($user->active_token !== $jwt) {
$user->active_token = '';
R::store($user);
$this->apiJson->addAlert('error', 'Invalid API token.');
return $this->jsonResponse($response, $status);
}
$jwt = $request->getHeader('Authorization')[0];
$payload = self::getJwtPayload($jwt);
$user = R::load('user', $payload->uid);
$opts = R::load('useroption', $user->user_option_id);
$collapsed = R::find('collapsed', ' user_id = ? ', [ $user->id ]);
$user->collapsed = [];
foreach ($collapsed as $collapse) {
$user->collapsed[] = $collapse->column_id;
}
$this->apiJson->setSuccess();
$this->apiJson->addData($jwt);
$this->apiJson->addData($this->sanitizeUser($user));
$this->apiJson->addData($opts);
return $this->jsonResponse($response);
return $response->withStatus(401);
}
public function refreshToken($request, $response) {
$response = self::ValidateToken($request, $response);
$status = $response->getStatusCode();
$response->getBody()->write($jwt);
if ($status !== 200) {
if ($status === 400) {
$this->apiJson->addAlert('error',
'Authorization header missing.');
return $this->jsonResponse($response, $status);
}
return $response;
}
$this->apiJson->addAlert('error', 'Invalid API token.');
return $this->jsonResponse($response, $status);
}
public static function GetUserId($request) {
$uid = -1;
$jwt = $request->getHeader('Authorization')[0];
$payload = self::getJwtPayload($jwt);
$user = R::load('user', $payload->uid);
$jwt = self::createJwt($user->id, (int)$payload->mul);
$user->active_token = $jwt;
R::store($user);
$opts = R::load('useroption', $user->user_option_id);
$this->apiJson->setSuccess();
$this->apiJson->addData($jwt);
$this->apiJson->addData($this->sanitizeUser($user));
$this->apiJson->addData($opts);
return $this->jsonResponse($response);
try {
$jwt = $request->getHeader('Authorization')[0];
} catch (Exception $ex) {
return $uid;
}
private function sanitizeUser($user) {
unset($user->password_hash);
unset($user->active_token);
$payload = self::getJwtPayload($jwt);
return $user;
if ($payload !== null) {
$uid = $payload->uid;
}
private static function getJwtPayload($jwt) {
try {
$payload = JWT::decode($jwt, self::getJwtKey(), ['HS256']);
} catch (Exception $ex) {
return null;
}
return $uid;
}
return $payload;
public function login($request, $response) {
$data = json_decode($request->getBody());
$user = R::findOne('user', 'username = ?', [$data->username]);
if ($user === null) {
$this->logger->addError('Login: ', [$data]);
$this->apiJson->addAlert('error', 'Invalid username or password.');
return $this->jsonResponse($response, 401);
}
private static function createJwt($userId, $mult = 1) {
// If 'remember me' feature is desired, set the multiplier higher.
// By default, a token will expire after half an hour, but can be
// refreshed by a call to /api/refresh.
if (!password_verify($data->password, $user->password_hash)) {
$this->logger->addError('Login: ', [$data]);
$this->apiJson->addAlert('error', 'Invalid username or password.');
return JWT::encode(array(
'exp' => time() + (60 * 30) * $mult, // 30 minutes * $mult
'uid' => (int)$userId,
'mul' => $mult
), Auth::getJwtKey());
return $this->jsonResponse($response, 401);
}
private static function getJwtKey() {
self::CreateJwtSigningKey();
$key = R::load('jwt', 1);
$jwt = self::createJwt($user->id, ($data->remember ? 200 : 1));
$user = R::load('user', $user->id);
return $key->secret;
if ($user->username === 'admin' && (int)$user->last_login === 0) {
$this->apiJson->addAlert('warn',
'This is your first login, go to Settings ' .
'to change your password.');
$this->apiJson->addAlert('success',
'Go to Settings to create your first board.');
}
$user->active_token = $jwt;
$user->last_login = time();
R::store($user);
$this->dbLogger->logChange($user->id, $user->username . ' logged in',
null, null, 'user', $user->id);
$this->apiJson->setSuccess();
$this->apiJson->addData($jwt);
$this->apiJson->addData($this->sanitizeUser($user));
return $this->jsonResponse($response);
}
public function logout($request, $response) {
if (!$request->hasHeader('Authorization')) {
return $this->jsonResponse($response, 400);
}
$jwt = $request->getHeader('Authorization')[0];
$payload = self::getJwtPayload($jwt);
if ($payload === null) {
$this->apiJson->addAlert('error', 'Invalid access token.');
return $this->jsonResponse($response, 401);
}
$user = R::load('user', $payload->uid);
if ($user->id) {
$user->active_token = '';
R::store($user);
}
$this->dbLogger->logChange($user->id, $user->username . ' logged out',
null, null, 'user', $user->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'You have been logged out.');
return $this->jsonResponse($response);
}
public function authenticate($request, $response) {
$response = self::ValidateToken($request, $response);
$status = $response->getStatusCode();
if ($status !== 200) {
if ($status === 400) {
$this->apiJson->addAlert('error',
'Authorization header missing.');
return $this->jsonResponse($response, $status);
}
$this->apiJson->addAlert('error', 'Invalid API token.');
return $this->jsonResponse($response, $status);
}
$jwt = $request->getHeader('Authorization')[0];
$payload = self::getJwtPayload($jwt);
$user = R::load('user', $payload->uid);
$opts = R::load('useroption', $user->user_option_id);
$collapsed = R::find('collapsed', ' user_id = ? ', [ $user->id ]);
$user->collapsed = [];
foreach ($collapsed as $collapse) {
$user->collapsed[] = $collapse->column_id;
}
$this->apiJson->setSuccess();
$this->apiJson->addData($jwt);
$this->apiJson->addData($this->sanitizeUser($user));
$this->apiJson->addData($opts);
return $this->jsonResponse($response);
}
public function refreshToken($request, $response) {
$response = self::ValidateToken($request, $response);
$status = $response->getStatusCode();
if ($status !== 200) {
if ($status === 400) {
$this->apiJson->addAlert('error',
'Authorization header missing.');
return $this->jsonResponse($response, $status);
}
$this->apiJson->addAlert('error', 'Invalid API token.');
return $this->jsonResponse($response, $status);
}
$jwt = $request->getHeader('Authorization')[0];
$payload = self::getJwtPayload($jwt);
$user = R::load('user', $payload->uid);
$jwt = self::createJwt($user->id, (int)$payload->mul);
$user->active_token = $jwt;
R::store($user);
$opts = R::load('useroption', $user->user_option_id);
$this->apiJson->setSuccess();
$this->apiJson->addData($jwt);
$this->apiJson->addData($this->sanitizeUser($user));
$this->apiJson->addData($opts);
return $this->jsonResponse($response);
}
private function sanitizeUser($user) {
unset($user->password_hash);
unset($user->active_token);
return $user;
}
private static function getJwtPayload($jwt) {
try {
$payload = JWT::decode($jwt, self::getJwtKey(), ['HS256']);
} catch (Exception $ex) {
return null;
}
return $payload;
}
private static function createJwt($userId, $mult = 1) {
// If 'remember me' feature is desired, set the multiplier higher.
// By default, a token will expire after half an hour, but can be
// refreshed by a call to /api/refresh.
return JWT::encode(array(
'exp' => time() + (60 * 30) * $mult, // 30 minutes * $mult
'uid' => (int)$userId,
'mul' => $mult
), Auth::getJwtKey());
}
private static function getJwtKey() {
self::CreateJwtSigningKey();
$key = R::load('jwt', 1);
return $key->secret;
}
}

View File

@ -3,124 +3,124 @@ use RedBeanPHP\R;
class AutoActions extends BaseController {
public function getAllActions($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$autoActions = $this->getAll($request);
if (!count($autoActions)) {
$this->apiJson->addAlert('info',
'No automatic actions in database.');
$this->apiJson->addData([]);
return $this->jsonResponse($response);
}
$this->apiJson->setSuccess();
$this->apiJson->addData($autoActions);
return $this->jsonResponse($response);
public function getAllActions($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
public function addAction($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::BOARD_ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$autoActions = $this->getAll($request);
$action = R::dispense('autoaction');
if (!BeanLoader::LoadAutoAction($action, $request->getBody())) {
$action->board_id = 0;
}
if (!count($autoActions)) {
$this->apiJson->addAlert('info',
'No automatic actions in database.');
$this->apiJson->addData([]);
$board = R::load('board', $action->board_id);
if ($board->id === 0) {
$this->logger->addError('Add Action: ', [$action]);
$this->apiJson->addAlert('error',
'Error adding automatic action. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($action->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
R::store($action);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' added automatic action.',
'', json_encode($action), 'action', $action->id);
$actions = $this->getAll($request);
$this->apiJson->setSuccess($actions);
$this->apiJson->addData($actions);
$this->apiJson->addAlert('success', 'Automatic action added.');
return $this->jsonResponse($response);
return $this->jsonResponse($response);
}
public function removeAction($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::BOARD_ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$this->apiJson->setSuccess();
$this->apiJson->addData($autoActions);
$id = (int)$args['id'];
$action = R::load('autoaction', $id);
return $this->jsonResponse($response);
}
if ((int)$action->id !== $id) {
$this->logger->addError('Remove Action: ', [$action]);
$this->apiJson->addAlert('error', 'Error removing action. ' .
'No action found for ID ' . $id . '.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($action->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
$before = $action;
R::trash($action);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username .' removed action ' . $before['id'] . '.',
json_encode($before), '', 'action', $id);
$actions = $this->getAll($request);
$this->apiJson->setSuccess();
$this->apiJson->addData($actions);
$this->apiJson->addAlert('success', 'Automatic action removed.');
return $this->jsonResponse($response);
public function addAction($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::BOARD_ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
private function getAll($request) {
$autoActions = R::findAll('autoaction');
$data = [];
foreach ($autoActions as $action) {
if (Auth::HasBoardAccess($request, $action->board_id)) {
$data[] = $action;
}
}
return $data;
$action = R::dispense('autoaction');
if (!BeanLoader::LoadAutoAction($action, $request->getBody())) {
$action->board_id = 0;
}
$board = R::load('board', $action->board_id);
if ($board->id === 0) {
$this->logger->addError('Add Action: ', [$action]);
$this->apiJson->addAlert('error',
'Error adding automatic action. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($action->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
R::store($action);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' added automatic action.',
'', json_encode($action), 'action', $action->id);
$actions = $this->getAll($request);
$this->apiJson->setSuccess($actions);
$this->apiJson->addData($actions);
$this->apiJson->addAlert('success', 'Automatic action added.');
return $this->jsonResponse($response);
}
public function removeAction($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::BOARD_ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$id = (int)$args['id'];
$action = R::load('autoaction', $id);
if ((int)$action->id !== $id) {
$this->logger->addError('Remove Action: ', [$action]);
$this->apiJson->addAlert('error', 'Error removing action. ' .
'No action found for ID ' . $id . '.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($action->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
$before = $action;
R::trash($action);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username .' removed action ' . $before['id'] . '.',
json_encode($before), '', 'action', $id);
$actions = $this->getAll($request);
$this->apiJson->setSuccess();
$this->apiJson->addData($actions);
$this->apiJson->addAlert('success', 'Automatic action removed.');
return $this->jsonResponse($response);
}
private function getAll($request) {
$autoActions = R::findAll('autoaction');
$data = [];
foreach ($autoActions as $action) {
if (Auth::HasBoardAccess($request, $action->board_id)) {
$data[] = $action;
}
}
return $data;
}
}

View File

@ -2,57 +2,57 @@
use RedBeanPHP\R;
abstract class BaseController {
protected $apiJson;
protected $logger;
protected $dbLogger;
protected $container;
protected $apiJson;
protected $logger;
protected $dbLogger;
protected $container;
public function __construct($container) {
$this->apiJson = new ApiJson();
$this->logger = $container->get('logger');
$this->dbLogger = new DbLogger();
$this->container = $container;
public function __construct($container) {
$this->apiJson = new ApiJson();
$this->logger = $container->get('logger');
$this->dbLogger = new DbLogger();
$this->container = $container;
}
public function jsonResponse($response, $status = 200) {
return $response->withStatus($status)->withJson($this->apiJson);
}
public function checkBoardAccess($boardId, $request) {
if (!Auth::HasBoardAccess($request, $boardId)) {
$this->apiJson->addAlert('error', 'Access restricted.');
return false;
}
public function jsonResponse($response, $status = 200) {
return $response->withStatus($status)->withJson($this->apiJson);
}
return true;
}
public function checkBoardAccess($boardId, $request) {
if (!Auth::HasBoardAccess($request, $boardId)) {
$this->apiJson->addAlert('error', 'Access restricted.');
return false;
}
return true;
}
public function secureRoute($request, $response, $securityLevel) {
$response = Auth::ValidateToken($request, $response);
$status = $response->getStatusCode();
if ($status !== 200) {
if ($status === 400) {
$this->apiJson->addAlert('error',
'Authorization header missing.');
return $status;
}
$this->apiJson->addAlert('error', 'Invalid API token.');
return $status;
}
$user = R::load('user', Auth::GetUserId($request));
if ((int)$user->security_level > $securityLevel) {
$this->apiJson->addAlert('error', 'Insufficient privileges.');
return 403;
}
$this->apiJson->addData((string) $response->getBody());
public function secureRoute($request, $response, $securityLevel) {
$response = Auth::ValidateToken($request, $response);
$status = $response->getStatusCode();
if ($status !== 200) {
if ($status === 400) {
$this->apiJson->addAlert('error',
'Authorization header missing.');
return $status;
}
$this->apiJson->addAlert('error', 'Invalid API token.');
return $status;
}
$user = R::load('user', Auth::GetUserId($request));
if ((int)$user->security_level > $securityLevel) {
$this->apiJson->addAlert('error', 'Insufficient privileges.');
return 403;
}
$this->apiJson->addData((string) $response->getBody());
return $status;
}
}

View File

@ -3,232 +3,224 @@ use RedBeanPHP\R;
class Boards extends BaseController {
public function getAllBoards($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$boards = $this->loadAllBoards($request);
if (!count($boards)) {
$this->apiJson->addAlert('info', 'No boards in database.');
return $this->jsonResponse($response);
}
$this->apiJson->setSuccess();
$this->apiJson->addData($boards);
return $this->jsonResponse($response);
public function getAllBoards($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
public function getBoard($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$boards = $this->loadAllBoards($request);
$board = R::load('board', (int)$args['id']);
if (!count($boards)) {
$this->apiJson->addAlert('info', 'No boards in database.');
if ($board->id === 0) {
$this->logger->addError('Attempt to load board ' . $args['id'] .
' failed.');
$this->apiJson->addAlert('error', 'No board found for ID ' .
$args['id'] . '.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($board->id, $request)) {
return $this->jsonResponse($response, 403);
}
$this->cleanBoard($board);
$this->apiJson->setSuccess();
$this->apiJson->addData(R::exportAll($board));
return $this->jsonResponse($response);
return $this->jsonResponse($response);
}
public function addBoard($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$this->apiJson->setSuccess();
$this->apiJson->addData($boards);
$board = R::dispense('board');
if (!BeanLoader::LoadBoard($board, $request->getBody())) {
$board->id = -1;
}
return $this->jsonResponse($response);
}
$this->includeAdmins($board);
if ($board->id === -1) {
$this->logger->addError('Add Board: ', [$board]);
$this->apiJson->addAlert('error', 'Error adding board. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
R::store($board);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' added board ' . $board->name . '.',
'', json_encode($board), 'board', $board->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'Board ' . $board->name . ' added.');
$this->apiJson->addData($this->loadAllBoards($request));
return $this->jsonResponse($response);
public function getBoard($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
public function updateBoard($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::BOARD_ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$board = R::load('board', (int)$args['id']);
$data = json_decode($request->getBody());
if ($board->id === 0) {
$this->logger->addError('Attempt to load board ' . $args['id'] .
' failed.');
$this->apiJson->addAlert('error', 'No board found for ID ' .
$args['id'] . '.');
if (!property_exists($args, 'id')) {
$this->logger->addError('Update Board: ', [$data]);
$this->apiJson->addAlert('error', 'Error updating board. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
$board = R::load('board', (int)$args['id']);
if (!$this->checkBoardAccess($board->id, $request)) {
return $this->jsonResponse($response, 403);
}
if (!property_exists($data, 'id')) {
$this->logger->addError('Update Board: ', [$board, $data]);
$this->apiJson->addAlert('error', 'Error updating board. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
$update = R::load('board', (int)$args['id']);
$update->id = BeanLoader::LoadBoard($update, $request->getBody())
? $board->id : 0;
if ($update->id === 0 || ($board->id !== $update->id)) {
$this->logger->addError('Update Board: ', [$board, $update]);
$this->apiJson->addAlert('error', 'Error updating board. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
$this->includeAdmins($update);
R::store($update);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' updated board ' . $update->name,
json_encode(R::exportAll($board)),
json_encode(R::exportAll($update)), 'board', $update->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'Board ' . $update->name . ' updated.');
$this->apiJson->addData($this->loadAllBoards($request));
return $this->jsonResponse($response);
return $this->jsonResponse($response);
}
public function removeBoard($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$id = (int)$args['id'];
$board = R::load('board', $id);
if ((int)$board->id !== $id) {
$this->logger->addError('Remove Board: ', [$board]);
$this->apiJson->addAlert('error', 'Error removing board. ' .
'No board found for ID ' . $id . '.');
return $this->jsonResponse($response);
}
$before = $board;
R::trash($board);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' removed board ' . $before->name,
json_encode($before), '', 'board', $id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'Board ' . $before->name . ' removed.');
$this->apiJson->addData($this->loadAllBoards($request));
return $this->jsonResponse($response);
if (!$this->checkBoardAccess($board->id, $request)) {
return $this->jsonResponse($response, 403);
}
private function includeAdmins($board) {
$admins = R::findAll('user', ' WHERE security_level = 1 ');
$this->cleanBoard($board);
$this->apiJson->setSuccess();
$this->apiJson->addData(R::exportAll($board));
foreach ($admins as $admin) {
if (!in_array($admin, $board->sharedUserList)) {
$board->sharedUserList[] = $admin;
}
}
return $this->jsonResponse($response);
}
public function addBoard($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
private function loadAllBoards($request) {
$boards = [];
$boardBeans = R::findAll('board');
if (count($boardBeans)) {
foreach ($boardBeans as $bean) {
if (Auth::HasBoardAccess($request, $bean->id)) {
$this->cleanBoard($bean);
$boards[] = $bean;
}
}
}
return R::exportAll($boards);
$board = R::dispense('board');
if (!BeanLoader::LoadBoard($board, $request->getBody())) {
$board->id = -1;
}
private function cleanBoard(&$board) {
foreach ($board->sharedUserList as $user) {
$user = $this->cleanUser($user);
}
$this->includeAdmins($board);
foreach ($board->xownColumnList as $column) {
foreach ($column->xownTaskList as $task) {
foreach ($task->sharedUserList as $user) {
$user = $this->cleanUser($user);
}
}
}
if ($board->id === -1) {
$this->logger->addError('Add Board: ', [$board]);
$this->apiJson->addAlert('error', 'Error adding board. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
private function cleanUser($user) {
unset($user->password_hash);
unset($user->active_token);
R::store($board);
return $user;
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' added board ' . $board->name . '.',
'', json_encode($board), 'board', $board->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'Board ' . $board->name . ' added.');
$this->apiJson->addData($this->loadAllBoards($request));
return $this->jsonResponse($response);
}
public function updateBoard($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::BOARD_ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$data = json_decode($request->getBody());
if (is_null($args) || !array_key_exists('id', $args)) {
$this->logger->addError('Update Board: ', [$data]);
$this->apiJson->addAlert('error', 'Error updating board. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
$board = R::load('board', (int)$args['id']);
if (!$this->checkBoardAccess($board->id, $request)) {
return $this->jsonResponse($response, 403);
}
$update = R::load('board', (int)$args['id']);
$update->id = BeanLoader::LoadBoard($update, $request->getBody())
? $board->id : 0;
if ($update->id === 0 || ($board->id !== $update->id)) {
$this->logger->addError('Update Board: ', [$board, $update]);
$this->apiJson->addAlert('error', 'Error updating board. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
$this->includeAdmins($update);
R::store($update);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' updated board ' . $update->name,
json_encode(R::exportAll($board)),
json_encode(R::exportAll($update)), 'board', $update->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'Board ' . $update->name . ' updated.');
$this->apiJson->addData($this->loadAllBoards($request));
return $this->jsonResponse($response);
}
public function removeBoard($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$id = (int)$args['id'];
$board = R::load('board', $id);
if ((int)$board->id !== $id) {
$this->logger->addError('Remove Board: ', [$board]);
$this->apiJson->addAlert('error', 'Error removing board. ' .
'No board found for ID ' . $id . '.');
return $this->jsonResponse($response);
}
$before = $board;
R::trash($board);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' removed board ' . $before->name,
json_encode($before), '', 'board', $id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'Board ' . $before->name . ' removed.');
$this->apiJson->addData($this->loadAllBoards($request));
return $this->jsonResponse($response);
}
private function includeAdmins($board) {
$admins = R::findAll('user', ' WHERE security_level = 1 ');
foreach ($admins as $admin) {
if (!in_array($admin, $board->sharedUserList)) {
$board->sharedUserList[] = $admin;
}
}
}
private function loadAllBoards($request) {
$boards = [];
$boardBeans = R::findAll('board');
if (count($boardBeans)) {
foreach ($boardBeans as $bean) {
if (Auth::HasBoardAccess($request, $bean->id)) {
$this->cleanBoard($bean);
$boards[] = $bean;
}
}
}
return R::exportAll($boards);
}
private function cleanBoard(&$board) {
foreach ($board->sharedUserList as $user) {
$user = $this->cleanUser($user);
}
foreach ($board->xownColumnList as $column) {
foreach ($column->xownTaskList as $task) {
foreach ($task->sharedUserList as $user) {
$user = $this->cleanUser($user);
}
}
}
}
private function cleanUser($user) {
unset($user->password_hash);
unset($user->active_token);
return $user;
}
}

View File

@ -3,151 +3,160 @@ use RedBeanPHP\R;
class Columns extends BaseController {
public function getColumn($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$column = R::load('column', (int)$args['id']);
if ((int)$column->id === 0) {
$this->logger->addError('Attempt to load column ' .
$args['id'] . ' failed.');
$this->apiJson->addAlert('error', 'No column found for ID ' .
$args['id'] . '.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($column->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
$this->apiJson->setSuccess();
$this->apiJson->addData(R::exportAll($column));
return $this->jsonResponse($response);
public function getColumn($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
public function addColumn($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::BOARD_ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$column = R::load('column', (int)$args['id']);
$column = R::dispense('column');
if (!BeanLoader::LoadColumn($column, $request->getBody())) {
$column->board_id = 0;
}
if ((int)$column->id === 0) {
$this->logger->addError('Attempt to load column ' .
$args['id'] . ' failed.');
$this->apiJson->addAlert('error', 'No column found for ID ' .
$args['id'] . '.');
$board = R::load('board', $column->board_id);
if ((int)$board->id === 0) {
$this->logger->addError('Add Column: ', [$column]);
$this->apiJson->addAlert('error', 'Error adding column. ' .
'Please try again.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($column->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
R::store($column);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' added column ' . $column->name . '.',
'', json_encode($column), 'column', $column->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Column ' .
$column->name . ' added.');
return $this->jsonResponse($response);
return $this->jsonResponse($response);
}
public function updateColumn($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::BOARD_ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$column = R::load('column', (int)$args['id']);
$update = R::dispense('column');
$update->id = BeanLoader::LoadColumn($update, $request->getBody())
? $column->id
: 0;
if ($column->id === 0 || (int)$column->id !== (int)$update->id) {
$this->logger->addError('Update Column: ', [$column, $update]);
$this->apiJson->addAlert('error', 'Error updating column ' .
$update->name . '. Please try again.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($column->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
R::store($update);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' updated column ' . $update->name,
json_encode($column), json_encode($update),
'column', $update->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Column ' .
$update->name . ' updated.');
$this->apiJson->addData(R::exportAll($update));
return $this->jsonResponse($response);
if (!$this->checkBoardAccess($column->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
public function removeColumn($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::BOARD_ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$this->apiJson->setSuccess();
$this->apiJson->addData(R::exportAll($column));
$id = (int)$args['id'];
$column = R::load('column', $id);
return $this->jsonResponse($response);
}
if ((int)$column->id !== $id) {
$this->logger->addError('Remove Column: ', [$column]);
$this->apiJson->addAlert('error', 'Error removing column. ' .
'No column found for ID ' . $id . '.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($column->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
$before = $column;
R::trash($column);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' removed column ' . $before->name,
json_encode($before), '', 'column', $id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'Column ' . $before->name . ' removed.');
return $this->jsonResponse($response);
public function addColumn($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::BOARD_ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$column = R::dispense('column');
if (!BeanLoader::LoadColumn($column, $request->getBody())) {
$column->board_id = 0;
}
$board = R::load('board', $column->board_id);
if ((int)$board->id === 0) {
$this->logger->addError('Add Column: ', [$column]);
$this->apiJson->addAlert('error', 'Error adding column. ' .
'Please try again.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($column->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
R::store($column);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' added column ' . $column->name . '.',
'', json_encode($column), 'column', $column->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Column ' .
$column->name . ' added.');
return $this->jsonResponse($response);
}
public function updateColumn($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::BOARD_ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$data = json_decode($request->getBody());
if (is_null($args) || !array_key_exists('id', $args)) {
$this->logger->addError('Update Task: ', [$data]);
$this->apiJson->addAlert('error', 'Error updating task. Please try again.');
return $this->jsonResponse($response);
}
$column = R::load('column', (int)$args['id']);
$update = R::dispense('column');
$update->id = BeanLoader::LoadColumn($update, $request->getBody())
? $column->id
: 0;
if ($column->id === 0 || (int)$column->id !== (int)$update->id) {
$this->logger->addError('Update Column: ', [$column, $update]);
$this->apiJson->addAlert('error', 'Error updating column ' .
$update->name . '. Please try again.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($column->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
R::store($update);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' updated column ' . $update->name,
json_encode($column), json_encode($update),
'column', $update->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Column ' .
$update->name . ' updated.');
$this->apiJson->addData(R::exportAll($update));
return $this->jsonResponse($response);
}
public function removeColumn($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::BOARD_ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$id = (int)$args['id'];
$column = R::load('column', $id);
if ((int)$column->id !== $id) {
$this->logger->addError('Remove Column: ', [$column]);
$this->apiJson->addAlert('error', 'Error removing column. ' .
'No column found for ID ' . $id . '.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($column->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
$before = $column;
R::trash($column);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' removed column ' . $before->name,
json_encode($before), '', 'column', $id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'Column ' . $before->name . ' removed.');
return $this->jsonResponse($response);
}
}

View File

@ -3,190 +3,199 @@ use RedBeanPHP\R;
class Comments extends BaseController {
public function getComment($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
public function getComment($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$comment = R::load('comment', (int)$args['id']);
$comment = R::load('comment', (int)$args['id']);
if ($comment->id === 0) {
$this->logger->addError('Attempt to load comment ' .
$args['id'] . ' failed.');
$this->apiJson->addAlert('error', 'No comment found for ID ' .
$args['id'] . '.');
if ($comment->id === 0) {
$this->logger->addError('Attempt to load comment ' .
$args['id'] . ' failed.');
$this->apiJson->addAlert('error', 'No comment found for ID ' .
$args['id'] . '.');
return $this->jsonResponse($response);
}
return $this->jsonResponse($response);
}
$task = R::load('task', $comment->task_id);
$column = R::load('column', $task->column_id);
$task = R::load('task', $comment->task_id);
$column = R::load('column', $task->column_id);
if (!$this->checkBoardAccess($column->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
if (!$this->checkBoardAccess($column->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
$this->apiJson->setSuccess();
$this->apiJson->addData($comment);
$this->apiJson->setSuccess();
$this->apiJson->addData($comment);
return $this->jsonResponse($response);
}
public function addComment($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$comment = R::dispense('comment');
if (!BeanLoader::LoadComment($comment, $request->getBody())) {
$comment->task_id = 0;
}
$task = R::load('task', $comment->task_id);
if ($task->id === 0) {
$this->logger->addError('Add Comment: ', [$comment]);
$this->apiJson->addAlert('error', 'Error adding comment. ' .
'Please try again.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($this->getBoardId($task->id), $request)) {
return $this->jsonResponse($response, 403);
}
R::store($comment);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' added comment ' . $comment->id . '.',
'', json_encode($comment), 'comment', $comment->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Comment added.');
return $this->jsonResponse($response);
}
public function updateComment($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$data = json_decode($request->getBody());
if (is_null($args) || !$args['id']) {
$this->logger->addError('Update Comment: ', [$data]);
$this->apiJson->addAlert('error', 'Error updating comment. ' .
'Please try again.');
return $this->jsonResponse($response);
}
$actor = R::load('user', Auth::GetUserId($request));
$comment = R::load('comment', (int)$args['id']);
// If User level, only the user that created the comment
// may update it. If higher level, update is allowed.
if ((int)$actor->security_level === SecurityLevel::USER) {
if ($actor->id !== $comment->user_id) {
$this->apiJson->addAlert('error',
'You do not have sufficient permissions ' .
'to update this comment.');
return $this->jsonResponse($response);
}
} // @codeCoverageIgnore
$update = R::dispense('comment');
$update->id = BeanLoader::LoadComment($update, json_encode($data))
? $comment->id
: 0;
if ($comment->id === 0 || ((int)$comment->id !== (int)$update->id)) {
$this->logger->addError('Update Comment: ', [$comment]);
$this->apiJson->addAlert('error', 'Error updating comment. ' .
'Please try again.');
return $this->jsonResponse($response);
}
public function addComment($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
if (!$this->checkBoardAccess(
$this->getBoardId($comment->task_id), $request)) {
return $this->jsonResponse($response, 403);
}
$comment = R::dispense('comment');
if (!BeanLoader::LoadComment($comment, $request->getBody())) {
$comment->task_id = 0;
}
R::store($update);
$task = R::load('task', $comment->task_id);
if ($task->id === 0) {
$this->logger->addError('Add Comment: ', [$comment]);
$this->apiJson->addAlert('error', 'Error adding comment. ' .
'Please try again.');
$this->dbLogger->logChange($actor->id,
$actor->username . ' updated comment ' . $update->id,
json_encode($comment), json_encode($update),
'comment', $update->id);
return $this->jsonResponse($response);
}
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Comment updated.');
if (!$this->checkBoardAccess($this->getBoardId($task->id), $request)) {
return $this->jsonResponse($response, 403);
}
$task = R::load('task', $comment->task_id);
$this->apiJson->addData(R::exportAll($task));
R::store($comment);
return $this->jsonResponse($response);
}
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' added comment ' . $comment->id . '.',
'', json_encode($comment), 'comment', $comment->id);
public function removeComment($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Comment added.');
$actor = R::load('user', Auth::GetUserId($request));
$id = (int)$args['id'];
$comment = R::load('comment', $id);
// If User level, only the user that created the comment
// may delete it. If higher level, delete is allowed.
if ((int)$actor->security_level === SecurityLevel::USER) {
if ($actor->id !== $comment->user_id) {
$this->apiJson->addAlert('error',
'You do not have sufficient permissions ' .
'to remove this comment.');
return $this->jsonResponse($response);
}
} // @codeCoverageIgnore
if ((int)$comment->id !== $id) {
$this->logger->addError('Remove Comment: ', [$comment]);
$this->apiJson->addAlert('error', 'Error removing comment. ' .
'No comment found for ID ' . $id . '.');
return $this->jsonResponse($response);
}
public function updateComment($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$actor = R::load('user', Auth::GetUserId($request));
$comment = R::load('comment', (int)$args['id']);
// If User level, only the user that created the comment
// may update it. If higher level, update is allowed.
if ((int)$actor->security_level === SecurityLevel::USER) {
if ($actor->id !== $comment->user_id) {
$this->apiJson->addAlert('error',
'You do not have sufficient permissions ' .
'to update this comment.');
return $this->jsonResponse($response);
}
} // @codeCoverageIgnore
$data = json_decode($request->getBody());
$update = R::dispense('comment');
$update->id = BeanLoader::LoadComment($update, json_encode($data))
? $comment->id
: 0;
if ($comment->id === 0 || ((int)$comment->id !== (int)$update->id)) {
$this->logger->addError('Update Comment: ', [$comment]);
$this->apiJson->addAlert('error', 'Error updating comment. ' .
'Please try again.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess(
$this->getBoardId($comment->task_id), $request)) {
return $this->jsonResponse($response, 403);
}
R::store($update);
$this->dbLogger->logChange($actor->id,
$actor->username . ' updated comment ' . $update->id,
json_encode($comment), json_encode($update),
'comment', $update->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Comment updated.');
$task = R::load('task', $comment->task_id);
$this->apiJson->addData(R::exportAll($task));
return $this->jsonResponse($response);
if (!$this->checkBoardAccess(
$this->getBoardId($comment->task_id), $request)) {
return $this->jsonResponse($response, 403);
}
public function removeComment($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$before = $comment;
R::trash($comment);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' removed comment ' . $before->id,
json_encode($before), '', 'comment', $id);
$id = (int)$args['id'];
$comment = R::load('comment', $id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Comment removed.');
// If User level, only the user that created the comment
// may delete it. If higher level, delete is allowed.
if ((int)$actor->security_level === SecurityLevel::USER) {
if ($actor->id !== $comment->user_id) {
$this->apiJson->addAlert('error',
'You do not have sufficient permissions ' .
'to remove this comment.');
$task = R::load('task', $comment->task_id);
$this->apiJson->addData(R::exportAll($task));
return $this->jsonResponse($response);
}
} // @codeCoverageIgnore
return $this->jsonResponse($response);
}
if ((int)$comment->id !== $id) {
$this->logger->addError('Remove Comment: ', [$comment]);
$this->apiJson->addAlert('error', 'Error removing comment. ' .
'No comment found for ID ' . $id . '.');
private function getBoardId($taskId) {
$task = R::load('task', $taskId);
$column = R::load('column', $task->column_id);
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess(
$this->getBoardId($comment->task_id), $request)) {
return $this->jsonResponse($response, 403);
}
$before = $comment;
R::trash($comment);
$this->dbLogger->logChange($actor->id,
$actor->username . ' removed comment ' . $before->id,
json_encode($before), '', 'comment', $id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Comment removed.');
$task = R::load('task', $comment->task_id);
$this->apiJson->addData(R::exportAll($task));
return $this->jsonResponse($response);
}
private function getBoardId($taskId) {
$task = R::load('task', $taskId);
$column = R::load('column', $task->column_id);
return $column->board_id;
}
return $column->board_id;
}
}

View File

@ -1,22 +1,22 @@
<?php
class Invalid extends BaseController {
public function noApi($request, $response) {
$request; // Not used, but required for Slim Framework
$this->apiJson->addAlert('error',
'No API functionality at this endpoint.');
public function noApi($request, $response) {
$request; // Not used, but required for Slim Framework
$this->apiJson->addAlert('error',
'No API functionality at this endpoint.');
$apiReturn = new stdClass();
$apiReturn->status = 'One of "success" or "failure".';
$apiReturn->data = 'An array of data (JSON objects and/or arrays). ' .
'The first object is a new JWT for the next request.';
$apiReturn->alerts = 'An array of alerts, with "type" of "success", ' .
'"error", "warn", or "info" and a "text" message.';
$apiReturn = new stdClass();
$apiReturn->status = 'One of "success" or "failure".';
$apiReturn->data = 'An array of data (JSON objects and/or arrays). ' .
'The first object is a new JWT for the next request.';
$apiReturn->alerts = 'An array of alerts, with "type" of "success", ' .
'"error", "warn", or "info" and a "text" message.';
$this->apiJson->addData($apiReturn);
$this->apiJson->addData($apiReturn);
return $this->jsonResponse($response);
}
return $this->jsonResponse($response);
}
}

View File

@ -3,370 +3,384 @@ use RedBeanPHP\R;
class Tasks extends BaseController {
public function getTask($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$task = R::load('task', (int)$args['id']);
if ((int)$task->id === 0) {
$this->logger->addError('Attemt to load task ' .
$args['id'] . ' failed.');
$this->apiJson->addAlert('error', 'No task found for ID ' .
$args['id'] . '.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess(
$this->getBoardId($task->column_id), $request)) {
return $this->jsonResponse($response, 403);
}
$this->apiJson->setSuccess();
$this->apiJson->addData($task);
return $this->jsonResponse($response);
public function getTask($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
public function addTask($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$task = R::load('task', (int)$args['id']);
$task = R::dispense('task');
BeanLoader::LoadTask($task, $request->getBody());
if ((int)$task->id === 0) {
$this->logger->addError('Attemt to load task ' .
$args['id'] . ' failed.');
$this->apiJson->addAlert('error', 'No task found for ID ' .
$args['id'] . '.');
$column = R::load('column', $task->column_id);
if ((int)$column->id === 0) {
$this->logger->addError('Add Task: ', [$task]);
$this->apiJson->addAlert('error', 'Error adding task. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess($column->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
R::store($task);
$actor = R::load('user', Auth::GetUserId($request));
$this->updateTaskOrder($task, $actor, true);
$this->checkAutomaticActions(null, $task);
$this->dbLogger->logChange($actor->id,
$actor->username . ' added task ' . $task->title . '.',
'', json_encode($task), 'task', $task->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Task ' .
$task->title . ' added.');
$this->apiJson->addData(R::exportAll($task));
$board = R::load('board', $column->board_id);
$this->apiJson->addData(R::exportAll($board));
return $this->jsonResponse($response);
return $this->jsonResponse($response);
}
public function updateTask($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$task = R::load('task', (int)$args['id']);
$update = R::load('task', (int)$args['id']);
$update->id = BeanLoader::LoadTask($update, $request->getBody())
? $task->id
: 0;
if ($task->id === 0 || ((int)$task->id !== (int)$update->id)) {
$this->logger->addError('Update Task: ', [$task, $update]);
$this->apiJson->addAlert('error', 'Error updating task ' .
$task->title . '. Please try again.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess(
$this->getBoardId($task->column_id), $request)) {
return $this->jsonResponse($response, 403);
}
$before = R::exportAll($task);
R::store($update);
$after= R::exportAll($update);
$actor = R::load('user', Auth::GetUserId($request));
$this->updateTaskOrder($update, $actor, false);
$this->checkAutomaticActions($before, $after);
$update = R::load('task', $update->id);
$this->dbLogger->logChange($actor->id,
$actor->username . ' updated task ' . $task->title,
json_encode($task), json_encode($update),
'task', $update->id);
$boardId = $this->getBoardId($task->column_id);
$board = R::load('board', $boardId);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Task ' .
$update->title . ' updated.');
$this->apiJson->addData(R::exportAll($update));
$this->apiJson->addData(R::exportAll($board));
return $this->jsonResponse($response);
if (!$this->checkBoardAccess(
$this->getBoardId($task->column_id), $request)) {
return $this->jsonResponse($response, 403);
}
public function removeTask($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$this->apiJson->setSuccess();
$this->apiJson->addData($task);
$id = (int)$args['id'];
$task = R::load('task', $id);
return $this->jsonResponse($response);
}
if ((int)$task->id !== $id || (int)$task->id === 0) {
$this->logger->addError('Remove Task: ', [$task]);
$this->apiJson->addAlert('error', 'Error removing task. ' .
'No task found for ID ' . $id . '.');
return $this->jsonResponse($response);
}
$boardId = $this->getBoardId($task->column_id);
if (!$this->checkBoardAccess($boardId, $request)) {
return $this->jsonResponse($response, 403);
}
$before = $task;
R::trash($task);
$actor = R::load('user', Auth::GetUserId($request));
$this->updateTaskOrder($task, $actor, false);
$this->dbLogger->logChange($actor->id,
$actor->username . ' removed task ' . $before->title,
json_encode($before), '', 'task', $id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'Task ' . $before->title . ' removed.');
$board = R::load('board', $boardId);
$this->apiJson->addData(R::exportAll($board));
return $this->jsonResponse($response);
public function addTask($request, $response) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
private function getBoardId($columnId) {
$column = R::load('column', $columnId);
$task = R::dispense('task');
BeanLoader::LoadTask($task, $request->getBody());
return $column->board_id;
$column = R::load('column', $task->column_id);
if ((int)$column->id === 0) {
$this->logger->addError('Add Task: ', [$task]);
$this->apiJson->addAlert('error', 'Error adding task. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
private function sortTasks($a, $b) {
return strcmp($a->position, $b->position);
if (!$this->checkBoardAccess($column->board_id, $request)) {
return $this->jsonResponse($response, 403);
}
private function updateTaskOrder($task, $user, $isNew) {
$column = R::load('column', $task->column_id);
$user_opts = R::load('useroption', $user->user_option_id);
R::store($task);
usort($column->xownTaskList, array($this, 'sortTasks'));
$actor = R::load('user', Auth::GetUserId($request));
$this->updateTaskOrder($task, $actor, true);
$this->checkAutomaticActions(null, $task);
$counter = 1;
foreach ($column->xownTaskList as $task) {
$task->position = $counter;
$counter++;
$this->dbLogger->logChange($actor->id,
$actor->username . ' added task ' . $task->title . '.',
'', json_encode($task), 'task', $task->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Task ' .
$task->title . ' added.');
$this->apiJson->addData(R::exportAll($task));
$board = R::load('board', $column->board_id);
$this->apiJson->addData(R::exportAll($board));
return $this->jsonResponse($response);
}
public function updateTask($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$data = json_decode($request->getBody());
if (is_null($args) || !array_key_exists('id', $args)) {
$this->logger->addError('Update Task: ', [$data]);
$this->apiJson->addAlert('error', 'Error updating task. Please try again.');
return $this->jsonResponse($response);
}
$task = R::load('task', (int)$args['id']);
$update = R::load('task', (int)$args['id']);
$update->id = BeanLoader::LoadTask($update, $request->getBody())
? $task->id
: 0;
if ($task->id === 0 || ((int)$task->id !== (int)$update->id)) {
$this->logger->addError('Update Task: ', [$task, $update]);
$this->apiJson->addAlert('error', 'Error updating task ' .
$task->title . '. Please try again.');
return $this->jsonResponse($response);
}
if (!$this->checkBoardAccess(
$this->getBoardId($task->column_id), $request)) {
return $this->jsonResponse($response, 403);
}
$before = R::exportAll($task);
R::store($update);
$after= R::exportAll($update);
$actor = R::load('user', Auth::GetUserId($request));
$this->updateTaskOrder($update, $actor, false);
$this->checkAutomaticActions($before, $after);
$update = R::load('task', $update->id);
$this->dbLogger->logChange($actor->id,
$actor->username . ' updated task ' . $task->title,
json_encode($task), json_encode($update),
'task', $update->id);
$boardId = $this->getBoardId($task->column_id);
$board = R::load('board', $boardId);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'Task ' .
$update->title . ' updated.');
$this->apiJson->addData(R::exportAll($update));
$this->apiJson->addData(R::exportAll($board));
return $this->jsonResponse($response);
}
public function removeTask($request, $response, $args) {
$status = $this->secureRoute($request, $response,
SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$id = (int)$args['id'];
$task = R::load('task', $id);
if ((int)$task->id !== $id || (int)$task->id === 0) {
$this->logger->addError('Remove Task: ', [$task]);
$this->apiJson->addAlert('error', 'Error removing task. ' .
'No task found for ID ' . $id . '.');
return $this->jsonResponse($response);
}
$boardId = $this->getBoardId($task->column_id);
if (!$this->checkBoardAccess($boardId, $request)) {
return $this->jsonResponse($response, 403);
}
$before = $task;
R::trash($task);
$actor = R::load('user', Auth::GetUserId($request));
$this->updateTaskOrder($task, $actor, false);
$this->dbLogger->logChange($actor->id,
$actor->username . ' removed task ' . $before->title,
json_encode($before), '', 'task', $id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'Task ' . $before->title . ' removed.');
$board = R::load('board', $boardId);
$this->apiJson->addData(R::exportAll($board));
return $this->jsonResponse($response);
}
private function getBoardId($columnId) {
$column = R::load('column', $columnId);
return $column->board_id;
}
private function sortTasks($a, $b) {
return strcmp($a->position, $b->position);
}
private function updateTaskOrder($task, $user, $isNew) {
$column = R::load('column', $task->column_id);
$user_opts = R::load('useroption', $user->user_option_id);
usort($column->xownTaskList, array($this, 'sortTasks'));
$counter = 1;
foreach ($column->xownTaskList as $task) {
$task->position = $counter;
$counter++;
}
R::store($column);
if (!$isNew || $user_opts->new_tasks_at_bottom) {
return;
}
$lastTask = end($column->xownTaskList);
$lastTask->position = 0;
R::store($column);
}
private function checkAutomaticActions($before, $after) {
$boardId = $this->getBoardId(
is_array($after) ? $after[0]['column_id'] : $after['column_id']
);
$autoActions = R::find('autoaction', ' board_id = ? ', [ $boardId ]);
foreach ($autoActions as $action) {
switch ($action->trigger) {
case ActionTrigger::MOVED_TO_COLUMN():
if ($before[0]['column_id'] !== $after[0]['column_id'] &&
$after[0]['column_id'] === (int)$action->source_id) {
$this->alterTask($action, $after[0]['id']);
}
break;
case ActionTrigger::ASSIGNED_TO_USER():
$prevAssigned = $this->isInList($action->source_id,
isset($before[0]['sharedUser']) ?
$before[0]['sharedUser'] :
[]);
if ($prevAssigned) {
break;
}
R::store($column);
foreach ($after[0]['sharedUser'] as $user) {
if ((int)$action->source_id === (int)$user['id']) {
$this->alterTask($action, $after[0]['id']);
}
}
break;
if (!$isNew || $user_opts->new_tasks_at_bottom) {
return;
case ActionTrigger::ADDED_TO_CATEGORY():
$prevAssigned = $this->isInList($action->source_id,
isset($before[0]['sharedCategory']) ?
$before[0]['sharedCategory'] :
[]);
if ($prevAssigned) {
break;
}
$lastTask = end($column->xownTaskList);
$lastTask->position = 0;
R::store($column);
}
private function checkAutomaticActions($before, $after) {
$boardId = $this->getBoardId($after[0]['column_id']);
$autoActions = R::find('autoaction', ' board_id = ? ', [ $boardId ]);
foreach ($autoActions as $action) {
switch ($action->trigger) {
case ActionTrigger::MOVED_TO_COLUMN():
if ($before[0]['column_id'] !== $after[0]['column_id'] &&
$after[0]['column_id'] === (int)$action->source_id) {
$this->alterTask($action, $after[0]['id']);
}
break;
case ActionTrigger::ASSIGNED_TO_USER():
$prevAssigned = $this->isInList($action->source_id,
isset($before[0]['sharedUser']) ?
$before[0]['sharedUser'] :
[]);
if ($prevAssigned) {
break;
}
foreach ($after[0]['sharedUser'] as $user) {
if ((int)$action->source_id === (int)$user['id']) {
$this->alterTask($action, $after[0]['id']);
}
}
break;
case ActionTrigger::ADDED_TO_CATEGORY():
$prevAssigned = $this->isInList($action->source_id,
isset($before[0]['sharedCategory']) ?
$before[0]['sharedCategory'] :
[]);
if ($prevAssigned) {
break;
}
foreach ($after[0]['sharedCategory'] as $category) {
if ((int)$action->source_id === (int)$category['id']) {
$this->alterTask($action, $after[0]['id']);
}
}
break;
case ActionTrigger::POINTS_CHANGED():
$points = (isset($before[0]['points'])) ?
(int)$before[0]['points'] :
0;
if ($points !== (int)$after[0]['points']) {
$this->updateTaskColor($after[0]['id'],
$points,
$after[0]['points']);
}
break;
}
foreach ($after[0]['sharedCategory'] as $category) {
if ((int)$action->source_id === (int)$category['id']) {
$this->alterTask($action, $after[0]['id']);
}
}
}
break;
private function isInList($itemId, $list) {
foreach ($list as $item) {
if ((int)$item['id'] === (int)$itemId) {
return true;
}
case ActionTrigger::POINTS_CHANGED():
$points = (isset($before[0]['points'])) ?
(int)$before[0]['points'] :
0;
if ($points !== (int)$after[0]['points']) {
$this->updateTaskColor($after[0]['id'],
$points,
$after[0]['points']);
}
break;
return false;
}
}
}
private function isInList($itemId, $list) {
foreach ($list as $item) {
if ((int)$item['id'] === (int)$itemId) {
return true;
}
}
private function alterTask($action, $taskId) {
switch ($action->type) {
case ActionType::SET_COLOR():
$task = R::load('task', $taskId);
$task->color = $action->change_to;
$this->apiJson->addAlert('info',
'Task color changed by automatic action.');
R::store($task);
break;
return false;
}
case ActionType::SET_CATEGORY():
$task = R::load('task', $taskId);
unset($task->sharedCategoryList);
case ActionType::ADD_CATEGORY():
if (!isset($task)) {
$task = R::load('task', $taskId);
}
private function alterTask($action, $taskId) {
switch ($action->type) {
case ActionType::SET_COLOR():
$task = R::load('task', $taskId);
$task->color = $action->change_to;
$this->apiJson->addAlert('info',
'Task color changed by automatic action.');
R::store($task);
break;
$cat = R::load('category', $action->change_to);
$task->sharedCategoryList[] = $cat;
$this->apiJson->addAlert('info',
'Task categories changed by automatic action.');
R::store($task);
break;
case ActionType::SET_ASSIGNEE():
$task = R::load('task', $taskId);
unset($task->sharedUserList);
case ActionType::ADD_ASSIGNEE():
if (!isset($task)) {
$task = R::load('task', $taskId);
}
$user = R::load('user', $action->change_to);
$task->sharedUserList[] = $user;
$this->apiJson->addAlert('info',
'Task assignees changed by automatic action.');
R::store($task);
break;
case ActionType::CLEAR_DUE_DATE():
$task = R::load('task', $taskId);
if ($task->due_date === '') {
break;
}
$task->due_date = '';
$this->apiJson->addAlert('info',
'Task due date cleared by automatic action.');
R::store($task);
break;
}
}
private function updateTaskColor($taskId, $beforePoints, $afterPoints) {
case ActionType::SET_CATEGORY():
$task = R::load('task', $taskId);
unset($task->sharedCategoryList);
case ActionType::ADD_CATEGORY():
if (!isset($task)) {
$task = R::load('task', $taskId);
$diff = (float)$beforePoints - (float)$afterPoints;
}
// Steps should be between -255 and 255.
// Negative = darker, positive = lighter
$steps = max(-255, min(255, $diff * 10));
$cat = R::load('category', $action->change_to);
$task->sharedCategoryList[] = $cat;
$this->apiJson->addAlert('info',
'Task categories changed by automatic action.');
R::store($task);
break;
// Normalize into a six character long hex string
$hex = $task->color;
$hex = str_replace('#', '', $hex);
if (strlen($hex) == 3) {
$hex = str_repeat(substr($hex, 0, 1), 2).
str_repeat(substr($hex, 1, 1), 2).
str_repeat(substr($hex, 2, 1), 2);
}
case ActionType::SET_ASSIGNEE():
$task = R::load('task', $taskId);
unset($task->sharedUserList);
case ActionType::ADD_ASSIGNEE():
if (!isset($task)) {
$task = R::load('task', $taskId);
}
// Split into three parts: R, G and B
$colorParts = str_split($hex, 2);
$newColor = '#';
$user = R::load('user', $action->change_to);
$task->sharedUserList[] = $user;
$this->apiJson->addAlert('info',
'Task assignees changed by automatic action.');
R::store($task);
break;
foreach ($colorParts as $color) {
// Convert to decimal
$color = hexdec($color);
// Adjust color
$color = max(0, min(255, $color + $steps));
// Make two char hex code
$newColor .= str_pad(dechex($color), 2, '0', STR_PAD_LEFT);
}
case ActionType::CLEAR_DUE_DATE():
$task = R::load('task', $taskId);
$task->color = $newColor;
if ($task->due_date === '') {
break;
}
$this->apiJson->addAlert('info',
'Task color changed by automatic action.');
R::store($task);
$task->due_date = '';
$this->apiJson->addAlert('info',
'Task due date cleared by automatic action.');
R::store($task);
break;
}
}
private function updateTaskColor($taskId, $beforePoints, $afterPoints) {
$task = R::load('task', $taskId);
$diff = (float)$beforePoints - (float)$afterPoints;
// Steps should be between -255 and 255.
// Negative = darker, positive = lighter
$steps = max(-255, min(255, $diff * 10));
// Normalize into a six character long hex string
$hex = $task->color;
$hex = str_replace('#', '', $hex);
if (strlen($hex) == 3) {
$hex = str_repeat(substr($hex, 0, 1), 2).
str_repeat(substr($hex, 1, 1), 2).
str_repeat(substr($hex, 2, 1), 2);
}
// Split into three parts: R, G and B
$colorParts = str_split($hex, 2);
$newColor = '#';
foreach ($colorParts as $color) {
// Convert to decimal
$color = hexdec($color);
// Adjust color
$color = max(0, min(255, $color + $steps));
// Make two char hex code
$newColor .= str_pad(dechex($color), 2, '0', STR_PAD_LEFT);
}
$task->color = $newColor;
$this->apiJson->addAlert('info',
'Task color changed by automatic action.');
R::store($task);
}
}

View File

@ -3,482 +3,482 @@ use RedBeanPHP\R;
class Users extends BaseController {
public function getAllUsers($request, $response) {
$status = $this->secureRoute($request, $response, SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
public function getAllUsers($request, $response) {
$status = $this->secureRoute($request, $response, SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$this->apiJson->setSuccess();
$data = $this->getAllUsersCleaned($request);
$this->apiJson->addData($data);
$this->apiJson->setSuccess();
$data = $this->getAllUsersCleaned($request);
$this->apiJson->addData($data);
return $this->jsonResponse($response);
}
public function getUser($request, $response, $args) {
$status = $this->secureRoute($request, $response, SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$id = (int)$args['id'];
$userIds = $this->getUserIdsByBoardAccess(Auth::GetUserId($request));
$user = R::load('user', $id);
if ($user->id === 0) {
$this->logger->addError('Attempt to load user ' . $id .
' failed.');
$this->apiJson->addAlert('error', 'No user found for ID ' .
$id . '.');
return $this->jsonResponse($response);
}
if (!in_array($id, $userIds)) {
$this->apiJson->addAlert('error', 'Access restricted.');
return $this->jsonResponse($response, 403);
}
$this->apiJson->setSuccess();
$this->apiJson->addData($this->cleanUser($user));
return $this->jsonResponse($response);
}
public function addUser($request, $response) {
$status = $this->secureRoute($request, $response, SecurityLevel::ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$data = json_decode($request->getBody());
$user = R::dispense('user');
if (isset($data->username)) {
if ($this->checkUsernameExists($data)) {
return $this->jsonResponse($response);
}
}
public function getUser($request, $response, $args) {
$status = $this->secureRoute($request, $response, SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
if (isset($data->password) &&
$data->password === $data->password_verify) {
$data->password_hash =
password_hash($data->password, PASSWORD_BCRYPT);
unset($data->password);
unset($data->password_verify);
}
$id = (int)$args['id'];
if (!BeanLoader::LoadUser($user, json_encode($data))) {
$user->id = -1;
}
$userIds = $this->getUserIdsByBoardAccess(Auth::GetUserId($request));
$user = R::load('user', $id);
if ($user->id === -1) {
$this->logger->addError('Add User: ', [$user]);
$this->apiJson->addAlert('error', 'Error adding user. ' .
'Please check your entries and try again.');
if ($user->id === 0) {
$this->logger->addError('Attempt to load user ' . $id .
' failed.');
$this->apiJson->addAlert('error', 'No user found for ID ' .
$id . '.');
return $this->jsonResponse($response);
}
return $this->jsonResponse($response);
}
$opts = R::dispense('useroption');
$opts->new_tasks_at_bottom = true;
$opts->show_animations = true;
$opts->show_assignee = true;
$opts->multiple_tasks_per_row = false;
$opts->language = 'en';
R::store($opts);
if (!in_array($id, $userIds)) {
$this->apiJson->addAlert('error', 'Access restricted.');
$user->user_option_id = $opts->id;
R::store($user);
return $this->jsonResponse($response, 403);
}
if (isset($data->default_board_id)) {
$data->boardAccess[] = $data->default_board_id;
}
$this->apiJson->setSuccess();
$this->apiJson->addData($this->cleanUser($user));
$data->id = $user->id;
$this->updateBoardAccess($data, $request);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' added user ' . $user->username . '.',
'', json_encode($user), 'user', $user->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'User ' . $user->username . ' added.');
$this->apiJson->addData($this->getAllUsersCleaned($request));
return $this->jsonResponse($response);
}
public function updateUser($request, $response, $args) {
$status = $this->secureRoute($request, $response, SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$data = json_decode($request->getBody());
$user = R::load('user', (int)$args['id']);
if (!property_exists($data, 'id')) {
$this->logger->addError('Update User: ', [$user, $data]);
$this->apiJson->addAlert('error', 'Error updating user. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
$update = R::load('user', $data->id);
$actor = R::load('user', Auth::GetUserId($request));
if (!$this->checkUserAccess($actor, $user)) {
return $this->jsonResponse($response, 403);
}
$data->password_hash = $user->password_hash;
if (isset($data->new_password) && isset($data->old_password)) {
if (!$this->verifyPassword($data, $user)) {
$this->logger->addError('Update User: ', [$user, $update]);
return $this->jsonResponse($response);
}
$data->password_hash =
password_hash($data->new_password, PASSWORD_BCRYPT);
unset($data->new_password);
unset($data->old_password);
}
public function addUser($request, $response) {
$status = $this->secureRoute($request, $response, SecurityLevel::ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$data->active_token = $user->active_token;
$data = json_decode($request->getBody());
$user = R::dispense('user');
if (isset($data->password) && $data->password !== '') {
$data->password_hash =
password_hash($data->password, PASSWORD_BCRYPT);
unset($data->password);
}
if (isset($data->username)) {
if ($this->checkUsernameExists($data)) {
return $this->jsonResponse($response);
}
}
BeanLoader::LoadUser($update, json_encode($data));
if (isset($data->password) &&
$data->password === $data->password_verify) {
$data->password_hash =
password_hash($data->password, PASSWORD_BCRYPT);
unset($data->password);
unset($data->password_verify);
}
if ((int)$user->id !== (int)$update->id) {
$this->logger->addError('Update User: ', [$user, $update]);
$this->apiJson->addAlert('error', 'Error updating user. ' .
'Please check your entries and try again.');
if (!BeanLoader::LoadUser($user, json_encode($data))) {
$user->id = -1;
}
if ($user->id === -1) {
$this->logger->addError('Add User: ', [$user]);
$this->apiJson->addAlert('error', 'Error adding user. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
$opts = R::dispense('useroption');
$opts->new_tasks_at_bottom = true;
$opts->show_animations = true;
$opts->show_assignee = true;
$opts->multiple_tasks_per_row = false;
$opts->language = 'en';
R::store($opts);
$user->user_option_id = $opts->id;
R::store($user);
if (isset($data->default_board_id)) {
$data->boardAccess[] = $data->default_board_id;
}
$data->id = $user->id;
$this->updateBoardAccess($data, $request);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' added user ' . $user->username . '.',
'', json_encode($user), 'user', $user->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'User ' . $user->username . ' added.');
$this->apiJson->addData($this->getAllUsersCleaned($request));
return $this->jsonResponse($response);
}
if ($user->username !== $update->username) {
if ($this->checkUsernameExists($update)) {
return $this->jsonResponse($response);
}
}
public function updateUser($request, $response, $args) {
$status = $this->secureRoute($request, $response, SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$this->updateDefaultBoardId($data, $user, $update);
$data = json_decode($request->getBody());
$user = R::load('user', (int)$args['id']);
$this->updateBoardAccess($data, $request);
R::store($update);
if (!property_exists($data, 'id')) {
$this->logger->addError('Update User: ', [$user, $data]);
$this->apiJson->addAlert('error', 'Error updating user. ' .
'Please check your entries and try again.');
$this->dbLogger->logChange($actor->id,
$actor->username . ' updated user ' . $update->username,
json_encode($user), json_encode($update),
'user', $update->id);
return $this->jsonResponse($response);
}
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'User ' . $update->username . ' updated.');
$this->apiJson->addData(json_encode($this->cleanUser($update)));
$update = R::load('user', $data->id);
$actor = R::load('user', Auth::GetUserId($request));
return $this->jsonResponse($response);
}
if (!$this->checkUserAccess($actor, $user)) {
return $this->jsonResponse($response, 403);
}
$data->password_hash = $user->password_hash;
if (isset($data->new_password) && isset($data->old_password)) {
if (!$this->verifyPassword($data, $user)) {
$this->logger->addError('Update User: ', [$user, $update]);
return $this->jsonResponse($response);
}
$data->password_hash =
password_hash($data->new_password, PASSWORD_BCRYPT);
unset($data->new_password);
unset($data->old_password);
}
$data->active_token = $user->active_token;
if (isset($data->password) && $data->password !== '') {
$data->password_hash =
password_hash($data->password, PASSWORD_BCRYPT);
unset($data->password);
}
BeanLoader::LoadUser($update, json_encode($data));
if ((int)$user->id !== (int)$update->id) {
$this->logger->addError('Update User: ', [$user, $update]);
$this->apiJson->addAlert('error', 'Error updating user. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
if ($user->username !== $update->username) {
if ($this->checkUsernameExists($update)) {
return $this->jsonResponse($response);
}
}
$this->updateDefaultBoardId($data, $user, $update);
$this->updateBoardAccess($data, $request);
R::store($update);
$this->dbLogger->logChange($actor->id,
$actor->username . ' updated user ' . $update->username,
json_encode($user), json_encode($update),
'user', $update->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'User ' . $update->username . ' updated.');
$this->apiJson->addData(json_encode($this->cleanUser($update)));
return $this->jsonResponse($response);
public function updateUserOptions($request, $response, $args) {
$status = $this->secureRoute($request, $response, SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
public function updateUserOptions($request, $response, $args) {
$status = $this->secureRoute($request, $response, SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$user = R::load('user', (int)$args['id']);
$actor = R::load('user', Auth::GetUserId($request));
$user = R::load('user', (int)$args['id']);
$actor = R::load('user', Auth::GetUserId($request));
if ($actor->id !== $user->id) {
$this->apiJson->addAlert('error', 'Access restricted.');
if ($actor->id !== $user->id) {
$this->apiJson->addAlert('error', 'Access restricted.');
return $this->jsonResponse($response, 403);
}
$data = $request->getBody();
$userOpts = R::load('useroption', $user->user_option_id);
$update = R::load('useroption', json_decode($data)->id);
if (!BeanLoader::LoadUserOption($update, $data)) {
$update->id = -1;
}
if ($userOpts->id !== $update->id) {
$this->logger->addError('Update User Options: ',
[$userOpts, $update]);
$this->apiJson->addAlert('error', 'Error updating user options. ' .
'Please check your entries and try again.');
return $this->jsonResponse($response);
}
R::store($update);
$this->dbLogger->logChange($actor->id,
$actor->username . ' updated user options',
json_encode($userOpts), json_encode($update),
'user_option', $update->id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'User options updated.');
$this->apiJson->addData(json_encode($update));
$this->apiJson->addData(json_encode($this->cleanUser($user)));
return $this->jsonResponse($response);
return $this->jsonResponse($response, 403);
}
public function toggleCollapsed($request, $response, $args) {
$status = $this->secureRoute($request, $response, SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
$data = $request->getBody();
$user = R::load('user', (int)$args['id']);
$actor = R::load('user', Auth::GetUserId($request));
$userOpts = R::load('useroption', $user->user_option_id);
$update = R::load('useroption', json_decode($data)->id);
if ($actor->id !== $user->id) {
$this->apiJson->addAlert('error', 'Access restricted.');
return $this->jsonResponse($response, 403);
}
$data = json_decode($request->getBody());
$collapsed = R::findOne('collapsed', ' user_id = ? AND column_id = ? ',
[ $user->id, $data->id ]);
$makeNew = true;
if (!is_null($collapsed)) {
R::trash($collapsed);
$makeNew = false;
}
if ($makeNew) {
$collapsed = R::dispense('collapsed');
$collapsed->user_id = $user->id;
$collapsed->column_id = $data->id;
R::store($collapsed);
}
$allCollapsed = R::find('collapsed', ' user_id = ? ', [ $user->id ]);
$this->apiJson->setSuccess();
$this->apiJson->addData(R::exportAll($allCollapsed));
return $this->jsonResponse($response);
if (!BeanLoader::LoadUserOption($update, $data)) {
$update->id = -1;
}
public function removeUser($request, $response, $args) {
$status = $this->secureRoute($request, $response, SecurityLevel::ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
if ($userOpts->id !== $update->id) {
$this->logger->addError('Update User Options: ',
[$userOpts, $update]);
$this->apiJson->addAlert('error', 'Error updating user options. ' .
'Please check your entries and try again.');
$id = (int)$args['id'];
$user = R::load('user', $id);
if ((int)$user->id !== $id) {
$this->logger->addError('Remove User: ', [$user]);
$this->apiJson->addAlert('error', 'Error removing user. ' .
'No user found for ID ' . $id . '.');
return $this->jsonResponse($response);
}
$before = $user;
R::trash($user);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' removed user ' . $before->username,
json_encode($before), '', 'user', $id);
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'User ' . $before->username . ' removed.');
$this->apiJson->addData($this->getAllUsersCleaned($request));
return $this->jsonResponse($response);
return $this->jsonResponse($response);
}
private function updateBoardAccess(&$userData, $request) {
$boardIds = $this->getBoardIdsByAccess($userData->id);
R::store($update);
if (isset($userData->boardAccess)) {
$user = R::load('user', $userData->id);
$this->dbLogger->logChange($actor->id,
$actor->username . ' updated user options',
json_encode($userOpts), json_encode($update),
'user_option', $update->id);
foreach ($userData->boardAccess as $boardId) {
if (!in_array($boardId, $boardIds)) {
$this->addUserToBoard((int)$boardId, $user, $request);
}
}
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success', 'User options updated.');
$this->apiJson->addData(json_encode($update));
$this->apiJson->addData(json_encode($this->cleanUser($user)));
if (count(array_diff($userData->boardAccess, $boardIds))) {
foreach ($boardIds as $removeId) {
if (!in_array($removeId, $userData->boardAccess)) {
$this->removeUserFromBoard($removeId, $user);
}
}
}
return $this->jsonResponse($response);
}
R::store($user);
unset($userData->boardAccess);
}
public function toggleCollapsed($request, $response, $args) {
$status = $this->secureRoute($request, $response, SecurityLevel::USER);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
private function addUserToBoard($boardId, $user, $request) {
if ($boardId > 0 &&
!Auth::HasBoardAccess($request, $boardId, $user->id)) {
$board = R::load('board', $boardId);
$board->sharedUserList[] = $user;
R::store($board);
}
$user = R::load('user', (int)$args['id']);
$actor = R::load('user', Auth::GetUserId($request));
if ($actor->id !== $user->id) {
$this->apiJson->addAlert('error', 'Access restricted.');
return $this->jsonResponse($response, 403);
}
private function removeUserFromBoard($boardId, $user) {
if ($boardId > 0) {
$board = R::load('board', $boardId);
unset($board->sharedUserList[$user->id]);
R::store($board);
}
$data = json_decode($request->getBody());
$collapsed = R::findOne('collapsed', ' user_id = ? AND column_id = ? ',
[ $user->id, $data->id ]);
$makeNew = true;
if (!is_null($collapsed)) {
R::trash($collapsed);
$makeNew = false;
}
private function getAllUsersCleaned($request) {
$userBeans = R::findAll('user');
$userId = Auth::GetUserId($request);
if ($makeNew) {
$collapsed = R::dispense('collapsed');
$collapsed->user_id = $user->id;
$collapsed->column_id = $data->id;
$userIds = $this->getUserIdsByBoardAccess(Auth::GetUserId($request));
// If a user has no board access, they should still see themselves
if (count($userIds) === 0) {
$userIds[] = $userId;
}
$actor = R::load('user', $userId);
$isAdmin = ((int)$actor->security_level === SecurityLevel::ADMIN);
$data = [];
foreach ($userBeans as $user) {
if (in_array($user->id, $userIds) || $isAdmin) {
$data[] = $this->cleanUser($user);
}
}
return $data;
R::store($collapsed);
}
private function getBoardIdsByAccess($userId) {
$boardIds = [];
$allCollapsed = R::find('collapsed', ' user_id = ? ', [ $user->id ]);
$boards = R::getAll('SELECT board_id FROM board_user ' .
'WHERE user_id = :user_id',
[':user_id' => $userId]);
$this->apiJson->setSuccess();
$this->apiJson->addData(R::exportAll($allCollapsed));
foreach ($boards as $board) {
$boardIds[] = (int)$board['board_id'];
}
return $this->jsonResponse($response);
}
return $boardIds;
public function removeUser($request, $response, $args) {
$status = $this->secureRoute($request, $response, SecurityLevel::ADMIN);
if ($status !== 200) {
return $this->jsonResponse($response, $status);
}
private function getUserIdsByBoardAccess($userId) {
$userIds = [];
$boardIds = $this->getBoardIdsByAccess($userId);
$id = (int)$args['id'];
$user = R::load('user', $id);
foreach ($boardIds as $id) {
$board = R::load('board', $id);
if ((int)$user->id !== $id) {
$this->logger->addError('Remove User: ', [$user]);
$this->apiJson->addAlert('error', 'Error removing user. ' .
'No user found for ID ' . $id . '.');
foreach ($board->sharedUserList as $user) {
if (!in_array((int) $user->id, $userIds)) {
$userIds[] = (int) $user->id;
}
}
}
return $userIds;
return $this->jsonResponse($response);
}
private function cleanUser($user) {
unset($user->password_hash);
unset($user->active_token);
$before = $user;
R::trash($user);
$this->setBoardAccess($user);
$actor = R::load('user', Auth::GetUserId($request));
$this->dbLogger->logChange($actor->id,
$actor->username . ' removed user ' . $before->username,
json_encode($before), '', 'user', $id);
return $user;
$this->apiJson->setSuccess();
$this->apiJson->addAlert('success',
'User ' . $before->username . ' removed.');
$this->apiJson->addData($this->getAllUsersCleaned($request));
return $this->jsonResponse($response);
}
private function updateBoardAccess(&$userData, $request) {
$boardIds = $this->getBoardIdsByAccess($userData->id);
if (isset($userData->boardAccess)) {
$user = R::load('user', $userData->id);
foreach ($userData->boardAccess as $boardId) {
if (!in_array($boardId, $boardIds)) {
$this->addUserToBoard((int)$boardId, $user, $request);
}
}
if (count(array_diff($userData->boardAccess, $boardIds))) {
foreach ($boardIds as $removeId) {
if (!in_array($removeId, $userData->boardAccess)) {
$this->removeUserFromBoard($removeId, $user);
}
}
}
R::store($user);
unset($userData->boardAccess);
}
}
private function addUserToBoard($boardId, $user, $request) {
if ($boardId > 0 &&
!Auth::HasBoardAccess($request, $boardId, $user->id)) {
$board = R::load('board', $boardId);
$board->sharedUserList[] = $user;
R::store($board);
}
}
private function removeUserFromBoard($boardId, $user) {
if ($boardId > 0) {
$board = R::load('board', $boardId);
unset($board->sharedUserList[$user->id]);
R::store($board);
}
}
private function getAllUsersCleaned($request) {
$userBeans = R::findAll('user');
$userId = Auth::GetUserId($request);
$userIds = $this->getUserIdsByBoardAccess(Auth::GetUserId($request));
// If a user has no board access, they should still see themselves
if (count($userIds) === 0) {
$userIds[] = $userId;
}
private function setBoardAccess(&$user) {
$user->board_access = [];
$boards = RedBeanPHP\R::getAll('select bu.board_id, bu.user_id from ' .
'board_user bu join board b on b.id = bu.board_id');
$actor = R::load('user', $userId);
$isAdmin = ((int)$actor->security_level === SecurityLevel::ADMIN);
foreach ($boards as $item) {
if ((int)$user->id === (int)$item['user_id']) {
$user->board_access[] = (int)$item['board_id'];
}
}
$data = [];
foreach ($userBeans as $user) {
if (in_array($user->id, $userIds) || $isAdmin) {
$data[] = $this->cleanUser($user);
}
}
private function checkUsernameExists($data) {
$existing = R::findOne('user', 'username = ?', [ $data->username ]);
return $data;
}
if ($existing) {
$this->apiJson->addAlert('error', 'Username already exists. ' .
'Change the username and try again.');
return true;
}
private function getBoardIdsByAccess($userId) {
$boardIds = [];
return false;
$boards = R::getAll('SELECT board_id FROM board_user ' .
'WHERE user_id = :user_id',
[':user_id' => $userId]);
foreach ($boards as $board) {
$boardIds[] = (int)$board['board_id'];
}
private function checkUserAccess($actor, $user) {
if ((int)$actor->id !== (int)$user->id) {
if ((int)$actor->security_level === SecurityLevel::ADMIN) {
return true;
}
return $boardIds;
}
$this->apiJson->addAlert('error', 'Access restricted.');
return false;
private function getUserIdsByBoardAccess($userId) {
$userIds = [];
$boardIds = $this->getBoardIdsByAccess($userId);
foreach ($boardIds as $id) {
$board = R::load('board', $id);
foreach ($board->sharedUserList as $user) {
if (!in_array((int) $user->id, $userIds)) {
$userIds[] = (int) $user->id;
}
}
}
return $userIds;
}
private function cleanUser($user) {
unset($user->password_hash);
unset($user->active_token);
$this->setBoardAccess($user);
return $user;
}
private function setBoardAccess(&$user) {
$user->board_access = [];
$boards = RedBeanPHP\R::getAll('select bu.board_id, bu.user_id from ' .
'board_user bu join board b on b.id = bu.board_id');
foreach ($boards as $item) {
if ((int)$user->id === (int)$item['user_id']) {
$user->board_access[] = (int)$item['board_id'];
}
}
}
private function checkUsernameExists($data) {
$existing = R::findOne('user', 'username = ?', [ $data->username ]);
if ($existing) {
$this->apiJson->addAlert('error', 'Username already exists. ' .
'Change the username and try again.');
return true;
}
return false;
}
private function checkUserAccess($actor, $user) {
if ((int)$actor->id !== (int)$user->id) {
if ((int)$actor->security_level === SecurityLevel::ADMIN) {
return true;
}
$this->apiJson->addAlert('error', 'Access restricted.');
return false;
}
private function verifyPassword($data, $user) {
if (!password_verify($data->old_password, $user->password_hash)) {
$this->apiJson->addAlert('error', 'Error updating user. ' .
'Incorrect current password.');
return false;
}
return true;
}
return true;
private function verifyPassword($data, $user) {
if (!password_verify($data->old_password, $user->password_hash)) {
$this->apiJson->addAlert('error', 'Error updating user. ' .
'Incorrect current password.');
return false;
}
private function updateDefaultBoardId(&$data, $user, $update) {
if ($user->default_board_id === $update->default_board_id ||
(int)$update->default_board_id === 0) {
return;
}
return true;
}
if (isset($data->boardAccess) &&
!in_array($data->default_board_id, $data->boardAccess)) {
$data->boardAccess[] = $data->default_board_id;
}
private function updateDefaultBoardId(&$data, $user, $update) {
if ($user->default_board_id === $update->default_board_id ||
(int)$update->default_board_id === 0) {
return;
}
if (isset($data->boardAccess) &&
!in_array($data->default_board_id, $data->boardAccess)) {
$data->boardAccess[] = $data->default_board_id;
}
}
}

View File

@ -2,9 +2,9 @@
use MyCLabs\Enum\Enum;
class ActionTrigger extends Enum {
const MOVED_TO_COLUMN = 1;
const ASSIGNED_TO_USER = 2;
const ADDED_TO_CATEGORY = 3;
const POINTS_CHANGED = 4;
const MOVED_TO_COLUMN = 1;
const ASSIGNED_TO_USER = 2;
const ADDED_TO_CATEGORY = 3;
const POINTS_CHANGED = 4;
}

View File

@ -2,12 +2,12 @@
use MyCLabs\Enum\Enum;
class ActionType extends Enum {
const SET_COLOR = 1;
const SET_CATEGORY = 2;
const ADD_CATEGORY = 3;
const SET_ASSIGNEE = 4;
const ADD_ASSIGNEE = 5;
const CLEAR_DUE_DATE = 6;
const ALTER_COLOR_BY_POINTS= 7;
const SET_COLOR = 1;
const SET_CATEGORY = 2;
const ADD_CATEGORY = 3;
const SET_ASSIGNEE = 4;
const ADD_ASSIGNEE = 5;
const CLEAR_DUE_DATE = 6;
const ALTER_COLOR_BY_POINTS= 7;
}

View File

@ -1,22 +1,22 @@
<?php
class ApiJson {
public $status = 'failure';
public $data = [];
public $alerts = [];
public $status = 'failure';
public $data = [];
public $alerts = [];
function setSuccess() {
$this->status = 'success';
}
function setSuccess() {
$this->status = 'success';
}
function addData($obj) {
$this->data[] = $obj;
}
function addData($obj) {
$this->data[] = $obj;
}
function addAlert($type, $text) {
$this->alerts[] = [
'type' => $type,
'text' => $text
];
}
function addAlert($type, $text) {
$this->alerts[] = [
'type' => $type,
'text' => $text
];
}
}

View File

@ -3,300 +3,300 @@ use RedBeanPHP\R;
class BeanLoader {
public static function LoadAttachment(&$attachment, $json) {
$data = json_decode($json);
public static function LoadAttachment(&$attachment, $json) {
$data = json_decode($json);
$attachment->filename = isset($data->filename) ? $data->filename : '';
$attachment->name = isset($data->name) ? $data->name : '';
$attachment->type = isset($data->type) ? $data->type : '';
$attachment->user_id = isset($data->user_id) ? $data->user_id : -1;
$attachment->timestamp = time();
$attachment->task_id = isset($data->task_id) ? $data->task_id : -1;
$attachment->filename = isset($data->filename) ? $data->filename : '';
$attachment->name = isset($data->name) ? $data->name : '';
$attachment->type = isset($data->type) ? $data->type : '';
$attachment->user_id = isset($data->user_id) ? $data->user_id : -1;
$attachment->timestamp = time();
$attachment->task_id = isset($data->task_id) ? $data->task_id : -1;
if (!isset($data->filename) || !isset($data->name) ||
!isset($data->type) || !isset($data->user_id) ||
!isset($data->task_id)) {
return false;
}
return true;
if (!isset($data->filename) || !isset($data->name) ||
!isset($data->type) || !isset($data->user_id) ||
!isset($data->task_id)) {
return false;
}
public static function LoadAutoAction(&$action, $json) {
$data = json_decode($json);
return true;
}
$action->trigger = isset($data->trigger) ? $data->trigger : -1;
$action->source_id = isset($data->source_id) ? $data->source_id: -1;
$action->type = isset($data->type) ? $data->type : '';
$action->change_to = isset($data->change_to) ? $data->change_to: -1;
$action->board_id = isset($data->board_id) ? $data->board_id: -1;
public static function LoadAutoAction(&$action, $json) {
$data = json_decode($json);
if (!isset($data->trigger) || !isset($data->type) ||
!isset($data->board_id)) {
return false;
}
$action->trigger = isset($data->trigger) ? $data->trigger : -1;
$action->source_id = isset($data->source_id) ? $data->source_id: -1;
$action->type = isset($data->type) ? $data->type : '';
$action->change_to = isset($data->change_to) ? $data->change_to: -1;
$action->board_id = isset($data->board_id) ? $data->board_id: -1;
return true;
if (!isset($data->trigger) || !isset($data->type) ||
!isset($data->board_id)) {
return false;
}
public static function LoadBoard(&$board, $json) {
$data = json_decode($json);
return true;
}
$board->name = isset($data->name) ? $data->name : '';
$board->is_active = isset($data->is_active) ? $data->is_active : false;
public static function LoadBoard(&$board, $json) {
$data = json_decode($json);
if (isset($data->categories)) {
self::updateObjectList('category', 'LoadCategory',
$board->xownCategoryList, $data->categories);
}
$board->name = isset($data->name) ? $data->name : '';
$board->is_active = isset($data->is_active) ? $data->is_active : false;
if (isset($data->issue_trackers)) {
self::updateObjectList('issuetracker', 'LoadIssueTracker',
$board->xownIssueTrackerList,
$data->issue_trackers);
}
if (isset($data->columns)) {
self::updateObjectList('column', 'LoadColumn',
$board->xownColumnList, $data->columns);
}
// Users do not get deleted when removed from a board
if (isset($data->users)) {
$board->sharedUserList = [];
foreach ($data->users as $userData) {
$user = R::load('user', $userData->id);
if ((int)$user->id) {
$board->sharedUserList[] = $user;
}
}
}
if (!isset($data->name) || !isset($data->is_active) ||
!isset($data->categories) || !isset($data->columns) ||
!isset($data->issue_trackers) || !isset($data->users)) {
return false;
}
return true;
if (isset($data->categories)) {
self::updateObjectList('category', 'LoadCategory',
$board->xownCategoryList, $data->categories);
}
public static function LoadCategory(&$category, $json) {
$data = json_decode($json);
$category->name = isset($data->name) ? $data->name : '';
$category->default_task_color = isset($data->default_task_color)
? $data->default_task_color : '';
$category->board_id = isset($data->board_id) ? $data->board_id : -1;
if (!isset($data->name) || !isset($data->default_task_color) ||
!isset($data->board_id)) {
return false;
}
return true;
if (isset($data->issue_trackers)) {
self::updateObjectList('issuetracker', 'LoadIssueTracker',
$board->xownIssueTrackerList,
$data->issue_trackers);
}
public static function LoadColumn(&$column, $json) {
$data = json_decode($json);
$column->name = isset($data->name) ? $data->name : '';
$column->position = isset($data->position) ? $data->position : -1;
$column->board_id = isset($data->board_id) ? $data->board_id : -1;
$column->task_limit = isset($data->task_limit) ? $data->task_limit : 0;
if (isset($data->tasks)) {
self::updateObjectList('task', 'LoadTask',
$column->xownTaskList, $data->tasks);
}
if (!isset($data->name) || !isset($data->position) ||
!isset($data->board_id)) {
return false;
}
return true;
if (isset($data->columns)) {
self::updateObjectList('column', 'LoadColumn',
$board->xownColumnList, $data->columns);
}
public static function LoadComment(&$comment, $json) {
$data = json_decode($json);
// Users do not get deleted when removed from a board
if (isset($data->users)) {
$board->sharedUserList = [];
$comment->text = isset($data->text) ? $data->text : '';
$comment->user_id = isset($data->user_id) ? $data->user_id : -1;
$comment->task_id = isset($data->task_id) ? $data->task_id : -1;
$comment->timestamp = isset($data->timestamp) ? $data->timestamp : -1;
$comment->is_edited = isset($data->is_edited) ? $data->is_edited : false;
foreach ($data->users as $userData) {
$user = R::load('user', $userData->id);
if (!isset($data->text) || !isset($data->user_id) ||
!isset($data->task_id) || !isset($data->timestamp)) {
return false;
if ((int)$user->id) {
$board->sharedUserList[] = $user;
}
return true;
}
}
public static function LoadIssueTracker(&$tracker, $json) {
$data = json_decode($json);
$tracker->url = isset($data->url) ? $data->url : '';
$tracker->regex = isset($data->regex) ? $data->regex : '';
$tracker->board_id = isset($data->board_id) ? $data->board_id : -1;
if (!isset($data->url) || !isset($data->regex) ||
!isset($data->board_id)) {
return false;
}
return true;
if (!isset($data->name) || !isset($data->is_active) ||
!isset($data->categories) || !isset($data->columns) ||
!isset($data->issue_trackers) || !isset($data->users)) {
return false;
}
public static function LoadTask(&$task, $json) {
$data = json_decode($json);
return true;
}
$task->title = isset($data->title) ? $data->title : '';
$task->description = isset($data->description)
? $data->description : '';
$task->color = isset($data->color) ? $data->color : '';
$task->due_date = isset($data->due_date) ? $data->due_date : '';
$task->points = isset($data->points) ? $data->points : 0;
$task->position = isset($data->position) ? $data->position : -1;
$task->column_id = isset($data->column_id) ? $data->column_id : -1;
public static function LoadCategory(&$category, $json) {
$data = json_decode($json);
if (isset($data->comments)) {
self::updateObjectList('comment', 'LoadComment',
$task->xownCommentList, $data->comments);
}
$category->name = isset($data->name) ? $data->name : '';
$category->default_task_color = isset($data->default_task_color)
? $data->default_task_color : '';
$category->board_id = isset($data->board_id) ? $data->board_id : -1;
if (isset($data->attachments)) {
self::updateObjectList('attachment', 'LoadAttachment',
$task->xownAttachmentList, $data->attachments);
}
if (isset($data->assignees)) {
$task->sharedUserList = [];
foreach ($data->assignees as $assignee) {
$user = R::load('user', $assignee->id);
if ((int)$user->id) {
$task->sharedUserList[] = $user;
}
}
}
if (isset($data->categories)) {
$task->sharedCategoryList = [];
foreach ($data->categories as $category) {
$cat = R::load('category', $category->id);
if ((int)$cat->id) {
$task->sharedCategoryList[] = $cat;
}
}
}
if (!isset($data->title) || !isset($data->position) ||
!isset($data->column_id)) {
return false;
}
return true;
if (!isset($data->name) || !isset($data->default_task_color) ||
!isset($data->board_id)) {
return false;
}
public static function LoadUser(&$user, $json) {
$data = json_decode($json);
return true;
}
$user->security_level = isset($data->security_level)
? $data->security_level : -1;
$user->username = isset($data->username) ? $data->username : '';
$user->email = isset($data->email) ? $data->email : '';
$user->default_board_id = isset($data->default_board_id)
? $data->default_board_id : -1;
$user->user_option_id = isset($data->user_option_id)
? $data->user_option_id : -1;
$user->last_login = isset($data->last_login) ? $data->last_login : '';
$user->password_hash = isset($data->password_hash)
? $data->password_hash : '';
public static function LoadColumn(&$column, $json) {
$data = json_decode($json);
if (!isset($data->security_level) || !isset($data->username)) {
return false;
}
$column->name = isset($data->name) ? $data->name : '';
$column->position = isset($data->position) ? $data->position : -1;
$column->board_id = isset($data->board_id) ? $data->board_id : -1;
$column->task_limit = isset($data->task_limit) ? $data->task_limit : 0;
return true;
if (isset($data->tasks)) {
self::updateObjectList('task', 'LoadTask',
$column->xownTaskList, $data->tasks);
}
public static function LoadUserOption(&$opts, $json) {
$data = json_decode($json);
$opts->new_tasks_at_bottom = isset($data->new_tasks_at_bottom)
? (boolean)$data->new_tasks_at_bottom : true;
$opts->show_animations = isset($data->show_animations)
? (boolean)$data->show_animations : true;
$opts->show_assignee = isset($data->show_assignee)
? (boolean)$data->show_assignee : true;
$opts->multiple_tasks_per_row = isset($data->multiple_tasks_per_row)
? (boolean)$data->multiple_tasks_per_row : false;
$opts->language = isset($data->language)
? $data->language : '';
if (!isset($data->new_tasks_at_bottom) ||
!isset($data->show_animations) || !isset($data->show_assignee) ||
!isset($data->multiple_tasks_per_row) || !isset($data->language)) {
return false;
}
return true;
if (!isset($data->name) || !isset($data->position) ||
!isset($data->board_id)) {
return false;
}
private static function removeObjectsNotInData($type, &$dataList, &$objectList) {
$dataIds = [];
return true;
}
foreach ($dataList as $data) {
if (isset($data->id)) {
$dataIds[] = (int)$data->id;
}
}
public static function LoadComment(&$comment, $json) {
$data = json_decode($json);
foreach ($objectList as $existing) {
if (!in_array((int)$existing->id, $dataIds)) {
$remove = R::load($type, $existing->id);
R::trash($remove);
}
}
$comment->text = isset($data->text) ? $data->text : '';
$comment->user_id = isset($data->user_id) ? $data->user_id : -1;
$comment->task_id = isset($data->task_id) ? $data->task_id : -1;
$comment->timestamp = isset($data->timestamp) ? $data->timestamp : -1;
$comment->is_edited = isset($data->is_edited) ? $data->is_edited : false;
if (!isset($data->text) || !isset($data->user_id) ||
!isset($data->task_id) || !isset($data->timestamp)) {
return false;
}
private static function loadObjectsFromData($type, $loadFunc, &$dataList,
&$objectList) {
foreach ($dataList as $obj) {
$object = R::load($type, (isset($obj->id) ? $obj->id : 0));
return true;
}
call_user_func_array(array(__CLASS__, $loadFunc),
array(&$object, json_encode($obj)));
$objectList[] = $object;
}
public static function LoadIssueTracker(&$tracker, $json) {
$data = json_decode($json);
$tracker->url = isset($data->url) ? $data->url : '';
$tracker->regex = isset($data->regex) ? $data->regex : '';
$tracker->board_id = isset($data->board_id) ? $data->board_id : -1;
if (!isset($data->url) || !isset($data->regex) ||
!isset($data->board_id)) {
return false;
}
private static function updateObjectList($type, $loadFunc,
&$objectList = [],
&$dataList = []) {
if (count($objectList) && count($dataList)) {
self::removeObjectsNotInData($type, $dataList, $objectList);
}
return true;
}
if (count($dataList)) {
self::loadObjectsFromData($type, $loadFunc, $dataList, $objectList);
}
public static function LoadTask(&$task, $json) {
$data = json_decode($json);
// Remove all objects from existing boardlist when none in datalist
if (!count($dataList) && count($objectList)) {
foreach ($objectList as $obj) {
R::trash($obj);
}
}
$task->title = isset($data->title) ? $data->title : '';
$task->description = isset($data->description)
? $data->description : '';
$task->color = isset($data->color) ? $data->color : '';
$task->due_date = isset($data->due_date) ? $data->due_date : '';
$task->points = isset($data->points) ? $data->points : 0;
$task->position = isset($data->position) ? $data->position : -1;
$task->column_id = isset($data->column_id) ? $data->column_id : -1;
if (isset($data->comments)) {
self::updateObjectList('comment', 'LoadComment',
$task->xownCommentList, $data->comments);
}
if (isset($data->attachments)) {
self::updateObjectList('attachment', 'LoadAttachment',
$task->xownAttachmentList, $data->attachments);
}
if (isset($data->assignees)) {
$task->sharedUserList = [];
foreach ($data->assignees as $assignee) {
$user = R::load('user', $assignee->id);
if ((int)$user->id) {
$task->sharedUserList[] = $user;
}
}
}
if (isset($data->categories)) {
$task->sharedCategoryList = [];
foreach ($data->categories as $category) {
$cat = R::load('category', $category->id);
if ((int)$cat->id) {
$task->sharedCategoryList[] = $cat;
}
}
}
if (!isset($data->title) || !isset($data->position) ||
!isset($data->column_id)) {
return false;
}
return true;
}
public static function LoadUser(&$user, $json) {
$data = json_decode($json);
$user->security_level = isset($data->security_level)
? $data->security_level : -1;
$user->username = isset($data->username) ? $data->username : '';
$user->email = isset($data->email) ? $data->email : '';
$user->default_board_id = isset($data->default_board_id)
? $data->default_board_id : -1;
$user->user_option_id = isset($data->user_option_id)
? $data->user_option_id : -1;
$user->last_login = isset($data->last_login) ? $data->last_login : '';
$user->password_hash = isset($data->password_hash)
? $data->password_hash : '';
if (!isset($data->security_level) || !isset($data->username)) {
return false;
}
return true;
}
public static function LoadUserOption(&$opts, $json) {
$data = json_decode($json);
$opts->new_tasks_at_bottom = isset($data->new_tasks_at_bottom)
? (boolean)$data->new_tasks_at_bottom : true;
$opts->show_animations = isset($data->show_animations)
? (boolean)$data->show_animations : true;
$opts->show_assignee = isset($data->show_assignee)
? (boolean)$data->show_assignee : true;
$opts->multiple_tasks_per_row = isset($data->multiple_tasks_per_row)
? (boolean)$data->multiple_tasks_per_row : false;
$opts->language = isset($data->language)
? $data->language : '';
if (!isset($data->new_tasks_at_bottom) ||
!isset($data->show_animations) || !isset($data->show_assignee) ||
!isset($data->multiple_tasks_per_row) || !isset($data->language)) {
return false;
}
return true;
}
private static function removeObjectsNotInData($type, &$dataList, &$objectList) {
$dataIds = [];
foreach ($dataList as $data) {
if (isset($data->id)) {
$dataIds[] = (int)$data->id;
}
}
foreach ($objectList as $existing) {
if (!in_array((int)$existing->id, $dataIds)) {
$remove = R::load($type, $existing->id);
R::trash($remove);
}
}
}
private static function loadObjectsFromData($type, $loadFunc, &$dataList,
&$objectList) {
foreach ($dataList as $obj) {
$object = R::load($type, (isset($obj->id) ? $obj->id : 0));
call_user_func_array(array(__CLASS__, $loadFunc),
array(&$object, json_encode($obj)));
$objectList[] = $object;
}
}
private static function updateObjectList($type, $loadFunc,
&$objectList = [],
&$dataList = []) {
if (count($objectList) && count($dataList)) {
self::removeObjectsNotInData($type, $dataList, $objectList);
}
if (count($dataList)) {
self::loadObjectsFromData($type, $loadFunc, $dataList, $objectList);
}
// Remove all objects from existing boardlist when none in datalist
if (!count($dataList) && count($objectList)) {
foreach ($objectList as $obj) {
R::trash($obj);
}
}
}
}

View File

@ -2,19 +2,19 @@
use RedBeanPHP\R;
class DbLogger {
public static function logChange($user_id, $log_text, $before,
$after, $item_type, $item_id) {
$activity = R::dispense('activity');
public static function logChange($user_id, $log_text, $before,
$after, $item_type, $item_id) {
$activity = R::dispense('activity');
$activity->user_id = $user_id;
$activity->log_text = $log_text;
$activity->before = $before;
$activity->after = $after;
$activity->item_type = $item_type;
$activity->item_id = $item_id;
$activity->timestamp = time();
$activity->user_id = $user_id;
$activity->log_text = $log_text;
$activity->before = $before;
$activity->after = $after;
$activity->item_type = $item_type;
$activity->item_id = $item_id;
$activity->timestamp = time();
R::store($activity);
}
R::store($activity);
}
}

View File

@ -2,9 +2,9 @@
use MyCLabs\Enum\Enum;
final class SecurityLevel extends Enum {
const ADMIN = 1;
const BOARD_ADMIN = 2;
const USER = 3;
const UNPRIVILEGED = 4;
const ADMIN = 1;
const BOARD_ADMIN = 2;
const USER = 3;
const UNPRIVILEGED = 4;
}

View File

@ -132,6 +132,7 @@ export class BoardDisplayComponent implements OnInit, OnDestroy, AfterContentIni
}
});
/* istanbul ignore next */
this.dragula.dropModel('tasks-bag').subscribe((value: any) => {
const taskId = +value[1].id;
const toColumnId = +value[2].parentNode.id;
@ -298,6 +299,7 @@ export class BoardDisplayComponent implements OnInit, OnDestroy, AfterContentIni
}
}
/* istanbul ignore next */
private changeTaskColumn(taskId: number, toColumnId: number) {
const column = this.activeBoard.columns
.find(col => col.id === toColumnId);

View File

@ -134,6 +134,7 @@ export class BoardService {
);
}
/* istanbul ignore next */
uploadAttachment(attachment: Attachment, data: FormData): Observable<ApiResponse> {
const headers = new HttpHeaders();
const options = { headers, params: new HttpParams() };
@ -151,7 +152,10 @@ export class BoardService {
}
private defaultCallback = (err: any, text: string) => {
console.log('default', err, text);
if (err) {
return '';
}
return text;
}

View File

@ -281,10 +281,12 @@ export class ColumnDisplayComponent implements OnInit, OnDestroy {
});
}
/* istanbul ignore next */
fileChange(file: File) {
this.fileUpload = file;
}
/* istanbul ignore next */
uploadFile() {
if (!this.fileUpload) {
this.notes.add({ type: 'error', text: this.strings.boards_taskNoFileError });

View File

@ -1,5 +1,6 @@
import { Component, Input } from '@angular/core';
/* istanbul ignore next */
@Component({
selector: 'tb-calendar',
templateUrl: './calendar.component.html'

View File

@ -1,6 +1,7 @@
import { Component, Input, AfterViewInit } from '@angular/core';
import * as Chartist from 'chartist';
/* istanbul ignore next */
@Component({
selector: 'tb-charts',
templateUrl: './charts.component.html'

View File

@ -4,6 +4,7 @@ import { Title } from '@angular/platform-browser';
// import { Charts } from './charts/charts.component';
// import { Calendar } from './calendar/calendar.component';
/* istanbul ignore next */
@Component({
selector: 'tb-dashboard',
templateUrl: './dashboard.component.html'

View File

@ -4,182 +4,182 @@ use Firebase\JWT\JWT;
class AppMock {
public function getContainer() {
return new ContainerMock();
}
public function getContainer() {
return new ContainerMock();
}
}
$app = new AppMock();
class DataMock {
public static function GetJwt($userId = 1) {
Auth::CreateJwtSigningKey();
public static function GetJwt($userId = 1) {
Auth::CreateJwtSigningKey();
$key = R::load('jwt', 1);
$key = R::load('jwt', 1);
$jwt = JWT::encode(array(
'exp' => time() + (60 * 30), // 30 minutes
'uid' => $userId,
'mul' => 1
), $key->secret);
$jwt = JWT::encode(array(
'exp' => time() + (60 * 30), // 30 minutes
'uid' => $userId,
'mul' => 1
), $key->secret);
$user = R::load('user', $userId);
$user->active_token = $jwt;
R::store($user);
$user = R::load('user', $userId);
$user->active_token = $jwt;
R::store($user);
return $jwt;
}
return $jwt;
}
public static function CreateStandardUser() {
$user = R::dispense('user');
self::setUserDefaults($user);
R::store($user);
}
public static function CreateStandardUser() {
$user = R::dispense('user');
self::setUserDefaults($user);
R::store($user);
}
public static function CreateBoardAdminUser() {
$user = R::dispense('user');
self::setUserDefaults($user);
public static function CreateBoardAdminUser() {
$user = R::dispense('user');
self::setUserDefaults($user);
$user->username = 'boardadmin';
$user->security_level = SecurityLevel::BOARD_ADMIN;
R::store($user);
}
$user->username = 'boardadmin';
$user->security_level = SecurityLevel::BOARD_ADMIN;
R::store($user);
}
public static function CreateUnprivilegedUser() {
$user = R::dispense('user');
self::setUserDefaults($user);
public static function CreateUnprivilegedUser() {
$user = R::dispense('user');
self::setUserDefaults($user);
$user->username = 'badtester';
$user->security_level = SecurityLevel::UNPRIVILEGED;
R::store($user);
}
$user->username = 'badtester';
$user->security_level = SecurityLevel::UNPRIVILEGED;
R::store($user);
}
public static function CreateBoard() {
$board = R::dispense('board');
$board->name = 'test';
$board->is_active = true;
}
public static function CreateBoard() {
$board = R::dispense('board');
$board->name = 'test';
$board->is_active = true;
}
private static function setUserDefaults(&$user) {
$user->username = 'tester';
$user->security_level = SecurityLevel::USER;
$user->password_hash = 'hashpass1234';
$user->email = 'user@example.com';
$user->default_board_id = 0;
$user->user_option_id = 0;
$user->last_login = 123456789;
$user->active_token = '';
}
private static function setUserDefaults(&$user) {
$user->username = 'tester';
$user->security_level = SecurityLevel::USER;
$user->password_hash = 'hashpass1234';
$user->email = 'user@example.com';
$user->default_board_id = 0;
$user->user_option_id = 0;
$user->last_login = 123456789;
$user->active_token = '';
}
}
class LoggerMock {
public function addInfo() {
}
public function addInfo() {
}
public function addError() {
// Uncomment to log errors to file
// The tests cover errors, so there will be plenty to sift through
// $msg = func_get_arg(0);
// $err = 'API ERROR: ' . $msg . PHP_EOL;
public function addError() {
// Uncomment to log errors to file
// The tests cover errors, so there will be plenty to sift through
// $msg = func_get_arg(0);
// $err = 'API ERROR: ' . $msg . PHP_EOL;
// $objs = func_get_args();
// array_splice($objs, 0, 1);
// $objs = func_get_args();
// array_splice($objs, 0, 1);
// ob_start();
// foreach($objs as $obj) {
// var_dump($obj);
// }
// $strings = ob_get_clean();
// ob_start();
// foreach($objs as $obj) {
// var_dump($obj);
// }
// $strings = ob_get_clean();
// file_put_contents('tests.log', [$err, $strings], FILE_APPEND);
}
// file_put_contents('tests.log', [$err, $strings], FILE_APPEND);
}
}
class ContainerMock {
public function get() {
return new LoggerMock();
}
public function get() {
return new LoggerMock();
}
}
class RequestMock {
public $invalidPayload = false;
public $payload = null;
public $hasHeader = true;
public $header = null;
public $throwInHeader = false;
public $invalidPayload = false;
public $payload = null;
public $hasHeader = true;
public $header = null;
public $throwInHeader = false;
public function getBody() {
if ($this->invalidPayload) {
return '{}';
}
if ($this->payload) {
return json_encode($this->payload);
}
return '';
public function getBody() {
if ($this->invalidPayload) {
return '{}';
}
public function hasHeader() {
return $this->hasHeader;
if ($this->payload) {
return json_encode($this->payload);
}
public function getHeader($header) {
if ($this->throwInHeader) {
throw new Exception();
}
return '';
}
if ($this->header) {
return $this->header;
}
public function hasHeader() {
return $this->hasHeader;
}
return $header;
public function getHeader($header) {
if ($this->throwInHeader) {
throw new Exception();
}
if ($this->header) {
return $this->header;
}
return $header;
}
}
class ResponseMock {
public $status = 200;
public $body;
public $status = 200;
public $body;
public function __construct() {
$this->body = new RequestBodyMock();
}
public function __construct() {
$this->body = new RequestBodyMock();
}
public function withJson($apiJson) {
return $apiJson;
}
public function withJson($apiJson) {
return $apiJson;
}
public function withStatus($status) {
$this->status = $status;
public function withStatus($status) {
$this->status = $status;
return $this;
}
return $this;
}
public function getStatusCode() {
return $this->status;
}
public function getStatusCode() {
return $this->status;
}
public function getBody() {
return $this->body;
}
public function getBody() {
return $this->body;
}
}
class RequestBodyMock {
public $data;
public $data;
public function __toString() {
return $this->data;
}
public function __toString() {
return $this->data;
}
public function write($string) {
$this->data = $string;
}
public function write($string) {
$this->data = $string;
}
}

View File

@ -3,96 +3,96 @@ require_once __DIR__ . '/../Mocks.php';
use RedBeanPHP\R;
class ActivityTest extends PHPUnit\Framework\TestCase {
private $activity;
private $activity;
public static function setupBeforeClass() {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
public static function setUpBeforeClass(): void {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
}
public function setUp() {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
public function setUp(): void {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
$this->activity = new Activity(new ContainerMock());
}
$this->activity = new Activity(new ContainerMock());
}
public function testGetActivityInvalid() {
$request = new RequestMock();
$request->hasHeader = false;
public function testGetActivityInvalid() {
$request = new RequestMock();
$request->hasHeader = false;
$args = [];
$args['type'] = 'task';
$args['id'] = 1;
$args = [];
$args['type'] = 'task';
$args['id'] = 1;
$actual = $this->activity->getActivity($request,
new ResponseMock(), $args);
$this->assertEquals('error', $actual->alerts[0]['type']);
}
$actual = $this->activity->getActivity($request,
new ResponseMock(), $args);
$this->assertEquals('error', $actual->alerts[0]['type']);
}
public function testGetActivityForbidden() {
$this->setupTaskActivity();
public function testGetActivityForbidden() {
$this->setupTaskActivity();
$args = [];
$args['type'] = 'task';
$args['id'] = 1;
$args = [];
$args['type'] = 'task';
$args['id'] = 1;
DataMock::CreateBoardAdminUser();
DataMock::CreateBoardAdminUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->activity->getActivity($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.', $actual->alerts[0]['text']);
}
$actual = $this->activity->getActivity($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.', $actual->alerts[0]['text']);
}
public function testGetActivityForTask() {
$this->setupTaskActivity();
public function testGetActivityForTask() {
$this->setupTaskActivity();
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$args = [];
$args['type'] = 'task';
$args['id'] = 1;
$args = [];
$args['type'] = 'task';
$args['id'] = 1;
$actual = $this->activity->getActivity($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
$this->assertEquals(3, count($actual->data[1]));
}
$actual = $this->activity->getActivity($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
$this->assertEquals(3, count($actual->data[1]));
}
private function setupTaskActivity() {
$task = R::dispense('task');
$comment = R::dispense('comment');
$attachment = R::dispense('attachment');
$task->ownComment[] = $comment;
$task->ownAttachment[] = $attachment;
R::store($task);
private function setupTaskActivity() {
$task = R::dispense('task');
$comment = R::dispense('comment');
$attachment = R::dispense('attachment');
$task->ownComment[] = $comment;
$task->ownAttachment[] = $attachment;
R::store($task);
$activity = R::dispense('activity');
$activity->item_type = 'task';
$activity->item_id = 1;
$activity->log_text = 'test change';
$activity->timestamp = time();
R::store($activity);
$activity = R::dispense('activity');
$activity->item_type = 'task';
$activity->item_id = 1;
$activity->log_text = 'test change';
$activity->timestamp = time();
R::store($activity);
$activity = R::dispense('activity');
$activity->item_type = 'task';
$activity->item_id = 1;
$activity->log_text = 'test change';
$activity->timestamp = time();
R::store($activity);
$activity = R::dispense('activity');
$activity->item_type = 'task';
$activity->item_id = 1;
$activity->log_text = 'test change';
$activity->timestamp = time();
R::store($activity);
$activity = R::dispense('activity');
$activity->item_type = 'task';
$activity->item_id = 1;
$activity->log_text = 'test change';
$activity->timestamp = time() + 10;
R::store($activity);
}
$activity = R::dispense('activity');
$activity->item_type = 'task';
$activity->item_id = 1;
$activity->log_text = 'test change';
$activity->timestamp = time() + 10;
R::store($activity);
}
}

View File

@ -3,231 +3,231 @@ require_once __DIR__ . '/../Mocks.php';
use RedBeanPHP\R;
class AttachmentsTest extends PHPUnit\Framework\TestCase {
private $attachments;
private $attachments;
public static function setupBeforeClass() {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
public static function setUpBeforeClass(): void {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
}
public function setUp() {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
public function setUp(): void {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
$this->attachments = new Attachments(new ContainerMock());
}
$this->attachments = new Attachments(new ContainerMock());
}
public function testGetAttachment() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
public function testGetAttachment() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$actual = $this->attachments->getAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('No attachment found for ID 1.',
$actual->alerts[0]['text']);
$actual = $this->attachments->getAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('No attachment found for ID 1.',
$actual->alerts[0]['text']);
$this->createAttachment();
$request->header = [DataMock::GetJwt()];
$this->createAttachment();
$request->header = [DataMock::GetJwt()];
$this->attachments = new Attachments(new ContainerMock());
$this->attachments = new Attachments(new ContainerMock());
$actual = $this->attachments->getAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
$this->assertEquals(2, count($actual->data));
}
$actual = $this->attachments->getAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
$this->assertEquals(2, count($actual->data));
}
public function testGetAttachmentInvalid() {
$request = new RequestMock();
$request->hasHeader = false;
public function testGetAttachmentInvalid() {
$request = new RequestMock();
$request->hasHeader = false;
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$actual = $this->attachments->getAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('error', $actual->alerts[0]['type']);
}
$actual = $this->attachments->getAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('error', $actual->alerts[0]['type']);
}
public function testGetAttachmentForbidden() {
$this->createAttachment();
public function testGetAttachmentForbidden() {
$this->createAttachment();
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$actual = $this->attachments->getAttachment(new RequestMock(),
new ResponseMock(), $args);
$this->assertEquals('error', $actual->alerts[0]['type']);
$actual = $this->attachments->getAttachment(new RequestMock(),
new ResponseMock(), $args);
$this->assertEquals('error', $actual->alerts[0]['type']);
DataMock::CreateBoardAdminUser();
DataMock::CreateBoardAdminUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$this->attachments = new Attachments(new ContainerMock());
$this->attachments = new Attachments(new ContainerMock());
$actual = $this->attachments->getAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$actual = $this->attachments->getAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testAddAttachment() {
$task = R::dispense('task');
R::store($task);
public function testAddAttachment() {
$task = R::dispense('task');
R::store($task);
$data = new stdClass();
$data->filename = 'test';
$data->name = 'test.png';
$data->type = 'image';
$data->user_id = 1;
$data->task_id = 1;
$data = new stdClass();
$data->filename = 'test';
$data->name = 'test.png';
$data->type = 'image';
$data->user_id = 1;
$data->task_id = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $data;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $data;
$actual = $this->attachments->addAttachment($request,
new ResponseMock(), null);
$this->assertEquals('Attachment added.', $actual->alerts[0]['text']);
}
$actual = $this->attachments->addAttachment($request,
new ResponseMock(), null);
$this->assertEquals('Attachment added.', $actual->alerts[0]['text']);
}
public function testAddAttachmentInvalid() {
$request = new RequestMock();
$request->invalidPayload = true;
$request->header = [DataMock::GetJwt()];
public function testAddAttachmentInvalid() {
$request = new RequestMock();
$request->invalidPayload = true;
$request->header = [DataMock::GetJwt()];
$actual = $this->attachments->addAttachment($request,
new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
$this->assertEquals('error', $actual->alerts[0]['type']);
}
$actual = $this->attachments->addAttachment($request,
new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
$this->assertEquals('error', $actual->alerts[0]['type']);
}
public function testAddAttachmentForbidden() {
$task = R::dispense('task');
R::store($task);
public function testAddAttachmentForbidden() {
$task = R::dispense('task');
R::store($task);
$attachment = new stdClass();
$attachment->filename = "test";
$attachment->name = 'test.png';
$attachment->type = 'image';
$attachment->user_id = 1;
$attachment->task_id = 1;
$attachment = new stdClass();
$attachment->filename = "test";
$attachment->name = 'test.png';
$attachment->type = 'image';
$attachment->user_id = 1;
$attachment->task_id = 1;
$request = new RequestMock();
$request->payload = $attachment;
$request = new RequestMock();
$request->payload = $attachment;
$actual = $this->attachments->addAttachment($request,
new ResponseMock(), null);
$this->assertEquals('error', $actual->alerts[0]['type']);
$actual = $this->attachments->addAttachment($request,
new ResponseMock(), null);
$this->assertEquals('error', $actual->alerts[0]['type']);
DataMock::CreateBoardAdminUser();
$request->header = [DataMock::GetJwt(2)];
DataMock::CreateBoardAdminUser();
$request->header = [DataMock::GetJwt(2)];
$this->attachments = new Attachments(new ContainerMock());
$this->attachments = new Attachments(new ContainerMock());
$actual = $this->attachments->addAttachment($request,
new ResponseMock(), null);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$actual = $this->attachments->addAttachment($request,
new ResponseMock(), null);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testRemoveAttachment() {
$this->createAttachment();
public function testRemoveAttachment() {
$this->createAttachment();
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->attachments->removeAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('Attachment file.png removed.',
$actual->alerts[0]['text']);
}
$actual = $this->attachments->removeAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('Attachment file.png removed.',
$actual->alerts[0]['text']);
}
public function testRemoveUnprivileged() {
DataMock::CreateUnprivilegedUser();
$this->createAttachment();
public function testRemoveUnprivileged() {
DataMock::CreateUnprivilegedUser();
$this->createAttachment();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$actual = $this->attachments->removeAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->attachments->removeAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testRemoveAttachmentUserSecurity() {
$this->createAttachment();
DataMock::CreateStandardUser();
public function testRemoveAttachmentUserSecurity() {
$this->createAttachment();
DataMock::CreateStandardUser();
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->attachments->removeAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('You do not have sufficient permissions to ' .
'remove this attachment.', $actual->alerts[0]['text']);
}
$actual = $this->attachments->removeAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('You do not have sufficient permissions to ' .
'remove this attachment.', $actual->alerts[0]['text']);
}
public function testRemoveAttachmentForbidden() {
$this->createAttachment();
DataMock::CreateBoardAdminUser();
public function testRemoveAttachmentForbidden() {
$this->createAttachment();
DataMock::CreateBoardAdminUser();
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->attachments->removeAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$actual = $this->attachments->removeAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testRemoveBadAttachment() {
$this->createAttachment();
public function testRemoveBadAttachment() {
$this->createAttachment();
$args = [];
$args['id'] = 2; // No such attachment
$args = [];
$args['id'] = 2; // No such attachment
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->attachments->removeAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('Error removing attachment. ' .
'No attachment found for ID 2.', $actual->alerts[0]['text']);
}
$actual = $this->attachments->removeAttachment($request,
new ResponseMock(), $args);
$this->assertEquals('Error removing attachment. ' .
'No attachment found for ID 2.', $actual->alerts[0]['text']);
}
private function createAttachment() {
$board = R::dispense('board');
$column = R::dispense('column');
$task = R::dispense('task');
$attachment = R::dispense('attachment');
private function createAttachment() {
$board = R::dispense('board');
$column = R::dispense('column');
$task = R::dispense('task');
$attachment = R::dispense('attachment');
$attachment->name = 'file.png';
$attachment->user_id = 1;
$attachment->name = 'file.png';
$attachment->user_id = 1;
$task->xownAttachmentList[] = $attachment;
$column->xownTaskList[] = $task;
$board->xownColumnList[] = $column;
R::store($board);
}
$task->xownAttachmentList[] = $attachment;
$column->xownTaskList[] = $task;
$board->xownColumnList[] = $column;
R::store($board);
}
}

View File

@ -3,275 +3,275 @@ use RedBeanPHP\R;
use Firebase\JWT\JWT;
class AuthTest extends PHPUnit\Framework\TestCase {
private $auth;
private $auth;
public static function setupBeforeClass() {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
public static function setUpBeforeClass(): void {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
}
public function setUp() {
R::nuke();
public function setUp(): void {
R::nuke();
$this->auth = new Auth(new ContainerMock());
}
$this->auth = new Auth(new ContainerMock());
}
public function testHasBoardAccess() {
$user = R::dispense('user');
public function testHasBoardAccess() {
$user = R::dispense('user');
$board = R::dispense('board');
$board->sharedUserList[] = $user;
R::store($board);
$board = R::dispense('board');
$board->sharedUserList[] = $user;
R::store($board);
$hasAccess = Auth::HasBoardAccess(new RequestMock(), 1, 1);
$this->assertEquals(true, $hasAccess);
$hasAccess = Auth::HasBoardAccess(new RequestMock(), 1, 1);
$this->assertEquals(true, $hasAccess);
$user->security_level = SecurityLevel::ADMIN;
R::store($user);
$user->security_level = SecurityLevel::ADMIN;
R::store($user);
$hasAccess = Auth::HasBoardAccess(new RequestMock(), 1, 1);
$this->assertEquals(true, $hasAccess);
}
$hasAccess = Auth::HasBoardAccess(new RequestMock(), 1, 1);
$this->assertEquals(true, $hasAccess);
}
public function testCreateInitialAdmin() {
Auth::CreateInitialAdmin(new ContainerMock());
public function testCreateInitialAdmin() {
Auth::CreateInitialAdmin(new ContainerMock());
$admin = R::load('user', 1);
$admin = R::load('user', 1);
$this->assertEquals(1, (int) $admin->id);
$this->assertEquals('admin', $admin->username);
$this->assertEquals(1, (int) $admin->id);
$this->assertEquals('admin', $admin->username);
// Call again to verify only one is created
Auth::CreateInitialAdmin(new ContainerMock());
$this->assertEquals(1, R::count('user'));
}
// Call again to verify only one is created
Auth::CreateInitialAdmin(new ContainerMock());
$this->assertEquals(1, R::count('user'));
}
public function testCreateJwtSigningKey() {
Auth::CreateJwtSigningKey();
public function testCreateJwtSigningKey() {
Auth::CreateJwtSigningKey();
$jwt = R::load('jwt', 1);
$jwt = R::load('jwt', 1);
$this->assertEquals(1, (int) $jwt->id);
$this->assertTrue(strlen($jwt->secret) > 1);
$this->assertEquals(1, (int) $jwt->id);
$this->assertTrue(strlen($jwt->secret) > 1);
// Call again to verify only one is created
Auth::CreateJwtSigningKey();
$this->assertEquals(1, R::count('jwt'));
}
// Call again to verify only one is created
Auth::CreateJwtSigningKey();
$this->assertEquals(1, R::count('jwt'));
}
public function testValidateTokenFailures() {
$request = new RequestMock();
$request->hasHeader = false;
public function testValidateTokenFailures() {
$request = new RequestMock();
$request->hasHeader = false;
$actual = Auth::ValidateToken($request, new ResponseMock(), null);
$this->assertEquals(400, $actual->status);
$actual = Auth::ValidateToken($request, new ResponseMock(), null);
$this->assertEquals(400, $actual->status);
$actual = Auth::ValidateToken(new RequestMock(),
new ResponseMock(), null);
$this->assertEquals(401, $actual->status);
$actual = Auth::ValidateToken(new RequestMock(),
new ResponseMock(), null);
$this->assertEquals(401, $actual->status);
Auth::CreateInitialAdmin(new ContainerMock());
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
Auth::CreateInitialAdmin(new ContainerMock());
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$user = R::load('user', 1);
$user->active_token = 'whatever';
R::store($user);
$user = R::load('user', 1);
$user->active_token = 'whatever';
R::store($user);
$actual = Auth::ValidateToken($request, new ResponseMock(), null);
$this->assertEquals(401, $actual->status);
}
$actual = Auth::ValidateToken($request, new ResponseMock(), null);
$this->assertEquals(401, $actual->status);
}
public function testValidateToken() {
Auth::CreateInitialAdmin(new ContainerMock());
Auth::CreateJwtSigningKey();
public function testValidateToken() {
Auth::CreateInitialAdmin(new ContainerMock());
Auth::CreateJwtSigningKey();
$jwtKey = R::load('jwt', 1);
$admin = R::load('user', 1);
$jwtKey = R::load('jwt', 1);
$admin = R::load('user', 1);
$token = JWT::encode(array(
'exp' => time() + 600,
'uid' => 1,
'mul' => 1
), $jwtKey->secret);
$token = JWT::encode(array(
'exp' => time() + 600,
'uid' => 1,
'mul' => 1
), $jwtKey->secret);
$admin->active_token = $token;
R::store($admin);
$admin->active_token = $token;
R::store($admin);
$response = new ResponseMock();
$request = new RequestMock();
$request->header = [$token];
$response = new ResponseMock();
$request = new RequestMock();
$request->header = [$token];
Auth::ValidateToken($request, $response,
new ContainerMock());
$this->assertEquals(200, $response->status);
}
Auth::ValidateToken($request, $response,
new ContainerMock());
$this->assertEquals(200, $response->status);
}
public function testGetUserId() {
Auth::CreateJwtSigningKey();
$jwtKey = R::load('jwt', 1);
public function testGetUserId() {
Auth::CreateJwtSigningKey();
$jwtKey = R::load('jwt', 1);
$token = JWT::encode(array(
'exp' => time() + 600,
'uid' => 1,
'mul' => 1
), $jwtKey->secret);
$token = JWT::encode(array(
'exp' => time() + 600,
'uid' => 1,
'mul' => 1
), $jwtKey->secret);
$request = new RequestMock();
$request->header = [$token];
$request = new RequestMock();
$request->header = [$token];
$actual = Auth::GetUserId($request);
$this->assertEquals(1, $actual);
$actual = Auth::GetUserId($request);
$this->assertEquals(1, $actual);
$request->throwInHeader = true;
$actual = Auth::GetUserId($request);
$this->assertEquals(-1, $actual);
}
$request->throwInHeader = true;
$actual = Auth::GetUserId($request);
$this->assertEquals(-1, $actual);
}
public function testLogin() {
$data = new stdClass();
$data->username = 'admin';
$data->password = 'admin';
$data->remember = false;
public function testLogin() {
$data = new stdClass();
$data->username = 'admin';
$data->password = 'admin';
$data->remember = false;
$request = new RequestMock();
$request->payload = $data;
$request = new RequestMock();
$request->payload = $data;
$actual = $this->auth->login($request, new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
$actual = $this->auth->login($request, new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
$this->auth = new Auth(new ContainerMock());
Auth::CreateInitialAdmin(new ContainerMock());
Auth::CreateJwtSigningKey();
$this->auth = new Auth(new ContainerMock());
Auth::CreateInitialAdmin(new ContainerMock());
Auth::CreateJwtSigningKey();
$actual = $this->auth->login($request, new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
$actual = $this->auth->login($request, new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
$this->auth = new Auth(new ContainerMock());
$request->payload->password = 'asdf';
$this->auth = new Auth(new ContainerMock());
$request->payload->password = 'asdf';
$actual = $this->auth->login($request, new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
}
$actual = $this->auth->login($request, new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
}
public function testLogout() {
Auth::CreateInitialAdmin(new ContainerMock());
$data = new stdClass();
$data->username = 'admin';
$data->password = 'admin';
$data->remember = false;
public function testLogout() {
Auth::CreateInitialAdmin(new ContainerMock());
$data = new stdClass();
$data->username = 'admin';
$data->password = 'admin';
$data->remember = false;
$request = new RequestMock();
$request->payload = $data;
$request = new RequestMock();
$request->payload = $data;
$actual = $this->auth->login($request, new ResponseMock(), null);
$jwt = $actual->data[0];
$actual = $this->auth->login($request, new ResponseMock(), null);
$jwt = $actual->data[0];
$this->auth = new Auth(new ContainerMock());
$request = new RequestMock();
$request->header = [$jwt];
$this->auth = new Auth(new ContainerMock());
$request = new RequestMock();
$request->header = [$jwt];
$actual = $this->auth->logout($request, new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
}
$actual = $this->auth->logout($request, new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
}
public function testLogoutFailures() {
$actual = $this->auth->logout(new RequestMock(),
new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
public function testLogoutFailures() {
$actual = $this->auth->logout(new RequestMock(),
new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
$this->auth = new Auth(new ContainerMock());
$request = new RequestMock();
$request->hasHeader = false;
$this->auth = new Auth(new ContainerMock());
$request = new RequestMock();
$request->hasHeader = false;
$actual = $this->auth->logout($request, new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
}
$actual = $this->auth->logout($request, new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
}
public function testAuthenticate() {
$data = new stdClass();
$data->username = 'admin';
$data->password = 'admin';
$data->remember = false;
public function testAuthenticate() {
$data = new stdClass();
$data->username = 'admin';
$data->password = 'admin';
$data->remember = false;
$collapsed = R::dispense('collapsed');
$collapsed->user_id = 1;
$collapsed->column_id = 1;
R::store($collapsed);
$collapsed = R::dispense('collapsed');
$collapsed->user_id = 1;
$collapsed->column_id = 1;
R::store($collapsed);
$request = new RequestMock();
$request->payload = $data;
$request = new RequestMock();
$request->payload = $data;
Auth::CreateInitialAdmin(new ContainerMock());
Auth::CreateJwtSigningKey();
Auth::CreateInitialAdmin(new ContainerMock());
Auth::CreateJwtSigningKey();
$actual = $this->auth->login($request, new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
$actual = $this->auth->login($request, new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
$jwt = $actual->data[0];
$jwt = $actual->data[0];
$this->auth = new Auth(new ContainerMock());
$request = new RequestMock();
$request->header = [$jwt];
$this->auth = new Auth(new ContainerMock());
$request = new RequestMock();
$request->header = [$jwt];
$actual = $this->auth->authenticate($request, new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
$actual = $this->auth->authenticate($request, new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
$this->auth = new Auth(new ContainerMock());
$request->hasHeader = false;
$this->auth = new Auth(new ContainerMock());
$request->hasHeader = false;
$actual = $this->auth->authenticate($request, new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
$actual = $this->auth->authenticate($request, new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
$this->auth = new Auth(new ContainerMock());
$request = new RequestMock();
$request->header = ['not a valid JWT'];
$this->auth = new Auth(new ContainerMock());
$request = new RequestMock();
$request->header = ['not a valid JWT'];
$actual = $this->auth->authenticate($request, new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
}
$actual = $this->auth->authenticate($request, new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
}
public function testRefreshToken() {
$data = new stdClass();
$data->username = 'admin';
$data->password = 'admin';
$data->remember = false;
public function testRefreshToken() {
$data = new stdClass();
$data->username = 'admin';
$data->password = 'admin';
$data->remember = false;
$request = new RequestMock();
$request->payload = $data;
$request = new RequestMock();
$request->payload = $data;
Auth::CreateInitialAdmin(new ContainerMock());
Auth::CreateJwtSigningKey();
Auth::CreateInitialAdmin(new ContainerMock());
Auth::CreateJwtSigningKey();
$actual = $this->auth->login($request, new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
$actual = $this->auth->login($request, new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
$jwt = $actual->data[0];
$jwt = $actual->data[0];
$this->auth = new Auth(new ContainerMock());
$request = new RequestMock();
$request->header = [$jwt];
$this->auth = new Auth(new ContainerMock());
$request = new RequestMock();
$request->header = [$jwt];
$actual = $this->auth->refreshToken($request, new ResponseMock(), null);
$user = R::load('user', 1);
$actual = $this->auth->refreshToken($request, new ResponseMock(), null);
$user = R::load('user', 1);
$this->assertEquals('success', $actual->status);
$this->assertEquals($user->active_token, $actual->data[0]);
$this->assertEquals('success', $actual->status);
$this->assertEquals($user->active_token, $actual->data[0]);
$this->auth = new Auth(new ContainerMock());
$request->hasHeader = false;
$this->auth = new Auth(new ContainerMock());
$request->hasHeader = false;
$actual = $this->auth->refreshToken($request, new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
$actual = $this->auth->refreshToken($request, new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
$this->auth = new Auth(new ContainerMock());
$request = new RequestMock();
$request->header = ['not a valid JWT'];
$this->auth = new Auth(new ContainerMock());
$request = new RequestMock();
$request->header = ['not a valid JWT'];
$actual = $this->auth->refreshToken($request, new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
}
$actual = $this->auth->refreshToken($request, new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
}
}

View File

@ -3,197 +3,197 @@ require_once __DIR__ . '/../Mocks.php';
use RedBeanPHP\R;
class AutoActionsTest extends PHPUnit\Framework\TestCase {
private $actions;
private $actions;
public static function setupBeforeClass() {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
public static function setUpBeforeClass(): void {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
}
public function setUp() {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
public function setUp(): void {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
$this->actions = new AutoActions(new ContainerMock());
}
$this->actions = new AutoActions(new ContainerMock());
}
public function testGetAllActions() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
public function testGetAllActions() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->actions->getAllActions($request,
new ResponseMock(), null);
$this->assertEquals('No automatic actions in database.',
$actual->alerts[0]['text']);
$actual = $this->actions->getAllActions($request,
new ResponseMock(), null);
$this->assertEquals('No automatic actions in database.',
$actual->alerts[0]['text']);
$this->actions = new AutoActions(new ContainerMock());
$this->createAutoAction();
$this->actions = new AutoActions(new ContainerMock());
$this->createAutoAction();
$actual = $this->actions->getAllActions($request,
new ResponseMock(), null);
$this->assertEquals(1, count($actual->data[1]));
$this->assertEquals('success', $actual->status);
$actual = $this->actions->getAllActions($request,
new ResponseMock(), null);
$this->assertEquals(1, count($actual->data[1]));
$this->assertEquals('success', $actual->status);
DataMock::CreateStandardUser();
$this->actions = new AutoActions(new ContainerMock());
$request->header = [DataMock::GetJwt(2)];
DataMock::CreateStandardUser();
$this->actions = new AutoActions(new ContainerMock());
$request->header = [DataMock::GetJwt(2)];
$actual = $this->actions->getAllActions($request,
new ResponseMock(), null);
$this->assertEquals(0, count($actual->data[1]));
$this->assertEquals('failure', $actual->status);
}
$actual = $this->actions->getAllActions($request,
new ResponseMock(), null);
$this->assertEquals(0, count($actual->data[1]));
$this->assertEquals('failure', $actual->status);
}
public function testGetAllActionsUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testGetAllActionsUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->actions->getAllActions($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->actions->getAllActions($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testAddAction() {
$board = R::dispense('board');
R::store($board);
public function testAddAction() {
$board = R::dispense('board');
R::store($board);
$data = $this->getDefaultAction();
$data = $this->getDefaultAction();
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $data;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $data;
$actual = $this->actions->addAction($request,
new ResponseMock(), null);
$this->assertEquals('success', $actual->alerts[0]['type']);
}
$actual = $this->actions->addAction($request,
new ResponseMock(), null);
$this->assertEquals('success', $actual->alerts[0]['type']);
}
public function testAddActionUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testAddActionUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->actions->addAction($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->actions->addAction($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testAddActionInvalid() {
$request = new RequestMock();
$request->invalidPayload = true;
$request->header = [DataMock::GetJwt()];
public function testAddActionInvalid() {
$request = new RequestMock();
$request->invalidPayload = true;
$request->header = [DataMock::GetJwt()];
$actual = $this->actions->addAction($request,
new ResponseMock, null);
$this->assertEquals('failure', $actual->status);
}
$actual = $this->actions->addAction($request,
new ResponseMock, null);
$this->assertEquals('failure', $actual->status);
}
public function testAddActionForbidden() {
$board = R::dispense('board');
R::store($board);
public function testAddActionForbidden() {
$board = R::dispense('board');
R::store($board);
DataMock::CreateBoardAdminUser();
$data = $this->getDefaultAction();
DataMock::CreateBoardAdminUser();
$data = $this->getDefaultAction();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $data;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $data;
$actual = $this->actions->addAction($request,
new ResponseMock(), null);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$actual = $this->actions->addAction($request,
new ResponseMock(), null);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testRemoveAction() {
$this->createAutoAction();
public function testRemoveAction() {
$this->createAutoAction();
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->actions->removeAction($request,
new ResponseMock(), $args);
$this->assertEquals('Automatic action removed.',
$actual->alerts[0]['text']);
}
$actual = $this->actions->removeAction($request,
new ResponseMock(), $args);
$this->assertEquals('Automatic action removed.',
$actual->alerts[0]['text']);
}
public function testRemoveActionForbidden() {
$this->createAutoAction();
DataMock::CreateBoardAdminUser();
public function testRemoveActionForbidden() {
$this->createAutoAction();
DataMock::CreateBoardAdminUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$this->actions = new AutoActions(new ContainerMock());
$this->actions = new AutoActions(new ContainerMock());
$actual = $this->actions->removeAction($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$actual = $this->actions->removeAction($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testRemoveActionUnprivileged() {
DataMock::CreateUnprivilegedUser();
$this->createAutoAction();
public function testRemoveActionUnprivileged() {
DataMock::CreateUnprivilegedUser();
$this->createAutoAction();
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->actions->removeAction($request,
new ResponseMock(), $args);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->actions->removeAction($request,
new ResponseMock(), $args);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testRemovedActionInvalid() {
$args = [];
$args['id'] = 2; // No such action
public function testRemovedActionInvalid() {
$args = [];
$args['id'] = 2; // No such action
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->actions->removeAction($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $actual->status);
}
$actual = $this->actions->removeAction($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $actual->status);
}
private function getDefaultAction() {
$data = new stdClass();
$data->board_id = 1;
$data->trigger = ActionTrigger::ADDED_TO_CATEGORY;
$data->source_id = 1;
$data->type = ActionType::CLEAR_DUE_DATE;
$data->change_to = 'null';
private function getDefaultAction() {
$data = new stdClass();
$data->board_id = 1;
$data->trigger = ActionTrigger::ADDED_TO_CATEGORY;
$data->source_id = 1;
$data->type = ActionType::CLEAR_DUE_DATE;
$data->change_to = 'null';
return $data;
}
return $data;
}
private function createAutoAction() {
$auto_action = R::dispense('autoaction');
$auto_action->trigger = ActionTrigger::ADDED_TO_CATEGORY;
$auto_action->source_id = 1;
$auto_action->type = ActionType::CLEAR_DUE_DATE;
$auto_action->change_to = 'null';
private function createAutoAction() {
$auto_action = R::dispense('autoaction');
$auto_action->trigger = ActionTrigger::ADDED_TO_CATEGORY;
$auto_action->source_id = 1;
$auto_action->type = ActionType::CLEAR_DUE_DATE;
$auto_action->change_to = 'null';
$board = R::dispense('board');
$board->xownAutoActionList[] = $auto_action;
R::store($board);
}
$board = R::dispense('board');
$board->xownAutoActionList[] = $auto_action;
R::store($board);
}
}

View File

@ -3,370 +3,373 @@ require_once __DIR__ . '/../Mocks.php';
use RedBeanPHP\R;
class BoardsTest extends PHPUnit\Framework\TestCase {
private $boards;
private $boards;
public static function setupBeforeClass() {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
public static function setUpBeforeClass(): void {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
}
public function setUp() {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
public function setUp(): void {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
$this->boards = new Boards(new ContainerMock());
}
$this->boards = new Boards(new ContainerMock());
}
public function testGetAllBoards() {
$this->createBoard();
public function testGetAllBoards() {
$this->createBoard();
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$boards = $this->boards->getAllBoards($request,
new ResponseMock, null);
$this->assertEquals(2, count($boards->data));
$this->assertEquals('success', $boards->status);
}
$boards = $this->boards->getAllBoards($request,
new ResponseMock, null);
$this->assertEquals(2, count($boards->data));
$this->assertEquals('success', $boards->status);
}
public function testGetAllBoardsNotFound() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
public function testGetAllBoardsNotFound() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->boards->getAllBoards($request,
new ResponseMock(), null);
$this->assertEquals('No boards in database.',
$actual->alerts[0]['text']);
}
$actual = $this->boards->getAllBoards($request,
new ResponseMock(), null);
$this->assertEquals('No boards in database.',
$actual->alerts[0]['text']);
}
public function testGetAllBoardsUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testGetAllBoardsUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->getAllBoards($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->boards->getAllBoards($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testGetBoard() {
$this->createBoard();
public function testGetBoard() {
$this->createBoard();
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->boards->getBoard($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
$this->assertEquals(2, count($actual->data));
}
$actual = $this->boards->getBoard($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
$this->assertEquals(2, count($actual->data));
}
public function testGetBoardUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testGetBoardUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->getBoard($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->boards->getBoard($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testGetBoardNotFound() {
$args = [];
$args['id'] = 1;
public function testGetBoardNotFound() {
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->boards->getBoard($request,
new ResponseMock(), $args);
$this->assertEquals('No board found for ID 1.',
$actual->alerts[0]['text']);
}
$actual = $this->boards->getBoard($request,
new ResponseMock(), $args);
$this->assertEquals('No board found for ID 1.',
$actual->alerts[0]['text']);
}
public function testGetBoardForbidden() {
$this->createBoard();
DataMock::CreateBoardAdminUser();
public function testGetBoardForbidden() {
$this->createBoard();
DataMock::CreateBoardAdminUser();
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->getBoard($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$actual = $this->boards->getBoard($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testAddBoard() {
$data = $this->getBoardData();
public function testAddBoard() {
$data = $this->getBoardData();
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $data;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $data;
$actual = $this->boards->addBoard($request,
new ResponseMock(), null);
$actual = $this->boards->addBoard($request,
new ResponseMock(), null);
$this->assertEquals('Board test added.',
$actual->alerts[0]['text']);
}
$this->assertEquals('Board test added.',
$actual->alerts[0]['text']);
}
public function testAddBoardUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testAddBoardUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->addBoard($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->boards->addBoard($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testAddBoardInvalid() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->invalidPayload = true;
public function testAddBoardInvalid() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->invalidPayload = true;
$response = $this->boards->addBoard($request,
new ResponseMock(), null);
$response = $this->boards->addBoard($request,
new ResponseMock(), null);
$this->assertEquals('failure', $response->status);
$this->assertEquals('error', $response->alerts[0]['type']);
}
$this->assertEquals('failure', $response->status);
$this->assertEquals('error', $response->alerts[0]['type']);
}
public function testUpdateBoard() {
$board = $this->getBoardUpdateData();
public function testUpdateBoard() {
$board = $this->getBoardUpdateData();
$args = [];
$args['id'] = $board->id;
$args = [];
$args['id'] = $board->id;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $board;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $board;
$response = $this->boards->updateBoard($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
$response = $this->boards->updateBoard($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
public function testUpdateBoardUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testUpdateBoardUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->updateBoard($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->boards->updateBoard($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testUpdateBoardInvalid() {
$this->createBoard();
public function testUpdateBoardInvalid() {
$this->createBoard();
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->invalidPayload = true;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->invalidPayload = true;
$response = $this->boards->updateBoard($request,
new ResponseMock(), null);
$this->assertEquals('error', $response->alerts[0]['type']);
}
$response = $this->boards->updateBoard($request,
new ResponseMock(), null);
$this->assertEquals('error', $response->alerts[0]['type']);
}
public function testUpdateBoardColumn() {
$board = $this->getBoardUpdateData();
$board->columns[0]->name = 'changed';
public function testUpdateBoardColumn() {
$board = $this->getBoardUpdateData();
$board->columns[0]->name = 'changed';
$args = [];
$args['id'] = $board->id;
$args = [];
$args['id'] = $board->id;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $board;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $board;
$response = $this->boards->updateBoard($request,
new ResponseMock(), $args);
$response = $this->boards->updateBoard($request,
new ResponseMock(), $args);
$cols = $response->data[1][0]['ownColumn'];
$this->assertEquals('success', $response->status);
$this->assertEquals('changed', $cols[0]['name']);
}
public function testUpdateBoardNotFound() {
$this->createBoard();
$cols = $response->data[1][0]['ownColumn'];
$this->assertEquals('success', $response->status);
$this->assertEquals('changed', $cols[0]['name']);
}
public function testUpdateBoardNotFound() {
$this->createBoard();
$board = $this->getBoardData();
$board->id = 3;
unset($board->columns[0]->board_id);
unset($board->categories[0]->board_id);
unset($board->issue_trackers[0]->board_id);
$board = $this->getBoardData();
$board->id = 3;
unset($board->columns[0]->board_id);
unset($board->categories[0]->board_id);
unset($board->issue_trackers[0]->board_id);
$args = [];
$args['id'] = $board->id;
$args = [];
$args['id'] = $board->id;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $board;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $board;
$response = $this->boards->updateBoard($request,
new ResponseMock(), $args);
$this->assertEquals('error', $response->alerts[0]['type']);
}
$response = $this->boards->updateBoard($request,
new ResponseMock(), $args);
$this->assertEquals('error', $response->alerts[0]['type']);
}
public function testUpdateBoardForbidden() {
DataMock::CreateBoardAdminUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->updateBoard($request,
new ResponseMock(), null);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testUpdateBoardForbidden() {
DataMock::CreateBoardAdminUser();
public function testRemoveBoard() {
$this->createBoard();
$args = [];
$args['id'] = 1;
$action = R::dispense('autoaction');
$action->board_id = 1;
R::store($action);
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->boards->removeBoard($request,
new ResponseMock(), $args);
$this->assertEquals('Board test removed.',
$actual->alerts[0]['text']);
}
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
public function testRemoveBoardUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->removeBoard($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testRemoveBoardInvalid() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$args = [];
$args['id'] = 1; // No such board
$this->boards = new Boards(new ContainerMock());
$response = $this->boards->removeBoard($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
private function getBoardUpdateData() {
$this->createBoard();
$existing = R::load('board', 1);
$column = R::dispense('column');
$column->name = 'one';
$column->position = 1;
$existing->xownColumnList[] = $column;
$column = R::dispense('column');
$column->name = 'two';
$column->position = 2;
$existing->xownColumnList[] = $column;
$category = R::dispense('category');
$existing->xownCategoryList[] = $category;
R::store($existing);
$user = R::dispense('user');
$user->username = 'test';
R::store($user);
$board = $this->getBoardData();
$board->id = 1;
$newColumn = new stdClass();
$newColumn->name = 'col1';
$newColumn->position = 0;
$board->columns[] = $newColumn;
$board->users[] = $user->export();
$board->issue_trackers[0]->board_id = 1;
$board->categories = [];
return $board;
}
private function getBoardData() {
$board = new stdClass();
$tracker = new stdClass();
$category = new stdClass();
$column = new stdClass();
$column->name = 'col2';
$column->position = 1;
$column->id = 1;
$column->board_id = 1;
$category->name = 'cat 1';
$category->default_task_color = '';
$category->board_id = 1;
$tracker->url = 'testing';
$tracker->regex = '';
$tracker->board_id = 1;
$actual = $this->boards->updateBoard($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$board->name = 'test';
$board->is_active = true;
$board->sharedUserList[] = R::load('user', 1);
$board->issue_trackers[] = $tracker;
$board->categories[] = $category;
$board->columns[] = $column;
$board->users = [];
return $board;
}
private function createBoard() {
$board = R::dispense('board');
$column = R::dispense('column');
$task = R::dispense('task');
$task->sharedUserList[] = R::load('user', 1);
$column->name = 'test';
$column->position = 0;
$column->xownTaskList[] = $task;
$board->name = 'test';
$board->is_active = true;
$board->sharedUserList[] = R::load('user', 1);
$board->xownColumnList[] = $column;
R::store($board);
}
public function testRemoveBoard() {
$this->createBoard();
$args = [];
$args['id'] = 1;
$action = R::dispense('autoaction');
$action->board_id = 1;
R::store($action);
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->boards->removeBoard($request,
new ResponseMock(), $args);
$this->assertEquals('Board test removed.',
$actual->alerts[0]['text']);
}
public function testRemoveBoardUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->removeBoard($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testRemoveBoardInvalid() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$args = [];
$args['id'] = 1; // No such board
$this->boards = new Boards(new ContainerMock());
$response = $this->boards->removeBoard($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
private function getBoardUpdateData() {
$this->createBoard();
$existing = R::load('board', 1);
$column = R::dispense('column');
$column->name = 'one';
$column->position = 1;
$existing->xownColumnList[] = $column;
$column = R::dispense('column');
$column->name = 'two';
$column->position = 2;
$existing->xownColumnList[] = $column;
$category = R::dispense('category');
$existing->xownCategoryList[] = $category;
R::store($existing);
$user = R::dispense('user');
$user->username = 'test';
R::store($user);
$board = $this->getBoardData();
$board->id = 1;
$newColumn = new stdClass();
$newColumn->name = 'col1';
$newColumn->position = 0;
$board->columns[] = $newColumn;
$board->users[] = $user->export();
$board->issue_trackers[0]->board_id = 1;
$board->categories = [];
return $board;
}
private function getBoardData() {
$board = new stdClass();
$tracker = new stdClass();
$category = new stdClass();
$column = new stdClass();
$column->name = 'col2';
$column->position = 1;
$column->id = 1;
$column->board_id = 1;
$category->name = 'cat 1';
$category->default_task_color = '';
$category->board_id = 1;
$tracker->url = 'testing';
$tracker->regex = '';
$tracker->board_id = 1;
$board->name = 'test';
$board->is_active = true;
$board->sharedUserList[] = R::load('user', 1);
$board->issue_trackers[] = $tracker;
$board->categories[] = $category;
$board->columns[] = $column;
$board->users = [];
return $board;
}
private function createBoard() {
$board = R::dispense('board');
$column = R::dispense('column');
$task = R::dispense('task');
$task->sharedUserList[] = R::load('user', 1);
$column->name = 'test';
$column->position = 0;
$column->xownTaskList[] = $task;
$board->name = 'test';
$board->is_active = true;
$board->sharedUserList[] = R::load('user', 1);
$board->xownColumnList[] = $column;
R::store($board);
}
}

View File

@ -3,272 +3,279 @@ require_once __DIR__ . '/../Mocks.php';
use RedBeanPHP\R;
class ColumnsTest extends PHPUnit\Framework\TestCase {
private $columns;
private $columns;
public static function setupBeforeClass() {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
public static function setUpBeforeClass(): void {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
}
public function setUp() {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
public function setUp(): void {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
$this->columns = new Columns(new ContainerMock());
}
$this->columns = new Columns(new ContainerMock());
}
public function testGetColumn() {
$this->createColumn();
public function testGetColumn() {
$this->createColumn();
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$actual = $this->columns->getColumn($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
$this->assertEquals(2, count($actual->data));
}
$actual = $this->columns->getColumn($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
$this->assertEquals(2, count($actual->data));
}
public function testGetColumnNotFound() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
public function testGetColumnNotFound() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$actual = $this->columns->getColumn($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $actual->status);
}
$actual = $this->columns->getColumn($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $actual->status);
}
public function testGetColumnUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testGetColumnUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->columns->getColumn($request,
new ResponseMock(), null);
$actual = $this->columns->getColumn($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testGetColumnForbidden() {
$this->createColumn();
DataMock::CreateBoardAdminUser();
public function testGetColumnForbidden() {
$this->createColumn();
DataMock::CreateBoardAdminUser();
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->columns->getColumn($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$actual = $this->columns->getColumn($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testAddColumn() {
$board = R::dispense('board');
R::store($board);
public function testAddColumn() {
$board = R::dispense('board');
R::store($board);
$this->createColumn();
$data = $this->getColumnData();
$this->createColumn();
$data = $this->getColumnData();
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $data;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $data;
$actual = $this->columns->addColumn($request,
new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
}
$actual = $this->columns->addColumn($request,
new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
}
public function testAddColumnUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testAddColumnUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->columns->addColumn($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->columns->addColumn($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testAddColumnInvalid() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->invalidPayload = true;
public function testAddColumnInvalid() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->invalidPayload = true;
$response = $this->columns->addColumn($request,
new ResponseMock(), null);
$response = $this->columns->addColumn($request,
new ResponseMock(), null);
$this->assertEquals('failure', $response->status);
$this->assertEquals('error', $response->alerts[0]['type']);
}
$this->assertEquals('failure', $response->status);
$this->assertEquals('error', $response->alerts[0]['type']);
}
public function testAddColumnForbidden() {
$this->createColumn();
DataMock::CreateBoardAdminUser();
public function testAddColumnForbidden() {
$this->createColumn();
DataMock::CreateBoardAdminUser();
$column = $this->getColumnData();
$column->id = 0;
$column = $this->getColumnData();
$column->id = 0;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $column;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $column;
$actual = $this->columns->addColumn($request,
new ResponseMock(), null);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$actual = $this->columns->addColumn($request,
new ResponseMock(), null);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testUpdateColumn() {
$this->createColumn();
public function testUpdateColumn() {
$this->createColumn();
$column = $this->getColumnData();
$column->id = 1;
$column->name = 'updated';
$column = $this->getColumnData();
$column->id = 1;
$column->name = 'updated';
$args = [];
$args['id'] = $column->id;
$args = [];
$args['id'] = $column->id;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $column;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $column;
$response = $this->columns->updateColumn($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
$response = $this->columns->updateColumn($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
public function testUpdateColumnUnprivileged() {
$this->createColumn();
DataMock::CreateUnprivilegedUser();
public function testUpdateColumnUnprivileged() {
$this->createColumn();
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->columns->updateColumn($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->columns->updateColumn($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testUpdateColumnForbidden() {
$this->createColumn();
DataMock::CreateBoardAdminUser();
public function testUpdateColumnForbidden() {
$this->createColumn();
DataMock::CreateBoardAdminUser();
$column = $this->getColumnData();
$column->id = 1;
$column->name = 'test';
$column = $this->getColumnData();
$column->id = 1;
$column->name = 'test';
$args = [];
$args['id'] = $column->id;
$args = [];
$args['id'] = $column->id;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $column;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $column;
$this->columns = new Columns(new ContainerMock());
$this->columns = new Columns(new ContainerMock());
$actual = $this->columns->updateColumn($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$actual = $this->columns->updateColumn($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testUpdateColumnInvalid() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->invalidPayload = true;
public function testUpdateColumnInvalid() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->invalidPayload = true;
$response = $this->columns->updateColumn($request,
new ResponseMock(), null);
$this->assertEquals('error', $response->alerts[0]['type']);
}
$args = [];
$args['id'] = 1;
public function testRemoveColumn() {
$this->createColumn();
$response = $this->columns->updateColumn($request,
new ResponseMock(), $args);
$this->assertEquals('error', $response->alerts[0]['type']);
$args = [];
$args['id'] = 1;
$response = $this->columns->updateColumn($request,
new ResponseMock(), null);
$this->assertEquals('error', $response->alerts[0]['type']);
}
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
public function testRemoveColumn() {
$this->createColumn();
$actual = $this->columns->removeColumn($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
}
$args = [];
$args['id'] = 1;
public function testRemoveColumnUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->columns->removeColumn($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
}
$actual = $this->columns->removeColumn($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testRemoveColumnUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testRemoveColumnInvalid() {
$args = [];
$args['id'] = 1; // No such column
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->columns->removeColumn($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$response = $this->columns->removeColumn($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
public function testRemoveColumnInvalid() {
$args = [];
$args['id'] = 1; // No such column
public function testRemoveColumnForbidden() {
$this->createColumn();
DataMock::CreateBoardAdminUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$args = [];
$args['id'] = 1;
$response = $this->columns->removeColumn($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
public function testRemoveColumnForbidden() {
$this->createColumn();
DataMock::CreateBoardAdminUser();
$actual = $this->columns->removeColumn($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$args = [];
$args['id'] = 1;
private function getColumnData() {
$data = new stdClass();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$data->name = 'test';
$data->position = 0;
$data->board_id = 1;
$data->tasks = [];
$actual = $this->columns->removeColumn($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
return $data;
}
private function getColumnData() {
$data = new stdClass();
private function createColumn() {
$column = R::dispense('column');
$data->name = 'test';
$data->position = 0;
$data->board_id = 1;
$data->tasks = [];
$board = R::dispense('board');
$board->xownColumnList[] = $column;
return $data;
}
R::store($board);
}
private function createColumn() {
$column = R::dispense('column');
$board = R::dispense('board');
$board->xownColumnList[] = $column;
R::store($board);
}
}

View File

@ -3,313 +3,320 @@ require_once __DIR__ . '/../Mocks.php';
use RedBeanPHP\R;
class CommentsTest extends PHPUnit\Framework\TestCase {
private $comments;
private $comments;
public static function setupBeforeClass() {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
public static function setUpBeforeClass(): void {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
}
public function setUp() {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
public function setUp(): void {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
$this->comments = new Comments(new ContainerMock());
}
public function testGetComment() {
$this->createComment();
$this->comments = new Comments(new ContainerMock());
}
public function testGetComment() {
$this->createComment();
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$args = [];
$args['id'] = 1;
$actual = $this->comments->getComment($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
$this->assertEquals(2, count($actual->data));
}
public function testGetCommentNotFound() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$actual = $this->comments->getComment($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
$this->assertEquals(2, count($actual->data));
}
$actual = $this->comments->getComment($request,
new ResponseMock(), $args);
$this->assertEquals('No comment found for ID 1.',
$actual->alerts[0]['text']);
}
public function testGetCommentForbidden() {
$this->createComment();
DataMock::CreateBoardAdminUser();
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
public function testGetCommentNotFound() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$this->comments = new Comments(new ContainerMock());
$actual = $this->comments->getComment($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testGetCommentUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->comments->getComment($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testAddComment() {
$this->createComment();
$data = $this->getCommentData();
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $data;
$actual = $this->comments->addComment($request,
new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
}
public function testAddCommentUnprivileged() {
DataMock::CreateUnprivilegedUser();
$comment = $this->getCommentData();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $comment;
$actual = $this->comments->addComment($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testAddCommentInvalid() {
$request = new RequestMock();
$request->invalidPayload = true;
$request->header = [DataMock::GetJwt()];
$args = [];
$args['id'] = 1;
$actual = $this->comments->addComment($request,
new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
$this->assertEquals('error', $actual->alerts[0]['type']);
}
public function testAddCommentForbidden() {
$this->createComment();
DataMock::createBoardAdminUser();
$comment = $this->getCommentData();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $comment;
$actual = $this->comments->addComment($request,
new ResponseMock(), null);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testUpdateComment() {
$this->createComment();
$actual = $this->comments->getComment($request,
new ResponseMock(), $args);
$this->assertEquals('No comment found for ID 1.',
$actual->alerts[0]['text']);
}
public function testGetCommentForbidden() {
$this->createComment();
DataMock::CreateBoardAdminUser();
$args = [];
$args['id'] = 1;
$comment = $this->getCommentData();
$comment->id = 1;
$comment->text = 'updated';
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$this->comments = new Comments(new ContainerMock());
$actual = $this->comments->getComment($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$args = [];
$args['id'] = $comment->id;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $comment;
$response = $this->comments->updateComment($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
public function testGetCommentUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->comments->getComment($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testAddComment() {
$this->createComment();
$data = $this->getCommentData();
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $data;
$actual = $this->comments->addComment($request,
new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
}
public function testAddCommentUnprivileged() {
DataMock::CreateUnprivilegedUser();
$comment = $this->getCommentData();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $comment;
$actual = $this->comments->addComment($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testAddCommentInvalid() {
$request = new RequestMock();
$request->invalidPayload = true;
$request->header = [DataMock::GetJwt()];
public function testUpdateCommentInvalid() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->invalidPayload = true;
$actual = $this->comments->addComment($request,
new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
$this->assertEquals('error', $actual->alerts[0]['type']);
}
$args = [];
$args['id'] = 1;
$response = $this->comments->updateComment($request,
new ResponseMock(), $args);
$this->assertEquals('error', $response->alerts[0]['type']);
$response = $this->comments->updateComment($request,
new ResponseMock(), null);
$this->assertEquals('error', $response->alerts[0]['type']);
}
public function testUpdateCommentUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->comments->updateComment($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testUpdateCommentForbidden() {
$this->createComment();
DataMock::createBoardAdminUser();
public function testAddCommentForbidden() {
$this->createComment();
DataMock::createBoardAdminUser();
$comment = $this->getCommentData();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $comment;
$actual = $this->comments->addComment($request,
new ResponseMock(), null);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testUpdateComment() {
$this->createComment();
$comment = $this->getCommentData();
$comment->id = 1;
$comment->text = 'updated';
$args = [];
$args['id'] = $comment->id;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $comment;
$response = $this->comments->updateComment($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
public function testUpdateCommentInvalid() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->invalidPayload = true;
$comment = $this->getCommentData();
$comment->id = 1;
$comment->text = 'updated';
$response = $this->comments->updateComment($request,
new ResponseMock(), null);
$this->assertEquals('error', $response->alerts[0]['type']);
}
public function testUpdateCommentUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->comments->updateComment($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testUpdateCommentForbidden() {
$this->createComment();
DataMock::createBoardAdminUser();
$args = [];
$args['id'] = $comment->id;
$comment = $this->getCommentData();
$comment->id = 1;
$comment->text = 'updated';
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $comment;
$args = [];
$args['id'] = $comment->id;
$actual = $this->comments->updateComment($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $comment;
public function testUpdateCommentUserSecurity() {
$this->createComment();
DataMock::CreateStandardUser();
$actual = $this->comments->updateComment($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$args = [];
$args['id'] = 1;
public function testUpdateCommentUserSecurity() {
$this->createComment();
DataMock::CreateStandardUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$args = [];
$args['id'] = 1;
$actual = $this->comments->updateComment($request,
new ResponseMock(), $args);
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$this->assertEquals('You do not have sufficient permissions to ' .
'update this comment.', $actual->alerts[0]['text']);
}
$actual = $this->comments->updateComment($request,
new ResponseMock(), $args);
public function testRemoveComment() {
$this->createComment();
$this->assertEquals('You do not have sufficient permissions to ' .
'update this comment.', $actual->alerts[0]['text']);
}
$args = [];
$args['id'] = 1;
public function testRemoveComment() {
$this->createComment();
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$args = [];
$args['id'] = 1;
$actual = $this->comments->removeComment($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
}
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
public function testRemoveCommentUnprivileged() {
DataMock::CreateUnprivilegedUser();
$actual = $this->comments->removeComment($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
}
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
public function testRemoveCommentUnprivileged() {
DataMock::CreateUnprivilegedUser();
$actual = $this->comments->removeComment($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
public function testRemoveCommentInvalid() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->comments->removeComment($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$args = [];
$args['id'] = 1; // No such comment
public function testRemoveCommentInvalid() {
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$response = $this->comments->removeComment($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
$args = [];
$args['id'] = 1; // No such comment
public function testRemoveCommentForbidden() {
$this->createComment();
DataMock::CreateBoardAdminUser();
$response = $this->comments->removeComment($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
$args = [];
$args['id'] = 1;
public function testRemoveCommentForbidden() {
$this->createComment();
DataMock::CreateBoardAdminUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$args = [];
$args['id'] = 1;
$actual = $this->comments->removeComment($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
public function testRemoveCommentUserSecurity() {
$this->createComment();
DataMock::CreateStandardUser();
$actual = $this->comments->removeComment($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$args = [];
$args['id'] = 1;
public function testRemoveCommentUserSecurity() {
$this->createComment();
DataMock::CreateStandardUser();
$this->comments = new Comments(new ContainerMock());
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$this->comments = new Comments(new ContainerMock());
$actual = $this->comments->removeComment($request,
new ResponseMock(), $args);
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$this->assertEquals('You do not have sufficient permissions to ' .
'remove this comment.', $actual->alerts[0]['text']);
}
$actual = $this->comments->removeComment($request,
new ResponseMock(), $args);
$this->assertEquals('You do not have sufficient permissions to ' .
'remove this comment.', $actual->alerts[0]['text']);
}
private function getCommentData() {
$data = new stdClass();
$data->text = 'test comment';
$data->user_id = 1;
$data->task_id = 1;
$data->timestamp = time();
private function getCommentData() {
$data = new stdClass();
return $data;
}
$data->text = 'test comment';
$data->user_id = 1;
$data->task_id = 1;
$data->timestamp = time();
private function createComment() {
$comment = R::dispense('comment');
R::store($comment);
return $data;
}
$task = R::dispense('task');
$task->xownCommentList[] = $comment;
private function createComment() {
$comment = R::dispense('comment');
R::store($comment);
$column = R::dispense('column');
$column->xownTaskList[] = $task;
$task = R::dispense('task');
$task->xownCommentList[] = $comment;
$admin = R::load('user', 1);
$board = R::dispense('board');
$board->xownColumnList[] = $column;
$board->sharedUserList[] = $admin;
$column = R::dispense('column');
$column->xownTaskList[] = $task;
$admin = R::load('user', 1);
$board = R::dispense('board');
$board->xownColumnList[] = $column;
$board->sharedUserList[] = $admin;
R::store($board);
}
R::store($board);
}
}

View File

@ -3,436 +3,443 @@ require_once __DIR__ . '/../Mocks.php';
use RedBeanPHP\R;
class TasksTest extends PHPUnit\Framework\TestCase {
private $tasks;
private $tasks;
public static function setupBeforeClass() {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
public static function setUpBeforeClass(): void {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
}
public function setUp() {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
public function setUp(): void {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
$this->tasks = new Tasks(new ContainerMock());
}
$this->tasks = new Tasks(new ContainerMock());
}
public function testGetTask() {
$this->createTask();
public function testGetTask() {
$this->createTask();
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$actual = $this->tasks->getTask($request, new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
$this->assertEquals(2, count($actual->data));
}
$actual = $this->tasks->getTask($request, new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
$this->assertEquals(2, count($actual->data));
}
public function testGetTaskNotFound() {
$args = [];
$args['id'] = 1;
public function testGetTaskNotFound() {
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$actual = $this->tasks->getTask($request, new ResponseMock(), $args);
$this->assertEquals('No task found for ID 1.',
$actual->alerts[0]['text']);
$actual = $this->tasks->getTask($request, new ResponseMock(), $args);
$this->assertEquals('No task found for ID 1.',
$actual->alerts[0]['text']);
}
}
public function testGetTaskForbidden() {
$this->createTask();
DataMock::CreateBoardAdminUser();
public function testGetTaskForbidden() {
$this->createTask();
DataMock::CreateBoardAdminUser();
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::getJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::getJwt(2)];
$actual = $this->tasks->getTask($request, new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$actual = $this->tasks->getTask($request, new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testGetTaskUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testGetTaskUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::getJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::getJwt(2)];
$actual = $this->tasks->getTask($request, new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->tasks->getTask($request, new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testAddTask() {
$this->createTask();
$data = $this->getTaskData();
public function testAddTask() {
$this->createTask();
$data = $this->getTaskData();
$assignee = R::load('user', 1);
$data->assignees[] = $assignee;
$assignee = R::load('user', 1);
$data->assignees[] = $assignee;
$category = R::load('category', 1);
$category->name = 'Front End';
R::store($category);
$data->categories[] = $category;
$category = R::load('category', 1);
$category->name = 'Front End';
R::store($category);
$data->categories[] = $category;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $data;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $data;
$actual = $this->tasks->addTask($request, new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
}
$actual = $this->tasks->addTask($request, new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
}
public function testAddTaskTop() {
$this->createTask();
$data = $this->getTaskData();
public function testAddTaskTop() {
$this->createTask();
$data = $this->getTaskData();
$user = R::load('user', 1);
$opts = R::load('useroption', $user->user_option_id);
$user = R::load('user', 1);
$opts = R::load('useroption', $user->user_option_id);
$opts->new_tasks_at_bottom = false;
R::store($opts);
$opts->new_tasks_at_bottom = false;
R::store($opts);
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $data;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $data;
$actual = $this->tasks->addTask($request, new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
}
$actual = $this->tasks->addTask($request, new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
}
public function testAddTaskUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testAddTaskUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request= new RequestMock();
$request->header = [DataMock::getJwt(2)];
$request= new RequestMock();
$request->header = [DataMock::getJwt(2)];
$actual = $this->tasks->addTask($request, new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->tasks->addTask($request, new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testAddTaskInvalid() {
$request = new RequestMock();
$request->invalidPayload = true;
$request->header = [DataMock::getJwt()];
$response = $this->tasks->addTask($request,
new ResponseMock(), null);
$this->assertEquals('failure', $response->status);
$this->assertEquals('error', $response->alerts[0]['type']);
}
public function testAddTaskInvalid() {
$request = new RequestMock();
$request->invalidPayload = true;
$request->header = [DataMock::getJwt()];
public function testAddTaskForbidden() {
$this->createTask();
DataMock::CreateBoardAdminUser();
$response = $this->tasks->addTask($request,
new ResponseMock(), null);
$this->assertEquals('failure', $response->status);
$this->assertEquals('error', $response->alerts[0]['type']);
}
$task = $this->getTaskData();
$task->id = 0;
public function testAddTaskForbidden() {
$this->createTask();
DataMock::CreateBoardAdminUser();
$request = new RequestMock();
$request->header = [DataMock::getJwt(2)];
$request->payload = $task;
$task = $this->getTaskData();
$task->id = 0;
$actual = $this->tasks->addTask($request, new ResponseMock(), null);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testUpdateTask() {
$this->createTask();
$task = $this->getTaskData();
$task->id = 1;
$task->title = 'updated';
$args = [];
$args['id'] = $task->id;
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$request->payload = $task;
$response = $this->tasks->updateTask($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
$this->assertEquals('updated', $response->data[1][0]['title']);
}
public function testUpdateTaskWithActions() {
$this->addActions();
$this->createTask();
DataMock::CreateStandardUser();
$task = $this->getTaskData();
$task->id = 1;
$task->column_id = 2;
$task->title = 'updated';
$task->assignees = [];
$task->assignees[] = R::load('user', 2);
$task->categories = [];
$task->categories[] = R::load('category', 2);
$task->points = 5;
$task->due_date = '1/1/2017';
$request = new RequestMock();
$request->header = [DataMock::getJwt(2)];
$request->payload = $task;
$args = [];
$args['id'] = $task->id;
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$request->payload = $task;
$response = $this->tasks->updateTask($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
$updated = $response->data[1][0];
$this->assertEquals('updated', $updated['title']);
$this->assertEquals('#cdcdcd', $updated['color']);
$this->assertEquals(2, (int)$updated['sharedUser'][0]['id']);
$this->assertEquals('', $updated['due_date']);
$temp = R::load('task', 1);
$temp->due_date = '';
R::store($temp);
$task->column_id = 1;
$task->due_date ='';
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$request->payload = $task;
$actual = $this->tasks->addTask($request, new ResponseMock(), null);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testUpdateTask() {
$this->createTask();
$task = $this->getTaskData();
$task->id = 1;
$task->title = 'updated';
$args = [];
$args['id'] = $task->id;
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$request->payload = $task;
$response = $this->tasks->updateTask($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
$this->assertEquals('updated', $response->data[1][0]['title']);
}
public function testUpdateTaskWithActions() {
$this->addActions();
$this->createTask();
DataMock::CreateStandardUser();
$task = $this->getTaskData();
$task->id = 1;
$task->column_id = 2;
$task->title = 'updated';
$task->assignees = [];
$task->assignees[] = R::load('user', 2);
$task->categories = [];
$task->categories[] = R::load('category', 2);
$task->points = 5;
$task->due_date = '1/1/2017';
$response = $this->tasks->updateTask($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
public function testUpdateTaskInvalid() {
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$request->invalidPayload = true;
$response = $this->tasks->updateTask($request,
new ResponseMock(), null);
$this->assertEquals('error', $response->alerts[0]['type']);
}
public function testUpdateTaskUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::getJwt(2)];
$actual = $this->tasks->updateTask($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testUpdateTaskForbidden() {
$this->createTask();
DataMock::CreateBoardAdminUser();
$task = $this->getTaskData();
$task->id = 1;
$task->title = 'updated';
$args = [];
$args['id'] = $task->id;
$request = new RequestMock();
$request->header = [DataMock::getJwt(2)];
$request->payload = $task;
$actual = $this->tasks->updateTask($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testRemoveTask() {
$this->createTask();
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$actual = $this->tasks->removeTask($request,
new ResponseMock(), $args);
$this->assertEquals('Task test removed.', $actual->alerts[0]['text']);
}
public function testRemoveTaskUnprivileged() {
DataMock::CreateUnprivilegedUser();
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::getJwt(2)];
$actual = $this->tasks->removeTask($request,
new ResponseMock(), $args);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testRemoveTaskInvalid() {
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$args = [];
$args['id'] = 2; // No such task
$response = $this->tasks->removeTask($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
public function testRemoveTaskForbidden() {
$this->createTask();
DataMock::CreateBoardAdminUser();
$request = new RequestMock();
$request->header = [DataMock::getJwt(2)];
$args = [];
$args['id'] = 1;
$actual = $this->tasks->removeTask($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
private function addActions() {
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 1; // Moved to column
$action->source_id = 2; // Column ID
$action->type = 1; // Set color
$action->change_to = '#fff';
R::store($action);
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 2; // Assigned to user
$action->source_id = 2; // User ID
$action->type = 2; // Set category
$action->change_to = 2; // Category ID
R::store($action);
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 2; // Assigned to user
$action->source_id = 2; // User ID
$action->type = 3; // Add category
$action->change_to = 0; // Category ID
R::store($action);
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 3; // Assigned to category
$action->source_id = 2; // Category ID
$action->type = 4; // Set assignee
$action->change_to = 1; // User ID
R::store($action);
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 3; // Assigned to category
$action->source_id = 2; // Category ID
$action->type = 5; // Add assignee
$action->change_to = 0; // User ID
R::store($action);
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 3; // Assigned to category
$action->source_id = 2; // Category ID
$action->type = 6; // Clear due date
$action->change_to = 0;
R::store($action);
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 1; // Moved to column
$action->source_id = 1; // Category ID
$action->type = 6; // Clear due date
$action->change_to = 0;
R::store($action);
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 4; // Points changed
$action->source_id = 0;
$action->type = 7; // Alter color by points
$action->change_to = 0;
R::store($action);
}
private function getTaskData() {
$data = new stdClass();
$data->title = 'task';
$data->description = 'the words';
$data->column_id = 1;
$data->color = '';
$data->due_date = null;
$data->points = null;
$data->position = 0;
$data->comments = [];
$data->attachments = [];
$data->assignees = [];
$data->categories = [];
return $data;
}
private function createTask() {
$user = R::load('user', 1);
$task = R::dispense('task');
$task->title = 'test';
$task->sharedUserList[] = $user;
$column = R::dispense('column');
$column->xownTaskList[] = $task;
$column2 = R::dispense('column');
$category = R::dispense('category');
$category2 = R::dispense('category');
$board = R::dispense('board');
$board->xownColumnList[] = $column;
$board->xownColumnList[] = $column2;
$board->xownCategoryList[] = $category;
$board->xownCategoryList[] = $category2;
R::store($board);
}
$args = [];
$args['id'] = $task->id;
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$request->payload = $task;
$response = $this->tasks->updateTask($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
$updated = $response->data[1][0];
$this->assertEquals('updated', $updated['title']);
$this->assertEquals('#cdcdcd', $updated['color']);
$this->assertEquals(2, (int)$updated['sharedUser'][0]['id']);
$this->assertEquals('', $updated['due_date']);
$temp = R::load('task', 1);
$temp->due_date = '';
R::store($temp);
$task->column_id = 1;
$task->due_date ='';
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$request->payload = $task;
$response = $this->tasks->updateTask($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
public function testUpdateTaskInvalid() {
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$request->invalidPayload = true;
$args = [];
$args['id'] = 1;
$response = $this->tasks->updateTask($request,
new ResponseMock(), $args);
$this->assertEquals('error', $response->alerts[0]['type']);
$response = $this->tasks->updateTask($request,
new ResponseMock(), null);
$this->assertEquals('error', $response->alerts[0]['type']);
}
public function testUpdateTaskUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::getJwt(2)];
$actual = $this->tasks->updateTask($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testUpdateTaskForbidden() {
$this->createTask();
DataMock::CreateBoardAdminUser();
$task = $this->getTaskData();
$task->id = 1;
$task->title = 'updated';
$args = [];
$args['id'] = $task->id;
$request = new RequestMock();
$request->header = [DataMock::getJwt(2)];
$request->payload = $task;
$actual = $this->tasks->updateTask($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testRemoveTask() {
$this->createTask();
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$actual = $this->tasks->removeTask($request,
new ResponseMock(), $args);
$this->assertEquals('Task test removed.', $actual->alerts[0]['text']);
}
public function testRemoveTaskUnprivileged() {
DataMock::CreateUnprivilegedUser();
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::getJwt(2)];
$actual = $this->tasks->removeTask($request,
new ResponseMock(), $args);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testRemoveTaskInvalid() {
$request = new RequestMock();
$request->header = [DataMock::getJwt()];
$args = [];
$args['id'] = 2; // No such task
$response = $this->tasks->removeTask($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
public function testRemoveTaskForbidden() {
$this->createTask();
DataMock::CreateBoardAdminUser();
$request = new RequestMock();
$request->header = [DataMock::getJwt(2)];
$args = [];
$args['id'] = 1;
$actual = $this->tasks->removeTask($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
private function addActions() {
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 1; // Moved to column
$action->source_id = 2; // Column ID
$action->type = 1; // Set color
$action->change_to = '#fff';
R::store($action);
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 2; // Assigned to user
$action->source_id = 2; // User ID
$action->type = 2; // Set category
$action->change_to = 2; // Category ID
R::store($action);
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 2; // Assigned to user
$action->source_id = 2; // User ID
$action->type = 3; // Add category
$action->change_to = 0; // Category ID
R::store($action);
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 3; // Assigned to category
$action->source_id = 2; // Category ID
$action->type = 4; // Set assignee
$action->change_to = 1; // User ID
R::store($action);
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 3; // Assigned to category
$action->source_id = 2; // Category ID
$action->type = 5; // Add assignee
$action->change_to = 0; // User ID
R::store($action);
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 3; // Assigned to category
$action->source_id = 2; // Category ID
$action->type = 6; // Clear due date
$action->change_to = 0;
R::store($action);
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 1; // Moved to column
$action->source_id = 1; // Category ID
$action->type = 6; // Clear due date
$action->change_to = 0;
R::store($action);
$action = R::dispense('autoaction');
$action->board_id = 1;
$action->trigger = 4; // Points changed
$action->source_id = 0;
$action->type = 7; // Alter color by points
$action->change_to = 0;
R::store($action);
}
private function getTaskData() {
$data = new stdClass();
$data->title = 'task';
$data->description = 'the words';
$data->column_id = 1;
$data->color = '';
$data->due_date = null;
$data->points = null;
$data->position = 0;
$data->comments = [];
$data->attachments = [];
$data->assignees = [];
$data->categories = [];
return $data;
}
private function createTask() {
$user = R::load('user', 1);
$task = R::dispense('task');
$task->title = 'test';
$task->sharedUserList[] = $user;
$column = R::dispense('column');
$column->xownTaskList[] = $task;
$column2 = R::dispense('column');
$category = R::dispense('category');
$category2 = R::dispense('category');
$board = R::dispense('board');
$board->xownColumnList[] = $column;
$board->xownColumnList[] = $column2;
$board->xownCategoryList[] = $category;
$board->xownCategoryList[] = $category2;
R::store($board);
}
}

View File

@ -3,546 +3,546 @@ require_once __DIR__ . '/../Mocks.php';
use RedBeanPHP\R;
class UsersTest extends PHPUnit\Framework\TestCase {
private $users;
private $users;
public static function setupBeforeClass() {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
public static function setUpBeforeClass(): void {
try {
R::setup('sqlite:tests.db');
} catch (Exception $ex) {
}
}
public function setUp() {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
public function setUp(): void {
R::nuke();
Auth::CreateInitialAdmin(new ContainerMock());
$this->users = new Users(new ContainerMock());
}
$this->users = new Users(new ContainerMock());
}
public function testGetAllUsers() {
$this->createUser();
public function testGetAllUsers() {
$this->createUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->users->getAllUsers($request,
new ResponseMock(), null);
$this->assertEquals(2, count($actual->data[1]));
$actual = $this->users->getAllUsers($request,
new ResponseMock(), null);
$this->assertEquals(2, count($actual->data[1]));
DataMock::CreateUnprivilegedUser();
DataMock::CreateUnprivilegedUser();
$this->users = new Users(new ContainerMock());
$request = new RequestMock();
$request->header = [DataMock::GetJwt(3)];
$this->users = new Users(new ContainerMock());
$request = new RequestMock();
$request->header = [DataMock::GetJwt(3)];
$actual = $this->users->getAllUsers($request,
new ResponseMock(), null);
$this->assertEquals('error', $actual->alerts[0]['type']);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->users->getAllUsers($request,
new ResponseMock(), null);
$this->assertEquals('error', $actual->alerts[0]['type']);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testGetUser() {
$this->createUser();
public function testGetUser() {
$this->createUser();
$args = [];
$args['id'] = 2;
$args = [];
$args['id'] = 2;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->users->getUser($request,
new ResponseMock(), $args);
$actual = $this->users->getUser($request,
new ResponseMock(), $args);
$this->assertEquals('success', $actual->status);
$this->assertEquals(2, count($actual->data));
}
$this->assertEquals('success', $actual->status);
$this->assertEquals(2, count($actual->data));
}
public function testGetUserUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testGetUserUnprivileged() {
DataMock::CreateUnprivilegedUser();
$args = [];
$args['id'] = 2;
$args = [];
$args['id'] = 2;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->users->getUser($request,
new ResponseMock(), $args);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->users->getUser($request,
new ResponseMock(), $args);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testGetUserNotFound() {
$args = [];
$args['id'] = 2;
public function testGetUserNotFound() {
$args = [];
$args['id'] = 2;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->users->getUser($request,
new ResponseMock(), $args);
$this->assertEquals('No user found for ID 2.',
$actual->alerts[0]['text']);
}
$actual = $this->users->getUser($request,
new ResponseMock(), $args);
$this->assertEquals('No user found for ID 2.',
$actual->alerts[0]['text']);
}
public function testGetUserForbidden() {
$this->createUser();
DataMock::CreateStandardUser('nono');
public function testGetUserForbidden() {
$this->createUser();
DataMock::CreateStandardUser('nono');
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(3)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(3)];
$this->users = new Users(new ContainerMock());
$this->users = new Users(new ContainerMock());
$actual = $this->users->getUser($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
$actual = $this->users->getUser($request,
new ResponseMock(), $args);
$this->assertEquals('Access restricted.',
$actual->alerts[0]['text']);
}
public function testAddUser() {
$board = R::dispense('board');
R::store($board);
public function testAddUser() {
$board = R::dispense('board');
R::store($board);
$user = $this->getUserData();
$user->default_board_id = $board->id;
$user = $this->getUserData();
$user->default_board_id = $board->id;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $user;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $user;
$actual = $this->users->addUser($request,
new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
}
$actual = $this->users->addUser($request,
new ResponseMock(), null);
$this->assertEquals('success', $actual->status);
}
public function testAddDuplicateUser() {
$user = $this->getUserData();
$user->username = 'admin';
public function testAddDuplicateUser() {
$user = $this->getUserData();
$user->username = 'admin';
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $user;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $user;
$actual = $this->users->addUser($request,
new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
}
$actual = $this->users->addUser($request,
new ResponseMock(), null);
$this->assertEquals('failure', $actual->status);
}
public function testAddUserUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testAddUserUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$actual = $this->users->addUser($request,
new ResponseMock(), $args);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->users->addUser($request,
new ResponseMock(), $args);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testAddBadUser() {
$request = new RequestMock();
$request->invalidPayload = true;
$request->header = [DataMock::GetJwt()];
public function testAddBadUser() {
$request = new RequestMock();
$request->invalidPayload = true;
$request->header = [DataMock::GetJwt()];
$response = $this->users->addUser($request,
new ResponseMock(), null);
$response = $this->users->addUser($request,
new ResponseMock(), null);
$this->assertEquals('failure', $response->status);
$this->assertEquals('error', $response->alerts[0]['type']);
}
$this->assertEquals('failure', $response->status);
$this->assertEquals('error', $response->alerts[0]['type']);
}
public function testUpdateUser() {
$this->createUser();
public function testUpdateUser() {
$this->createUser();
$user = $this->getUserData();
$user->id = 2;
$user->username = 'newname';
$user->default_board_id = 1;
$user->password = 'test';
$user->boardAccess = [2];
$user = $this->getUserData();
$user->id = 2;
$user->username = 'newname';
$user->default_board_id = 1;
$user->password = 'test';
$user->boardAccess = [2];
$args = [];
$args['id'] = $user->id;
$args = [];
$args['id'] = $user->id;
$request = new RequestMock();
$request->payload = $user;
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->payload = $user;
$request->header = [DataMock::GetJwt()];
$response = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
$response = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
public function testUpdateUserRemoveDefaultBoard() {
$this->createUser();
public function testUpdateUserRemoveDefaultBoard() {
$this->createUser();
$user = $this->getUserData();
$user->id = 2;
$user->boardAccess = [1];
$user = $this->getUserData();
$user->id = 2;
$user->boardAccess = [1];
$args = [];
$args['id'] = $user->id;
$args = [];
$args['id'] = $user->id;
$request = new RequestMock();
$request->payload = $user;
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->payload = $user;
$request->header = [DataMock::GetJwt()];
$response = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
$response = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
public function testUpdateUserPassword() {
$this->createUser();
public function testUpdateUserPassword() {
$this->createUser();
$board = R::dispense('board');
R::store($board);
$board = R::dispense('board');
R::store($board);
$user = $this->getUserData();
$user->id = 2;
$user->new_password = 'updated';
$user->old_password = 'test';
$user->default_board_id = 2;
$user->boardAccess = [];
$user = $this->getUserData();
$user->id = 2;
$user->new_password = 'updated';
$user->old_password = 'test';
$user->default_board_id = 2;
$user->boardAccess = [];
$args = [];
$args['id'] = $user->id;
$args = [];
$args['id'] = $user->id;
$request = new RequestMock();
$request->payload = $user;
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->payload = $user;
$request->header = [DataMock::GetJwt()];
$response = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
$response = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
public function testUpdateUserBadPassword() {
$this->createUser();
public function testUpdateUserBadPassword() {
$this->createUser();
$user = $this->getUserData();
$user->id = 2;
$user->new_password = 'updated';
$user->old_password = 'wrong';
$user = $this->getUserData();
$user->id = 2;
$user->new_password = 'updated';
$user->old_password = 'wrong';
$args = [];
$args['id'] = $user->id;
$args = [];
$args['id'] = $user->id;
$request = new RequestMock();
$request->payload = $user;
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->payload = $user;
$request->header = [DataMock::GetJwt()];
$response = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
$response = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
public function testUpdateUserInvalid() {
$this->createUser();
public function testUpdateUserInvalid() {
$this->createUser();
$user = $this->getUserData();
$user->id = 2;
$user->username = 'newname';
$user->default_board_id = 1;
$user = $this->getUserData();
$user->id = 2;
$user->username = 'newname';
$user->default_board_id = 1;
$args = [];
$args['id'] = $user->id;
$args = [];
$args['id'] = $user->id;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->invalidPayload = true;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->invalidPayload = true;
$response = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('error', $response->alerts[0]['type']);
}
$response = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('error', $response->alerts[0]['type']);
}
public function testUpdateUserUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testUpdateUserUnprivileged() {
DataMock::CreateUnprivilegedUser();
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->users->updateUser($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->users->updateUser($request,
new ResponseMock(), null);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testUpdateUserRestricted() {
$this->createUser();
public function testUpdateUserRestricted() {
$this->createUser();
$user = $this->getUserData();
$user->id = 1;
$user = $this->getUserData();
$user->id = 1;
$args = [];
$args['id'] = $user->id;
$args = [];
$args['id'] = $user->id;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $user;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $user;
$actual = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $actual->status);
}
$actual = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $actual->status);
}
public function testUpdateUserBadId() {
$this->createUser();
public function testUpdateUserBadId() {
$this->createUser();
$user = $this->getUserData();
$user->id = 2;
$user->username = 'newname';
$user->default_board_id = 1;
$user = $this->getUserData();
$user->id = 2;
$user->username = 'newname';
$user->default_board_id = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $user;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request->payload = $user;
$args = [];
$args['id'] = $user->id + 1;
$args = [];
$args['id'] = $user->id + 1;
$response = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
$response = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
public function testUpdateUserNameInUse() {
$this->createUser();
public function testUpdateUserNameInUse() {
$this->createUser();
$user = $this->getUserData();
$user->id = 2;
$user->username = 'admin';
$user = $this->getUserData();
$user->id = 2;
$user->username = 'admin';
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $user;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request->payload = $user;
$args = [];
$args['id'] = $user->id;
$args = [];
$args['id'] = $user->id;
$response = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
$response = $this->users->updateUser($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
public function testUpdateUserOptions() {
$this->createUser();
public function testUpdateUserOptions() {
$this->createUser();
$args = [];
$args['id'] = 2;
$args = [];
$args['id'] = 2;
$opts = $this->getUserOptionData();
$opts->id = 2;
$opts->new_tasks_at_bottom = false;
$opts = $this->getUserOptionData();
$opts->id = 2;
$opts->new_tasks_at_bottom = false;
$request = new RequestMock();
$request->payload = $opts;
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->payload = $opts;
$request->header = [DataMock::GetJwt(2)];
$response = $this->users->updateUserOptions($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
$response = $this->users->updateUserOptions($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
public function testUpdateUserOptionsRestricted() {
$this->createUser();
public function testUpdateUserOptionsRestricted() {
$this->createUser();
$args = [];
$args['id'] = 1;
$args = [];
$args['id'] = 1;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$this->users = new Users(new ContainerMock());
$response = $this->users->updateUserOptions($request,
new ResponseMock(), $args);
$this->users = new Users(new ContainerMock());
$response = $this->users->updateUserOptions($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
$this->assertEquals('Access restricted.',
$response->alerts[0]['text']);
}
$this->assertEquals('failure', $response->status);
$this->assertEquals('Access restricted.',
$response->alerts[0]['text']);
}
public function testUpdateUserOptionsUnprivileged() {
DataMock::createUnprivilegedUser();
public function testUpdateUserOptionsUnprivileged() {
DataMock::createUnprivilegedUser();
$data = $this->getUserOptionData();
$data->id = 2;
$data = $this->getUserOptionData();
$data->id = 2;
$args = [];
$args['id'] = 2;
$args = [];
$args['id'] = 2;
$request = new RequestMock();
$request->payload = $data;
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->payload = $data;
$request->header = [DataMock::GetJwt(2)];
$response = $this->users->updateUserOptions($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
$response = $this->users->updateUserOptions($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
public function testUpdateUserOptionsBadId() {
$this->createUser();
public function testUpdateUserOptionsBadId() {
$this->createUser();
$data = new stdClass();
$data->id = 2; // No such user options
$data = new stdClass();
$data->id = 2; // No such user options
$args = [];
$args['id'] = 2;
$args = [];
$args['id'] = 2;
$request = new RequestMock();
$request->payload = $data;
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->payload = $data;
$request->header = [DataMock::GetJwt(2)];
$response = $this->users->updateUserOptions($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
$response = $this->users->updateUserOptions($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
public function testToggleCollapsed() {
$this->createUser();
public function testToggleCollapsed() {
$this->createUser();
$data = new stdClass();
$data->id = 1;
$data = new stdClass();
$data->id = 1;
$args = [];
$args['id'] = 2;
$args = [];
$args['id'] = 2;
$request = new RequestMock();
$request->payload = $data;
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->payload = $data;
$request->header = [DataMock::GetJwt(2)];
// Collapse the column
$response = $this->users->toggleCollapsed($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
// Collapse the column
$response = $this->users->toggleCollapsed($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
// Expand the column
$response = $this->users->toggleCollapsed($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
// Expand the column
$response = $this->users->toggleCollapsed($request,
new ResponseMock(), $args);
$this->assertEquals('success', $response->status);
}
public function testToggleCollapsedNoAccess() {
$response = $this->users->toggleCollapsed(new RequestMock(),
new ResponseMock(), null);
public function testToggleCollapsedNoAccess() {
$response = $this->users->toggleCollapsed(new RequestMock(),
new ResponseMock(), null);
$this->assertEquals('failure', $response->status);
$this->assertEquals('failure', $response->status);
$data = new stdClass();
$data->id = 1;
$data = new stdClass();
$data->id = 1;
$args = [];
$args['id'] = 2;
$args = [];
$args['id'] = 2;
$request = new RequestMock();
$request->payload = $data;
$request->header = [DataMock::GetJwt(1)];
$request = new RequestMock();
$request->payload = $data;
$request->header = [DataMock::GetJwt(1)];
$response = $this->users->toggleCollapsed($request,
new ResponseMock(), $args);
$response = $this->users->toggleCollapsed($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
$this->assertEquals('failure', $response->status);
}
public function testRemoveUser() {
$this->createUser();
public function testRemoveUser() {
$this->createUser();
$args = [];
$args['id'] = 2;
$args = [];
$args['id'] = 2;
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$actual = $this->users->removeUser($request,
new ResponseMock(), $args);
$actual = $this->users->removeUser($request,
new ResponseMock(), $args);
$this->assertEquals('User tester removed.',
$actual->alerts[0]['text']);
}
$this->assertEquals('User tester removed.',
$actual->alerts[0]['text']);
}
public function testRemoveUserUnprivileged() {
DataMock::CreateUnprivilegedUser();
public function testRemoveUserUnprivileged() {
DataMock::CreateUnprivilegedUser();
$args = [];
$args['id'] = 2;
$args = [];
$args['id'] = 2;
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$request = new RequestMock();
$request->header = [DataMock::GetJwt(2)];
$actual = $this->users->removeUser($request,
new ResponseMock(), $args);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
$actual = $this->users->removeUser($request,
new ResponseMock(), $args);
$this->assertEquals('Insufficient privileges.',
$actual->alerts[0]['text']);
}
public function testRemoveBadUser() {
$args = [];
$args['id'] = 2; // No such user
public function testRemoveBadUser() {
$args = [];
$args['id'] = 2; // No such user
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$request = new RequestMock();
$request->header = [DataMock::GetJwt()];
$response = $this->users->removeUser($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
$response = $this->users->removeUser($request,
new ResponseMock(), $args);
$this->assertEquals('failure', $response->status);
}
private function getUserData() {
$data = new stdClass();
private function getUserData() {
$data = new stdClass();
$data->security_level = SecurityLevel::USER;
$data->username = 'tester';
$data->email = '';
$data->default_board_id = 0;
$data->user_option_id = 0;
$data->last_login = 0;
$data->active_token = '';
$data->security_level = SecurityLevel::USER;
$data->username = 'tester';
$data->email = '';
$data->default_board_id = 0;
$data->user_option_id = 0;
$data->last_login = 0;
$data->active_token = '';
$data->password = 'test';
$data->password_verify = 'test';
$data->password = 'test';
$data->password_verify = 'test';
return $data;
}
return $data;
}
private function getUserOptionData() {
$data = new stdClass();
private function getUserOptionData() {
$data = new stdClass();
$data->new_tasks_at_bottom = true;
$data->show_animations = true;
$data->show_assignee = true;
$data->multiple_tasks_per_row = false;
$data->language = "en";
$data->new_tasks_at_bottom = true;
$data->show_animations = true;
$data->show_assignee = true;
$data->multiple_tasks_per_row = false;
$data->language = "en";
return $data;
}
return $data;
}
private function createUser() {
$opts = R::dispense('useroption');
R::store($opts);
private function createUser() {
$opts = R::dispense('useroption');
R::store($opts);
$user = R::dispense('user');
$user->security_level = SecurityLevel::USER;
$user->username = 'tester';
$user->default_board_id = 1;
$user->password_hash = password_hash('test', PASSWORD_BCRYPT);
$user->user_option_id = $opts->id;
$user = R::dispense('user');
$user->security_level = SecurityLevel::USER;
$user->username = 'tester';
$user->default_board_id = 1;
$user->password_hash = password_hash('test', PASSWORD_BCRYPT);
$user->user_option_id = $opts->id;
$admin = R::load('user', 1);
$board = R::dispense('board');
$board->sharedUserList[] = $admin;
$board->sharedUserList[] = $user;
R::store($board);
}
$admin = R::load('user', 1);
$board = R::dispense('board');
$board->sharedUserList[] = $admin;
$board->sharedUserList[] = $user;
R::store($board);
}
}

View File

@ -1,6 +1,6 @@
<phpunit>
<testsuites>
<testsuite>
<testsuite name="api">
<directory>./</directory>
</testsuite>
</testsuites>

View File

@ -82,7 +82,7 @@ describe('ApiInterceptor', () => {
it('handles errors and clears the JWT',
inject([HttpClient, HttpTestingController],
(http: HttpClient, httpMock: HttpTestingController) => {
sessionStorage.setItem('taskboard.jwt', 'fake');
sessionStorage.setItem('taskboard.jwt', null);
http.get('').subscribe(response => {
expect(response).toBeTruthy();

View File

@ -41,180 +41,186 @@ describe('BoardService', () => {
expect(service).toBeTruthy();
});
// it('lets the active board get updated', () => {
// let changed = false;
//
// service.activeBoardChanged.subscribe(() => (changed = true));
//
// service.updateActiveBoard(<any>{});
//
// expect(changed).toEqual(true);
// });
//
// it('gets all boards', () => {
// service.getBoards().subscribe(response => {
// expect(response.data.length).toEqual(0);
// });
//
// testCall('api/boards', 'GET');
// });
//
// it('handles errors when getting all boards', () => {
// service.getBoards().subscribe(() => {}, response => {
// expect(response.alerts.length).toEqual(1);
// });
//
// testCall('api/boards', 'GET', true);
// });
//
// it('toggles the collapsed state of a column', () => {
// service.toggleCollapsed(1, 1).subscribe(response => {
// expect(response.data.length).toEqual(0);
// });
//
// testCall('api/users/1/cols', 'POST');
// });
//
// it('handles error when toggling collapse', () => {
// service.toggleCollapsed(1, 1).subscribe(() => {}, response => {
// expect(response.alerts.length).toEqual(1);
// });
//
// testCall('api/users/1/cols', 'POST', true);
// });
//
// it('updates a board', () => {
// service.updateBoard(<any>{ id: 1 }).subscribe(response => {
// expect(response.data.length).toEqual(0);
// });
//
// testCall('api/boards/1', 'POST');
// });
//
// it('handles errors on board update', () => {
// service.updateBoard(<any>{ id: 1 }).subscribe(() => {}, response => {
// expect(response.alerts.length).toEqual(1);
// });
//
// testCall('api/boards/1', 'POST', true);
// });
//
// it('updates a column', () => {
// service.updateColumn(<any>{ id: 1 }).subscribe(response => {
// expect(response.data.length).toEqual(0);
// });
//
// testCall('api/columns/1', 'POST');
// });
//
// it('handles errors on column update', () => {
// service.updateColumn(<any>{ id: 1 }).subscribe(() => {}, response => {
// expect(response.alerts.length).toEqual(1);
// });
//
// testCall('api/columns/1', 'POST', true);
// });
//
// it('adds a task', () => {
// service.addTask(<any>{}).subscribe(response => {
// expect(response.data.length).toEqual(0);
// });
//
// testCall('api/tasks', 'POST');
// });
//
// it('handles errors on task add', () => {
// service.addTask(<any>{}).subscribe(() => {}, response => {
// expect(response.alerts.length).toEqual(1);
// });
//
// testCall('api/tasks', 'POST', true);
// });
//
// it('updates a task', () => {
// service.updateTask(<any>{ id: 1 }).subscribe(response => {
// expect(response.data.length).toEqual(0);
// });
//
// testCall('api/tasks/1', 'POST');
// });
//
// it('handles errors on task update', () => {
// service.updateTask(<any>{ id: 1 }).subscribe(() => {}, response => {
// expect(response.alerts.length).toEqual(1);
// });
//
// testCall('api/tasks/1', 'POST', true);
// });
//
// it('removes a task', () => {
// service.removeTask(1).subscribe(response => {
// expect(response.data.length).toEqual(0);
// });
//
// testCall('api/tasks/1', 'DELETE');
// });
//
// it('handles errors on task removal', () => {
// service.removeTask(1).subscribe(() => {}, response => {
// expect(response.alerts.length).toEqual(1);
// });
//
// testCall('api/tasks/1', 'DELETE', true);
// });
//
// it('gets task activity', () => {
// service.getTaskActivity(1).subscribe(response => {
// expect(response.data.length).toEqual(0);
// });
//
// testCall('api/activity/task/1', 'GET');
// });
//
// it('handles errors on get task activity', () => {
// service.getTaskActivity(1).subscribe(() => {}, response => {
// expect(response.alerts.length).toEqual(1);
// });
//
// testCall('api/activity/task/1', 'GET', true);
// });
//
// it('updates a comment', () => {
// service.updateComment(<any>{ id: 1 }).subscribe(response => {
// expect(response.data.length).toEqual(0);
// });
//
// testCall('api/comments/1', 'POST');
// });
//
// it('handles errors on comment update', () => {
// service.updateComment(<any>{ id: 1 }).subscribe(() => {}, response => {
// expect(response.alerts.length).toEqual(1);
// });
//
// testCall('api/comments/1', 'POST', true);
// });
//
// it('removes a comment', () => {
// service.removeComment(1).subscribe(response => {
// expect(response.data.length).toEqual(0);
// });
//
// testCall('api/comments/1', 'DELETE');
// });
//
// it('handles errors on comment removal', () => {
// service.removeComment(1).subscribe(() => {}, response => {
// expect(response.alerts.length).toEqual(1);
// });
//
// testCall('api/comments/1', 'DELETE', true);
// });
//
// it('refreshes the API token', () => {
// service.refreshToken();
// testCall('api/refresh', 'POST');
// });
it('lets the active board get updated', () => {
let changed = false;
service.activeBoardChanged.subscribe(() => (changed = true));
service.updateActiveBoard(<any>{});
expect(changed).toEqual(true);
});
it('gets all boards', () => {
service.getBoards().subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/boards', 'GET');
});
it('converts markdown', () => {
const actual = service.convertMarkdown('# Test');
expect(actual.html).toEqual('<h1 id="test">Test</h1>\n');
});
it('handles errors when getting all boards', () => {
service.getBoards().subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/boards', 'GET', true);
});
it('toggles the collapsed state of a column', () => {
service.toggleCollapsed(1, 1).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/users/1/cols', 'POST');
});
it('handles error when toggling collapse', () => {
service.toggleCollapsed(1, 1).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/users/1/cols', 'POST', true);
});
it('updates a board', () => {
service.updateBoard(<any>{ id: 1 }).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/boards/1', 'POST');
});
it('handles errors on board update', () => {
service.updateBoard(<any>{ id: 1 }).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/boards/1', 'POST', true);
});
it('updates a column', () => {
service.updateColumn(<any>{ id: 1 }).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/columns/1', 'POST');
});
it('handles errors on column update', () => {
service.updateColumn(<any>{ id: 1 }).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/columns/1', 'POST', true);
});
it('adds a task', () => {
service.addTask(<any>{}).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/tasks', 'POST');
});
it('handles errors on task add', () => {
service.addTask(<any>{}).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/tasks', 'POST', true);
});
it('updates a task', () => {
service.updateTask(<any>{ id: 1 }).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/tasks/1', 'POST');
});
it('handles errors on task update', () => {
service.updateTask(<any>{ id: 1 }).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/tasks/1', 'POST', true);
});
it('removes a task', () => {
service.removeTask(1).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/tasks/1', 'DELETE');
});
it('handles errors on task removal', () => {
service.removeTask(1).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/tasks/1', 'DELETE', true);
});
it('gets task activity', () => {
service.getTaskActivity(1).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/activity/task/1', 'GET');
});
it('handles errors on get task activity', () => {
service.getTaskActivity(1).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/activity/task/1', 'GET', true);
});
it('updates a comment', () => {
service.updateComment(<any>{ id: 1 }).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/comments/1', 'POST');
});
it('handles errors on comment update', () => {
service.updateComment(<any>{ id: 1 }).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/comments/1', 'POST', true);
});
it('removes a comment', () => {
service.removeComment(1).subscribe(response => {
expect(response.data.length).toEqual(0);
});
testCall('api/comments/1', 'DELETE');
});
it('handles errors on comment removal', () => {
service.removeComment(1).subscribe(() => {}, response => {
expect(response.alerts.length).toEqual(1);
});
testCall('api/comments/1', 'DELETE', true);
});
it('refreshes the API token', () => {
service.refreshToken();
testCall('api/refresh', 'POST');
});
});

View File

@ -44,6 +44,8 @@ describe('ContextMenu', () => {
it('captures parent oncontextmenu events', () => {
const parentElement = component.el.nativeElement.parentElement;
component.el.nativeElement.appendChild(document.createElement('div'));
expect(parentElement.oncontextmenu).toEqual(jasmine.any(Function));
parentElement.oncontextmenu({

View File

@ -10,7 +10,7 @@
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"target": "es5",
"typeRoots": [
"node_modules/@types"
],