[dd-sso] Add API documentation
The API spec file can be generated with: python -m admin.views.test.test_ApiViews --generate-spec From the admin development environment. A simple testing ground that serves the Swagger UI can also be started with: python -m admin.views.test.test_ApiViewsGON-3874-DD-moodle
parent
10e6afe351
commit
d37b4dfa6a
|
@ -21,6 +21,7 @@ requests = "*"
|
||||||
python-keycloak = "*"
|
python-keycloak = "*"
|
||||||
attrs = "*"
|
attrs = "*"
|
||||||
cryptography = "*"
|
cryptography = "*"
|
||||||
|
flasgger = "*"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
mypy = "*"
|
mypy = "*"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "cd4a56afb09ac033e44f2b8c075a8103f5ee27b31b766508441e34539f654ea1"
|
"sha256": "7ce3de9caf3a9fcc47859dc03ad9e09db96185bd6be89480c7264ce71f6e80ca"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -185,7 +185,7 @@
|
||||||
"sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e",
|
"sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e",
|
||||||
"sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f"
|
"sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.6' and python_version < '4'",
|
"markers": "python_version >= '3.6' and python_version < '4.0'",
|
||||||
"version": "==2.2.1"
|
"version": "==2.2.1"
|
||||||
},
|
},
|
||||||
"ecdsa": {
|
"ecdsa": {
|
||||||
|
@ -204,6 +204,14 @@
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==0.33.2"
|
"version": "==0.33.2"
|
||||||
},
|
},
|
||||||
|
"flasgger": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0603941cf4003626b4ee551ca87331f1d17b8eecce500ccf1a1f1d3a332fc94a",
|
||||||
|
"sha256:6ebea406b5beecd77e8da42550f380d4d05a6107bc90b69ce9e77aee7612e2d0"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.9.5"
|
||||||
|
},
|
||||||
"flask": {
|
"flask": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b",
|
"sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b",
|
||||||
|
@ -310,6 +318,14 @@
|
||||||
"markers": "python_version < '3.10'",
|
"markers": "python_version < '3.10'",
|
||||||
"version": "==5.1.0"
|
"version": "==5.1.0"
|
||||||
},
|
},
|
||||||
|
"importlib-resources": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:32bb095bda29741f6ef0e5278c42df98d135391bee5f932841efc0041f748dc3",
|
||||||
|
"sha256:c09b067d82e72c66f4f8eb12332f5efbebc9b007c0b6c40818108c9870adc363"
|
||||||
|
],
|
||||||
|
"markers": "python_version < '3.9'",
|
||||||
|
"version": "==5.10.1"
|
||||||
|
},
|
||||||
"itsdangerous": {
|
"itsdangerous": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44",
|
"sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44",
|
||||||
|
@ -326,6 +342,14 @@
|
||||||
"markers": "python_version >= '3.7'",
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==3.1.2"
|
"version": "==3.1.2"
|
||||||
},
|
},
|
||||||
|
"jsonschema": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d",
|
||||||
|
"sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==4.17.3"
|
||||||
|
},
|
||||||
"markupsafe": {
|
"markupsafe": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003",
|
"sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003",
|
||||||
|
@ -380,6 +404,13 @@
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==7.1.12"
|
"version": "==7.1.12"
|
||||||
},
|
},
|
||||||
|
"mistune": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:182cc5ee6f8ed1b807de6b7bb50155df7b66495412836b9a74c8fbdfc75fe36d",
|
||||||
|
"sha256:9ee0a66053e2267aba772c71e06891fa8f1af6d4b01d5e84e267b4570d4d9808"
|
||||||
|
],
|
||||||
|
"version": "==2.0.4"
|
||||||
|
},
|
||||||
"mysql-connector-python": {
|
"mysql-connector-python": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:02526f16eacc3961ff681c5c8455d2306a9b45124f2f012ca75a1eac9ceb5165",
|
"sha256:02526f16eacc3961ff681c5c8455d2306a9b45124f2f012ca75a1eac9ceb5165",
|
||||||
|
@ -479,6 +510,14 @@
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==9.3.0"
|
"version": "==9.3.0"
|
||||||
},
|
},
|
||||||
|
"pkgutil-resolve-name": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174",
|
||||||
|
"sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"
|
||||||
|
],
|
||||||
|
"markers": "python_version < '3.9'",
|
||||||
|
"version": "==1.3.10"
|
||||||
|
},
|
||||||
"protobuf": {
|
"protobuf": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:06059eb6953ff01e56a25cd02cca1a9649a75a7e65397b5b9b4e929ed71d10cf",
|
"sha256:06059eb6953ff01e56a25cd02cca1a9649a75a7e65397b5b9b4e929ed71d10cf",
|
||||||
|
@ -553,6 +592,34 @@
|
||||||
],
|
],
|
||||||
"version": "==2.21"
|
"version": "==2.21"
|
||||||
},
|
},
|
||||||
|
"pyrsistent": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:055ab45d5911d7cae397dc418808d8802fb95262751872c841c170b0dbf51eed",
|
||||||
|
"sha256:111156137b2e71f3a9936baf27cb322e8024dac3dc54ec7fb9f0bcf3249e68bb",
|
||||||
|
"sha256:187d5730b0507d9285a96fca9716310d572e5464cadd19f22b63a6976254d77a",
|
||||||
|
"sha256:21455e2b16000440e896ab99e8304617151981ed40c29e9507ef1c2e4314ee95",
|
||||||
|
"sha256:2aede922a488861de0ad00c7630a6e2d57e8023e4be72d9d7147a9fcd2d30712",
|
||||||
|
"sha256:3ba4134a3ff0fc7ad225b6b457d1309f4698108fb6b35532d015dca8f5abed73",
|
||||||
|
"sha256:456cb30ca8bff00596519f2c53e42c245c09e1a4543945703acd4312949bfd41",
|
||||||
|
"sha256:71d332b0320642b3261e9fee47ab9e65872c2bd90260e5d225dabeed93cbd42b",
|
||||||
|
"sha256:879b4c2f4d41585c42df4d7654ddffff1239dc4065bc88b745f0341828b83e78",
|
||||||
|
"sha256:9cd3e9978d12b5d99cbdc727a3022da0430ad007dacf33d0bf554b96427f33ab",
|
||||||
|
"sha256:a178209e2df710e3f142cbd05313ba0c5ebed0a55d78d9945ac7a4e09d923308",
|
||||||
|
"sha256:b39725209e06759217d1ac5fcdb510e98670af9e37223985f330b611f62e7425",
|
||||||
|
"sha256:bfa0351be89c9fcbcb8c9879b826f4353be10f58f8a677efab0c017bf7137ec2",
|
||||||
|
"sha256:bfd880614c6237243ff53a0539f1cb26987a6dc8ac6e66e0c5a40617296a045e",
|
||||||
|
"sha256:c43bec251bbd10e3cb58ced80609c5c1eb238da9ca78b964aea410fb820d00d6",
|
||||||
|
"sha256:d690b18ac4b3e3cab73b0b7aa7dbe65978a172ff94970ff98d82f2031f8971c2",
|
||||||
|
"sha256:d6982b5a0237e1b7d876b60265564648a69b14017f3b5f908c5be2de3f9abb7a",
|
||||||
|
"sha256:dec3eac7549869365fe263831f576c8457f6c833937c68542d08fde73457d291",
|
||||||
|
"sha256:e371b844cec09d8dc424d940e54bba8f67a03ebea20ff7b7b0d56f526c71d584",
|
||||||
|
"sha256:e5d8f84d81e3729c3b506657dddfe46e8ba9c330bf1858ee33108f8bb2adb38a",
|
||||||
|
"sha256:ea6b79a02a28550c98b6ca9c35b9f492beaa54d7c5c9e9949555893c8a9234d0",
|
||||||
|
"sha256:f1258f4e6c42ad0b20f9cfcc3ada5bd6b83374516cd01c0960e3cb75fdca6770"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==0.19.2"
|
||||||
|
},
|
||||||
"python-engineio": {
|
"python-engineio": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:7454314a529bba20e745928601ffeaf101c1b5aca9a6c4e48ad397803d10ea0c",
|
"sha256:7454314a529bba20e745928601ffeaf101c1b5aca9a6c4e48ad397803d10ea0c",
|
||||||
|
@ -651,7 +718,7 @@
|
||||||
"sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7",
|
"sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7",
|
||||||
"sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"
|
"sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.6' and python_version < '4'",
|
"markers": "python_version >= '3.6' and python_version < '4.0'",
|
||||||
"version": "==4.9"
|
"version": "==4.9"
|
||||||
},
|
},
|
||||||
"schema": {
|
"schema": {
|
||||||
|
|
|
@ -23,6 +23,7 @@ Flask==2.1.3
|
||||||
Flask-Login==0.6.2
|
Flask-Login==0.6.2
|
||||||
eventlet==0.33.1
|
eventlet==0.33.1
|
||||||
Flask-SocketIO==5.2.0
|
Flask-SocketIO==5.2.0
|
||||||
|
flasgger==0.9.5
|
||||||
bcrypt==3.2.2
|
bcrypt==3.2.2
|
||||||
# diceware can't be upgraded without issues
|
# diceware can't be upgraded without issues
|
||||||
diceware==0.9.6
|
diceware==0.9.6
|
||||||
|
|
|
@ -21,10 +21,13 @@
|
||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
import logging as log
|
import logging as log
|
||||||
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional
|
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional
|
||||||
|
|
||||||
|
from flasgger import Swagger
|
||||||
|
from flasgger.utils import swag_from
|
||||||
from flask import request
|
from flask import request
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -66,8 +69,34 @@ ERR_412 = (
|
||||||
|
|
||||||
|
|
||||||
def setup_api_views(app: "AdminFlaskApp") -> None:
|
def setup_api_views(app: "AdminFlaskApp") -> None:
|
||||||
|
swagger = Swagger(
|
||||||
|
app,
|
||||||
|
template={
|
||||||
|
"info": {
|
||||||
|
"title": "DD API",
|
||||||
|
"description": "DD API for external integrations",
|
||||||
|
"version": "2022.11.0",
|
||||||
|
"termsOfService": "",
|
||||||
|
},
|
||||||
|
"externalDocs": {
|
||||||
|
"description": "Online Documentation",
|
||||||
|
"url": "https://dd.digitalitzacio-democratica.xnet-x.net/docs/",
|
||||||
|
},
|
||||||
|
"securityDefinitions": {
|
||||||
|
"dd_jwt": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"in": "header",
|
||||||
|
"name": "Authorization",
|
||||||
|
"description": "JWS token using API_SECRET (e.g. 'bearer X.Y')",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": {"dd_jwt": {"$ref": "#/securityDefinitions/dd_jwt"}},
|
||||||
|
"swagger_ui": bool(os.environ.get("SWAGGER_UI", "")),
|
||||||
|
},
|
||||||
|
)
|
||||||
# LISTS
|
# LISTS
|
||||||
@app.json_route("/ddapi/users", methods=["GET"])
|
@app.json_route("/ddapi/users", methods=["GET"], endpoint="api_users")
|
||||||
|
@swag_from("api_docs/users.yml", endpoint="api_users")
|
||||||
@has_token
|
@has_token
|
||||||
def ddapi_users() -> OptionalJsonResponse:
|
def ddapi_users() -> OptionalJsonResponse:
|
||||||
try:
|
try:
|
||||||
|
@ -84,7 +113,10 @@ def setup_api_views(app: "AdminFlaskApp") -> None:
|
||||||
return ERR_500
|
return ERR_500
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@app.json_route("/ddapi/users/filter", methods=["POST"])
|
@app.json_route(
|
||||||
|
"/ddapi/users/filter", methods=["POST"], endpoint="api_users_filter"
|
||||||
|
)
|
||||||
|
@swag_from("api_docs/users_filter.yml", endpoint="api_users_filter")
|
||||||
@has_token
|
@has_token
|
||||||
def ddapi_users_search() -> OptionalJsonResponse:
|
def ddapi_users_search() -> OptionalJsonResponse:
|
||||||
try:
|
try:
|
||||||
|
@ -110,7 +142,8 @@ def setup_api_views(app: "AdminFlaskApp") -> None:
|
||||||
return ERR_500
|
return ERR_500
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@app.json_route("/ddapi/groups", methods=["GET"])
|
@app.json_route("/ddapi/groups", methods=["GET"], endpoint="api_groups")
|
||||||
|
@swag_from("api_docs/groups.yml", endpoint="api_groups")
|
||||||
@has_token
|
@has_token
|
||||||
def ddapi_groups() -> OptionalJsonResponse:
|
def ddapi_groups() -> OptionalJsonResponse:
|
||||||
try:
|
try:
|
||||||
|
@ -127,7 +160,8 @@ def setup_api_views(app: "AdminFlaskApp") -> None:
|
||||||
return ERR_500
|
return ERR_500
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@app.json_route("/ddapi/roles", methods=["GET"])
|
@app.json_route("/ddapi/roles", methods=["GET"], endpoint="api_roles")
|
||||||
|
@swag_from("api_docs/roles.yml", endpoint="api_roles")
|
||||||
@has_token
|
@has_token
|
||||||
def ddapi_roles() -> OptionalJsonResponse:
|
def ddapi_roles() -> OptionalJsonResponse:
|
||||||
try:
|
try:
|
||||||
|
@ -141,7 +175,8 @@ def setup_api_views(app: "AdminFlaskApp") -> None:
|
||||||
return ERR_500
|
return ERR_500
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@app.json_route("/ddapi/role/users", methods=["POST"])
|
@app.json_route("/ddapi/role/users", methods=["POST"], endpoint="api_role_users")
|
||||||
|
@swag_from("api_docs/role_users.yml", endpoint="api_role_users")
|
||||||
@has_token
|
@has_token
|
||||||
def ddapi_role_users() -> OptionalJsonResponse:
|
def ddapi_role_users() -> OptionalJsonResponse:
|
||||||
try:
|
try:
|
||||||
|
@ -174,8 +209,16 @@ def setup_api_views(app: "AdminFlaskApp") -> None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# INDIVIDUAL ACTIONS
|
# INDIVIDUAL ACTIONS
|
||||||
@app.json_route("/ddapi/user", methods=["POST"])
|
@app.json_route("/ddapi/user", methods=["POST"], endpoint="api_user_new")
|
||||||
@app.json_route("/ddapi/user/<user_ddid>", methods=["PUT", "GET", "DELETE"])
|
@app.json_route(
|
||||||
|
"/ddapi/user/<user_ddid>",
|
||||||
|
methods=["PUT", "GET", "DELETE"],
|
||||||
|
endpoint="api_user_ddid",
|
||||||
|
)
|
||||||
|
@swag_from("api_docs/user_new.yml", endpoint="api_user_new")
|
||||||
|
@swag_from("api_docs/user_get.yml", endpoint="api_user_ddid", methods=["GET"])
|
||||||
|
@swag_from("api_docs/user_put.yml", endpoint="api_user_ddid", methods=["PUT"])
|
||||||
|
@swag_from("api_docs/user_delete.yml", endpoint="api_user_ddid", methods=["DELETE"])
|
||||||
@has_token
|
@has_token
|
||||||
def ddapi_user(user_ddid: Optional[str] = None) -> OptionalJsonResponse:
|
def ddapi_user(user_ddid: Optional[str] = None) -> OptionalJsonResponse:
|
||||||
try:
|
try:
|
||||||
|
@ -284,8 +327,18 @@ def setup_api_views(app: "AdminFlaskApp") -> None:
|
||||||
log.error(traceback.format_exc())
|
log.error(traceback.format_exc())
|
||||||
return ERR_500
|
return ERR_500
|
||||||
|
|
||||||
@app.json_route("/ddapi/group", methods=["POST"])
|
@app.json_route("/ddapi/group", methods=["POST"], endpoint="api_group_new")
|
||||||
@app.json_route("/ddapi/group/<group_id>", methods=["GET", "POST", "DELETE"])
|
@app.json_route(
|
||||||
|
"/ddapi/group/<group_id>",
|
||||||
|
methods=["GET", "POST", "DELETE"],
|
||||||
|
endpoint="api_group_group_id",
|
||||||
|
)
|
||||||
|
@swag_from("api_docs/group_new.yml", endpoint="api_group_new")
|
||||||
|
@swag_from("api_docs/group_get.yml", endpoint="api_group_group_id", methods=["GET"])
|
||||||
|
# @swag_from('api_docs/group_put.yml', endpoint='api_group_group_id', methods=["PUT"])
|
||||||
|
@swag_from(
|
||||||
|
"api_docs/group_delete.yml", endpoint="api_group_group_id", methods=["DELETE"]
|
||||||
|
)
|
||||||
# @app.json_route("/api/group/<group_id>", methods=["PUT", "GET", "DELETE"])
|
# @app.json_route("/api/group/<group_id>", methods=["PUT", "GET", "DELETE"])
|
||||||
@has_token
|
@has_token
|
||||||
def ddapi_group(group_id: Optional[str] = None) -> OptionalJsonResponse:
|
def ddapi_group(group_id: Optional[str] = None) -> OptionalJsonResponse:
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
Delete a registered group in DD
|
||||||
|
---
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- in: url
|
||||||
|
name: group_id
|
||||||
|
description: |
|
||||||
|
The group to delete from DD
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
404:
|
||||||
|
description: |
|
||||||
|
The group does not exist
|
|
@ -0,0 +1,20 @@
|
||||||
|
Get a registered group in DD
|
||||||
|
---
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- in: url
|
||||||
|
name: group_id
|
||||||
|
description: |
|
||||||
|
The group to retrieve from DD
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: |
|
||||||
|
The group as it exists on DD
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Group'
|
||||||
|
404:
|
||||||
|
description: |
|
||||||
|
The group does not exist
|
|
@ -0,0 +1,30 @@
|
||||||
|
Register a new group in DD
|
||||||
|
---
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: group
|
||||||
|
description: |
|
||||||
|
The group to be registered on DD.
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
required: True
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
required: False
|
||||||
|
type: string
|
||||||
|
parent:
|
||||||
|
required: False
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: |
|
||||||
|
The keycloak_id of the newly registered group
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/KeycloakId'
|
||||||
|
409:
|
||||||
|
description: |
|
||||||
|
The group already exists
|
|
@ -0,0 +1,34 @@
|
||||||
|
List all registered groups on DD.
|
||||||
|
---
|
||||||
|
definitions:
|
||||||
|
Group:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
keycloak_id:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
path:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
Groups:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/Group'
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The list of groups registered on DD
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Groups'
|
||||||
|
examples: |
|
||||||
|
[{
|
||||||
|
"keycloak_id": "f6ec2bda-bec9-415f-bcb7-f5ae644bfec5",
|
||||||
|
"id": "ID",
|
||||||
|
"name": "NAME",
|
||||||
|
"path": "PATH",
|
||||||
|
"description": "DESCRIPITON",
|
||||||
|
}]
|
|
@ -0,0 +1,31 @@
|
||||||
|
List registered users on DD with a the given role.
|
||||||
|
---
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: role
|
||||||
|
description: |
|
||||||
|
The role to search users registered on DD.
|
||||||
|
One of 'id', 'name' and 'keycloak_id' must be provided.
|
||||||
|
This is also the order in which the parameters are checked,
|
||||||
|
in case multiple are provided.
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
required: False
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
required: False
|
||||||
|
keycloak_id:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
required: False
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: |
|
||||||
|
The list of users registered on DD with the filter applied.
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Users'
|
|
@ -0,0 +1,31 @@
|
||||||
|
List all roles configured on DD.
|
||||||
|
---
|
||||||
|
definitions:
|
||||||
|
Role:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
keycloak_id:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
Roles:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/Role'
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The list of roles configured on DD
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Roles'
|
||||||
|
examples: |
|
||||||
|
[{
|
||||||
|
"keycloak_id": "f6ec2bda-bec9-415f-bcb7-f5ae644bfec5",
|
||||||
|
"id": "ID",
|
||||||
|
"name": "NAME",
|
||||||
|
"description": "DESCRIPITON",
|
||||||
|
}]
|
|
@ -0,0 +1,18 @@
|
||||||
|
Delete a registered user in DD
|
||||||
|
---
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- in: url
|
||||||
|
name: user_ddid
|
||||||
|
description: |
|
||||||
|
The user to delete from DD
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
404:
|
||||||
|
description: |
|
||||||
|
The user does not exist
|
|
@ -0,0 +1,20 @@
|
||||||
|
Get a registered user in DD
|
||||||
|
---
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- in: url
|
||||||
|
name: user_ddid
|
||||||
|
description: |
|
||||||
|
The user to retrieve from DD
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: |
|
||||||
|
The user as it exists on DD
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/User'
|
||||||
|
404:
|
||||||
|
description: |
|
||||||
|
The user does not exist
|
|
@ -0,0 +1,63 @@
|
||||||
|
Register a new user in DD
|
||||||
|
---
|
||||||
|
definitions:
|
||||||
|
KeycloakId:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
keycloak_id:
|
||||||
|
required: True
|
||||||
|
type: string
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: user
|
||||||
|
description: |
|
||||||
|
The user to be registered on DD.
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
required: True
|
||||||
|
type: string
|
||||||
|
first:
|
||||||
|
required: True
|
||||||
|
type: string
|
||||||
|
last:
|
||||||
|
required: True
|
||||||
|
type: string
|
||||||
|
email:
|
||||||
|
required: True
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
password:
|
||||||
|
required: True
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
password_temporary:
|
||||||
|
required: False
|
||||||
|
type: bool
|
||||||
|
quota:
|
||||||
|
required: True
|
||||||
|
type: string
|
||||||
|
enabled:
|
||||||
|
required: True
|
||||||
|
type: bool
|
||||||
|
role:
|
||||||
|
required: True
|
||||||
|
groups:
|
||||||
|
required: True
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: |
|
||||||
|
The keycloak_id of the newly registered user
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/KeycloakId'
|
||||||
|
examples: |
|
||||||
|
{ "keycloak_id": "f6ec2bda-bec9-415f-bcb7-f5ae644bfec5" }
|
||||||
|
409:
|
||||||
|
description: |
|
||||||
|
The user already exists
|
|
@ -0,0 +1,49 @@
|
||||||
|
Modify a user in DD
|
||||||
|
---
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: user
|
||||||
|
description: |
|
||||||
|
The user to be modified on DD.
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
first:
|
||||||
|
required: False
|
||||||
|
type: string
|
||||||
|
last:
|
||||||
|
required: False
|
||||||
|
type: string
|
||||||
|
email:
|
||||||
|
required: False
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
password:
|
||||||
|
required: False
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
password_temporary:
|
||||||
|
required: False
|
||||||
|
type: bool
|
||||||
|
quota:
|
||||||
|
required: False
|
||||||
|
type: string
|
||||||
|
enabled:
|
||||||
|
required: False
|
||||||
|
type: bool
|
||||||
|
role:
|
||||||
|
required: False
|
||||||
|
groups:
|
||||||
|
required: False
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
404:
|
||||||
|
description: |
|
||||||
|
The user does not exist
|
|
@ -0,0 +1,58 @@
|
||||||
|
List all registered users on DD.
|
||||||
|
---
|
||||||
|
definitions:
|
||||||
|
User:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
keycloak_id:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
enabled:
|
||||||
|
type: boolean
|
||||||
|
first:
|
||||||
|
type: string
|
||||||
|
last:
|
||||||
|
type: string
|
||||||
|
role:
|
||||||
|
type: string
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
fomat: email
|
||||||
|
groups:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
quota:
|
||||||
|
type: string
|
||||||
|
quota_used_bytes:
|
||||||
|
type: string
|
||||||
|
Users:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/User'
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The list of users registered on DD
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Users'
|
||||||
|
examples: |
|
||||||
|
[{
|
||||||
|
"keycloak_id": "a773d249-a113-4542-8101-3a50f4cd28c2",
|
||||||
|
"id": "ID",
|
||||||
|
"username": "ID",
|
||||||
|
"enabled": true,
|
||||||
|
"first": "NAME",
|
||||||
|
"last": "LASTNAME",
|
||||||
|
"role": "student",
|
||||||
|
"email": "ID@DOMAIN",
|
||||||
|
"groups": [
|
||||||
|
"GRUP",
|
||||||
|
"student"
|
||||||
|
],
|
||||||
|
"quota": "500 MB",
|
||||||
|
"quota_used_bytes": "0 MB"
|
||||||
|
}]
|
|
@ -0,0 +1,21 @@
|
||||||
|
List registered users on DD with a filter applied.
|
||||||
|
---
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: filter
|
||||||
|
description: The filter to apply to users registered on DD
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- filter
|
||||||
|
properties:
|
||||||
|
text:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: |
|
||||||
|
The list of users registered on DD with the filter applied.
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Users'
|
|
@ -553,3 +553,27 @@ class ApiViewsTests(flask_unittest.ClientTestCase):
|
||||||
# rv = self._r(client, "/ddapi/role/users", method="POST")
|
# rv = self._r(client, "/ddapi/role/users", method="POST")
|
||||||
# print(rv)
|
# print(rv)
|
||||||
# print(rv.json)
|
# print(rv.json)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if "DOMAIN" not in os.environ:
|
||||||
|
os.environ["DOMAIN"] = "localhost"
|
||||||
|
os.environ["SWAGGER_UI"] = "TRUE"
|
||||||
|
app = _testApp()
|
||||||
|
if "--generate-spec" in sys.argv:
|
||||||
|
with app.app_context():
|
||||||
|
ep = app.swag.config["specs"][0]["endpoint"]
|
||||||
|
spec = app.swag.get_apispecs(ep)
|
||||||
|
import json
|
||||||
|
|
||||||
|
print(json.dumps(spec, indent=4))
|
||||||
|
else:
|
||||||
|
# Start a simple testing server
|
||||||
|
app.socketio.run(
|
||||||
|
app,
|
||||||
|
host=os.environ.get("ADMIN_LISTEN_ADDESS", "::"),
|
||||||
|
port=int(os.environ.get("ADMIN_LISTEN_PORT", "9000")),
|
||||||
|
debug=True,
|
||||||
|
)
|
||||||
|
|
|
@ -77,3 +77,8 @@ Un cop fet això, a la interfície d'administració de Keycloak haurem de triar
|
||||||
> **Nota:** el directori dd-custom no s'actualitzarà mai, és responsabilitat
|
> **Nota:** el directori dd-custom no s'actualitzarà mai, és responsabilitat
|
||||||
> vostra revisar els canvis al tema `dd` i al directori `dd-custom.sample`
|
> vostra revisar els canvis al tema `dd` i al directori `dd-custom.sample`
|
||||||
> per tal de mantenir la compatibilitat amb els vostres canvis.
|
> per tal de mantenir la compatibilitat amb els vostres canvis.
|
||||||
|
|
||||||
|
## Integració amb altres eines
|
||||||
|
|
||||||
|
És possible integrar el DD amb altres eines, vegeu la secció
|
||||||
|
d'[integracions](integrations.ca.md).
|
||||||
|
|
|
@ -0,0 +1,554 @@
|
||||||
|
{
|
||||||
|
"info": {
|
||||||
|
"title": "DD API",
|
||||||
|
"description": "DD API for external integrations",
|
||||||
|
"version": "2022.11.0",
|
||||||
|
"termsOfService": ""
|
||||||
|
},
|
||||||
|
"paths": {
|
||||||
|
"/ddapi/users": {
|
||||||
|
"get": {
|
||||||
|
"summary": "List all registered users on DD.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The list of users registered on DD",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Users"
|
||||||
|
},
|
||||||
|
"examples": "[{\n \"keycloak_id\": \"a773d249-a113-4542-8101-3a50f4cd28c2\",\n \"id\": \"ID\",\n \"username\": \"ID\",\n \"enabled\": true,\n \"first\": \"NAME\",\n \"last\": \"LASTNAME\",\n \"role\": \"student\",\n \"email\": \"ID@DOMAIN\",\n \"groups\": [\n \"GRUP\",\n \"student\"\n ],\n \"quota\": \"500 MB\",\n \"quota_used_bytes\": \"0 MB\"\n}]\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/ddapi/users/filter": {
|
||||||
|
"post": {
|
||||||
|
"summary": "List registered users on DD with a filter applied.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The list of users registered on DD with the filter applied.\n",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Users"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "body",
|
||||||
|
"name": "filter",
|
||||||
|
"description": "The filter to apply to users registered on DD",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"filter"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"text": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/ddapi/groups": {
|
||||||
|
"get": {
|
||||||
|
"summary": "List all registered groups on DD.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The list of groups registered on DD",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Groups"
|
||||||
|
},
|
||||||
|
"examples": "[{\n \"keycloak_id\": \"f6ec2bda-bec9-415f-bcb7-f5ae644bfec5\",\n \"id\": \"ID\",\n \"name\": \"NAME\",\n \"path\": \"PATH\",\n \"description\": \"DESCRIPITON\",\n}]\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/ddapi/roles": {
|
||||||
|
"get": {
|
||||||
|
"summary": "List all roles configured on DD.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The list of roles configured on DD",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Roles"
|
||||||
|
},
|
||||||
|
"examples": "[{\n \"keycloak_id\": \"f6ec2bda-bec9-415f-bcb7-f5ae644bfec5\",\n \"id\": \"ID\",\n \"name\": \"NAME\",\n \"description\": \"DESCRIPITON\",\n}]\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/ddapi/role/users": {
|
||||||
|
"post": {
|
||||||
|
"summary": "List registered users on DD with a the given role.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The list of users registered on DD with the filter applied.\n",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Users"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "body",
|
||||||
|
"name": "role",
|
||||||
|
"description": "The role to search users registered on DD.\nOne of 'id', 'name' and 'keycloak_id' must be provided.\nThis is also the order in which the parameters are checked,\nin case multiple are provided.\n",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"keycloak_id": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uuid",
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/ddapi/user/{user_ddid}": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Get a registered user in DD",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The user as it exists on DD\n",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "The user does not exist\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "url",
|
||||||
|
"name": "user_ddid",
|
||||||
|
"description": "The user to retrieve from DD\n",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"summary": "Delete a registered user in DD",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "The user does not exist\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "url",
|
||||||
|
"name": "user_ddid",
|
||||||
|
"description": "The user to delete from DD\n",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"summary": "Modify a user in DD",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "The user does not exist\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "body",
|
||||||
|
"name": "user",
|
||||||
|
"description": "The user to be modified on DD.\n",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"first": {
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"last": {
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"required": false,
|
||||||
|
"type": "string",
|
||||||
|
"format": "email"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"required": false,
|
||||||
|
"type": "string",
|
||||||
|
"format": "email"
|
||||||
|
},
|
||||||
|
"password_temporary": {
|
||||||
|
"required": false,
|
||||||
|
"type": "bool"
|
||||||
|
},
|
||||||
|
"quota": {
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"required": false,
|
||||||
|
"type": "bool"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"groups": {
|
||||||
|
"required": false,
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/ddapi/user": {
|
||||||
|
"post": {
|
||||||
|
"summary": "Register a new user in DD",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The keycloak_id of the newly registered user\n",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/KeycloakId"
|
||||||
|
},
|
||||||
|
"examples": "{ \"keycloak_id\": \"f6ec2bda-bec9-415f-bcb7-f5ae644bfec5\" }\n"
|
||||||
|
},
|
||||||
|
"409": {
|
||||||
|
"description": "The user already exists\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "body",
|
||||||
|
"name": "user",
|
||||||
|
"description": "The user to be registered on DD.\n",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"username": {
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"first": {
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"last": {
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"format": "email"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"format": "email"
|
||||||
|
},
|
||||||
|
"password_temporary": {
|
||||||
|
"required": false,
|
||||||
|
"type": "bool"
|
||||||
|
},
|
||||||
|
"quota": {
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"required": true,
|
||||||
|
"type": "bool"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"groups": {
|
||||||
|
"required": true,
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/ddapi/group/{group_id}": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Get a registered group in DD",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The group as it exists on DD\n",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Group"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "The group does not exist\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "url",
|
||||||
|
"name": "group_id",
|
||||||
|
"description": "The group to retrieve from DD\n",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"summary": "Delete a registered group in DD",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "The group does not exist\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "url",
|
||||||
|
"name": "group_id",
|
||||||
|
"description": "The group to delete from DD\n",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/ddapi/group": {
|
||||||
|
"post": {
|
||||||
|
"summary": "Register a new group in DD",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The keycloak_id of the newly registered group\n",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/KeycloakId"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"409": {
|
||||||
|
"description": "The group already exists\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "body",
|
||||||
|
"name": "group",
|
||||||
|
"description": "The group to be registered on DD.\n",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"parent": {
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"User": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"keycloak_id": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uuid"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"first": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"last": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string",
|
||||||
|
"fomat": "email"
|
||||||
|
},
|
||||||
|
"groups": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"quota": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"quota_used_bytes": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Users": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Group": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"keycloak_id": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uuid"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Groups": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/Group"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Role": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"keycloak_id": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uuid"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Roles": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/Role"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"KeycloakId": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"keycloak_id": {
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"swagger": "2.0",
|
||||||
|
"externalDocs": {
|
||||||
|
"description": "Online Documentation",
|
||||||
|
"url": "https://dd.digitalitzacio-democratica.xnet-x.net/docs/"
|
||||||
|
},
|
||||||
|
"securityDefinitions": {
|
||||||
|
"dd_jwt": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"in": "header",
|
||||||
|
"name": "Authorization",
|
||||||
|
"description": "JWS token using API_SECRET (e.g. 'bearer X.Y')"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"dd_jwt": {
|
||||||
|
"$ref": "#/securityDefinitions/dd_jwt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"swagger_ui": true
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
# Integracions
|
||||||
|
|
||||||
|
El DD es pot integrar amb altres sistemes a través de les seves APIs.
|
||||||
|
|
||||||
|
## Autenticació
|
||||||
|
|
||||||
|
Totes les peticions han d'estar autenticades amb un [Json Web Token (JWT)][jwt],
|
||||||
|
que estigui signat per l'`API_SECRET` (present al fitxer `dd.conf`).
|
||||||
|
|
||||||
|
Aquesta autenticació es fa mitjançant la capcelera HTTP `Authentication`.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Vegeu-ne els detalls</summary>
|
||||||
|
```sh
|
||||||
|
> curl -H "Authorization: bearer ${jwt}" https://admin.DOMAIN/ddapi/roles
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"keycloak_id": "9325ad99-7e04-4c31-9768-5512e1564160",
|
||||||
|
"id": "admin",
|
||||||
|
"name": "admin",
|
||||||
|
"description": "${role_admin}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keycloak_id": "c6c8a73e-51fc-4716-831d-1dfc0e0b62b0",
|
||||||
|
"id": "manager",
|
||||||
|
"name": "manager",
|
||||||
|
"description": "Realm managers"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keycloak_id": "24d7977e-da83-4591-8e13-0fac3126afa1",
|
||||||
|
"id": "student",
|
||||||
|
"name": "student",
|
||||||
|
"description": "Realm students"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keycloak_id": "d6699c41-13d5-4623-bdca-e5f2775474ed",
|
||||||
|
"id": "teacher",
|
||||||
|
"name": "teacher",
|
||||||
|
"description": "Realm teachers"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
On el <code>JWT</code> es pot generar, per exemple fent servir <code>python-jose</code>, de la
|
||||||
|
següent manera:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import os
|
||||||
|
from jose import jws
|
||||||
|
t = jws.sign({}, os.environ["API_SECRET"], algorithm="HS256")
|
||||||
|
print(t)
|
||||||
|
```
|
||||||
|
|
||||||
|
Altres llenguatges de programació i llibreries tindran una manera anàloga de
|
||||||
|
generar aquests tokens.
|
||||||
|
</details>
|
||||||
|
|
||||||
|
[jwt]: https://jwt.io/
|
||||||
|
[jose]: https://python-jose.readthedocs.io/
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
!!swagger ddapi.json!!
|
|
@ -42,6 +42,7 @@ markdown_extensions:
|
||||||
plugins:
|
plugins:
|
||||||
- search
|
- search
|
||||||
#- enumerate-headings
|
#- enumerate-headings
|
||||||
|
- render_swagger
|
||||||
- i18n:
|
- i18n:
|
||||||
languages:
|
languages:
|
||||||
ca: "Català"
|
ca: "Català"
|
||||||
|
|
Loading…
Reference in New Issue