Skip to content

Commit b050663

Browse files
authored
Implement /api/name-groups endpoint (#61)
1 parent b5960ce commit b050663

File tree

4 files changed

+191
-0
lines changed

4 files changed

+191
-0
lines changed

gramps_webapi/api/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from .resources.filters import FilterResource
1818
from .resources.media import MediaObjectResource, MediaObjectsResource
1919
from .resources.metadata import MetadataResource
20+
from .resources.name_groups import NameGroupsResource
2021
from .resources.note import NoteResource, NotesResource
2122
from .resources.person import PeopleResource, PersonResource
2223
from .resources.place import PlaceResource, PlacesResource
@@ -69,6 +70,12 @@ def register_endpt(resource: Type[Resource], url: str, name: str):
6970
# Token
7071
register_endpt(TokenResource, "/login/", "token")
7172
register_endpt(TokenRefreshResource, "/refresh/", "token_refresh")
73+
# Name Groups
74+
register_endpt(
75+
NameGroupsResource, "/name-groups/<string:surname>/<string:group>", "set-name-group"
76+
)
77+
register_endpt(NameGroupsResource, "/name-groups/<string:surname>", "get-name-group")
78+
register_endpt(NameGroupsResource, "/name-groups/", "name-groups")
7279
# Bookmark
7380
register_endpt(BookmarkResource, "/bookmarks/<string:namespace>", "bookmark")
7481
register_endpt(BookmarksResource, "/bookmarks/", "bookmarks")
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
"""Name Groups API resource."""
2+
3+
from flask import Response, abort
4+
from gramps.gen.db.base import DbReadBase
5+
6+
from ..util import get_dbstate
7+
from . import ProtectedResource
8+
from .emit import GrampsJSONEncoder
9+
10+
11+
class NameGroupsResource(ProtectedResource, GrampsJSONEncoder):
12+
"""Name group mappings resource."""
13+
14+
@property
15+
def db_handle(self) -> DbReadBase:
16+
"""Get the database instance."""
17+
return get_dbstate().db
18+
19+
def get(self, surname: str = None) -> Response:
20+
"""Get list of name group mappings."""
21+
db_handle = self.db_handle
22+
if surname is not None:
23+
return self.response(
24+
200,
25+
{
26+
"surname": surname,
27+
"group": db_handle.get_name_group_mapping(surname),
28+
},
29+
)
30+
result = db_handle.get_name_group_keys()
31+
mappings = []
32+
if result is not None:
33+
for name in result:
34+
mappings.append(
35+
{"surname": name, "group": db_handle.get_name_group_mapping(name)}
36+
)
37+
return self.response(200, mappings)
38+
39+
def post(self, surname: str = None, group: str = None) -> Response:
40+
"""Set a name group mapping."""
41+
db_handle = self.db_handle
42+
if surname is None or group is None or len(surname) == 0 or len(group) == 0:
43+
abort(400)
44+
db_handle.set_name_group_mapping(surname, group)
45+
return self.response(201, {"surname": surname, "group": group})

gramps_webapi/data/apispec.yaml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ tags:
4747
description: Access to note objects.
4848
- name: tags
4949
description: Access to tag objects.
50+
- name: name-groups
51+
description: Access to name group mappings.
5052
- name: bookmarks
5153
description: Access to user bookmarks.
5254
- name: filters
@@ -1690,6 +1692,77 @@ paths:
16901692
404:
16911693
description: "Not Found: Tag not found."
16921694

1695+
##############################################################################
1696+
# Endpoint - NameGroups
1697+
##############################################################################
1698+
1699+
/name-groups:
1700+
get:
1701+
tags:
1702+
- name-groups
1703+
summary: "Get a list of name group mappings."
1704+
operationId: getNameGroupMappings
1705+
security:
1706+
- Bearer: []
1707+
responses:
1708+
200:
1709+
description: "OK: Successful operation."
1710+
schema:
1711+
type: array
1712+
items:
1713+
$ref: "#/definitions/NameGroupMapping"
1714+
401:
1715+
description: "Unauthorized: Missing authorization header."
1716+
1717+
/name-groups/{surname}:
1718+
get:
1719+
tags:
1720+
- name-groups
1721+
summary: "Get name group mapping for a given surname."
1722+
operationId: getNameGroupMapping
1723+
security:
1724+
- Bearer: []
1725+
parameters:
1726+
- name: surname
1727+
in: path
1728+
required: true
1729+
type: string
1730+
description: "The surname for which to get the grouping."
1731+
responses:
1732+
200:
1733+
description: "OK: Successful operation."
1734+
schema:
1735+
$ref: "#/definitions/NameGroupMapping"
1736+
401:
1737+
description: "Unauthorized: Missing authorization header."
1738+
1739+
/name-groups/{surname}/{group}:
1740+
post:
1741+
tags:
1742+
- name-groups
1743+
summary: "Set name group mapping for a given surname."
1744+
operationId: setNameGroupMapping
1745+
security:
1746+
- Bearer: []
1747+
parameters:
1748+
- name: surname
1749+
in: path
1750+
required: true
1751+
type: string
1752+
description: "The surname to set the mapping for."
1753+
- name: group
1754+
in: path
1755+
required: true
1756+
type: string
1757+
description: "The group to map the surname to."
1758+
responses:
1759+
200:
1760+
description: "OK: Successful operation."
1761+
schema:
1762+
$ref: "#/definitions/NameGroupMapping"
1763+
401:
1764+
description: "Unauthorized: Missing authorization header."
1765+
16931766
##############################################################################
16941767
# Endpoint - Bookmarks
16951768
##############################################################################
@@ -4200,3 +4273,19 @@ definitions:
42004273
example:
42014274
- e9027bf5e7f77551b12e7da3c77
42024275
- e9027bf3de2402f9faaac001cef
4276+
4277+
##############################################################################
4278+
# Model - NameGroupMapping
4279+
##############################################################################
4280+
4281+
NameGroupMapping:
4282+
type: object
4283+
properties:
4284+
surname:
4285+
description: "Surname to be grouped."
4286+
type: string
4287+
example: Fernández
4288+
group:
4289+
description: "Surname to be grouped with."
4290+
type: string
4291+
example: Fernandez
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
"""Tests for the /api/name-groups endpoint using example_gramps."""
2+
3+
import unittest
4+
5+
from jsonschema import RefResolver, validate
6+
7+
from . import API_SCHEMA, get_test_client
8+
9+
10+
class TestNameGroups(unittest.TestCase):
11+
"""Test cases for the /api/name-groups endpoint."""
12+
13+
@classmethod
14+
def setUpClass(cls):
15+
"""Test class setup."""
16+
cls.client = get_test_client()
17+
18+
def test_name_groups_endpoint(self):
19+
"""Test name groups."""
20+
# check response returned for name groups listing
21+
result = self.client.get("/api/name-groups/")
22+
self.assertEqual(result.json[0], {"surname": "Fernández", "group": "Fernandez"})
23+
# check response returned for specific surname
24+
result = self.client.get("/api/name-groups/Fernández")
25+
self.assertEqual(result.json, {"surname": "Fernández", "group": "Fernandez"})
26+
# check response setting incomplete new group mapping
27+
result = self.client.post("/api/name-groups/Stephen")
28+
self.assertEqual(result.status_code, 400)
29+
result = self.client.post("/api/name-groups/Stephen/")
30+
self.assertEqual(result.status_code, 404)
31+
# check response setting new group mapping
32+
result = self.client.post("/api/name-groups/Stephen/Steven")
33+
self.assertEqual(result.status_code, 201)
34+
# check response returned for surname group mapping just created
35+
result = self.client.get("/api/name-groups/Stephen")
36+
self.assertEqual(result.json, {"surname": "Stephen", "group": "Steven"})
37+
result = self.client.get("/api/name-groups/Steven")
38+
self.assertEqual(result.json, {"surname": "Steven", "group": "Steven"})
39+
40+
def test_name_groups_endpoint_schema(self):
41+
"""Test name groups against the name group schema."""
42+
# check record conforms to expected schema
43+
result = self.client.get("/api/name-groups/")
44+
resolver = RefResolver(base_uri="", referrer=API_SCHEMA, store={"": API_SCHEMA})
45+
for group in result.json:
46+
validate(
47+
instance=group,
48+
schema=API_SCHEMA["definitions"]["NameGroupMapping"],
49+
resolver=resolver,
50+
)

0 commit comments

Comments
 (0)