Compare commits

..

1 Commits

Author SHA1 Message Date
f7bb86433b added script_location entry (it was missed in OSX environment) 2021-06-20 14:20:03 +02:00
7 changed files with 82 additions and 257 deletions

View File

@ -74,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" \

View File

@ -5,40 +5,27 @@ from app import app, db
from ki.models import User, Token from ki.models import User, Token
class UserWrongCredentialsException(Exception):
pass
class UserAllreadyLoggedInException(Exception):
pass
def auth(username, password): def auth(username, password):
auth_file_path = app.config["KI_DATA_DIR"] + "/auth.yml" auth_file_path = app.config["KI_DATA_DIR"] + "/auth.yml"
with open(auth_file_path, "r") as auth_file_stream: with open(auth_file_path, "r") as auth_file_stream:
try:
users = yaml.safe_load(auth_file_stream) users = yaml.safe_load(auth_file_stream)
except yaml.YAMLError: if username not in users:
print('Could not parse auth.yml.') return None
try:
auth_user = users[username] auth_user = users[username]
if auth_user["password"] != password: if auth_user["password"] != password:
raise UserWrongCredentialsException
except (UserWrongCredentialsException, KeyError):
print('Wrong username/password combination')
return None return None
else:
user = User.query.filter(User.auth_id.__eq__(username)).first() user = User.query.filter(User.auth_id.__eq__(username)).first()
token = Token(token=str(uuid.uuid4()), user=user) if user is None:
user = User(nickname=username, auth_id=username)
db.session.add(user)
token = Token(token=str(uuid.uuid4()), user=user)
db.session.add(token) db.session.add(token)
db.session.commit() db.session.commit()

View File

@ -9,43 +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", uselist=False, 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 {
"nickname": self.nickname, "id": self.id,
"pronouns": self.pronouns, "nickname": self.nickname
"volunteerwork": self.volunteerwork,
"freetext": self.freetext
} }
@ -63,11 +45,9 @@ 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)
@ -91,8 +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")
class Skill(db.Model): class Skill(db.Model):
@ -101,21 +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 {"id": self.id, "name": self.name} return {"id": self.id, "name": self.name}
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")
class Language(db.Model): class Language(db.Model):
@ -124,18 +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 {"id": self.id, "name": self.name} return {"id": self.id, "name": self.name}
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")

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):
@ -110,34 +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,98 +0,0 @@
from alembic import command
import unittest
import json
from app import app, db, migrate
from ki.commands import seed
from ki.models import Profile, User
class TestProfileEndpoint(unittest.TestCase):
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()
def tearDown(self):
db.engine.dispose()
def test_create_profile(self):
user = User(auth_id="peter")
db.session.add(user)
db.session.commit()
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": "Herr Dr. Dr.",
"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("Herr Dr. Dr.", profile.pronouns)
self.assertEqual("ja", profile.volunteerwork)
self.assertEqual("Hallo", profile.freetext)
def test_get_profile(self):
user = User(auth_id="peter")
db.session.add(user)
profile = Profile(user=user)
profile.nickname = "Popeter"
db.session.add(profile)
db.session.commit()
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.assertEqual(
response.json, {
"profile": {
"freetext": "",
"nickname": "Popeter",
"pronouns": "",
"volunteerwork": ""
}
})
if __name__ == "main":
unittest.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 ###