forked from kompetenzinventar/ki-backend
Compare commits
No commits in common. "f131ee335c5d5b867027e10c8e417ab1b34eaec2" and "main" have entirely different histories.
f131ee335c
...
main
44
README.md
44
README.md
@ -9,32 +9,6 @@ SPDX-License-Identifier: AGPL-3.0-or-later
|
|||||||
[![Build Status](https://drone.wtf-eg.de/api/badges/kompetenzinventar/ki-backend/status.svg?ref=refs/heads/main)](https://drone.wtf-eg.de/kompetenzinventar/ki-backend)
|
[![Build Status](https://drone.wtf-eg.de/api/badges/kompetenzinventar/ki-backend/status.svg?ref=refs/heads/main)](https://drone.wtf-eg.de/kompetenzinventar/ki-backend)
|
||||||
[![REUSE status](https://api.reuse.software/badge/git.wtf-eg.de/kompetenzinventar/ki-backend)](https://api.reuse.software/info/git.wtf-eg.de/kompetenzinventar/ki-backend)
|
[![REUSE status](https://api.reuse.software/badge/git.wtf-eg.de/kompetenzinventar/ki-backend)](https://api.reuse.software/info/git.wtf-eg.de/kompetenzinventar/ki-backend)
|
||||||
|
|
||||||
## Über
|
|
||||||
|
|
||||||
Dieses Repo enthält das Backend des Projekts Kompentenzinventar - einer Webapplikation zur Erfassung von Userprofilen für die WTF eG.
|
|
||||||
|
|
||||||
Implementiert ist das Backend mit Flask.
|
|
||||||
|
|
||||||
### Mitmachen
|
|
||||||
|
|
||||||
Du kannst gerne bei der Entwicklung des Kompetenzinventars mitmachen.
|
|
||||||
|
|
||||||
- Fehler oder fehlende Funktionen erfassen. Bitte direkt über die [Issues](https://git.wtf-eg.de/kompetenzinventar/ki-backend/issues) in Gitea.
|
|
||||||
- Dokumentation oder Implementierung verbessern. Bitte forke hierzu das Projekt, branche von `main` ab und erstelle dann einen [Pull Request](https://git.wtf-eg.de/kompetenzinventar/ki-backend/pulls).
|
|
||||||
|
|
||||||
### Kommunikation
|
|
||||||
|
|
||||||
Folgende Kanäle gibt es für die Kommunikation über das Kompetenzinventar:
|
|
||||||
|
|
||||||
- Die [Issues](https://git.wtf-eg.de/kompetenzinventar/ki-backend/issues) im WTF Gitea.
|
|
||||||
- Den Bereich [AG Entwicklung](https://forum.wtf-eg.de/c/interna/ag-entwicklung/21) im WTF Forum.
|
|
||||||
- Einen Raum in Matrix. Zutritt per Einladung, frlan lädt ein, eine einfache PN im Forum reicht.
|
|
||||||
|
|
||||||
### Repos
|
|
||||||
|
|
||||||
* **[ki-backend](https://git.wtf-eg.de/kompetenzinventar/ki-backend)** (dieses Repo) enthält das Backend
|
|
||||||
* [ki-frontend](https://git.wtf-eg.de/kompetenzinventar/ki-frontend) enthält das Frontend
|
|
||||||
* Weitere Repositories befinden sich in der Gitea Organisation [Kompetenzinventar](https://git.wtf-eg.de/kompetenzinventar).
|
|
||||||
## Entwicklung
|
## Entwicklung
|
||||||
|
|
||||||
### Abhängigkeiten
|
### Abhängigkeiten
|
||||||
@ -222,24 +196,6 @@ docker-compose up
|
|||||||
|
|
||||||
Dann http://localhost:13337 aufrufen.
|
Dann http://localhost:13337 aufrufen.
|
||||||
|
|
||||||
### Workaround, falls der Zugriff auf registry.wtf-eg.net nicht möglich ist
|
|
||||||
|
|
||||||
Voraussetzung:
|
|
||||||
|
|
||||||
[ki-backend-docker](https://git.wtf-eg.de/kompetenzinventar/ki-backend-docker) muss parallel zum `ki-backend` ausgecheckt sein.
|
|
||||||
|
|
||||||
```
|
|
||||||
cd ki-backend-docker
|
|
||||||
docker build . --target base -t ki-backend-base
|
|
||||||
docker build . --target builder -t ki-backend-builder
|
|
||||||
```
|
|
||||||
|
|
||||||
Ändern der 2 Einträge im `Dockerfile` des `ki-backend`:
|
|
||||||
|
|
||||||
- registry.wtf-eg.net/ki-backend-builder:1.0.0 -> ki-backend-builder
|
|
||||||
- registry.wtf-eg.net/ki-backend-base:1.0.0 -> ki-backend-base
|
|
||||||
|
|
||||||
Danach sollte `docker-compose up` funktionieren.
|
|
||||||
|
|
||||||
## Lizenzen
|
## Lizenzen
|
||||||
|
|
||||||
|
@ -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
|
|
|
@ -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)
|
||||||
|
|
||||||
|
app.logger.info("seeding dieter \\o/")
|
||||||
|
|
||||||
|
dieter = User(auth_id="dieter")
|
||||||
|
db.session.add(dieter)
|
||||||
|
|
||||||
|
dieters_profile = Profile(nickname="dirtydieter",
|
||||||
|
pronouns="",
|
||||||
volunteerwork="Müll sammeln",
|
volunteerwork="Müll sammeln",
|
||||||
availability="Nur nachts",
|
availability="Nur nachts",
|
||||||
freetext="1001010010111!!!",
|
freetext="1001010010111!!!",
|
||||||
skills=[(Skill.skill_id_php, 5)])
|
|
||||||
|
|
||||||
seed_user("jutta",
|
|
||||||
visible=True,
|
visible=True,
|
||||||
languages=[("fr", 5)],
|
user=dieter)
|
||||||
skills=[(Skill.skill_id_php, 3), (Skill.skill_id_mysql, 4)])
|
db.session.add(dieters_profile)
|
||||||
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)])
|
|
||||||
seed_user("monique", visible=True, languages=[("fr", 4)])
|
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
Loading…
Reference in New Issue
Block a user