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

Order by last change #299

Merged
merged 7 commits into from
Mar 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.demo
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ LAYMAN_CLIENT_URL=http://layman_client:3000/client/

# client
LAYMAN_CLIENT_PUBLIC_URL=http://localhost/client/
LAYMAN_CLIENT_VERSION=ab35c7cca3ca5f8b1323405b9e7a17a099cbc214
LAYMAN_CLIENT_VERSION=1af9250d1451edc3142febcc6ae70ad9c4728970

# extra hosts to be added to /etc/hosts
EXTRA_HOST1=1.2.3.4:1.2.3.4
Expand Down
2 changes: 1 addition & 1 deletion .env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ LAYMAN_CLIENT_URL=http://layman_client:3000/client/

# client
LAYMAN_CLIENT_PUBLIC_URL=http://localhost:3000/client/
LAYMAN_CLIENT_VERSION=ab35c7cca3ca5f8b1323405b9e7a17a099cbc214
LAYMAN_CLIENT_VERSION=1af9250d1451edc3142febcc6ae70ad9c4728970


##############################################################################
Expand Down
2 changes: 1 addition & 1 deletion .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ LAYMAN_CLIENT_URL=http://layman_client_test:3000/client/

# client
LAYMAN_CLIENT_PUBLIC_URL=http://layman_test_run_1:8000/client/
LAYMAN_CLIENT_VERSION=ab35c7cca3ca5f8b1323405b9e7a17a099cbc214
LAYMAN_CLIENT_VERSION=1af9250d1451edc3142febcc6ae70ad9c4728970


##############################################################################
Expand Down
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@

### Migrations and checks
- [#257](https://github.com/jirik/layman/issues/257) Adjust prime DB schema for full-text filtering (install [unaccent](https://www.postgresql.org/docs/10/unaccent.html), create immutable `my_unaccent` function, index unaccented `title` column in `publications` table).
- [#257](https://github.com/jirik/layman/issues/257) Adjust prime DB schema for ordering by last change (create and fill column `updated_at` in `publications` table).

### Changes
- [#257](https://github.com/jirik/layman/issues/257) Endpoints [GET Layers](doc/rest.md#get-layers) and [GET Maps](doc/rest.md#get-maps) can filter and reorder results according to new query parameters.
- [#257](https://github.com/jirik/layman/issues/257) Endpoints [GET Layers](doc/rest.md#get-layers) and [GET Maps](doc/rest.md#get-maps) can filter and reorder results according to new query parameters.
- [#257](https://github.com/jirik/layman/issues/257) Responses of [GET Layers](doc/rest.md#get-layers), [GET Workspace Layers](doc/rest.md#get-workspace-layer), [GET Workspace Layer](doc/rest.md#get-workspace-layer), [PATCH Workspace Layer](doc/rest.md#patch-workspace-layer), [GET Maps](doc/rest.md#get-maps), [GET Workspace Maps](doc/rest.md#get-workspace-map), [GET Workspace Map](doc/rest.md#get-workspace-map), and [PATCH Workspace Map](doc/rest.md#patch-workspace-map) contains new attribute `updated_at` with date and time of last PATCH/POST request to given publication.

## v1.11.0
2021-03-16
Expand Down
8 changes: 8 additions & 0 deletions doc/rest.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Query parameters:
- *order_by*: String. Can be one of these values:
- `full_text` Publications will be ordered by results of full-text search. Can be used only in combination with *full_text_filter*.
- `title` Publications will be ordered lexicographically by title value.
- `last_change` Publications will be ordered by time of last change. Recently updated publications will be first.

#### Response
Content-Type: `application/json`
Expand All @@ -49,6 +50,7 @@ JSON array of objects representing available layers with following structure:
- **title**: String. Title of the layer.
- **uuid**: String. UUID of the layer.
- **url**: String. URL of the layer. It points to [GET Workspace Layer](#get-workspace-layer).
- **updated_at**: String. Date and time of last POST/PATCH of the publication. Format is [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601), more specifically `YYYY-MM-DDThh:mm:ss.sss±hh:mm`, always in UTC. Sample value: `"2021-03-18T09:29:53.769233+00:00"`
- **access_rights**:
- **read**: Array of strings. Names of [users](./models.md#user) and [roles](./models.md#role) with [read access](./security.md#Authorization).
- **write**: Array of strings. Names of [users](./models.md#user) and [roles](./models.md#role) with [write access](./security.md#Authorization).
Expand All @@ -71,6 +73,7 @@ JSON array of objects representing available layers with following structure:
- **title**: String. Title of the layer.
- **uuid**: String. UUID of the layer.
- **url**: String. URL of the layer. It points to [GET Workspace Layer](#get-workspace-layer).
- **updated_at**: String. Date and time of last POST/PATCH of the publication. Format is [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601), more specifically `YYYY-MM-DDThh:mm:ss.sss±hh:mm`, always in UTC. Sample value: `"2021-03-18T09:29:53.769233+00:00"`
- **access_rights**:
- **read**: Array of strings. Names of [users](./models.md#user) and [roles](./models.md#role) with [read access](./security.md#Authorization).
- **write**: Array of strings. Names of [users](./models.md#user) and [roles](./models.md#role) with [write access](./security.md#Authorization).
Expand Down Expand Up @@ -195,6 +198,7 @@ JSON object with following structure:
- **url**: String. URL pointing to this endpoint.
- **title**: String.
- **description**: String.
- **updated_at**: String. Date and time of last POST/PATCH of the publication. Format is [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601), more specifically `YYYY-MM-DDThh:mm:ss.sss±hh:mm`, always in UTC. Sample value: `"2021-03-18T09:29:53.769233+00:00"`
- **wms**
- *url*: String. URL of WMS endpoint. It points to WMS endpoint of appropriate GeoServer workspace.
- *status*: Status information about GeoServer import and availability of WMS layer. No status object means the source is available. Usual state values are
Expand Down Expand Up @@ -400,6 +404,7 @@ Query parameters:
- *order_by*: String. Can be one of these values:
- `full_text` Publications will be ordered by results of full-text search. Can be used only in combination with *full_text_filter*.
- `title` Publications will be ordered lexicographically by title value.
- `last_change` Publications will be ordered by time of last change. Recently updated publications will be first.

#### Response
Content-Type: `application/json`
Expand All @@ -410,6 +415,7 @@ JSON array of objects representing available maps with following structure:
- **title**: String. Title of the map.
- **uuid**: String. UUID of the map.
- **url**: String. URL of the map. It points to [GET Workspace Map](#get-workspace-map).
- **updated_at**: String. Date and time of last POST/PATCH of the publication. Format is [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601), more specifically `YYYY-MM-DDThh:mm:ss.sss±hh:mm`, always in UTC. Sample value: `"2021-03-18T09:29:53.769233+00:00"`
- **access_rights**:
- **read**: Array of strings. Names of [users](./models.md#user) and [roles](./models.md#role) with [read access](./security.md#Authorization).
- **write**: Array of strings. Names of [users](./models.md#user) and [roles](./models.md#role) with [write access](./security.md#Authorization).
Expand All @@ -433,6 +439,7 @@ JSON array of objects representing available maps with following structure:
- **title**: String. Title of the map.
- **uuid**: String. UUID of the map.
- **url**: String. URL of the map. It points to [GET Workspace Map](#get-workspace-map).
- **updated_at**: String. Date and time of last POST/PATCH of the publication. Format is [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601), more specifically `YYYY-MM-DDThh:mm:ss.sss±hh:mm`, always in UTC. Sample value: `"2021-03-18T09:29:53.769233+00:00"`
- **access_rights**:
- **read**: Array of strings. Names of [users](./models.md#user) and [roles](./models.md#role) with [read access](./security.md#Authorization).
- **write**: Array of strings. Names of [users](./models.md#user) and [roles](./models.md#role) with [write access](./security.md#Authorization).
Expand Down Expand Up @@ -525,6 +532,7 @@ JSON object with following structure:
- **url**: String. URL pointing to this endpoint.
- **title**: String. Taken from `title` attribute of JSON root object
- **description**: String. Taken from `abstract` attribute of JSON root object.
- **updated_at**: String. Date and time of last POST/PATCH of the publication. Format is [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601), more specifically `YYYY-MM-DDThh:mm:ss.sss±hh:mm`, always in UTC. Sample value: `"2021-03-18T09:29:53.769233+00:00"`
- **file**
- *url*: String. URL of map-composition JSON file. It points to [GET Workspace Map File](#get-workspace-map-file).
- *path*: String. Path to map-composition JSON file, relative to workspace directory.
Expand Down
1 change: 1 addition & 0 deletions src/layman/common/get_publications_consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

ORDER_BY_FULL_TEXT = 'full_text'
ORDER_BY_TITLE = 'title'
ORDER_BY_LAST_CHANGE = 'last_change'
2 changes: 1 addition & 1 deletion src/layman/common/prime_db_schema/migrate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from layman import settings, app, util, upgrade
from layman.layer import LAYER_TYPE
from layman.map import MAP_TYPE
from layman import upgrade
from . import model, publications as pub_util, workspaces as workspaces_util
from .schema_initialization import ensure_schema
from .util import run_query, run_statement
Expand All @@ -30,6 +29,7 @@ def save_upgrade_status():
upgrade.upgrade_v1_10.alter_schema()
upgrade.upgrade_v1_10.update_style_type_in_db()
upgrade.upgrade_v1_12.adjust_prime_db_schema_for_fulltext_search()
upgrade.upgrade_v1_12.adjust_prime_db_schema_for_last_change_search()

upgrade.set_current_data_version(current_version)

Expand Down
12 changes: 8 additions & 4 deletions src/layman/common/prime_db_schema/publications.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def get_publication_infos(workspace_name=None, pub_type=None, style_type=None,
order_by_definition = {
consts.ORDER_BY_FULL_TEXT: ('ts_rank_cd(_prime_schema.my_unaccent(p.title), to_tsquery(unaccent(%s))) DESC', (ordering_full_text,)),
consts.ORDER_BY_TITLE: ('unaccent(p.title) ASC', tuple()),
consts.ORDER_BY_LAST_CHANGE: ('updated_at DESC', tuple()),
}

assert all(ordering_item in order_by_definition.keys() for ordering_item in order_by_list)
Expand All @@ -64,6 +65,7 @@ def get_publication_infos(workspace_name=None, pub_type=None, style_type=None,
p.title,
p.uuid::text,
p.style_type,
p.updated_at,
(select rtrim(concat(case when u.id is not null then w.name || ',' end,
string_agg(w2.name, ',') || ',',
case when p.everyone_can_read then %s || ',' end
Expand Down Expand Up @@ -129,10 +131,11 @@ def get_publication_infos(workspace_name=None, pub_type=None, style_type=None,
'uuid': uuid,
'type': type,
'style_type': style_type,
'updated_at': updated_at,
'access_rights': {'read': [x for x in can_read_users.split(',')],
'write': [x for x in can_write_users.split(',')]}
}
for id_publication, workspace_name, type, publication_name, title, uuid, style_type, can_read_users, can_write_users
for id_publication, workspace_name, type, publication_name, title, uuid, style_type, updated_at, can_read_users, can_write_users
in values}
return infos

Expand Down Expand Up @@ -224,8 +227,8 @@ def insert_publication(workspace_name, info):
check_publication_info(workspace_name, info)

insert_publications_sql = f'''insert into {DB_SCHEMA}.publications as p
(id_workspace, name, title, type, uuid, style_type, everyone_can_read, everyone_can_write) values
(%s, %s, %s, %s, %s, %s, %s, %s)
(id_workspace, name, title, type, uuid, style_type, everyone_can_read, everyone_can_write, updated_at) values
(%s, %s, %s, %s, %s, %s, %s, %s, current_timestamp)
returning id
;'''

Expand Down Expand Up @@ -286,7 +289,8 @@ def update_publication(workspace_name, info):
title = coalesce(%s, title),
style_type = coalesce(%s, style_type),
everyone_can_read = coalesce(%s, everyone_can_read),
everyone_can_write = coalesce(%s, everyone_can_write)
everyone_can_write = coalesce(%s, everyone_can_write),
updated_at = current_timestamp
index-git marked this conversation as resolved.
Show resolved Hide resolved
where id_workspace = %s
and name = %s
and type = %s
Expand Down
7 changes: 7 additions & 0 deletions src/layman/common/prime_db_schema/publications_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,13 @@ def provide_data(self):
(workspace1, MAP_TYPE, 'test_select_publications_publication1e'),
(workspace2, MAP_TYPE, 'test_select_publications_publication2e'),
]),
({'order_by_list': ['last_change'], }, [
(workspace2, MAP_TYPE, 'test_select_publications_publication2o'),
(workspace2, MAP_TYPE, 'test_select_publications_publication2e'),
(workspace1, MAP_TYPE, 'test_select_publications_publication1oe'),
(workspace1, MAP_TYPE, 'test_select_publications_publication1o'),
(workspace1, MAP_TYPE, 'test_select_publications_publication1e'),
]),
])
@pytest.mark.usefixtures('liferay_mock', 'ensure_layman', 'provide_data')
def test_get_publications(self, query_params, expected_publications):
Expand Down
7 changes: 5 additions & 2 deletions src/layman/common/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,9 @@ def setup_post_access_rights(request_form, kwargs, actor_name):
kwargs['access_rights'][type] = access_rights


def get_publications(publication_type, user, request_args):
known_order_by_values = [consts.ORDER_BY_TITLE, consts.ORDER_BY_FULL_TEXT, ]
def get_publications(publication_type, user, request_args=None, workspace=None):
request_args = request_args or {}
known_order_by_values = [consts.ORDER_BY_TITLE, consts.ORDER_BY_FULL_TEXT, consts.ORDER_BY_LAST_CHANGE, ]

full_text_filter = None
if consts.FILTER_FULL_TEXT in request_args:
Expand All @@ -128,6 +129,7 @@ def get_publications(publication_type, user, request_args):
order_by_list = [consts.ORDER_BY_FULL_TEXT]

publication_infos_whole = layman_util.get_publication_infos(publ_type=publication_type,
workspace=workspace,
context={'actor_name': user,
'access_type': 'read'
},
Expand All @@ -144,6 +146,7 @@ def get_publications(publication_type, user, request_args):
'url': layman_util.get_workspace_publication_url(publication_type, workspace, name),
'uuid': info["uuid"],
'access_rights': info['access_rights'],
'updated_at': info['updated_at'].isoformat(),
}
for (workspace, _, name), info in publication_infos_whole.items()
]
Expand Down
1 change: 1 addition & 0 deletions src/layman/common/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ def clear_publication_info(info):
del info[key]
except KeyError:
pass
info['updated_at'] = info['updated_at'].isoformat()
index-git marked this conversation as resolved.
Show resolved Hide resolved
return info
2 changes: 1 addition & 1 deletion src/layman/layer/rest_layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ def get():
app.logger.info(f"GET Layers, user={g.user}")

user = get_authn_username() or settings.ANONYM_USER
return rest_common.get_publications(LAYER_TYPE, user, request.args)
return rest_common.get_publications(LAYER_TYPE, user, request_args=request.args)
21 changes: 4 additions & 17 deletions src/layman/layer/rest_workspace_layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
from layman import settings, authn, util as layman_util
from . import util, LAYER_TYPE, LAYER_REST_PATH_NAME
from .filesystem import input_file, input_style, input_chunk, uuid
from layman.authn import authenticate
from layman.authn import authenticate, get_authn_username
from layman.authz import authorize_workspace_publications_decorator
from layman.common import redis as redis_util
from layman.common import redis as redis_util, rest as rest_common

bp = Blueprint('rest_workspace_layers', __name__)

Expand All @@ -32,21 +32,8 @@ def after_request(response):
def get(username):
app.logger.info(f"GET Layers, user={g.user}")

layer_infos_whole = layman_util.get_publication_infos(username, LAYER_TYPE)

infos = [
{
'name': info["name"],
'workspace': workspace,
'title': info.get("title", None),
'url': url_for('rest_workspace_layer.get', layername=name, username=username),
'uuid': info["uuid"],
'access_rights': info['access_rights'],
}
for (workspace, publication_type, name), info in layer_infos_whole.items()
]
sorted_infos = sorted(infos, key=lambda x: x['name'])
return jsonify(sorted_infos), 200
user = get_authn_username() or settings.ANONYM_USER
return rest_common.get_publications(LAYER_TYPE, user, workspace=username)


@bp.route(f"/{LAYER_REST_PATH_NAME}", methods=['POST'])
Expand Down
2 changes: 1 addition & 1 deletion src/layman/map/rest_maps.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ def get():
app.logger.info(f"GET Maps, user={g.user}")

user = get_authn_username() or settings.ANONYM_USER
return rest_common.get_publications(MAP_TYPE, user, request.args)
return rest_common.get_publications(MAP_TYPE, user, request_args=request.args)
23 changes: 5 additions & 18 deletions src/layman/map/rest_workspace_maps.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
from layman.util import check_username_decorator, url_for
from . import util, MAP_TYPE, MAP_REST_PATH_NAME
from .filesystem import input_file, uuid
from layman import authn, util as layman_util
from layman.authn import authenticate
from layman import authn, util as layman_util, settings
from layman.authn import authenticate, get_authn_username
from layman.authz import authorize_workspace_publications_decorator
from layman.common import redis as redis_util
from layman.common import redis as redis_util, rest as rest_common

bp = Blueprint('rest_workspace_maps', __name__)

Expand All @@ -35,21 +35,8 @@ def after_request(response):
def get(username):
app.logger.info(f"GET Maps, user={g.user}")

mapinfos_whole = layman_util.get_publication_infos(username, MAP_TYPE)

infos = [
{
'name': info["name"],
'workspace': workspace,
'title': info.get("title", None),
'url': url_for('rest_workspace_map.get', mapname=name, username=username),
'uuid': info['uuid'],
'access_rights': info['access_rights'],
}
for (workspace, publication_type, name), info in mapinfos_whole.items()
]
sorted_infos = sorted(infos, key=lambda x: x['name'])
return jsonify(sorted_infos), 200
user = get_authn_username() or settings.ANONYM_USER
return rest_common.get_publications(MAP_TYPE, user, workspace=username)


@bp.route(f"/{MAP_REST_PATH_NAME}", methods=['POST'])
Expand Down
4 changes: 4 additions & 0 deletions src/layman/rest_multipublication_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ def provide_data(self):
(workspace1, 'test_get_publications_publication1e'),
(workspace2, 'test_get_publications_publication2e'),
],),
(authn_headers_user2, {'order_by': 'last_change'}, [(workspace2, 'test_get_publications_publication2o'),
(workspace2, 'test_get_publications_publication2e'),
(workspace1, 'test_get_publications_publication1e'),
],),
])
@pytest.mark.parametrize('publication_type', process_client.PUBLICATION_TYPES)
@pytest.mark.usefixtures('liferay_mock', 'ensure_layman', 'provide_data')
Expand Down
Loading