Initdb: create database schemas, admin role, initial background map
All checks were successful
/ test (push) Successful in 32s

This commit is contained in:
phil 2024-12-20 11:45:44 +01:00
parent e44911db8e
commit 7354b9bab8
6 changed files with 76 additions and 47 deletions

View file

@ -2,6 +2,3 @@ FROM docker.io/postgis/postgis:17-3.5-alpine
ENV POSTGRES_USER gisaf
ENV POSTGRES_PASSWORD secret
# Overwrite standard postgis entrypoint
COPY ./database-container-entrypoint-postgis.sh /docker-entrypoint-initdb.d/10_postgis.sh

View file

@ -1,29 +0,0 @@
#!/bin/bash
set -e
# Perform all actions as $POSTGRES_USER
export PGUSER="$POSTGRES_USER"
# Create the 'template_postgis' template db
"${psql[@]}" <<-'EOSQL'
CREATE DATABASE template_postgis IS_TEMPLATE true;
EOSQL
# Load PostGIS into both template_database and $POSTGRES_DB
for DB in template_postgis "$POSTGRES_DB"; do
echo "Loading PostGIS extensions into $DB"
"${psql[@]}" --dbname="$DB" <<-'EOSQL'
CREATE EXTENSION IF NOT EXISTS postgis;
EOSQL
done
"${psql[@]}" --dbname="$DB" <<-'EOSQL'
CREATE EXTENSION IF NOT EXISTS hstore;
CREATE SCHEMA gisaf;
CREATE SCHEMA gisaf_admin;
CREATE SCHEMA gisaf_map;
CREATE SCHEMA gisaf_survey;
CREATE SCHEMA raw_survey;
CREATE SCHEMA survey;
EOSQL

View file

@ -115,7 +115,7 @@ async def get_acls(
db_session: db_session, user: Annotated[User, Depends(get_current_active_user)]
) -> list[UserRoleLink]:
"""New: ACLs returned as UserRoleLink"""
if user is not None or not user.has_role("manager"):
if user is None or not user.has_role("manager"):
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)
data = await db_session.exec(select(UserRoleLink))
return data.all() # type: ignore[return-value]

View file

@ -5,7 +5,7 @@ from asyncio import sleep
import logging
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy import create_engine
from sqlalchemy import create_engine, text
from sqlalchemy.orm import joinedload, QueryableAttribute
from sqlalchemy.sql.selectable import Select
from sqlmodel import SQLModel, select, func, col
@ -163,6 +163,8 @@ async def create_db(drop=False):
attempts = CREATE_DB_TIMEOUT
async def try_once():
async with engine.begin() as conn:
await create_schemas(conn)
async with engine.begin() as conn:
if drop:
await conn.run_sync(SQLModel.metadata.drop_all)
@ -199,14 +201,30 @@ async def is_fresh_install() -> bool:
return nb_users == 0
async def create_schemas(conn):
"""Create schemas and extensions"""
raw_sql = [
"CREATE EXTENSION IF NOT EXISTS hstore",
"CREATE SCHEMA IF NOT EXISTS gisaf",
"CREATE SCHEMA IF NOT EXISTS gisaf_admin",
"CREATE SCHEMA IF NOT EXISTS gisaf_map",
"CREATE SCHEMA IF NOT EXISTS gisaf_survey",
"CREATE SCHEMA IF NOT EXISTS raw_survey",
"CREATE SCHEMA IF NOT EXISTS survey",
]
for rs in raw_sql:
await conn.execute(text(rs))
async def populate_init_db():
"""Populate the database for a fresh install"""
from sqlalchemy import text
from gisaf.security import create_user # , add_role, add_user_role
from gisaf.security import create_user, create_role, add_user_role
from gisaf.models.map_bases import BaseStyle
logger.info("Populating initial database")
async with db_session() as session:
user = await create_user(
session=session,
username="admin",
@ -215,10 +233,15 @@ async def populate_init_db():
email="root@localhost.localdomain",
active=True,
)
assert user is not None
# role = await add_role(role_id="admin")
# await add_user_role(user.username, role.name)
# for initial in initials:
# await session.execute(text(initial))
# logger.debug(f"Added map style {initial}")
# await session.commit()
role = await create_role(
session, name="admin", description="Initial admin user"
)
await session.refresh(user)
await session.refresh(role)
await add_user_role(session, user, role)
openFreeMap = BaseStyle(
name="OpenFreeMap",
static_url="https://tiles.openfreemap.org/styles/liberty",
)
session.add(openFreeMap)
await session.commit()

View file

@ -19,9 +19,9 @@ class BaseStyle(Model, table=True):
id: int | None = Field(primary_key=True, default=None)
name: str
style: dict[str, Any] | None = Field(sa_type=JSON(none_as_null=True)) # type: ignore
mbtiles: str = Field(sa_type=String(50)) # type: ignore
static_tiles_url: str
style: dict[str, Any] | None = Field(sa_type=JSON(none_as_null=True), default=None)
mbtiles: str | None = Field(sa_type=String(50), default=None)
static_url: str | None = Field(sa_type=String(250), default=None)
enabled: bool = True
def __repr__(self):

View file

@ -15,7 +15,7 @@ from sqlalchemy.orm import selectinload
from gisaf.config import conf
from gisaf.database import db_session
from gisaf.models.authentication import User, UserRead
from gisaf.models.authentication import User, UserRead, Role, UserRoleLink
logger = logging.getLogger(__name__)
@ -97,6 +97,38 @@ async def create_user(
return user_in_db
async def create_role(
session: AsyncSession,
name: str,
description: str | None = None,
):
role_in_db = await get_role(session, name)
if role_in_db is None:
role = Role(
name=name,
description=description,
)
session.add(role)
await session.commit()
return role
else:
role_in_db.description = description
await session.commit()
return role_in_db
async def add_user_role(session: AsyncSession, user: User, role: Role) -> User | None:
query = select(UserRoleLink).where(
UserRoleLink.user_id == user.id, UserRoleLink.role_id == role.id
)
data = await session.exec(query)
user_role = data.one_or_none()
if user_role is None:
user_role = UserRoleLink(user_id=user.id, role_id=role.id)
session.add(user_role)
await session.commit()
async def get_user(session: AsyncSession, username: str) -> User | None:
query = (
select(User).where(User.username == username).options(selectinload(User.roles))
@ -105,6 +137,12 @@ async def get_user(session: AsyncSession, username: str) -> User | None:
return data.one_or_none()
async def get_role(session: AsyncSession, name: str) -> Role | None:
query = select(Role).where(Role.name == name)
data = await session.exec(query)
return data.one_or_none()
def verify_password(user: User, plain_password):
try:
return pwd_context.verify(plain_password, user.password)