Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create get.users endpoint #121

Merged
merged 14 commits into from
Oct 27, 2020
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Upgrade requirements
### Changes
- [#28](https://github.com/jirik/layman/issues/28) New environment variable [LAYMAN_PRIME_SCHEMA](doc/env-settings.md#LAYMAN_PRIME_SCHEMA).
- [#28](https://github.com/jirik/layman/issues/28) New REST endpoint [GET Users](doc/rest.md#get-users) with list of all users registered in Layman.

## v1.7.1
2020-09-30
Expand Down
21 changes: 21 additions & 0 deletions doc/rest.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
|Map File|`/rest/<username>/maps/<mapname>/file`|[GET](#get-map-file)| x | x | x |
|Map Thumbnail|`/rest/<username>/maps/<mapname>/thumbnail`|[GET](#get-map-thumbnail)| x | x | x |
|Map Metadata Comparison|`/rest/<username>/layers/<layername>/metadata-comparison`|[GET](#get-map-metadata-comparison) | x | x | x |
|Users|`/rest/users`|[GET](#get-users)| x | x | x |
|Current [User](models.md#user)|`/rest/current-user`|[GET](#get-current-user)| x | [PATCH](#patch-current-user) | [DELETE](#delete-current-user) |

#### REST path parameters
Expand Down Expand Up @@ -490,6 +491,26 @@ JSON object with one attribute:
- **equal_or_null**: Boolean. True if all values are considered equal or null, false otherwise.


## Users
### URL
`/rest/users`

### GET Users
Get list of registered users.

#### Request.
No action parameters.

#### Response
Content-Type: `application/json`

JSON array of objects representing users of Layman with following structure:
- **username**: String. Username of the user.
- **given_name**: String. Given name of the user.
- **family_name**: String. Family name of the user
- **middle_name**: String. Middle name of the user
- **name**: String. Whole name of the user (given_name + middle_name + family_name).

## Current User
### URL
`/rest/current-user`
Expand Down
11 changes: 7 additions & 4 deletions src/layman/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import sys
import time


IN_CELERY_WORKER_PROCESS = sys.argv and sys.argv[0].endswith('/celery/__main__.py')
IN_PYTEST_PROCESS = sys.argv and sys.argv[0].endswith('/pytest/__main__.py')
IN_FLOWER_PROCESS = sys.argv and sys.argv[0].endswith('/flower/__main__.py')
Expand Down Expand Up @@ -35,10 +34,11 @@

from .user.rest_current_user import bp as current_user_bp
from .gs_wfs_proxy import bp as gs_wfs_proxy_bp
from .common import prime_db_schema as db_util
from .user.rest_users import bp as users_bp

app.register_blueprint(current_user_bp, url_prefix='/rest/current-user')
app.register_blueprint(gs_wfs_proxy_bp, url_prefix='/geoserver')
app.register_blueprint(users_bp, url_prefix=f'/rest/{settings.REST_USERS_PREFIX}')

app.logger.info(f"IN_CELERY_WORKER_PROCESS={IN_CELERY_WORKER_PROCESS}")
app.logger.info(f"IN_PYTEST_PROCESS={IN_PYTEST_PROCESS}")
Expand All @@ -64,8 +64,11 @@
ensure_proxy_base_url(settings.LAYMAN_GS_PROXY_BASE_URL, settings.LAYMAN_GS_AUTH)

with app.app_context():
db_util.check_schema_name()
db_util.ensure_schema()
import layman.common.prime_db_schema.schema_initialization as prime_db_schema
prime_db_schema.check_schema_name(settings.LAYMAN_PRIME_SCHEMA)
prime_db_schema.ensure_schema(settings.LAYMAN_PRIME_SCHEMA,
app,
settings.PUBLICATION_MODULES)

app.logger.info(f'Loading Redis database')
with app.app_context():
Expand Down
9 changes: 9 additions & 0 deletions src/layman/authn/prime_db_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from layman.common.prime_db_schema import ensure_whole_user


def save_username_reservation(username, iss_id, sub, claims):
userinfo = {"iss_id": iss_id,
"sub": sub,
"claims": claims,
}
ensure_whole_user(username, userinfo)
79 changes: 23 additions & 56 deletions src/layman/common/prime_db_schema/__init__.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,23 @@
from layman.util import get_usernames, get_modules_from_names, call_modules_fn
from layman.common.util import merge_infos
from layman import settings, app, LaymanError
from layman.authz.util import get_publication_access_rights
from layman.common.prime_db_schema import publications, model, users
from layman.common.prime_db_schema.util import run_query, run_statement


DB_SCHEMA = settings.LAYMAN_PRIME_SCHEMA


def get_default_everyone_can_read():
return model.BOOLEAN_TRUE


def get_default_everyone_can_write():
return get_publication_access_rights('', '', '')["guest"] == "w"


def migrate_users_and_publications():
usernames = get_usernames(use_cache=False)

for username in usernames:
users.ensure_user(username)
for publ_module in get_modules_from_names(settings.PUBLICATION_MODULES):
for type_def in publ_module.PUBLICATION_TYPES.values():
publ_type_name = type_def['type']
sources = get_modules_from_names(type_def['internal_sources'])
results = call_modules_fn(sources, 'get_publication_infos', [username, publ_type_name])
pubs = merge_infos(results)
for name, info in pubs.items():
pub_info = {"name": name,
"title": info.get("title"),
"publ_type_name": publ_type_name,
"uuid": info.get("uuid"),
"can_read": set(),
"can_write": set(),
}
publications.insert_publication(username, pub_info)


def check_schema_name():
usernames = get_usernames(use_cache=False, skip_modules=('layman.map.prime_db_schema', 'layman.layer.prime_db_schema', ))
if DB_SCHEMA in usernames:
raise LaymanError(42, {'username': DB_SCHEMA})


def ensure_schema():
exists_schema = run_query(model.EXISTS_SCHEMA_SQL)
if exists_schema[0][0] == 0:
app.logger.info(f"Going to create Layman DB schema, schema_name={DB_SCHEMA}")
run_statement(model.CREATE_SCHEMA_SQL)
run_statement(model.setup_codelists_data())
migrate_users_and_publications()
else:
app.logger.info(f"Layman DB schema already exists, schema_name={DB_SCHEMA}")
from layman.common.prime_db_schema import users as users_util, workspaces as workspaces_util

get_usernames = workspaces_util.get_workspace_names


def check_new_layername(username, layername):
pass


def delete_whole_user(username):
users_util.delete_user(username)
workspaces_util.delete_workspace(username)


def ensure_whole_user(username, userinfo=None):
id_workspace = workspaces_util.ensure_workspace(username)
if userinfo:
users_util.ensure_user(id_workspace, userinfo)


def check_username(username):
users_util.check_username(username)
workspaces_util.check_workspace_name(username)
42 changes: 27 additions & 15 deletions src/layman/common/prime_db_schema/migrate_test.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import test.flask_client as client_util

from layman import settings, app as app
from . import ensure_schema, migrate_users_and_publications, model, publications
from . import model, publications as pub_util, workspaces as workspaces_util
from .schema_initialization import migrate_users_and_publications, ensure_schema
from .util import run_query, run_statement
from layman import util
from layman.layer import util as layer_util
Expand All @@ -18,7 +19,9 @@ def test_recreate_schema(client):

with app.app_context():
run_statement(model.DROP_SCHEMA_SQL)
ensure_schema()
ensure_schema(settings.LAYMAN_PRIME_SCHEMA,
app,
settings.PUBLICATION_MODULES)

client_util.delete_layer(username, 'test_recreate_schema_layer1', client)
client_util.delete_map(username, 'test_recreate_schema_map1', client)
Expand All @@ -32,17 +35,26 @@ def test_recreate_schema(client):

def test_schema(client):
username = 'migration_test_user1'
client_util.publish_layer(username, 'migration_test_layer1', client)
client_util.publish_map(username, 'migration_test_map1', client)
layername = 'migration_test_layer1'
mapname = 'migration_test_map1'
client_util.publish_layer(username, layername, client)
client_util.publish_map(username, mapname, client)

with app.app_context():
run_statement(model.DROP_SCHEMA_SQL)
ensure_schema()
users = run_query(f'select count(*) from {DB_SCHEMA}.users;')
assert users[0][0] == len(util.get_usernames())

client_util.delete_layer(username, 'migration_test_layer1', client)
client_util.delete_map(username, 'migration_test_map1', client)
ensure_schema(settings.LAYMAN_PRIME_SCHEMA,
app,
settings.PUBLICATION_MODULES)
workspaces = run_query(f'select count(*) from {DB_SCHEMA}.workspaces;')
assert workspaces[0][0] == len(util.get_usernames())
user_infos = workspaces_util.get_workspace_infos(username)
assert username in user_infos
pub_infos = pub_util.get_publication_infos(username)
assert layername in pub_infos
assert mapname in pub_infos

client_util.delete_layer(username, layername, client)
client_util.delete_map(username, mapname, client)

with app.app_context():
pubs = layer_util.get_layer_infos(username)
Expand Down Expand Up @@ -71,13 +83,13 @@ def test_steps(client):
exists_right_types = run_query(f'select count(*) from {DB_SCHEMA}.right_types;')
assert exists_right_types[0][0] == 2

exists_users = run_query(f'select count(*) from {DB_SCHEMA}.users;')
assert exists_users[0][0] == 0
exists_workspaces = run_query(f'select count(*) from {DB_SCHEMA}.workspaces;')
assert exists_workspaces[0][0] == 0
exists_pubs = run_query(f'select count(*) from {DB_SCHEMA}.publications;')
assert exists_pubs[0][0] == 0
migrate_users_and_publications()
exists_users = run_query(f'select count(*) from {DB_SCHEMA}.users;')
assert exists_users[0][0] > 0
migrate_users_and_publications(settings.PUBLICATION_MODULES)
exists_workspaces = run_query(f'select count(*) from {DB_SCHEMA}.workspaces;')
assert exists_workspaces[0][0] > 0
exists_pubs = run_query(f'select count(*) from {DB_SCHEMA}.publications;')
assert exists_pubs[0][0] > 0

Expand Down
33 changes: 29 additions & 4 deletions src/layman/common/prime_db_schema/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ def setup_codelists_data():
ALTER SEQUENCE {DB_SCHEMA}.users_id_seq
OWNER TO {settings.LAYMAN_PG_USER};

CREATE SEQUENCE {DB_SCHEMA}.workspaces_id_seq
INCREMENT 1
START 1
MINVALUE 1
MAXVALUE 2147483647
CACHE 1;
ALTER SEQUENCE {DB_SCHEMA}.workspaces_id_seq
OWNER TO {settings.LAYMAN_PG_USER};

CREATE SEQUENCE {DB_SCHEMA}.rights_id_seq
INCREMENT 1
START 1
Expand Down Expand Up @@ -96,19 +105,35 @@ def setup_codelists_data():
)
TABLESPACE pg_default;

CREATE TABLE {DB_SCHEMA}.workspaces
(
id integer NOT NULL DEFAULT nextval('{DB_SCHEMA}.workspaces_id_seq'::regclass),
name VARCHAR(256) COLLATE pg_catalog."default",
CONSTRAINT workspaces_pkey PRIMARY KEY (id),
CONSTRAINT workspaces_name_key UNIQUE (name)
)
TABLESPACE pg_default;

CREATE TABLE {DB_SCHEMA}.users
(
id integer NOT NULL DEFAULT nextval('{DB_SCHEMA}.users_id_seq'::regclass),
username VARCHAR(256) COLLATE pg_catalog."default" not null,
id_workspace integer REFERENCES {DB_SCHEMA}.workspaces (id),
given_name VARCHAR(256) COLLATE pg_catalog."default",
family_name VARCHAR(256) COLLATE pg_catalog."default",
middle_name VARCHAR(256) COLLATE pg_catalog."default",
name VARCHAR(256) COLLATE pg_catalog."default",
email VARCHAR(1024) COLLATE pg_catalog."default",
issuer_id VARCHAR(256) COLLATE pg_catalog."default",
sub VARCHAR(256) COLLATE pg_catalog."default",
CONSTRAINT users_pkey PRIMARY KEY (id),
CONSTRAINT users_username_key UNIQUE (username)
CONSTRAINT users_workspace_key UNIQUE (id_workspace)
)
TABLESPACE pg_default;

CREATE TABLE {DB_SCHEMA}.publications
(
id integer NOT NULL DEFAULT nextval('{DB_SCHEMA}.publications_id_seq'::regclass),
id_user integer NOT NULL REFERENCES {DB_SCHEMA}.users (id),
id_workspace integer REFERENCES {DB_SCHEMA}.workspaces (id),
name VARCHAR(256) COLLATE pg_catalog."default" not null,
title VARCHAR(256) COLLATE pg_catalog."default" not null,
type VARCHAR(64) COLLATE pg_catalog."default" not null references {DB_SCHEMA}.publication_types (name),
Expand All @@ -117,7 +142,7 @@ def setup_codelists_data():
everyone_can_write boolean not null,
constraint publications_pkey primary key (id),
constraint publications_uuid_key unique (uuid),
constraint publications_name_type_key unique (id_user, type, name)
constraint publications_name_type_key unique (id_workspace, type, name)
)
TABLESPACE pg_default;

Expand Down
Loading