Compare commits

..

3 Commits

Author SHA1 Message Date
b54a21dd2d „data/seed_data/skills.csv“ ändern
Some checks failed
continuous-integration/drone/push Build is failing
2021-07-26 19:59:29 +02:00
ea2b8a815c „data/seed_data/skills.csv“ ändern
Some checks failed
continuous-integration/drone/push Build is failing
2021-07-26 19:57:07 +02:00
db0f033b3a „data/seed_data/skills.csv“ ändern
Some checks failed
continuous-integration/drone/push Build is failing
2021-07-26 19:56:36 +02:00
14 changed files with 115 additions and 402 deletions

View File

@ -26,6 +26,9 @@ steps:
from_secret: "docker_username" from_secret: "docker_username"
password: password:
from_secret: "docker_password" from_secret: "docker_password"
when:
event:
- tag
image_pull_secrets: image_pull_secrets:
- dockerconfig - dockerconfig

View File

@ -17,7 +17,6 @@ waitress = "~=2.0.0"
pyyaml = "~=5.4.1" pyyaml = "~=5.4.1"
flask-cors = "~=3.0.10" flask-cors = "~=3.0.10"
ldap3 = "~=2.9" ldap3 = "~=2.9"
pymysql = "~=1.0.2"
[dev-packages] [dev-packages]
flake8 = "~=3.9.2" flake8 = "~=3.9.2"

153
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "332b04c923ecb74bc066ee5348a664274ce87736981cc8e56e60070ff26e7d0e" "sha256": "9dfe9cdb37253c770013fcf80c413f9b0ffdfc1cc16210fb9d80cdac760c2b93"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -29,7 +29,7 @@
"sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a", "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a",
"sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6" "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"
], ],
"markers": "python_version >= '3.6'", "markers": "python_full_version >= '3.6.0'",
"version": "==8.0.1" "version": "==8.0.1"
}, },
"flask": { "flask": {
@ -124,7 +124,7 @@
"sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c", "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c",
"sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0" "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0"
], ],
"markers": "python_version >= '3.6'", "markers": "python_full_version >= '3.6.0'",
"version": "==2.0.1" "version": "==2.0.1"
}, },
"jinja2": { "jinja2": {
@ -132,19 +132,19 @@
"sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4", "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4",
"sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4" "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"
], ],
"markers": "python_version >= '3.6'", "markers": "python_full_version >= '3.6.0'",
"version": "==3.0.1" "version": "==3.0.1"
}, },
"ldap3": { "ldap3": {
"hashes": [ "hashes": [
"sha256:2bc966556fc4d4fa9f445a1c31dc484ee81d44a51ab0e2d0fd05b62cac75daa6", "sha256:18c3ee656a6775b9b0d60f7c6c5b094d878d1d90fc03d56731039f0a4b546a91",
"sha256:5630d1383e09ba94839e253e013f1aa1a2cf7a547628ba1265cb7b9a844b5687", "sha256:4139c91f0eef9782df7b77c8cbc6243086affcb6a8a249b768a9658438e5da59",
"sha256:5869596fc4948797020d3f03b7939da938778a0f9e2009f7a072ccf92b8e8d70", "sha256:8c949edbad2be8a03e719ba48bd6779f327ec156929562814b3e84ab56889c8c",
"sha256:5ab7febc00689181375de40c396dcad4f2659cd260fc5e94c508b6d77c17e9d5", "sha256:afc6fc0d01f02af82cd7bfabd3bbfd5dc96a6ae91e97db0a2dab8a0f1b436056",
"sha256:f3e7fc4718e3f09dda568b57100095e0ce58633bcabbed8667ce3f8fbaa4229f" "sha256:c1df41d89459be6f304e0ceec4b00fdea533dbbcd83c802b1272dcdb94620b57"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.9.1" "version": "==2.9"
}, },
"mako": { "mako": {
"hashes": [ "hashes": [
@ -191,7 +191,7 @@
"sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51",
"sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"
], ],
"markers": "python_version >= '3.6'", "markers": "python_full_version >= '3.6.0'",
"version": "==2.0.1" "version": "==2.0.1"
}, },
"pyasn1": { "pyasn1": {
@ -212,21 +212,13 @@
], ],
"version": "==0.4.8" "version": "==0.4.8"
}, },
"pymysql": {
"hashes": [
"sha256:41fc3a0c5013d5f039639442321185532e3e2c8924687abe6537de157d403641",
"sha256:816927a350f38d56072aeca5dfb10221fe1dc653745853d30a216637f5d7ad36"
],
"index": "pypi",
"version": "==1.0.2"
},
"python-dateutil": { "python-dateutil": {
"hashes": [ "hashes": [
"sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
"sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.8.2" "version": "==2.8.1"
}, },
"python-dotenv": { "python-dotenv": {
"hashes": [ "hashes": [
@ -291,39 +283,39 @@
}, },
"sqlalchemy": { "sqlalchemy": {
"hashes": [ "hashes": [
"sha256:09dbb4bc01a734ccddbf188deb2a69aede4b3c153a72b6d5c6900be7fb2945b1", "sha256:0f6d467b67a7e5048f1408e8ea60d6caa70be5b386d0eebbf1185ab49cb8c7e4",
"sha256:12bac5fa1a6ea870bdccb96fe01610641dd44ebe001ed91ef7fcd980e9702db5", "sha256:238d78b3110b7f7cffdb70bf9cda686e0d876a849bc78ba4d471aa7b1461f306",
"sha256:1fdae7d980a2fa617d119d0dc13ecb5c23cc63a8b04ffcb5298f2c59d86851e9", "sha256:25c0e0f3a7e8c19350086b3c0fe93c4def045cec053d749ef15da710c4d54c81",
"sha256:26daa429f039e29b1e523bf763bfab17490556b974c77b5ca7acb545b9230e9a", "sha256:2f60a2e599cf5cf5e5327ce60f2918b897e42ad9f405d10dd01e37869c0ce6fc",
"sha256:36a089dc604032d41343d86290ce85d4e6886012eea73faa88001260abf5ff81", "sha256:38ee3a266afef2978e82824650457f70c5d74ec0cadec1b10fe5ed6f038eb5d0",
"sha256:39b5d36ab71f73c068cdcf70c38075511de73616e6c7fdd112d6268c2704d9f5", "sha256:46361690f1e1c5385994a4caeb6e8126063ff593a5c635700bbc1245de793c1e",
"sha256:4014978de28163cd8027434916a92d0f5bb1a3a38dff5e8bf8bff4d9372a9117", "sha256:46b99eab618cdc1c871ea707b7c52edc23cfea6c750740cd242ba62b5c84de7f",
"sha256:44d23ea797a5e0be71bc5454b9ae99158ea0edc79e2393c6e9a2354de88329c0", "sha256:4a67371752fd86d1d03a3b82d4e75404608f6f4d579b9676124079a22a40c79f",
"sha256:488608953385d6c127d2dcbc4b11f8d7f2f30b89f6bd27c01b042253d985cc2f", "sha256:525dd3c2205b11a2bc6d770bf1ec63bde0253fd754b4c19c399d27ddc9dad0d3",
"sha256:5102b9face693e8b2db3b2539c7e1a5d9a5b4dc0d79967670626ffd2f710d6e6", "sha256:6c8406c3d8c1c7d15da454de15d77f7bb48d14ede5db994f74226c348cf1050e",
"sha256:5908ea6c652a050d768580d01219c98c071e71910ab8e7b42c02af4010608397", "sha256:6da83225a23eaf7b3f48f3d5f53c91b2cf00fbfa48b24a7a758160112dd3e123",
"sha256:5d856cc50fd26fc8dd04892ed5a5a3d7eeb914fea2c2e484183e2d84c14926e0", "sha256:7150e5b543b466f45f668b352f7abda27998cc8035f051d1b7e9524ca9eb2f5f",
"sha256:68393d3fd31469845b6ba11f5b4209edbea0b58506be0e077aafbf9aa2e21e11", "sha256:76fbc24311a3d039d6cd147d396719f606d96d1413f3816c028a48e29367f646",
"sha256:6a16c7c4452293da5143afa3056680db2d187b380b3ef4d470d4e29885720de3", "sha256:854a7b15750e617e16f8d65dbc004f065a7963544b253b923f16109557648777",
"sha256:756f5d2f5b92d27450167247fb574b09c4cd192a3f8c2e493b3e518a204ee543", "sha256:86c079732328f1add097b0b8079cd532b5d28e207fac93e9d6ea5f487506deef",
"sha256:891927a49b2363a4199763a9d436d97b0b42c65922a4ea09025600b81a00d17e", "sha256:8d860c62e3f51623ccd528d8fac44580501df557d4b467cc5581587fcf057719",
"sha256:9bfe882d5a1bbde0245dca0bd48da0976bd6634cf2041d2fdf0417c5463e40e5", "sha256:9675d5bc7e4f96a7bb2b54d14e9b269a5fb6e5d36ecc7d01f0f65bb9af3185f9",
"sha256:9fcbb4b4756b250ed19adc5e28c005b8ed56fdb5c21efa24c6822c0575b4964d", "sha256:9841762d114018c49483c089fa2d47f7e612e57666323f615913d7d7f46e9606",
"sha256:a00d9c6d3a8afe1d1681cd8a5266d2f0ed684b0b44bada2ca82403b9e8b25d39", "sha256:9eb25bcf9161e2fcbe9eebe8e829719b2334e849183f0e496bf4b83722bcccfa",
"sha256:a5e14cb0c0a4ac095395f24575a0e7ab5d1be27f5f9347f1762f21505e3ba9f1", "sha256:aad3234a41340e9cf6184e621694e2a7233ba3f8aef9b1e6de8cba431b45ebd2",
"sha256:b48148ceedfb55f764562e04c00539bb9ea72bf07820ca15a594a9a049ff6b0e", "sha256:b502b5e2f08500cc4b8d29bfc4f51d805adcbc00f8d149e98fda8aae85ddb644",
"sha256:b7fb937c720847879c7402fe300cfdb2aeff22349fa4ea3651bca4e2d6555939", "sha256:b86d83fefc8a8c394f3490c37e1953bc16c311a3d1d1cf91518793bfb9847fb4",
"sha256:bc34a007e604091ca3a4a057525efc4cefd2b7fe970f44d20b9cfa109ab1bddb", "sha256:c0eb2cd3ad4967fcbdd9e066e8cd91fe2c23c671dbae9952f0b4d3d42832cc5f",
"sha256:c9373ef67a127799027091fa53449125351a8c943ddaa97bec4e99271dbb21f4", "sha256:e0d48456e1aa4f0537f9c9af7be71e1f0659ff68bc1cd538ebc785f6b007bd0d",
"sha256:d09a760b0a045b4d799102ae7965b5491ccf102123f14b2a8cc6c01d1021a2d9", "sha256:eaee5dd378f6f0d7c3ec49aeeb26564d55ac0ad73b9b4688bf29e66deabddf73",
"sha256:ec1be26cdccd60d180359a527d5980d959a26269a2c7b1b327a1eea0cab37ed8", "sha256:f14acb0fd16d404fda9370f93aace682f284340c89c3442ac747c5466ac7e2b5",
"sha256:eedd76f135461cf237534a6dc0d1e0f6bb88a1dc193678fab48a11d223462da5", "sha256:f6fc526bd70898489d02bf52c8f0632ab377592ae954d0c0a5bb38d618dddaa9",
"sha256:f028ef6a1d828bc754852a022b2160e036202ac8658a6c7d34875aafd14a9a15", "sha256:fcd84e4d46a86291495d131a7824ba38d2e8278bda9425c50661a04633174319",
"sha256:f814d80844969b0d22ea63663da4de5ca1c434cfbae226188901e5d368792c17", "sha256:ff38ecf89c69a531a7326c2dae71982edfe2f805f3c016cdc5bfd1a04ebf80cb",
"sha256:fd2102a8f8a659522719ed73865dff3d3cc76eb0833039dc473e0ad3041d04be" "sha256:ff8bebc7a9d297dff2003460e01db2c20c63818b45fb19170f388b1a72fe5a14"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.4.22" "version": "==1.4.20"
}, },
"waitress": { "waitress": {
"hashes": [ "hashes": [
@ -338,18 +330,17 @@
"sha256:1de1db30d010ff1af14a009224ec49ab2329ad2cde454c8a708130642d579c42", "sha256:1de1db30d010ff1af14a009224ec49ab2329ad2cde454c8a708130642d579c42",
"sha256:6c1ec500dcdba0baa27600f6a22f6333d8b662d22027ff9f6202e3367413caa8" "sha256:6c1ec500dcdba0baa27600f6a22f6333d8b662d22027ff9f6202e3367413caa8"
], ],
"markers": "python_version >= '3.6'", "markers": "python_full_version >= '3.6.0'",
"version": "==2.0.1" "version": "==2.0.1"
} }
}, },
"develop": { "develop": {
"backports.entry-points-selectable": { "appdirs": {
"hashes": [ "hashes": [
"sha256:988468260ec1c196dab6ae1149260e2f5472c9110334e5d51adcb77867361f6a", "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41",
"sha256:a6d9a871cde5e15b4c4a53e3d43ba890cc6861ec1332c9c2428c92f977192acc" "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"
], ],
"markers": "python_version >= '2.7'", "version": "==1.4.4"
"version": "==1.1.0"
}, },
"binaryornot": { "binaryornot": {
"hashes": [ "hashes": [
@ -388,14 +379,6 @@
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==4.0.0" "version": "==4.0.0"
}, },
"charset-normalizer": {
"hashes": [
"sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b",
"sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"
],
"markers": "python_version >= '3'",
"version": "==2.0.4"
},
"distlib": { "distlib": {
"hashes": [ "hashes": [
"sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736", "sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736",
@ -428,18 +411,18 @@
}, },
"idna": { "idna": {
"hashes": [ "hashes": [
"sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a", "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
"sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
], ],
"markers": "python_version >= '3'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==3.2" "version": "==2.10"
}, },
"jinja2": { "jinja2": {
"hashes": [ "hashes": [
"sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4", "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4",
"sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4" "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"
], ],
"markers": "python_version >= '3.6'", "markers": "python_full_version >= '3.6.0'",
"version": "==3.0.1" "version": "==3.0.1"
}, },
"license-expression": { "license-expression": {
@ -486,7 +469,7 @@
"sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51",
"sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"
], ],
"markers": "python_version >= '3.6'", "markers": "python_full_version >= '3.6.0'",
"version": "==2.0.1" "version": "==2.0.1"
}, },
"mccabe": { "mccabe": {
@ -503,14 +486,6 @@
], ],
"version": "==1.6.0" "version": "==1.6.0"
}, },
"platformdirs": {
"hashes": [
"sha256:4666d822218db6a262bdfdc9c39d21f23b4cfdb08af331a81e92751daf6c866c",
"sha256:632daad3ab546bd8e6af0537d09805cec458dce201bccfe23012df73332e181e"
],
"markers": "python_version >= '3.6'",
"version": "==2.2.0"
},
"pre-commit": { "pre-commit": {
"hashes": [ "hashes": [
"sha256:764972c60693dc668ba8e86eb29654ec3144501310f7198742a767bec385a378", "sha256:764972c60693dc668ba8e86eb29654ec3144501310f7198742a767bec385a378",
@ -580,11 +555,11 @@
}, },
"requests": { "requests": {
"hashes": [ "hashes": [
"sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
"sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==2.26.0" "version": "==2.25.1"
}, },
"reuse": { "reuse": {
"hashes": [ "hashes": [
@ -620,11 +595,11 @@
}, },
"virtualenv": { "virtualenv": {
"hashes": [ "hashes": [
"sha256:97066a978431ec096d163e72771df5357c5c898ffdd587048f45e0aecc228094", "sha256:14fdf849f80dbb29a4eb6caa9875d476ee2a5cf76a5f5415fa2f1606010ab467",
"sha256:fdfdaaf0979ac03ae7f76d5224a05b58165f3c804f8aa633f3dd6f22fbd435d5" "sha256:2b0126166ea7c9c3661f5b8e06773d28f83322de7a3ff7d06f0aed18c9de6a76"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==20.7.0" "version": "==20.4.7"
}, },
"yapf": { "yapf": {
"hashes": [ "hashes": [

View File

@ -177,26 +177,6 @@ Für die Produktionsumgebung wird [waitress](https://docs.pylonsproject.org/proj
[`run_prod.py`](./run_prod.py) führt die DB Migrationen aus und startet den Server. [`run_prod.py`](./run_prod.py) führt die DB Migrationen aus und startet den Server.
## Integrationsumgebung
Per [`docker-compose`](https://docs.docker.com/compose/) kann eine Integrationsumgebung gestartet werden.
Beide Projekte müssen nebeneinander ausgecheckt sein:
```
./
ki-backend
ki-frontend
```
Alles starten:
```
docker-compose up
```
Dann http://localhost:13337 aufrufen.
## Lizenzen ## Lizenzen
Dieses Projekt erfüllt die [REUSE](https://reuse.software/) Spezifikation. Dieses Projekt erfüllt die [REUSE](https://reuse.software/) Spezifikation.

View File

@ -15,112 +15,4 @@ id,name
14,C 14,C
15,VHDL 15,VHDL
16,go 16,go
17,Perl 17, Perl
18,3D-Druck
19,ABAP
20,Android
21,Ansible
22,Arduino
23,Bash
24,batou
25,bind
26,Buchführung
27,C#
28,CAD
29,CAM
30,Cobol
31,CRM
32,CSS
33,D
34,Debian
35,Delphi
36,DevOPS
37,Discourse
38,Django
39,DNS
40,Dovecot
41,Elasticsearch
42,Emacs
43,Email
44,ERP
45,ESP
46,Excel
47,Fahrdienstleitung
48,Fedora
49,FLOSS
50,Geographie
51,Geologie
52,Gnome
53,GPS
54,Grafana
55,GrayLog
56,GSM
57,GTK
58,HTML
59,IBM Z
60,IMAP
61,Ionic
62,iOS
63,Java
64,Kryptographie
65,LDAP
66,LibreOffice
67,Linux
68,Literaturgeschichte
69,Lithographie
70,Lucene
71,Mailman
72,MariaDB
73,Markdown
74,Marketing
75,Microsoft Office
76,Monitoring
77,Nagios
78,nähen
79,NixOS
80,odoo
81,OpenOffice
82,OpenPGP
83,OpenStreetMap
84,openSUSE
85,Oracle
86,Percona
87,PGP
88,Plone
89,Postfix
90,PowerDNS
91,PowerPC
92,Projektmanagement
93,puppet
94,Qt
95,R/3
96,RedHat
97,RHEL
98,S/4
99,Salt
100,SAP
101,Scrum
102,ScummVM
103,Sensu
104,sh
105,Siemens S5
106,Siemens S7
107,Simatic
108,SLES
109,Spring
110,SQL
111,Stenographie
112,Steuerrecht
113,Teppich knüpfen
114,TeX
115,Verlagswesen
116,vi(m)
117,Windows 10
118,Windows 2000
119,Windows 2012R2
120,Windows 7
121,Windows NT
122,Windows XP
123,x86
124,Zope
125,zsh
1 id name
15 14 C
16 15 VHDL
17 16 go
18 17 Perl
18 3D-Druck
19 ABAP
20 Android
21 Ansible
22 Arduino
23 Bash
24 batou
25 bind
26 Buchführung
27 C#
28 CAD
29 CAM
30 Cobol
31 CRM
32 CSS
33 D
34 Debian
35 Delphi
36 DevOPS
37 Discourse
38 Django
39 DNS
40 Dovecot
41 Elasticsearch
42 Emacs
43 Email
44 ERP
45 ESP
46 Excel
47 Fahrdienstleitung
48 Fedora
49 FLOSS
50 Geographie
51 Geologie
52 Gnome
53 GPS
54 Grafana
55 GrayLog
56 GSM
57 GTK
58 HTML
59 IBM Z
60 IMAP
61 Ionic
62 iOS
63 Java
64 Kryptographie
65 LDAP
66 LibreOffice
67 Linux
68 Literaturgeschichte
69 Lithographie
70 Lucene
71 Mailman
72 MariaDB
73 Markdown
74 Marketing
75 Microsoft Office
76 Monitoring
77 Nagios
78 nähen
79 NixOS
80 odoo
81 OpenOffice
82 OpenPGP
83 OpenStreetMap
84 openSUSE
85 Oracle
86 Percona
87 PGP
88 Plone
89 Postfix
90 PowerDNS
91 PowerPC
92 Projektmanagement
93 puppet
94 Qt
95 R/3
96 RedHat
97 RHEL
98 S/4
99 Salt
100 SAP
101 Scrum
102 ScummVM
103 Sensu
104 sh
105 Siemens S5
106 Siemens S7
107 Simatic
108 SLES
109 Spring
110 SQL
111 Stenographie
112 Steuerrecht
113 Teppich knüpfen
114 TeX
115 Verlagswesen
116 vi(m)
117 Windows 10
118 Windows 2000
119 Windows 2012R2
120 Windows 7
121 Windows NT
122 Windows XP
123 x86
124 Zope
125 zsh

View File

@ -1,22 +0,0 @@
# SPDX-FileCopyrightText: 2021 WTF Kooperative eG <https://wtf-eg.de/>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
version: "3"
services:
ki_backend:
build: .
restart: "no"
ports:
- "13338:5000"
volumes:
- "./env.dev:/app/.env"
ki_frontend:
build: ./../ki-frontend
restart: "no"
ports:
- "13337:80"
volumes:
- "../ki-frontend/public/config.js.int:/user/share/nginx/html/config.js"

View File

@ -26,31 +26,6 @@ def seed_contacttypes():
db.session.add(ContactType(id=int(contacttype["id"]), name=contacttype["name"])) db.session.add(ContactType(id=int(contacttype["id"]), name=contacttype["name"]))
def seed_user(nickname, visible=False, skills=[], languages=[], volunteerwork="", availability="", freetext=""):
app.logger.info(f"seeding {nickname} \\o/")
user = User(auth_id=nickname)
db.session.add(user)
profile = Profile(nickname=nickname,
pronouns="",
volunteerwork=volunteerwork,
availability=availability,
freetext=freetext,
visible=visible,
user=user)
for skill_data in skills:
skill = ProfileSkill(profile=profile, skill_id=skill_data[0], level=skill_data[1])
db.session.add(skill)
for language_data in languages:
language = ProfileLanguage(profile=profile, language_id=language_data[0], level=language_data[1])
db.session.add(language)
db.session.add(profile)
def seed(dev: bool): def seed(dev: bool):
seed_contacttypes() seed_contacttypes()
@ -130,21 +105,23 @@ def seed(dev: bool):
peter_fr = ProfileLanguage(profile=peters_profile, language_id="fr", level=3) peter_fr = ProfileLanguage(profile=peters_profile, language_id="fr", level=3)
db.session.add(peter_fr) db.session.add(peter_fr)
seed_user("klaus") app.logger.info("seeding klaus :D")
seed_user("dirtydieter", klaus = User(auth_id="klaus")
visible=True, db.session.add(klaus)
volunteerwork="Müll sammeln",
availability="Nur nachts",
freetext="1001010010111!!!",
skills=[(Skill.skill_id_php, 5)])
seed_user("jutta", app.logger.info("seeding dieter \\o/")
visible=True,
languages=[("fr", 5)], dieter = User(auth_id="dieter")
skills=[(Skill.skill_id_php, 3), (Skill.skill_id_mysql, 4)]) db.session.add(dieter)
seed_user("giesela", visible=True, skills=[(Skill.skill_id_mysql, 3), (Skill.skill_id_postgresql, 5)])
seed_user("bertha", visible=False, skills=[(Skill.skill_id_sqlite, 3), (Skill.skill_id_postgresql, 5)]) dieters_profile = Profile(nickname="dirtydieter",
seed_user("monique", visible=True, languages=[("fr", 4)]) pronouns="",
volunteerwork="Müll sammeln",
availability="Nur nachts",
freetext="1001010010111!!!",
visible=True,
user=dieter)
db.session.add(dieters_profile)
db.session.commit() db.session.commit()

View File

@ -4,7 +4,7 @@
from flask import make_response, request from flask import make_response, request
from ki.models import Profile, ProfileSkill, Skill, ProfileLanguage, Language from ki.models import Profile
def find_profiles(): def find_profiles():
@ -18,21 +18,13 @@ def find_profiles():
if page_size > 100: if page_size > 100:
return make_response({"messages": {"page_size": "Die maximale Anzahl Einträge pro Seite beträgt 100"}}, 400) return make_response({"messages": {"page_size": "Die maximale Anzahl Einträge pro Seite beträgt 100"}}, 400)
query = Profile.query.filter(Profile.visible.is_(True)) \ query = Profile.query.filter(Profile.visible.is_(True))
.join(Profile.skills, isouter=True).join(ProfileSkill.skill, isouter=True) \
.join(Profile.languages, isouter=True).join(ProfileLanguage.language, isouter=True)
if "search" in request.args:
terms = request.args["search"].split(" ")
for term in terms:
query = query.filter(
Profile.nickname.like(f"%{term}%") | Skill.name.like(f"%{term}%") | Language.name.like(f"%{term}%"))
if "nickname" in request.args: if "nickname" in request.args:
nickname = request.args.get("nickname") nickname = request.args.get("nickname")
query = query.filter(Profile.nickname.like(f"%{nickname}%")) query = query.filter(Profile.nickname.like(f"%{nickname}%"))
count = query.distinct(Profile.id).count() count = query.count()
offset = (page - 1) * page_size offset = (page - 1) * page_size
db_profiles = query.limit(page_size).offset(offset).all() db_profiles = query.limit(page_size).offset(offset).all()

View File

@ -133,13 +133,6 @@ class Address(db.Model):
class Skill(db.Model): class Skill(db.Model):
skill_id_php = 1
skill_id_python = 3
skill_id_sqlalchemy = 7
skill_id_mysql = 9
skill_id_postgresql = 10
skill_id_sqlite = 11
__tablename__ = "skill" __tablename__ = "skill"
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
@ -153,19 +146,6 @@ class Skill(db.Model):
class ProfileSkill(db.Model): class ProfileSkill(db.Model):
level1_text = "bis 6 Monate"
level2_text = "bis 1 Jahr"
level3_text = "bis 3 Jahre"
level4_text = "bis 5 Jahre"
level5_text = "mehr als 5 Jahre"
level_texts = {
1: level1_text,
2: level2_text,
3: level3_text,
4: level4_text,
5: level5_text,
}
__tablename__ = "profile_skill" __tablename__ = "profile_skill"
profile_id = Column(Integer, ForeignKey("profile.id"), primary_key=True) profile_id = Column(Integer, ForeignKey("profile.id"), primary_key=True)
@ -195,8 +175,8 @@ class ProfileSearchtopic(db.Model):
class Language(db.Model): class Language(db.Model):
__tablename__ = "language" __tablename__ = "language"
id = Column(String(4), primary_key=True) id = Column(String(2), primary_key=True)
name = Column(String(100), nullable=False) name = Column(String(25), nullable=False)
profiles = relationship("ProfileLanguage", back_populates="language") profiles = relationship("ProfileLanguage", back_populates="language")
@ -205,23 +185,10 @@ class Language(db.Model):
class ProfileLanguage(db.Model): class ProfileLanguage(db.Model):
level1_text = "keine Angabe"
level2_text = "Grundkenntnisse"
level3_text = "Gut"
level4_text = "Fließend"
level5_text = "Muttersprache"
level_texts = {
1: level1_text,
2: level2_text,
3: level3_text,
4: level4_text,
5: level5_text,
}
__tablename__ = "profile_language" __tablename__ = "profile_language"
profile_id = Column(Integer, ForeignKey("profile.id"), primary_key=True) profile_id = Column(Integer, ForeignKey("profile.id"), primary_key=True)
language_id = Column(String(4), ForeignKey("language.id"), primary_key=True) language_id = Column(Integer, ForeignKey("language.id"), primary_key=True)
level = Column(SmallInteger, nullable=False) level = Column(SmallInteger, nullable=False)
profile = relationship("Profile", back_populates="languages") profile = relationship("Profile", back_populates="languages")

View File

@ -8,7 +8,6 @@ import unittest
from app import app, db, migrate from app import app, db, migrate
from ki.actions import seed from ki.actions import seed
from ki.models import Skill
class ApiTest(unittest.TestCase): class ApiTest(unittest.TestCase):
@ -27,8 +26,6 @@ class ApiTest(unittest.TestCase):
command.upgrade(config, "head") command.upgrade(config, "head")
seed(True) seed(True)
max_skill = Skill.query.order_by(Skill.id.desc()).first()
self.max_skill_id = max_skill.id
def tearDown(self): def tearDown(self):
db.drop_all() db.drop_all()

View File

@ -34,59 +34,9 @@ class TestFindProfilesEndpoint(ApiTest):
response = self.client.get("/users/profiles", headers={"Authorization": "Bearer " + token}) response = self.client.get("/users/profiles", headers={"Authorization": "Bearer " + token})
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertDictContainsSubset({"total": 4}, response.json)
self.assertDictContainsSubset({"nickname": "dirtydieter"}, response.json["profiles"][0])
def test_find_dieter(self):
token = self.login("peter", "geheim")["token"]
response = self.client.get("/users/profiles?search=dieter%20php", headers={"Authorization": "Bearer " + token})
self.assertEqual(response.status_code, 200)
self.assertDictContainsSubset({"total": 1}, response.json) self.assertDictContainsSubset({"total": 1}, response.json)
self.assertDictContainsSubset({"nickname": "dirtydieter"}, response.json["profiles"][0]) self.assertDictContainsSubset({"nickname": "dirtydieter"}, response.json["profiles"][0])
def test_not_find_dieter(self):
token = self.login("peter", "geheim")["token"]
response = self.client.get("/users/profiles?search=dieter%20sqlite",
headers={"Authorization": "Bearer " + token})
self.assertEqual(response.status_code, 200)
self.assertDictContainsSubset({"total": 0}, response.json)
def test_find_sql(self):
token = self.login("peter", "geheim")["token"]
response = self.client.get("/users/profiles?search=sql", headers={"Authorization": "Bearer " + token})
self.assertEqual(response.status_code, 200)
self.assertDictContainsSubset({"total": 2}, response.json)
self.assertDictContainsSubset({"nickname": "jutta"}, response.json["profiles"][0])
self.assertDictContainsSubset({"nickname": "giesela"}, response.json["profiles"][1])
def test_find_postgres(self):
token = self.login("peter", "geheim")["token"]
response = self.client.get("/users/profiles?search=post", headers={"Authorization": "Bearer " + token})
self.assertEqual(response.status_code, 200)
self.assertDictContainsSubset({"total": 1}, response.json)
self.assertDictContainsSubset({"nickname": "giesela"}, response.json["profiles"][0])
def test_find_php_franzosen(self):
token = self.login("peter", "geheim")["token"]
response = self.client.get("/users/profiles?search=php%20franz", headers={"Authorization": "Bearer " + token})
self.assertEqual(response.status_code, 200)
self.assertDictContainsSubset({"total": 1}, response.json)
self.assertDictContainsSubset({"nickname": "jutta"}, response.json["profiles"][0])
def test_find_franzosen(self):
token = self.login("peter", "geheim")["token"]
response = self.client.get("/users/profiles?search=französisch", headers={"Authorization": "Bearer " + token})
self.assertEqual(response.status_code, 200)
self.assertDictContainsSubset({"total": 2}, response.json)
self.assertDictContainsSubset({"nickname": "jutta"}, response.json["profiles"][0])
self.assertDictContainsSubset({"nickname": "monique"}, response.json["profiles"][1])
if __name__ == "main": if __name__ == "main":
unittest.main() unittest.main()

View File

@ -143,7 +143,7 @@ class TestProfileEndpoint(ApiTest):
self.assertEqual(first_skill.level, 4) self.assertEqual(first_skill.level, 4)
second_skill = skills[1] second_skill = skills[1]
self.assertEqual(second_skill.skill.id, self.max_skill_id + 1) self.assertEqual(second_skill.skill.id, 13)
self.assertEqual(second_skill.skill.name, "Tschunkproduktion") self.assertEqual(second_skill.skill.name, "Tschunkproduktion")
self.assertEqual(second_skill.level, 5) self.assertEqual(second_skill.level, 5)
@ -155,7 +155,7 @@ class TestProfileEndpoint(ApiTest):
self.assertEqual(first_searchtopic.skill.name, "Python") self.assertEqual(first_searchtopic.skill.name, "Python")
second_searchtopic = searchtopics[1] second_searchtopic = searchtopics[1]
self.assertEqual(second_searchtopic.skill.id, self.max_skill_id + 2) self.assertEqual(second_searchtopic.skill.id, 14)
self.assertEqual(second_searchtopic.skill.name, "Assembler") self.assertEqual(second_searchtopic.skill.name, "Assembler")
languages = profile.languages languages = profile.languages

View File

@ -14,24 +14,27 @@ class TestSkillsEndpoint(ApiTest):
self.assertIn("Access-Control-Allow-Origin", response.headers) self.assertIn("Access-Control-Allow-Origin", response.headers)
self.assertEqual(response.headers["Access-Control-Allow-Origin"], "*") self.assertEqual(response.headers["Access-Control-Allow-Origin"], "*")
def test_find_skills_php(self): def test_get_skills1(self):
token = self.login("peter", "geheim")["token"]
response = self.client.get("/skills?search=php", headers={"Authorization": "Bearer " + token})
self.assertEqual(response.status_code, 200)
self.assertGreaterEqual(len(response.json['skills']), 1)
self.assertIn({"id": 1, "name": "PHP", "icon_url": "/skills/1/icon"}, response.json['skills'])
self.assertIn("Access-Control-Allow-Origin", response.headers)
self.assertEqual(response.headers["Access-Control-Allow-Origin"], "*")
def test_find_skills_p(self):
token = self.login("peter", "geheim")["token"] token = self.login("peter", "geheim")["token"]
response = self.client.get("/skills?search=p", headers={"Authorization": "Bearer " + token}) response = self.client.get("/skills?search=p", headers={"Authorization": "Bearer " + token})
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertGreaterEqual(len(response.json['skills']), 3) self.assertEqual(
{
"skills": [{
"id": 1,
"name": "PHP",
"icon_url": "/skills/1/icon"
}, {
"id": 10,
"name": "PostgreSQL",
"icon_url": "/skills/10/icon"
}, {
"id": 3,
"name": "Python",
"icon_url": "/skills/3/icon"
}]
}, response.json)
self.assertIn("Access-Control-Allow-Origin", response.headers) self.assertIn("Access-Control-Allow-Origin", response.headers)
self.assertEqual(response.headers["Access-Control-Allow-Origin"], "*") self.assertEqual(response.headers["Access-Control-Allow-Origin"], "*")

View File

@ -1,8 +1,8 @@
"""Initial migration. """Initial migration.
Revision ID: 9183e2335b05 Revision ID: 44b45a772abd
Revises: Revises:
Create Date: 2021-08-02 21:51:30.400680 Create Date: 2021-07-06 21:19:44.217722
""" """
from alembic import op from alembic import op
@ -10,7 +10,7 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '9183e2335b05' revision = '44b45a772abd'
down_revision = None down_revision = None
branch_labels = None branch_labels = None
depends_on = None depends_on = None
@ -24,8 +24,8 @@ def upgrade():
sa.PrimaryKeyConstraint('id') sa.PrimaryKeyConstraint('id')
) )
op.create_table('language', op.create_table('language',
sa.Column('id', sa.String(length=4), nullable=False), sa.Column('id', sa.String(length=2), nullable=False),
sa.Column('name', sa.String(length=100), nullable=False), sa.Column('name', sa.String(length=25), nullable=False),
sa.PrimaryKeyConstraint('id') sa.PrimaryKeyConstraint('id')
) )
op.create_table('profile', op.create_table('profile',
@ -71,7 +71,7 @@ def upgrade():
) )
op.create_table('profile_language', op.create_table('profile_language',
sa.Column('profile_id', sa.Integer(), nullable=False), sa.Column('profile_id', sa.Integer(), nullable=False),
sa.Column('language_id', sa.String(length=4), nullable=False), sa.Column('language_id', sa.Integer(), nullable=False),
sa.Column('level', sa.SmallInteger(), nullable=False), sa.Column('level', sa.SmallInteger(), nullable=False),
sa.ForeignKeyConstraint(['language_id'], ['language.id'], ), sa.ForeignKeyConstraint(['language_id'], ['language.id'], ),
sa.ForeignKeyConstraint(['profile_id'], ['profile.id'], ), sa.ForeignKeyConstraint(['profile_id'], ['profile.id'], ),