mirror of
https://github.com/ilri/dspace-statistics-api.git
synced 2025-09-07 20:31:46 +02:00
Compare commits
7 Commits
70b2ba83ba
...
v1.4.0-dev
Author | SHA1 | Date | |
---|---|---|---|
a02211fd60
|
|||
fc814593c7
|
|||
7de1084f60
|
|||
6b78e82fe9
|
|||
4004515967
|
|||
d1229c2387
|
|||
be83514de1
|
@@ -1,21 +1,34 @@
|
||||
import json
|
||||
|
||||
import falcon
|
||||
import psycopg2.extras
|
||||
from falcon_swagger_ui import register_swaggerui_app
|
||||
|
||||
from .config import DSPACE_STATISTICS_API_URL, VERSION
|
||||
from .database import DatabaseManager
|
||||
from .stats import get_downloads, get_views
|
||||
from .util import set_statistics_scope, validate_post_parameters
|
||||
from .config import VERSION
|
||||
from .config import SWAGGERUI_URL
|
||||
from .config import SWAGGERUI_SCHEMA_URL
|
||||
|
||||
|
||||
class RootResource:
|
||||
def on_get(self, req, resp):
|
||||
resp.status = falcon.HTTP_200
|
||||
resp.content_type = "text/html"
|
||||
with open("dspace_statistics_api/docs/index.html", "r") as f:
|
||||
resp.body = f.read()
|
||||
docs_html = (
|
||||
"<!DOCTYPE html>"
|
||||
"<html lang=\"en-US\">"
|
||||
" <head>"
|
||||
" <meta charset=\"UTF-8\">"
|
||||
" <title>DSpace Statistics API</title>"
|
||||
" </head>"
|
||||
" <body>"
|
||||
f" <h1>DSpace Statistics API {VERSION}</h1>"
|
||||
f" <p>This site is running the <a href=\"https://github.com/ilri/dspace-statistics-api\" title=\"DSpace Statistics API project\">DSpace Statistics API</a>. For more information see the project's README.md or the interactive <a href=\"{DSPACE_STATISTICS_API_URL + '/swagger'}\">Swagger UI</a> built into this API.</p>"
|
||||
" </body>"
|
||||
"</html"
|
||||
)
|
||||
|
||||
resp.body = docs_html
|
||||
|
||||
|
||||
class StatusResource:
|
||||
@@ -31,7 +44,20 @@ class OpenAPIJSONResource:
|
||||
resp.status = falcon.HTTP_200
|
||||
resp.content_type = "text/html"
|
||||
with open("dspace_statistics_api/docs/openapi.json", "r") as f:
|
||||
resp.body = f.read()
|
||||
# Load the openapi.json schema
|
||||
data = json.load(f)
|
||||
|
||||
# Swagger assumes your API is at the root of the current host unless
|
||||
# you configure a "servers" block in the schema. The problem is that
|
||||
# I want this to work in both development and production, so we need
|
||||
# to make this configurable.
|
||||
#
|
||||
# If the DSPACE_STATISTICS_API_URL is configured then we will add a
|
||||
# server entry to the openapi.json schema before sending it.
|
||||
if DSPACE_STATISTICS_API_URL != "":
|
||||
data["servers"] = [{"url": DSPACE_STATISTICS_API_URL}]
|
||||
|
||||
resp.body = json.dumps(data)
|
||||
|
||||
|
||||
class AllStatisticsResource:
|
||||
@@ -199,16 +225,29 @@ api.add_route("/community/{id_:uuid}", SingleStatisticsResource())
|
||||
api.add_route("/collections", AllStatisticsResource())
|
||||
api.add_route("/collection/{id_:uuid}", SingleStatisticsResource())
|
||||
|
||||
# Swagger configuration
|
||||
api.add_route(SWAGGERUI_SCHEMA_URL, OpenAPIJSONResource())
|
||||
# Route to the Swagger UI OpenAPI schema
|
||||
api.add_route("/docs/openapi.json", OpenAPIJSONResource())
|
||||
|
||||
# Path to host the Swagger UI. Keep in mind that Falcon will add a route for
|
||||
# this automatically when we register Swagger and the path will be relative
|
||||
# to the Falcon app like all other routes, not the absolute root.
|
||||
SWAGGERUI_PATH = "/swagger"
|
||||
|
||||
# The *absolute* path to the OpenJSON schema. This must be absolute because
|
||||
# it will be requested by the client and must resolve absolutely. Note: the
|
||||
# name of this variable is misleading because it is actually the schema URL
|
||||
# but we pass it into the register_swaggerui_app() function as the api_url
|
||||
# parameter.
|
||||
SWAGGERUI_API_URL = f"{DSPACE_STATISTICS_API_URL}/docs/openapi.json"
|
||||
|
||||
register_swaggerui_app(
|
||||
api,
|
||||
SWAGGERUI_URL,
|
||||
SWAGGERUI_SCHEMA_URL,
|
||||
SWAGGERUI_PATH,
|
||||
SWAGGERUI_API_URL,
|
||||
config={
|
||||
"supportedSubmitMethods": ["get", "post"],
|
||||
},
|
||||
uri_prefix=DSPACE_STATISTICS_API_URL,
|
||||
)
|
||||
|
||||
# vim: set sw=4 ts=4 expandtab:
|
||||
|
@@ -9,12 +9,12 @@ DATABASE_PASS = os.environ.get("DATABASE_PASS", "dspacestatistics")
|
||||
DATABASE_HOST = os.environ.get("DATABASE_HOST", "localhost")
|
||||
DATABASE_PORT = os.environ.get("DATABASE_PORT", "5432")
|
||||
|
||||
# SwaggerUI configuration
|
||||
|
||||
# URI path where the Swagger UI should be available (without trailing slash)
|
||||
SWAGGERUI_URL = os.environ.get("SWAGGERUI_URL", "/swagger")
|
||||
# URI path to the OpenAPI JSON schema
|
||||
SWAGGERUI_SCHEMA_URL = os.environ.get("SWAGGERUI_SCHEMA_URL", "/docs/openapi.json")
|
||||
# URL to DSpace Statistics API, which will be used as a prefix to API calls in
|
||||
# the Swagger UI. An empty string will allow this to work out of the box in a
|
||||
# local development environment, but for production it should be set to a value
|
||||
# like "/rest/statistics", assuming that the statistics API is deployed next to
|
||||
# the vanilla DSpace REST API.
|
||||
DSPACE_STATISTICS_API_URL = os.environ.get("DSPACE_STATISTICS_API_URL", "")
|
||||
|
||||
VERSION = "1.4.0-dev"
|
||||
|
||||
|
@@ -1,44 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>DSpace Statistics API</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>DSpace Statistics API v1.4.0-dev</h1>
|
||||
<p>This site is running the <a href="https://github.com/ilri/dspace-statistics-api" title="DSpace Statistics API project">DSpace Statistics API</a>. The following endpoints are available:</p>
|
||||
<ul>
|
||||
<li>GET <code>/</code> — return a basic API documentation page.</li>
|
||||
<li>GET <code>/items</code> — return views and downloads for all items that Solr knows about¹. Accepts <code>limit</code> and <code>page</code> query parameters for pagination of results (<code>limit</code> must be an integer between 1 and 100, and <code>page</code> must be an integer greater than or equal to 0).</li>
|
||||
<li>POST <code>/items</code> — return views and downloads for an arbitrary list of items with an optional date range. Accepts <code>limit</code>, <code>page</code>, <code>dateFrom</code>, and <code>dateTo</code> parameters².</li>
|
||||
<li>GET <code>/item/id</code> — return views and downloads for a single item (<code>id</code> must be a UUID). Returns HTTP 404 if an item id is not found.</li>
|
||||
<li>GET <code>/communities</code> — return views and downloads for all communities that Solr knows about¹. Accepts <code>limit</code> and <code>page</code> query parameters for pagination of results (<code>limit</code> must be an integer between 1 and 100, and <code>page</code> must be an integer greater than or equal to 0).
|
||||
<li>POST <code>/communities</code> — return views and downloads for an arbitrary list of communities with an optional date range. Accepts <code>limit</code>, <code>page</code>, <code>dateFrom</code>, and <code>dateTo</code> parameters².
|
||||
<li>GET <code>/community/id</code> — return views and downloads for a single community (<code>id</code> must be a UUID). Returns HTTP 404 if a community id is not found.
|
||||
<li>GET <code>/collections</code> — return views and downloads for all collections that Solr knows about¹. Accepts <code>limit</code> and <code>page</code> query parameters for pagination of results (<code>limit</code> must be an integer between 1 and 100, and <code>page</code> must be an integer greater than or equal to 0).
|
||||
<li>POST <code>/collections</code> — return views and downloads for an arbitrary list of collections with an optional date range. Accepts <code>limit</code>, <code>page</code>, <code>dateFrom</code>, and <code>dateTo</code> parameters².
|
||||
<li>GET <code>/collection/id</code> — return views and downloads for a single collection (<code>id</code> must be a UUID). Returns HTTP 404 if an collection id is not found.
|
||||
</ul>
|
||||
|
||||
<p>The id is the <em>internal</em> UUID for an item, community, or collection. You can get these from the standard DSpace REST API.</p>
|
||||
|
||||
<hr/>
|
||||
|
||||
<p>¹ We are querying the Solr statistics core, which technically only knows about items, communities, or collections that have either views or downloads. If an item, community, or collection is not present here you can assume it has zero views and zero downloads, but not necessarily that it does not exist in the repository.</p>
|
||||
|
||||
<p>² POST requests to <code>/items</code>, <code>/communities</code>, and <code>/collections</code> should be in JSON format with the following parameters (substitute the "items" list for communities or collections accordingly):</p>
|
||||
<pre><code>{
|
||||
"limit": 100, // optional, integer between 1 and 100, default 100
|
||||
"page": 0, // optional, integer greater than 0, default 0
|
||||
"dateFrom": "2020-01-01T00:00:00Z", // optional, default *
|
||||
"dateTo": "2020-09-09T00:00:00Z", // optional, default *
|
||||
"items": [
|
||||
"f44cf173-2344-4eb2-8f00-ee55df32c76f",
|
||||
"2324aa41-e9de-4a2b-bc36-16241464683e",
|
||||
"8542f9da-9ce1-4614-abf4-f2e3fdb4b305",
|
||||
"0fe573e7-042a-4240-a4d9-753b61233908"
|
||||
]
|
||||
}</code></pre>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
11
poetry.lock
generated
11
poetry.lock
generated
@@ -144,6 +144,11 @@ python-versions = "*"
|
||||
falcon = "*"
|
||||
Jinja2 = "*"
|
||||
|
||||
[package.source]
|
||||
url = "https://github.com/alanorth/falcon-swagger-ui.git"
|
||||
reference = "a44244c85dceccfcd249b62fea4ee82a8221e3d2"
|
||||
type = "git"
|
||||
|
||||
[[package]]
|
||||
name = "flake8"
|
||||
version = "3.8.4"
|
||||
@@ -589,7 +594,7 @@ testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pyt
|
||||
[metadata]
|
||||
lock-version = "1.0"
|
||||
python-versions = "^3.6"
|
||||
content-hash = "1d56758c9e3aa4586109e8aaf4def576d3506385bc749b97e8518f936f2e91ca"
|
||||
content-hash = "3a8e8a7152971ae091864e7dd5a8fd25f895f68dd1444bffc153c61227e84914"
|
||||
|
||||
[metadata.files]
|
||||
appdirs = [
|
||||
@@ -655,9 +660,7 @@ falcon = [
|
||||
{file = "falcon-2.0.0-py2.py3-none-any.whl", hash = "sha256:54f2cb4b687035b2a03206dbfc538055cc48b59a953187b0458aa1b574d47b53"},
|
||||
{file = "falcon-2.0.0.tar.gz", hash = "sha256:eea593cf466b9c126ce667f6d30503624ef24459f118c75594a69353b6c3d5fc"},
|
||||
]
|
||||
falcon-swagger-ui = [
|
||||
{file = "falcon_swagger_ui-1.2.1-py3-none-any.whl", hash = "sha256:2514e6cb403e87e49a1527764cf090c82885185cc650b7ab5cefa8ebe89af8b8"},
|
||||
]
|
||||
falcon-swagger-ui = []
|
||||
flake8 = [
|
||||
{file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"},
|
||||
{file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"},
|
||||
|
@@ -1,7 +1,7 @@
|
||||
[tool.poetry]
|
||||
name = "dspace-statistics-api"
|
||||
version = "1.4.0-dev"
|
||||
description = "A simple REST API to expose Solr view and download statistics for items in a DSpace repository."
|
||||
description = "A simple REST API to expose Solr view and download statistics for items, communities, and collections in a DSpace repository."
|
||||
authors = ["Alan Orth <aorth@mjanja.ch>"]
|
||||
license = "GPL-3.0-only"
|
||||
|
||||
@@ -11,7 +11,7 @@ gunicorn = "^20.0.4"
|
||||
falcon = "^2.0.0"
|
||||
psycopg2-binary = "^2.8.6"
|
||||
requests = "^2.24.0"
|
||||
falcon-swagger-ui = "^1.2.1"
|
||||
falcon-swagger-ui = {git = "https://github.com/alanorth/falcon-swagger-ui.git"}
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
ipython = { version = "^7.18.1", python = "^3.7" }
|
||||
|
@@ -11,7 +11,7 @@ colorama==0.4.4; python_version >= "3.7" and python_version < "4.0" and sys_plat
|
||||
dataclasses==0.6; python_version < "3.7"
|
||||
decorator==4.4.2; python_version >= "3.7" and python_version < "4.0"
|
||||
falcon==2.0.0
|
||||
falcon-swagger-ui==1.2.1
|
||||
-e git+https://github.com/alanorth/falcon-swagger-ui.git@a44244c85dceccfcd249b62fea4ee82a8221e3d2#egg=falcon-swagger-ui
|
||||
flake8==3.8.4
|
||||
gunicorn==20.0.4
|
||||
idna==2.10
|
||||
|
@@ -1,7 +1,7 @@
|
||||
certifi==2020.12.5
|
||||
chardet==4.0.0
|
||||
falcon==2.0.0
|
||||
falcon-swagger-ui==1.2.1
|
||||
-e git+https://github.com/alanorth/falcon-swagger-ui.git@a44244c85dceccfcd249b62fea4ee82a8221e3d2#egg=falcon-swagger-ui
|
||||
gunicorn==20.0.4
|
||||
idna==2.10
|
||||
jinja2==2.11.2
|
||||
|
@@ -371,3 +371,6 @@ def test_post_collections_invalid_page(client):
|
||||
response = client.simulate_post("/collections", json=request_body)
|
||||
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
# vim: set sw=4 ts=4 expandtab:
|
||||
|
@@ -371,3 +371,6 @@ def test_post_communities_invalid_page(client):
|
||||
response = client.simulate_post("/communities", json=request_body)
|
||||
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
# vim: set sw=4 ts=4 expandtab:
|
||||
|
@@ -43,3 +43,6 @@ def test_get_status(client):
|
||||
|
||||
assert isinstance(response.content, bytes)
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# vim: set sw=4 ts=4 expandtab:
|
||||
|
@@ -371,3 +371,6 @@ def test_post_items_invalid_page(client):
|
||||
response = client.simulate_post("/items", json=request_body)
|
||||
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
# vim: set sw=4 ts=4 expandtab:
|
||||
|
Reference in New Issue
Block a user