Finished email functionality

This commit is contained in:
Matthew Ross 2020-05-20 16:25:44 -04:00
parent 0c9b66a18f
commit d0d1cb2c45
22 changed files with 624 additions and 337 deletions

View File

@ -30,7 +30,7 @@ Installing TaskBoard is as easy as 1, 2, 3!
2. Extract it to your webserver 2. Extract it to your webserver
3. Verify the `api` directory is writable 3. Verify the `api` directory is writable
Optionally, you will want to edit `api/helpers/mailer.php` if you intend to use email features. If you intend to use email features, you will need to edit `api/helpers/mailer.php`.
### Server Config ### Server Config
@ -197,11 +197,11 @@ Because I like seeing the numbers.
Language | Files | Blank | Comment | Code Language | Files | Blank | Comment | Code
-----------|--------:|---------:|---------:|---------: -----------|--------:|---------:|---------:|---------:
TypeScript | 66 | 957 | 126 | 4055 TypeScript | 66 | 958 | 126 | 4057
PHP | 19 | 705 | 33 | 2132 PHP | 20 | 752 | 40 | 2265
HTML | 21 | 257 | 0 | 1537 HTML | 21 | 257 | 0 | 1540
SASS | 14 | 296 | 10 | 1338 SASS | 14 | 298 | 10 | 1344
**SUM:** | **120** | **2215** | **169** | **9062** **SUM:** | **121** | **2265** | **176** | **9206**
Command: `cloc --exclude-dir=vendor --exclude-ext=json,svg,ini src/` Command: `cloc --exclude-dir=vendor --exclude-ext=json,svg,ini src/`
@ -209,8 +209,8 @@ Command: `cloc --exclude-dir=vendor --exclude-ext=json,svg,ini src/`
Language | Files | Blank | Comment | Code Language | Files | Blank | Comment | Code
-----------|-------:|---------:|---------:|---------: -----------|-------:|---------:|---------:|---------:
TypeScript | 38 | 1009 | 8 | 3505 TypeScript | 38 | 1009 | 8 | 3523
PHP | 11 | 793 | 16 | 2338 PHP | 11 | 795 | 19 | 2300
**SUM:** | **49** | **1802** | **24** | **5843** **SUM:** | **49** | **1804** | **27** | **5823**
Command: `cloc --exclude-ext=xml test/` Command: `cloc --exclude-ext=xml test/`

426
package-lock.json generated
View File

@ -1753,9 +1753,9 @@
} }
}, },
"@types/highlight.js": { "@types/highlight.js": {
"version": "9.12.3", "version": "9.12.4",
"resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.3.tgz", "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.4.tgz",
"integrity": "sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ==", "integrity": "sha512-t2szdkwmg2JJyuCM20e8kR2X59WCE5Zkl4bzm1u1Oukjm79zpbiAv+QjnwLnuuV0WHEcX2NgUItu0pAMKuOPww==",
"dev": true "dev": true
}, },
"@types/jasmine": { "@types/jasmine": {
@ -2686,9 +2686,9 @@
"dev": true "dev": true
}, },
"base64id": { "base64id": {
"version": "1.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
"integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
"dev": true "dev": true
}, },
"batch": { "batch": {
@ -4458,9 +4458,9 @@
} }
}, },
"date-format": { "date-format": {
"version": "2.1.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", "resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz",
"integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", "integrity": "sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w==",
"dev": true "dev": true
}, },
"debug": { "debug": {
@ -4916,64 +4916,91 @@
} }
}, },
"engine.io": { "engine.io": {
"version": "3.2.1", "version": "3.4.1",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.1.tgz",
"integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", "integrity": "sha512-8MfIfF1/IIfxuc2gv5K+XlFZczw/BpTvqBdl0E2fBLkYQp4miv4LuDTVtYt4yMyaIFLEr4vtaSgV4mjvll8Crw==",
"dev": true, "dev": true,
"requires": { "requires": {
"accepts": "~1.3.4", "accepts": "~1.3.4",
"base64id": "1.0.0", "base64id": "2.0.0",
"cookie": "0.3.1", "cookie": "0.3.1",
"debug": "~3.1.0", "debug": "~4.1.0",
"engine.io-parser": "~2.1.0", "engine.io-parser": "~2.2.0",
"ws": "~3.3.1" "ws": "^7.1.2"
}, },
"dependencies": { "dependencies": {
"debug": { "debug": {
"version": "3.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true, "dev": true,
"requires": { "requires": {
"ms": "2.0.0" "ms": "^2.1.1"
} }
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
} }
} }
}, },
"engine.io-client": { "engine.io-client": {
"version": "3.2.1", "version": "3.4.2",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.2.tgz",
"integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", "integrity": "sha512-AWjc1Xg06a6UPFOBAzJf48W1UR/qKYmv/ubgSCumo9GXgvL/xGIvo05dXoBL+2NTLMipDI7in8xK61C17L25xg==",
"dev": true, "dev": true,
"requires": { "requires": {
"component-emitter": "1.2.1", "component-emitter": "~1.3.0",
"component-inherit": "0.0.3", "component-inherit": "0.0.3",
"debug": "~3.1.0", "debug": "~4.1.0",
"engine.io-parser": "~2.1.1", "engine.io-parser": "~2.2.0",
"has-cors": "1.1.0", "has-cors": "1.1.0",
"indexof": "0.0.1", "indexof": "0.0.1",
"parseqs": "0.0.5", "parseqs": "0.0.5",
"parseuri": "0.0.5", "parseuri": "0.0.5",
"ws": "~3.3.1", "ws": "~6.1.0",
"xmlhttprequest-ssl": "~1.5.4", "xmlhttprequest-ssl": "~1.5.4",
"yeast": "0.1.2" "yeast": "0.1.2"
}, },
"dependencies": { "dependencies": {
"component-emitter": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
"dev": true
},
"debug": { "debug": {
"version": "3.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true, "dev": true,
"requires": { "requires": {
"ms": "2.0.0" "ms": "^2.1.1"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"ws": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
"integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==",
"dev": true,
"requires": {
"async-limiter": "~1.0.0"
} }
} }
} }
}, },
"engine.io-parser": { "engine.io-parser": {
"version": "2.1.3", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz",
"integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", "integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==",
"dev": true, "dev": true,
"requires": { "requires": {
"after": "0.8.2", "after": "0.8.2",
@ -5124,9 +5151,9 @@
"dev": true "dev": true
}, },
"eventemitter3": { "eventemitter3": {
"version": "4.0.0", "version": "4.0.4",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz",
"integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==",
"dev": true "dev": true
}, },
"events": { "events": {
@ -5632,9 +5659,9 @@
} }
}, },
"follow-redirects": { "follow-redirects": {
"version": "1.9.0", "version": "1.11.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz",
"integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", "integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==",
"dev": true, "dev": true,
"requires": { "requires": {
"debug": "^3.0.0" "debug": "^3.0.0"
@ -6273,9 +6300,9 @@
"dev": true "dev": true
}, },
"http-proxy": { "http-proxy": {
"version": "1.18.0", "version": "1.18.1",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
"integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"eventemitter3": "^4.0.0", "eventemitter3": "^4.0.0",
@ -7514,33 +7541,33 @@
} }
}, },
"karma": { "karma": {
"version": "5.0.5", "version": "5.0.8",
"resolved": "https://registry.npmjs.org/karma/-/karma-5.0.5.tgz", "resolved": "https://registry.npmjs.org/karma/-/karma-5.0.8.tgz",
"integrity": "sha512-Q4Su7kNwkTgqS+KbSCYgH0p4a/0JIxVLyp7qKNV7vgPNhIF4kIoh0GlUfMKpw67BrR3hgPQSJoxgF7xnzUtPpg==", "integrity": "sha512-n0iQ66to2YivGTw202ReC5I33F7/BaiQRBEP6MNRex//3ckblNcEDV5T5CL+2W/wdjPc479IxDkMtBoOZ/4PnA==",
"dev": true, "dev": true,
"requires": { "requires": {
"body-parser": "^1.16.1", "body-parser": "^1.19.0",
"braces": "^3.0.2", "braces": "^3.0.2",
"chokidar": "^3.0.0", "chokidar": "^3.0.0",
"colors": "^1.1.0", "colors": "^1.4.0",
"connect": "^3.6.0", "connect": "^3.7.0",
"di": "^0.0.1", "di": "^0.0.1",
"dom-serialize": "^2.2.0", "dom-serialize": "^2.2.1",
"flatted": "^2.0.0", "flatted": "^2.0.2",
"glob": "^7.1.1", "glob": "^7.1.6",
"graceful-fs": "^4.1.2", "graceful-fs": "^4.2.4",
"http-proxy": "^1.13.0", "http-proxy": "^1.18.0",
"isbinaryfile": "^4.0.2", "isbinaryfile": "^4.0.6",
"lodash": "^4.17.14", "lodash": "^4.17.15",
"log4js": "^4.0.0", "log4js": "^6.2.1",
"mime": "^2.3.1", "mime": "^2.4.5",
"minimatch": "^3.0.2", "minimatch": "^3.0.4",
"qjobs": "^1.1.4", "qjobs": "^1.2.0",
"range-parser": "^1.2.0", "range-parser": "^1.2.1",
"rimraf": "^2.6.0", "rimraf": "^3.0.2",
"socket.io": "2.1.1", "socket.io": "^2.3.0",
"source-map": "^0.6.1", "source-map": "^0.6.1",
"tmp": "0.0.33", "tmp": "0.2.1",
"ua-parser-js": "0.7.21", "ua-parser-js": "0.7.21",
"yargs": "^15.3.1" "yargs": "^15.3.1"
}, },
@ -7603,6 +7630,26 @@
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true "dev": true
}, },
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"graceful-fs": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
"dev": true
},
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@ -7618,6 +7665,12 @@
"p-locate": "^4.1.0" "p-locate": "^4.1.0"
} }
}, },
"mime": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz",
"integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==",
"dev": true
},
"p-limit": { "p-limit": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
@ -7654,6 +7707,15 @@
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"dev": true "dev": true
}, },
"rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
},
"string-width": { "string-width": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
@ -7674,6 +7736,15 @@
"ansi-regex": "^5.0.0" "ansi-regex": "^5.0.0"
} }
}, },
"tmp": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
"integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
"dev": true,
"requires": {
"rimraf": "^3.0.0"
}
},
"wrap-ansi": { "wrap-ansi": {
"version": "6.2.0", "version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
@ -8011,16 +8082,16 @@
} }
}, },
"log4js": { "log4js": {
"version": "4.5.1", "version": "6.2.1",
"resolved": "https://registry.npmjs.org/log4js/-/log4js-4.5.1.tgz", "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.2.1.tgz",
"integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==", "integrity": "sha512-7n+Oqxxz7VcQJhIlqhcYZBTpbcQ7XsR0MUIfJkx/n3VUjkAS4iUr+4UJlhxf28RvP9PMGQXbgTUhLApnu0XXgA==",
"dev": true, "dev": true,
"requires": { "requires": {
"date-format": "^2.0.0", "date-format": "^3.0.0",
"debug": "^4.1.1", "debug": "^4.1.1",
"flatted": "^2.0.0", "flatted": "^2.0.1",
"rfdc": "^1.1.4", "rfdc": "^1.1.4",
"streamroller": "^1.0.6" "streamroller": "^2.2.4"
}, },
"dependencies": { "dependencies": {
"debug": { "debug": {
@ -8222,9 +8293,9 @@
} }
}, },
"marked": { "marked": {
"version": "1.0.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-1.0.0.tgz", "resolved": "https://registry.npmjs.org/marked/-/marked-1.1.0.tgz",
"integrity": "sha512-Wo+L1pWTVibfrSr+TTtMuiMfNzmZWiOPeO7rZsQUY5bgsxpHesBEcIWJloWVTFnrMXnf/TL30eTFSGJddmQAng==" "integrity": "sha512-EkE7RW6KcXfMHy2PA7Jg0YJE1l8UPEZE8k45tylzmZM30/r1M1MUXWQfJlrSbsTeh7m/XTwHbWUENvAJZpp1YA=="
}, },
"md5.js": { "md5.js": {
"version": "1.3.5", "version": "1.3.5",
@ -12218,9 +12289,9 @@
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
}, },
"puppeteer": { "puppeteer": {
"version": "3.0.4", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-3.0.4.tgz", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-3.1.0.tgz",
"integrity": "sha512-1QEb4tJXXbNId7WSHlcDkS3B4GklTIebKn8Y9D6B7tAdUjQncb+8QlTjbQsAgGX5dhRG32Qycuk5XKzJgLs0sg==", "integrity": "sha512-jLa9sqdVx0tPnr2FcwAq+8DSjGhSM4YpkwOf3JE22Ycyqm71SW7B5uGfTyMGFoLCmbCozbLZclCjasPb0flTRw==",
"dev": true, "dev": true,
"requires": { "requires": {
"debug": "^4.1.0", "debug": "^4.1.0",
@ -12274,12 +12345,6 @@
"requires": { "requires": {
"glob": "^7.1.3" "glob": "^7.1.3"
} }
},
"ws": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz",
"integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==",
"dev": true
} }
} }
}, },
@ -13568,27 +13633,33 @@
} }
}, },
"socket.io": { "socket.io": {
"version": "2.1.1", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz",
"integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", "integrity": "sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==",
"dev": true, "dev": true,
"requires": { "requires": {
"debug": "~3.1.0", "debug": "~4.1.0",
"engine.io": "~3.2.0", "engine.io": "~3.4.0",
"has-binary2": "~1.0.2", "has-binary2": "~1.0.2",
"socket.io-adapter": "~1.1.0", "socket.io-adapter": "~1.1.0",
"socket.io-client": "2.1.1", "socket.io-client": "2.3.0",
"socket.io-parser": "~3.2.0" "socket.io-parser": "~3.4.0"
}, },
"dependencies": { "dependencies": {
"debug": { "debug": {
"version": "3.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true, "dev": true,
"requires": { "requires": {
"ms": "2.0.0" "ms": "^2.1.1"
} }
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
} }
} }
}, },
@ -13599,56 +13670,34 @@
"dev": true "dev": true
}, },
"socket.io-client": { "socket.io-client": {
"version": "2.1.1", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz",
"integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==",
"dev": true, "dev": true,
"requires": { "requires": {
"backo2": "1.0.2", "backo2": "1.0.2",
"base64-arraybuffer": "0.1.5", "base64-arraybuffer": "0.1.5",
"component-bind": "1.0.0", "component-bind": "1.0.0",
"component-emitter": "1.2.1", "component-emitter": "1.2.1",
"debug": "~3.1.0", "debug": "~4.1.0",
"engine.io-client": "~3.2.0", "engine.io-client": "~3.4.0",
"has-binary2": "~1.0.2", "has-binary2": "~1.0.2",
"has-cors": "1.1.0", "has-cors": "1.1.0",
"indexof": "0.0.1", "indexof": "0.0.1",
"object-component": "0.0.3", "object-component": "0.0.3",
"parseqs": "0.0.5", "parseqs": "0.0.5",
"parseuri": "0.0.5", "parseuri": "0.0.5",
"socket.io-parser": "~3.2.0", "socket.io-parser": "~3.3.0",
"to-array": "0.1.4" "to-array": "0.1.4"
}, },
"dependencies": { "dependencies": {
"debug": { "debug": {
"version": "3.1.0", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true, "dev": true,
"requires": { "requires": {
"ms": "2.0.0" "ms": "^2.1.1"
}
}
}
},
"socket.io-parser": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz",
"integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==",
"dev": true,
"requires": {
"component-emitter": "1.2.1",
"debug": "~3.1.0",
"isarray": "2.0.1"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
} }
}, },
"isarray": { "isarray": {
@ -13656,6 +13705,74 @@
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
"dev": true "dev": true
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"socket.io-parser": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz",
"integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==",
"dev": true,
"requires": {
"component-emitter": "1.2.1",
"debug": "~3.1.0",
"isarray": "2.0.1"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
}
}
}
}
},
"socket.io-parser": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz",
"integrity": "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==",
"dev": true,
"requires": {
"component-emitter": "1.2.1",
"debug": "~4.1.0",
"isarray": "2.0.1"
},
"dependencies": {
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
"dev": true
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
} }
} }
}, },
@ -14089,38 +14206,48 @@
"dev": true "dev": true
}, },
"streamroller": { "streamroller": {
"version": "1.0.6", "version": "2.2.4",
"resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.6.tgz", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-2.2.4.tgz",
"integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==", "integrity": "sha512-OG79qm3AujAM9ImoqgWEY1xG4HX+Lw+yY6qZj9R1K2mhF5bEmQ849wvrb+4vt4jLMLzwXttJlQbOdPOQVRv7DQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"async": "^2.6.2", "date-format": "^2.1.0",
"date-format": "^2.0.0", "debug": "^4.1.1",
"debug": "^3.2.6", "fs-extra": "^8.1.0"
"fs-extra": "^7.0.1",
"lodash": "^4.17.14"
}, },
"dependencies": { "dependencies": {
"date-format": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz",
"integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==",
"dev": true
},
"debug": { "debug": {
"version": "3.2.6", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true, "dev": true,
"requires": { "requires": {
"ms": "^2.1.1" "ms": "^2.1.1"
} }
}, },
"fs-extra": { "fs-extra": {
"version": "7.0.1", "version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"dev": true, "dev": true,
"requires": { "requires": {
"graceful-fs": "^4.1.2", "graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0", "jsonfile": "^4.0.0",
"universalify": "^0.1.0" "universalify": "^0.1.0"
} }
}, },
"graceful-fs": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
"dev": true
},
"ms": { "ms": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@ -15182,12 +15309,6 @@
"integrity": "sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==", "integrity": "sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==",
"dev": true "dev": true
}, },
"ultron": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==",
"dev": true
},
"unbzip2-stream": { "unbzip2-stream": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.2.tgz", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.2.tgz",
@ -16573,15 +16694,10 @@
} }
}, },
"ws": { "ws": {
"version": "3.3.3", "version": "7.3.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz",
"integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", "integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==",
"dev": true, "dev": true
"requires": {
"async-limiter": "~1.0.0",
"safe-buffer": "~5.1.0",
"ultron": "~1.1.0"
}
}, },
"xdg-basedir": { "xdg-basedir": {
"version": "3.0.0", "version": "3.0.0",

View File

@ -65,7 +65,7 @@
"classlist.js": "^1.1.20150312", "classlist.js": "^1.1.20150312",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"highlight.js": "^10.0.3", "highlight.js": "^10.0.3",
"marked": "^1.0.0", "marked": "^1.1.0",
"node-sass": "^4.14.1", "node-sass": "^4.14.1",
"rxjs": "^6.5.5", "rxjs": "^6.5.5",
"scss-base": "^1.4.0", "scss-base": "^1.4.0",
@ -77,7 +77,7 @@
"@angular/compiler-cli": "^9.1.7", "@angular/compiler-cli": "^9.1.7",
"@angular/language-service": "^9.1.7", "@angular/language-service": "^9.1.7",
"@types/chartist": "^0.9.48", "@types/chartist": "^0.9.48",
"@types/highlight.js": "^9.12.3", "@types/highlight.js": "^9.12.4",
"@types/jasmine": "~3.5.10", "@types/jasmine": "~3.5.10",
"@types/jasminewd2": "~2.0.8", "@types/jasminewd2": "~2.0.8",
"@types/marked": "^0.7.4", "@types/marked": "^0.7.4",
@ -89,7 +89,7 @@
"jasmine": "^3.5.0", "jasmine": "^3.5.0",
"jasmine-core": "^3.5.0", "jasmine-core": "^3.5.0",
"jasmine-spec-reporter": "~5.0.2", "jasmine-spec-reporter": "~5.0.2",
"karma": "^5.0.5", "karma": "^5.0.8",
"karma-chrome-launcher": "^3.1.0", "karma-chrome-launcher": "^3.1.0",
"karma-coverage-istanbul-reporter": "^3.0.2", "karma-coverage-istanbul-reporter": "^3.0.2",
"karma-jasmine": "~3.1.1", "karma-jasmine": "~3.1.1",
@ -97,7 +97,7 @@
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"npm-watch": "^0.6.0", "npm-watch": "^0.6.0",
"protractor": "^7.0.0", "protractor": "^7.0.0",
"puppeteer": "^3.0.4", "puppeteer": "^3.1.0",
"ts-node": "^8.10.1", "ts-node": "^8.10.1",
"tslint": "^6.1.2", "tslint": "^6.1.2",
"typescript": "^3.8.3" "typescript": "^3.8.3"

View File

@ -15,7 +15,6 @@ abstract class BaseController {
$this->dbLogger = new DbLogger(); $this->dbLogger = new DbLogger();
// Default to English // Default to English
$this->mailer = new Mailer('en');
$this->loadStrings('en'); $this->loadStrings('en');
} }
@ -74,6 +73,15 @@ abstract class BaseController {
return $status; return $status;
} }
protected function getAdminEmailAddresses($boardId) {
$emails = R::getAll('SELECT email FROM user u ' .
'JOIN board_user bu ON u.id = bu.user_id ' .
'WHERE u.security_level < 3 AND u.email <> "" AND board_id = ?',
[$boardId]);
return count($emails) > 0 ? $emails[0] : [];
}
private function loadStrings($lang) { private function loadStrings($lang) {
$json = '{}'; $json = '{}';

View File

@ -83,6 +83,8 @@ class Boards extends BaseController {
'(' . $board->name . ').'); '(' . $board->name . ').');
$this->apiJson->addData($this->loadAllBoards($request)); $this->apiJson->addData($this->loadAllBoards($request));
$this->sendEmail($board, $actor, 'newBoard');
return $this->jsonResponse($response); return $this->jsonResponse($response);
} }
@ -133,6 +135,8 @@ class Boards extends BaseController {
'(' . $update->name . ').'); '(' . $update->name . ').');
$this->apiJson->addData($this->loadAllBoards($request)); $this->apiJson->addData($this->loadAllBoards($request));
$this->sendEmail($update, $actor, 'editBoard');
return $this->jsonResponse($response); return $this->jsonResponse($response);
} }
@ -166,6 +170,8 @@ class Boards extends BaseController {
'(' . $before->name . ').'); '(' . $before->name . ').');
$this->apiJson->addData($this->loadAllBoards($request)); $this->apiJson->addData($this->loadAllBoards($request));
$this->sendEmail($before, $actor, 'removeBoard');
return $this->jsonResponse($response); return $this->jsonResponse($response);
} }
@ -215,5 +221,23 @@ class Boards extends BaseController {
return $user; return $user;
} }
private function sendEmail($board, $actor, $type) {
$data = new EmailData($board->id);
$data->username = $actor->username;
$data->boardName = $board->name;
$data->type = $type;
$emails = $this->getAdminEmailAddresses($board->id);
if($actor->email !== '' && !in_array($actor->email, $emails)) {
$emails[] = $actor->email;
}
$result = $this->mailer->sendMail($emails, $data);
if ($result !== '') {
$this->apiJson->addAlert('info', $result);
}
}
} }

View File

@ -52,7 +52,9 @@ class Comments extends BaseController {
return $this->jsonResponse($response); return $this->jsonResponse($response);
} }
if (!$this->checkBoardAccess($this->getBoardId($task->id), $request)) { $boardId = $this->getBoardId($task->id);
if (!$this->checkBoardAccess($boardId, $request)) {
return $this->jsonResponse($response, 403); return $this->jsonResponse($response, 403);
} }
@ -67,6 +69,9 @@ class Comments extends BaseController {
$this->apiJson->addData(R::exportAll($task)); $this->apiJson->addData(R::exportAll($task));
$this->apiJson->addAlert('success', $this->strings->api_commentAdded); $this->apiJson->addAlert('success', $this->strings->api_commentAdded);
$board = R::load('board', $boardId);
$this->sendEmail($board, $task, $comment->text, $actor, 'newComment');
return $this->jsonResponse($response); return $this->jsonResponse($response);
} }
@ -110,8 +115,9 @@ class Comments extends BaseController {
return $this->jsonResponse($response); return $this->jsonResponse($response);
} }
if (!$this->checkBoardAccess( $boardId = $this->getBoardId($comment->task_id);
$this->getBoardId($comment->task_id), $request)) {
if (!$this->checkBoardAccess($boardId, $request)) {
return $this->jsonResponse($response, 403); return $this->jsonResponse($response, 403);
} }
@ -127,6 +133,9 @@ class Comments extends BaseController {
$task = R::load('task', $comment->task_id); $task = R::load('task', $comment->task_id);
$this->apiJson->addData(R::exportAll($task)); $this->apiJson->addData(R::exportAll($task));
$board = R::load('board', $boardId);
$this->sendEmail($board, $task, $comment->text, $actor, 'editComment');
return $this->jsonResponse($response); return $this->jsonResponse($response);
} }
@ -159,8 +168,9 @@ class Comments extends BaseController {
return $this->jsonResponse($response); return $this->jsonResponse($response);
} }
if (!$this->checkBoardAccess( $boardId = $this->getBoardId($comment->task_id);
$this->getBoardId($comment->task_id), $request)) {
if (!$this->checkBoardAccess($boardId, $request)) {
return $this->jsonResponse($response, 403); return $this->jsonResponse($response, 403);
} }
@ -177,6 +187,9 @@ class Comments extends BaseController {
$task = R::load('task', $comment->task_id); $task = R::load('task', $comment->task_id);
$this->apiJson->addData(R::exportAll($task)); $this->apiJson->addData(R::exportAll($task));
$board = R::load('board', $boardId);
$this->sendEmail($board, $task, $comment->text, $actor, 'editComment');
return $this->jsonResponse($response); return $this->jsonResponse($response);
} }
@ -186,5 +199,44 @@ class Comments extends BaseController {
return $column->board_id; return $column->board_id;
} }
private function sendEmail($board, $task, $comment, $actor, $type) {
$data = new EmailData($board->id);
$column = R::load('column', $task->column_id);
$data->comment = $comment ?: '';
$data->username = $actor->username ?: '';
$data->boardName = $board->name ?: '';
$data->type = $type;
$data->taskName = $task->title ?: '';
$data->taskDescription = $task->description ?: '';
$data->taskDueDate = date('F j, Y, g:i:s A', (int)$task->due_date * 1000);
$data->taskAssignees = '';
foreach($task->sharedUserList as $assignee) {
$data->taskAssignees .= $assignee->username ?: '' . ' ';
}
$data->taskCategories = '';
foreach($task->sharedCategoryList as $category) {
$data->taskCategories .= $category->name ?: '' . ' ';
}
$data->taskPoints = $task->points ?: '';
$data->taskColumnName = $column->name ?: '';
$data->taskPosition = $task->position ?: '';
$emails = $this->getAdminEmailAddresses($board->id);
if($actor->email !== '' && !in_array($actor->email, $emails)) {
$emails[] = $actor->email; // @codeCoverageIgnore
}
$result = $this->mailer->sendMail($emails, $data);
if ($result !== '') {
$this->apiJson->addAlert('info', $result); // @codeCoverageIgnore
}
}
} }

View File

@ -70,6 +70,8 @@ class Tasks extends BaseController {
$board = R::load('board', $column->board_id); $board = R::load('board', $column->board_id);
$this->apiJson->addData(R::exportAll($board)); $this->apiJson->addData(R::exportAll($board));
$this->sendEmail($board, $task, $actor, 'newTask');
return $this->jsonResponse($response); return $this->jsonResponse($response);
} }
@ -119,8 +121,7 @@ class Tasks extends BaseController {
$this->dbLogger->logChange($actor->id, $this->dbLogger->logChange($actor->id,
$actor->username . ' updated task ' . $task->title, $actor->username . ' updated task ' . $task->title,
json_encode($task), json_encode($update), json_encode($task), json_encode($update), 'task', $update->id);
'task', $update->id);
$boardId = $this->getBoardId($task->column_id); $boardId = $this->getBoardId($task->column_id);
$board = R::load('board', $boardId); $board = R::load('board', $boardId);
@ -131,6 +132,8 @@ class Tasks extends BaseController {
$this->apiJson->addData(R::exportAll($update)); $this->apiJson->addData(R::exportAll($update));
$this->apiJson->addData(R::exportAll($board)); $this->apiJson->addData(R::exportAll($board));
$this->sendEmail($board, $update, $actor, 'editTask');
return $this->jsonResponse($response); return $this->jsonResponse($response);
} }
@ -174,6 +177,8 @@ class Tasks extends BaseController {
$board = R::load('board', $boardId); $board = R::load('board', $boardId);
$this->apiJson->addData(R::exportAll($board)); $this->apiJson->addData(R::exportAll($board));
$this->sendEmail($board, $before, $actor, 'removeTask');
return $this->jsonResponse($response); return $this->jsonResponse($response);
} }
@ -227,9 +232,10 @@ class Tasks extends BaseController {
case ActionTrigger::ASSIGNED_TO_USER(): case ActionTrigger::ASSIGNED_TO_USER():
$prevAssigned = $this->isInList($action->source_id, $prevAssigned = $this->isInList($action->source_id,
isset($before[0]['sharedUser']) ? isset($before[0]['sharedUser'])
$before[0]['sharedUser'] : ? $before[0]['sharedUser']
[]); : []
);
if ($prevAssigned) { if ($prevAssigned) {
break; break;
@ -244,9 +250,10 @@ class Tasks extends BaseController {
case ActionTrigger::ADDED_TO_CATEGORY(): case ActionTrigger::ADDED_TO_CATEGORY():
$prevAssigned = $this->isInList($action->source_id, $prevAssigned = $this->isInList($action->source_id,
isset($before[0]['sharedCategory']) ? isset($before[0]['sharedCategory'])
$before[0]['sharedCategory'] : ? $before[0]['sharedCategory']
[]); : []
);
if ($prevAssigned) { if ($prevAssigned) {
break; break;
} }
@ -264,9 +271,7 @@ class Tasks extends BaseController {
0; 0;
if ($points !== (int)$after[0]['points']) { if ($points !== (int)$after[0]['points']) {
$this->updateTaskColor($after[0]['id'], $this->updateTaskColor($after[0]['id'], $points, $after[0]['points']);
$points,
$after[0]['points']);
} }
break; break;
@ -370,5 +375,42 @@ class Tasks extends BaseController {
$this->apiJson->addAlert('info',$this->strings->api_taskAutoColor); $this->apiJson->addAlert('info',$this->strings->api_taskAutoColor);
R::store($task); R::store($task);
} }
private function sendEmail($board, $task, $actor, $type) {
$data = new EmailData($board->id);
$column = R::load('column', $task->column_id ?: '');
$data->username = $actor->username ?: '';
$data->boardName = $board->name ?: '';
$data->type = $type;
$data->taskName = $task->title ?: '';
$data->taskDescription = $task->description ?: '';
$data->taskDueDate = date('F j, Y, g:i:s A', (int)$task->due_date * 1000);
$data->taskAssignees = '';
foreach($task->sharedUserList as $assignee) {
$data->taskAssignees .= $assignee->username . ' ';
}
$data->taskCategories = '';
foreach($task->sharedCategoryList as $category) {
$data->taskCategories .= $category->name . ' ';
}
$data->taskPoints = $task->points ?: '';
$data->taskColumnName = $column->name ?: '';
$data->taskPosition = $task->position ?: '';
$emails = $this->getAdminEmailAddresses($board->id);
if($actor->email !== '' && !in_array($actor->email, $emails)) {
$emails[] = $actor->email; // @codeCoverageIgnore
}
$result = $this->mailer->sendMail($emails, $data);
if ($result !== '') {
$this->apiJson->addAlert('info', $result); // @codeCoverageIgnore
}
}
} }

View File

@ -0,0 +1,40 @@
<?php
class EmailData {
public string $hostUrl;
public string $boardId;
public string $type;
public string $username;
public string $boardName;
public string $comment;
public string $taskName;
public string $taskDescription;
public string $taskDueDate;
public string $taskAssignees;
public string $taskCategories;
public string $taskPoints;
public string $taskColumnName;
public string $taskPosition;
public function __construct($boardId) {
$this->hostUrl = $_SERVER['HTTP_REFERER'];
$this->boardId = $boardId;
$this->type = '';
$this->username = '';
$this->boardName = '';
$this->comment = '';
$this->taskName = '';
$this->taskDescription = '';
$this->taskDueDate = '';
$this->taskAssignees = '';
$this->taskCategories = '';
$this->taskPoints = '';
$this->taskColumnName = '';
$this->taskPosition = '';
}
}

View File

@ -26,18 +26,19 @@ class Mailer {
/** /**
* Send email to one or more users in the provided list. * Send email to one or more users in the provided list.
* @param $users List of users to email (must have at least one). *
* @param $emails List of email addresses (must have at least one).
* @param $data Object containing template type and replacements for template. * @param $data Object containing template type and replacements for template.
*/ */
public function sendMail($users, $data) { public function sendMail($emails, $data) {
$this->initMail(); $this->initMail();
if (count($users) < 1) { if (count($emails) < 1) {
return $this->strings->mail_error; return '';
} }
foreach($users as $user) { foreach($emails as $user) {
$this->mail->addAddress($user->email); $this->mail->addAddress($user);
} }
$this->mail->Subject = $this->strings->mail_subject; $this->mail->Subject = $this->strings->mail_subject;
@ -47,33 +48,53 @@ class Mailer {
return $this->strings->mail_error; return $this->strings->mail_error;
} }
return $this->strings->mail_sent; return $this->strings->mail_sent; // @codeCoverageIgnore
} }
private function parseTemplate($data) { private function parseTemplate(EmailData $data) {
$template = $this->getTemplate($data->type); $template = $this->getTemplate($data->type);
str_replace('%username%', $data->username, $template); $template = str_replace('%hostUrl%', $data->hostUrl, $template);
str_replace('%boardName%', $data->boardName, $template); $template = str_replace('%boardId%', $data->boardId, $template);
str_replace('%taskName%', $data->taskName, $template);
str_replace('%comment%', $data->comment, $template); $template = str_replace('%username%', $data->username, $template);
str_replace('%taskDescription%', $data->taskDescription, $template); $template = str_replace('%boardName%', $data->boardName, $template);
str_replace('%taskDueDate%', $data->taskDueDate, $template);
str_replace('%taskAssignees%', $data->taskAssignees, $template); $template = str_replace('%comment%', $data->comment, $template);
str_replace('%taskCategories%', $data->taskCategories, $template); $template = str_replace('%taskName%', $data->taskName, $template);
str_replace('%taskPoints%', $data->taskPoints, $template);
str_replace('%taskColumnName%', $data->taskColumnName, $template); $template =
str_replace('%taskPosition%', $data->taskPosition, $template); str_replace('%taskDescription%', $data->taskDescription, $template);
str_replace('%hostUrl%', $data->hostUrl, $template); $template = str_replace('%taskDueDate%', $data->taskDueDate, $template);
str_replace('%boardId%', $data->boardId, $template); $template = str_replace('%taskAssignees%', $data->taskAssignees, $template);
$template =
str_replace('%taskCategories%', $data->taskCategories, $template);
$template = str_replace('%taskPoints%', $data->taskPoints, $template);
$template =
str_replace('%taskColumnName%', $data->taskColumnName, $template);
$template = str_replace('%taskPosition%', $data->taskPosition, $template);
return $template; return $template;
} }
/**
* @codeCoverageIgnore
*/
private function getTemplate($type) { private function getTemplate($type) {
$template = ''; $template = '';
switch($type) { switch($type) {
case 'newBoard':
$template = $this->strings->mail_template_newBoard;
break;
case 'newComment':
$template = $this->strings->mail_template_newComment;
break;
case 'newTask':
$template = $this->strings->mail_template_newTask;
case 'editBoard': case 'editBoard':
$template = $this->strings->mail_template_editBoard; $template = $this->strings->mail_template_editBoard;
break; break;
@ -86,16 +107,17 @@ class Mailer {
$template = $this->strings->mail_template_editTask; $template = $this->strings->mail_template_editTask;
break; break;
case 'newBoard': case 'removeBoard':
$template = $this->strings->mail_template_newBoard; $template = $this->strings->mail_template_removeBoard;
break; break;
case 'newComment': case 'removeComment':
$template = $this->strings->mail_template_newComment; $template = $this->strings->mail_template_removeComment;
break; break;
case 'newTask': case 'removeTask':
$template = $this->strings->mail_template_newTask; $template = $this->strings->mail_template_removeTask;
break;
} }
$template .= $this->strings->mail_template_openBoardLink; $template .= $this->strings->mail_template_openBoardLink;
@ -107,28 +129,26 @@ class Mailer {
$this->mail = new PHPMailer(); $this->mail = new PHPMailer();
$this->mail->isSendmail(); $this->mail->isSendmail();
$this->mail->setFrom($this->FROM_EMAIL, $this->FROM_NAME); $this->mail->setFrom(Mailer::FROM_EMAIL, Mailer::FROM_NAME);
if (!$this->USE_SENDMAIL) { // @codeCoverageIgnoreStart
if (!Mailer::USE_SENDMAIL) {
$this->mail->isSMTP(); $this->mail->isSMTP();
$this->mail->Host = $this->SMTP_HOST; $this->mail->Host = Mailer::SMTP_HOST;
$this->mail->Port = $this->SMTP_PORT; $this->mail->Port = Mailer::SMTP_PORT;
$this->mail->Username = $this->SMTP_USER; $this->mail->Username = Mailer::SMTP_USER;
$this->mail->Password = $this->SMTP_PASS; $this->mail->Password = Mailer::SMTP_PASS;
$this->mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; $this->mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$this->mail->SMTPAuth = true; $this->mail->SMTPAuth = true;
} }
// @codeCoverageIgnoreEnd
} }
private function loadStrings($lang) { private function loadStrings($lang) {
$json = '{}'; $json = '{}';
if (!$lang) {
$lang = 'en';
}
try { try {
$json = $json =
file_get_contents(__DIR__ . '/../../strings/' . $lang . '_api.json'); file_get_contents(__DIR__ . '/../../strings/' . $lang . '_api.json');

View File

@ -328,7 +328,7 @@
</select> </select>
</label> </label>
<label *ngIf="modalProps.categories.length"> <label *ngIf="activeBoard.categories.length">
{{ strings['boards_taskCategories'] }} {{ strings['boards_taskCategories'] }}
<select name="categories" multiple [ngModel]="modalProps.categories" <select name="categories" multiple [ngModel]="modalProps.categories"

View File

@ -68,10 +68,16 @@
"mail_subject": "TaskBoard Notification", "mail_subject": "TaskBoard Notification",
"mail_template_openBoardLink": "<br><br><a href=\"%hostUrl%/boards/%boardId%\">Open TaskBoard</a>", "mail_template_openBoardLink": "<br><br><a href=\"%hostUrl%/boards/%boardId%\">Open TaskBoard</a>",
"mail_template_editBoard": "%username% edited board %boardName%",
"mail_template_newBoard": "%username% added board %boardName%.",
"mail_template_newComment": "%username% added a comment in board %boardName%.<br>Task: %taskName%<br>Comment: %comment%",
"mail_template_newTask": "%username% added a task in board %boardName%.<br>Task: %taskName%<br>Description: %taskDescription%<br>Due Date: %taskDueDate%<br>Asignees: %taskAssignees%<br>Categories: %taskCategories%<br>Points: %taskPoints%<br>Column: %taskColumnName%<br>Position: %taskPosition%",
"mail_template_editBoard": "%username% edited board %boardName%.",
"mail_template_editComment": "%username% edited comment in board %boardName%.<br>Task: %taskName%<br>Comment: %comment%", "mail_template_editComment": "%username% edited comment in board %boardName%.<br>Task: %taskName%<br>Comment: %comment%",
"mail_template_editTask": "%username% edited task in board %boardName%.<br>Task: %taskName%<br>Description: %taskDescription%<br>Due Date: %taskDueDate%<br>Asignees: %taskAssignees%<br>Categories: %taskCategories%<br>Points: %taskPoints%<br>Column: %taskColumnName%<br>Position: %taskPosition%", "mail_template_editTask": "%username% edited task in board %boardName%.<br>Task: %taskName%<br>Description: %taskDescription%<br>Due Date: %taskDueDate%<br>Asignees: %taskAssignees%<br>Categories: %taskCategories%<br>Points: %taskPoints%<br>Column: %taskColumnName%<br>Position: %taskPosition%",
"mail_template_newBoard": "%username% added board %boardName%",
"mail_template_newComment": "%username% added a comment in board %boardName%.<br>Task: %taskName%<br>Comment: %comment%", "mail_template_removeBoard": "%username% removed board %boardName%.",
"mail_template_newTask": "%username% added a task in board %boardName%.<br>Task: %taskName%<br>Description: %taskDescription%<br>Due Date: %taskDueDate%<br>Asignees: %taskAssignees%<br>Categories: %taskCategories%<br>Points: %taskPoints%<br>Column: %taskColumnName%<br>Position: %taskPosition%" "mail_template_removeComment": "%username% removed comment in board %boardName%.<br>Task: %taskName%",
"mail_template_removeTask": "%username% removed a task in board %boardName%<br>Task: %taskName%"
} }

View File

@ -68,10 +68,16 @@
"mail_subject": "Notificación del tablero de tareas", "mail_subject": "Notificación del tablero de tareas",
"mail_template_openBoardLink": "<br><br><a href=\"%hostUrl%/boards/%boardId%\">Abrir TaskBoard</a>", "mail_template_openBoardLink": "<br><br><a href=\"%hostUrl%/boards/%boardId%\">Abrir TaskBoard</a>",
"mail_template_editBoard": "%username% tablero editado %boardName%",
"mail_template_editComment": "%username% comentario editado en el tablero %boardName%.<br>Tarea: %taskName%<br>Comentario: %comment%", "mail_template_newBoard": "%username% placa agregada %boardName%.",
"mail_template_editTask": "%username% tarea editada en el tablero %boardName%.<br>Tarea: %taskName%<br>Descripción: %taskDescription%<br>Fecha de vencimiento: %taskDueDate%<br>Asignees: %taskAssignees%<br>Categorías: %taskCategories%<br>Puntos: %taskPoints%<br>Columna: %taskColumnName%<br>Posición: %taskPosition% ", "mail_template_newComment": "%username% agregó un comentario en tablero %boardName%.<br>Tarea: %taskName%<br>Comentario: %comment%",
"mail_template_newBoard": "%username% placa agregada %boardName%", "mail_template_newTask": "%username% agregó una tarea en tablero %boardName%.<br>Tarea: %taskName%<br>Descripción: %taskDescription%<br>Fecha de vencimiento: %taskDueDate%<br>Asignees: %taskAssignees%<br>Categorías: %taskCategories%<br>Puntos: %taskPoints%<br>Columna: %taskColumnName%<br>Posición: %taskPosition% ",
"mail_template_newComment": "%username% agregó un comentario en el tablero %boardName%.<br>Tarea: %taskName%<br>Comentario: %comment%",
"mail_template_newTask": "%username% agregó una tarea en el tablero %boardName%.<br>Tarea: %taskName%<br>Descripción: %taskDescription%<br>Fecha de vencimiento: %taskDueDate%<br>Asignees: %taskAssignees%<br>Categorías: %taskCategories%<br>Puntos: %taskPoints%<br>Columna: %taskColumnName%<br>Posición: %taskPosition% " "mail_template_editBoard": "%username% tablero editado %boardName%.",
"mail_template_editComment": "%username% comentario editado en tablero %boardName%.<br>Tarea: %taskName%<br>Comentario: %comment%",
"mail_template_editTask": "%username% tarea editada en tablero %boardName%.<br>Tarea: %taskName%<br>Descripción: %taskDescription%<br>Fecha de vencimiento: %taskDueDate%<br>Asignees: %taskAssignees%<br>Categorías: %taskCategories%<br>Puntos: %taskPoints%<br>Columna: %taskColumnName%<br>Posición: %taskPosition% ",
"mail_template_removeBoard": "%username% tablero eliminado %boardName%.",
"mail_template_removeComment": "%username% comentario eliminado en tablero %boardName%.<br>Tarea: %taskName%",
"mail_template_removeTask": "%username% eliminó una tarea en tablero %boardName%<br>Tarea: %taskName%"
} }

View File

@ -68,10 +68,16 @@
"mail_subject":"Notification TaskBoard", "mail_subject":"Notification TaskBoard",
"mail_template_openBoardLink": "<br><br><a href=\"%hostUrl%/boards/%boardId%\">Ouvrir TaskBoard</a>", "mail_template_openBoardLink": "<br><br><a href=\"%hostUrl%/boards/%boardId%\">Ouvrir TaskBoard</a>",
"mail_template_editBoard": "%username% a modifié la carte %boardName%",
"mail_template_newBoard": "%username% a ajouté la carte %boardName%.",
"mail_template_newComment": "%username% a ajouté un commentaire dans le tableau %boardName%.<br>Tâche: %taskName%<br>Commentaire: %comment%",
"mail_template_newTask": "%username% a ajouté une tâche dans la carte %boardName%.<br>Tâche: %taskName%<br>Description: %taskDescription%<br>Date d'échéance: %taskDueDate%<br>Destinataires: %taskAssignees%<br>Catégories: %taskCategories%<br>Points: %taskPoints%<br>Colonne: %taskColumnName%<br>Position: %taskPosition%",
"mail_template_editBoard": "%username% a modifié la carte %boardName%.",
"mail_template_editComment": "%username% commentaire modifié dans le tableau %boardName%.<br>Tâche: %taskName%<br>Commentaire: %comment%", "mail_template_editComment": "%username% commentaire modifié dans le tableau %boardName%.<br>Tâche: %taskName%<br>Commentaire: %comment%",
"mail_template_editTask": "%username% tâche modifiée dans la carte %boardName%.<br>Tâche: %taskName%<br>Description: %taskDescription%<br>Date d'échéance: %taskDueDate%<br>Destinataires: %taskAssignees%<br>Catégories: %taskCategories%<br>Points: %taskPoints%<br>Colonne: %taskColumnName%<br>Position: %taskPosition%", "mail_template_editTask": "%username% tâche modifiée dans la carte %boardName%.<br>Tâche: %taskName%<br>Description: %taskDescription%<br>Date d'échéance: %taskDueDate%<br>Destinataires: %taskAssignees%<br>Catégories: %taskCategories%<br>Points: %taskPoints%<br>Colonne: %taskColumnName%<br>Position: %taskPosition%",
"mail_template_newBoard": "%username% a ajouté la carte %boardName%",
"mail_template_newComment": "%username% a ajouté un commentaire dans le tableau %boardName%.<br>Tâche: %taskName%<br>Commentaire: %comment%", "mail_template_removeBoard": "%username% a supprimé le tableau %boardName%.",
"mail_template_newTask": "%username% a ajouté une tâche dans la carte %boardName%.<br>Tâche: %taskName%<br>Description: %taskDescription%<br>Date d'échéance: %taskDueDate%<br>Destinataires: %taskAssignees%<br>Catégories: %taskCategories%<br>Points: %taskPoints%<br>Colonne: %taskColumnName%<br>Position: %taskPosition%" "mail_template_removeComment": "%username% a supprimé un commentaire du tableau %boardName%.<br>Tâche: %taskName%",
"mail_template_removeTask": "%username% a supprimé un tâche du tableau %boardName%<br>Tâche: %taskName%"
} }

View File

@ -8,8 +8,7 @@ class ActivityTest extends PHPUnit\Framework\TestCase {
public static function setUpBeforeClass(): void { public static function setUpBeforeClass(): void {
try { try {
R::setup('sqlite:tests.db'); R::setup('sqlite:tests.db');
} catch (Exception $ex) { } catch (Exception $ex) { }
}
} }
public function setUp(): void { public function setUp(): void {

View File

@ -10,8 +10,7 @@ class AttachmentsTest extends PHPUnit\Framework\TestCase {
public static function setUpBeforeClass(): void { public static function setUpBeforeClass(): void {
try { try {
R::setup('sqlite:tests.db'); R::setup('sqlite:tests.db');
} catch (Exception $ex) { } catch (Exception $ex) { }
}
} }
public function setUp(): void { public function setUp(): void {

View File

@ -8,8 +8,7 @@ class AuthTest extends PHPUnit\Framework\TestCase {
public static function setUpBeforeClass(): void { public static function setUpBeforeClass(): void {
try { try {
R::setup('sqlite:tests.db'); R::setup('sqlite:tests.db');
} catch (Exception $ex) { } catch (Exception $ex) { }
}
} }
public function setUp(): void { public function setUp(): void {

View File

@ -8,8 +8,7 @@ class AutoActionsTest extends PHPUnit\Framework\TestCase {
public static function setUpBeforeClass(): void { public static function setUpBeforeClass(): void {
try { try {
R::setup('sqlite:tests.db'); R::setup('sqlite:tests.db');
} catch (Exception $ex) { } catch (Exception $ex) { }
}
} }
public function setUp(): void { public function setUp(): void {

View File

@ -2,20 +2,25 @@
require_once __DIR__ . '/../Mocks.php'; require_once __DIR__ . '/../Mocks.php';
use RedBeanPHP\R; use RedBeanPHP\R;
$_SERVER['HTTP_REFERER'] = 'tests';
class BoardsTest extends PHPUnit\Framework\TestCase { class BoardsTest extends PHPUnit\Framework\TestCase {
private $boards; private $boards;
public static function setUpBeforeClass(): void { public static function setUpBeforeClass(): void {
try { try {
R::setup('sqlite:tests.db'); R::setup('sqlite:tests.db');
} catch (Exception $ex) { } catch (Exception $ex) { }
}
} }
public function setUp(): void { public function setUp(): void {
R::nuke(); R::nuke();
Auth::CreateInitialAdmin(new LoggerMock()); Auth::CreateInitialAdmin(new LoggerMock());
$admin = R::load('user', 1);
$admin->email = 'test@test.com';
R::store($admin);
$this->boards = new Boards(new LoggerMock()); $this->boards = new Boards(new LoggerMock());
} }
@ -25,8 +30,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::GetJwt()]; $request->header = [DataMock::GetJwt()];
$boards = $this->boards->getAllBoards($request, $boards = $this->boards->getAllBoards($request, new ResponseMock, null);
new ResponseMock, null);
$this->assertEquals(2, count($boards->body->data->data)); $this->assertEquals(2, count($boards->body->data->data));
$this->assertEquals('success', $boards->body->data->status); $this->assertEquals('success', $boards->body->data->status);
} }
@ -35,8 +39,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::GetJwt()]; $request->header = [DataMock::GetJwt()];
$actual = $this->boards->getAllBoards($request, $actual = $this->boards->getAllBoards($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('No boards in database.', $this->assertEquals('No boards in database.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -47,8 +50,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::GetJwt(2)]; $request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->getAllBoards($request, $actual = $this->boards->getAllBoards($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -62,8 +64,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::GetJwt()]; $request->header = [DataMock::GetJwt()];
$actual = $this->boards->getBoard($request, $actual = $this->boards->getBoard($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('success', $actual->body->data->status); $this->assertEquals('success', $actual->body->data->status);
$this->assertEquals(2, count($actual->body->data->data)); $this->assertEquals(2, count($actual->body->data->data));
} }
@ -74,8 +75,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::GetJwt(2)]; $request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->getBoard($request, $actual = $this->boards->getBoard($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -87,8 +87,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::GetJwt()]; $request->header = [DataMock::GetJwt()];
$actual = $this->boards->getBoard($request, $actual = $this->boards->getBoard($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('No board found for ID 1.', $this->assertEquals('No board found for ID 1.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -103,8 +102,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::GetJwt(2)]; $request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->getBoard($request, $actual = $this->boards->getBoard($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -116,8 +114,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request->header = [DataMock::GetJwt()]; $request->header = [DataMock::GetJwt()];
$request->payload = $data; $request->payload = $data;
$actual = $this->boards->addBoard($request, $actual = $this->boards->addBoard($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('Board added (test).', $this->assertEquals('Board added (test).',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
@ -129,8 +126,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::GetJwt(2)]; $request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->addBoard($request, $actual = $this->boards->addBoard($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -140,8 +136,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request->header = [DataMock::GetJwt()]; $request->header = [DataMock::GetJwt()];
$request->invalidPayload = true; $request->invalidPayload = true;
$response = $this->boards->addBoard($request, $response = $this->boards->addBoard($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('failure', $response->body->data->status); $this->assertEquals('failure', $response->body->data->status);
$this->assertEquals('error', $response->body->data->alerts[0]['type']); $this->assertEquals('error', $response->body->data->alerts[0]['type']);
@ -157,8 +152,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request->header = [DataMock::GetJwt()]; $request->header = [DataMock::GetJwt()];
$request->payload = $board; $request->payload = $board;
$response = $this->boards->updateBoard($request, $response = $this->boards->updateBoard($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('success', $response->body->data->status); $this->assertEquals('success', $response->body->data->status);
} }
@ -168,8 +162,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::GetJwt(2)]; $request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->updateBoard($request, $actual = $this->boards->updateBoard($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -181,8 +174,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request->header = [DataMock::GetJwt()]; $request->header = [DataMock::GetJwt()];
$request->invalidPayload = true; $request->invalidPayload = true;
$response = $this->boards->updateBoard($request, $response = $this->boards->updateBoard($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('error', $response->body->data->alerts[0]['type']); $this->assertEquals('error', $response->body->data->alerts[0]['type']);
} }
@ -197,8 +189,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request->header = [DataMock::GetJwt()]; $request->header = [DataMock::GetJwt()];
$request->payload = $board; $request->payload = $board;
$response = $this->boards->updateBoard($request, $response = $this->boards->updateBoard($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$cols = $response->body->data->data[1][0]['ownColumn']; $cols = $response->body->data->data[1][0]['ownColumn'];
$this->assertEquals('success', $response->body->data->status); $this->assertEquals('success', $response->body->data->status);
@ -221,8 +212,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request->header = [DataMock::GetJwt()]; $request->header = [DataMock::GetJwt()];
$request->payload = $board; $request->payload = $board;
$response = $this->boards->updateBoard($request, $response = $this->boards->updateBoard($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('error', $response->body->data->alerts[0]['type']); $this->assertEquals('error', $response->body->data->alerts[0]['type']);
} }
@ -235,8 +225,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::GetJwt(2)]; $request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->updateBoard($request, $actual = $this->boards->updateBoard($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -254,8 +243,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::GetJwt()]; $request->header = [DataMock::GetJwt()];
$actual = $this->boards->removeBoard($request, $actual = $this->boards->removeBoard($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('Board removed (test).', $this->assertEquals('Board removed (test).',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -266,8 +254,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::GetJwt(2)]; $request->header = [DataMock::GetJwt(2)];
$actual = $this->boards->removeBoard($request, $actual = $this->boards->removeBoard($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -281,8 +268,7 @@ class BoardsTest extends PHPUnit\Framework\TestCase {
$this->boards = new Boards(new LoggerMock()); $this->boards = new Boards(new LoggerMock());
$response = $this->boards->removeBoard($request, $response = $this->boards->removeBoard($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('failure', $response->body->data->status); $this->assertEquals('failure', $response->body->data->status);
} }

View File

@ -8,8 +8,7 @@ class ColumnsTest extends PHPUnit\Framework\TestCase {
public static function setUpBeforeClass(): void { public static function setUpBeforeClass(): void {
try { try {
R::setup('sqlite:tests.db'); R::setup('sqlite:tests.db');
} catch (Exception $ex) { } catch (Exception $ex) { }
}
} }
public function setUp(): void { public function setUp(): void {

View File

@ -2,14 +2,16 @@
require_once __DIR__ . '/../Mocks.php'; require_once __DIR__ . '/../Mocks.php';
use RedBeanPHP\R; use RedBeanPHP\R;
/**
* @group single
*/
class CommentsTest extends PHPUnit\Framework\TestCase { class CommentsTest extends PHPUnit\Framework\TestCase {
private $comments; private $comments;
public static function setUpBeforeClass(): void { public static function setUpBeforeClass(): void {
try { try {
R::setup('sqlite:tests.db'); R::setup('sqlite:tests.db');
} catch (Exception $ex) { } catch (Exception $ex) { }
}
} }
public function setUp(): void { public function setUp(): void {
@ -28,8 +30,7 @@ class CommentsTest extends PHPUnit\Framework\TestCase {
$args = []; $args = [];
$args['id'] = 1; $args['id'] = 1;
$actual = $this->comments->getComment($request, $actual = $this->comments->getComment($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('success', $actual->body->data->status); $this->assertEquals('success', $actual->body->data->status);
$this->assertEquals(2, count($actual->body->data->data)); $this->assertEquals(2, count($actual->body->data->data));
} }
@ -41,8 +42,7 @@ class CommentsTest extends PHPUnit\Framework\TestCase {
$args = []; $args = [];
$args['id'] = 1; $args['id'] = 1;
$actual = $this->comments->getComment($request, $actual = $this->comments->getComment($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('No comment found for ID 1.', $this->assertEquals('No comment found for ID 1.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -59,8 +59,7 @@ class CommentsTest extends PHPUnit\Framework\TestCase {
$this->comments = new Comments(new LoggerMock()); $this->comments = new Comments(new LoggerMock());
$actual = $this->comments->getComment($request, $actual = $this->comments->getComment($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -71,8 +70,7 @@ class CommentsTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::GetJwt(2)]; $request->header = [DataMock::GetJwt(2)];
$actual = $this->comments->getComment($request, $actual = $this->comments->getComment($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -85,8 +83,7 @@ class CommentsTest extends PHPUnit\Framework\TestCase {
$request->header = [DataMock::GetJwt()]; $request->header = [DataMock::GetJwt()];
$request->payload = $data; $request->payload = $data;
$actual = $this->comments->addComment($request, $actual = $this->comments->addComment($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('success', $actual->body->data->status); $this->assertEquals('success', $actual->body->data->status);
} }
@ -98,8 +95,7 @@ class CommentsTest extends PHPUnit\Framework\TestCase {
$request->header = [DataMock::GetJwt(2)]; $request->header = [DataMock::GetJwt(2)];
$request->payload = $comment; $request->payload = $comment;
$actual = $this->comments->addComment($request, $actual = $this->comments->addComment($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -109,8 +105,7 @@ class CommentsTest extends PHPUnit\Framework\TestCase {
$request->invalidPayload = true; $request->invalidPayload = true;
$request->header = [DataMock::GetJwt()]; $request->header = [DataMock::GetJwt()];
$actual = $this->comments->addComment($request, $actual = $this->comments->addComment($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('failure', $actual->body->data->status); $this->assertEquals('failure', $actual->body->data->status);
$this->assertEquals('error', $actual->body->data->alerts[0]['type']); $this->assertEquals('error', $actual->body->data->alerts[0]['type']);
} }
@ -124,8 +119,7 @@ class CommentsTest extends PHPUnit\Framework\TestCase {
$request->header = [DataMock::GetJwt(2)]; $request->header = [DataMock::GetJwt(2)];
$request->payload = $comment; $request->payload = $comment;
$actual = $this->comments->addComment($request, $actual = $this->comments->addComment($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -211,7 +205,6 @@ class CommentsTest extends PHPUnit\Framework\TestCase {
$actual = $this->comments->updateComment($request, $actual = $this->comments->updateComment($request,
new ResponseMock(), $args); new ResponseMock(), $args);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -284,12 +277,10 @@ class CommentsTest extends PHPUnit\Framework\TestCase {
$actual = $this->comments->removeComment($request, $actual = $this->comments->removeComment($request,
new ResponseMock(), $args); new ResponseMock(), $args);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
private function getCommentData() { private function getCommentData() {
$data = new stdClass(); $data = new stdClass();
@ -302,16 +293,23 @@ class CommentsTest extends PHPUnit\Framework\TestCase {
} }
private function createComment() { private function createComment() {
$admin = R::load('user', 1);
$comment = R::dispense('comment'); $comment = R::dispense('comment');
R::store($comment); R::store($comment);
$category = R::dispense('category');
$category->name = 'cat';
R::store($category);
$task = R::dispense('task'); $task = R::dispense('task');
$task->xownCommentList[] = $comment; $task->xownCommentList[] = $comment;
$task->sharedUserList[] = $admin;
$task->sharedCategoryList[] = $category;
$column = R::dispense('column'); $column = R::dispense('column');
$column->xownTaskList[] = $task; $column->xownTaskList[] = $task;
$admin = R::load('user', 1);
$board = R::dispense('board'); $board = R::dispense('board');
$board->xownColumnList[] = $column; $board->xownColumnList[] = $column;
$board->sharedUserList[] = $admin; $board->sharedUserList[] = $admin;

View File

@ -8,8 +8,7 @@ class TasksTest extends PHPUnit\Framework\TestCase {
public static function setUpBeforeClass(): void { public static function setUpBeforeClass(): void {
try { try {
R::setup('sqlite:tests.db'); R::setup('sqlite:tests.db');
} catch (Exception $ex) { } catch (Exception $ex) { }
}
} }
public function setUp(): void { public function setUp(): void {
@ -126,8 +125,7 @@ class TasksTest extends PHPUnit\Framework\TestCase {
$request->invalidPayload = true; $request->invalidPayload = true;
$request->header = [DataMock::getJwt()]; $request->header = [DataMock::getJwt()];
$response = $this->tasks->addTask($request, $response = $this->tasks->addTask($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('failure', $response->body->data->status); $this->assertEquals('failure', $response->body->data->status);
$this->assertEquals('error', $response->body->data->alerts[0]['type']); $this->assertEquals('error', $response->body->data->alerts[0]['type']);
@ -163,8 +161,7 @@ class TasksTest extends PHPUnit\Framework\TestCase {
$request->header = [DataMock::getJwt()]; $request->header = [DataMock::getJwt()];
$request->payload = $task; $request->payload = $task;
$response = $this->tasks->updateTask($request, $response = $this->tasks->updateTask($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('success', $response->body->data->status); $this->assertEquals('success', $response->body->data->status);
} }
@ -192,8 +189,7 @@ class TasksTest extends PHPUnit\Framework\TestCase {
$request->header = [DataMock::getJwt()]; $request->header = [DataMock::getJwt()];
$request->payload = $task; $request->payload = $task;
$response = $this->tasks->updateTask($request, $response = $this->tasks->updateTask($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('success', $response->body->data->status); $this->assertEquals('success', $response->body->data->status);
$updated = $response->body->data->data[1][0]; $updated = $response->body->data->data[1][0];
@ -212,8 +208,7 @@ class TasksTest extends PHPUnit\Framework\TestCase {
$request->header = [DataMock::getJwt()]; $request->header = [DataMock::getJwt()];
$request->payload = $task; $request->payload = $task;
$response = $this->tasks->updateTask($request, $response = $this->tasks->updateTask($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('success', $response->body->data->status); $this->assertEquals('success', $response->body->data->status);
} }
@ -225,12 +220,10 @@ class TasksTest extends PHPUnit\Framework\TestCase {
$args = []; $args = [];
$args['id'] = 1; $args['id'] = 1;
$response = $this->tasks->updateTask($request, $response = $this->tasks->updateTask($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('error', $response->body->data->alerts[0]['type']); $this->assertEquals('error', $response->body->data->alerts[0]['type']);
$response = $this->tasks->updateTask($request, $response = $this->tasks->updateTask($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('error', $response->body->data->alerts[0]['type']); $this->assertEquals('error', $response->body->data->alerts[0]['type']);
} }
@ -240,8 +233,7 @@ class TasksTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::getJwt(2)]; $request->header = [DataMock::getJwt(2)];
$actual = $this->tasks->updateTask($request, $actual = $this->tasks->updateTask($request, new ResponseMock(), null);
new ResponseMock(), null);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -261,8 +253,7 @@ class TasksTest extends PHPUnit\Framework\TestCase {
$request->header = [DataMock::getJwt(2)]; $request->header = [DataMock::getJwt(2)];
$request->payload = $task; $request->payload = $task;
$actual = $this->tasks->updateTask($request, $actual = $this->tasks->updateTask($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -276,8 +267,7 @@ class TasksTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::getJwt()]; $request->header = [DataMock::getJwt()];
$actual = $this->tasks->removeTask($request, $actual = $this->tasks->removeTask($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('Task removed (test).', $this->assertEquals('Task removed (test).',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
@ -292,8 +282,7 @@ class TasksTest extends PHPUnit\Framework\TestCase {
$request = new RequestMock(); $request = new RequestMock();
$request->header = [DataMock::getJwt(2)]; $request->header = [DataMock::getJwt(2)];
$actual = $this->tasks->removeTask($request, $actual = $this->tasks->removeTask($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -305,8 +294,7 @@ class TasksTest extends PHPUnit\Framework\TestCase {
$args = []; $args = [];
$args['id'] = 2; // No such task $args['id'] = 2; // No such task
$response = $this->tasks->removeTask($request, $response = $this->tasks->removeTask($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('failure', $response->body->data->status); $this->assertEquals('failure', $response->body->data->status);
} }
@ -320,8 +308,7 @@ class TasksTest extends PHPUnit\Framework\TestCase {
$args = []; $args = [];
$args['id'] = 1; $args['id'] = 1;
$actual = $this->tasks->removeTask($request, $actual = $this->tasks->removeTask($request, new ResponseMock(), $args);
new ResponseMock(), $args);
$this->assertEquals('Access restricted.', $this->assertEquals('Access restricted.',
$actual->body->data->alerts[0]['text']); $actual->body->data->alerts[0]['text']);
} }
@ -432,6 +419,8 @@ class TasksTest extends PHPUnit\Framework\TestCase {
$category = R::dispense('category'); $category = R::dispense('category');
$category2 = R::dispense('category'); $category2 = R::dispense('category');
$task->sharedCategoryList[] = $category;
$board = R::dispense('board'); $board = R::dispense('board');
$board->xownColumnList[] = $column; $board->xownColumnList[] = $column;
$board->xownColumnList[] = $column2; $board->xownColumnList[] = $column2;

View File

@ -8,8 +8,7 @@ class UsersTest extends PHPUnit\Framework\TestCase {
public static function setUpBeforeClass(): void { public static function setUpBeforeClass(): void {
try { try {
R::setup('sqlite:tests.db'); R::setup('sqlite:tests.db');
} catch (Exception $ex) { } catch (Exception $ex) { }
}
} }
public function setUp(): void { public function setUp(): void {