Compare commits

..

2 Commits

24 changed files with 200 additions and 690 deletions

View File

@ -4,7 +4,7 @@ type: docker
name: default name: default
steps: steps:
- name: qa_main - name: qa
image: python:3.8-alpine image: python:3.8-alpine
commands: commands:
- apk add --no-cache gcc g++ musl-dev python3-dev - apk add --no-cache gcc g++ musl-dev python3-dev
@ -12,18 +12,3 @@ steps:
- pipenv install --dev - pipenv install --dev
- pipenv run flake8 - pipenv run flake8
- pipenv run python -m unittest discover ki - pipenv run python -m unittest discover ki
when:
branch:
- main
- name: qa_pr
image: python:3.8-alpine
commands:
- apk add --no-cache gcc g++ musl-dev python3-dev
- pip3 install pipenv
- pipenv install --dev
- pipenv run flake8
- pipenv run python -m unittest discover ki
when:
event:
- pull_request

View File

@ -1,4 +1,5 @@
[flake8] [flake8]
max-line-length = 120 max-line-length = 120
extend-exclude = exclude =
.git,
migrations migrations

1
.gitignore vendored
View File

@ -1,2 +1 @@
/.env /.env
*.pyc

View File

@ -1,14 +0,0 @@
- repo: local
hooks:
- id: flake8
name: flake8
entry: flake8
language: system
files: ^.*\.py$
exclude: ^(migrations).*$
- id: unittest
name: unittest
entry: python -m unittest discover ki
language: system
exclude: .*
always_run: true

View File

@ -1,3 +0,0 @@
[style]
based_on_style = pep8
allow_split_before_dict_value = 0

View File

@ -11,12 +11,9 @@ flask-sqlalchemy = "~=2.5.1"
sqlalchemy = "~=1.4.18" sqlalchemy = "~=1.4.18"
waitress = "~=2.0.0" waitress = "~=2.0.0"
pyyaml = "~=5.4.1" pyyaml = "~=5.4.1"
flask-cors = "~=3.0.10"
[dev-packages] [dev-packages]
flake8 = "~=3.9.2" flake8 = "~=3.9.2"
yapf = "~=0.31.0"
pre-commit = "~=2.13.0"
[requires] [requires]
python_version = "3.8" python_version = "3.8"

135
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "11a821c6c1f072dcf7c39a020056fa289b7a5283aa33d96e2ed6860fbc023fa4" "sha256": "439b60cb87b0180f0b78c531085f9bbeef7685ef038256f80b0a8123e7d144e6"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -21,6 +21,7 @@
"sha256:a21fedebb3fb8f6bbbba51a11114f08c78709377051384c9c5ead5705ee93a51", "sha256:a21fedebb3fb8f6bbbba51a11114f08c78709377051384c9c5ead5705ee93a51",
"sha256:e78be5b919f5bb184e3e0e2dd1ca986f2362e29a2bc933c446fe89f39dbe4e9c" "sha256:e78be5b919f5bb184e3e0e2dd1ca986f2362e29a2bc933c446fe89f39dbe4e9c"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==1.6.5" "version": "==1.6.5"
}, },
"click": { "click": {
@ -28,6 +29,7 @@
"sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a", "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a",
"sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6" "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"
], ],
"markers": "python_version >= '3.6'",
"version": "==8.0.1" "version": "==8.0.1"
}, },
"flask": { "flask": {
@ -38,14 +40,6 @@
"index": "pypi", "index": "pypi",
"version": "==2.0.1" "version": "==2.0.1"
}, },
"flask-cors": {
"hashes": [
"sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438",
"sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de"
],
"index": "pypi",
"version": "==3.0.10"
},
"flask-migrate": { "flask-migrate": {
"hashes": [ "hashes": [
"sha256:4d42e8f861d78cb6e9319afcba5bf76062e5efd7784184dd2a1cccd9de34a702", "sha256:4d42e8f861d78cb6e9319afcba5bf76062e5efd7784184dd2a1cccd9de34a702",
@ -122,6 +116,7 @@
"sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c", "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c",
"sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0" "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0"
], ],
"markers": "python_version >= '3.6'",
"version": "==2.0.1" "version": "==2.0.1"
}, },
"jinja2": { "jinja2": {
@ -129,6 +124,7 @@
"sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4", "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4",
"sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4" "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"
], ],
"markers": "python_version >= '3.6'",
"version": "==3.0.1" "version": "==3.0.1"
}, },
"mako": { "mako": {
@ -136,6 +132,7 @@
"sha256:17831f0b7087c313c0ffae2bcbbd3c1d5ba9eeac9c38f2eb7b50e8c99fe9d5ab", "sha256:17831f0b7087c313c0ffae2bcbbd3c1d5ba9eeac9c38f2eb7b50e8c99fe9d5ab",
"sha256:aea166356da44b9b830c8023cd9b557fa856bd8b4035d6de771ca027dfc5cc6e" "sha256:aea166356da44b9b830c8023cd9b557fa856bd8b4035d6de771ca027dfc5cc6e"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.1.4" "version": "==1.1.4"
}, },
"markupsafe": { "markupsafe": {
@ -175,6 +172,7 @@
"sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51",
"sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"
], ],
"markers": "python_version >= '3.6'",
"version": "==2.0.1" "version": "==2.0.1"
}, },
"python-dateutil": { "python-dateutil": {
@ -182,6 +180,7 @@
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.8.1" "version": "==2.8.1"
}, },
"python-dotenv": { "python-dotenv": {
@ -242,6 +241,7 @@
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0" "version": "==1.16.0"
}, },
"sqlalchemy": { "sqlalchemy": {
@ -293,38 +293,11 @@
"sha256:1de1db30d010ff1af14a009224ec49ab2329ad2cde454c8a708130642d579c42", "sha256:1de1db30d010ff1af14a009224ec49ab2329ad2cde454c8a708130642d579c42",
"sha256:6c1ec500dcdba0baa27600f6a22f6333d8b662d22027ff9f6202e3367413caa8" "sha256:6c1ec500dcdba0baa27600f6a22f6333d8b662d22027ff9f6202e3367413caa8"
], ],
"markers": "python_version >= '3.6'",
"version": "==2.0.1" "version": "==2.0.1"
} }
}, },
"develop": { "develop": {
"appdirs": {
"hashes": [
"sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41",
"sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"
],
"version": "==1.4.4"
},
"cfgv": {
"hashes": [
"sha256:9e600479b3b99e8af981ecdfc80a0296104ee610cab48a5ae4ffd0b668650eb1",
"sha256:b449c9c6118fe8cca7fa5e00b9ec60ba08145d281d52164230a69211c5d597a1"
],
"version": "==3.3.0"
},
"distlib": {
"hashes": [
"sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736",
"sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c"
],
"version": "==0.3.2"
},
"filelock": {
"hashes": [
"sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59",
"sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"
],
"version": "==3.0.12"
},
"flake8": { "flake8": {
"hashes": [ "hashes": [
"sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b", "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b",
@ -333,13 +306,6 @@
"index": "pypi", "index": "pypi",
"version": "==3.9.2" "version": "==3.9.2"
}, },
"identify": {
"hashes": [
"sha256:18d0c531ee3dbc112fa6181f34faa179de3f57ea57ae2899754f16a7e0ff6421",
"sha256:5b41f71471bc738e7b586308c3fca172f78940195cb3bf6734c1e66fdac49306"
],
"version": "==2.2.10"
},
"mccabe": { "mccabe": {
"hashes": [ "hashes": [
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
@ -347,26 +313,12 @@
], ],
"version": "==0.6.1" "version": "==0.6.1"
}, },
"nodeenv": {
"hashes": [
"sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b",
"sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"
],
"version": "==1.6.0"
},
"pre-commit": {
"hashes": [
"sha256:764972c60693dc668ba8e86eb29654ec3144501310f7198742a767bec385a378",
"sha256:b679d0fddd5b9d6d98783ae5f10fd0c4c59954f375b70a58cbe1ce9bcf9809a4"
],
"index": "pypi",
"version": "==2.13.0"
},
"pycodestyle": { "pycodestyle": {
"hashes": [ "hashes": [
"sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068", "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068",
"sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef" "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.7.0" "version": "==2.7.0"
}, },
"pyflakes": { "pyflakes": {
@ -374,71 +326,8 @@
"sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3", "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3",
"sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db" "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.3.1" "version": "==2.3.1"
},
"pyyaml": {
"hashes": [
"sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf",
"sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696",
"sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393",
"sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77",
"sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922",
"sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5",
"sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8",
"sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10",
"sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc",
"sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018",
"sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e",
"sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253",
"sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347",
"sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183",
"sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541",
"sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb",
"sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185",
"sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc",
"sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db",
"sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa",
"sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46",
"sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122",
"sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b",
"sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63",
"sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df",
"sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc",
"sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247",
"sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6",
"sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"
],
"index": "pypi",
"version": "==5.4.1"
},
"six": {
"hashes": [
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"version": "==1.16.0"
},
"toml": {
"hashes": [
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
],
"version": "==0.10.2"
},
"virtualenv": {
"hashes": [
"sha256:14fdf849f80dbb29a4eb6caa9875d476ee2a5cf76a5f5415fa2f1606010ab467",
"sha256:2b0126166ea7c9c3661f5b8e06773d28f83322de7a3ff7d06f0aed18c9de6a76"
],
"version": "==20.4.7"
},
"yapf": {
"hashes": [
"sha256:408fb9a2b254c302f49db83c59f9aa0b4b0fd0ec25be3a5c51181327922ff63d",
"sha256:e3a234ba8455fe201eaa649cdac872d590089a18b661e39bbac7020978dd9c2e"
],
"index": "pypi",
"version": "==0.31.0"
} }
} }
} }

View File

@ -9,7 +9,6 @@
- Python 3.8 - Python 3.8
- [Pipenv](https://github.com/pypa/pipenv) - [Pipenv](https://github.com/pypa/pipenv)
### Entwicklungsumgebung aufbauen und starten ### Entwicklungsumgebung aufbauen und starten
Ggf. vorher aufräumen Ggf. vorher aufräumen
@ -22,39 +21,25 @@ rm data/ki.sqlite
cp env.dev .env cp env.dev .env
pipenv install --dev pipenv install --dev
pipenv shell pipenv shell
export FLASK_APP=app.py
flask db upgrade flask db upgrade
flask seed --dev flask seed
flask run flask run
``` ```
http://localhost:5000/ http://localhost:5000/
### pre-commit einrichten ### Tests ausführen
Damit mensch nicht verpeilt kaputten Code Style zu commiten,
kann pre-commit benutzt werden. Einmal im Virtualenv ausführen:
```
pre-commit install
```
### `alembic` Befehle
`alembic` ist über [Flask-Migrate](https://flask-migrate.readthedocs.io/en/latest/index.html) eingebunden.
Es wird über `flask db ...` aufgerufen.
### QA
``` ```
python -m unittest discover ki python -m unittest discover ki
```
# Code formatieren
yapf -i --recursive ki/
# Code-Style prüfen ### Linting
```
flake8 flake8
``` ```
@ -89,16 +74,6 @@ curl -s \
http://localhost:5000/users/login | jq http://localhost:5000/users/login | jq
``` ```
```
curl -s \
-D "/dev/stderr" \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer 22e6c5fc-8a5a-440e-b1f4-018deb9fd24e" \
-d '{"pronouns": "Herr Dr. Dr."}' \
http://localhost:5000/users/1/profile | jq
```
``` ```
curl -s \ curl -s \
-D "/dev/stderr" \ -D "/dev/stderr" \

14
app.py
View File

@ -1,27 +1,17 @@
import logging
import os import os
from dotenv import load_dotenv, find_dotenv from dotenv import load_dotenv, find_dotenv
from flask import Flask from flask import Flask
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate from flask_migrate import Migrate
load_dotenv(find_dotenv()) load_dotenv(find_dotenv())
loglevel = os.getenv("KI_LOGLEVEL", logging.WARNING)
loglevel = int(loglevel)
logging.basicConfig(level=loglevel)
logging.debug("Hello from KI")
app = Flask(__name__) app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = os.getenv("SQLALCHEMY_DATABASE_URI") app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv("SQLALCHEMY_DATABASE_URI")
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config["KI_DATA_DIR"] = os.path.dirname(__file__) + "/data" app.config["KI_DATA_DIR"] = os.path.dirname(__file__) + "/data"
app.config["KI_AUTH"] = os.getenv("KI_AUTH") app.config["KI_AUTH"] = os.getenv("KI_AUTH")
app.config["CORS_ORIGINS"] = os.getenv("CORS_ORIGINS", "*")
CORS(app)
db = SQLAlchemy(app) db = SQLAlchemy(app)
migrate = Migrate(app, db) migrate = Migrate(app, db)

14
drone.yml Normal file
View File

@ -0,0 +1,14 @@
---
kind: pipeline
type: docker
name: default
steps:
- name: qa
image: python3.8-alpine
commands:
- apk add --no-cache gcc g++ musl-dev python3-dev
- pip3 install pipenv
- pipenv install --system
- flake8
- python -m unittest discover ki

10
env.dev
View File

@ -1,11 +1,3 @@
SQLALCHEMY_DATABASE_URI=sqlite:///data/ki.sqlite SQLALCHEMY_DATABASE_URI = 'sqlite:///data/ki.sqlite'
CORS_ORIGINS=*
FLASK_APP=app.py
FLASK_ENV=development
KI_AUTH=file KI_AUTH=file
# 10 = debug
KI_LOGLEVEL=10

View File

@ -1 +0,0 @@
from ki.actions.seed import seed # noqa

View File

@ -1,83 +0,0 @@
import csv
import logging
from app import app, db
from ki.models import Address, Contact, ContactType, Language, Skill, Profile, ProfileLanguage, ProfileSkill, User
def seed(dev: bool):
skill_seed_file_path = app.config["KI_DATA_DIR"] + "/seed_data/skills.csv"
logging.info("importing skills")
with open(skill_seed_file_path) as skills_file:
skills_csv_reader = csv.DictReader(skills_file)
for skill in skills_csv_reader:
id = int(skill["id"])
db_skill = Skill.query.get(id)
if db_skill is None:
db.session.add(Skill(id=int(skill["id"]), name=skill["name"]))
logging.info("importing languages")
iso_seed_file_path = app.config["KI_DATA_DIR"] + "/seed_data/iso_639_1.csv"
with open(iso_seed_file_path) as iso_file:
iso_csv_reader = csv.DictReader(iso_file)
for iso in iso_csv_reader:
id = iso["639-1"]
db_language = Language.query.get(id)
if db_language is None:
db.session.add(Language(id=iso["639-1"], name=iso["Sprache"]))
if dev:
logging.info("seeding peter :)")
peter = User(auth_id="peter")
db.session.add(peter)
peters_profile = Profile(nickname="peternichtlustig",
pronouns="Herr Dr. Dr.",
volunteerwork="Gartenverein",
freetext="Ich mag Kaffee",
user=peter)
db.session.add(peters_profile)
matrix_type = ContactType(name="Matrix")
db.session.add(matrix_type)
matrix_contact = Contact(profile=peters_profile,
contacttype=matrix_type,
content="@peter:wtf-eg.de")
db.session.add(matrix_contact)
peters_address = Address(name="Peter Nichtlustig",
street="Waldweg",
house_number="23i",
additional="Hinterhaus",
postcode="13337",
city="Bielefeld",
country="Deutschland",
profile=peters_profile)
db.session.add(peters_address)
peters_python_skill = ProfileSkill(profile=peters_profile,
skill_id=3,
level=5)
db.session.add(peters_python_skill)
peter_de = ProfileLanguage(profile=peters_profile,
language_id="de",
level=5)
db.session.add(peter_de)
peter_fr = ProfileLanguage(profile=peters_profile,
language_id="fr",
level=3)
db.session.add(peter_fr)
db.session.commit()

View File

@ -22,7 +22,7 @@ def auth(username, password):
user = User.query.filter(User.auth_id.__eq__(username)).first() user = User.query.filter(User.auth_id.__eq__(username)).first()
if user is None: if user is None:
user = User(auth_id=username) user = User(nickname=username, auth_id=username)
db.session.add(user) db.session.add(user)
token = Token(token=str(uuid.uuid4()), user=user) token = Token(token=str(uuid.uuid4()), user=user)

View File

@ -1,10 +1,39 @@
import click import csv
from app import app from ki.models import Language, Skill
from ki.actions import seed from app import app, db
def seed():
skill_seed_file_path = app.config["KI_DATA_DIR"] + "/seed_data/skills.csv"
print("importing skills")
with open(skill_seed_file_path) as skills_file:
skills_csv_reader = csv.DictReader(skills_file)
for skill in skills_csv_reader:
id = int(skill["id"])
db_skill = Skill.query.get(id)
if db_skill is None:
db.session.add(Skill(id=int(skill["id"]), name=skill["name"]))
iso_seed_file_path = app.config["KI_DATA_DIR"] + "/seed_data/iso_639_1.csv"
with open(iso_seed_file_path) as iso_file:
iso_csv_reader = csv.DictReader(iso_file)
for iso in iso_csv_reader:
id = iso["639-1"]
db_language = Language.query.get(id)
if db_language is None:
db.session.add(Language(id=iso["639-1"], name=iso["Sprache"]))
db.session.commit()
@app.cli.command("seed") @app.cli.command("seed")
@click.option("--dev", is_flag=True) def seed_command():
def seed_command(dev): seed()
seed(dev)

View File

@ -9,50 +9,25 @@ from app import db
class User(db.Model): class User(db.Model):
__tablename__ = "user" __tablename__ = "user"
id = Column(Integer, primary_key=True)
auth_id = Column(String(50), nullable=False, unique=True)
profile_id = Column(Integer, ForeignKey("profile.id"), nullable=True)
tokens = relationship("Token", back_populates="user")
profile = relationship("Profile", back_populates="user")
def to_dict(self):
return {"id": self.id}
class Profile(db.Model):
__tablename__ = "profile"
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
nickname = Column(String(25), unique=True, nullable=False) nickname = Column(String(25), unique=True, nullable=False)
pronouns = Column(String(25), default="") pronouns = Column(String(25), default="")
volunteerwork = Column(String(4000), default="") volunteerwork = Column(String(4000), default="")
freetext = Column(String(4000), default="") freetext = Column(String(4000), default="")
created = Column(DateTime, nullable=False, default=datetime.now) created = Column(DateTime, nullable=False, default=datetime.now)
updated = Column(DateTime, updated = Column(DateTime, onupdate=datetime.now, nullable=False, default=datetime.now)
onupdate=datetime.now, auth_id = Column(String(50), nullable=False, unique=True)
nullable=False,
default=datetime.now)
user = relationship("User", back_populates="profile", uselist=False)
contacts = relationship("Contact") contacts = relationship("Contact")
address = relationship("Address", uselist=False, back_populates="profile") address = relationship("Address", uselist=False, back_populates="user")
skills = relationship("ProfileSkill", back_populates="profile") tokens = relationship("Token", uselist=False, back_populates="user")
languages = relationship("ProfileLanguage", back_populates="profile") skills = relationship("UserSkill", back_populates="user")
languages = relationship("UserLanguage", back_populates="user")
def to_dict(self): def to_dict(self):
return { return {
"user_id": self.user.id, "id": self.id,
"nickname": self.nickname, "nickname": self.nickname
"pronouns": self.pronouns,
"volunteerwork": self.volunteerwork,
"freetext": self.freetext,
"address": self.address.to_dict(),
"contacts": list(
map(lambda contact: contact.to_dict(), self.contacts)),
"skills": list(map(lambda skill: skill.to_dict(), self.skills)),
"languages": list(
map(lambda language: language.to_dict(), self.languages))
} }
@ -65,30 +40,17 @@ class Token(db.Model):
user = relationship("User", back_populates="tokens") user = relationship("User", back_populates="tokens")
def to_dict(self):
return {"user_id": self.user_id, "token": self.token}
class Contact(db.Model): class Contact(db.Model):
__tablename__ = "contact" __tablename__ = "contact"
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
profile_id = Column(Integer, ForeignKey("profile.id"), nullable=False) user_id = Column(Integer, ForeignKey("user.id"), nullable=False)
profile = relationship("Profile", back_populates="contacts") user = relationship("User", back_populates="contacts")
contacttype_id = Column(Integer, contacttype_id = Column(Integer, ForeignKey("contacttype.id"), nullable=False)
ForeignKey("contacttype.id"),
nullable=False)
contacttype = relationship("ContactType") contacttype = relationship("ContactType")
content = Column(String(200), nullable=False) content = Column(String(200), nullable=False)
def to_dict(self):
return {
"id": self.id,
"profile_id": self.profile_id,
"contacttype": self.contacttype.to_dict(),
"content": self.content
}
class ContactType(db.Model): class ContactType(db.Model):
__tablename__ = "contacttype" __tablename__ = "contacttype"
@ -96,9 +58,6 @@ class ContactType(db.Model):
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
name = Column(String(25), nullable=False) name = Column(String(25), nullable=False)
def to_dict(self):
return {"id": self.id, "name": self.name}
class Address(db.Model): class Address(db.Model):
__tablename__ = "address" __tablename__ = "address"
@ -112,21 +71,8 @@ class Address(db.Model):
city = Column(String(25), default="") city = Column(String(25), default="")
country = Column(String(25), default="") country = Column(String(25), default="")
profile_id = Column(Integer, ForeignKey("profile.id"), nullable=False) user_id = Column(Integer, ForeignKey("user.id"), nullable=False)
profile = relationship("Profile", back_populates="address") user = relationship("User", back_populates="address")
def to_dict(self):
return {
"id": self.id,
"name": self.name,
"street": self.street,
"house_number": self.house_number,
"additional": self.additional,
"postcode": self.postcode,
"city": self.city,
"country": self.country,
"profile_id": self.profile_id
}
class Skill(db.Model): class Skill(db.Model):
@ -135,32 +81,21 @@ class Skill(db.Model):
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
name = Column(String(25), unique=True, nullable=False) name = Column(String(25), unique=True, nullable=False)
profiles = relationship("ProfileSkill", back_populates="skill") users = relationship("UserSkill", back_populates="skill")
def to_dict(self): def to_dict(self):
return { return {"id": self.id, "name": self.name}
"id": self.id,
"name": self.name,
"icon_url": "/skills/{}/icon".format(self.id)
}
class ProfileSkill(db.Model): class UserSkill(db.Model):
__tablename__ = "profile_skill" __tablename__ = "user_skill"
profile_id = Column(Integer, ForeignKey("profile.id"), primary_key=True) user_id = Column(Integer, ForeignKey("user.id"), primary_key=True)
skill_id = Column(Integer, ForeignKey("skill.id"), primary_key=True) skill_id = Column(Integer, ForeignKey("skill.id"), primary_key=True)
level = Column(SmallInteger, nullable=False) level = Column(SmallInteger, nullable=False)
profile = relationship("Profile", back_populates="skills") user = relationship("User", back_populates="skills")
skill = relationship("Skill", back_populates="profiles") skill = relationship("Skill", back_populates="users")
def to_dict(self):
return {
"profile_id": self.profile_id,
"skill": self.skill.to_dict(),
"level": self.level
}
class Language(db.Model): class Language(db.Model):
@ -169,29 +104,18 @@ class Language(db.Model):
id = Column(String(2), primary_key=True) id = Column(String(2), primary_key=True)
name = Column(String(25), nullable=False) name = Column(String(25), nullable=False)
profiles = relationship("ProfileLanguage", back_populates="language") users = relationship("UserLanguage", back_populates="language")
def to_dict(self): def to_dict(self):
return { return {"id": self.id, "name": self.name}
"id": self.id,
"name": self.name,
"icon_url": "/languages/{}/icon".format(self.id)
}
class ProfileLanguage(db.Model): class UserLanguage(db.Model):
__tablename__ = "profile_language" __tablename__ = "user_language"
profile_id = Column(Integer, ForeignKey("profile.id"), primary_key=True) user_id = Column(Integer, ForeignKey("user.id"), primary_key=True)
language_id = Column(Integer, 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") user = relationship("User", back_populates="languages")
language = relationship("Language", back_populates="profiles") language = relationship("Language", back_populates="users")
def to_dict(self):
return {
"profile_id": self.profile_id,
"language": self.language.to_dict(),
"level": self.level
}

View File

@ -1 +1 @@
from ki import models, commands, routes # noqa from ki import models, commands, routes # noqa

View File

@ -3,8 +3,8 @@ from flask import g, make_response, request, send_file
from functools import wraps from functools import wraps
from ki.auth import auth from ki.auth import auth
from ki.models import Language, Skill, Token, User, Profile from ki.models import Language, Skill, Token, User
from app import app, db from app import app
def token_auth(func): def token_auth(func):
@ -99,7 +99,7 @@ def login():
if token is None: if token is None:
return make_response({}, 403) return make_response({}, 403)
return make_response({"token": token.token, "user_id": token.user_id}) return make_response({"token": token.token})
@app.route("/users/<user_id>/profile") @app.route("/users/<user_id>/profile")
@ -110,36 +110,7 @@ def get_user_profile(user_id):
if user is None: if user is None:
return make_response({}, 404) return make_response({}, 404)
profile = user.profile return make_response({"user": user.to_dict()})
if profile is None:
return make_response({}, 404)
return make_response({
"profile": profile.to_dict(),
})
@app.route("/users/<user_id>/profile", methods=["POST"])
def update_profile(user_id):
user = User.query.filter(User.id == int(user_id)).first()
if user is None:
return make_response({}, 404)
profile = user.profile
if (profile is None):
profile = Profile(user=user, nickname=user.auth_id)
db.session.add(profile)
profile.pronouns = request.json.get("pronouns", "")
profile.volunteerwork = request.json.get("volunteerwork", "")
profile.freetext = request.json.get("freetext", "")
db.session.commit()
return make_response(profile.to_dict(), 200)
@app.route("/skills") @app.route("/skills")

View File

@ -1,43 +0,0 @@
from alembic import command
import json
import unittest
from app import app, db, migrate
from ki.actions import seed
class TestLoginEndpoint(unittest.TestCase):
def setUp(self):
app.debug = True
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"
self.client = app.test_client()
with app.app_context():
config = migrate.get_config()
command.upgrade(config, "head")
seed(True)
def tearDown(self):
db.drop_all()
db.engine.dispose()
def test_login(self):
response1_data = self.login()
response2_data = self.login()
self.assertNotEqual(response1_data["token"], response2_data["token"])
def login(self):
response = self.client.post("/users/login",
data=json.dumps({
"username": "peter",
"password": "geheim"
}),
content_type="application/json")
self.assertEqual(response.status_code, 200)
self.assertIn("token", response.json)
return response.json
if __name__ == "main":
unittest.main()

View File

@ -1,134 +0,0 @@
from alembic import command
import unittest
import json
from app import app, db, migrate
from ki.actions import seed
from ki.models import User
class TestProfileEndpoint(unittest.TestCase):
maxDiff = None
def setUp(self):
app.debug = True
app.config["TESTING"] = True
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"
self.client = app.test_client()
with app.app_context():
config = migrate.get_config()
command.upgrade(config, "head")
seed(True)
def tearDown(self):
db.drop_all()
db.engine.dispose()
def test_update_profile(self):
login_data = {"username": "peter", "password": "geheim"}
login_response = self.client.post("/users/login",
data=json.dumps(login_data),
content_type="application/json")
self.assertEqual(login_response.status_code, 200)
self.assertIn("token", login_response.json)
data = {
"pronouns": "Monsieur",
"volunteerwork": "ja",
"freetext": "Hallo",
}
response = self.client.post("/users/1/profile",
data=json.dumps(data),
content_type="application/json",
headers={
"Authorization": "Bearer " +
login_response.json["token"]
})
self.assertEqual(response.status_code, 200)
with app.app_context():
user = User.query.filter(User.id == 1).first()
profile = user.profile
self.assertEqual("Monsieur", profile.pronouns)
self.assertEqual("ja", profile.volunteerwork)
self.assertEqual("Hallo", profile.freetext)
def test_get_profile(self):
login_data = {"username": "peter", "password": "geheim"}
login_response = self.client.post("/users/login",
data=json.dumps(login_data),
content_type="application/json")
self.assertEqual(login_response.status_code, 200)
self.assertIn("token", login_response.json)
response = self.client.get("/users/1/profile",
headers={
"Authorization": "Bearer " +
login_response.json["token"]
})
self.assertEqual(response.status_code, 200)
self.assertDictEqual(
response.json, {
"profile": {
"user_id": 1,
"nickname": "peternichtlustig",
"pronouns": "Herr Dr. Dr.",
"freetext": "Ich mag Kaffee",
"volunteerwork": "Gartenverein",
"address": {
"additional": "Hinterhaus",
"city": "Bielefeld",
"country": "Deutschland",
"house_number": "23i",
"id": 1,
"name": "Peter Nichtlustig",
"postcode": "13337",
"profile_id": 1,
"street": "Waldweg"
},
"contacts": [{
"id": 1,
"profile_id": 1,
"contacttype": {
"id": 1,
"name": "Matrix"
},
"content": "@peter:wtf-eg.de"
}],
"skills": [{
"profile_id": 1,
"skill": {
"id": 3,
"name": "Python",
"icon_url": "/skills/3/icon"
},
"level": 5
}],
"languages": [{
"profile_id": 1,
"language": {
"id": "de",
"name": "Deutsch",
"icon_url": "/languages/de/icon"
},
"level": 5
}, {
"profile_id": 1,
"language": {
"id": "fr",
"name": "Französisch",
"icon_url": "/languages/fr/icon"
},
"level": 3
}]
}
})
if __name__ == "main":
unittest.main()

View File

@ -1,8 +1,8 @@
from alembic import command from alembic import command
import unittest import unittest
from app import app, db, migrate from app import app, migrate
from ki.actions import seed from ki.commands import seed
class TestSkillsEndpoint(unittest.TestCase): class TestSkillsEndpoint(unittest.TestCase):
@ -15,35 +15,20 @@ class TestSkillsEndpoint(unittest.TestCase):
config = migrate.get_config() config = migrate.get_config()
command.upgrade(config, "head") command.upgrade(config, "head")
seed(True) seed()
def tearDown(self):
db.drop_all()
db.engine.dispose()
def test_skills_options(self):
response = self.client.options("/skills")
self.assertEqual(response.status_code, 200)
self.assertIn("Access-Control-Allow-Origin", response.headers)
self.assertEqual(response.headers["Access-Control-Allow-Origin"], "*")
def test_get_skills1(self): def test_get_skills1(self):
response = self.client.get("/skills?search=p") response = self.client.get("/skills?search=p")
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual( self.assertEqual(
{ {
"skills": [{ "skills": [
"id": 1, {"id": 1, "name": "PHP"},
"name": "PHP", {"id": 3, "name": "Python"}
"icon_url": "/skills/1/icon" ]
}, { },
"id": 3, response.json
"name": "Python", )
"icon_url": "/skills/3/icon"
}]
}, response.json)
self.assertIn("Access-Control-Allow-Origin", response.headers)
self.assertEqual(response.headers["Access-Control-Allow-Origin"], "*")
if __name__ == "main": if __name__ == "main":

View File

@ -7,7 +7,7 @@
# set to 'true' to run the environment during # set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate # the 'revision' command, regardless of autogenerate
# revision_environment = false # revision_environment = false
script_location = .
# Logging configuration # Logging configuration
[loggers] [loggers]

View File

@ -1,8 +1,8 @@
"""Initial migration. """Initial migration
Revision ID: f95308aceda1 Revision ID: 575a8924eb16
Revises: Revises:
Create Date: 2021-06-20 19:11:47.086814 Create Date: 2021-06-12 13:18:24.903142
""" """
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 = 'f95308aceda1' revision = '575a8924eb16'
down_revision = None down_revision = None
branch_labels = None branch_labels = None
depends_on = None depends_on = None
@ -28,7 +28,13 @@ def upgrade():
sa.Column('name', sa.String(length=25), nullable=False), sa.Column('name', sa.String(length=25), nullable=False),
sa.PrimaryKeyConstraint('id') sa.PrimaryKeyConstraint('id')
) )
op.create_table('profile', op.create_table('skill',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=25), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('user',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('nickname', sa.String(length=25), nullable=False), sa.Column('nickname', sa.String(length=25), nullable=False),
sa.Column('pronouns', sa.String(length=25), nullable=True), sa.Column('pronouns', sa.String(length=25), nullable=True),
@ -36,15 +42,11 @@ def upgrade():
sa.Column('freetext', sa.String(length=4000), nullable=True), sa.Column('freetext', sa.String(length=4000), nullable=True),
sa.Column('created', sa.DateTime(), nullable=False), sa.Column('created', sa.DateTime(), nullable=False),
sa.Column('updated', sa.DateTime(), nullable=False), sa.Column('updated', sa.DateTime(), nullable=False),
sa.Column('auth_id', sa.String(length=50), nullable=False),
sa.PrimaryKeyConstraint('id'), sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('auth_id'),
sa.UniqueConstraint('nickname') sa.UniqueConstraint('nickname')
) )
op.create_table('skill',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=25), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('address', op.create_table('address',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=25), nullable=True), sa.Column('name', sa.String(length=25), nullable=True),
@ -54,63 +56,54 @@ def upgrade():
sa.Column('postcode', sa.String(length=10), nullable=True), sa.Column('postcode', sa.String(length=10), nullable=True),
sa.Column('city', sa.String(length=25), nullable=True), sa.Column('city', sa.String(length=25), nullable=True),
sa.Column('country', sa.String(length=25), nullable=True), sa.Column('country', sa.String(length=25), nullable=True),
sa.Column('profile_id', sa.Integer(), nullable=False), sa.Column('user_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['profile_id'], ['profile.id'], ), sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('id') sa.PrimaryKeyConstraint('id')
) )
op.create_table('contact', op.create_table('contact',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('profile_id', sa.Integer(), nullable=False), sa.Column('user_id', sa.Integer(), nullable=True),
sa.Column('contacttype_id', sa.Integer(), nullable=False), sa.Column('contacttype_id', sa.Integer(), nullable=True),
sa.Column('content', sa.String(length=200), nullable=False), sa.Column('content', sa.String(length=200), nullable=False),
sa.ForeignKeyConstraint(['contacttype_id'], ['contacttype.id'], ), sa.ForeignKeyConstraint(['contacttype_id'], ['contacttype.id'], ),
sa.ForeignKeyConstraint(['profile_id'], ['profile.id'], ), sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('id') sa.PrimaryKeyConstraint('id')
) )
op.create_table('profile_language',
sa.Column('profile_id', sa.Integer(), nullable=False),
sa.Column('language_id', sa.Integer(), nullable=False),
sa.Column('level', sa.SmallInteger(), nullable=False),
sa.ForeignKeyConstraint(['language_id'], ['language.id'], ),
sa.ForeignKeyConstraint(['profile_id'], ['profile.id'], ),
sa.PrimaryKeyConstraint('profile_id', 'language_id')
)
op.create_table('profile_skill',
sa.Column('profile_id', sa.Integer(), nullable=False),
sa.Column('skill_id', sa.Integer(), nullable=False),
sa.Column('level', sa.SmallInteger(), nullable=False),
sa.ForeignKeyConstraint(['profile_id'], ['profile.id'], ),
sa.ForeignKeyConstraint(['skill_id'], ['skill.id'], ),
sa.PrimaryKeyConstraint('profile_id', 'skill_id')
)
op.create_table('user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('auth_id', sa.String(length=50), nullable=False),
sa.Column('profile_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['profile_id'], ['profile.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('auth_id')
)
op.create_table('token', op.create_table('token',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False), sa.Column('user_id', sa.Integer(), nullable=True),
sa.Column('token', sa.String(length=36), nullable=False), sa.Column('token', sa.String(length=36), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('id') sa.PrimaryKeyConstraint('id')
) )
op.create_table('user_language',
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('language_id', sa.Integer(), nullable=False),
sa.Column('level', sa.SmallInteger(), nullable=False),
sa.ForeignKeyConstraint(['language_id'], ['language.id'], ),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('user_id', 'language_id')
)
op.create_table('user_skill',
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('skill_id', sa.Integer(), nullable=False),
sa.Column('level', sa.SmallInteger(), nullable=False),
sa.ForeignKeyConstraint(['skill_id'], ['skill.id'], ),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('user_id', 'skill_id')
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_table('user_skill')
op.drop_table('user_language')
op.drop_table('token') op.drop_table('token')
op.drop_table('user')
op.drop_table('profile_skill')
op.drop_table('profile_language')
op.drop_table('contact') op.drop_table('contact')
op.drop_table('address') op.drop_table('address')
op.drop_table('user')
op.drop_table('skill') op.drop_table('skill')
op.drop_table('profile')
op.drop_table('language') op.drop_table('language')
op.drop_table('contacttype') op.drop_table('contacttype')
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -0,0 +1,44 @@
"""split user to user and profile
Revision ID: de2164c615e8
Revises: 575a8924eb16
Create Date: 2021-06-20 14:17:02.102076
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'de2164c615e8'
down_revision = '575a8924eb16'
branch_labels = None
depends_on = None
def upgrade():
op.create_table('user_profile',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=True),
sa.Column('pronouns', sa.String(length=25), nullable=True),
sa.Column('volunteerwork', sa.String(length=4000), nullable=True),
sa.Column('freetext', sa.String(length=4000), nullable=True),
sa.Column('created', sa.DateTime(), nullable=False),
sa.Column('updated', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id'),
)
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('id')
op.execute("INSERT INTO user_profile (user_id,pronouns,volunteerwork,freetext,created,updated) SELECT id,pronouns,volunteerwork,freetext,created,updated FROM user")
op.drop_column("user","pronouns")
op.drop_column("user","volunteerwork")
op.drop_column("user","freetext")
def downgrade():
op.add_column("user", Column('pronouns', sa.String(length=25), nullable=True))
op.add_column("user", Column("volunteerwork",sa.String(length=4000), nullable=True))
op.add_column("user", Column("freetext",sa.String(length=4000), nullable=True))
# tbd update user table fields from user profile fields
op.drop_table('user_profile')