diff --git a/.dockerignore b/.dockerignore
index 6c32d9cb..46846562 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -9,9 +9,7 @@ db/
LICENSE
README.md
Dockerfile
-Dockerfile.dev
Makefile
docker-compose.yml
-docker-compose.dev.yml
CHANGELOG.md
diff --git a/.env.example b/.env.example
index 311a47a3..d8cfaf77 100644
--- a/.env.example
+++ b/.env.example
@@ -2,14 +2,14 @@
THOTH_GRAPHQL_API=http://localhost:8000
# THOTH_EXPORT_API is used at compile time, must be a public facing URL
THOTH_EXPORT_API=http://localhost:8181
-# Authentication cookie domain
-THOTH_DOMAIN=localhost
# Full postgres URL
DATABASE_URL=postgres://thoth:thoth@localhost/thoth
# Full redis URL
REDIS_URL=redis://localhost:6379
-# Authentication cookie secret key
-SECRET_KEY=an_up_to_255_bytes_random_key
+# AWS credentials for file uploads
+AWS_ACCESS_KEY_ID=
+AWS_SECRET_ACCESS_KEY=
+AWS_REGION=
# Logging level
RUST_LOG=info
diff --git a/.github/workflows/build_test_and_check.yml b/.github/workflows/build_test_and_check.yml
index 4aa9cbf3..9315d7e4 100644
--- a/.github/workflows/build_test_and_check.yml
+++ b/.github/workflows/build_test_and_check.yml
@@ -25,8 +25,8 @@ on:
env:
CARGO_TERM_COLOR: always
- THOTH_GRAPHQL_API: https://api.thoth.pub
THOTH_EXPORT_API: https://export.thoth.pub
+ TEST_DATABASE_URL: postgres://thoth:thoth@localhost:5432/thoth_test
TEST_REDIS_URL: redis://localhost:6379
jobs:
@@ -48,6 +48,19 @@ jobs:
test:
runs-on: ubuntu-latest
services:
+ postgres:
+ image: postgres:17
+ env:
+ POSTGRES_DB: thoth_test
+ POSTGRES_USER: thoth
+ POSTGRES_PASSWORD: thoth
+ ports:
+ - 5432:5432
+ options: >-
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
redis:
image: redis:alpine
options: >-
diff --git a/.github/workflows/docker_build_and_push_to_dockerhub.yml b/.github/workflows/docker_build_and_push_to_dockerhub.yml
index 2899e54a..d6b12a5d 100644
--- a/.github/workflows/docker_build_and_push_to_dockerhub.yml
+++ b/.github/workflows/docker_build_and_push_to_dockerhub.yml
@@ -41,27 +41,6 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
- THOTH_GRAPHQL_API=https://api.test.thoth.pub
THOTH_EXPORT_API=https://export.test.thoth.pub
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}
-
- build_dev_docker_image:
- runs-on: ubuntu-latest
- steps:
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v3
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
- - name: Build
- id: docker_build
- uses: docker/build-push-action@v5
- with:
- push: false
- tags: thoth-pub/thoth:latest
- file: Dockerfile.dev
- build-args: |
- THOTH_GRAPHQL_API=https://api.thoth.pub
- THOTH_EXPORT_API=https://export.thoth.pub
- - name: Image digest
- run: echo ${{ steps.docker_build.outputs.digest }}
diff --git a/.github/workflows/docker_build_and_push_to_dockerhub_release.yml b/.github/workflows/docker_build_and_push_to_dockerhub_release.yml
index ad848fd0..beedc5f2 100644
--- a/.github/workflows/docker_build_and_push_to_dockerhub_release.yml
+++ b/.github/workflows/docker_build_and_push_to_dockerhub_release.yml
@@ -43,7 +43,6 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
- THOTH_GRAPHQL_API=https://api.thoth.pub
THOTH_EXPORT_API=https://export.thoth.pub
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}
diff --git a/.gitignore b/.gitignore
index c4534ef2..05c6b644 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
.env
db/
target/
+machinekey/
+coverage/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aab00a3d..4797a339 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,10 +5,31 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
+### Changed
+ - [697](https://github.com/thoth-pub/thoth/pull/697) - Migrated GraphQL API authentication to OIDC via Zitadel. Internal JWT handling has been replaced with introspection of Zitadel-issued tokens. Authorisation is now based entirely on token claims, removing the need for the internal `account` and `publisher_account` tables.
+ - [697](https://github.com/thoth-pub/thoth/pull/697) - Improved and standardised backend model test coverage.
+ - [689](https://github.com/thoth-pub/thoth/issues/689) - Move `Work.fullTitle`, `Work.title` and `Work.subtitle` into a dedicated `Title` table, supporting multilingual and rich text fields
+ - [689](https://github.com/thoth-pub/thoth/issues/689) - Move `Work.shortAbstract` and `Work.longAbstract` into a dedicated `Abstract` table with `abstractType`, supporting multilingual and rich text fields
+ - [689](https://github.com/thoth-pub/thoth/issues/689) - Move `Contribution.biography` into a dedicated `Biography` table, supporting multilingual and rich text fields
+ - [689](https://github.com/thoth-pub/thoth/issues/689) - Store all rich text fields internally as JATS XML, supporting conversion to/from HTML, Markdown, and plain text
+ - [689](https://github.com/thoth-pub/thoth/issues/689) - Mark existing GraphQL fields as deprecated and return only the canonical version
+ - [701](https://github.com/thoth-pub/thoth/issues/701) - Add accessibility-related metadata to Thoth data model and outputs
+ - [682](https://github.com/thoth-pub/thoth/issues/682) - Improve ONIX 3.0 and 3.1 outputs based on feedback from EDItEUR
+
+### Added
+ - [711](https://github.com/thoth-pub/thoth/pull/711) - Allow filtering work queries by publication date
+ - [715](https://github.com/thoth-pub/thoth/pull/715) - Support reordering items which have ordinals
+ - [713](https://github.com/thoth-pub/thoth/issues/713) - Add a secure and scalable file upload architecture for books and chapters.
+
+### Fixed
+ - [712](https://github.com/thoth-pub/thoth/pull/712) - Make `updated_at_with_relations` propagation less deadlock-prone
+
+### Removed
+ - [710](https://github.com/thoth-pub/thoth/pull/710) - Deprecated thoth-app
## [[0.13.15]](https://github.com/thoth-pub/thoth/releases/tag/v0.13.15) - 2025-12-03
### Changed
- - [#717](https://github.com/thoth-pub/thoth/pull/717) - Update Thema codes to v1.6
+- [#717](https://github.com/thoth-pub/thoth/pull/717) - Update Thema codes to v1.6
## [[0.13.14]](https://github.com/thoth-pub/thoth/releases/tag/v0.13.14) - 2025-10-14
### Changed
diff --git a/Cargo.lock b/Cargo.lock
index cb906b79..871b2cca 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -8,7 +8,7 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.10.0",
"bytes",
"futures-core",
"futures-sink",
@@ -27,7 +27,7 @@ checksum = "daa239b93927be1ff123eebada5a3ff23e89f0124ccb8609234e5103d5a5ae6d"
dependencies = [
"actix-utils",
"actix-web",
- "derive_more 2.0.1",
+ "derive_more 2.1.0",
"futures-util",
"log",
"once_cell",
@@ -36,25 +36,25 @@ dependencies = [
[[package]]
name = "actix-http"
-version = "3.10.0"
+version = "3.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa882656b67966045e4152c634051e70346939fced7117d5f0b52146a7c74c9"
+checksum = "7926860314cbe2fb5d1f13731e387ab43bd32bca224e82e6e2db85de0a3dba49"
dependencies = [
"actix-codec",
"actix-rt",
"actix-service",
"actix-utils",
"base64 0.22.1",
- "bitflags 2.9.0",
+ "bitflags 2.10.0",
"brotli",
"bytes",
"bytestring",
- "derive_more 2.0.1",
+ "derive_more 2.1.0",
"encoding_rs",
"flate2",
- "foldhash",
+ "foldhash 0.1.5",
"futures-core",
- "h2 0.3.26",
+ "h2 0.3.27",
"http 0.2.12",
"httparse",
"httpdate",
@@ -64,7 +64,7 @@ dependencies = [
"mime",
"percent-encoding",
"pin-project-lite",
- "rand 0.9.0",
+ "rand 0.9.2",
"sha1",
"smallvec",
"tokio",
@@ -73,22 +73,6 @@ dependencies = [
"zstd",
]
-[[package]]
-name = "actix-identity"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23b8ddc6f6a8b19c4016aaa13519968da9969bc3bc1c1c883cdb0f25dd6c8cf7"
-dependencies = [
- "actix-service",
- "actix-session",
- "actix-utils",
- "actix-web",
- "derive_more 1.0.0",
- "futures-core",
- "serde",
- "tracing",
-]
-
[[package]]
name = "actix-macros"
version = "0.2.4"
@@ -96,7 +80,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
dependencies = [
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
@@ -116,9 +100,9 @@ dependencies = [
[[package]]
name = "actix-rt"
-version = "2.10.0"
+version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208"
+checksum = "92589714878ca59a7626ea19734f0e07a6a875197eec751bb5d3f99e64998c63"
dependencies = [
"futures-core",
"tokio",
@@ -126,9 +110,9 @@ dependencies = [
[[package]]
name = "actix-server"
-version = "2.5.1"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6398974fd4284f4768af07965701efbbb5fdc0616bff20cade1bb14b77675e24"
+checksum = "a65064ea4a457eaf07f2fba30b4c695bf43b721790e9530d26cb6f9019ff7502"
dependencies = [
"actix-rt",
"actix-service",
@@ -136,7 +120,7 @@ dependencies = [
"futures-core",
"futures-util",
"mio",
- "socket2",
+ "socket2 0.5.10",
"tokio",
"tracing",
]
@@ -151,23 +135,6 @@ dependencies = [
"pin-project-lite",
]
-[[package]]
-name = "actix-session"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efe6976a74f34f1b6d07a6c05aadc0ed0359304a7781c367fa5b4029418db08f"
-dependencies = [
- "actix-service",
- "actix-utils",
- "actix-web",
- "anyhow",
- "derive_more 1.0.0",
- "rand 0.8.5",
- "serde",
- "serde_json",
- "tracing",
-]
-
[[package]]
name = "actix-utils"
version = "3.0.1"
@@ -180,9 +147,9 @@ dependencies = [
[[package]]
name = "actix-web"
-version = "4.10.2"
+version = "4.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2e3b15b3dc6c6ed996e4032389e9849d4ab002b1e92fbfe85b5f307d1479b4d"
+checksum = "1654a77ba142e37f049637a3e5685f864514af11fcbc51cb51eb6596afe5b8d6"
dependencies = [
"actix-codec",
"actix-http",
@@ -197,9 +164,9 @@ dependencies = [
"bytestring",
"cfg-if",
"cookie",
- "derive_more 2.0.1",
+ "derive_more 2.1.0",
"encoding_rs",
- "foldhash",
+ "foldhash 0.1.5",
"futures-core",
"futures-util",
"impl-more",
@@ -215,7 +182,7 @@ dependencies = [
"serde_json",
"serde_urlencoded",
"smallvec",
- "socket2",
+ "socket2 0.6.1",
"time",
"tracing",
"url",
@@ -230,64 +197,33 @@ dependencies = [
"actix-router",
"proc-macro2",
"quote",
- "syn 2.0.100",
-]
-
-[[package]]
-name = "addr2line"
-version = "0.24.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
-dependencies = [
- "gimli",
+ "syn 2.0.111",
]
[[package]]
name = "adler2"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
-
-[[package]]
-name = "aead"
-version = "0.5.2"
+version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
-dependencies = [
- "crypto-common",
- "generic-array",
-]
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
-name = "aes"
-version = "0.8.4"
+name = "ahash"
+version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
+checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
dependencies = [
"cfg-if",
- "cipher",
- "cpufeatures",
-]
-
-[[package]]
-name = "aes-gcm"
-version = "0.10.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
-dependencies = [
- "aead",
- "aes",
- "cipher",
- "ctr",
- "ghash",
- "subtle",
+ "getrandom 0.3.4",
+ "once_cell",
+ "version_check",
+ "zerocopy",
]
[[package]]
name = "aho-corasick"
-version = "1.1.3"
+version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
@@ -308,10 +244,10 @@ dependencies = [
]
[[package]]
-name = "android-tzdata"
-version = "0.1.1"
+name = "allocator-api2"
+version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "android_system_properties"
@@ -324,9 +260,9 @@ dependencies = [
[[package]]
name = "anstream"
-version = "0.6.18"
+version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -339,56 +275,44 @@ dependencies = [
[[package]]
name = "anstyle"
-version = "1.0.10"
+version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
[[package]]
name = "anstyle-parse"
-version = "0.2.6"
+version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
-version = "1.1.2"
+version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
- "windows-sys 0.59.0",
+ "windows-sys 0.61.2",
]
[[package]]
name = "anstyle-wincon"
-version = "3.0.7"
+version = "3.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
- "once_cell",
- "windows-sys 0.59.0",
+ "once_cell_polyfill",
+ "windows-sys 0.61.2",
]
[[package]]
name = "anyhow"
-version = "1.0.97"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
-
-[[package]]
-name = "anymap"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344"
-
-[[package]]
-name = "anymap2"
-version = "0.13.0"
+version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c"
+checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "arc-swap"
@@ -421,15 +345,37 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
+[[package]]
+name = "async-stream"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
+dependencies = [
+ "async-stream-impl",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-stream-impl"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.111",
+]
+
[[package]]
name = "async-trait"
-version = "0.1.88"
+version = "0.1.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
+checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
@@ -447,207 +393,726 @@ dependencies = [
"derive_utils",
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
name = "autocfg"
-version = "1.4.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
-name = "backtrace"
-version = "0.3.74"
+name = "aws-config"
+version = "1.8.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
+checksum = "c456581cb3c77fafcc8c67204a70680d40b61112d6da78c77bd31d945b65f1b5"
dependencies = [
- "addr2line",
- "cfg-if",
- "libc",
- "miniz_oxide",
- "object",
- "rustc-demangle",
- "windows-targets 0.52.6",
+ "aws-credential-types",
+ "aws-runtime",
+ "aws-sdk-sso",
+ "aws-sdk-ssooidc",
+ "aws-sdk-sts",
+ "aws-smithy-async",
+ "aws-smithy-http",
+ "aws-smithy-json",
+ "aws-smithy-runtime",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "aws-types",
+ "bytes",
+ "fastrand",
+ "hex",
+ "http 1.4.0",
+ "ring",
+ "time",
+ "tokio",
+ "tracing",
+ "url",
+ "zeroize",
]
[[package]]
-name = "base64"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5"
-
-[[package]]
-name = "base64"
-version = "0.22.1"
+name = "aws-credential-types"
+version = "1.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+checksum = "3cd362783681b15d136480ad555a099e82ecd8e2d10a841e14dfd0078d67fee3"
+dependencies = [
+ "aws-smithy-async",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "zeroize",
+]
[[package]]
-name = "bincode"
-version = "1.3.3"
+name = "aws-lc-rs"
+version = "1.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256"
dependencies = [
- "serde",
+ "aws-lc-sys",
+ "zeroize",
]
[[package]]
-name = "bitflags"
-version = "1.3.2"
+name = "aws-lc-sys"
+version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+checksum = "5c34dda4df7017c8db52132f0f8a2e0f8161649d15723ed63fc00c82d0f2081a"
+dependencies = [
+ "cc",
+ "cmake",
+ "dunce",
+ "fs_extra",
+]
[[package]]
-name = "bitflags"
-version = "2.9.0"
+name = "aws-runtime"
+version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
+checksum = "c635c2dc792cb4a11ce1a4f392a925340d1bdf499289b5ec1ec6810954eb43f5"
+dependencies = [
+ "aws-credential-types",
+ "aws-sigv4",
+ "aws-smithy-async",
+ "aws-smithy-eventstream",
+ "aws-smithy-http",
+ "aws-smithy-runtime",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "aws-types",
+ "bytes",
+ "fastrand",
+ "http 0.2.12",
+ "http 1.4.0",
+ "http-body 0.4.6",
+ "http-body 1.0.1",
+ "percent-encoding",
+ "pin-project-lite",
+ "tracing",
+ "uuid",
+]
[[package]]
-name = "blake2-rfc"
-version = "0.2.18"
+name = "aws-sdk-cloudfront"
+version = "1.110.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
+checksum = "eecd6b1a0c74d26e90c7a610fd6633fd57fd889b0004f8bec1b025f2bd0798bf"
dependencies = [
- "arrayvec 0.4.12",
- "constant_time_eq",
+ "aws-credential-types",
+ "aws-runtime",
+ "aws-smithy-async",
+ "aws-smithy-http",
+ "aws-smithy-json",
+ "aws-smithy-observability",
+ "aws-smithy-runtime",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "aws-smithy-xml",
+ "aws-types",
+ "fastrand",
+ "http 0.2.12",
+ "http 1.4.0",
+ "regex-lite",
+ "tracing",
]
[[package]]
-name = "block-buffer"
-version = "0.10.4"
+name = "aws-sdk-s3"
+version = "1.122.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+checksum = "94c2ca0cba97e8e279eb6c0b2d0aa10db5959000e602ab2b7c02de6b85d4c19b"
dependencies = [
- "generic-array",
+ "aws-credential-types",
+ "aws-runtime",
+ "aws-sigv4",
+ "aws-smithy-async",
+ "aws-smithy-checksums",
+ "aws-smithy-eventstream",
+ "aws-smithy-http",
+ "aws-smithy-json",
+ "aws-smithy-observability",
+ "aws-smithy-runtime",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "aws-smithy-xml",
+ "aws-types",
+ "bytes",
+ "fastrand",
+ "hex",
+ "hmac",
+ "http 0.2.12",
+ "http 1.4.0",
+ "http-body 1.0.1",
+ "lru",
+ "percent-encoding",
+ "regex-lite",
+ "sha2",
+ "tracing",
+ "url",
]
[[package]]
-name = "boolinator"
-version = "2.4.0"
+name = "aws-sdk-sso"
+version = "1.93.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9"
+checksum = "9dcb38bb33fc0a11f1ffc3e3e85669e0a11a37690b86f77e75306d8f369146a0"
+dependencies = [
+ "aws-credential-types",
+ "aws-runtime",
+ "aws-smithy-async",
+ "aws-smithy-http",
+ "aws-smithy-json",
+ "aws-smithy-observability",
+ "aws-smithy-runtime",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "aws-types",
+ "bytes",
+ "fastrand",
+ "http 0.2.12",
+ "http 1.4.0",
+ "regex-lite",
+ "tracing",
+]
[[package]]
-name = "brotli"
-version = "7.0.0"
+name = "aws-sdk-ssooidc"
+version = "1.95.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd"
+checksum = "2ada8ffbea7bd1be1f53df1dadb0f8fdb04badb13185b3321b929d1ee3caad09"
dependencies = [
- "alloc-no-stdlib",
- "alloc-stdlib",
- "brotli-decompressor",
+ "aws-credential-types",
+ "aws-runtime",
+ "aws-smithy-async",
+ "aws-smithy-http",
+ "aws-smithy-json",
+ "aws-smithy-observability",
+ "aws-smithy-runtime",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "aws-types",
+ "bytes",
+ "fastrand",
+ "http 0.2.12",
+ "http 1.4.0",
+ "regex-lite",
+ "tracing",
]
[[package]]
-name = "brotli-decompressor"
-version = "4.0.2"
+name = "aws-sdk-sts"
+version = "1.97.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37"
+checksum = "e6443ccadc777095d5ed13e21f5c364878c9f5bad4e35187a6cdbd863b0afcad"
dependencies = [
- "alloc-no-stdlib",
- "alloc-stdlib",
+ "aws-credential-types",
+ "aws-runtime",
+ "aws-smithy-async",
+ "aws-smithy-http",
+ "aws-smithy-json",
+ "aws-smithy-observability",
+ "aws-smithy-query",
+ "aws-smithy-runtime",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "aws-smithy-xml",
+ "aws-types",
+ "fastrand",
+ "http 0.2.12",
+ "http 1.4.0",
+ "regex-lite",
+ "tracing",
]
[[package]]
-name = "bumpalo"
-version = "3.17.0"
+name = "aws-sigv4"
+version = "1.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
+checksum = "efa49f3c607b92daae0c078d48a4571f599f966dce3caee5f1ea55c4d9073f99"
+dependencies = [
+ "aws-credential-types",
+ "aws-smithy-eventstream",
+ "aws-smithy-http",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "bytes",
+ "crypto-bigint 0.5.5",
+ "form_urlencoded",
+ "hex",
+ "hmac",
+ "http 0.2.12",
+ "http 1.4.0",
+ "p256 0.11.1",
+ "percent-encoding",
+ "ring",
+ "sha2",
+ "subtle",
+ "time",
+ "tracing",
+ "zeroize",
+]
[[package]]
-name = "byteorder"
-version = "1.5.0"
+name = "aws-smithy-async"
+version = "1.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+checksum = "52eec3db979d18cb807fc1070961cc51d87d069abe9ab57917769687368a8c6c"
+dependencies = [
+ "futures-util",
+ "pin-project-lite",
+ "tokio",
+]
[[package]]
-name = "bytes"
-version = "1.10.1"
+name = "aws-smithy-checksums"
+version = "0.64.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
+checksum = "ddcf418858f9f3edd228acb8759d77394fed7531cce78d02bdda499025368439"
+dependencies = [
+ "aws-smithy-http",
+ "aws-smithy-types",
+ "bytes",
+ "crc-fast",
+ "hex",
+ "http 1.4.0",
+ "http-body 1.0.1",
+ "http-body-util",
+ "md-5",
+ "pin-project-lite",
+ "sha1",
+ "sha2",
+ "tracing",
+]
[[package]]
-name = "bytestring"
-version = "1.4.0"
+name = "aws-smithy-eventstream"
+version = "0.60.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f"
+checksum = "35b9c7354a3b13c66f60fe4616d6d1969c9fd36b1b5333a5dfb3ee716b33c588"
dependencies = [
+ "aws-smithy-types",
"bytes",
+ "crc32fast",
]
[[package]]
-name = "cc"
-version = "1.2.16"
+name = "aws-smithy-http"
+version = "0.63.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
+checksum = "630e67f2a31094ffa51b210ae030855cb8f3b7ee1329bdd8d085aaf61e8b97fc"
dependencies = [
- "jobserver",
- "libc",
- "shlex",
+ "aws-smithy-eventstream",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "bytes",
+ "bytes-utils",
+ "futures-core",
+ "futures-util",
+ "http 1.4.0",
+ "http-body 1.0.1",
+ "http-body-util",
+ "percent-encoding",
+ "pin-project-lite",
+ "pin-utils",
+ "tracing",
]
[[package]]
-name = "cc_license"
-version = "0.1.0"
+name = "aws-smithy-http-client"
+version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9e604b8591d0dbbd946023bcf91b4171f944765c1eb6c73003d3928d9e8c64c"
+checksum = "12fb0abf49ff0cab20fd31ac1215ed7ce0ea92286ba09e2854b42ba5cabe7525"
dependencies = [
- "regex",
+ "aws-smithy-async",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "h2 0.3.27",
+ "h2 0.4.12",
+ "http 0.2.12",
+ "http 1.4.0",
+ "http-body 0.4.6",
+ "hyper 0.14.32",
+ "hyper 1.8.1",
+ "hyper-rustls 0.24.2",
+ "hyper-rustls 0.27.7",
+ "hyper-util",
+ "pin-project-lite",
+ "rustls 0.21.12",
+ "rustls 0.23.35",
+ "rustls-native-certs",
+ "rustls-pki-types",
+ "tokio",
+ "tokio-rustls 0.26.4",
+ "tower 0.5.2",
+ "tracing",
]
[[package]]
-name = "cfg-if"
-version = "1.0.0"
+name = "aws-smithy-json"
+version = "0.62.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+checksum = "3cb96aa208d62ee94104645f7b2ecaf77bf27edf161590b6224bfbac2832f979"
+dependencies = [
+ "aws-smithy-types",
+]
[[package]]
-name = "cfg-match"
-version = "0.2.1"
+name = "aws-smithy-observability"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8100e46ff92eb85bf6dc2930c73f2a4f7176393c84a9446b3d501e1b354e7b34"
+checksum = "c0a46543fbc94621080b3cf553eb4cbbdc41dd9780a30c4756400f0139440a1d"
+dependencies = [
+ "aws-smithy-runtime-api",
+]
[[package]]
-name = "chrono"
-version = "0.4.40"
+name = "aws-smithy-query"
+version = "0.60.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
+checksum = "0cebbddb6f3a5bd81553643e9c7daf3cc3dc5b0b5f398ac668630e8a84e6fff0"
dependencies = [
- "android-tzdata",
- "iana-time-zone",
- "js-sys",
- "num-traits",
- "serde",
- "wasm-bindgen",
- "windows-link",
+ "aws-smithy-types",
+ "urlencoding",
]
[[package]]
-name = "cipher"
-version = "0.4.4"
+name = "aws-smithy-runtime"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+checksum = "f3df87c14f0127a0d77eb261c3bc45d5b4833e2a1f63583ebfb728e4852134ee"
dependencies = [
- "crypto-common",
- "inout",
+ "aws-smithy-async",
+ "aws-smithy-http",
+ "aws-smithy-http-client",
+ "aws-smithy-observability",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "bytes",
+ "fastrand",
+ "http 0.2.12",
+ "http 1.4.0",
+ "http-body 0.4.6",
+ "http-body 1.0.1",
+ "http-body-util",
+ "pin-project-lite",
+ "pin-utils",
+ "tokio",
+ "tracing",
]
[[package]]
-name = "clap"
-version = "4.5.32"
+name = "aws-smithy-runtime-api"
+version = "1.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83"
+checksum = "49952c52f7eebb72ce2a754d3866cc0f87b97d2a46146b79f80f3a93fb2b3716"
+dependencies = [
+ "aws-smithy-async",
+ "aws-smithy-types",
+ "bytes",
+ "http 0.2.12",
+ "http 1.4.0",
+ "pin-project-lite",
+ "tokio",
+ "tracing",
+ "zeroize",
+]
+
+[[package]]
+name = "aws-smithy-types"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b3a26048eeab0ddeba4b4f9d51654c79af8c3b32357dc5f336cee85ab331c33"
+dependencies = [
+ "base64-simd",
+ "bytes",
+ "bytes-utils",
+ "futures-core",
+ "http 0.2.12",
+ "http 1.4.0",
+ "http-body 0.4.6",
+ "http-body 1.0.1",
+ "http-body-util",
+ "itoa",
+ "num-integer",
+ "pin-project-lite",
+ "pin-utils",
+ "ryu",
+ "serde",
+ "time",
+ "tokio",
+ "tokio-util",
+]
+
+[[package]]
+name = "aws-smithy-xml"
+version = "0.60.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11b2f670422ff42bf7065031e72b45bc52a3508bd089f743ea90731ca2b6ea57"
+dependencies = [
+ "xmlparser",
+]
+
+[[package]]
+name = "aws-types"
+version = "1.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d980627d2dd7bfc32a3c025685a033eeab8d365cc840c631ef59d1b8f428164"
+dependencies = [
+ "aws-credential-types",
+ "aws-smithy-async",
+ "aws-smithy-runtime-api",
+ "aws-smithy-types",
+ "rustc_version",
+ "tracing",
+]
+
+[[package]]
+name = "axum"
+version = "0.7.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
+dependencies = [
+ "async-trait",
+ "axum-core",
+ "bytes",
+ "futures-util",
+ "http 1.4.0",
+ "http-body 1.0.1",
+ "http-body-util",
+ "itoa",
+ "matchit",
+ "memchr",
+ "mime",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustversion",
+ "serde",
+ "sync_wrapper 1.0.2",
+ "tower 0.5.2",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "axum-core"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
+dependencies = [
+ "async-trait",
+ "bytes",
+ "futures-util",
+ "http 1.4.0",
+ "http-body 1.0.1",
+ "http-body-util",
+ "mime",
+ "pin-project-lite",
+ "rustversion",
+ "sync_wrapper 1.0.2",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "base16ct"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
+
+[[package]]
+name = "base16ct"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
+
+[[package]]
+name = "base64"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
+
+[[package]]
+name = "base64"
+version = "0.21.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "base64-compat"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a8d4d2746f89841e49230dd26917df1876050f95abafafbe34f47cb534b88d7"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "base64-simd"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195"
+dependencies = [
+ "outref",
+ "vsimd",
+]
+
+[[package]]
+name = "base64ct"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
+
+[[package]]
+name = "blake2-rfc"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
+dependencies = [
+ "arrayvec 0.4.12",
+ "constant_time_eq",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "brotli"
+version = "8.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560"
+dependencies = [
+ "alloc-no-stdlib",
+ "alloc-stdlib",
+ "brotli-decompressor",
+]
+
+[[package]]
+name = "brotli-decompressor"
+version = "5.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03"
+dependencies = [
+ "alloc-no-stdlib",
+ "alloc-stdlib",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
+
+[[package]]
+name = "bytes-utils"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35"
+dependencies = [
+ "bytes",
+ "either",
+]
+
+[[package]]
+name = "bytestring"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "113b4343b5f6617e7ad401ced8de3cc8b012e73a594347c307b90db3e9271289"
+dependencies = [
+ "bytes",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.49"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215"
+dependencies = [
+ "find-msvc-tools",
+ "jobserver",
+ "libc",
+ "shlex",
+]
+
+[[package]]
+name = "cc_license"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9e604b8591d0dbbd946023bcf91b4171f944765c1eb6c73003d3928d9e8c64c"
+dependencies = [
+ "regex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "chrono"
+version = "0.4.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
+dependencies = [
+ "iana-time-zone",
+ "js-sys",
+ "num-traits",
+ "serde",
+ "wasm-bindgen",
+ "windows-link",
+]
+
+[[package]]
+name = "clap"
+version = "4.5.53"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
-version = "4.5.32"
+version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
+checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
dependencies = [
"anstream",
"anstyle",
@@ -657,9 +1122,18 @@ dependencies = [
[[package]]
name = "clap_lex"
-version = "0.7.4"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
+
+[[package]]
+name = "cmake"
+version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d"
+dependencies = [
+ "cc",
+]
[[package]]
name = "codegen"
@@ -672,9 +1146,9 @@ dependencies = [
[[package]]
name = "colorchoice"
-version = "1.0.3"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "combine"
@@ -704,14 +1178,10 @@ dependencies = [
]
[[package]]
-name = "console_error_panic_hook"
-version = "0.1.7"
+name = "const-oid"
+version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
-dependencies = [
- "cfg-if",
- "wasm-bindgen",
-]
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "constant_time_eq"
@@ -719,20 +1189,22 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
+[[package]]
+name = "convert_case"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
+dependencies = [
+ "unicode-segmentation",
+]
+
[[package]]
name = "cookie"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
dependencies = [
- "aes-gcm",
- "base64 0.20.0",
- "hkdf",
- "hmac",
"percent-encoding",
- "rand 0.8.5",
- "sha2",
- "subtle",
"time",
"version_check",
]
@@ -747,6 +1219,16 @@ dependencies = [
"libc",
]
+[[package]]
+name = "core-foundation"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
@@ -762,15 +1244,66 @@ dependencies = [
"libc",
]
+[[package]]
+name = "crc"
+version = "3.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675"
+dependencies = [
+ "crc-catalog",
+]
+
+[[package]]
+name = "crc-catalog"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
+
+[[package]]
+name = "crc-fast"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2fd92aca2c6001b1bf5ba0ff84ee74ec8501b52bbef0cac80bf25a6c1d87a83d"
+dependencies = [
+ "crc",
+ "digest",
+ "rustversion",
+ "spin 0.10.0",
+]
+
[[package]]
name = "crc32fast"
-version = "1.4.2"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
+[[package]]
+name = "crypto-bigint"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef"
+dependencies = [
+ "generic-array",
+ "rand_core 0.6.4",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "crypto-bigint"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
+dependencies = [
+ "generic-array",
+ "rand_core 0.6.4",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "crypto-common"
version = "0.1.6"
@@ -778,45 +1311,91 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
- "rand_core 0.6.4",
"typenum",
]
+[[package]]
+name = "cssparser"
+version = "0.31.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b3df4f93e5fbbe73ec01ec8d3f68bba73107993a5b1e7519273c32db9b0d5be"
+dependencies = [
+ "cssparser-macros",
+ "dtoa-short",
+ "itoa",
+ "phf 0.11.3",
+ "smallvec",
+]
+
+[[package]]
+name = "cssparser-macros"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
+dependencies = [
+ "quote",
+ "syn 2.0.111",
+]
+
[[package]]
name = "csv"
-version = "1.3.1"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
+checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938"
dependencies = [
"csv-core",
"itoa",
"ryu",
- "serde",
+ "serde_core",
]
[[package]]
name = "csv-core"
-version = "0.1.12"
+version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d"
+checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782"
dependencies = [
"memchr",
]
[[package]]
-name = "ctr"
-version = "0.9.2"
+name = "curve25519-dalek"
+version = "4.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "curve25519-dalek-derive",
+ "digest",
+ "fiat-crypto",
+ "rustc_version",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "curve25519-dalek-derive"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
+checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
- "cipher",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.111",
]
+[[package]]
+name = "custom_error"
+version = "1.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f8a51dd197fa6ba5b4dc98a990a43cc13693c23eb0089ebb0fcc1f04152bca6"
+
[[package]]
name = "darling"
-version = "0.20.10"
+version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
+checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0"
dependencies = [
"darling_core",
"darling_macro",
@@ -824,36 +1403,37 @@ dependencies = [
[[package]]
name = "darling_core"
-version = "0.20.10"
+version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
+checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
name = "darling_macro"
-version = "0.20.10"
+version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
+checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
dependencies = [
"darling_core",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
name = "deadpool"
-version = "0.12.2"
+version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ed5957ff93768adf7a65ab167a17835c3d2c3c50d084fe305174c112f468e2f"
+checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b"
dependencies = [
"deadpool-runtime",
+ "lazy_static",
"num_cpus",
"tokio",
]
@@ -878,53 +1458,67 @@ dependencies = [
]
[[package]]
-name = "deranged"
-version = "0.4.0"
+name = "der"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
+checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
dependencies = [
- "powerfmt",
+ "const-oid",
+ "zeroize",
]
[[package]]
-name = "derive_more"
-version = "1.0.0"
+name = "der"
+version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
+checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
dependencies = [
- "derive_more-impl 1.0.0",
+ "const-oid",
+ "pem-rfc7468",
+ "zeroize",
]
[[package]]
-name = "derive_more"
-version = "2.0.1"
+name = "deranged"
+version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
+checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
dependencies = [
- "derive_more-impl 2.0.1",
+ "powerfmt",
+ "serde_core",
]
[[package]]
-name = "derive_more-impl"
-version = "1.0.0"
+name = "derive_more"
+version = "0.99.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
+checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
- "unicode-xid",
+ "syn 2.0.111",
+]
+
+[[package]]
+name = "derive_more"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618"
+dependencies = [
+ "derive_more-impl",
]
[[package]]
name = "derive_more-impl"
-version = "2.0.1"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
+checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b"
dependencies = [
+ "convert_case",
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "rustc_version",
+ "syn 2.0.111",
"unicode-xid",
]
@@ -936,7 +1530,7 @@ checksum = "ccfae181bab5ab6c5478b2ccb69e4c68a02f8c3ec72f6616bfec9dbc599d2ee0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
@@ -954,14 +1548,15 @@ dependencies = [
[[package]]
name = "diesel"
-version = "2.2.8"
+version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "470eb10efc8646313634c99bb1593f402a6434cbd86e266770c6e39219adb86a"
+checksum = "0c415189028b232660655e4893e8bc25ca7aee8e96888db66d9edb400535456a"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.10.0",
"byteorder",
"chrono",
"diesel_derives",
+ "downcast-rs",
"itoa",
"pq-sys",
"r2d2",
@@ -978,100 +1573,231 @@ dependencies = [
"heck 0.4.1",
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
+]
+
+[[package]]
+name = "diesel-derive-newtype"
+version = "2.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5adf688c584fe33726ce0e2898f608a2a92578ac94a4a92fcecf73214fe0716"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.111",
+]
+
+[[package]]
+name = "diesel_derives"
+version = "2.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8587cbca3c929fb198e7950d761d31ca72b80aa6e07c1b7bec5879d187720436"
+dependencies = [
+ "diesel_table_macro_syntax",
+ "dsl_auto_type",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.111",
+]
+
+[[package]]
+name = "diesel_migrations"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "745fd255645f0f1135f9ec55c7b00e0882192af9683ab4731e4bba3da82b8f9c"
+dependencies = [
+ "diesel",
+ "migrations_internals",
+ "migrations_macros",
+]
+
+[[package]]
+name = "diesel_table_macro_syntax"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe2444076b48641147115697648dc743c2c00b61adade0f01ce67133c7babe8c"
+dependencies = [
+ "syn 2.0.111",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "const-oid",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.111",
+]
+
+[[package]]
+name = "dotenv"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
+
+[[package]]
+name = "downcast-rs"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc"
+
+[[package]]
+name = "dsl_auto_type"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd122633e4bef06db27737f21d3738fb89c8f6d5360d6d9d7635dda142a7757e"
+dependencies = [
+ "darling",
+ "either",
+ "heck 0.5.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.111",
+]
+
+[[package]]
+name = "dtoa"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04"
+
+[[package]]
+name = "dtoa-short"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87"
+dependencies = [
+ "dtoa",
]
[[package]]
-name = "diesel-derive-newtype"
-version = "2.1.2"
+name = "dunce"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5adf688c584fe33726ce0e2898f608a2a92578ac94a4a92fcecf73214fe0716"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.100",
-]
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]]
-name = "diesel_derives"
-version = "2.2.4"
+name = "dyn-clone"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
+
+[[package]]
+name = "ecdsa"
+version = "0.14.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a93958254b70bea63b4187ff73d10180599d9d8d177071b7f91e6da4e0c0ad55"
+checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c"
dependencies = [
- "diesel_table_macro_syntax",
- "dsl_auto_type",
- "proc-macro2",
- "quote",
- "syn 2.0.100",
+ "der 0.6.1",
+ "elliptic-curve 0.12.3",
+ "rfc6979 0.3.1",
+ "signature 1.6.4",
]
[[package]]
-name = "diesel_migrations"
-version = "2.2.0"
+name = "ecdsa"
+version = "0.16.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a73ce704bad4231f001bff3314d91dce4aba0770cee8b233991859abc15c1f6"
+checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
dependencies = [
- "diesel",
- "migrations_internals",
- "migrations_macros",
+ "der 0.7.10",
+ "digest",
+ "elliptic-curve 0.13.8",
+ "rfc6979 0.4.0",
+ "signature 2.2.0",
+ "spki 0.7.3",
]
[[package]]
-name = "diesel_table_macro_syntax"
-version = "0.2.0"
+name = "ed25519"
+version = "2.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25"
+checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
dependencies = [
- "syn 2.0.100",
+ "pkcs8 0.10.2",
+ "signature 2.2.0",
]
[[package]]
-name = "digest"
-version = "0.10.7"
+name = "ed25519-dalek"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
dependencies = [
- "block-buffer",
- "crypto-common",
+ "curve25519-dalek",
+ "ed25519",
+ "serde",
+ "sha2",
"subtle",
+ "zeroize",
]
[[package]]
-name = "displaydoc"
-version = "0.2.5"
+name = "ego-tree"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.100",
-]
+checksum = "12a0bb14ac04a9fcf170d0bbbef949b44cc492f4452bd20c095636956f653642"
[[package]]
-name = "dotenv"
-version = "0.15.0"
+name = "either"
+version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
-name = "dsl_auto_type"
-version = "0.1.3"
+name = "elliptic-curve"
+version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "139ae9aca7527f85f26dd76483eb38533fd84bd571065da1739656ef71c5ff5b"
+checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3"
dependencies = [
- "darling",
- "either",
- "heck 0.5.0",
- "proc-macro2",
- "quote",
- "syn 2.0.100",
+ "base16ct 0.1.1",
+ "crypto-bigint 0.4.9",
+ "der 0.6.1",
+ "digest",
+ "ff 0.12.1",
+ "generic-array",
+ "group 0.12.1",
+ "pkcs8 0.9.0",
+ "rand_core 0.6.4",
+ "sec1 0.3.0",
+ "subtle",
+ "zeroize",
]
[[package]]
-name = "either"
-version = "1.15.0"
+name = "elliptic-curve"
+version = "0.13.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
+dependencies = [
+ "base16ct 0.2.0",
+ "crypto-bigint 0.5.5",
+ "digest",
+ "ff 0.13.1",
+ "generic-array",
+ "group 0.13.0",
+ "hkdf",
+ "pem-rfc7468",
+ "pkcs8 0.10.2",
+ "rand_core 0.6.4",
+ "sec1 0.7.3",
+ "subtle",
+ "zeroize",
+]
[[package]]
name = "encode_unicode"
@@ -1090,9 +1816,9 @@ dependencies = [
[[package]]
name = "env_filter"
-version = "0.1.3"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
+checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2"
dependencies = [
"log",
"regex",
@@ -1100,9 +1826,9 @@ dependencies = [
[[package]]
name = "env_logger"
-version = "0.11.7"
+version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3716d7a920fb4fac5d84e9d4bce8ceb321e9414b4409da61b07b75c1e3d0697"
+checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
dependencies = [
"anstream",
"anstyle",
@@ -1119,12 +1845,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
-version = "0.3.10"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
- "windows-sys 0.59.0",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -1133,11 +1859,49 @@ version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+[[package]]
+name = "ff"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
+dependencies = [
+ "rand_core 0.6.4",
+ "subtle",
+]
+
+[[package]]
+name = "ff"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
+dependencies = [
+ "rand_core 0.6.4",
+ "subtle",
+]
+
+[[package]]
+name = "fiat-crypto"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
+
+[[package]]
+name = "fixedbitset"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
+
[[package]]
name = "flate2"
-version = "1.1.0"
+version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
+checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
dependencies = [
"crc32fast",
"miniz_oxide",
@@ -1155,6 +1919,12 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+[[package]]
+name = "foldhash"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
+
[[package]]
name = "foreign-types"
version = "0.3.2"
@@ -1172,13 +1942,39 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
-version = "1.2.1"
+version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
dependencies = [
"percent-encoding",
]
+[[package]]
+name = "fs2"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "fs_extra"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+
+[[package]]
+name = "futf"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
+dependencies = [
+ "mac",
+ "new_debug_unreachable",
+]
+
[[package]]
name = "futures"
version = "0.3.31"
@@ -1235,7 +2031,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
@@ -1269,237 +2065,57 @@ dependencies = [
]
[[package]]
-name = "generic-array"
-version = "0.14.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
-dependencies = [
- "typenum",
- "version_check",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.2.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
-dependencies = [
- "cfg-if",
- "js-sys",
- "libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
-dependencies = [
- "cfg-if",
- "libc",
- "r-efi",
- "wasi 0.14.2+wasi-0.2.4",
-]
-
-[[package]]
-name = "ghash"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
-dependencies = [
- "opaque-debug",
- "polyval",
-]
-
-[[package]]
-name = "gimli"
-version = "0.31.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
-
-[[package]]
-name = "gloo"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68ce6f2dfa9f57f15b848efa2aade5e1850dc72986b87a2b0752d44ca08f4967"
-dependencies = [
- "gloo-console-timer",
- "gloo-events",
- "gloo-file 0.1.0",
- "gloo-timers 0.2.6",
-]
-
-[[package]]
-name = "gloo"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23947965eee55e3e97a5cd142dd4c10631cc349b48cecca0ed230fd296f568cd"
-dependencies = [
- "gloo-console",
- "gloo-dialogs",
- "gloo-events",
- "gloo-file 0.2.3",
- "gloo-render",
- "gloo-storage 0.2.2",
- "gloo-timers 0.2.6",
- "gloo-utils 0.1.7",
-]
-
-[[package]]
-name = "gloo-console"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f"
-dependencies = [
- "gloo-utils 0.1.7",
- "js-sys",
- "serde",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "gloo-console-timer"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b48675544b29ac03402c6dffc31a912f716e38d19f7e74b78b7e900ec3c941ea"
-dependencies = [
- "web-sys",
-]
-
-[[package]]
-name = "gloo-dialogs"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6"
-dependencies = [
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "gloo-events"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc"
-dependencies = [
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "gloo-file"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f9fecfe46b5dc3cc46f58e98ba580cc714f2c93860796d002eb3527a465ef49"
-dependencies = [
- "gloo-events",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "gloo-file"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7"
-dependencies = [
- "futures-channel",
- "gloo-events",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "gloo-render"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764"
-dependencies = [
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "gloo-storage"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480"
-dependencies = [
- "gloo-utils 0.1.7",
- "js-sys",
- "serde",
- "serde_json",
- "thiserror 1.0.69",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "gloo-storage"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a"
-dependencies = [
- "gloo-utils 0.2.0",
- "js-sys",
- "serde",
- "serde_json",
- "thiserror 1.0.69",
- "wasm-bindgen",
- "web-sys",
+name = "fxhash"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
+dependencies = [
+ "byteorder",
]
[[package]]
-name = "gloo-timers"
-version = "0.2.6"
+name = "generic-array"
+version = "0.14.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
+checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
dependencies = [
- "futures-channel",
- "futures-core",
- "js-sys",
- "wasm-bindgen",
+ "typenum",
+ "version_check",
+ "zeroize",
]
[[package]]
-name = "gloo-timers"
-version = "0.3.0"
+name = "getopts"
+version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
+checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df"
dependencies = [
- "js-sys",
- "wasm-bindgen",
+ "unicode-width",
]
[[package]]
-name = "gloo-utils"
-version = "0.1.7"
+name = "getrandom"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
+ "cfg-if",
"js-sys",
- "serde",
- "serde_json",
+ "libc",
+ "wasi",
"wasm-bindgen",
- "web-sys",
]
[[package]]
-name = "gloo-utils"
-version = "0.2.0"
+name = "getrandom"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
- "js-sys",
- "serde",
- "serde_json",
- "wasm-bindgen",
- "web-sys",
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasip2",
]
[[package]]
@@ -1560,11 +2176,33 @@ dependencies = [
"syn 1.0.109",
]
+[[package]]
+name = "group"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
+dependencies = [
+ "ff 0.12.1",
+ "rand_core 0.6.4",
+ "subtle",
+]
+
+[[package]]
+name = "group"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
+dependencies = [
+ "ff 0.13.1",
+ "rand_core 0.6.4",
+ "subtle",
+]
+
[[package]]
name = "h2"
-version = "0.3.26"
+version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
+checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d"
dependencies = [
"bytes",
"fnv",
@@ -1572,7 +2210,7 @@ dependencies = [
"futures-sink",
"futures-util",
"http 0.2.12",
- "indexmap 2.8.0",
+ "indexmap 2.12.1",
"slab",
"tokio",
"tokio-util",
@@ -1581,17 +2219,17 @@ dependencies = [
[[package]]
name = "h2"
-version = "0.4.8"
+version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2"
+checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386"
dependencies = [
"atomic-waker",
"bytes",
"fnv",
"futures-core",
"futures-sink",
- "http 1.3.1",
- "indexmap 2.8.0",
+ "http 1.4.0",
+ "indexmap 2.12.1",
"slab",
"tokio",
"tokio-util",
@@ -1606,9 +2244,14 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
-version = "0.15.2"
+version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash 0.2.0",
+]
[[package]]
name = "heck"
@@ -1624,9 +2267,15 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
-version = "0.3.9"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hkdf"
@@ -1646,6 +2295,20 @@ dependencies = [
"digest",
]
+[[package]]
+name = "html5ever"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4"
+dependencies = [
+ "log",
+ "mac",
+ "markup5ever",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.111",
+]
+
[[package]]
name = "http"
version = "0.2.12"
@@ -1659,15 +2322,25 @@ dependencies = [
[[package]]
name = "http"
-version = "1.3.1"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
+checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
dependencies = [
"bytes",
- "fnv",
"itoa",
]
+[[package]]
+name = "http-body"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
+dependencies = [
+ "bytes",
+ "http 0.2.12",
+ "pin-project-lite",
+]
+
[[package]]
name = "http-body"
version = "1.0.1"
@@ -1675,7 +2348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
- "http 1.3.1",
+ "http 1.4.0",
]
[[package]]
@@ -1686,8 +2359,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
dependencies = [
"bytes",
"futures-core",
- "http 1.3.1",
- "http-body",
+ "http 1.4.0",
+ "http-body 1.0.1",
"pin-project-lite",
]
@@ -1705,19 +2378,46 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
-version = "1.6.0"
+version = "0.14.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
+checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
dependencies = [
"bytes",
"futures-channel",
+ "futures-core",
"futures-util",
- "h2 0.4.8",
- "http 1.3.1",
- "http-body",
+ "h2 0.3.27",
+ "http 0.2.12",
+ "http-body 0.4.6",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "socket2 0.5.10",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "hyper"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "h2 0.4.12",
+ "http 1.4.0",
+ "http-body 1.0.1",
"httparse",
+ "httpdate",
"itoa",
"pin-project-lite",
+ "pin-utils",
"smallvec",
"tokio",
"want",
@@ -1725,18 +2425,46 @@ dependencies = [
[[package]]
name = "hyper-rustls"
-version = "0.27.5"
+version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
+checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
dependencies = [
"futures-util",
- "http 1.3.1",
- "hyper",
+ "http 0.2.12",
+ "hyper 0.14.32",
+ "log",
+ "rustls 0.21.12",
+ "tokio",
+ "tokio-rustls 0.24.1",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
+dependencies = [
+ "http 1.4.0",
+ "hyper 1.8.1",
"hyper-util",
- "rustls",
+ "rustls 0.23.35",
+ "rustls-native-certs",
"rustls-pki-types",
"tokio",
- "tokio-rustls",
+ "tokio-rustls 0.26.4",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-timeout"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
+dependencies = [
+ "hyper 1.8.1",
+ "hyper-util",
+ "pin-project-lite",
+ "tokio",
"tower-service",
]
@@ -1748,7 +2476,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
dependencies = [
"bytes",
"http-body-util",
- "hyper",
+ "hyper 1.8.1",
"hyper-util",
"native-tls",
"tokio",
@@ -1758,33 +2486,41 @@ dependencies = [
[[package]]
name = "hyper-util"
-version = "0.1.10"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
+checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
dependencies = [
+ "base64 0.22.1",
"bytes",
"futures-channel",
+ "futures-core",
"futures-util",
- "http 1.3.1",
- "http-body",
- "hyper",
+ "http 1.4.0",
+ "http-body 1.0.1",
+ "hyper 1.8.1",
+ "ipnet",
+ "libc",
+ "percent-encoding",
"pin-project-lite",
- "socket2",
+ "socket2 0.6.1",
+ "system-configuration 0.6.1",
"tokio",
"tower-service",
"tracing",
+ "windows-registry",
]
[[package]]
name = "iana-time-zone"
-version = "0.1.61"
+version = "0.1.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
+checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
+ "log",
"wasm-bindgen",
"windows-core",
]
@@ -1800,21 +2536,22 @@ dependencies = [
[[package]]
name = "icu_collections"
-version = "1.5.0"
+version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
dependencies = [
"displaydoc",
+ "potential_utf",
"yoke",
"zerofrom",
"zerovec",
]
[[package]]
-name = "icu_locid"
-version = "1.5.0"
+name = "icu_locale_core"
+version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
dependencies = [
"displaydoc",
"litemap",
@@ -1823,99 +2560,61 @@ dependencies = [
"zerovec",
]
-[[package]]
-name = "icu_locid_transform"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
-dependencies = [
- "displaydoc",
- "icu_locid",
- "icu_locid_transform_data",
- "icu_provider",
- "tinystr",
- "zerovec",
-]
-
-[[package]]
-name = "icu_locid_transform_data"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
-
[[package]]
name = "icu_normalizer"
-version = "1.5.0"
+version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
dependencies = [
- "displaydoc",
"icu_collections",
"icu_normalizer_data",
"icu_properties",
"icu_provider",
"smallvec",
- "utf16_iter",
- "utf8_iter",
- "write16",
"zerovec",
]
[[package]]
name = "icu_normalizer_data"
-version = "1.5.0"
+version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
+checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
[[package]]
name = "icu_properties"
-version = "1.5.1"
+version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
dependencies = [
- "displaydoc",
"icu_collections",
- "icu_locid_transform",
+ "icu_locale_core",
"icu_properties_data",
"icu_provider",
- "tinystr",
+ "zerotrie",
"zerovec",
]
[[package]]
name = "icu_properties_data"
-version = "1.5.0"
+version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
+checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
[[package]]
name = "icu_provider"
-version = "1.5.0"
+version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
dependencies = [
"displaydoc",
- "icu_locid",
- "icu_provider_macros",
- "stable_deref_trait",
- "tinystr",
+ "icu_locale_core",
"writeable",
"yoke",
"zerofrom",
+ "zerotrie",
"zerovec",
]
-[[package]]
-name = "icu_provider_macros"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.100",
-]
-
[[package]]
name = "ident_case"
version = "1.0.1"
@@ -1924,9 +2623,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
-version = "1.0.3"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
dependencies = [
"idna_adapter",
"smallvec",
@@ -1935,9 +2634,9 @@ dependencies = [
[[package]]
name = "idna_adapter"
-version = "1.2.0"
+version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
dependencies = [
"icu_normalizer",
"icu_properties",
@@ -1957,26 +2656,19 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
+ "serde",
]
[[package]]
name = "indexmap"
-version = "2.8.0"
+version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
+checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
dependencies = [
"equivalent",
- "hashbrown 0.15.2",
+ "hashbrown 0.16.1",
"serde",
-]
-
-[[package]]
-name = "inout"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
-dependencies = [
- "generic-array",
+ "serde_core",
]
[[package]]
@@ -1997,11 +2689,21 @@ version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
+[[package]]
+name = "iri-string"
+version = "0.7.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
[[package]]
name = "is_terminal_polyfill"
-version = "1.70.1"
+version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "isbn"
@@ -2023,6 +2725,24 @@ dependencies = [
"either",
]
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itertools"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
+dependencies = [
+ "either",
+]
+
[[package]]
name = "itoa"
version = "1.0.15"
@@ -2031,42 +2751,43 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "jiff"
-version = "0.2.4"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d699bc6dfc879fb1bf9bdff0d4c56f0884fc6f0d0eb0fba397a6d00cd9a6b85e"
+checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35"
dependencies = [
"jiff-static",
"log",
"portable-atomic",
"portable-atomic-util",
- "serde",
+ "serde_core",
]
[[package]]
name = "jiff-static"
-version = "0.2.4"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d16e75759ee0aa64c57a56acbf43916987b20c77373cb7e808979e02b93c9f9"
+checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
name = "jobserver"
-version = "0.1.32"
+version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
+checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
dependencies = [
+ "getrandom 0.3.4",
"libc",
]
[[package]]
name = "js-sys"
-version = "0.3.77"
+version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
+checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
dependencies = [
"once_cell",
"wasm-bindgen",
@@ -2089,9 +2810,9 @@ dependencies = [
[[package]]
name = "juniper"
-version = "0.16.1"
+version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "943306315b1a7a03d27af9dfb0c288d9f4da8830c17df4bceb7d50a47da0982c"
+checksum = "3478f4a8a2a1c7679944f5f4f08c60d6440f9970da481d79c8f8931201424403"
dependencies = [
"async-trait",
"auto_enums",
@@ -2099,7 +2820,7 @@ dependencies = [
"fnv",
"futures",
"graphql-parser",
- "indexmap 2.8.0",
+ "indexmap 2.12.1",
"juniper_codegen",
"serde",
"smartstring",
@@ -2116,7 +2837,7 @@ checksum = "760dbe46660494d469023d661e8d268f413b2cb68c999975dcc237407096a693"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
"url",
]
@@ -2131,24 +2852,33 @@ name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+dependencies = [
+ "spin 0.9.8",
+]
[[package]]
name = "libc"
-version = "0.2.171"
+version = "0.2.178"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
+
+[[package]]
+name = "libm"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
+checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "linux-raw-sys"
-version = "0.9.3"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
+checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]]
name = "litemap"
-version = "0.7.5"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
+checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
[[package]]
name = "local-channel"
@@ -2169,19 +2899,33 @@ checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487"
[[package]]
name = "lock_api"
-version = "0.4.12"
+version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
- "autocfg",
"scopeguard",
]
[[package]]
name = "log"
-version = "0.4.26"
+version = "0.4.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
+
+[[package]]
+name = "lru"
+version = "0.16.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593"
+dependencies = [
+ "hashbrown 0.16.1",
+]
+
+[[package]]
+name = "mac"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
+checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "marc"
@@ -2192,17 +2936,47 @@ dependencies = [
"xml-rs",
]
+[[package]]
+name = "markup5ever"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45"
+dependencies = [
+ "log",
+ "phf 0.11.3",
+ "phf_codegen 0.11.3",
+ "string_cache",
+ "string_cache_codegen",
+ "tendril",
+]
+
+[[package]]
+name = "matchit"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
+
+[[package]]
+name = "md-5"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
+dependencies = [
+ "cfg-if",
+ "digest",
+]
+
[[package]]
name = "memchr"
-version = "2.7.4"
+version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "migrations_internals"
-version = "2.2.0"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd01039851e82f8799046eabbb354056283fb265c8ec0996af940f4e85a380ff"
+checksum = "36c791ecdf977c99f45f23280405d7723727470f6689a5e6dbf513ac547ae10d"
dependencies = [
"serde",
"toml",
@@ -2210,9 +2984,9 @@ dependencies = [
[[package]]
name = "migrations_macros"
-version = "2.2.0"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffb161cc72176cb37aa47f1fc520d3ef02263d67d661f44f05d05a079e1237fd"
+checksum = "36fc5ac76be324cfd2d3f2cf0fdf5d5d3c4f14ed8aaebadb09e304ba42282703"
dependencies = [
"migrations_internals",
"proc-macro2",
@@ -2237,25 +3011,32 @@ dependencies = [
[[package]]
name = "miniz_oxide"
-version = "0.8.5"
+version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
+ "simd-adler32",
]
[[package]]
name = "mio"
-version = "1.0.3"
+version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
+checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
dependencies = [
"libc",
"log",
- "wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys 0.52.0",
+ "wasi",
+ "windows-sys 0.61.2",
]
+[[package]]
+name = "multimap"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084"
+
[[package]]
name = "native-tls"
version = "0.2.14"
@@ -2268,11 +3049,17 @@ dependencies = [
"openssl-probe",
"openssl-sys",
"schannel",
- "security-framework",
+ "security-framework 2.11.1",
"security-framework-sys",
"tempfile",
]
+[[package]]
+name = "new_debug_unreachable"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
+
[[package]]
name = "nodrop"
version = "0.1.14"
@@ -2289,6 +3076,22 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "num-bigint-dig"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7"
+dependencies = [
+ "lazy_static",
+ "libm",
+ "num-integer",
+ "num-iter",
+ "num-traits",
+ "rand 0.8.5",
+ "smallvec",
+ "zeroize",
+]
+
[[package]]
name = "num-conv"
version = "0.1.0"
@@ -2304,6 +3107,17 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "num-iter"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -2311,38 +3125,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
+ "libm",
]
[[package]]
name = "num_cpus"
-version = "1.16.0"
+version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
-name = "object"
-version = "0.36.7"
+name = "oauth2"
+version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
+checksum = "c38841cdd844847e3e7c8d29cef9dcfed8877f8f56f9071f77843ecf3baf937f"
dependencies = [
- "memchr",
+ "base64 0.13.1",
+ "chrono",
+ "getrandom 0.2.16",
+ "http 0.2.12",
+ "rand 0.8.5",
+ "reqwest 0.11.27",
+ "serde",
+ "serde_json",
+ "serde_path_to_error",
+ "sha2",
+ "thiserror 1.0.69",
+ "url",
]
[[package]]
name = "once_cell"
-version = "1.21.1"
+version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
-name = "opaque-debug"
-version = "0.3.1"
+name = "once_cell_polyfill"
+version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "openapiv3-paper"
@@ -2350,18 +3176,50 @@ version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f21aa89c0b45d63c9a4976b0de5dcf4e041defc2cd9720820f0012f0046a0bc"
dependencies = [
- "indexmap 2.8.0",
+ "indexmap 2.12.1",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "openidconnect"
+version = "3.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f47e80a9cfae4462dd29c41e987edd228971d6565553fbc14b8a11e666d91590"
+dependencies = [
+ "base64 0.13.1",
+ "chrono",
+ "dyn-clone",
+ "ed25519-dalek",
+ "hmac",
+ "http 0.2.12",
+ "itertools 0.10.5",
+ "log",
+ "oauth2",
+ "p256 0.13.2",
+ "p384",
+ "rand 0.8.5",
+ "rsa",
"serde",
+ "serde-value",
+ "serde_derive",
"serde_json",
+ "serde_path_to_error",
+ "serde_plain",
+ "serde_with",
+ "sha2",
+ "subtle",
+ "thiserror 1.0.69",
+ "url",
]
[[package]]
name = "openssl"
-version = "0.10.72"
+version = "0.10.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
+checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.10.0",
"cfg-if",
"foreign-types",
"libc",
@@ -2378,7 +3236,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
@@ -2389,9 +3247,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "openssl-sys"
-version = "0.9.107"
+version = "0.9.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
+checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
dependencies = [
"cc",
"libc",
@@ -2399,6 +3257,56 @@ dependencies = [
"vcpkg",
]
+[[package]]
+name = "ordered-float"
+version = "2.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "outref"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e"
+
+[[package]]
+name = "p256"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594"
+dependencies = [
+ "ecdsa 0.14.8",
+ "elliptic-curve 0.12.3",
+ "sha2",
+]
+
+[[package]]
+name = "p256"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"
+dependencies = [
+ "ecdsa 0.16.9",
+ "elliptic-curve 0.13.8",
+ "primeorder",
+ "sha2",
+]
+
+[[package]]
+name = "p384"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6"
+dependencies = [
+ "ecdsa 0.16.9",
+ "elliptic-curve 0.13.8",
+ "primeorder",
+ "sha2",
+]
+
[[package]]
name = "paperclip"
version = "0.9.5"
@@ -2406,7 +3314,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa5b33308ca3f5902ccef8aa51f72dd71d6ee9f1c3cd04ac2e77eec33fe1da4f"
dependencies = [
"anyhow",
- "itertools",
+ "itertools 0.10.5",
"once_cell",
"openapiv3-paper",
"paperclip-actix",
@@ -2489,12 +3397,12 @@ dependencies = [
[[package]]
name = "parking_lot"
-version = "0.12.3"
+version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
- "parking_lot_core 0.9.10",
+ "parking_lot_core 0.9.12",
]
[[package]]
@@ -2513,32 +3421,97 @@ dependencies = [
[[package]]
name = "parking_lot_core"
-version = "0.9.10"
+version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall 0.5.10",
+ "redox_syscall 0.5.18",
"smallvec",
- "windows-targets 0.52.6",
+ "windows-link",
+]
+
+[[package]]
+name = "pbjson"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7e6349fa080353f4a597daffd05cb81572a9c031a6d4fff7e504947496fcc68"
+dependencies = [
+ "base64 0.21.7",
+ "serde",
+]
+
+[[package]]
+name = "pbjson-build"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6eea3058763d6e656105d1403cb04e0a41b7bbac6362d413e7c33be0c32279c9"
+dependencies = [
+ "heck 0.5.0",
+ "itertools 0.13.0",
+ "prost",
+ "prost-types",
+]
+
+[[package]]
+name = "pbjson-types"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e54e5e7bfb1652f95bc361d76f3c780d8e526b134b85417e774166ee941f0887"
+dependencies = [
+ "bytes",
+ "chrono",
+ "pbjson",
+ "pbjson-build",
+ "prost",
+ "prost-build",
+ "serde",
]
[[package]]
name = "pem"
-version = "3.0.5"
+version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3"
+checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be"
dependencies = [
"base64 0.22.1",
- "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "pem-rfc7468"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
+dependencies = [
+ "base64ct",
]
[[package]]
name = "percent-encoding"
-version = "2.3.1"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
+
+[[package]]
+name = "petgraph"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
+dependencies = [
+ "fixedbitset",
+ "indexmap 2.12.1",
+]
+
+[[package]]
+name = "phf"
+version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
+dependencies = [
+ "phf_shared 0.10.0",
+]
[[package]]
name = "phf"
@@ -2547,7 +3520,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
dependencies = [
"phf_macros",
- "phf_shared",
+ "phf_shared 0.11.3",
+]
+
+[[package]]
+name = "phf_codegen"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd"
+dependencies = [
+ "phf_generator 0.10.0",
+ "phf_shared 0.10.0",
+]
+
+[[package]]
+name = "phf_codegen"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
+dependencies = [
+ "phf_generator 0.11.3",
+ "phf_shared 0.11.3",
+]
+
+[[package]]
+name = "phf_generator"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
+dependencies = [
+ "phf_shared 0.10.0",
+ "rand 0.8.5",
]
[[package]]
@@ -2556,7 +3559,7 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
dependencies = [
- "phf_shared",
+ "phf_shared 0.11.3",
"rand 0.8.5",
]
@@ -2566,11 +3569,20 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
dependencies = [
- "phf_generator",
- "phf_shared",
+ "phf_generator 0.11.3",
+ "phf_shared 0.11.3",
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
+dependencies = [
+ "siphasher 0.3.11",
]
[[package]]
@@ -2579,7 +3591,27 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
dependencies = [
- "siphasher",
+ "siphasher 1.0.1",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.111",
]
[[package]]
@@ -2595,28 +3627,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
-name = "pkg-config"
-version = "0.3.32"
+name = "pkcs1"
+version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
+dependencies = [
+ "der 0.7.10",
+ "pkcs8 0.10.2",
+ "spki 0.7.3",
+]
[[package]]
-name = "polyval"
-version = "0.6.2"
+name = "pkcs8"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
+checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba"
dependencies = [
- "cfg-if",
- "cpufeatures",
- "opaque-debug",
- "universal-hash",
+ "der 0.6.1",
+ "spki 0.6.0",
]
+[[package]]
+name = "pkcs8"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
+dependencies = [
+ "der 0.7.10",
+ "spki 0.7.3",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+
[[package]]
name = "portable-atomic"
-version = "1.11.0"
+version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
+checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
[[package]]
name = "portable-atomic-util"
@@ -2628,99 +3679,190 @@ dependencies = [
]
[[package]]
-name = "powerfmt"
-version = "0.2.0"
+name = "potential_utf"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "pq-sys"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "574ddd6a267294433f140b02a726b0640c43cf7c6f717084684aaa3b285aba61"
+dependencies = [
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "precomputed-hash"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
+
+[[package]]
+name = "prettyplease"
+version = "0.2.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
+dependencies = [
+ "proc-macro2",
+ "syn 2.0.111",
+]
+
+[[package]]
+name = "primeorder"
+version = "0.13.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6"
+dependencies = [
+ "elliptic-curve 0.13.8",
+]
+
+[[package]]
+name = "proc-macro-error-attr2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "proc-macro-error2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
+dependencies = [
+ "proc-macro-error-attr2",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.111",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
+dependencies = [
+ "unicode-ident",
+]
[[package]]
-name = "ppv-lite86"
-version = "0.2.21"
+name = "prost"
+version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5"
dependencies = [
- "zerocopy",
+ "bytes",
+ "prost-derive",
]
[[package]]
-name = "pq-sys"
-version = "0.7.0"
+name = "prost-build"
+version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30b51d65ebe1cb1f40641b15abae017fed35ccdda46e3dab1ff8768f625a3222"
+checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf"
dependencies = [
- "libc",
- "vcpkg",
+ "heck 0.5.0",
+ "itertools 0.14.0",
+ "log",
+ "multimap",
+ "once_cell",
+ "petgraph",
+ "prettyplease",
+ "prost",
+ "prost-types",
+ "regex",
+ "syn 2.0.111",
+ "tempfile",
]
[[package]]
-name = "proc-macro-error"
-version = "1.0.4"
+name = "prost-derive"
+version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
dependencies = [
- "proc-macro-error-attr",
+ "anyhow",
+ "itertools 0.14.0",
"proc-macro2",
"quote",
- "syn 1.0.109",
- "version_check",
+ "syn 2.0.111",
]
[[package]]
-name = "proc-macro-error-attr"
-version = "1.0.4"
+name = "prost-types"
+version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16"
dependencies = [
- "proc-macro2",
- "quote",
- "version_check",
+ "prost",
]
[[package]]
-name = "proc-macro-error-attr2"
-version = "2.0.0"
+name = "pulldown-cmark"
+version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
+checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0"
dependencies = [
- "proc-macro2",
- "quote",
+ "bitflags 2.10.0",
+ "getopts",
+ "memchr",
+ "pulldown-cmark-escape",
+ "unicase",
]
[[package]]
-name = "proc-macro-error2"
-version = "2.0.1"
+name = "pulldown-cmark-escape"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
-dependencies = [
- "proc-macro-error-attr2",
- "proc-macro2",
- "quote",
- "syn 2.0.100",
-]
+checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
[[package]]
-name = "proc-macro2"
-version = "1.0.94"
+name = "quick-xml"
+version = "0.36.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
+checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe"
dependencies = [
- "unicode-ident",
+ "memchr",
]
[[package]]
name = "quote"
-version = "1.0.40"
+version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
-version = "5.2.0"
+version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "r2d2"
@@ -2729,7 +3871,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93"
dependencies = [
"log",
- "parking_lot 0.12.3",
+ "parking_lot 0.12.5",
"scheduled-thread-pool",
]
@@ -2746,13 +3888,12 @@ dependencies = [
[[package]]
name = "rand"
-version = "0.9.0"
+version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
+checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.3",
- "zerocopy",
]
[[package]]
@@ -2781,7 +3922,7 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
- "getrandom 0.2.15",
+ "getrandom 0.2.16",
]
[[package]]
@@ -2790,14 +3931,14 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
- "getrandom 0.3.2",
+ "getrandom 0.3.4",
]
[[package]]
name = "redis"
-version = "0.29.1"
+version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8034fb926579ff49d3fe58d288d5dcb580bf11e9bccd33224b45adebf0fd0c23"
+checksum = "1bc42f3a12fd4408ce64d8efef67048a924e543bd35c6591c0447fda9054695f"
dependencies = [
"arc-swap",
"bytes",
@@ -2808,7 +3949,7 @@ dependencies = [
"percent-encoding",
"pin-project-lite",
"ryu",
- "socket2",
+ "socket2 0.5.10",
"tokio",
"tokio-util",
"url",
@@ -2825,18 +3966,38 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.5.10"
+version = "0.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
+dependencies = [
+ "bitflags 2.10.0",
+]
+
+[[package]]
+name = "ref-cast"
+version = "1.0.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
+dependencies = [
+ "ref-cast-impl",
+]
+
+[[package]]
+name = "ref-cast-impl"
+version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
+checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
dependencies = [
- "bitflags 2.9.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.111",
]
[[package]]
name = "regex"
-version = "1.11.1"
+version = "1.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
dependencies = [
"aho-corasick",
"memchr",
@@ -2846,9 +4007,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.9"
+version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
+checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
dependencies = [
"aho-corasick",
"memchr",
@@ -2857,70 +4018,107 @@ dependencies = [
[[package]]
name = "regex-lite"
-version = "0.1.6"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
+checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da"
[[package]]
name = "regex-syntax"
-version = "0.8.5"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
[[package]]
name = "reqwest"
-version = "0.12.14"
+version = "0.11.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "989e327e510263980e231de548a33e63d34962d29ae61b467389a1a09627a254"
+checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
dependencies = [
- "base64 0.22.1",
+ "base64 0.21.7",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
- "h2 0.4.8",
- "http 1.3.1",
- "http-body",
+ "h2 0.3.27",
+ "http 0.2.12",
+ "http-body 0.4.6",
+ "hyper 0.14.32",
+ "hyper-rustls 0.24.2",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustls 0.21.12",
+ "rustls-pemfile 1.0.4",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper 0.1.2",
+ "system-configuration 0.5.1",
+ "tokio",
+ "tokio-rustls 0.24.1",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "webpki-roots",
+ "winreg",
+]
+
+[[package]]
+name = "reqwest"
+version = "0.12.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b4c14b2d9afca6a60277086b0cc6a6ae0b568f6f7916c943a8cdc79f8be240f"
+dependencies = [
+ "base64 0.22.1",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "h2 0.4.12",
+ "http 1.4.0",
+ "http-body 1.0.1",
"http-body-util",
- "hyper",
- "hyper-rustls",
+ "hyper 1.8.1",
+ "hyper-rustls 0.27.7",
"hyper-tls",
"hyper-util",
- "ipnet",
"js-sys",
"log",
"mime",
"native-tls",
- "once_cell",
"percent-encoding",
"pin-project-lite",
- "rustls-pemfile",
+ "rustls-pki-types",
"serde",
"serde_json",
"serde_urlencoded",
- "sync_wrapper",
- "system-configuration",
+ "sync_wrapper 1.0.2",
"tokio",
"tokio-native-tls",
- "tower",
+ "tower 0.5.2",
+ "tower-http",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "windows-registry",
]
[[package]]
name = "reqwest-middleware"
-version = "0.4.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64e8975513bd9a7a43aad01030e79b3498e05db14e9d945df6483e8cf9b8c4c4"
+checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e"
dependencies = [
"anyhow",
"async-trait",
- "http 1.3.1",
- "reqwest",
+ "http 1.4.0",
+ "reqwest 0.12.26",
"serde",
"thiserror 1.0.69",
"tower-service",
@@ -2935,11 +4133,11 @@ dependencies = [
"anyhow",
"async-trait",
"futures",
- "getrandom 0.2.15",
- "http 1.3.1",
- "hyper",
+ "getrandom 0.2.16",
+ "http 1.4.0",
+ "hyper 1.8.1",
"parking_lot 0.11.2",
- "reqwest",
+ "reqwest 0.12.26",
"reqwest-middleware",
"retry-policies",
"thiserror 1.0.69",
@@ -2957,6 +4155,27 @@ dependencies = [
"rand 0.8.5",
]
+[[package]]
+name = "rfc6979"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb"
+dependencies = [
+ "crypto-bigint 0.4.9",
+ "hmac",
+ "zeroize",
+]
+
+[[package]]
+name = "rfc6979"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
+dependencies = [
+ "hmac",
+ "subtle",
+]
+
[[package]]
name = "ring"
version = "0.17.14"
@@ -2965,18 +4184,12 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
dependencies = [
"cc",
"cfg-if",
- "getrandom 0.2.15",
+ "getrandom 0.2.16",
"libc",
"untrusted",
"windows-sys 0.52.0",
]
-[[package]]
-name = "route-recognizer"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746"
-
[[package]]
name = "roxmltree"
version = "0.14.1"
@@ -2987,37 +4200,96 @@ dependencies = [
]
[[package]]
-name = "rustc-demangle"
-version = "0.1.24"
+name = "rsa"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88"
+dependencies = [
+ "const-oid",
+ "digest",
+ "num-bigint-dig",
+ "num-integer",
+ "num-traits",
+ "pkcs1",
+ "pkcs8 0.10.2",
+ "rand_core 0.6.4",
+ "signature 2.2.0",
+ "spki 0.7.3",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
[[package]]
name = "rustix"
-version = "1.0.2"
+version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825"
+checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.10.0",
"errno",
"libc",
"linux-raw-sys",
- "windows-sys 0.59.0",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustls"
+version = "0.21.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
+dependencies = [
+ "log",
+ "ring",
+ "rustls-webpki 0.101.7",
+ "sct",
]
[[package]]
name = "rustls"
-version = "0.23.25"
+version = "0.23.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c"
+checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
dependencies = [
+ "aws-lc-rs",
+ "log",
"once_cell",
+ "ring",
"rustls-pki-types",
- "rustls-webpki",
+ "rustls-webpki 0.103.8",
"subtle",
"zeroize",
]
+[[package]]
+name = "rustls-native-certs"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923"
+dependencies = [
+ "openssl-probe",
+ "rustls-pki-types",
+ "schannel",
+ "security-framework 3.5.1",
+]
+
+[[package]]
+name = "rustls-pemfile"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
+dependencies = [
+ "base64 0.21.7",
+]
+
[[package]]
name = "rustls-pemfile"
version = "2.2.0"
@@ -3029,16 +4301,30 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
-version = "1.11.0"
+version = "1.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c"
+dependencies = [
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.101.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
+checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
+dependencies = [
+ "ring",
+ "untrusted",
+]
[[package]]
name = "rustls-webpki"
-version = "0.103.0"
+version = "0.103.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0aa4eeac2588ffff23e9d7a7e9b3f971c5fb5b7ebc9452745e0c232c64f83b2f"
+checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
dependencies = [
+ "aws-lc-rs",
"ring",
"rustls-pki-types",
"untrusted",
@@ -3046,9 +4332,9 @@ dependencies = [
[[package]]
name = "rustversion"
-version = "1.0.20"
+version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "ryu"
@@ -3058,11 +4344,11 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "schannel"
-version = "0.1.27"
+version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
+checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1"
dependencies = [
- "windows-sys 0.59.0",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -3071,14 +4357,32 @@ version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19"
dependencies = [
- "parking_lot 0.12.3",
+ "parking_lot 0.12.5",
]
[[package]]
-name = "scoped-tls-hkt"
-version = "0.1.5"
+name = "schemars"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
+dependencies = [
+ "dyn-clone",
+ "ref-cast",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "schemars"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9603871ffe5df3ac39cb624790c296dbd47a400d202f56bf3e414045099524d"
+checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289"
+dependencies = [
+ "dyn-clone",
+ "ref-cast",
+ "serde",
+ "serde_json",
+]
[[package]]
name = "scoped_threadpool"
@@ -3092,14 +4396,81 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+[[package]]
+name = "scraper"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b90460b31bfe1fc07be8262e42c665ad97118d4585869de9345a84d501a9eaf0"
+dependencies = [
+ "ahash",
+ "cssparser",
+ "ego-tree",
+ "getopts",
+ "html5ever",
+ "once_cell",
+ "selectors",
+ "tendril",
+]
+
+[[package]]
+name = "sct"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
+dependencies = [
+ "ring",
+ "untrusted",
+]
+
+[[package]]
+name = "sec1"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928"
+dependencies = [
+ "base16ct 0.1.1",
+ "der 0.6.1",
+ "generic-array",
+ "pkcs8 0.9.0",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "sec1"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
+dependencies = [
+ "base16ct 0.2.0",
+ "der 0.7.10",
+ "generic-array",
+ "pkcs8 0.10.2",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "security-framework"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [
- "bitflags 2.9.0",
- "core-foundation",
+ "bitflags 2.10.0",
+ "core-foundation 0.9.4",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework"
+version = "3.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef"
+dependencies = [
+ "bitflags 2.10.0",
+ "core-foundation 0.10.1",
"core-foundation-sys",
"libc",
"security-framework-sys",
@@ -3107,73 +4478,121 @@ dependencies = [
[[package]]
name = "security-framework-sys"
-version = "2.14.0"
+version = "2.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
+checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0"
dependencies = [
"core-foundation-sys",
"libc",
]
+[[package]]
+name = "selectors"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06"
+dependencies = [
+ "bitflags 2.10.0",
+ "cssparser",
+ "derive_more 0.99.20",
+ "fxhash",
+ "log",
+ "new_debug_unreachable",
+ "phf 0.10.1",
+ "phf_codegen 0.10.0",
+ "precomputed-hash",
+ "servo_arc",
+ "smallvec",
+]
+
[[package]]
name = "semver"
-version = "1.0.26"
+version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
+checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
[[package]]
name = "serde"
-version = "1.0.219"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
+ "serde_core",
"serde_derive",
]
[[package]]
-name = "serde-wasm-bindgen"
-version = "0.3.1"
+name = "serde-value"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "618365e8e586c22123d692b72a7d791d5ee697817b65a218cdf12a98870af0f7"
+checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
dependencies = [
- "fnv",
- "js-sys",
+ "ordered-float",
"serde",
- "wasm-bindgen",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.219"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
name = "serde_json"
-version = "1.0.140"
+version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
+ "serde_core",
]
[[package]]
-name = "serde_spanned"
-version = "0.6.8"
+name = "serde_path_to_error"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
+dependencies = [
+ "itoa",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "serde_plain"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50"
dependencies = [
"serde",
]
+[[package]]
+name = "serde_spanned"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392"
+dependencies = [
+ "serde_core",
+]
+
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@@ -3186,19 +4605,59 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde_with"
+version = "3.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7"
+dependencies = [
+ "base64 0.22.1",
+ "chrono",
+ "hex",
+ "indexmap 1.9.3",
+ "indexmap 2.12.1",
+ "schemars 0.9.0",
+ "schemars 1.1.0",
+ "serde_core",
+ "serde_json",
+ "serde_with_macros",
+ "time",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "3.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.111",
+]
+
[[package]]
name = "serde_yaml"
version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
- "indexmap 2.8.0",
+ "indexmap 2.12.1",
"itoa",
"ryu",
"serde",
"unsafe-libyaml",
]
+[[package]]
+name = "servo_arc"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d036d71a959e00c77a63538b90a6c2390969f9772b096ea837205c6bd0491a44"
+dependencies = [
+ "stable_deref_trait",
+]
+
[[package]]
name = "sha1"
version = "0.10.6"
@@ -3212,9 +4671,9 @@ dependencies = [
[[package]]
name = "sha2"
-version = "0.10.8"
+version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
@@ -3223,9 +4682,9 @@ dependencies = [
[[package]]
name = "shell-words"
-version = "1.1.0"
+version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
+checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77"
[[package]]
name = "shlex"
@@ -3235,13 +4694,39 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook-registry"
-version = "1.4.2"
+version = "1.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
+checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad"
dependencies = [
"libc",
]
+[[package]]
+name = "signature"
+version = "1.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
+dependencies = [
+ "digest",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "signature"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
+dependencies = [
+ "digest",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "simd-adler32"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
+
[[package]]
name = "simple_asn1"
version = "0.6.3"
@@ -3250,10 +4735,16 @@ checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb"
dependencies = [
"num-bigint",
"num-traits",
- "thiserror 2.0.12",
+ "thiserror 2.0.17",
"time",
]
+[[package]]
+name = "siphasher"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
+
[[package]]
name = "siphasher"
version = "1.0.1"
@@ -3262,18 +4753,15 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
[[package]]
name = "slab"
-version = "0.4.9"
+version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
-dependencies = [
- "autocfg",
-]
+checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
[[package]]
name = "smallvec"
-version = "1.14.0"
+version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "smartstring"
@@ -3288,19 +4776,61 @@ dependencies = [
[[package]]
name = "socket2"
-version = "0.5.8"
+version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
+checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
+[[package]]
+name = "socket2"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
+dependencies = [
+ "libc",
+ "windows-sys 0.60.2",
+]
+
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+
+[[package]]
+name = "spin"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591"
+
+[[package]]
+name = "spki"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b"
+dependencies = [
+ "base64ct",
+ "der 0.6.1",
+]
+
+[[package]]
+name = "spki"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
+dependencies = [
+ "base64ct",
+ "der 0.7.10",
+]
+
[[package]]
name = "stable_deref_trait"
-version = "1.2.0"
+version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
[[package]]
name = "static_assertions"
@@ -3308,6 +4838,31 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+[[package]]
+name = "string_cache"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f"
+dependencies = [
+ "new_debug_unreachable",
+ "parking_lot 0.12.5",
+ "phf_shared 0.11.3",
+ "precomputed-hash",
+ "serde",
+]
+
+[[package]]
+name = "string_cache_codegen"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0"
+dependencies = [
+ "phf_generator 0.11.3",
+ "phf_shared 0.11.3",
+ "proc-macro2",
+ "quote",
+]
+
[[package]]
name = "strsim"
version = "0.11.1"
@@ -3322,11 +4877,11 @@ checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
[[package]]
name = "strum"
-version = "0.27.1"
+version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
+checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
dependencies = [
- "strum_macros 0.27.1",
+ "strum_macros 0.27.2",
]
[[package]]
@@ -3344,15 +4899,14 @@ dependencies = [
[[package]]
name = "strum_macros"
-version = "0.27.1"
+version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
+checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "rustversion",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
@@ -3374,15 +4928,21 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.100"
+version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
+[[package]]
+name = "sync_wrapper"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
+
[[package]]
name = "sync_wrapper"
version = "1.0.2"
@@ -3394,13 +4954,24 @@ dependencies = [
[[package]]
name = "synstructure"
-version = "0.13.1"
+version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
+]
+
+[[package]]
+name = "system-configuration"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation 0.9.4",
+ "system-configuration-sys 0.5.0",
]
[[package]]
@@ -3409,9 +4980,19 @@ version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
dependencies = [
- "bitflags 2.9.0",
- "core-foundation",
- "system-configuration-sys",
+ "bitflags 2.10.0",
+ "core-foundation 0.9.4",
+ "system-configuration-sys 0.6.0",
+]
+
+[[package]]
+name = "system-configuration-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
]
[[package]]
@@ -3426,15 +5007,26 @@ dependencies = [
[[package]]
name = "tempfile"
-version = "3.19.0"
+version = "3.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "488960f40a3fd53d72c2a29a58722561dee8afdd175bd88e3db4677d7b2ba600"
+checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
dependencies = [
"fastrand",
- "getrandom 0.3.2",
+ "getrandom 0.3.4",
"once_cell",
"rustix",
- "windows-sys 0.59.0",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "tendril"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0"
+dependencies = [
+ "futf",
+ "mac",
+ "utf-8",
]
[[package]]
@@ -3448,11 +5040,11 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "2.0.12"
+version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
dependencies = [
- "thiserror-impl 2.0.12",
+ "thiserror-impl 2.0.17",
]
[[package]]
@@ -3463,34 +5055,35 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
name = "thiserror-impl"
-version = "2.0.12"
+version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
+checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
name = "thoth"
version = "0.13.15"
dependencies = [
+ "base64 0.22.1",
"clap",
"dialoguer",
"dotenv",
"lazy_static",
"thoth-api",
"thoth-api-server",
- "thoth-app-server",
"thoth-errors",
"thoth-export-server",
"tokio",
+ "zitadel",
]
[[package]]
@@ -3499,6 +5092,11 @@ version = "0.13.15"
dependencies = [
"actix-web",
"argon2rs",
+ "aws-config",
+ "aws-credential-types",
+ "aws-sdk-cloudfront",
+ "aws-sdk-s3",
+ "base64 0.22.1",
"chrono",
"deadpool-redis",
"diesel",
@@ -3506,19 +5104,24 @@ dependencies = [
"diesel-derive-newtype",
"diesel_migrations",
"dotenv",
+ "fs2",
"futures",
+ "hex",
"isbn",
"jsonwebtoken",
"juniper",
"lazy_static",
- "rand 0.9.0",
+ "pulldown-cmark",
+ "rand 0.9.2",
"regex",
+ "scraper",
"serde",
"serde_json",
- "strum 0.27.1",
+ "strum 0.27.2",
"thoth-errors",
"tokio",
"uuid",
+ "zitadel",
]
[[package]]
@@ -3527,51 +5130,15 @@ version = "0.13.15"
dependencies = [
"actix-cors",
"actix-http",
- "actix-identity",
- "actix-session",
"actix-web",
+ "base64 0.22.1",
"env_logger",
"futures-util",
"log",
"serde",
- "serde_json",
- "thoth-api",
- "thoth-errors",
-]
-
-[[package]]
-name = "thoth-app"
-version = "0.13.15"
-dependencies = [
- "chrono",
- "dotenv",
- "gloo-storage 0.3.0",
- "gloo-timers 0.3.0",
- "reqwest",
- "semver",
- "serde",
- "serde_json",
- "thiserror 2.0.12",
"thoth-api",
"thoth-errors",
- "uuid",
- "wasm-bindgen",
- "wasm-logger",
- "web-sys",
- "yew 0.19.3",
- "yew-agent",
- "yew-router",
- "yewtil",
-]
-
-[[package]]
-name = "thoth-app-server"
-version = "0.13.15"
-dependencies = [
- "actix-cors",
- "actix-web",
- "dotenv",
- "env_logger",
+ "zitadel",
]
[[package]]
@@ -3580,7 +5147,7 @@ version = "0.13.15"
dependencies = [
"chrono",
"graphql_client",
- "reqwest",
+ "reqwest 0.12.26",
"reqwest-middleware",
"reqwest-retry",
"serde",
@@ -3602,15 +5169,15 @@ dependencies = [
"diesel",
"juniper",
"marc",
- "phf",
- "reqwest",
+ "phf 0.11.3",
+ "reqwest 0.12.26",
"reqwest-middleware",
"serde",
"serde_json",
- "thiserror 2.0.12",
+ "thiserror 2.0.17",
+ "tonic",
"uuid",
"xml-rs",
- "yewtil",
]
[[package]]
@@ -3629,6 +5196,7 @@ dependencies = [
"log",
"marc",
"paperclip",
+ "quick-xml",
"regex",
"serde",
"serde_json",
@@ -3641,9 +5209,9 @@ dependencies = [
[[package]]
name = "time"
-version = "0.3.40"
+version = "0.3.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618"
+checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
dependencies = [
"deranged",
"itoa",
@@ -3656,15 +5224,15 @@ dependencies = [
[[package]]
name = "time-core"
-version = "0.1.4"
+version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
+checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
[[package]]
name = "time-macros"
-version = "0.2.21"
+version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29aa485584182073ed57fd5004aa09c371f021325014694e432313345865fd04"
+checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
dependencies = [
"num-conv",
"time-core",
@@ -3672,9 +5240,9 @@ dependencies = [
[[package]]
name = "tinystr"
-version = "0.7.6"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
+checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
dependencies = [
"displaydoc",
"zerovec",
@@ -3682,31 +5250,30 @@ dependencies = [
[[package]]
name = "tokio"
-version = "1.44.2"
+version = "1.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
+checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
dependencies = [
- "backtrace",
"bytes",
"libc",
"mio",
- "parking_lot 0.12.3",
+ "parking_lot 0.12.5",
"pin-project-lite",
"signal-hook-registry",
- "socket2",
+ "socket2 0.6.1",
"tokio-macros",
- "windows-sys 0.52.0",
+ "windows-sys 0.61.2",
]
[[package]]
name = "tokio-macros"
-version = "2.5.0"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
+checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
@@ -3721,19 +5288,40 @@ dependencies = [
[[package]]
name = "tokio-rustls"
-version = "0.26.2"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
+dependencies = [
+ "rustls 0.21.12",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
+checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
dependencies = [
- "rustls",
+ "rustls 0.23.35",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-stream"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-util"
-version = "0.7.14"
+version = "0.7.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034"
+checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594"
dependencies = [
"bytes",
"futures-core",
@@ -3744,38 +5332,99 @@ dependencies = [
[[package]]
name = "toml"
-version = "0.8.20"
+version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
+checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8"
dependencies = [
- "serde",
+ "serde_core",
"serde_spanned",
"toml_datetime",
- "toml_edit",
+ "toml_parser",
+ "winnow",
]
[[package]]
name = "toml_datetime"
-version = "0.6.8"
+version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533"
dependencies = [
- "serde",
+ "serde_core",
]
[[package]]
-name = "toml_edit"
-version = "0.22.24"
+name = "toml_parser"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
+checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e"
dependencies = [
- "indexmap 2.8.0",
- "serde",
- "serde_spanned",
- "toml_datetime",
"winnow",
]
+[[package]]
+name = "tonic"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52"
+dependencies = [
+ "async-stream",
+ "async-trait",
+ "axum",
+ "base64 0.22.1",
+ "bytes",
+ "h2 0.4.12",
+ "http 1.4.0",
+ "http-body 1.0.1",
+ "http-body-util",
+ "hyper 1.8.1",
+ "hyper-timeout",
+ "hyper-util",
+ "percent-encoding",
+ "pin-project",
+ "prost",
+ "rustls-native-certs",
+ "rustls-pemfile 2.2.0",
+ "socket2 0.5.10",
+ "tokio",
+ "tokio-rustls 0.26.4",
+ "tokio-stream",
+ "tower 0.4.13",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "tonic-types"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0081d8ee0847d01271392a5aebe960a4600f5d4da6c67648a6382a0940f8b367"
+dependencies = [
+ "prost",
+ "prost-types",
+ "tonic",
+]
+
+[[package]]
+name = "tower"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "indexmap 1.9.3",
+ "pin-project",
+ "pin-project-lite",
+ "rand 0.8.5",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
[[package]]
name = "tower"
version = "0.5.2"
@@ -3785,12 +5434,30 @@ dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
- "sync_wrapper",
+ "sync_wrapper 1.0.2",
"tokio",
"tower-layer",
"tower-service",
]
+[[package]]
+name = "tower-http"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
+dependencies = [
+ "bitflags 2.10.0",
+ "bytes",
+ "futures-util",
+ "http 1.4.0",
+ "http-body 1.0.1",
+ "iri-string",
+ "pin-project-lite",
+ "tower 0.5.2",
+ "tower-layer",
+ "tower-service",
+]
+
[[package]]
name = "tower-layer"
version = "0.3.3"
@@ -3805,9 +5472,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
-version = "0.1.41"
+version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647"
dependencies = [
"log",
"pin-project-lite",
@@ -3817,20 +5484,20 @@ dependencies = [
[[package]]
name = "tracing-attributes"
-version = "0.1.28"
+version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
name = "tracing-core"
-version = "0.1.33"
+version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
+checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c"
dependencies = [
"once_cell",
]
@@ -3843,9 +5510,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "typenum"
-version = "1.18.0"
+version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
+checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
[[package]]
name = "unicase"
@@ -3855,15 +5522,21 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
[[package]]
name = "unicode-ident"
-version = "1.0.18"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-width"
-version = "0.2.0"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
+checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "unicode-xid"
@@ -3871,16 +5544,6 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
-[[package]]
-name = "universal-hash"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
-dependencies = [
- "crypto-common",
- "subtle",
-]
-
[[package]]
name = "unsafe-libyaml"
version = "0.2.11"
@@ -3895,20 +5558,27 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "url"
-version = "2.5.4"
+version = "2.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
+checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
+ "serde",
]
[[package]]
-name = "utf16_iter"
-version = "1.0.5"
+name = "urlencoding"
+version = "2.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
+
+[[package]]
+name = "utf-8"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
+checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "utf8_iter"
@@ -3924,13 +5594,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
-version = "1.16.0"
+version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
+checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
dependencies = [
- "getrandom 0.3.2",
+ "getrandom 0.3.4",
"js-sys",
- "serde",
+ "serde_core",
"wasm-bindgen",
]
@@ -3952,6 +5622,12 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+[[package]]
+name = "vsimd"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64"
+
[[package]]
name = "want"
version = "0.3.1"
@@ -3963,52 +5639,37 @@ dependencies = [
[[package]]
name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
+version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
-name = "wasi"
-version = "0.14.2+wasi-0.2.4"
+name = "wasip2"
+version = "1.0.1+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
dependencies = [
- "wit-bindgen-rt",
+ "wit-bindgen",
]
[[package]]
name = "wasm-bindgen"
-version = "0.2.100"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
+checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
- "serde",
- "serde_json",
"wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
-dependencies = [
- "bumpalo",
- "log",
- "proc-macro2",
- "quote",
- "syn 2.0.100",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.50"
+version = "0.4.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
+checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c"
dependencies = [
"cfg-if",
"js-sys",
@@ -4019,9 +5680,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.100"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
+checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -4029,37 +5690,26 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.100"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
+checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
dependencies = [
+ "bumpalo",
"proc-macro2",
"quote",
- "syn 2.0.100",
- "wasm-bindgen-backend",
+ "syn 2.0.111",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.100"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
dependencies = [
"unicode-ident",
]
-[[package]]
-name = "wasm-logger"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "074649a66bb306c8f2068c9016395fa65d8e08d2affcbf95acf3c24c3ab19718"
-dependencies = [
- "log",
- "wasm-bindgen",
- "web-sys",
-]
-
[[package]]
name = "wasm-timer"
version = "0.2.5"
@@ -4077,14 +5727,20 @@ dependencies = [
[[package]]
name = "web-sys"
-version = "0.3.77"
+version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
+checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
dependencies = [
"js-sys",
"wasm-bindgen",
]
+[[package]]
+name = "webpki-roots"
+version = "0.25.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
+
[[package]]
name = "winapi"
version = "0.3.9"
@@ -4109,48 +5765,83 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
-version = "0.52.0"
+version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
- "windows-targets 0.52.6",
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.111",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.111",
]
[[package]]
name = "windows-link"
-version = "0.1.0"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-registry"
-version = "0.4.0"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
+checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
dependencies = [
+ "windows-link",
"windows-result",
"windows-strings",
- "windows-targets 0.53.0",
]
[[package]]
name = "windows-result"
-version = "0.3.1"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
-version = "0.3.1"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
"windows-link",
]
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
[[package]]
name = "windows-sys"
version = "0.52.0"
@@ -4169,6 +5860,39 @@ dependencies = [
"windows-targets 0.52.6",
]
+[[package]]
+name = "windows-sys"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
+dependencies = [
+ "windows-targets 0.53.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
[[package]]
name = "windows-targets"
version = "0.52.6"
@@ -4187,20 +5911,27 @@ dependencies = [
[[package]]
name = "windows-targets"
-version = "0.53.0"
+version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
+checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
- "windows_aarch64_gnullvm 0.53.0",
- "windows_aarch64_msvc 0.53.0",
- "windows_i686_gnu 0.53.0",
- "windows_i686_gnullvm 0.53.0",
- "windows_i686_msvc 0.53.0",
- "windows_x86_64_gnu 0.53.0",
- "windows_x86_64_gnullvm 0.53.0",
- "windows_x86_64_msvc 0.53.0",
+ "windows-link",
+ "windows_aarch64_gnullvm 0.53.1",
+ "windows_aarch64_msvc 0.53.1",
+ "windows_i686_gnu 0.53.1",
+ "windows_i686_gnullvm 0.53.1",
+ "windows_i686_msvc 0.53.1",
+ "windows_x86_64_gnu 0.53.1",
+ "windows_x86_64_gnullvm 0.53.1",
+ "windows_x86_64_msvc 0.53.1",
]
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
@@ -4209,9 +5940,15 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.53.0"
+version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
+checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
@@ -4221,9 +5958,15 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
-version = "0.53.0"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
@@ -4233,9 +5976,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
-version = "0.53.0"
+version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
+checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
@@ -4245,9 +5988,15 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
-version = "0.53.0"
+version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
+checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
@@ -4257,9 +6006,15 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
-version = "0.53.0"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
@@ -4269,9 +6024,15 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.53.0"
+version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
+checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
@@ -4281,9 +6042,15 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.53.0"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
@@ -4293,45 +6060,43 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.53.0"
+version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
+checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "winnow"
-version = "0.7.4"
+version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
-dependencies = [
- "memchr",
-]
+checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
[[package]]
-name = "wit-bindgen-rt"
-version = "0.39.0"
+name = "winreg"
+version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
- "bitflags 2.9.0",
+ "cfg-if",
+ "windows-sys 0.48.0",
]
[[package]]
-name = "write16"
-version = "1.0.0"
+name = "wit-bindgen"
+version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
+checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
[[package]]
name = "writeable"
-version = "0.5.5"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
[[package]]
name = "xml-rs"
-version = "0.8.25"
+version = "0.8.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4"
+checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f"
[[package]]
name = "xmlparser"
@@ -4339,152 +6104,12 @@ version = "0.13.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4"
-[[package]]
-name = "yew"
-version = "0.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4d5154faef86dddd2eb333d4755ea5643787d20aca683e58759b0e53351409f"
-dependencies = [
- "anyhow",
- "anymap",
- "bincode",
- "cfg-if",
- "cfg-match",
- "console_error_panic_hook",
- "gloo 0.2.1",
- "http 0.2.12",
- "indexmap 1.9.3",
- "js-sys",
- "log",
- "ryu",
- "serde",
- "serde_json",
- "slab",
- "thiserror 1.0.69",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "yew-macro 0.18.0",
-]
-
-[[package]]
-name = "yew"
-version = "0.19.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a1ccb53e57d3f7d847338cf5758befa811cabe207df07f543c06f502f9998cd"
-dependencies = [
- "console_error_panic_hook",
- "gloo 0.4.2",
- "gloo-utils 0.1.7",
- "indexmap 1.9.3",
- "js-sys",
- "scoped-tls-hkt",
- "slab",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "yew-macro 0.19.3",
-]
-
-[[package]]
-name = "yew-agent"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "616700dc3851945658c44ba4477ede6b77c795462fbbb9b0ad9a8b6273a3ca77"
-dependencies = [
- "anymap2",
- "bincode",
- "gloo-console",
- "gloo-utils 0.1.7",
- "js-sys",
- "serde",
- "slab",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "yew 0.19.3",
-]
-
-[[package]]
-name = "yew-macro"
-version = "0.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6e23bfe3dc3933fbe9592d149c9985f3047d08c637a884b9344c21e56e092ef"
-dependencies = [
- "boolinator",
- "lazy_static",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "yew-macro"
-version = "0.19.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fab79082b556d768d6e21811869c761893f0450e1d550a67892b9bce303b7bb"
-dependencies = [
- "boolinator",
- "lazy_static",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "yew-router"
-version = "0.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "155804f6f3aa309f596d5c3fa14486a94e7756f1edd7634569949e401d5099f2"
-dependencies = [
- "gloo 0.4.2",
- "gloo-utils 0.1.7",
- "js-sys",
- "route-recognizer",
- "serde",
- "serde-wasm-bindgen",
- "serde_urlencoded",
- "thiserror 1.0.69",
- "wasm-bindgen",
- "web-sys",
- "yew 0.19.3",
- "yew-router-macro",
-]
-
-[[package]]
-name = "yew-router-macro"
-version = "0.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39049d193b52eaad4ffc80916bf08806d142c90b5edcebd527644de438a7e19a"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "yewtil"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8543663ac49cd613df079282a1d8bdbdebdad6e02bac229f870fd4237b5d9aaa"
-dependencies = [
- "log",
- "serde",
- "serde_json",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "yew 0.18.0",
-]
-
[[package]]
name = "yoke"
-version = "0.7.5"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
+checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
dependencies = [
- "serde",
"stable_deref_trait",
"yoke-derive",
"zerofrom",
@@ -4492,34 +6117,34 @@ dependencies = [
[[package]]
name = "yoke-derive"
-version = "0.7.5"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
+checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
"synstructure",
]
[[package]]
name = "zerocopy"
-version = "0.8.23"
+version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6"
+checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
-version = "0.8.23"
+version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154"
+checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
]
[[package]]
@@ -4539,21 +6164,32 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
"synstructure",
]
[[package]]
name = "zeroize"
-version = "1.8.1"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
+
+[[package]]
+name = "zerotrie"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
[[package]]
name = "zerovec"
-version = "0.10.4"
+version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
dependencies = [
"yoke",
"zerofrom",
@@ -4562,13 +6198,37 @@ dependencies = [
[[package]]
name = "zerovec-derive"
-version = "0.10.3"
+version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.100",
+ "syn 2.0.111",
+]
+
+[[package]]
+name = "zitadel"
+version = "5.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "168b66027ca4fd1aa3c529f1359a59f94495db612b57223bf933b2900df4e052"
+dependencies = [
+ "actix-web",
+ "base64-compat",
+ "custom_error",
+ "jsonwebtoken",
+ "openidconnect",
+ "pbjson-types",
+ "prost",
+ "prost-types",
+ "reqwest 0.11.27",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "time",
+ "tokio",
+ "tonic",
+ "tonic-types",
]
[[package]]
@@ -4582,18 +6242,18 @@ dependencies = [
[[package]]
name = "zstd-safe"
-version = "7.2.3"
+version = "7.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3051792fbdc2e1e143244dc28c60f73d8470e93f3f9cbd0ead44da5ed802722"
+checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
-version = "2.0.14+zstd.1.5.7"
+version = "2.0.16+zstd.1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fb060d4926e4ac3a3ad15d864e99ceb5f343c6b34f5bd6d81ae6ed417311be5"
+checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748"
dependencies = [
"cc",
"pkg-config",
diff --git a/Cargo.toml b/Cargo.toml
index fc6e98d7..ad60d07f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,16 +12,17 @@ readme = "README.md"
maintenance = { status = "actively-developed" }
[workspace]
-members = ["thoth-api", "thoth-api-server", "thoth-app", "thoth-app-server", "thoth-client", "thoth-errors", "thoth-export-server"]
+members = ["thoth-api", "thoth-api-server", "thoth-client", "thoth-errors", "thoth-export-server"]
[dependencies]
thoth-api = { version = "=0.13.15", path = "thoth-api", features = ["backend"] }
thoth-api-server = { version = "=0.13.15", path = "thoth-api-server" }
-thoth-app-server = { version = "=0.13.15", path = "thoth-app-server" }
thoth-errors = { version = "=0.13.15", path = "thoth-errors" }
thoth-export-server = { version = "=0.13.15", path = "thoth-export-server" }
+base64 = "0.22.1"
clap = { version = "4.5.32", features = ["cargo", "env"] }
dialoguer = { version = "0.11.0", features = ["password"] }
dotenv = "0.15.0"
lazy_static = "1.5.0"
tokio = { version = "1.44.1", features = ["rt", "rt-multi-thread", "macros"] }
+zitadel = { version = "5.5.1", features = ["api", "interceptors"]}
diff --git a/Dockerfile b/Dockerfile
index 89a928a0..c5e51447 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,24 +1,23 @@
-FROM rust:1.90.0
+FROM ghcr.io/thoth-pub/muslrust AS build
-ARG THOTH_GRAPHQL_API=https://api.thoth.pub
ARG THOTH_EXPORT_API=https://export.thoth.pub
-ENV THOTH_GRAPHQL_API=${THOTH_GRAPHQL_API}
ENV THOTH_EXPORT_API=${THOTH_EXPORT_API}
-# Install build dependencies
-RUN apt-get update && apt-get install -y \
- libssl-dev \
- pkg-config \
- && rm -rf /var/lib/apt/lists/*
-
# Get source
COPY . .
# Build Thoth for release from source
RUN cargo build --release
-# Move the binary to root for easier access
-RUN mv target/release/thoth /thoth
+FROM scratch
+
+# Get thoth binary
+COPY --from=build \
+ /volume/target/x86_64-unknown-linux-musl/release/thoth /
+
+# Get CA certificates
+COPY --from=build \
+ /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
# Expose thoth's default ports
EXPOSE 8080
@@ -29,4 +28,4 @@ EXPOSE 8181
ENTRYPOINT ["/thoth"]
# By default run `thoth init` (runs migrations and starts the server on port 8080)
-CMD ["init"]
+CMD ["init"]
\ No newline at end of file
diff --git a/Dockerfile.dev b/Dockerfile.dev
deleted file mode 100644
index 8107eed2..00000000
--- a/Dockerfile.dev
+++ /dev/null
@@ -1,59 +0,0 @@
-FROM rust
-
-ENV TRUNK_VERSION=0.21.9
-
-ARG THOTH_GRAPHQL_API=http://localhost:8000
-ARG THOTH_EXPORT_API=http://localhost:8181
-ENV THOTH_GRAPHQL_API=${THOTH_GRAPHQL_API}
-ENV THOTH_EXPORT_API=${THOTH_EXPORT_API}
-
-WORKDIR /usr/src/thoth
-
-# Expose thoth's default ports
-EXPOSE 8080
-EXPOSE 8000
-EXPOSE 8181
-
-# Install build dependencies for thoth-app
-RUN rustup target add wasm32-unknown-unknown
-RUN cargo install trunk --version ${TRUNK_VERSION}
-
-# Use dummy file to force cargo to install dependencies without compiling code.
-# We need to get dummy lib files for all members of the workspace, and their cargo files,
-# then we run wasm-pack and cargo build to download and compile all project dependencies.
-RUN mkdir src
-RUN echo "fn main() {}" > src/main.rs
-COPY Cargo.lock .
-COPY Cargo.toml .
-COPY thoth-api/Cargo.toml thoth-api/Cargo.toml
-COPY thoth-api-server/Cargo.toml thoth-api-server/Cargo.toml
-COPY thoth-app/Cargo.toml thoth-app/Cargo.toml
-COPY thoth-app-server/Cargo.toml thoth-app-server/Cargo.toml
-COPY thoth-client/Cargo.toml thoth-client/Cargo.toml
-COPY thoth-errors/Cargo.toml thoth-errors/Cargo.toml
-COPY thoth-export-server/Cargo.toml thoth-export-server/Cargo.toml
-RUN mkdir thoth-api/src thoth-api-server/src thoth-app/src \
- thoth-app-server/src thoth-client/src thoth-errors/src \
- thoth-export-server/src
-RUN touch thoth-api/src/lib.rs thoth-api-server/src/lib.rs \
- thoth-app/src/lib.rs thoth-app-server/src/lib.rs thoth-client/src/lib.rs \
- thoth-errors/src/lib.rs thoth-export-server/src/lib.rs
-RUN echo "fn main() {}" > thoth-client/build.rs
-RUN echo "fn main() {}" > thoth-app-server/build.rs
-RUN echo "fn main() {}" > thoth-export-server/build.rs
-RUN cargo build
-RUN rm -rf src thoth-api thoth-api-server thoth-app thoth-app-server thoth-client \
- thoth-errors thoth-export-server Cargo.toml Cargo.lock
-
-# Get the actual source
-COPY . .
-
-# Change access and modified times of previously-defined-as-dummy files to let cargo know
-# it needs to (re)compile these modules
-RUN touch -a -m thoth-api/src/lib.rs thoth-api-server/src/lib.rs \
- thoth-app/src/lib.rs thoth-app-server/src/lib.rs thoth-client/src/lib.rs \
- thoth-errors/src/lib.rs thoth-export-server/src/lib.rs thoth-app-server/build.rs \
- thoth-export-server/build.rs
-
-# Build Thoth for debug
-RUN cargo build
diff --git a/Makefile b/Makefile
index 6b0bf3bc..a073d2a3 100644
--- a/Makefile
+++ b/Makefile
@@ -1,65 +1,76 @@
.PHONY: \
- build-graphql-api \
- build-export-api \
- build-app \
- run-app \
+ help \
+ run-db \
+ run-zitadel-db \
+ run-redis \
+ run-zitadel \
run-graphql-api \
run-export-api \
- watch-app \
- docker-dev \
- docker-dev-build \
- docker-dev-run \
- docker-dev-db \
- docker-dev-redis \
build \
test \
+ check \
clippy \
format \
check-format \
- check \
check-all \
-
-all: build-graphql-api build-export-api build-app
-check-all: test check clippy check-format
-
-run-app: build-app
- RUST_BACKTRACE=1 cargo run start app
-
-run-graphql-api: build-graphql-api
+ migration \
+ coverage
+
+CARGO_VERSION := $(shell grep '^version' Cargo.toml | sed -E 's/version *= *"([^"]+)"/\1/')
+MAJOR := $(word 1,$(subst ., ,$(CARGO_VERSION)))
+MINOR := $(word 2,$(subst ., ,$(CARGO_VERSION)))
+
+DATE = $(shell date +"%Y%m%d")
+
+help:
+ @echo "Available targets:"
+ @echo " help Show this help"
+ @echo " run-db Start PostgreSQL (docker)"
+ @echo " run-zitadel-db Start Zitadel PostgreSQL (docker)"
+ @echo " run-redis Start Redis (docker)"
+ @echo " run-zitadel Start Zitadel (docker)"
+ @echo " run-graphql-api Run GraphQL API (cargo)"
+ @echo " run-export-api Run export API (cargo)"
+ @echo " build Build the workspace"
+ @echo " test Run tests"
+ @echo " coverage Run test coverage (cargo llvm-cov)"
+ @echo " check Run cargo check"
+ @echo " clippy Lint with cargo clippy"
+ @echo " format Format code with cargo fmt"
+ @echo " check-format Check formatting"
+ @echo " check-all Run tests, clippy, and formatting checks"
+ @echo " migration Create a database migration"
+
+run-db:
+ docker compose up db
+
+run-zitadel-db:
+ docker compose up zitadel-db
+
+run-redis:
+ docker compose up redis
+
+run-zitadel:
+ docker compose up zitadel
+
+run-graphql-api: build
RUST_BACKTRACE=1 cargo run init
-run-export-api: build-export-api
+run-export-api: build
RUST_BACKTRACE=1 cargo run start export-api
-watch-app:
- trunk serve thoth-app/index.html
-
-docker-dev: docker-dev-build docker-dev-run
-
-docker-dev-build:
- docker compose -f docker-compose.dev.yml build
-
-docker-dev-run:
- docker compose -f docker-compose.dev.yml up
-
-docker-dev-db:
- docker compose -f docker-compose.dev.yml up db
-
-docker-dev-redis:
- docker compose -f docker-compose.dev.yml up redis
-
build:
cargo build -vv
-build-graphql-api: build
-
-build-export-api: build
-
-build-app: build
-
test:
cargo test --workspace
+coverage:
+ cargo llvm-cov --workspace --all-features --html --output-dir ./coverage
+
+check:
+ cargo check --workspace
+
clippy:
cargo clippy --all --all-targets --all-features -- -D warnings
@@ -69,5 +80,13 @@ format:
check-format:
cargo fmt --all -- --check
-check:
- cargo check --workspace
+check-all: test check clippy check-format
+
+migration:
+ @new_minor=$$(expr $(MINOR) + 1); \
+ new_version="$(MAJOR).$$new_minor.0"; \
+ dir="thoth-api/migrations/$(DATE)_v$$new_version"; \
+ mkdir -p $$dir; \
+ touch $$dir/up.sql; \
+ touch $$dir/down.sql;
+
diff --git a/README.md b/README.md
index 19f67fb3..58a1635e 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,6 @@
* A [GraphQL API](https://api.thoth.pub), implementing a data model specifically designed for OA books
* A [REST API](https://export.thoth.pub) to export metadata in formats like ONIX, MARC, etc.
-* A [WebAssembly GUI](https://thoth.pub) to manage metadata records.
For more information about Thoth, its data and metadata formats, and more, see the repo's [wiki](https://github.com/thoth-pub/thoth/wiki). You can also use GraphiQL to [explore the GraphQL API](https://api.thoth.pub/graphiql) (click on "Docs" at the top right), or RapiDoc to [inspect the REST API](https://export.thoth.pub).
@@ -30,8 +29,6 @@ For more information about Thoth, its data and metadata formats, and more, see t
- [Rustup](https://rustup.rs/)
- Stable Toolchain: `rustup default stable`
-- [wasm-pack](https://rustwasm.github.io/docs/wasm-pack/introduction.html)
-- [rollup](https://www.npmjs.com/package/rollup)
- A PostgreSQL database (included in docker-compose.yml if ran using docker)
- `libssl-dev`
@@ -113,12 +110,6 @@ cargo run init
cargo run start export-api
```
-#### GUI
-
-```sh
-cargo run start app
-```
-
### Building with docker
The wasm APP needs to know the endpoint the API will be running at compile time, we must provide `THOTH_API` as a build argument to the docker daemon upon build:
diff --git a/diesel.toml b/diesel.toml
index 752265c1..abde98b4 100644
--- a/diesel.toml
+++ b/diesel.toml
@@ -14,7 +14,10 @@ custom_type_derives = [
"crate::model::language::Language_code",
"crate::model::series::Series_type",
"crate::model::price::Currency_code",
- "crate::model::subject::Subject_type"
- "crate::model::institution::Country_code"
+ "crate::model::subject::Subject_type",
+ "crate::model::institution::Country_code",
"crate::model::work_relation::Relation_type"
+ "crate::model::contact::Contact_type"
+ "crate::model::publication::Accessibility_standard"
+ "crate::model::publication::Accessibility_exception"
]
diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml
deleted file mode 100644
index 245d7cff..00000000
--- a/docker-compose.dev.yml
+++ /dev/null
@@ -1,56 +0,0 @@
-services:
- db:
- image: postgres:17
- container_name: "thoth_db"
- ports:
- - "5432:5432"
- volumes:
- - ./db/_data:/var/lib/postgresql/data
- env_file:
- - .env
-
- redis:
- image: redis:alpine
- container_name: "thoth_redis"
- ports:
- - "6379:6379"
-
- graphql-api:
- build:
- context: .
- dockerfile: Dockerfile.dev
- container_name: "thoth_graphql_api"
- ports:
- - "8000:8000"
- command: ["cargo", "run", "init"]
- env_file:
- - .env
- depends_on:
- - db
-
- export-api:
- build:
- context: .
- dockerfile: Dockerfile.dev
- container_name: "thoth_export_api"
- ports:
- - "8181:8181"
- command: ["cargo", "run", "start", "export-api"]
- env_file:
- - .env
- depends_on:
- - graphql-api
-
- app:
- build:
- context: .
- dockerfile: Dockerfile.dev
- container_name: "thoth_app"
- ports:
- - "8080:8080"
- command: ["cargo", "run", "start", "app"]
- env_file:
- - .env
- depends_on:
- - graphql-api
- - export-api
diff --git a/docker-compose.yml b/docker-compose.yml
index 1fba394c..e2b86094 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -2,47 +2,36 @@ services:
db:
image: postgres:17
container_name: "thoth_db"
- restart: unless-stopped
+ ports:
+ - "5432:5432"
volumes:
- - db:/var/lib/postgresql/data
- - /etc/localtime:/etc/localtime:ro
+ - ./db/_data:/var/lib/postgresql/data
env_file:
- .env
+ zitadel-db:
+ image: postgres:17
+ container_name: "zitadel_db"
+ volumes:
+ - ./db/_zitadel:/var/lib/postgresql/data
+ environment:
+ POSTGRES_PASSWORD: postgres
+
redis:
image: redis:alpine
container_name: "thoth_redis"
- restart: unless-stopped
-
- graphql-api:
- image: ghcr.io/thoth-pub/thoth
- container_name: "thoth_graphql_api"
- restart: unless-stopped
- env_file:
- - .env
- depends_on:
- - db
+ ports:
+ - "6379:6379"
- export-api:
- image: ghcr.io/thoth-pub/thoth
- container_name: "thoth_export_api"
- restart: unless-stopped
- command: ["start", "export-api"]
- env_file:
- - .env
- depends_on:
- - graphql-api
-
- app:
- image: ghcr.io/thoth-pub/thoth
- container_name: "thoth_app"
- restart: unless-stopped
- command: ["start", "app"]
+ zitadel:
+ image: ghcr.io/zitadel/zitadel:v3.2.2
+ command: 'start-from-init --masterkey "${ZITADEL_MASTERKEY}" --tlsMode disabled'
+ container_name: "zitadel"
+ ports:
+ - "8282:8080"
env_file:
- .env
+ volumes:
+ - ./machinekey:/machinekey
depends_on:
- - graphql-api
- - export-api
-
-volumes:
- db:
+ - zitadel-db
diff --git a/src/bin/arguments/mod.rs b/src/bin/arguments/mod.rs
index 53d75d51..23694810 100644
--- a/src/bin/arguments/mod.rs
+++ b/src/bin/arguments/mod.rs
@@ -42,37 +42,14 @@ pub fn port(default_value: &'static str, env_value: &'static str) -> Arg {
.num_args(1)
}
-pub fn domain() -> Arg {
- Arg::new("domain")
- .short('d')
- .long("domain")
- .value_name("THOTH_DOMAIN")
- .env("THOTH_DOMAIN")
- .default_value("localhost")
- .help("Authentication cookie domain")
- .num_args(1)
-}
-
pub fn key() -> Arg {
Arg::new("key")
.short('k')
- .long("secret-key")
- .value_name("SECRET")
- .env("SECRET_KEY")
- .help("Authentication cookie secret key")
- .num_args(1)
-}
-
-pub fn session() -> Arg {
- Arg::new("duration")
- .short('s')
- .long("session-length")
- .value_name("DURATION")
- .env("SESSION_DURATION_SECONDS")
- .default_value("3600")
- .help("Authentication cookie session duration (seconds)")
+ .long("private-key")
+ .value_name("PRIVATE_KEY")
+ .env("PRIVATE_KEY")
+ .help("Thoth's GraphQL API zitadel private key (base64-encoded JSON key)")
.num_args(1)
- .value_parser(value_parser!(i64))
}
pub fn gql_url() -> Arg {
@@ -108,6 +85,27 @@ pub fn export_url() -> Arg {
.num_args(1)
}
+pub fn zitadel_url() -> Arg {
+ Arg::new("zitadel-url")
+ .short('z')
+ .long("zitadel-url")
+ .value_name("ZITADEL_URL")
+ .env("ZITADEL_URL")
+ .default_value("http://localhost:8282")
+ .help("Zitadel's, public facing, root URL.")
+ .num_args(1)
+}
+
+pub fn thoth_pat() -> Arg {
+ Arg::new("thoth-pat")
+ .short('P')
+ .long("thoth-pat")
+ .value_name("THOTH_PAT")
+ .env("THOTH_PAT")
+ .help("Thoth service account Personal Access Token (PAT)")
+ .num_args(1)
+}
+
pub fn threads(env_value: &'static str) -> Arg {
Arg::new("threads")
.short('t')
@@ -138,3 +136,30 @@ pub fn revert() -> Arg {
.help("Revert all database migrations")
.action(ArgAction::SetTrue)
}
+
+pub fn aws_access_key_id() -> Arg {
+ Arg::new("aws-access-key-id")
+ .long("aws-access-key-id")
+ .value_name("AWS_ACCESS_KEY_ID")
+ .env("AWS_ACCESS_KEY_ID")
+ .help("AWS access key id")
+ .num_args(1)
+}
+
+pub fn aws_secret_access_key() -> Arg {
+ Arg::new("aws-secret-access-key")
+ .long("aws-secret-access-key")
+ .value_name("AWS_SECRET_ACCESS_KEY")
+ .env("AWS_SECRET_ACCESS_KEY")
+ .help("AWS secret access key")
+ .num_args(1)
+}
+
+pub fn aws_region() -> Arg {
+ Arg::new("aws-region")
+ .long("aws-region")
+ .value_name("AWS_REGION")
+ .env("AWS_REGION")
+ .help("AWS region for S3/CloudFront")
+ .num_args(1)
+}
diff --git a/src/bin/commands/account.rs b/src/bin/commands/account.rs
index 629c637e..98c43141 100644
--- a/src/bin/commands/account.rs
+++ b/src/bin/commands/account.rs
@@ -110,7 +110,7 @@ fn password_input() -> ThothResult {
fn is_admin_input(publisher_name: &str) -> ThothResult {
Input::with_theme(&ColorfulTheme::default())
- .with_prompt(format!("Make user an admin of '{}'?", publisher_name))
+ .with_prompt(format!("Make user an admin of '{publisher_name}'?"))
.default(false)
.interact_on(&Term::stdout())
.map_err(Into::into)
diff --git a/src/bin/commands/cache.rs b/src/bin/commands/cache.rs
index c9ff9c29..d59fd080 100644
--- a/src/bin/commands/cache.rs
+++ b/src/bin/commands/cache.rs
@@ -32,7 +32,7 @@ pub fn delete(arguments: &ArgMatches) -> ThothResult<()> {
runtime.block_on(async {
for index in chosen {
let specification = ALL_SPECIFICATIONS.get(index).unwrap();
- let keys = scan_match(&pool, &format!("{}*", specification)).await?;
+ let keys = scan_match(&pool, &format!("{specification}*")).await?;
for key in keys {
del(&pool, &key).await?;
}
diff --git a/src/bin/commands/mod.rs b/src/bin/commands/mod.rs
index f6a585c9..7b5a002a 100644
--- a/src/bin/commands/mod.rs
+++ b/src/bin/commands/mod.rs
@@ -3,18 +3,15 @@ use clap::Command;
use lazy_static::lazy_static;
use thoth::{
api::{
- db::{
- init_pool as init_pg_pool, revert_migrations as revert_db_migrations,
- run_migrations as run_db_migrations, PgPool,
- },
+ db::{revert_migrations as revert_db_migrations, run_migrations as run_db_migrations},
redis::{init_pool as init_redis_pool, RedisPool},
},
errors::ThothResult,
};
-pub(super) mod account;
pub(super) mod cache;
pub(super) mod start;
+pub(super) mod zitadel;
lazy_static! {
pub(super) static ref INIT: Command = Command::new("init")
@@ -25,9 +22,11 @@ lazy_static! {
.arg(arguments::threads("GRAPHQL_API_THREADS"))
.arg(arguments::keep_alive("GRAPHQL_API_KEEP_ALIVE"))
.arg(arguments::gql_url())
- .arg(arguments::domain())
.arg(arguments::key())
- .arg(arguments::session());
+ .arg(arguments::zitadel_url())
+ .arg(arguments::aws_access_key_id())
+ .arg(arguments::aws_secret_access_key())
+ .arg(arguments::aws_region());
}
lazy_static! {
@@ -37,11 +36,6 @@ lazy_static! {
.arg(arguments::revert());
}
-fn get_pg_pool(arguments: &clap::ArgMatches) -> PgPool {
- let database_url = arguments.get_one::("db").unwrap();
- init_pg_pool(database_url)
-}
-
fn get_redis_pool(arguments: &clap::ArgMatches) -> RedisPool {
let redis_url = arguments.get_one::("redis").unwrap();
init_redis_pool(redis_url)
diff --git a/src/bin/commands/start.rs b/src/bin/commands/start.rs
index 9ef2f3c8..c557c857 100644
--- a/src/bin/commands/start.rs
+++ b/src/bin/commands/start.rs
@@ -1,7 +1,7 @@
use crate::arguments;
use clap::{ArgMatches, Command};
use lazy_static::lazy_static;
-use thoth::{api_server, app_server, errors::ThothResult, export_server};
+use thoth::{api_server, errors::ThothResult, export_server};
lazy_static! {
pub(crate) static ref COMMAND: Command = Command::new("start")
@@ -17,17 +17,11 @@ lazy_static! {
.arg(arguments::threads("GRAPHQL_API_THREADS"))
.arg(arguments::keep_alive("GRAPHQL_API_KEEP_ALIVE"))
.arg(arguments::gql_url())
- .arg(arguments::domain())
.arg(arguments::key())
- .arg(arguments::session()),
- )
- .subcommand(
- Command::new("app")
- .about("Start the thoth client GUI")
- .arg(arguments::host("APP_HOST"))
- .arg(arguments::port("8080", "APP_PORT"))
- .arg(arguments::threads("APP_THREADS"))
- .arg(arguments::keep_alive("APP_KEEP_ALIVE")),
+ .arg(arguments::zitadel_url())
+ .arg(arguments::aws_access_key_id())
+ .arg(arguments::aws_secret_access_key())
+ .arg(arguments::aws_region()),
)
.subcommand(
Command::new("export-api")
@@ -49,9 +43,12 @@ pub fn graphql_api(arguments: &ArgMatches) -> ThothResult<()> {
let threads = *arguments.get_one::("threads").unwrap();
let keep_alive = *arguments.get_one::("keep-alive").unwrap();
let url = arguments.get_one::("gql-url").unwrap().to_owned();
- let domain = arguments.get_one::("domain").unwrap().to_owned();
- let secret_str = arguments.get_one::("key").unwrap().to_owned();
- let session_duration = *arguments.get_one::("duration").unwrap();
+ let private_key = arguments.get_one::("key").unwrap().to_owned();
+ let zitadel_url = arguments
+ .get_one::("zitadel-url")
+ .unwrap()
+ .to_owned();
+
api_server(
database_url,
host,
@@ -59,21 +56,23 @@ pub fn graphql_api(arguments: &ArgMatches) -> ThothResult<()> {
threads,
keep_alive,
url,
- domain,
- secret_str,
- session_duration,
+ private_key,
+ zitadel_url,
+ arguments
+ .get_one::("aws-access-key-id")
+ .unwrap()
+ .to_owned(),
+ arguments
+ .get_one::("aws-secret-access-key")
+ .unwrap()
+ .to_owned(),
+ arguments
+ .get_one::("aws-region")
+ .unwrap()
+ .to_owned(),
)
.map_err(|e| e.into())
}
-
-pub fn app(arguments: &ArgMatches) -> ThothResult<()> {
- let host = arguments.get_one::("host").unwrap().to_owned();
- let port = arguments.get_one::("port").unwrap().to_owned();
- let threads = *arguments.get_one::("threads").unwrap();
- let keep_alive = *arguments.get_one::("keep-alive").unwrap();
- app_server(host, port, threads, keep_alive).map_err(|e| e.into())
-}
-
pub fn export_api(arguments: &ArgMatches) -> ThothResult<()> {
let redis_url = arguments.get_one::("redis").unwrap().to_owned();
let host = arguments.get_one::("host").unwrap().to_owned();
diff --git a/src/bin/commands/zitadel.rs b/src/bin/commands/zitadel.rs
new file mode 100644
index 00000000..2859ea84
--- /dev/null
+++ b/src/bin/commands/zitadel.rs
@@ -0,0 +1,158 @@
+use crate::arguments;
+use base64::{engine::general_purpose, Engine as _};
+use clap::{ArgMatches, Command};
+use lazy_static::lazy_static;
+use thoth::errors::{ThothError, ThothResult};
+use zitadel::api::{
+ clients::ClientBuilder,
+ zitadel::app::v1::{
+ ApiAuthMethodType, OidcAppType, OidcAuthMethodType, OidcGrantType, OidcResponseType,
+ OidcTokenType, OidcVersion,
+ },
+ zitadel::authn::v1::KeyType,
+ zitadel::management::v1::{
+ AddApiAppRequest, AddAppKeyRequest, AddOidcAppRequest, AddProjectRequest,
+ AddProjectRoleRequest, AddUserGrantRequest,
+ },
+ zitadel::project::v1::PrivateLabelingSetting,
+ zitadel::user::v2::{ListUsersRequest, UserFieldName},
+};
+
+lazy_static! {
+ pub(crate) static ref COMMAND: Command = Command::new("zitadel")
+ .about("Manage Zitadel workflows")
+ .arg(arguments::zitadel_url())
+ .arg(arguments::thoth_pat())
+ .subcommand_required(true)
+ .arg_required_else_help(true)
+ .subcommand(Command::new("setup").about("Intial setup of OIDC APPs in zitadel"));
+}
+
+pub fn setup(arguments: &ArgMatches) -> ThothResult<()> {
+ let zitadel_url = arguments.get_one::("zitadel-url").unwrap();
+ let pat = arguments.get_one::("thoth-pat").unwrap();
+ let runtime = tokio::runtime::Builder::new_multi_thread()
+ .worker_threads(1)
+ .enable_all()
+ .build()?;
+
+ runtime.block_on(async {
+ let mut management_client = ClientBuilder::new(zitadel_url)
+ .with_access_token(pat)
+ .build_management_client()
+ .await?;
+ let mut user_client = ClientBuilder::new(zitadel_url)
+ .with_access_token(pat)
+ .build_user_client()
+ .await?;
+
+ // Create Zitadel project
+ let project_name = "Thoth";
+ let project = management_client
+ .add_project(AddProjectRequest {
+ name: project_name.to_string(),
+ project_role_assertion: false,
+ project_role_check: false,
+ has_project_check: false,
+ private_labeling_setting: PrivateLabelingSetting::EnforceProjectResourceOwnerPolicy
+ as i32,
+ })
+ .await?
+ .into_inner();
+ println!("\n✅ Created Zitadel project: {}", project_name);
+
+ // Create project user roles
+ let roles = [
+ ("SUPERUSER", "Superuser", "Superusers"),
+ ("PUBLISHER_ADMIN", "Publisher Admin", "Publisher admins"),
+ ("PUBLISHER_USER", "Publisher User", "Publisher users"),
+ ];
+ for (role_key, display_name, group) in roles {
+ management_client
+ .add_project_role(AddProjectRoleRequest {
+ project_id: project.id.clone(),
+ role_key: role_key.to_string(),
+ display_name: display_name.to_string(),
+ group: group.to_string(),
+ })
+ .await?;
+ println!("\n✅ Added project role: {}", role_key);
+ }
+
+ // Assign SUPERUSER role to default accounts
+ let users = user_client
+ .list_users(ListUsersRequest {
+ query: None,
+ sorting_column: UserFieldName::CreationDate as i32,
+ queries: vec![],
+ })
+ .await?
+ .into_inner()
+ .result;
+ for user in users {
+ management_client
+ .add_user_grant(AddUserGrantRequest {
+ user_id: user.user_id.clone(),
+ project_id: project.id.clone(),
+ project_grant_id: "".to_string(),
+ role_keys: vec!["SUPERUSER".to_string()],
+ })
+ .await?;
+ println!("\n✅ Granted SUPERUSER role to user: {}", user.username);
+ }
+
+ // Create Zitadel APPs for GraphQL API and APP
+ let graphql_api_name = "Thoth GraphQL API";
+ let graphql_api = management_client
+ .add_api_app(AddApiAppRequest {
+ project_id: project.id.clone(),
+ name: graphql_api_name.to_string(),
+ auth_method_type: ApiAuthMethodType::PrivateKeyJwt as i32,
+ })
+ .await?
+ .into_inner();
+ println!("\n✅ Created API app: {}", graphql_api_name);
+
+ let graphql_api_key = management_client
+ .add_app_key(AddAppKeyRequest {
+ project_id: project.id.clone(),
+ app_id: graphql_api.app_id,
+ r#type: KeyType::Json as i32,
+ expiration_date: None,
+ })
+ .await?
+ .into_inner();
+ let encoded_key = general_purpose::STANDARD.encode(&graphql_api_key.key_details);
+ println!("\n✅ {} application key generated.", graphql_api_name);
+ println!("👉 Please copy the following and add it to the `.env` file as `PRIVATE_KEY`:\n");
+ println!("PRIVATE_KEY={}\n", encoded_key);
+
+ let app_name = "Thoth APP";
+ management_client
+ .add_oidc_app(AddOidcAppRequest {
+ project_id: project.id.clone(),
+ name: app_name.to_string(),
+ redirect_uris: vec!["http://localhost:8080/callback".to_string()],
+ response_types: vec![OidcResponseType::Code as i32],
+ grant_types: vec![OidcGrantType::AuthorizationCode as i32],
+ app_type: OidcAppType::UserAgent as i32,
+ auth_method_type: OidcAuthMethodType::None as i32, // PKCE
+ post_logout_redirect_uris: vec!["http://localhost:8080/logout".to_string()],
+ version: OidcVersion::OidcVersion10 as i32,
+ dev_mode: true,
+ access_token_type: OidcTokenType::Bearer as i32,
+ access_token_role_assertion: false,
+ id_token_role_assertion: false,
+ id_token_userinfo_assertion: false,
+ clock_skew: None,
+ additional_origins: vec!["http://localhost:8080".to_string()],
+ skip_native_app_success_page: false,
+ back_channel_logout_uri: "".to_string(),
+ login_version: None,
+ })
+ .await?;
+ println!("\n✅ Created OIDC app: {}", app_name);
+
+ Ok::<(), ThothError>(())
+ })
+}
diff --git a/src/bin/thoth.rs b/src/bin/thoth.rs
index 42597884..6ee60f80 100644
--- a/src/bin/thoth.rs
+++ b/src/bin/thoth.rs
@@ -11,8 +11,8 @@ lazy_static::lazy_static! {
.subcommand(commands::MIGRATE.clone())
.subcommand(commands::start::COMMAND.clone())
.subcommand(commands::INIT.clone())
- .subcommand(commands::account::COMMAND.clone())
- .subcommand(commands::cache::COMMAND.clone());
+ .subcommand(commands::cache::COMMAND.clone())
+ .subcommand(commands::zitadel::COMMAND.clone());
}
fn main() -> thoth::errors::ThothResult<()> {
@@ -22,7 +22,6 @@ fn main() -> thoth::errors::ThothResult<()> {
match THOTH.clone().get_matches().subcommand() {
Some(("start", start_arguments)) => match start_arguments.subcommand() {
Some(("graphql-api", arguments)) => commands::start::graphql_api(arguments),
- Some(("app", arguments)) => commands::start::app(arguments),
Some(("export-api", arguments)) => commands::start::export_api(arguments),
_ => unreachable!(),
},
@@ -31,16 +30,14 @@ fn main() -> thoth::errors::ThothResult<()> {
commands::run_migrations(arguments)?;
commands::start::graphql_api(arguments)
}
- Some(("account", arguments)) => match arguments.subcommand() {
- Some(("register", _)) => commands::account::register(arguments),
- Some(("publishers", _)) => commands::account::publishers(arguments),
- Some(("password", _)) => commands::account::password(arguments),
- _ => unreachable!(),
- },
Some(("cache", arguments)) => match arguments.subcommand() {
Some(("delete", _)) => commands::cache::delete(arguments),
_ => unreachable!(),
},
+ Some(("zitadel", arguments)) => match arguments.subcommand() {
+ Some(("setup", _)) => commands::zitadel::setup(arguments),
+ _ => unreachable!(),
+ },
_ => unreachable!(),
}
}
diff --git a/src/lib.rs b/src/lib.rs
index b0e60dc4..10b035ce 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,4 @@
pub use thoth_api as api;
pub use thoth_api_server::start_server as api_server;
-pub use thoth_app_server::start_server as app_server;
pub use thoth_errors as errors;
pub use thoth_export_server::{start_server as export_server, ALL_SPECIFICATIONS};
diff --git a/thoth-api-server/Cargo.toml b/thoth-api-server/Cargo.toml
index 833837b6..11430e9e 100644
--- a/thoth-api-server/Cargo.toml
+++ b/thoth-api-server/Cargo.toml
@@ -14,10 +14,9 @@ thoth-errors = { version = "=0.13.15", path = "../thoth-errors" }
actix-web = "4.10"
actix-cors = "0.7.1"
actix-http = "3.10.0"
-actix-identity = "0.8.0"
-actix-session = { version = "0.10.1", features = ["cookie-session"] }
+base64 = "0.22.1"
env_logger = "0.11.7"
futures-util = "0.3.31"
log = "0.4.26"
serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
+zitadel = { version = "5.5.1", features = ["actix"]}
diff --git a/thoth-api-server/src/graphiql.rs b/thoth-api-server/src/graphiql.rs
index 185baecf..79636ebc 100644
--- a/thoth-api-server/src/graphiql.rs
+++ b/thoth-api-server/src/graphiql.rs
@@ -26,7 +26,9 @@ pub fn graphiql_source(graphql_endpoint_url: &str) -> String {
#
{
books(order: {field: PUBLICATION_DATE, direction: ASC}) {
- fullTitle
+ titles {
+ fullTitle
+ }
doi
publications {
publicationType
diff --git a/thoth-api-server/src/lib.rs b/thoth-api-server/src/lib.rs
index 318faaf0..0e1ee503 100644
--- a/thoth-api-server/src/lib.rs
+++ b/thoth-api-server/src/lib.rs
@@ -4,28 +4,25 @@ mod logger;
use std::{io, sync::Arc, time::Duration};
use actix_cors::Cors;
-use actix_identity::{Identity, IdentityMiddleware};
-use actix_session::{config::PersistentSession, storage::CookieSessionStore, SessionMiddleware};
use actix_web::{
- cookie::{time::Duration as CookieDuration, Key},
- error, get,
+ get,
http::header,
middleware::Compress,
post,
web::{Data, Json},
- App, Error, HttpMessage, HttpRequest, HttpResponse, HttpServer, Result,
+ App, Error, HttpResponse, HttpServer, Result,
};
+use base64::{engine::general_purpose, Engine as _};
use serde::Serialize;
use thoth_api::{
- account::model::{AccountDetails, DecodedToken, LoginCredentials},
- account::service::{get_account, get_account_details, login},
db::{init_pool, PgPool},
- graphql::{
- model::{create_schema, Context, Schema},
- GraphQLRequest,
- },
+ graphql::{create_schema, Context, GraphQLRequest, Schema},
+ storage::{create_cloudfront_client, create_s3_client, CloudFrontClient, S3Client},
+};
+use zitadel::{
+ actix::introspection::{IntrospectedUser, IntrospectionConfigBuilder},
+ credentials::Application,
};
-use thoth_errors::ThothError;
use crate::graphiql::graphiql_source;
use crate::logger::{BodyLogger, Logger};
@@ -91,10 +88,17 @@ async fn graphql_schema(st: Data>) -> HttpResponse {
async fn graphql(
st: Data>,
pool: Data,
- token: DecodedToken,
+ s3_client: Data,
+ cloudfront_client: Data,
+ user: Option,
data: Json,
) -> Result {
- let ctx = Context::new(pool.into_inner(), token);
+ let ctx = Context::new(
+ pool.into_inner(),
+ user,
+ s3_client.into_inner(),
+ cloudfront_client.into_inner(),
+ );
let result = data.execute(&st, &ctx).await;
match result.is_ok() {
true => Ok(HttpResponse::Ok().json(result)),
@@ -102,86 +106,6 @@ async fn graphql(
}
}
-#[post("/account/login")]
-async fn login_credentials(
- request: HttpRequest,
- payload: Json,
- pool: Data,
-) -> Result {
- let r = payload.into_inner();
-
- login(&r.email, &r.password, &pool)
- .and_then(|account| {
- account.issue_token(&pool)?;
- let details = get_account_details(&account.email, &pool).unwrap();
- let user_string = serde_json::to_string(&details)
- .map_err(|_| ThothError::InternalError("Serder error".into()))?;
- Identity::login(&request.extensions(), user_string)
- .map_err(|_| ThothError::InternalError("Failed to store session cookie".into()))?;
- Ok(HttpResponse::Ok().json(details))
- })
- .map_err(error::ErrorUnauthorized)
-}
-
-#[post("/account/token/renew")]
-async fn login_session(
- request: HttpRequest,
- token: DecodedToken,
- identity: Option,
- pool: Data,
-) -> Result {
- let email = match identity {
- Some(session) => {
- let id = session.id().map_err(|_| ThothError::Unauthorised)?;
- let details: AccountDetails =
- serde_json::from_str(&id).map_err(|_| ThothError::Unauthorised)?;
- details.email
- }
- None => {
- token.jwt.as_ref().ok_or(ThothError::Unauthorised)?;
- let t = token.jwt.unwrap();
- t.sub
- }
- };
-
- get_account(&email, &pool)
- .and_then(|account| {
- account.issue_token(&pool)?;
- let details = get_account_details(&account.email, &pool).unwrap();
- let user_string = serde_json::to_string(&details)
- .map_err(|_| ThothError::InternalError("Serder error".into()))?;
- Identity::login(&request.extensions(), user_string)
- .map_err(|_| ThothError::InternalError("Failed to store session cookie".into()))?;
- Ok(HttpResponse::Ok().json(details))
- })
- .map_err(error::ErrorUnauthorized)
-}
-
-#[get("/account")]
-async fn account_details(
- token: DecodedToken,
- identity: Option,
- pool: Data,
-) -> Result {
- let email = match identity {
- Some(session) => {
- let id = session.id().map_err(|_| ThothError::Unauthorised)?;
- let details: AccountDetails =
- serde_json::from_str(&id).map_err(|_| ThothError::Unauthorised)?;
- details.email
- }
- None => {
- token.jwt.as_ref().ok_or(ThothError::Unauthorised)?;
- let t = token.jwt.unwrap();
- t.sub
- }
- };
-
- get_account_details(&email, &pool)
- .map(|account_details| HttpResponse::Ok().json(account_details))
- .map_err(error::ErrorUnauthorized)
-}
-
#[allow(clippy::too_many_arguments)]
#[actix_web::main]
pub async fn start_server(
@@ -191,33 +115,34 @@ pub async fn start_server(
threads: usize,
keep_alive: u64,
public_url: String,
- domain: String,
- secret_str: String,
- session_duration: i64,
+ private_key: String,
+ zitadel_url: String,
+ aws_access_key_id: String,
+ aws_secret_access_key: String,
+ aws_region: String,
) -> io::Result<()> {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
+ let decoded_private_key = general_purpose::STANDARD
+ .decode(&private_key)
+ .expect("Failed to base64-decode private key");
+ let decoded_str =
+ std::str::from_utf8(&decoded_private_key).expect("Decoded key is not valid UTF-8");
+ let auth = IntrospectionConfigBuilder::new(&zitadel_url)
+ .with_jwt_profile(Application::load_from_json(decoded_str).unwrap())
+ .build()
+ .await
+ .unwrap();
+
+ let s3_client = create_s3_client(&aws_access_key_id, &aws_secret_access_key, &aws_region).await;
+ let cloudfront_client =
+ create_cloudfront_client(&aws_access_key_id, &aws_secret_access_key, &aws_region).await;
+
HttpServer::new(move || {
App::new()
.wrap(Compress::default())
.wrap(Logger::default())
.wrap(BodyLogger)
- .wrap(IdentityMiddleware::default())
- .wrap(
- SessionMiddleware::builder(
- CookieSessionStore::default(),
- Key::from(secret_str.as_bytes()),
- )
- .cookie_name("auth".to_string())
- .cookie_path("/".to_string())
- .cookie_domain(Some(domain.clone()))
- .cookie_secure(domain.clone().ne("localhost")) // Authentication requires https unless running on localhost
- .session_lifecycle(
- PersistentSession::default()
- .session_ttl(CookieDuration::seconds(session_duration)),
- )
- .build(),
- )
.wrap(
Cors::default()
.allowed_methods(vec!["GET", "POST", "OPTIONS"])
@@ -226,16 +151,16 @@ pub async fn start_server(
.allowed_header(header::CONTENT_TYPE)
.supports_credentials(),
)
+ .app_data(auth.clone())
.app_data(Data::new(ApiConfig::new(public_url.clone())))
.app_data(Data::new(init_pool(&database_url)))
+ .app_data(Data::new(s3_client.clone()))
+ .app_data(Data::new(cloudfront_client.clone()))
.app_data(Data::new(Arc::new(create_schema())))
.service(index)
.service(graphql_index)
.service(graphql)
.service(graphiql_interface)
- .service(login_credentials)
- .service(login_session)
- .service(account_details)
.service(graphql_schema)
})
.workers(threads)
diff --git a/thoth-api/Cargo.toml b/thoth-api/Cargo.toml
index e0b541d5..a8958900 100644
--- a/thoth-api/Cargo.toml
+++ b/thoth-api/Cargo.toml
@@ -21,7 +21,14 @@ backend = [
"jsonwebtoken",
"deadpool-redis",
"rand",
- "argon2rs"
+ "argon2rs",
+ "zitadel",
+ "aws-sdk-s3",
+ "aws-sdk-cloudfront",
+ "aws-config",
+ "aws-credential-types",
+ "base64",
+ "hex"
]
[dependencies]
@@ -40,12 +47,22 @@ futures = { version = "0.3.31", optional = true }
jsonwebtoken = { version = "9.3.1", optional = true }
juniper = { version = "0.16.1", features = ["chrono", "schema-language", "uuid"] }
lazy_static = "1.5.0"
+pulldown-cmark = "0.13.0"
rand = { version = "0.9.0", optional = true }
regex = "1.11.1"
+scraper = "0.20.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
strum = { version = "0.27.1", features = ["derive"] }
uuid = { version = "1.16.0", features = ["serde", "v4"] }
+zitadel = { version = "5.5.1", features = ["actix"], optional = true }
+aws-sdk-s3 = { version = "1", optional = true }
+aws-sdk-cloudfront = { version = "1", optional = true }
+aws-config = { version = "1", optional = true }
+aws-credential-types = { version = "1", optional = true }
+base64 = { version = "0.22", optional = true }
+hex = { version = "0.4", optional = true }
[dev-dependencies]
-tokio = { version = "1.44", features = ["macros"] }
+fs2 = "0.4.3"
+tokio = { version = "1.44", features = ["macros", "rt"] }
diff --git a/thoth-api/migrations/0.0.0_diesel_initial_setup/down.sql b/thoth-api/migrations/0.0.0_diesel_initial_setup/down.sql
deleted file mode 100644
index a9f52609..00000000
--- a/thoth-api/migrations/0.0.0_diesel_initial_setup/down.sql
+++ /dev/null
@@ -1,6 +0,0 @@
--- This file was automatically created by Diesel to setup helper functions
--- and other internal bookkeeping. This file is safe to edit, any future
--- changes will be added to existing projects as new migrations.
-
-DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass);
-DROP FUNCTION IF EXISTS diesel_set_updated_at();
diff --git a/thoth-api/migrations/0.0.0_diesel_initial_setup/up.sql b/thoth-api/migrations/0.0.0_diesel_initial_setup/up.sql
deleted file mode 100644
index 3400c7c5..00000000
--- a/thoth-api/migrations/0.0.0_diesel_initial_setup/up.sql
+++ /dev/null
@@ -1,37 +0,0 @@
--- This file was automatically created by Diesel to setup helper functions
--- and other internal bookkeeping. This file is safe to edit, any future
--- changes will be added to existing projects as new migrations.
-
-
-
-
--- Sets up a trigger for the given table to automatically set a column called
--- `updated_at` whenever the row is modified (unless `updated_at` was included
--- in the modified columns)
---
--- # Example
---
--- ```sql
--- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW());
---
--- SELECT diesel_manage_updated_at('users');
--- ```
-CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$
-BEGIN
- EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s
- FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl);
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$
-BEGIN
- IF (
- NEW IS DISTINCT FROM OLD AND
- NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at
- ) THEN
- NEW.updated_at := current_timestamp;
- END IF;
- RETURN NEW;
-END;
-$$ LANGUAGE plpgsql;
-
diff --git a/thoth-api/migrations/0.1.0/down.sql b/thoth-api/migrations/0.1.0/down.sql
deleted file mode 100644
index c833fe95..00000000
--- a/thoth-api/migrations/0.1.0/down.sql
+++ /dev/null
@@ -1,32 +0,0 @@
-DROP TABLE IF EXISTS funding;
-DROP TABLE IF EXISTS funder;
-
-DROP TABLE IF EXISTS subject;
-DROP TYPE IF EXISTS subject_type;
-
-DROP TABLE IF EXISTS price;
-DROP TYPE IF EXISTS currency_code;
-
-DROP TABLE IF EXISTS publication;
-DROP TYPE IF EXISTS publication_type;
-
-DROP TABLE IF EXISTS contribution;
-DROP TYPE IF EXISTS contribution_type;
-DROP TABLE IF EXISTS contributor;
-
-DROP TABLE IF EXISTS issue;
-DROP TABLE IF EXISTS series;
-DROP TYPE IF EXISTS series_type;
-
-DROP TABLE IF EXISTS language;
-DROP TYPE IF EXISTS language_code;
-DROP TYPE IF EXISTS language_relation;
-
-DROP TABLE IF EXISTS work;
-DROP TYPE IF EXISTS work_type;
-DROP TYPE IF EXISTS work_status;
-
-DROP TABLE IF EXISTS imprint;
-DROP TABLE IF EXISTS publisher;
-
-DROP EXTENSION IF EXISTS "uuid-ossp";
diff --git a/thoth-api/migrations/0.1.0/up.sql b/thoth-api/migrations/0.1.0/up.sql
deleted file mode 100644
index b9e56883..00000000
--- a/thoth-api/migrations/0.1.0/up.sql
+++ /dev/null
@@ -1,1037 +0,0 @@
-CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-
--------------------- Publisher
-CREATE TABLE publisher (
- publisher_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- publisher_name TEXT NOT NULL CHECK (octet_length(publisher_name) >= 1),
- publisher_shortname TEXT CHECK (octet_length(publisher_shortname) >= 1),
- publisher_url TEXT CHECK (publisher_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)')
-);
--- case-insensitive UNIQ index on publisher_name
-CREATE UNIQUE INDEX publisher_uniq_idx ON publisher(lower(publisher_name));
-
-CREATE TABLE imprint (
- imprint_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- publisher_id UUID NOT NULL REFERENCES publisher(publisher_id) ON DELETE CASCADE,
- imprint_name TEXT NOT NULL CHECK (octet_length(imprint_name) >= 1),
- imprint_url TEXT CHECK (imprint_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)')
-);
--- case-insensitive UNIQ index on imprint_name
-CREATE UNIQUE INDEX imprint_uniq_idx ON imprint(lower(imprint_name));
-
--------------------- Work
-
-CREATE TYPE work_type AS ENUM (
- 'book-chapter',
- 'monograph',
- 'edited-book',
- 'textbook',
- 'journal-issue',
- 'book-set'
-);
-
--- ONIX Publishing status https://onix-codelists.io/codelist/64
-CREATE TYPE work_status AS ENUM (
- 'unspecified',
- 'cancelled',
- 'forthcoming',
- 'postponed-indefinitely',
- 'active',
- 'no-longer-our-product',
- 'out-of-stock-indefinitely',
- 'out-of-print',
- 'inactive',
- 'unknown',
- 'remaindered',
- 'withdrawn-from-sale',
- 'recalled'
-);
-
-CREATE TABLE work (
- work_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- work_type work_type NOT NULL,
- work_status work_status NOT NULL,
- full_title TEXT NOT NULL CHECK (octet_length(full_title) >= 1),
- title TEXT NOT NULL CHECK (octet_length(title) >= 1),
- subtitle TEXT CHECK (octet_length(subtitle) >= 1),
- reference TEXT CHECK (octet_length(reference) >= 1),
- edition INTEGER NOT NULL CHECK (edition > 0),
- imprint_id UUID NOT NULL REFERENCES imprint(imprint_id) ON DELETE CASCADE,
- doi TEXT CHECK (doi ~* 'https:\/\/doi.org\/10.\d{4,9}\/[-._\;\(\)\/:a-zA-Z0-9]+$'),
- publication_date DATE,
- place TEXT CHECK (octet_length(reference) >= 1),
- width INTEGER CHECK (width > 0),
- height INTEGER CHECK (height > 0),
- page_count INTEGER CHECK (page_count > 0),
- page_breakdown TEXT CHECK(octet_length(page_breakdown) >=1),
- image_count INTEGER CHECK (image_count >= 0),
- table_count INTEGER CHECK (table_count >= 0),
- audio_count INTEGER CHECK (audio_count >= 0),
- video_count INTEGER CHECK (video_count >= 0),
- license TEXT CHECK (license ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'),
- copyright_holder TEXT NOT NULL CHECK (octet_length(copyright_holder) >= 1),
- landing_page TEXT CHECK (landing_page ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'),
- lccn TEXT CHECK (octet_length(lccn) >= 1),
- oclc TEXT CHECK (octet_length(oclc) >= 1),
- short_abstract TEXT CHECK (octet_length(short_abstract) >= 1),
- long_abstract TEXT CHECK (octet_length(long_abstract) >= 1),
- general_note TEXT CHECK (octet_length(general_note) >= 1),
- toc TEXT CHECK (octet_length(toc) >= 1),
- cover_url TEXT CHECK (cover_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'),
- cover_caption TEXT CHECK (octet_length(cover_caption) >= 1)
-);
--- case-insensitive UNIQ index on doi
-CREATE UNIQUE INDEX doi_uniq_idx ON work(lower(doi));
-
--------------------- Language
-
-CREATE TYPE language_relation AS ENUM (
- 'original',
- 'translated-from',
- 'translated-into'
-);
-
-CREATE TYPE language_code AS ENUM (
- 'aar',
- 'abk',
- 'ace',
- 'ach',
- 'ada',
- 'ady',
- 'afa',
- 'afh',
- 'afr',
- 'ain',
- 'aka',
- 'akk',
- 'alb',
- 'ale',
- 'alg',
- 'alt',
- 'amh',
- 'ang',
- 'anp',
- 'apa',
- 'ara',
- 'arc',
- 'arg',
- 'arm',
- 'arn',
- 'arp',
- 'art',
- 'arw',
- 'asm',
- 'ast',
- 'ath',
- 'aus',
- 'ava',
- 'ave',
- 'awa',
- 'aym',
- 'aze',
- 'bad',
- 'bai',
- 'bak',
- 'bal',
- 'bam',
- 'ban',
- 'baq',
- 'bas',
- 'bat',
- 'bej',
- 'bel',
- 'bem',
- 'ben',
- 'ber',
- 'bho',
- 'bih',
- 'bik',
- 'bin',
- 'bis',
- 'bla',
- 'bnt',
- 'bos',
- 'bra',
- 'bre',
- 'btk',
- 'bua',
- 'bug',
- 'bul',
- 'bur',
- 'byn',
- 'cad',
- 'cai',
- 'car',
- 'cat',
- 'cau',
- 'ceb',
- 'cel',
- 'cha',
- 'chb',
- 'che',
- 'chg',
- 'chi',
- 'chk',
- 'chm',
- 'chn',
- 'cho',
- 'chp',
- 'chr',
- 'chu',
- 'chv',
- 'chy',
- 'cmc',
- 'cnr',
- 'cop',
- 'cor',
- 'cos',
- 'cpe',
- 'cpf',
- 'cpp',
- 'cre',
- 'crh',
- 'crp',
- 'csb',
- 'cus',
- 'cze',
- 'dak',
- 'dan',
- 'dar',
- 'day',
- 'del',
- 'den',
- 'dgr',
- 'din',
- 'div',
- 'doi',
- 'dra',
- 'dsb',
- 'dua',
- 'dum',
- 'dut',
- 'dyu',
- 'dzo',
- 'efi',
- 'egy',
- 'eka',
- 'elx',
- 'eng',
- 'enm',
- 'epo',
- 'est',
- 'ewe',
- 'ewo',
- 'fan',
- 'fao',
- 'fat',
- 'fij',
- 'fil',
- 'fin',
- 'fiu',
- 'fon',
- 'fre',
- 'frm',
- 'fro',
- 'frr',
- 'frs',
- 'fry',
- 'ful',
- 'fur',
- 'gaa',
- 'gay',
- 'gba',
- 'gem',
- 'geo',
- 'ger',
- 'gez',
- 'gil',
- 'gla',
- 'gle',
- 'glg',
- 'glv',
- 'gmh',
- 'goh',
- 'gon',
- 'gor',
- 'got',
- 'grb',
- 'grc',
- 'gre',
- 'grn',
- 'gsw',
- 'guj',
- 'gwi',
- 'hai',
- 'hat',
- 'hau',
- 'haw',
- 'heb',
- 'her',
- 'hil',
- 'him',
- 'hin',
- 'hit',
- 'hmn',
- 'hmo',
- 'hrv',
- 'hsb',
- 'hun',
- 'hup',
- 'iba',
- 'ibo',
- 'ice',
- 'ido',
- 'iii',
- 'ijo',
- 'iku',
- 'ile',
- 'ilo',
- 'ina',
- 'inc',
- 'ind',
- 'ine',
- 'inh',
- 'ipk',
- 'ira',
- 'iro',
- 'ita',
- 'jav',
- 'jbo',
- 'jpn',
- 'jpr',
- 'jrb',
- 'kaa',
- 'kab',
- 'kac',
- 'kal',
- 'kam',
- 'kan',
- 'kar',
- 'kas',
- 'kau',
- 'kaw',
- 'kaz',
- 'kbd',
- 'kha',
- 'khi',
- 'khm',
- 'kho',
- 'kik',
- 'kin',
- 'kir',
- 'kmb',
- 'kok',
- 'kom',
- 'kon',
- 'kor',
- 'kos',
- 'kpe',
- 'krc',
- 'krl',
- 'kro',
- 'kru',
- 'kua',
- 'kum',
- 'kur',
- 'kut',
- 'lad',
- 'lah',
- 'lam',
- 'lao',
- 'lat',
- 'lav',
- 'lez',
- 'lim',
- 'lin',
- 'lit',
- 'lol',
- 'loz',
- 'ltz',
- 'lua',
- 'lub',
- 'lug',
- 'lui',
- 'lun',
- 'luo',
- 'lus',
- 'mac',
- 'mad',
- 'mag',
- 'mah',
- 'mai',
- 'mak',
- 'mal',
- 'man',
- 'mao',
- 'map',
- 'mar',
- 'mas',
- 'may',
- 'mdf',
- 'mdr',
- 'men',
- 'mga',
- 'mic',
- 'min',
- 'mis',
- 'mkh',
- 'mlg',
- 'mlt',
- 'mnc',
- 'mni',
- 'mno',
- 'moh',
- 'mon',
- 'mos',
- 'mul',
- 'mun',
- 'mus',
- 'mwl',
- 'mwr',
- 'myn',
- 'myv',
- 'nah',
- 'nai',
- 'nap',
- 'nau',
- 'nav',
- 'nbl',
- 'nde',
- 'ndo',
- 'nds',
- 'nep',
- 'new',
- 'nia',
- 'nic',
- 'niu',
- 'nno',
- 'nob',
- 'nog',
- 'non',
- 'nor',
- 'nqo',
- 'nso',
- 'nub',
- 'nwc',
- 'nya',
- 'nym',
- 'nyn',
- 'nyo',
- 'nzi',
- 'oci',
- 'oji',
- 'ori',
- 'orm',
- 'osa',
- 'oss',
- 'ota',
- 'oto',
- 'paa',
- 'pag',
- 'pal',
- 'pam',
- 'pan',
- 'pap',
- 'pau',
- 'peo',
- 'per',
- 'phi',
- 'phn',
- 'pli',
- 'pol',
- 'pon',
- 'por',
- 'pra',
- 'pro',
- 'pus',
- 'qaa',
- 'que',
- 'raj',
- 'rap',
- 'rar',
- 'roa',
- 'roh',
- 'rom',
- 'rum',
- 'run',
- 'rup',
- 'rus',
- 'sad',
- 'sag',
- 'sah',
- 'sai',
- 'sal',
- 'sam',
- 'san',
- 'sas',
- 'sat',
- 'scn',
- 'sco',
- 'sel',
- 'sem',
- 'sga',
- 'sgn',
- 'shn',
- 'sid',
- 'sin',
- 'sio',
- 'sit',
- 'sla',
- 'slo',
- 'slv',
- 'sma',
- 'sme',
- 'smi',
- 'smj',
- 'smn',
- 'smo',
- 'sms',
- 'sna',
- 'snd',
- 'snk',
- 'sog',
- 'som',
- 'son',
- 'sot',
- 'spa',
- 'srd',
- 'srn',
- 'srp',
- 'srr',
- 'ssa',
- 'ssw',
- 'suk',
- 'sun',
- 'sus',
- 'sux',
- 'swa',
- 'swe',
- 'syc',
- 'syr',
- 'tah',
- 'tai',
- 'tam',
- 'tat',
- 'tel',
- 'tem',
- 'ter',
- 'tet',
- 'tgk',
- 'tgl',
- 'tha',
- 'tib',
- 'tig',
- 'tir',
- 'tiv',
- 'tkl',
- 'tlh',
- 'tli',
- 'tmh',
- 'tog',
- 'ton',
- 'tpi',
- 'tsi',
- 'tsn',
- 'tso',
- 'tuk',
- 'tum',
- 'tup',
- 'tur',
- 'tut',
- 'tvl',
- 'twi',
- 'tyv',
- 'udm',
- 'uga',
- 'uig',
- 'ukr',
- 'umb',
- 'und',
- 'urd',
- 'uzb',
- 'vai',
- 'ven',
- 'vie',
- 'vol',
- 'vot',
- 'wak',
- 'wal',
- 'war',
- 'was',
- 'wel',
- 'wen',
- 'wln',
- 'wol',
- 'xal',
- 'xho',
- 'yao',
- 'yap',
- 'yid',
- 'yor',
- 'ypk',
- 'zap',
- 'zbl',
- 'zen',
- 'zgh',
- 'zha',
- 'znd',
- 'zul',
- 'zun',
- 'zxx',
- 'zza'
-);
-
-CREATE TABLE language (
- language_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- work_id UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
- language_code language_code NOT NULL,
- language_relation language_relation NOT NULL,
- main_language BOOLEAN NOT NULL DEFAULT False
-);
-
--- UNIQ index on combination of language and work
-CREATE UNIQUE INDEX language_uniq_work_idx ON language(work_id, language_code);
-
--------------------- Series
-
-CREATE TYPE series_type AS ENUM (
- 'journal',
- 'book-series'
-);
-
-CREATE TABLE series (
- series_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- series_type series_type NOT NULL,
- series_name TEXT NOT NULL CHECK (octet_length(series_name) >= 1),
- issn_print TEXT NOT NULL CHECK (issn_print ~* '\d{4}\-\d{3}(\d|X)'),
- issn_digital TEXT NOT NULL CHECK (issn_digital ~* '\d{4}\-\d{3}(\d|X)'),
- series_url TEXT CHECK (series_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'),
- imprint_id UUID NOT NULL REFERENCES imprint(imprint_id) ON DELETE CASCADE
-);
-
--- UNIQ index on ISSNs
-CREATE UNIQUE INDEX series_issn_print_idx ON series(issn_print);
-CREATE UNIQUE INDEX series_issn_digital_idx ON series(issn_digital);
-
-CREATE TABLE issue (
- series_id UUID NOT NULL REFERENCES series(series_id) ON DELETE CASCADE,
- work_id UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
- issue_ordinal INTEGER NOT NULL CHECK (issue_ordinal > 0),
- PRIMARY KEY (series_id, work_id)
-);
-
--- UNIQ index on issue_ordinal and series_id
-CREATE UNIQUE INDEX issue_uniq_ord_in_series_idx ON issue(series_id, issue_ordinal);
-
--------------------- Contributor
-
-CREATE TABLE contributor (
- contributor_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- first_name TEXT CHECK (octet_length(first_name) >= 1),
- last_name TEXT NOT NULL CHECK (octet_length(last_name) >= 1),
- full_name TEXT NOT NULL CHECK (octet_length(full_name) >= 1),
- orcid TEXT CHECK (orcid ~* '0000-000(1-[5-9]|2-[0-9]|3-[0-4])\d{3}-\d{3}[\dX]'),
- website TEXT CHECK (octet_length(website) >= 1)
-);
--- case-insensitive UNIQ index on orcid
-CREATE UNIQUE INDEX orcid_uniq_idx ON contributor(lower(orcid));
-
-CREATE TYPE contribution_type AS ENUM (
- 'author',
- 'editor',
- 'translator',
- 'photographer',
- 'ilustrator',
- 'music-editor',
- 'foreword-by',
- 'introduction-by',
- 'afterword-by',
- 'preface-by'
-);
-
-CREATE TABLE contribution (
- work_id UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
- contributor_id UUID NOT NULL REFERENCES contributor(contributor_id) ON DELETE CASCADE,
- contribution_type contribution_type NOT NULL,
- main_contribution BOOLEAN NOT NULL DEFAULT False,
- biography TEXT CHECK (octet_length(biography) >= 1),
- institution TEXT CHECK (octet_length(institution) >= 1),
- PRIMARY KEY (work_id, contributor_id, contribution_type)
-);
-
--------------------- Publication
-
-CREATE TYPE publication_type AS ENUM (
- 'Paperback',
- 'Hardback',
- 'PDF',
- 'HTML',
- 'XML',
- 'Epub',
- 'Mobi'
-);
-
-CREATE TABLE publication (
- publication_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- publication_type publication_type NOT NULL,
- work_id UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
- isbn TEXT CHECK (octet_length(isbn) = 17),
- publication_url TEXT CHECK (publication_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)')
-);
-
-CREATE INDEX publication_isbn_idx ON publication(isbn);
-
-
--------------------- Price
-
-CREATE TYPE currency_code AS ENUM (
- 'adp',
- 'aed',
- 'afa',
- 'afn',
- 'alk',
- 'all',
- 'amd',
- 'ang',
- 'aoa',
- 'aok',
- 'aon',
- 'aor',
- 'ara',
- 'arp',
- 'ars',
- 'ary',
- 'ats',
- 'aud',
- 'awg',
- 'aym',
- 'azm',
- 'azn',
- 'bad',
- 'bam',
- 'bbd',
- 'bdt',
- 'bec',
- 'bef',
- 'bel',
- 'bgj',
- 'bgk',
- 'bgl',
- 'bgn',
- 'bhd',
- 'bif',
- 'bmd',
- 'bnd',
- 'bob',
- 'bop',
- 'bov',
- 'brb',
- 'brc',
- 'bre',
- 'brl',
- 'brn',
- 'brr',
- 'bsd',
- 'btn',
- 'buk',
- 'bwp',
- 'byb',
- 'byn',
- 'byr',
- 'bzd',
- 'cad',
- 'cdf',
- 'chc',
- 'che',
- 'chf',
- 'chw',
- 'clf',
- 'clp',
- 'cny',
- 'cop',
- 'cou',
- 'crc',
- 'csd',
- 'csj',
- 'csk',
- 'cuc',
- 'cup',
- 'cve',
- 'cyp',
- 'czk',
- 'ddm',
- 'dem',
- 'djf',
- 'dkk',
- 'dop',
- 'dzd',
- 'ecs',
- 'ecv',
- 'eek',
- 'egp',
- 'ern',
- 'esa',
- 'esb',
- 'esp',
- 'etb',
- 'eur',
- 'fim',
- 'fjd',
- 'fkp',
- 'frf',
- 'gbp',
- 'gek',
- 'gel',
- 'ghc',
- 'ghp',
- 'ghs',
- 'gip',
- 'gmd',
- 'gne',
- 'gnf',
- 'gns',
- 'gqe',
- 'grd',
- 'gtq',
- 'gwe',
- 'gwp',
- 'gyd',
- 'hkd',
- 'hnl',
- 'hrd',
- 'hrk',
- 'htg',
- 'huf',
- 'idr',
- 'iep',
- 'ilp',
- 'ilr',
- 'ils',
- 'inr',
- 'iqd',
- 'irr',
- 'isj',
- 'isk',
- 'itl',
- 'jmd',
- 'jod',
- 'jpy',
- 'kes',
- 'kgs',
- 'khr',
- 'kmf',
- 'kpw',
- 'krw',
- 'kwd',
- 'kyd',
- 'kzt',
- 'laj',
- 'lak',
- 'lbp',
- 'lkr',
- 'lrd',
- 'lsl',
- 'lsm',
- 'ltl',
- 'ltt',
- 'luc',
- 'luf',
- 'lul',
- 'lvl',
- 'lvr',
- 'lyd',
- 'mad',
- 'mdl',
- 'mga',
- 'mgf',
- 'mkd',
- 'mlf',
- 'mmk',
- 'mnt',
- 'mop',
- 'mro',
- 'mru',
- 'mtl',
- 'mtp',
- 'mur',
- 'mvq',
- 'mvr',
- 'mwk',
- 'mxn',
- 'mxp',
- 'mxv',
- 'myr',
- 'mze',
- 'mzm',
- 'mzn',
- 'nad',
- 'ngn',
- 'nic',
- 'nio',
- 'nlg',
- 'nok',
- 'npr',
- 'nzd',
- 'omr',
- 'pab',
- 'peh',
- 'pei',
- 'pen',
- 'pes',
- 'pgk',
- 'php',
- 'pkr',
- 'pln',
- 'plz',
- 'pte',
- 'pyg',
- 'qar',
- 'rhd',
- 'rok',
- 'rol',
- 'ron',
- 'rsd',
- 'rub',
- 'rur',
- 'rwf',
- 'sar',
- 'sbd',
- 'scr',
- 'sdd',
- 'sdg',
- 'sdp',
- 'sek',
- 'sgd',
- 'shp',
- 'sit',
- 'skk',
- 'sll',
- 'sos',
- 'srd',
- 'srg',
- 'ssp',
- 'std',
- 'stn',
- 'sur',
- 'svc',
- 'syp',
- 'szl',
- 'thb',
- 'tjr',
- 'tjs',
- 'tmm',
- 'tmt',
- 'tnd',
- 'top',
- 'tpe',
- 'trl',
- 'try',
- 'ttd',
- 'twd',
- 'tzs',
- 'uah',
- 'uak',
- 'ugs',
- 'ugw',
- 'ugx',
- 'usd',
- 'usn',
- 'uss',
- 'uyi',
- 'uyn',
- 'uyp',
- 'uyu',
- 'uyw',
- 'uzs',
- 'veb',
- 'vef',
- 'ves',
- 'vnc',
- 'vnd',
- 'vuv',
- 'wst',
- 'xaf',
- 'xag',
- 'xau',
- 'xba',
- 'xbb',
- 'xbc',
- 'xbd',
- 'xcd',
- 'xdr',
- 'xeu',
- 'xfo',
- 'xfu',
- 'xof',
- 'xpd',
- 'xpf',
- 'xpt',
- 'xre',
- 'xsu',
- 'xts',
- 'xua',
- 'xxx',
- 'ydd',
- 'yer',
- 'yud',
- 'yum',
- 'yun',
- 'zal',
- 'zar',
- 'zmk',
- 'zmw',
- 'zrn',
- 'zrz',
- 'zwc',
- 'zwd',
- 'zwl',
- 'zwn',
- 'zwr'
-);
-
-CREATE TABLE price (
- price_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- publication_id UUID NOT NULL REFERENCES publication(publication_id) ON DELETE CASCADE,
- currency_code currency_code NOT NULL,
- unit_price double precision NOT NULL
-);
-
--------------------- Subject
-
-CREATE TYPE subject_type AS ENUM (
- 'bic',
- 'bisac',
- 'thema',
- 'lcc',
- 'custom',
- 'keyword'
-);
-
-CREATE TABLE subject (
- subject_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- work_id UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
- subject_type subject_type NOT NULL,
- subject_code TEXT NOT NULL CHECK (octet_length(subject_code) >= 1),
- subject_ordinal INTEGER NOT NULL CHECK (subject_ordinal > 0)
-);
-
--------------------- Funder
-
-CREATE TABLE funder (
- funder_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- funder_name TEXT NOT NULL CHECK (octet_length(funder_name) >= 1),
- funder_doi TEXT CHECK (funder_doi ~* 'https:\/\/doi.org\/10.\d{4,9}\/[-._\;\(\)\/:a-zA-Z0-9]+$')
-);
--- case-insensitive UNIQ index on funder_doi
-CREATE UNIQUE INDEX funder_doi_uniq_idx ON funder(lower(funder_doi));
-
-CREATE TABLE funding (
- funding_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- work_id UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
- funder_id UUID NOT NULL REFERENCES funder(funder_id) ON DELETE CASCADE,
- program TEXT CHECK (octet_length(program) >= 1),
- project_name TEXT CHECK (octet_length(project_name) >= 1),
- project_shortname TEXT CHECK (octet_length(project_shortname) >= 1),
- grant_number TEXT CHECK (octet_length(grant_number) >= 1),
- jurisdiction TEXT CHECK (octet_length(jurisdiction) >= 1)
-);
diff --git a/thoth-api/migrations/0.10.0/down.sql b/thoth-api/migrations/0.10.0/down.sql
deleted file mode 100644
index e581cc31..00000000
--- a/thoth-api/migrations/0.10.0/down.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE work
- DROP COLUMN IF EXISTS bibliography_note;
diff --git a/thoth-api/migrations/0.10.0/up.sql b/thoth-api/migrations/0.10.0/up.sql
deleted file mode 100644
index 6e138725..00000000
--- a/thoth-api/migrations/0.10.0/up.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE work
- ADD COLUMN IF NOT EXISTS bibliography_note TEXT CHECK (octet_length(bibliography_note) >= 1);
diff --git a/thoth-api/migrations/0.11.3/down.sql b/thoth-api/migrations/0.11.3/down.sql
deleted file mode 100644
index 6d21b774..00000000
--- a/thoth-api/migrations/0.11.3/down.sql
+++ /dev/null
@@ -1,6 +0,0 @@
--- Reinstate earlier version of ORCID validation
-
-ALTER TABLE contributor
- DROP CONSTRAINT contributor_orcid_check,
- ADD CONSTRAINT contributor_orcid_check
- CHECK (orcid ~ '^https:\/\/orcid\.org\/0000-000(1-[5-9]|2-[0-9]|3-[0-4])\d{3}-\d{3}[\dX]$');
diff --git a/thoth-api/migrations/0.11.3/up.sql b/thoth-api/migrations/0.11.3/up.sql
deleted file mode 100644
index e3662ebc..00000000
--- a/thoth-api/migrations/0.11.3/up.sql
+++ /dev/null
@@ -1,7 +0,0 @@
--- Make ORCID validation more permissive as the docs don't specify a strict pattern
--- Should be kept in line with Orcid::FromStr, although regex syntax differs slightly
-
-ALTER TABLE contributor
- DROP CONSTRAINT contributor_orcid_check,
- ADD CONSTRAINT contributor_orcid_check
- CHECK (orcid ~ '^https:\/\/orcid\.org\/\d{4}-\d{4}-\d{4}-\d{3}[\dX]$');
diff --git a/thoth-api/migrations/0.2.0/down.sql b/thoth-api/migrations/0.2.0/down.sql
deleted file mode 100644
index 5dfb76bd..00000000
--- a/thoth-api/migrations/0.2.0/down.sql
+++ /dev/null
@@ -1 +0,0 @@
-DROP TABLE account;
diff --git a/thoth-api/migrations/0.2.0/up.sql b/thoth-api/migrations/0.2.0/up.sql
deleted file mode 100644
index 908a6c80..00000000
--- a/thoth-api/migrations/0.2.0/up.sql
+++ /dev/null
@@ -1,17 +0,0 @@
--------------------- Account
-CREATE TABLE account (
- account_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- name TEXT NOT NULL CHECK (octet_length(name) >= 1),
- surname TEXT NOT NULL CHECK (octet_length(surname) >= 1),
- email TEXT NOT NULL CHECK (octet_length(email) >= 1),
- hash BYTEA NOT NULL,
- salt TEXT NOT NULL CHECK (octet_length(salt) >= 1),
- is_admin BOOLEAN NOT NULL DEFAULT False,
- is_bot BOOLEAN NOT NULL DEFAULT False,
- is_active BOOLEAN NOT NULL DEFAULT True,
- registered TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
- token TEXT NULL CHECK (OCTET_LENGTH(token) >= 1)
-);
-
--- case-insensitive UNIQ index on email
-CREATE UNIQUE INDEX email_uniq_idx ON account(lower(email));
diff --git a/thoth-api/migrations/0.2.11/down.sql b/thoth-api/migrations/0.2.11/down.sql
deleted file mode 100644
index c2456835..00000000
--- a/thoth-api/migrations/0.2.11/down.sql
+++ /dev/null
@@ -1,73 +0,0 @@
-DROP TRIGGER set_updated_at ON publisher;
-ALTER TABLE publisher
- DROP COLUMN created_at,
- DROP COLUMN updated_at;
-
-DROP TRIGGER set_updated_at ON imprint;
-ALTER TABLE imprint
- DROP COLUMN created_at,
- DROP COLUMN updated_at;
-
-DROP TRIGGER set_updated_at ON work;
-ALTER TABLE work
- DROP COLUMN created_at,
- DROP COLUMN updated_at;
-
-DROP TRIGGER set_updated_at ON language;
-ALTER TABLE language
- DROP COLUMN created_at,
- DROP COLUMN updated_at;
-
-DROP TRIGGER set_updated_at ON series;
-ALTER TABLE series
- DROP COLUMN created_at,
- DROP COLUMN updated_at;
-
-DROP TRIGGER set_updated_at ON issue;
-ALTER TABLE issue
- DROP COLUMN created_at,
- DROP COLUMN updated_at;
-
-DROP TRIGGER set_updated_at ON contributor;
-ALTER TABLE contributor
- DROP COLUMN created_at,
- DROP COLUMN updated_at;
-
-DROP TRIGGER set_updated_at ON contribution;
-ALTER TABLE contribution
- DROP COLUMN created_at,
- DROP COLUMN updated_at;
-
-DROP TRIGGER set_updated_at ON publication;
-ALTER TABLE publication
- DROP COLUMN created_at,
- DROP COLUMN updated_at;
-
-DROP TRIGGER set_updated_at ON price;
-ALTER TABLE price
- DROP COLUMN created_at,
- DROP COLUMN updated_at;
-
-DROP TRIGGER set_updated_at ON subject;
-ALTER TABLE subject
- DROP COLUMN created_at,
- DROP COLUMN updated_at;
-
-DROP TRIGGER set_updated_at ON funder;
-ALTER TABLE funder
- DROP COLUMN created_at,
- DROP COLUMN updated_at;
-
-DROP TRIGGER set_updated_at ON funding;
-ALTER TABLE funding
- DROP COLUMN created_at,
- DROP COLUMN updated_at;
-
-DROP TRIGGER set_updated_at ON account;
-ALTER TABLE account
- RENAME COLUMN created_at TO registered;
-ALTER TABLE account
- ALTER COLUMN registered TYPE TIMESTAMP WITH TIME ZONE,
- ALTER COLUMN registered SET NOT NULL,
- ALTER COLUMN registered SET DEFAULT now(),
- DROP COLUMN updated_at;
diff --git a/thoth-api/migrations/0.2.11/up.sql b/thoth-api/migrations/0.2.11/up.sql
deleted file mode 100644
index 7e5116f5..00000000
--- a/thoth-api/migrations/0.2.11/up.sql
+++ /dev/null
@@ -1,73 +0,0 @@
-ALTER TABLE publisher
- ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-SELECT diesel_manage_updated_at('publisher');
-
-ALTER TABLE imprint
- ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-SELECT diesel_manage_updated_at('imprint');
-
-ALTER TABLE work
- ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-SELECT diesel_manage_updated_at('work');
-
-ALTER TABLE language
- ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-SELECT diesel_manage_updated_at('language');
-
-ALTER TABLE series
- ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-SELECT diesel_manage_updated_at('series');
-
-ALTER TABLE issue
- ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-SELECT diesel_manage_updated_at('issue');
-
-ALTER TABLE contributor
- ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-SELECT diesel_manage_updated_at('contributor');
-
-ALTER TABLE contribution
- ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-SELECT diesel_manage_updated_at('contribution');
-
-ALTER TABLE publication
- ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-SELECT diesel_manage_updated_at('publication');
-
-ALTER TABLE price
- ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-SELECT diesel_manage_updated_at('price');
-
-ALTER TABLE subject
- ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-SELECT diesel_manage_updated_at('subject');
-
-ALTER TABLE funder
- ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-SELECT diesel_manage_updated_at('funder');
-
-ALTER TABLE funding
- ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-SELECT diesel_manage_updated_at('funding');
-
-ALTER TABLE account
- RENAME COLUMN registered TO created_at;
-ALTER TABLE account
- ALTER COLUMN created_at TYPE TIMESTAMP,
- ALTER COLUMN created_at SET NOT NULL,
- ALTER COLUMN created_at SET DEFAULT CURRENT_TIMESTAMP,
- ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-SELECT diesel_manage_updated_at('account');
diff --git a/thoth-api/migrations/0.3.0/down.sql b/thoth-api/migrations/0.3.0/down.sql
deleted file mode 100644
index 03723c6d..00000000
--- a/thoth-api/migrations/0.3.0/down.sql
+++ /dev/null
@@ -1,23 +0,0 @@
-DROP TRIGGER set_updated_at ON publisher_account;
-DROP TABLE publisher_account;
-
-ALTER TABLE account RENAME COLUMN is_superuser TO is_admin;
-
-ALTER TABLE contribution
- DROP COLUMN first_name,
- DROP COLUMN last_name,
- DROP COLUMN full_name;
-
-DROP TABLE publisher_history;
-DROP TABLE imprint_history;
-DROP TABLE work_history;
-DROP TABLE language_history;
-DROP TABLE series_history;
-DROP TABLE issue_history;
-DROP TABLE contributor_history;
-DROP TABLE contribution_history;
-DROP TABLE publication_history;
-DROP TABLE price_history;
-DROP TABLE subject_history;
-DROP TABLE funder_history;
-DROP TABLE funding_history;
diff --git a/thoth-api/migrations/0.3.0/up.sql b/thoth-api/migrations/0.3.0/up.sql
deleted file mode 100644
index c63c43a4..00000000
--- a/thoth-api/migrations/0.3.0/up.sql
+++ /dev/null
@@ -1,139 +0,0 @@
-CREATE TABLE publisher_account (
- account_id UUID NOT NULL REFERENCES account(account_id) ON DELETE CASCADE,
- publisher_id UUID NOT NULL REFERENCES publisher(publisher_id) ON DELETE CASCADE,
- is_admin BOOLEAN NOT NULL DEFAULT False,
- created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- PRIMARY KEY (account_id, publisher_id)
-);
-SELECT diesel_manage_updated_at('publisher_account');
-
-ALTER TABLE account RENAME COLUMN is_admin TO is_superuser;
-
-ALTER TABLE contribution
- ADD COLUMN first_name TEXT,
- ADD COLUMN last_name TEXT,
- ADD COLUMN full_name TEXT;
-
-UPDATE contribution
- SET first_name = contributor.first_name,
- last_name = contributor.last_name,
- full_name = contributor.full_name
- FROM contributor
- WHERE contribution.contributor_id = contributor.contributor_id;
-
-ALTER TABLE contribution
- ALTER COLUMN last_name SET NOT NULL,
- ALTER COLUMN full_name SET NOT NULL,
- ADD CONSTRAINT contribution_first_name_check CHECK (octet_length(first_name) >= 1),
- ADD CONSTRAINT contribution_last_name_check CHECK (octet_length(last_name) >= 1),
- ADD CONSTRAINT contribution_full_name_check CHECK (octet_length(full_name) >= 1);
-
-CREATE TABLE publisher_history (
- publisher_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- publisher_id UUID NOT NULL REFERENCES publisher(publisher_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
-CREATE TABLE imprint_history (
- imprint_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- imprint_id UUID NOT NULL REFERENCES imprint(imprint_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
-CREATE TABLE work_history (
- work_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- work_id UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
-CREATE TABLE language_history (
- language_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- language_id UUID NOT NULL REFERENCES language(language_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
-CREATE TABLE series_history (
- series_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- series_id UUID NOT NULL REFERENCES series(series_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
-CREATE TABLE issue_history (
- issue_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- series_id UUID NOT NULL,
- work_id UUID NOT NULL,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- FOREIGN KEY (series_id, work_id) REFERENCES issue(series_id, work_id) ON DELETE CASCADE
-);
-
-CREATE TABLE contributor_history (
- contributor_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- contributor_id UUID NOT NULL REFERENCES contributor(contributor_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
-CREATE TABLE contribution_history (
- contribution_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- work_id UUID NOT NULL,
- contributor_id UUID NOT NULL,
- contribution_type contribution_type NOT NULL,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- FOREIGN KEY (work_id, contributor_id, contribution_type) REFERENCES contribution(work_id, contributor_id, contribution_type) ON DELETE CASCADE
-);
-
-CREATE TABLE publication_history (
- publication_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- publication_id UUID NOT NULL REFERENCES publication(publication_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
-CREATE TABLE price_history (
- price_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- price_id UUID NOT NULL REFERENCES price(price_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
-CREATE TABLE subject_history (
- subject_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- subject_id UUID NOT NULL REFERENCES subject(subject_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
-CREATE TABLE funder_history (
- funder_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- funder_id UUID NOT NULL REFERENCES funder(funder_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
-CREATE TABLE funding_history (
- funding_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- funding_id UUID NOT NULL REFERENCES funding(funding_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
diff --git a/thoth-api/migrations/0.3.5/down.sql b/thoth-api/migrations/0.3.5/down.sql
deleted file mode 100644
index 0399274b..00000000
--- a/thoth-api/migrations/0.3.5/down.sql
+++ /dev/null
@@ -1,60 +0,0 @@
--- Convert Issue table to use composite key instead of single primary key
-
-ALTER TABLE issue_history
- ADD COLUMN series_id UUID,
- ADD COLUMN work_id UUID;
-
-UPDATE issue_history
- SET series_id = issue.series_id,
- work_id = issue.work_id
- FROM issue
- WHERE issue_history.issue_id = issue.issue_id;
-
-ALTER TABLE issue_history
- DROP COLUMN issue_id,
- ALTER COLUMN series_id SET NOT NULL,
- ALTER COLUMN work_id SET NOT NULL;
-
-ALTER TABLE issue
- DROP COLUMN issue_id,
- ADD PRIMARY KEY (series_id, work_id),
- -- Remove the manually-added constraint which will now be enforced by the composite key
- DROP CONSTRAINT issue_series_id_work_id_uniq;
-
-ALTER TABLE issue_history
- ADD CONSTRAINT issue_history_series_id_work_id_fkey
- FOREIGN KEY (series_id, work_id)
- REFERENCES issue(series_id, work_id)
- ON DELETE CASCADE;
-
--- Convert Contribution table to use composite key instead of single primary key
-
-ALTER TABLE contribution_history
- ADD COLUMN work_id UUID,
- ADD COLUMN contributor_id UUID,
- ADD COLUMN contribution_type contribution_type;
-
-UPDATE contribution_history
- SET work_id = contribution.work_id,
- contributor_id = contribution.contributor_id,
- contribution_type = contribution.contribution_type
- FROM contribution
- WHERE contribution_history.contribution_id = contribution.contribution_id;
-
-ALTER TABLE contribution_history
- DROP COLUMN contribution_id,
- ALTER COLUMN work_id SET NOT NULL,
- ALTER COLUMN contributor_id SET NOT NULL,
- ALTER COLUMN contribution_type SET NOT NULL;
-
-ALTER TABLE contribution
- DROP COLUMN contribution_id,
- ADD PRIMARY KEY (work_id, contributor_id, contribution_type),
- -- Remove the manually-added constraint which will now be enforced by the composite key
- DROP CONSTRAINT contribution_work_id_contributor_id_contribution_type_uniq;
-
-ALTER TABLE contribution_history
- ADD CONSTRAINT contribution_history_work_id_contributor_id_contribution_t_fkey
- FOREIGN KEY (work_id, contributor_id, contribution_type)
- REFERENCES contribution(work_id, contributor_id, contribution_type)
- ON DELETE CASCADE;
diff --git a/thoth-api/migrations/0.3.5/up.sql b/thoth-api/migrations/0.3.5/up.sql
deleted file mode 100644
index f1e3a9aa..00000000
--- a/thoth-api/migrations/0.3.5/up.sql
+++ /dev/null
@@ -1,63 +0,0 @@
--- Convert Issue table to use single primary key instead of composite key
-
-ALTER TABLE issue
- ADD COLUMN issue_id UUID NOT NULL DEFAULT uuid_generate_v4();
-
-ALTER TABLE issue_history
- ADD COLUMN issue_id UUID;
-
-UPDATE issue_history
- SET issue_id = issue.issue_id
- FROM issue
- WHERE issue_history.series_id = issue.series_id
- AND issue_history.work_id = issue.work_id;
-
-ALTER TABLE issue_history
- DROP COLUMN series_id,
- DROP COLUMN work_id,
- ALTER COLUMN issue_id SET NOT NULL;
-
-ALTER TABLE issue
- DROP CONSTRAINT issue_pkey,
- ADD PRIMARY KEY (issue_id),
- -- Retain the data constraint originally enforced by the composite key
- ADD CONSTRAINT issue_series_id_work_id_uniq UNIQUE (series_id, work_id);
-
-ALTER TABLE issue_history
- ADD CONSTRAINT issue_history_issue_id_fkey
- FOREIGN KEY (issue_id)
- REFERENCES issue(issue_id)
- ON DELETE CASCADE;
-
--- Convert Contribution table to use single primary key instead of composite key
-
-ALTER TABLE contribution
- ADD COLUMN contribution_id UUID NOT NULL DEFAULT uuid_generate_v4();
-
-ALTER TABLE contribution_history
- ADD COLUMN contribution_id UUID;
-
-UPDATE contribution_history
- SET contribution_id = contribution.contribution_id
- FROM contribution
- WHERE contribution_history.work_id = contribution.work_id
- AND contribution_history.contributor_id = contribution.contributor_id
- AND contribution_history.contribution_type = contribution.contribution_type;
-
-ALTER TABLE contribution_history
- DROP COLUMN work_id,
- DROP COLUMN contributor_id,
- DROP COLUMN contribution_type,
- ALTER COLUMN contribution_id SET NOT NULL;
-
-ALTER TABLE contribution
- DROP CONSTRAINT contribution_pkey,
- ADD PRIMARY KEY (contribution_id),
- -- Retain the data constraint originally enforced by the composite key
- ADD CONSTRAINT contribution_work_id_contributor_id_contribution_type_uniq UNIQUE (work_id, contributor_id, contribution_type);
-
-ALTER TABLE contribution_history
- ADD CONSTRAINT contribution_history_contribution_id_fkey
- FOREIGN KEY (contribution_id)
- REFERENCES contribution(contribution_id)
- ON DELETE CASCADE;
diff --git a/thoth-api/migrations/0.4.1/down.sql b/thoth-api/migrations/0.4.1/down.sql
deleted file mode 100644
index 035922c9..00000000
--- a/thoth-api/migrations/0.4.1/down.sql
+++ /dev/null
@@ -1,16 +0,0 @@
--- Reinstate earlier versions of ORCID and DOI validation
-
-ALTER TABLE contributor
- DROP CONSTRAINT contributor_orcid_check,
- ADD CONSTRAINT contributor_orcid_check
- CHECK (orcid ~* '0000-000(1-[5-9]|2-[0-9]|3-[0-4])\d{3}-\d{3}[\dX]');
-
-ALTER TABLE work
- DROP CONSTRAINT work_doi_check,
- ADD CONSTRAINT work_doi_check
- CHECK (doi ~* 'https:\/\/doi.org\/10.\d{4,9}\/[-._\;\(\)\/:a-zA-Z0-9]+$');
-
-ALTER TABLE funder
- DROP CONSTRAINT funder_funder_doi_check,
- ADD CONSTRAINT funder_funder_doi_check
- CHECK (funder_doi ~* 'https:\/\/doi.org\/10.\d{4,9}\/[-._\;\(\)\/:a-zA-Z0-9]+$');
diff --git a/thoth-api/migrations/0.4.1/up.sql b/thoth-api/migrations/0.4.1/up.sql
deleted file mode 100644
index 2eb361b0..00000000
--- a/thoth-api/migrations/0.4.1/up.sql
+++ /dev/null
@@ -1,21 +0,0 @@
--- Improve validation of ORCID identifiers (include protocol/resource name, make case-sensitive)
--- Should be kept in line with Orcid::FromStr, although regex syntax differs slightly
-
-ALTER TABLE contributor
- DROP CONSTRAINT contributor_orcid_check,
- ADD CONSTRAINT contributor_orcid_check
- CHECK (orcid ~ '^https:\/\/orcid\.org\/0000-000(1-[5-9]|2-[0-9]|3-[0-4])\d{3}-\d{3}[\dX]$');
-
--- Improve validation of DOI identifiers (add line start marker, escape periods, make case-sensitive)
--- Should be kept in line with Orcid::FromStr, although regex syntax differs slightly
--- (e.g. `;()/` need to be escaped here but not in Orcid::FromStr)
-
-ALTER TABLE work
- DROP CONSTRAINT work_doi_check,
- ADD CONSTRAINT work_doi_check
- CHECK (doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\/:a-zA-Z0-9]+$');
-
-ALTER TABLE funder
- DROP CONSTRAINT funder_funder_doi_check,
- ADD CONSTRAINT funder_funder_doi_check
- CHECK (funder_doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\/:a-zA-Z0-9]+$');
diff --git a/thoth-api/migrations/0.4.2/down.sql b/thoth-api/migrations/0.4.2/down.sql
deleted file mode 100644
index 6e526384..00000000
--- a/thoth-api/migrations/0.4.2/down.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE contribution
- DROP COLUMN contribution_ordinal;
\ No newline at end of file
diff --git a/thoth-api/migrations/0.4.2/up.sql b/thoth-api/migrations/0.4.2/up.sql
deleted file mode 100644
index 2b6a4220..00000000
--- a/thoth-api/migrations/0.4.2/up.sql
+++ /dev/null
@@ -1,24 +0,0 @@
-ALTER TABLE contribution
- ADD COLUMN contribution_ordinal INTEGER;
-
--- As a default, set the `contribution_ordinal` for existing records to reflect
--- the order in which they were added (within separate groups for each work).
--- We should be able to find this by sorting on the `created_at` timestamp, however,
--- records created prior to the introduction of `created_at` in v0.2.11 may have
--- identical default values for this field. Therefore, we perform a secondary
--- sort on the system column `ctid`; although this value is subject to change and
--- should not be relied upon, it should give a suitable rough ordering here.
-UPDATE contribution
- SET contribution_ordinal = c.rownum
- FROM (
- SELECT
- contribution_id,
- row_number() OVER (PARTITION BY work_id ORDER BY created_at,ctid) AS rownum
- FROM contribution
- ) c
- WHERE contribution.contribution_id = c.contribution_id;
-
-ALTER TABLE contribution
- ALTER COLUMN contribution_ordinal SET NOT NULL,
- ADD CONSTRAINT contribution_contribution_ordinal_check CHECK (contribution_ordinal > 0),
- ADD CONSTRAINT contribution_contribution_ordinal_work_id_uniq UNIQUE (contribution_ordinal, work_id);
\ No newline at end of file
diff --git a/thoth-api/migrations/0.4.5/down.sql b/thoth-api/migrations/0.4.5/down.sql
deleted file mode 100644
index 8a52d7b4..00000000
--- a/thoth-api/migrations/0.4.5/down.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-ALTER TABLE work
- ALTER COLUMN width TYPE INTEGER,
- ALTER COLUMN height TYPE INTEGER;
diff --git a/thoth-api/migrations/0.4.5/up.sql b/thoth-api/migrations/0.4.5/up.sql
deleted file mode 100644
index c81d1667..00000000
--- a/thoth-api/migrations/0.4.5/up.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-ALTER TABLE work
- ALTER COLUMN width TYPE double precision,
- ALTER COLUMN height TYPE double precision;
diff --git a/thoth-api/migrations/0.5.0/down.sql b/thoth-api/migrations/0.5.0/down.sql
deleted file mode 100644
index 8b6ab3bf..00000000
--- a/thoth-api/migrations/0.5.0/down.sql
+++ /dev/null
@@ -1,39 +0,0 @@
-ALTER TABLE publication
- DROP CONSTRAINT publication_publication_type_work_id_uniq,
- ADD COLUMN publication_url TEXT CHECK (publication_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)');
-
--- Migrate location URLs back into publication table as far as possible before dropping location table:
--- set the landing_page or full_text_url of the canonical location as the main publication_url,
--- then create duplicate publications to store all other location URLs (landing page/full text).
--- Note this will create multiple identical publications if the same URL is re-used across location fields.
-UPDATE publication
- SET publication_url = location.landing_page
- FROM location
- WHERE publication.publication_id = location.publication_id
- AND location.canonical
- AND location.landing_page IS NOT NULL;
-UPDATE publication
- SET publication_url = location.full_text_url
- FROM location
- WHERE publication.publication_id = location.publication_id
- AND location.canonical
- AND location.full_text_url IS NOT NULL
- AND location.landing_page IS NULL;
-INSERT INTO publication(publication_type, work_id, publication_url)
- SELECT publication.publication_type, publication.work_id, location.landing_page FROM publication, location
- WHERE publication.publication_id = location.publication_id
- AND location.landing_page IS NOT NULL
- AND NOT location.canonical;
-INSERT INTO publication(publication_type, work_id, publication_url)
- SELECT publication.publication_type, publication.work_id, location.full_text_url FROM publication, location
- WHERE publication.publication_id = location.publication_id
- AND location.full_text_url IS NOT NULL
- AND (
- NOT location.canonical
- OR (location.canonical AND location.landing_page IS NOT NULL)
- );
-
-DROP TABLE location_history;
-DROP TRIGGER set_updated_at ON location;
-DROP TABLE location;
-DROP TYPE IF EXISTS location_platform;
diff --git a/thoth-api/migrations/0.5.0/up.sql b/thoth-api/migrations/0.5.0/up.sql
deleted file mode 100644
index 9cbb0c11..00000000
--- a/thoth-api/migrations/0.5.0/up.sql
+++ /dev/null
@@ -1,57 +0,0 @@
-CREATE TYPE location_platform AS ENUM (
- 'Project MUSE',
- 'OAPEN',
- 'DOAB',
- 'JSTOR',
- 'EBSCO Host',
- 'OCLC KB',
- 'ProQuest KB',
- 'ProQuest ExLibris',
- 'EBSCO KB',
- 'JISC KB',
- 'Other'
-);
-
-CREATE TABLE location (
- location_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- publication_id UUID NOT NULL REFERENCES publication(publication_id) ON DELETE CASCADE,
- landing_page TEXT CHECK (landing_page ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'),
- full_text_url TEXT CHECK (full_text_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'),
- location_platform location_platform NOT NULL DEFAULT 'Other',
- canonical BOOLEAN NOT NULL DEFAULT False,
- created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- -- Location must contain at least one of landing_page or full_text_url
- CONSTRAINT location_url_check CHECK (landing_page IS NOT NULL OR full_text_url IS NOT NULL)
-);
-SELECT diesel_manage_updated_at('location');
-
--- Only allow one canonical location per publication
-CREATE UNIQUE INDEX location_uniq_canonical_true_idx ON location(publication_id)
- WHERE canonical;
-
--- Only allow one instance of each platform (except 'Other') per publication
-CREATE UNIQUE INDEX location_uniq_platform_idx ON location(publication_id, location_platform)
- WHERE NOT location_platform = 'Other';
-
-CREATE TABLE location_history (
- location_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- location_id UUID NOT NULL REFERENCES location(location_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
--- Create location entries for every existing publication_url (assume all are landing pages)
--- If a publication has locations, exactly one of them must be canonical;
--- this command will create at most one location per publication, so make them all canonical.
-INSERT INTO location(publication_id, landing_page, canonical)
- SELECT publication_id, publication_url, True FROM publication WHERE publication_url IS NOT NULL;
-
-ALTER TABLE publication
- -- Only allow one publication of each type per work (existing data may breach this)
- -- To check for records which breach this constraint:
- -- `select * from publication a where (select count(*) from publication b where a.publication_type = b.publication_type and a.work_id = b.work_id) > 1 order by work_id, publication_type;`
- ADD CONSTRAINT publication_publication_type_work_id_uniq UNIQUE (publication_type, work_id),
- -- Remove publication_url column (all data should have been migrated to location table above)
- DROP COLUMN publication_url;
diff --git a/thoth-api/migrations/0.6.0/down.sql b/thoth-api/migrations/0.6.0/down.sql
deleted file mode 100644
index 293b9311..00000000
--- a/thoth-api/migrations/0.6.0/down.sql
+++ /dev/null
@@ -1,37 +0,0 @@
-ALTER TABLE contribution
- ADD COLUMN institution TEXT CHECK (octet_length(institution) >= 1);
-
--- Migrate affiliation information back into contribution table as far as possible
--- before dropping affiliation table. Where a contribution has multiple affiliations,
--- combine the institution names into a single semicolon-separated string.
-UPDATE contribution
- SET institution = subquery.institutions
- FROM (
- SELECT affiliation.contribution_id, string_agg(institution_name, '; ') AS institutions
- FROM institution, affiliation
- WHERE affiliation.institution_id = institution.institution_id
- GROUP BY affiliation.contribution_id
- ) AS subquery
- WHERE contribution.contribution_id = subquery.contribution_id;
-
-ALTER TABLE institution_history RENAME COLUMN institution_history_id TO funder_history_id;
-ALTER TABLE institution_history RENAME COLUMN institution_id TO funder_id;
-
-ALTER TABLE institution_history RENAME TO funder_history;
-
-ALTER TABLE institution RENAME COLUMN institution_id TO funder_id;
-ALTER TABLE institution RENAME COLUMN institution_name TO funder_name;
-ALTER TABLE institution RENAME COLUMN institution_doi TO funder_doi;
-
-ALTER TABLE institution
- DROP COLUMN ror,
- DROP COLUMN country_code;
-
-ALTER TABLE institution RENAME TO funder;
-
-ALTER TABLE funding RENAME COLUMN institution_id TO funder_id;
-
-DROP TYPE IF EXISTS country_code;
-
-DROP TABLE affiliation_history;
-DROP TABLE affiliation;
diff --git a/thoth-api/migrations/0.6.0/up.sql b/thoth-api/migrations/0.6.0/up.sql
deleted file mode 100644
index 925079ce..00000000
--- a/thoth-api/migrations/0.6.0/up.sql
+++ /dev/null
@@ -1,307 +0,0 @@
--- Order is alphabetical by name of country (see string equivalents in API enum)
-CREATE TYPE country_code AS ENUM (
- 'afg',
- 'ala',
- 'alb',
- 'dza',
- 'asm',
- 'and',
- 'ago',
- 'aia',
- 'ata',
- 'atg',
- 'arg',
- 'arm',
- 'abw',
- 'aus',
- 'aut',
- 'aze',
- 'bhs',
- 'bhr',
- 'bgd',
- 'brb',
- 'blr',
- 'bel',
- 'blz',
- 'ben',
- 'bmu',
- 'btn',
- 'bol',
- 'bes',
- 'bih',
- 'bwa',
- 'bvt',
- 'bra',
- 'iot',
- 'brn',
- 'bgr',
- 'bfa',
- 'bdi',
- 'cpv',
- 'khm',
- 'cmr',
- 'can',
- 'cym',
- 'caf',
- 'tcd',
- 'chl',
- 'chn',
- 'cxr',
- 'cck',
- 'col',
- 'com',
- 'cok',
- 'cri',
- 'civ',
- 'hrv',
- 'cub',
- 'cuw',
- 'cyp',
- 'cze',
- 'cod',
- 'dnk',
- 'dji',
- 'dma',
- 'dom',
- 'ecu',
- 'egy',
- 'slv',
- 'gnq',
- 'eri',
- 'est',
- 'swz',
- 'eth',
- 'flk',
- 'fro',
- 'fji',
- 'fin',
- 'fra',
- 'guf',
- 'pyf',
- 'atf',
- 'gab',
- 'gmb',
- 'geo',
- 'deu',
- 'gha',
- 'gib',
- 'grc',
- 'grl',
- 'grd',
- 'glp',
- 'gum',
- 'gtm',
- 'ggy',
- 'gin',
- 'gnb',
- 'guy',
- 'hti',
- 'hmd',
- 'hnd',
- 'hkg',
- 'hun',
- 'isl',
- 'ind',
- 'idn',
- 'irn',
- 'irq',
- 'irl',
- 'imn',
- 'isr',
- 'ita',
- 'jam',
- 'jpn',
- 'jey',
- 'jor',
- 'kaz',
- 'ken',
- 'kir',
- 'kwt',
- 'kgz',
- 'lao',
- 'lva',
- 'lbn',
- 'lso',
- 'lbr',
- 'lby',
- 'lie',
- 'ltu',
- 'lux',
- 'mac',
- 'mdg',
- 'mwi',
- 'mys',
- 'mdv',
- 'mli',
- 'mlt',
- 'mhl',
- 'mtq',
- 'mrt',
- 'mus',
- 'myt',
- 'mex',
- 'fsm',
- 'mda',
- 'mco',
- 'mng',
- 'mne',
- 'msr',
- 'mar',
- 'moz',
- 'mmr',
- 'nam',
- 'nru',
- 'npl',
- 'nld',
- 'ncl',
- 'nzl',
- 'nic',
- 'ner',
- 'nga',
- 'niu',
- 'nfk',
- 'prk',
- 'mkd',
- 'mnp',
- 'nor',
- 'omn',
- 'pak',
- 'plw',
- 'pse',
- 'pan',
- 'png',
- 'pry',
- 'per',
- 'phl',
- 'pcn',
- 'pol',
- 'prt',
- 'pri',
- 'qat',
- 'cog',
- 'reu',
- 'rou',
- 'rus',
- 'rwa',
- 'blm',
- 'shn',
- 'kna',
- 'lca',
- 'maf',
- 'spm',
- 'vct',
- 'wsm',
- 'smr',
- 'stp',
- 'sau',
- 'sen',
- 'srb',
- 'syc',
- 'sle',
- 'sgp',
- 'sxm',
- 'svk',
- 'svn',
- 'slb',
- 'som',
- 'zaf',
- 'sgs',
- 'kor',
- 'ssd',
- 'esp',
- 'lka',
- 'sdn',
- 'sur',
- 'sjm',
- 'swe',
- 'che',
- 'syr',
- 'twn',
- 'tjk',
- 'tza',
- 'tha',
- 'tls',
- 'tgo',
- 'tkl',
- 'ton',
- 'tto',
- 'tun',
- 'tur',
- 'tkm',
- 'tca',
- 'tuv',
- 'uga',
- 'ukr',
- 'are',
- 'gbr',
- 'umi',
- 'usa',
- 'ury',
- 'uzb',
- 'vut',
- 'vat',
- 'ven',
- 'vnm',
- 'vgb',
- 'vir',
- 'wlf',
- 'esh',
- 'yem',
- 'zmb',
- 'zwe'
-);
-
-ALTER TABLE funder RENAME TO institution;
-
-ALTER TABLE institution RENAME COLUMN funder_id TO institution_id;
-ALTER TABLE institution RENAME COLUMN funder_name TO institution_name;
-ALTER TABLE institution RENAME COLUMN funder_doi TO institution_doi;
-
-ALTER TABLE institution
- ADD COLUMN ror TEXT CHECK (ror ~ '^https:\/\/ror\.org\/0[a-hjkmnp-z0-9]{6}\d{2}$'),
- ADD COLUMN country_code country_code;
-
-ALTER TABLE funder_history RENAME TO institution_history;
-
-ALTER TABLE institution_history RENAME COLUMN funder_history_id TO institution_history_id;
-ALTER TABLE institution_history RENAME COLUMN funder_id TO institution_id;
-
-ALTER TABLE funding RENAME COLUMN funder_id TO institution_id;
-
-CREATE TABLE affiliation (
- affiliation_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- contribution_id UUID NOT NULL REFERENCES contribution(contribution_id) ON DELETE CASCADE,
- institution_id UUID NOT NULL REFERENCES institution(institution_id) ON DELETE CASCADE,
- affiliation_ordinal INTEGER NOT NULL CHECK (affiliation_ordinal > 0),
- position TEXT CHECK (octet_length(position) >= 1),
- created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-SELECT diesel_manage_updated_at('affiliation');
-
--- UNIQ index on affiliation_ordinal and contribution_id
-CREATE UNIQUE INDEX affiliation_uniq_ord_in_contribution_idx ON affiliation(contribution_id, affiliation_ordinal);
-
-CREATE TABLE affiliation_history (
- affiliation_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- affiliation_id UUID NOT NULL REFERENCES affiliation(affiliation_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
--- Create institution entries for every existing contribution institution
--- (unless an institution with that name already exists).
-INSERT INTO institution(institution_name)
- SELECT DISTINCT institution FROM contribution
- WHERE institution IS NOT NULL
- AND NOT EXISTS (SELECT * FROM institution WHERE institution_name = contribution.institution);
-
--- Create an affiliation linking the appropriate institution to each relevant contribution.
--- (Each contribution will have a maximum of one institution, so all entries can have ordinal 1.)
-INSERT INTO affiliation(contribution_id, institution_id, affiliation_ordinal)
- SELECT contribution.contribution_id, institution.institution_id, 1 FROM contribution, institution
- WHERE contribution.institution = institution.institution_name;
-
-ALTER TABLE contribution
- DROP COLUMN institution;
diff --git a/thoth-api/migrations/0.7.0/down.sql b/thoth-api/migrations/0.7.0/down.sql
deleted file mode 100644
index 697f3d5e..00000000
--- a/thoth-api/migrations/0.7.0/down.sql
+++ /dev/null
@@ -1,28 +0,0 @@
-DROP TABLE work_relation_history;
-DROP TRIGGER set_updated_at ON work_relation;
-DROP TABLE work_relation;
-DROP TYPE IF EXISTS relation_type;
-
-ALTER TABLE work
- DROP CONSTRAINT work_non_chapter_no_first_page,
- DROP CONSTRAINT work_non_chapter_no_last_page,
- DROP CONSTRAINT work_non_chapter_no_page_interval,
- DROP COLUMN first_page,
- DROP COLUMN last_page,
- DROP COLUMN page_interval,
- DROP CONSTRAINT work_non_chapter_has_edition,
- DROP CONSTRAINT work_chapter_no_edition,
- DROP CONSTRAINT work_chapter_no_width,
- DROP CONSTRAINT work_chapter_no_height,
- DROP CONSTRAINT work_chapter_no_toc,
- DROP CONSTRAINT work_chapter_no_lccn,
- DROP CONSTRAINT work_chapter_no_oclc;
-
--- Set a default edition value for any chapter records before
--- reintroducing the original blanket edition-not-null constraint.
-UPDATE work
- SET edition = 1
- WHERE work_type = 'book-chapter';
-
-ALTER TABLE work
- ALTER COLUMN edition SET NOT NULL;
diff --git a/thoth-api/migrations/0.7.0/up.sql b/thoth-api/migrations/0.7.0/up.sql
deleted file mode 100644
index 057586ec..00000000
--- a/thoth-api/migrations/0.7.0/up.sql
+++ /dev/null
@@ -1,79 +0,0 @@
-CREATE TYPE relation_type AS ENUM (
- 'replaces',
- 'has-translation',
- 'has-part',
- 'has-child',
- 'is-replaced-by',
- 'is-translation-of',
- 'is-part-of',
- 'is-child-of'
-);
-
-CREATE TABLE work_relation (
- work_relation_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- relator_work_id UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
- related_work_id UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
- relation_type relation_type NOT NULL,
- relation_ordinal INTEGER NOT NULL CHECK (relation_ordinal > 0),
- created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT work_relation_ids_check CHECK (relator_work_id != related_work_id),
- CONSTRAINT work_relation_ordinal_type_uniq UNIQUE (relation_ordinal, relator_work_id, relation_type),
- -- Two works cannot have more than one relationship.
- CONSTRAINT work_relation_relator_related_uniq UNIQUE (relator_work_id, related_work_id),
- -- Two records must exist for each relationship, one representing the 'active' relation_type
- -- (e.g. 'has-child'), and one representing the 'passive' type (e.g. 'is-child-of').
- -- Ensure that each relator/related record has a corresponding related/relator record
- -- (note we cannot verify that the relation_types themselves form a matching pair).
- CONSTRAINT work_relation_active_passive_pair
- FOREIGN KEY (relator_work_id, related_work_id)
- REFERENCES work_relation (related_work_id, relator_work_id)
- -- Allow transaction to complete before enforcing constraint
- -- (so that pairs of records can be created/updated in tandem)
- DEFERRABLE INITIALLY DEFERRED
-);
-SELECT diesel_manage_updated_at('work_relation');
-
-CREATE TABLE work_relation_history (
- work_relation_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- work_relation_id UUID NOT NULL REFERENCES work_relation(work_relation_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
-ALTER TABLE work
- -- Restrict the original edition-not-null constraint to non-chapter work types.
- ALTER COLUMN edition DROP NOT NULL,
- ADD CONSTRAINT work_non_chapter_has_edition CHECK
- (edition IS NOT NULL OR work_type = 'book-chapter');
-
--- If any chapter records exist, clear any values from existing fields
--- which are about to be newly constrained to null for chapters.
-UPDATE work
- SET edition = NULL, width = NULL, height = NULL, toc = NULL, lccn = NULL, oclc = NULL
- WHERE work_type = 'book-chapter';
-
-ALTER TABLE work
- ADD CONSTRAINT work_chapter_no_edition CHECK
- (edition IS NULL OR work_type <> 'book-chapter'),
- ADD CONSTRAINT work_chapter_no_width CHECK
- (width IS NULL OR work_type <> 'book-chapter'),
- ADD CONSTRAINT work_chapter_no_height CHECK
- (height IS NULL OR work_type <> 'book-chapter'),
- ADD CONSTRAINT work_chapter_no_toc CHECK
- (toc IS NULL OR work_type <> 'book-chapter'),
- ADD CONSTRAINT work_chapter_no_lccn CHECK
- (lccn IS NULL OR work_type <> 'book-chapter'),
- ADD CONSTRAINT work_chapter_no_oclc CHECK
- (oclc IS NULL OR work_type <> 'book-chapter'),
- -- Create new chapter-only columns.
- ADD COLUMN first_page TEXT CHECK (octet_length(first_page) >= 1),
- ADD COLUMN last_page TEXT CHECK (octet_length(last_page) >= 1),
- ADD COLUMN page_interval TEXT CHECK (octet_length(page_interval) >= 1),
- ADD CONSTRAINT work_non_chapter_no_first_page CHECK
- (first_page IS NULL OR work_type = 'book-chapter'),
- ADD CONSTRAINT work_non_chapter_no_last_page CHECK
- (last_page IS NULL OR work_type = 'book-chapter'),
- ADD CONSTRAINT work_non_chapter_no_page_interval CHECK
- (page_interval IS NULL OR work_type = 'book-chapter');
diff --git a/thoth-api/migrations/0.7.2/down.sql b/thoth-api/migrations/0.7.2/down.sql
deleted file mode 100644
index a8cd1a3a..00000000
--- a/thoth-api/migrations/0.7.2/down.sql
+++ /dev/null
@@ -1,20 +0,0 @@
-ALTER TABLE series
- DROP COLUMN series_description,
- DROP COLUMN series_cfp_url;
-
--- We cannot drop individual enum values - we must drop the type and recreate it
---
--- Delete publications with about-to-be-dropped types
-DELETE FROM publication WHERE publication_type IN ('AZW3', 'DOCX', 'FictionBook');
-ALTER TABLE publication ALTER publication_type TYPE text;
-DROP TYPE publication_type;
-CREATE TYPE publication_type AS ENUM (
- 'Paperback',
- 'Hardback',
- 'PDF',
- 'HTML',
- 'XML',
- 'Epub',
- 'Mobi'
-);
-ALTER TABLE publication ALTER publication_type TYPE publication_type USING publication_type::publication_type;
diff --git a/thoth-api/migrations/0.7.2/up.sql b/thoth-api/migrations/0.7.2/up.sql
deleted file mode 100644
index 0a63bab4..00000000
--- a/thoth-api/migrations/0.7.2/up.sql
+++ /dev/null
@@ -1,9 +0,0 @@
-ALTER TABLE series
- -- Description of the series
- ADD COLUMN series_description TEXT CHECK (octet_length(series_description) >= 1),
- -- Call for proposals URL
- ADD COLUMN series_cfp_url TEXT CHECK (series_cfp_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)');
-
-ALTER TYPE publication_type ADD VALUE IF NOT EXISTS 'AZW3';
-ALTER TYPE publication_type ADD VALUE IF NOT EXISTS 'DOCX';
-ALTER TYPE publication_type ADD VALUE IF NOT EXISTS 'FictionBook';
diff --git a/thoth-api/migrations/0.8.0/down.sql b/thoth-api/migrations/0.8.0/down.sql
deleted file mode 100644
index 505e5809..00000000
--- a/thoth-api/migrations/0.8.0/down.sql
+++ /dev/null
@@ -1,65 +0,0 @@
-ALTER TABLE work
- ADD COLUMN width double precision CHECK (width > 0.0),
- ADD COLUMN height double precision CHECK (height > 0.0),
- ADD CONSTRAINT work_chapter_no_width CHECK
- (width IS NULL OR work_type <> 'book-chapter'),
- ADD CONSTRAINT work_chapter_no_height CHECK
- (height IS NULL OR work_type <> 'book-chapter');
-
--- Migrate publication dimension information back into work table as far as possible
--- (width/height in mm only) before dropping publication dimension columns. Where
--- dimensions for both paperback and hardback are given, assume the paperback is canonical.
-UPDATE work
- SET width = publication.width_mm
- FROM publication
- WHERE work.work_type <> 'book-chapter'
- AND work.work_id = publication.work_id
- AND publication.width_mm IS NOT NULL
- AND publication.publication_type = 'Paperback';
-UPDATE work
- SET width = publication.width_mm
- FROM publication
- WHERE work.work_type <> 'book-chapter'
- AND work.work_id = publication.work_id
- AND work.width IS NULL
- AND publication.width_mm IS NOT NULL
- AND publication.publication_type = 'Hardback';
-
-UPDATE work
- SET height = publication.height_mm
- FROM publication
- WHERE work.work_type <> 'book-chapter'
- AND work.work_id = publication.work_id
- AND publication.height_mm IS NOT NULL
- AND publication.publication_type = 'Paperback';
-UPDATE work
- SET height = publication.height_mm
- FROM publication
- WHERE work.work_type <> 'book-chapter'
- AND work.work_id = publication.work_id
- AND work.height IS NULL
- AND publication.height_mm IS NOT NULL
- AND publication.publication_type = 'Hardback';
-
-DROP TRIGGER publication_chapter_no_dimensions_check ON publication;
-
-ALTER TABLE publication
- DROP CONSTRAINT publication_non_physical_no_dimensions,
- DROP CONSTRAINT publication_weight_g_not_missing,
- DROP CONSTRAINT publication_weight_oz_not_missing,
- DROP CONSTRAINT publication_width_mm_not_missing,
- DROP CONSTRAINT publication_width_in_not_missing,
- DROP CONSTRAINT publication_height_mm_not_missing,
- DROP CONSTRAINT publication_height_in_not_missing,
- DROP CONSTRAINT publication_depth_mm_not_missing,
- DROP CONSTRAINT publication_depth_in_not_missing,
- DROP COLUMN weight_g,
- DROP COLUMN weight_oz,
- DROP COLUMN width_mm,
- DROP COLUMN width_in,
- DROP COLUMN height_mm,
- DROP COLUMN height_in,
- DROP COLUMN depth_mm,
- DROP COLUMN depth_in;
-
-DROP FUNCTION IF EXISTS publication_chapter_no_dimensions();
diff --git a/thoth-api/migrations/0.8.0/up.sql b/thoth-api/migrations/0.8.0/up.sql
deleted file mode 100644
index 3b523e67..00000000
--- a/thoth-api/migrations/0.8.0/up.sql
+++ /dev/null
@@ -1,88 +0,0 @@
-ALTER TABLE publication
- ADD COLUMN width_mm double precision CHECK (width_mm > 0.0),
- ADD COLUMN width_in double precision CHECK (width_in > 0.0),
- ADD COLUMN height_mm double precision CHECK (height_mm > 0.0),
- ADD COLUMN height_in double precision CHECK (height_in > 0.0),
- ADD COLUMN depth_mm double precision CHECK (depth_mm > 0.0),
- ADD COLUMN depth_in double precision CHECK (depth_in > 0.0),
- ADD COLUMN weight_g double precision CHECK (weight_g > 0.0),
- ADD COLUMN weight_oz double precision CHECK (weight_oz > 0.0),
- ADD CONSTRAINT publication_non_physical_no_dimensions CHECK
- ((width_mm IS NULL AND width_in IS NULL
- AND height_mm IS NULL AND height_in IS NULL
- AND depth_mm IS NULL AND depth_in IS NULL
- AND weight_g IS NULL AND weight_oz IS NULL)
- OR publication_type = 'Paperback' OR publication_type = 'Hardback'),
- ADD CONSTRAINT publication_depth_mm_not_missing CHECK
- (depth_mm IS NOT NULL OR depth_in IS NULL),
- ADD CONSTRAINT publication_depth_in_not_missing CHECK
- (depth_in IS NOT NULL OR depth_mm IS NULL),
- ADD CONSTRAINT publication_weight_g_not_missing CHECK
- (weight_g IS NOT NULL OR weight_oz IS NULL),
- ADD CONSTRAINT publication_weight_oz_not_missing CHECK
- (weight_oz IS NOT NULL OR weight_g IS NULL);
-
-CREATE OR REPLACE FUNCTION publication_chapter_no_dimensions() RETURNS trigger AS $$
-BEGIN
- IF (
- (SELECT work_type FROM work WHERE work.work_id = NEW.work_id) = 'book-chapter' AND (
- NEW.width_mm IS NOT NULL OR
- NEW.width_in IS NOT NULL OR
- NEW.height_mm IS NOT NULL OR
- NEW.height_in IS NOT NULL OR
- NEW.depth_mm IS NOT NULL OR
- NEW.depth_in IS NOT NULL OR
- NEW.weight_g IS NOT NULL OR
- NEW.weight_oz IS NOT NULL
- )
- ) THEN
- RAISE EXCEPTION 'Chapters cannot have dimensions (Width/Height/Depth/Weight)';
- END IF;
- RETURN NEW;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE TRIGGER publication_chapter_no_dimensions_check BEFORE INSERT OR UPDATE ON publication
- FOR EACH ROW EXECUTE PROCEDURE publication_chapter_no_dimensions();
-
--- Migrate work dimension information into publication table before dropping work
--- width/height columns. Assume dimensions are same for paperback and hardback.
-UPDATE publication
- SET width_mm = work.width
- FROM work
- WHERE publication.work_id = work.work_id
- AND work.width IS NOT NULL
- AND (publication.publication_type = 'Paperback' OR publication.publication_type = 'Hardback');
-
-UPDATE publication
- SET height_mm = work.height
- FROM work
- WHERE publication.work_id = work.work_id
- AND work.height IS NOT NULL
- AND (publication.publication_type = 'Paperback' OR publication.publication_type = 'Hardback');
-
--- Add imperial dimension information based on metric. Conversion logic used here
--- replicates convert_length_from_to() function in thoth-api/src/model/mod.rs.
-UPDATE publication
- SET width_in = round((width_mm / 25.4)::numeric, 2)
- WHERE width_mm IS NOT NULL;
-
-UPDATE publication
- SET height_in = round((height_mm / 25.4)::numeric, 2)
- WHERE height_mm IS NOT NULL;
-
-ALTER TABLE publication
- ADD CONSTRAINT publication_width_mm_not_missing CHECK
- (width_mm IS NOT NULL OR width_in IS NULL),
- ADD CONSTRAINT publication_width_in_not_missing CHECK
- (width_in IS NOT NULL OR width_mm IS NULL),
- ADD CONSTRAINT publication_height_mm_not_missing CHECK
- (height_mm IS NOT NULL OR height_in IS NULL),
- ADD CONSTRAINT publication_height_in_not_missing CHECK
- (height_in IS NOT NULL OR height_mm IS NULL);
-
-ALTER TABLE work
- DROP CONSTRAINT work_chapter_no_width,
- DROP CONSTRAINT work_chapter_no_height,
- DROP COLUMN width,
- DROP COLUMN height;
diff --git a/thoth-api/migrations/0.8.11/down.sql b/thoth-api/migrations/0.8.11/down.sql
deleted file mode 100644
index cd994d56..00000000
--- a/thoth-api/migrations/0.8.11/down.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-ALTER TABLE work DROP CONSTRAINT work_place_check;
-ALTER TABLE work ADD CONSTRAINT work_reference_check1 CHECK (octet_length(reference) >= 1);
-
-ALTER TABLE institution RENAME CONSTRAINT institution_pkey TO funder_pkey;
-ALTER INDEX institution_doi_uniq_idx RENAME TO funder_doi_uniq_idx;
-ALTER TABLE institution RENAME CONSTRAINT institution_institution_doi_check TO funder_funder_doi_check;
-ALTER TABLE institution RENAME CONSTRAINT institution_institution_name_check TO funder_funder_name_check;
diff --git a/thoth-api/migrations/0.8.11/up.sql b/thoth-api/migrations/0.8.11/up.sql
deleted file mode 100644
index d783a904..00000000
--- a/thoth-api/migrations/0.8.11/up.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-ALTER TABLE work DROP CONSTRAINT work_reference_check1;
-ALTER TABLE work ADD CONSTRAINT work_place_check CHECK (octet_length(place) >= 1);
-
-ALTER TABLE institution RENAME CONSTRAINT funder_pkey TO institution_pkey;
-ALTER INDEX funder_doi_uniq_idx RENAME TO institution_doi_uniq_idx;
-ALTER TABLE institution RENAME CONSTRAINT funder_funder_doi_check TO institution_institution_doi_check;
-ALTER TABLE institution RENAME CONSTRAINT funder_funder_name_check TO institution_institution_name_check;
\ No newline at end of file
diff --git a/thoth-api/migrations/0.8.3/down.sql b/thoth-api/migrations/0.8.3/down.sql
deleted file mode 100644
index d03830b3..00000000
--- a/thoth-api/migrations/0.8.3/down.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-DROP TRIGGER publication_location_canonical_urls_check ON publication;
-
-DROP FUNCTION IF EXISTS publication_location_canonical_urls();
diff --git a/thoth-api/migrations/0.8.3/up.sql b/thoth-api/migrations/0.8.3/up.sql
deleted file mode 100644
index 702d024d..00000000
--- a/thoth-api/migrations/0.8.3/up.sql
+++ /dev/null
@@ -1,19 +0,0 @@
-CREATE OR REPLACE FUNCTION publication_location_canonical_urls() RETURNS trigger AS $$
-BEGIN
- IF (
- NEW.publication_type <> 'Hardback' AND
- NEW.publication_type <> 'Paperback' AND
- (SELECT COUNT(*) FROM location
- WHERE location.publication_id = NEW.publication_id
- AND location.canonical
- AND (location.landing_page IS NULL OR location.full_text_url IS NULL)
- ) > 0
- ) THEN
- RAISE EXCEPTION 'Digital publications must have both Landing Page and Full Text URL in all their canonical locations';
- END IF;
- RETURN NEW;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE TRIGGER publication_location_canonical_urls_check BEFORE UPDATE ON publication
- FOR EACH ROW EXECUTE PROCEDURE publication_location_canonical_urls();
diff --git a/thoth-api/migrations/0.8.5/down.sql b/thoth-api/migrations/0.8.5/down.sql
deleted file mode 100644
index 5b68c1eb..00000000
--- a/thoth-api/migrations/0.8.5/down.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE price
- DROP CONSTRAINT price_unit_price_check;
diff --git a/thoth-api/migrations/0.8.5/up.sql b/thoth-api/migrations/0.8.5/up.sql
deleted file mode 100644
index 1dec076a..00000000
--- a/thoth-api/migrations/0.8.5/up.sql
+++ /dev/null
@@ -1,4 +0,0 @@
-DELETE FROM price WHERE unit_price = 0.0;
-
-ALTER TABLE price
- ADD CONSTRAINT price_unit_price_check CHECK (unit_price > 0.0);
diff --git a/thoth-api/migrations/0.8.8/down.sql b/thoth-api/migrations/0.8.8/down.sql
deleted file mode 100644
index 5092cac0..00000000
--- a/thoth-api/migrations/0.8.8/down.sql
+++ /dev/null
@@ -1,4 +0,0 @@
-ALTER TABLE work
- ALTER COLUMN copyright_holder SET NOT NULL;
-
-UPDATE work SET page_interval = REPLACE(page_interval, '–', '-');
\ No newline at end of file
diff --git a/thoth-api/migrations/0.8.8/up.sql b/thoth-api/migrations/0.8.8/up.sql
deleted file mode 100644
index b6ae4a9e..00000000
--- a/thoth-api/migrations/0.8.8/up.sql
+++ /dev/null
@@ -1,4 +0,0 @@
-ALTER TABLE work
- ALTER COLUMN copyright_holder DROP NOT NULL;
-
-UPDATE work SET page_interval = REPLACE(page_interval, '-', '–');
\ No newline at end of file
diff --git a/thoth-api/migrations/0.8.9/down.sql b/thoth-api/migrations/0.8.9/down.sql
deleted file mode 100644
index 6bc8d589..00000000
--- a/thoth-api/migrations/0.8.9/down.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TYPE contribution_type RENAME VALUE 'illustrator' TO 'ilustrator';
diff --git a/thoth-api/migrations/0.8.9/up.sql b/thoth-api/migrations/0.8.9/up.sql
deleted file mode 100644
index a34a60c9..00000000
--- a/thoth-api/migrations/0.8.9/up.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TYPE contribution_type RENAME VALUE 'ilustrator' TO 'illustrator';
diff --git a/thoth-api/migrations/0.9.0/down.sql b/thoth-api/migrations/0.9.0/down.sql
deleted file mode 100644
index d7f5e0cc..00000000
--- a/thoth-api/migrations/0.9.0/down.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-DROP TABLE reference_history;
-DROP TABLE reference;
\ No newline at end of file
diff --git a/thoth-api/migrations/0.9.0/up.sql b/thoth-api/migrations/0.9.0/up.sql
deleted file mode 100644
index 27e591a2..00000000
--- a/thoth-api/migrations/0.9.0/up.sql
+++ /dev/null
@@ -1,43 +0,0 @@
-CREATE TABLE reference (
- reference_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- work_id UUID NOT NULL REFERENCES work(work_id) ON DELETE CASCADE,
- reference_ordinal INTEGER NOT NULL CHECK (reference_ordinal > 0),
- doi TEXT CHECK (doi ~* '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\/:a-zA-Z0-9]+$'),
- unstructured_citation TEXT CHECK (octet_length(unstructured_citation) >= 1),
- issn TEXT CHECK (issn ~* '\d{4}\-\d{3}(\d|X)'),
- isbn TEXT CHECK (octet_length(isbn) = 17),
- journal_title TEXT CHECK (octet_length(journal_title) >= 1),
- article_title TEXT CHECK (octet_length(article_title) >= 1),
- series_title TEXT CHECK (octet_length(series_title) >= 1),
- volume_title TEXT CHECK (octet_length(volume_title) >= 1),
- edition INTEGER CHECK (edition > 0),
- author TEXT CHECK (octet_length(author) >= 1),
- volume TEXT CHECK (octet_length(volume) >= 1),
- issue TEXT CHECK (octet_length(issue) >= 1),
- first_page TEXT CHECK (octet_length(first_page) >= 1),
- component_number TEXT CHECK (octet_length(component_number) >= 1),
- standard_designator TEXT CHECK (octet_length(standard_designator) >= 1),
- standards_body_name TEXT CHECK (octet_length(standards_body_name) >= 1),
- standards_body_acronym TEXT CHECK (octet_length(standards_body_acronym) >= 1),
- url TEXT CHECK (url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'),
- publication_date DATE,
- retrieval_date DATE,
- created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT reference_reference_ordinal_work_id_uniq UNIQUE (work_id, reference_ordinal),
- CONSTRAINT reference_doi_andor_unstructured_citation CHECK
- (doi IS NOT NULL OR unstructured_citation IS NOT NULL),
- CONSTRAINT reference_standard_citation_required_fields CHECK
- ((standard_designator IS NOT NULL AND standards_body_name IS NOT NULL AND standards_body_acronym IS NOT NULL)
- OR
- (standard_designator IS NULL AND standards_body_name IS NULL AND standards_body_acronym IS NULL))
-);
-SELECT diesel_manage_updated_at('reference');
-
-CREATE TABLE reference_history (
- reference_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
- reference_id UUID NOT NULL REFERENCES reference(reference_id) ON DELETE CASCADE,
- account_id UUID NOT NULL REFERENCES account(account_id),
- data JSONB NOT NULL,
- timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
diff --git a/thoth-api/migrations/0.9.16/down.sql b/thoth-api/migrations/0.9.16/down.sql
deleted file mode 100644
index 29364727..00000000
--- a/thoth-api/migrations/0.9.16/down.sql
+++ /dev/null
@@ -1,64 +0,0 @@
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON contribution;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON funding;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON issue;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON language;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON publication;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON reference;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON subject;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON work_relation;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON affiliation;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON location;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON price;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON contributor;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON institution;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON publisher;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON series;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON work;
-
-DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON imprint;
-
-DROP FUNCTION IF EXISTS work_updated_at_with_relations();
-
-DROP FUNCTION IF EXISTS work_relation_work_updated_at_with_relations();
-
-DROP FUNCTION IF EXISTS affiliation_work_updated_at_with_relations();
-
-DROP FUNCTION IF EXISTS location_work_updated_at_with_relations();
-
-DROP FUNCTION IF EXISTS price_work_updated_at_with_relations();
-
-DROP FUNCTION IF EXISTS contributor_work_updated_at_with_relations();
-
-DROP FUNCTION IF EXISTS institution_work_updated_at_with_relations();
-
-DROP FUNCTION IF EXISTS publisher_work_updated_at_with_relations();
-
-DROP FUNCTION IF EXISTS series_work_updated_at_with_relations();
-
-DROP FUNCTION IF EXISTS work_work_updated_at_with_relations();
-
-DROP FUNCTION IF EXISTS imprint_work_updated_at_with_relations();
-
-ALTER TABLE work
- DROP COLUMN updated_at_with_relations;
-
-DROP TRIGGER IF EXISTS set_updated_at ON work;
-
-DROP FUNCTION IF EXISTS work_set_updated_at();
-
-SELECT diesel_manage_updated_at('work');
diff --git a/thoth-api/migrations/0.9.16/up.sql b/thoth-api/migrations/0.9.16/up.sql
deleted file mode 100644
index 05e86700..00000000
--- a/thoth-api/migrations/0.9.16/up.sql
+++ /dev/null
@@ -1,298 +0,0 @@
--- Add work table field to track when the work or any of its relations was last updated.
-
-ALTER TABLE work
- ADD COLUMN updated_at_with_relations TIMESTAMP NULL;
-
--- Amend existing trigger which sets updated_at value on work table
--- to avoid setting updated_at when updated_at_with_relations changes.
-
-CREATE OR REPLACE FUNCTION work_set_updated_at() RETURNS trigger AS $$
-BEGIN
- IF (
- NEW IS DISTINCT FROM OLD AND
- NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at AND
- NEW.updated_at_with_relations IS NOT DISTINCT FROM OLD.updated_at_with_relations
- ) THEN
- NEW.updated_at := current_timestamp;
- NEW.updated_at_with_relations := current_timestamp;
- END IF;
- RETURN NEW;
-END;
-$$ LANGUAGE plpgsql;
-
-DROP TRIGGER IF EXISTS set_updated_at ON work;
-
-CREATE TRIGGER set_updated_at BEFORE UPDATE ON work
- FOR EACH ROW EXECUTE PROCEDURE work_set_updated_at();
-
--- Obtain current last relation update timestamp for all existing works.
-WITH update_times AS
-(
- SELECT w.work_id, GREATEST(
- w.updated_at, c.updated_at, f.updated_at, i.updated_at, iu.updated_at, l.updated_at, p.updated_at,
- r.updated_at, s.updated_at, wr.updated_at, a.updated_at, lo.updated_at, pr.updated_at,
- co.updated_at, inf.updated_at, ina.updated_at, pu.updated_at, se.updated_at, wo.updated_at
- ) last_updated
- FROM work w
- LEFT JOIN contribution c USING (work_id)
- LEFT JOIN funding f USING (work_id)
- LEFT JOIN imprint i USING (imprint_id)
- LEFT JOIN issue iu USING (work_id)
- LEFT JOIN language l USING (work_id)
- LEFT JOIN publication p USING (work_id)
- LEFT JOIN reference r USING (work_id)
- LEFT JOIN subject s USING (work_id)
- LEFT JOIN work_relation wr ON w.work_id = wr.relator_work_id
- LEFT JOIN affiliation a ON c.contribution_id = a.contribution_id
- LEFT JOIN location lo ON p.publication_id = lo.publication_id
- LEFT JOIN price pr ON p.publication_id = pr.publication_id
- LEFT JOIN contributor co ON c.contributor_id = co.contributor_id
- LEFT JOIN institution inf ON f.institution_id = inf.institution_id
- LEFT JOIN institution ina ON a.institution_id = ina.institution_id
- LEFT JOIN publisher pu ON i.publisher_id = pu.publisher_id
- LEFT JOIN series se ON iu.series_id = se.series_id
- LEFT JOIN work wo ON wr.related_work_id = wo.work_id
- GROUP BY w.work_id, last_updated
-)
-UPDATE work
- SET updated_at_with_relations = update_times.last_updated
- FROM update_times
- WHERE work.work_id = update_times.work_id;
-
-ALTER TABLE work
- ALTER COLUMN updated_at_with_relations SET NOT NULL,
- ALTER COLUMN updated_at_with_relations SET DEFAULT CURRENT_TIMESTAMP;
-
--- Add triggers to update this field whenever a relation is created, updated or deleted.
-
-CREATE OR REPLACE FUNCTION work_updated_at_with_relations() RETURNS trigger AS $$
-BEGIN
- IF (
- NEW IS DISTINCT FROM OLD
- ) THEN
- UPDATE work
- SET updated_at_with_relations = current_timestamp
- WHERE work_id = OLD.work_id OR work_id = NEW.work_id;
- END IF;
- RETURN NULL;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR UPDATE OR DELETE ON contribution
- FOR EACH ROW EXECUTE PROCEDURE work_updated_at_with_relations();
-
-CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR UPDATE OR DELETE ON funding
- FOR EACH ROW EXECUTE PROCEDURE work_updated_at_with_relations();
-
-CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR UPDATE OR DELETE ON issue
- FOR EACH ROW EXECUTE PROCEDURE work_updated_at_with_relations();
-
-CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR UPDATE OR DELETE ON language
- FOR EACH ROW EXECUTE PROCEDURE work_updated_at_with_relations();
-
-CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR UPDATE OR DELETE ON publication
- FOR EACH ROW EXECUTE PROCEDURE work_updated_at_with_relations();
-
-CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR UPDATE OR DELETE ON reference
- FOR EACH ROW EXECUTE PROCEDURE work_updated_at_with_relations();
-
-CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR UPDATE OR DELETE ON subject
- FOR EACH ROW EXECUTE PROCEDURE work_updated_at_with_relations();
-
-CREATE OR REPLACE FUNCTION work_relation_work_updated_at_with_relations() RETURNS trigger AS $$
-BEGIN
- IF (
- NEW IS DISTINCT FROM OLD
- ) THEN
- UPDATE work
- SET updated_at_with_relations = current_timestamp
- WHERE work_id = OLD.relator_work_id OR work_id = NEW.relator_work_id
- OR work_id = OLD.related_work_id OR work_id = NEW.related_work_id;
- END IF;
- RETURN NULL;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR UPDATE OR DELETE ON work_relation
- FOR EACH ROW EXECUTE PROCEDURE work_relation_work_updated_at_with_relations();
-
--- The following tables all reference tables which reference the work table.
--- As they are at the end of this chain of references, any creation, update or
--- deletion on them should also be marked as an update on the 'grandparent' work.
-CREATE OR REPLACE FUNCTION affiliation_work_updated_at_with_relations() RETURNS trigger AS $$
-BEGIN
- IF (
- NEW IS DISTINCT FROM OLD
- ) THEN
- UPDATE work
- SET updated_at_with_relations = current_timestamp
- FROM contribution
- WHERE work.work_id = contribution.work_id AND contribution.contribution_id = OLD.contribution_id
- OR work.work_id = contribution.work_id AND contribution.contribution_id = NEW.contribution_id;
- END IF;
- RETURN NULL;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR UPDATE OR DELETE ON affiliation
- FOR EACH ROW EXECUTE PROCEDURE affiliation_work_updated_at_with_relations();
-
-CREATE OR REPLACE FUNCTION location_work_updated_at_with_relations() RETURNS trigger AS $$
-BEGIN
- IF (
- NEW IS DISTINCT FROM OLD
- ) THEN
- UPDATE work
- SET updated_at_with_relations = current_timestamp
- FROM publication
- WHERE work.work_id = publication.work_id AND publication.publication_id = OLD.publication_id
- OR work.work_id = publication.work_id AND publication.publication_id = NEW.publication_id;
- END IF;
- RETURN NULL;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR UPDATE OR DELETE ON location
- FOR EACH ROW EXECUTE PROCEDURE location_work_updated_at_with_relations();
-
-CREATE OR REPLACE FUNCTION price_work_updated_at_with_relations() RETURNS trigger AS $$
-BEGIN
- IF (
- NEW IS DISTINCT FROM OLD
- ) THEN
- UPDATE work
- SET updated_at_with_relations = current_timestamp
- FROM publication
- WHERE work.work_id = publication.work_id AND publication.publication_id = OLD.publication_id
- OR work.work_id = publication.work_id AND publication.publication_id = NEW.publication_id;
- END IF;
- RETURN NULL;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR UPDATE OR DELETE ON price
- FOR EACH ROW EXECUTE PROCEDURE price_work_updated_at_with_relations();
-
-CREATE OR REPLACE FUNCTION contributor_work_updated_at_with_relations() RETURNS trigger AS $$
-BEGIN
- IF (
- NEW IS DISTINCT FROM OLD
- ) THEN
- UPDATE work
- SET updated_at_with_relations = current_timestamp
- FROM contribution
- -- No need to check OLD.contributor_id, as this will be the same as NEW.contributor_id in all relevant cases
- -- (contributor_id can't be changed on contributors which are referenced by existing contributions)
- WHERE work.work_id = contribution.work_id AND contribution.contributor_id = NEW.contributor_id;
- END IF;
- RETURN NULL;
-END;
-$$ LANGUAGE plpgsql;
-
--- Deleting a contributor will also delete its contributions, setting updated_at_with_relations where relevant.
--- Adding a contributor will not affect any existing works, because no contributions will reference it yet.
-CREATE TRIGGER set_work_updated_at_with_relations AFTER UPDATE ON contributor
- FOR EACH ROW EXECUTE PROCEDURE contributor_work_updated_at_with_relations();
-
-CREATE OR REPLACE FUNCTION institution_work_updated_at_with_relations() RETURNS trigger AS $$
-BEGIN
- IF (
- NEW IS DISTINCT FROM OLD
- ) THEN
- -- Same as contributor above (but can be connected to work via two different tables)
- -- Use two separate UPDATE statements as this is much faster than combining the WHERE clauses
- -- using OR (in tests, this caused several seconds' delay when saving institution updates)
- UPDATE work
- SET updated_at_with_relations = current_timestamp
- FROM funding
- WHERE work.work_id = funding.work_id AND funding.institution_id = NEW.institution_id;
- UPDATE work
- SET updated_at_with_relations = current_timestamp
- FROM affiliation, contribution
- WHERE work.work_id = contribution.work_id AND contribution.contribution_id = affiliation.contribution_id AND affiliation.institution_id = NEW.institution_id;
- END IF;
- RETURN NULL;
-END;
-$$ LANGUAGE plpgsql;
-
--- Same as contributor above
-CREATE TRIGGER set_work_updated_at_with_relations AFTER UPDATE ON institution
- FOR EACH ROW EXECUTE PROCEDURE institution_work_updated_at_with_relations();
-
-CREATE OR REPLACE FUNCTION publisher_work_updated_at_with_relations() RETURNS trigger AS $$
-BEGIN
- IF (
- NEW IS DISTINCT FROM OLD
- ) THEN
- UPDATE work
- SET updated_at_with_relations = current_timestamp
- FROM imprint
- -- Same as contributor above
- WHERE work.imprint_id = imprint.imprint_id AND imprint.publisher_id = NEW.publisher_id;
- END IF;
- RETURN NULL;
-END;
-$$ LANGUAGE plpgsql;
-
--- Same as contributor above
-CREATE TRIGGER set_work_updated_at_with_relations AFTER UPDATE ON publisher
- FOR EACH ROW EXECUTE PROCEDURE publisher_work_updated_at_with_relations();
-
-CREATE OR REPLACE FUNCTION series_work_updated_at_with_relations() RETURNS trigger AS $$
-BEGIN
- IF (
- NEW IS DISTINCT FROM OLD
- ) THEN
- UPDATE work
- SET updated_at_with_relations = current_timestamp
- FROM issue
- -- Same as contributor above (note that although series is also connected to work
- -- via the imprint_id, changes to a series don't affect its imprint)
- WHERE work.work_id = issue.work_id AND issue.series_id = NEW.series_id;
- END IF;
- RETURN NULL;
-END;
-$$ LANGUAGE plpgsql;
-
--- Same as contributor above
-CREATE TRIGGER set_work_updated_at_with_relations AFTER UPDATE ON series
- FOR EACH ROW EXECUTE PROCEDURE series_work_updated_at_with_relations();
-
--- Works can be related to each other via the work_relation table, with a relationship similar
--- to contributor above (a newly-created work won't have any references yet, etc)
-CREATE OR REPLACE FUNCTION work_work_updated_at_with_relations() RETURNS trigger AS $$
-BEGIN
- IF (
- NEW IS DISTINCT FROM OLD
- ) THEN
- UPDATE work
- SET updated_at_with_relations = current_timestamp
- FROM work_relation
- -- The positions of relator/related IDs in this statement don't matter, as
- -- every work_relation record has a mirrored record with relator/related IDs swapped
- WHERE work.work_id = work_relation.relator_work_id AND work_relation.related_work_id = NEW.work_id;
- END IF;
- RETURN NULL;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE TRIGGER set_work_updated_at_with_relations AFTER UPDATE ON work
- FOR EACH ROW EXECUTE PROCEDURE work_work_updated_at_with_relations();
-
--- Imprint relationship is similar to contributor, although the tables are directly adjacent;
--- new imprints won't be referenced by works yet, and deleting an imprint also deletes its works
-CREATE OR REPLACE FUNCTION imprint_work_updated_at_with_relations() RETURNS trigger AS $$
-BEGIN
- IF (
- NEW IS DISTINCT FROM OLD
- ) THEN
- UPDATE work
- SET updated_at_with_relations = current_timestamp
- WHERE imprint_id = NEW.imprint_id;
- END IF;
- RETURN NULL;
-END;
-$$ LANGUAGE plpgsql;
-
-CREATE TRIGGER set_work_updated_at_with_relations AFTER UPDATE ON imprint
- FOR EACH ROW EXECUTE PROCEDURE imprint_work_updated_at_with_relations();
diff --git a/thoth-api/migrations/0.9.2/down.sql b/thoth-api/migrations/0.9.2/down.sql
deleted file mode 100644
index c9c92dc7..00000000
--- a/thoth-api/migrations/0.9.2/down.sql
+++ /dev/null
@@ -1,24 +0,0 @@
--- We cannot drop individual enum values - we must drop the type and recreate it
---
--- Delete contributions with about-to-be-dropped types
-DELETE FROM contribution WHERE contribution_type IN (
- 'software-by',
- 'research-by',
- 'contributions-by',
- 'indexer'
-);
-ALTER TABLE contribution ALTER contribution_type TYPE text;
-DROP TYPE contribution_type;
-CREATE TYPE contribution_type AS ENUM (
- 'author',
- 'editor',
- 'translator',
- 'photographer',
- 'illustrator',
- 'music-editor',
- 'foreword-by',
- 'introduction-by',
- 'afterword-by',
- 'preface-by'
-);
-ALTER TABLE contribution ALTER contribution_type TYPE contribution_type USING contribution_type::contribution_type;
\ No newline at end of file
diff --git a/thoth-api/migrations/0.9.2/up.sql b/thoth-api/migrations/0.9.2/up.sql
deleted file mode 100644
index bebcbbaf..00000000
--- a/thoth-api/migrations/0.9.2/up.sql
+++ /dev/null
@@ -1,4 +0,0 @@
-ALTER TYPE contribution_type ADD VALUE IF NOT EXISTS 'software-by';
-ALTER TYPE contribution_type ADD VALUE IF NOT EXISTS 'research-by';
-ALTER TYPE contribution_type ADD VALUE IF NOT EXISTS 'contributions-by';
-ALTER TYPE contribution_type ADD VALUE IF NOT EXISTS 'indexer';
\ No newline at end of file
diff --git a/thoth-api/migrations/0.9.6/down.sql b/thoth-api/migrations/0.9.6/down.sql
deleted file mode 100644
index f502a6aa..00000000
--- a/thoth-api/migrations/0.9.6/down.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-ALTER TABLE work DROP CONSTRAINT work_doi_check;
-ALTER TABLE work ADD CONSTRAINT work_doi_check
- CHECK (doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\/:a-zA-Z0-9]+$');
-
-ALTER TABLE reference DROP CONSTRAINT reference_doi_check;
-ALTER TABLE reference ADD CONSTRAINT reference_doi_check
- CHECK (doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\/:a-zA-Z0-9]+$');
-
-ALTER TABLE institution DROP CONSTRAINT institution_institution_doi_check;
-ALTER TABLE institution ADD CONSTRAINT institution_institution_doi_check
- CHECK (institution_doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\/:a-zA-Z0-9]+$');
diff --git a/thoth-api/migrations/0.9.6/up.sql b/thoth-api/migrations/0.9.6/up.sql
deleted file mode 100644
index b9297c0c..00000000
--- a/thoth-api/migrations/0.9.6/up.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-ALTER TABLE work DROP CONSTRAINT work_doi_check;
-ALTER TABLE work ADD CONSTRAINT work_doi_check
- CHECK (doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\[\]\/:a-zA-Z0-9]+$');
-
-ALTER TABLE reference DROP CONSTRAINT reference_doi_check;
-ALTER TABLE reference ADD CONSTRAINT reference_doi_check
- CHECK (doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\[\]\/:a-zA-Z0-9]+$');
-
-ALTER TABLE institution DROP CONSTRAINT institution_institution_doi_check;
-ALTER TABLE institution ADD CONSTRAINT institution_institution_doi_check
- CHECK (institution_doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\[\]\/:a-zA-Z0-9]+$');
diff --git a/thoth-api/migrations/20250000_v1.0.0/down.sql b/thoth-api/migrations/20250000_v1.0.0/down.sql
new file mode 100644
index 00000000..2ad0e1a9
--- /dev/null
+++ b/thoth-api/migrations/20250000_v1.0.0/down.sql
@@ -0,0 +1,72 @@
+-- Drop tables
+DROP TABLE IF EXISTS public.work_relation_history CASCADE;
+DROP TABLE IF EXISTS public.work_relation CASCADE;
+DROP TABLE IF EXISTS public.work_history CASCADE;
+DROP TABLE IF EXISTS public.work CASCADE;
+DROP TABLE IF EXISTS public.subject_history CASCADE;
+DROP TABLE IF EXISTS public.subject CASCADE;
+DROP TABLE IF EXISTS public.series_history CASCADE;
+DROP TABLE IF EXISTS public.series CASCADE;
+DROP TABLE IF EXISTS public.reference_history CASCADE;
+DROP TABLE IF EXISTS public.reference CASCADE;
+DROP TABLE IF EXISTS public.publisher_history CASCADE;
+DROP TABLE IF EXISTS public.publisher_account CASCADE;
+DROP TABLE IF EXISTS public.publisher CASCADE;
+DROP TABLE IF EXISTS public.publication_history CASCADE;
+DROP TABLE IF EXISTS public.publication CASCADE;
+DROP TABLE IF EXISTS public.price_history CASCADE;
+DROP TABLE IF EXISTS public.price CASCADE;
+DROP TABLE IF EXISTS public.location_history CASCADE;
+DROP TABLE IF EXISTS public.location CASCADE;
+DROP TABLE IF EXISTS public.language_history CASCADE;
+DROP TABLE IF EXISTS public.language CASCADE;
+DROP TABLE IF EXISTS public.issue_history CASCADE;
+DROP TABLE IF EXISTS public.issue CASCADE;
+DROP TABLE IF EXISTS public.institution_history CASCADE;
+DROP TABLE IF EXISTS public.institution CASCADE;
+DROP TABLE IF EXISTS public.imprint_history CASCADE;
+DROP TABLE IF EXISTS public.imprint CASCADE;
+DROP TABLE IF EXISTS public.funding_history CASCADE;
+DROP TABLE IF EXISTS public.funding CASCADE;
+DROP TABLE IF EXISTS public.contributor_history CASCADE;
+DROP TABLE IF EXISTS public.contributor CASCADE;
+DROP TABLE IF EXISTS public.contribution_history CASCADE;
+DROP TABLE IF EXISTS public.contribution CASCADE;
+DROP TABLE IF EXISTS public.affiliation_history CASCADE;
+DROP TABLE IF EXISTS public.affiliation CASCADE;
+DROP TABLE IF EXISTS public.account CASCADE;
+
+-- Drop functions
+DROP FUNCTION IF EXISTS public.affiliation_work_updated_at_with_relations() CASCADE;
+DROP FUNCTION IF EXISTS public.contributor_work_updated_at_with_relations() CASCADE;
+DROP FUNCTION IF EXISTS public.imprint_work_updated_at_with_relations() CASCADE;
+DROP FUNCTION IF EXISTS public.institution_work_updated_at_with_relations() CASCADE;
+DROP FUNCTION IF EXISTS public.location_work_updated_at_with_relations() CASCADE;
+DROP FUNCTION IF EXISTS public.price_work_updated_at_with_relations() CASCADE;
+DROP FUNCTION IF EXISTS public.publisher_work_updated_at_with_relations() CASCADE;
+DROP FUNCTION IF EXISTS public.series_work_updated_at_with_relations() CASCADE;
+DROP FUNCTION IF EXISTS public.work_relation_work_updated_at_with_relations() CASCADE;
+DROP FUNCTION IF EXISTS public.work_work_updated_at_with_relations() CASCADE;
+DROP FUNCTION IF EXISTS public.work_updated_at_with_relations() CASCADE;
+DROP FUNCTION IF EXISTS public.work_set_updated_at() CASCADE;
+DROP FUNCTION IF EXISTS public.publication_chapter_no_dimensions() CASCADE;
+DROP FUNCTION IF EXISTS public.publication_location_canonical_urls() CASCADE;
+DROP FUNCTION IF EXISTS public.diesel_set_updated_at() CASCADE;
+DROP FUNCTION IF EXISTS public.diesel_manage_updated_at(regclass) CASCADE;
+
+-- Drop enum types
+DROP TYPE IF EXISTS public.work_type;
+DROP TYPE IF EXISTS public.work_status;
+DROP TYPE IF EXISTS public.subject_type;
+DROP TYPE IF EXISTS public.series_type;
+DROP TYPE IF EXISTS public.relation_type;
+DROP TYPE IF EXISTS public.publication_type;
+DROP TYPE IF EXISTS public.location_platform;
+DROP TYPE IF EXISTS public.language_relation;
+DROP TYPE IF EXISTS public.language_code;
+DROP TYPE IF EXISTS public.currency_code;
+DROP TYPE IF EXISTS public.country_code;
+DROP TYPE IF EXISTS public.contribution_type;
+
+-- Drop extension
+DROP EXTENSION IF EXISTS "uuid-ossp" CASCADE;
diff --git a/thoth-api/migrations/20250000_v1.0.0/up.sql b/thoth-api/migrations/20250000_v1.0.0/up.sql
new file mode 100644
index 00000000..45211227
--- /dev/null
+++ b/thoth-api/migrations/20250000_v1.0.0/up.sql
@@ -0,0 +1,3882 @@
+--
+-- Name: uuid-ossp; Type: EXTENSION; Schema: -; Owner: -
+--
+
+CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA public;
+
+
+--
+-- Name: EXTENSION "uuid-ossp"; Type: COMMENT; Schema: -; Owner: -
+--
+
+COMMENT ON EXTENSION "uuid-ossp" IS 'generate universally unique identifiers (UUIDs)';
+
+
+--
+-- Name: contribution_type; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE public.contribution_type AS ENUM (
+ 'author',
+ 'editor',
+ 'translator',
+ 'photographer',
+ 'illustrator',
+ 'music-editor',
+ 'foreword-by',
+ 'introduction-by',
+ 'afterword-by',
+ 'preface-by',
+ 'software-by',
+ 'research-by',
+ 'contributions-by',
+ 'indexer'
+);
+
+
+--
+-- Name: country_code; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE public.country_code AS ENUM (
+ 'afg',
+ 'ala',
+ 'alb',
+ 'dza',
+ 'asm',
+ 'and',
+ 'ago',
+ 'aia',
+ 'ata',
+ 'atg',
+ 'arg',
+ 'arm',
+ 'abw',
+ 'aus',
+ 'aut',
+ 'aze',
+ 'bhs',
+ 'bhr',
+ 'bgd',
+ 'brb',
+ 'blr',
+ 'bel',
+ 'blz',
+ 'ben',
+ 'bmu',
+ 'btn',
+ 'bol',
+ 'bes',
+ 'bih',
+ 'bwa',
+ 'bvt',
+ 'bra',
+ 'iot',
+ 'brn',
+ 'bgr',
+ 'bfa',
+ 'bdi',
+ 'cpv',
+ 'khm',
+ 'cmr',
+ 'can',
+ 'cym',
+ 'caf',
+ 'tcd',
+ 'chl',
+ 'chn',
+ 'cxr',
+ 'cck',
+ 'col',
+ 'com',
+ 'cok',
+ 'cri',
+ 'civ',
+ 'hrv',
+ 'cub',
+ 'cuw',
+ 'cyp',
+ 'cze',
+ 'cod',
+ 'dnk',
+ 'dji',
+ 'dma',
+ 'dom',
+ 'ecu',
+ 'egy',
+ 'slv',
+ 'gnq',
+ 'eri',
+ 'est',
+ 'swz',
+ 'eth',
+ 'flk',
+ 'fro',
+ 'fji',
+ 'fin',
+ 'fra',
+ 'guf',
+ 'pyf',
+ 'atf',
+ 'gab',
+ 'gmb',
+ 'geo',
+ 'deu',
+ 'gha',
+ 'gib',
+ 'grc',
+ 'grl',
+ 'grd',
+ 'glp',
+ 'gum',
+ 'gtm',
+ 'ggy',
+ 'gin',
+ 'gnb',
+ 'guy',
+ 'hti',
+ 'hmd',
+ 'hnd',
+ 'hkg',
+ 'hun',
+ 'isl',
+ 'ind',
+ 'idn',
+ 'irn',
+ 'irq',
+ 'irl',
+ 'imn',
+ 'isr',
+ 'ita',
+ 'jam',
+ 'jpn',
+ 'jey',
+ 'jor',
+ 'kaz',
+ 'ken',
+ 'kir',
+ 'kwt',
+ 'kgz',
+ 'lao',
+ 'lva',
+ 'lbn',
+ 'lso',
+ 'lbr',
+ 'lby',
+ 'lie',
+ 'ltu',
+ 'lux',
+ 'mac',
+ 'mdg',
+ 'mwi',
+ 'mys',
+ 'mdv',
+ 'mli',
+ 'mlt',
+ 'mhl',
+ 'mtq',
+ 'mrt',
+ 'mus',
+ 'myt',
+ 'mex',
+ 'fsm',
+ 'mda',
+ 'mco',
+ 'mng',
+ 'mne',
+ 'msr',
+ 'mar',
+ 'moz',
+ 'mmr',
+ 'nam',
+ 'nru',
+ 'npl',
+ 'nld',
+ 'ncl',
+ 'nzl',
+ 'nic',
+ 'ner',
+ 'nga',
+ 'niu',
+ 'nfk',
+ 'prk',
+ 'mkd',
+ 'mnp',
+ 'nor',
+ 'omn',
+ 'pak',
+ 'plw',
+ 'pse',
+ 'pan',
+ 'png',
+ 'pry',
+ 'per',
+ 'phl',
+ 'pcn',
+ 'pol',
+ 'prt',
+ 'pri',
+ 'qat',
+ 'cog',
+ 'reu',
+ 'rou',
+ 'rus',
+ 'rwa',
+ 'blm',
+ 'shn',
+ 'kna',
+ 'lca',
+ 'maf',
+ 'spm',
+ 'vct',
+ 'wsm',
+ 'smr',
+ 'stp',
+ 'sau',
+ 'sen',
+ 'srb',
+ 'syc',
+ 'sle',
+ 'sgp',
+ 'sxm',
+ 'svk',
+ 'svn',
+ 'slb',
+ 'som',
+ 'zaf',
+ 'sgs',
+ 'kor',
+ 'ssd',
+ 'esp',
+ 'lka',
+ 'sdn',
+ 'sur',
+ 'sjm',
+ 'swe',
+ 'che',
+ 'syr',
+ 'twn',
+ 'tjk',
+ 'tza',
+ 'tha',
+ 'tls',
+ 'tgo',
+ 'tkl',
+ 'ton',
+ 'tto',
+ 'tun',
+ 'tur',
+ 'tkm',
+ 'tca',
+ 'tuv',
+ 'uga',
+ 'ukr',
+ 'are',
+ 'gbr',
+ 'umi',
+ 'usa',
+ 'ury',
+ 'uzb',
+ 'vut',
+ 'vat',
+ 'ven',
+ 'vnm',
+ 'vgb',
+ 'vir',
+ 'wlf',
+ 'esh',
+ 'yem',
+ 'zmb',
+ 'zwe'
+);
+
+
+--
+-- Name: currency_code; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE public.currency_code AS ENUM (
+ 'adp',
+ 'aed',
+ 'afa',
+ 'afn',
+ 'alk',
+ 'all',
+ 'amd',
+ 'ang',
+ 'aoa',
+ 'aok',
+ 'aon',
+ 'aor',
+ 'ara',
+ 'arp',
+ 'ars',
+ 'ary',
+ 'ats',
+ 'aud',
+ 'awg',
+ 'aym',
+ 'azm',
+ 'azn',
+ 'bad',
+ 'bam',
+ 'bbd',
+ 'bdt',
+ 'bec',
+ 'bef',
+ 'bel',
+ 'bgj',
+ 'bgk',
+ 'bgl',
+ 'bgn',
+ 'bhd',
+ 'bif',
+ 'bmd',
+ 'bnd',
+ 'bob',
+ 'bop',
+ 'bov',
+ 'brb',
+ 'brc',
+ 'bre',
+ 'brl',
+ 'brn',
+ 'brr',
+ 'bsd',
+ 'btn',
+ 'buk',
+ 'bwp',
+ 'byb',
+ 'byn',
+ 'byr',
+ 'bzd',
+ 'cad',
+ 'cdf',
+ 'chc',
+ 'che',
+ 'chf',
+ 'chw',
+ 'clf',
+ 'clp',
+ 'cny',
+ 'cop',
+ 'cou',
+ 'crc',
+ 'csd',
+ 'csj',
+ 'csk',
+ 'cuc',
+ 'cup',
+ 'cve',
+ 'cyp',
+ 'czk',
+ 'ddm',
+ 'dem',
+ 'djf',
+ 'dkk',
+ 'dop',
+ 'dzd',
+ 'ecs',
+ 'ecv',
+ 'eek',
+ 'egp',
+ 'ern',
+ 'esa',
+ 'esb',
+ 'esp',
+ 'etb',
+ 'eur',
+ 'fim',
+ 'fjd',
+ 'fkp',
+ 'frf',
+ 'gbp',
+ 'gek',
+ 'gel',
+ 'ghc',
+ 'ghp',
+ 'ghs',
+ 'gip',
+ 'gmd',
+ 'gne',
+ 'gnf',
+ 'gns',
+ 'gqe',
+ 'grd',
+ 'gtq',
+ 'gwe',
+ 'gwp',
+ 'gyd',
+ 'hkd',
+ 'hnl',
+ 'hrd',
+ 'hrk',
+ 'htg',
+ 'huf',
+ 'idr',
+ 'iep',
+ 'ilp',
+ 'ilr',
+ 'ils',
+ 'inr',
+ 'iqd',
+ 'irr',
+ 'isj',
+ 'isk',
+ 'itl',
+ 'jmd',
+ 'jod',
+ 'jpy',
+ 'kes',
+ 'kgs',
+ 'khr',
+ 'kmf',
+ 'kpw',
+ 'krw',
+ 'kwd',
+ 'kyd',
+ 'kzt',
+ 'laj',
+ 'lak',
+ 'lbp',
+ 'lkr',
+ 'lrd',
+ 'lsl',
+ 'lsm',
+ 'ltl',
+ 'ltt',
+ 'luc',
+ 'luf',
+ 'lul',
+ 'lvl',
+ 'lvr',
+ 'lyd',
+ 'mad',
+ 'mdl',
+ 'mga',
+ 'mgf',
+ 'mkd',
+ 'mlf',
+ 'mmk',
+ 'mnt',
+ 'mop',
+ 'mro',
+ 'mru',
+ 'mtl',
+ 'mtp',
+ 'mur',
+ 'mvq',
+ 'mvr',
+ 'mwk',
+ 'mxn',
+ 'mxp',
+ 'mxv',
+ 'myr',
+ 'mze',
+ 'mzm',
+ 'mzn',
+ 'nad',
+ 'ngn',
+ 'nic',
+ 'nio',
+ 'nlg',
+ 'nok',
+ 'npr',
+ 'nzd',
+ 'omr',
+ 'pab',
+ 'peh',
+ 'pei',
+ 'pen',
+ 'pes',
+ 'pgk',
+ 'php',
+ 'pkr',
+ 'pln',
+ 'plz',
+ 'pte',
+ 'pyg',
+ 'qar',
+ 'rhd',
+ 'rok',
+ 'rol',
+ 'ron',
+ 'rsd',
+ 'rub',
+ 'rur',
+ 'rwf',
+ 'sar',
+ 'sbd',
+ 'scr',
+ 'sdd',
+ 'sdg',
+ 'sdp',
+ 'sek',
+ 'sgd',
+ 'shp',
+ 'sit',
+ 'skk',
+ 'sll',
+ 'sos',
+ 'srd',
+ 'srg',
+ 'ssp',
+ 'std',
+ 'stn',
+ 'sur',
+ 'svc',
+ 'syp',
+ 'szl',
+ 'thb',
+ 'tjr',
+ 'tjs',
+ 'tmm',
+ 'tmt',
+ 'tnd',
+ 'top',
+ 'tpe',
+ 'trl',
+ 'try',
+ 'ttd',
+ 'twd',
+ 'tzs',
+ 'uah',
+ 'uak',
+ 'ugs',
+ 'ugw',
+ 'ugx',
+ 'usd',
+ 'usn',
+ 'uss',
+ 'uyi',
+ 'uyn',
+ 'uyp',
+ 'uyu',
+ 'uyw',
+ 'uzs',
+ 'veb',
+ 'vef',
+ 'ves',
+ 'vnc',
+ 'vnd',
+ 'vuv',
+ 'wst',
+ 'xaf',
+ 'xag',
+ 'xau',
+ 'xba',
+ 'xbb',
+ 'xbc',
+ 'xbd',
+ 'xcd',
+ 'xdr',
+ 'xeu',
+ 'xfo',
+ 'xfu',
+ 'xof',
+ 'xpd',
+ 'xpf',
+ 'xpt',
+ 'xre',
+ 'xsu',
+ 'xts',
+ 'xua',
+ 'xxx',
+ 'ydd',
+ 'yer',
+ 'yud',
+ 'yum',
+ 'yun',
+ 'zal',
+ 'zar',
+ 'zmk',
+ 'zmw',
+ 'zrn',
+ 'zrz',
+ 'zwc',
+ 'zwd',
+ 'zwl',
+ 'zwn',
+ 'zwr'
+);
+
+
+--
+-- Name: language_code; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE public.language_code AS ENUM (
+ 'aar',
+ 'abk',
+ 'ace',
+ 'ach',
+ 'ada',
+ 'ady',
+ 'afa',
+ 'afh',
+ 'afr',
+ 'ain',
+ 'aka',
+ 'akk',
+ 'alb',
+ 'ale',
+ 'alg',
+ 'alt',
+ 'amh',
+ 'ang',
+ 'anp',
+ 'apa',
+ 'ara',
+ 'arc',
+ 'arg',
+ 'arm',
+ 'arn',
+ 'arp',
+ 'art',
+ 'arw',
+ 'asm',
+ 'ast',
+ 'ath',
+ 'aus',
+ 'ava',
+ 'ave',
+ 'awa',
+ 'aym',
+ 'aze',
+ 'bad',
+ 'bai',
+ 'bak',
+ 'bal',
+ 'bam',
+ 'ban',
+ 'baq',
+ 'bas',
+ 'bat',
+ 'bej',
+ 'bel',
+ 'bem',
+ 'ben',
+ 'ber',
+ 'bho',
+ 'bih',
+ 'bik',
+ 'bin',
+ 'bis',
+ 'bla',
+ 'bnt',
+ 'bos',
+ 'bra',
+ 'bre',
+ 'btk',
+ 'bua',
+ 'bug',
+ 'bul',
+ 'bur',
+ 'byn',
+ 'cad',
+ 'cai',
+ 'car',
+ 'cat',
+ 'cau',
+ 'ceb',
+ 'cel',
+ 'cha',
+ 'chb',
+ 'che',
+ 'chg',
+ 'chi',
+ 'chk',
+ 'chm',
+ 'chn',
+ 'cho',
+ 'chp',
+ 'chr',
+ 'chu',
+ 'chv',
+ 'chy',
+ 'cmc',
+ 'cnr',
+ 'cop',
+ 'cor',
+ 'cos',
+ 'cpe',
+ 'cpf',
+ 'cpp',
+ 'cre',
+ 'crh',
+ 'crp',
+ 'csb',
+ 'cus',
+ 'cze',
+ 'dak',
+ 'dan',
+ 'dar',
+ 'day',
+ 'del',
+ 'den',
+ 'dgr',
+ 'din',
+ 'div',
+ 'doi',
+ 'dra',
+ 'dsb',
+ 'dua',
+ 'dum',
+ 'dut',
+ 'dyu',
+ 'dzo',
+ 'efi',
+ 'egy',
+ 'eka',
+ 'elx',
+ 'eng',
+ 'enm',
+ 'epo',
+ 'est',
+ 'ewe',
+ 'ewo',
+ 'fan',
+ 'fao',
+ 'fat',
+ 'fij',
+ 'fil',
+ 'fin',
+ 'fiu',
+ 'fon',
+ 'fre',
+ 'frm',
+ 'fro',
+ 'frr',
+ 'frs',
+ 'fry',
+ 'ful',
+ 'fur',
+ 'gaa',
+ 'gay',
+ 'gba',
+ 'gem',
+ 'geo',
+ 'ger',
+ 'gez',
+ 'gil',
+ 'gla',
+ 'gle',
+ 'glg',
+ 'glv',
+ 'gmh',
+ 'goh',
+ 'gon',
+ 'gor',
+ 'got',
+ 'grb',
+ 'grc',
+ 'gre',
+ 'grn',
+ 'gsw',
+ 'guj',
+ 'gwi',
+ 'hai',
+ 'hat',
+ 'hau',
+ 'haw',
+ 'heb',
+ 'her',
+ 'hil',
+ 'him',
+ 'hin',
+ 'hit',
+ 'hmn',
+ 'hmo',
+ 'hrv',
+ 'hsb',
+ 'hun',
+ 'hup',
+ 'iba',
+ 'ibo',
+ 'ice',
+ 'ido',
+ 'iii',
+ 'ijo',
+ 'iku',
+ 'ile',
+ 'ilo',
+ 'ina',
+ 'inc',
+ 'ind',
+ 'ine',
+ 'inh',
+ 'ipk',
+ 'ira',
+ 'iro',
+ 'ita',
+ 'jav',
+ 'jbo',
+ 'jpn',
+ 'jpr',
+ 'jrb',
+ 'kaa',
+ 'kab',
+ 'kac',
+ 'kal',
+ 'kam',
+ 'kan',
+ 'kar',
+ 'kas',
+ 'kau',
+ 'kaw',
+ 'kaz',
+ 'kbd',
+ 'kha',
+ 'khi',
+ 'khm',
+ 'kho',
+ 'kik',
+ 'kin',
+ 'kir',
+ 'kmb',
+ 'kok',
+ 'kom',
+ 'kon',
+ 'kor',
+ 'kos',
+ 'kpe',
+ 'krc',
+ 'krl',
+ 'kro',
+ 'kru',
+ 'kua',
+ 'kum',
+ 'kur',
+ 'kut',
+ 'lad',
+ 'lah',
+ 'lam',
+ 'lao',
+ 'lat',
+ 'lav',
+ 'lez',
+ 'lim',
+ 'lin',
+ 'lit',
+ 'lol',
+ 'loz',
+ 'ltz',
+ 'lua',
+ 'lub',
+ 'lug',
+ 'lui',
+ 'lun',
+ 'luo',
+ 'lus',
+ 'mac',
+ 'mad',
+ 'mag',
+ 'mah',
+ 'mai',
+ 'mak',
+ 'mal',
+ 'man',
+ 'mao',
+ 'map',
+ 'mar',
+ 'mas',
+ 'may',
+ 'mdf',
+ 'mdr',
+ 'men',
+ 'mga',
+ 'mic',
+ 'min',
+ 'mis',
+ 'mkh',
+ 'mlg',
+ 'mlt',
+ 'mnc',
+ 'mni',
+ 'mno',
+ 'moh',
+ 'mon',
+ 'mos',
+ 'mul',
+ 'mun',
+ 'mus',
+ 'mwl',
+ 'mwr',
+ 'myn',
+ 'myv',
+ 'nah',
+ 'nai',
+ 'nap',
+ 'nau',
+ 'nav',
+ 'nbl',
+ 'nde',
+ 'ndo',
+ 'nds',
+ 'nep',
+ 'new',
+ 'nia',
+ 'nic',
+ 'niu',
+ 'nno',
+ 'nob',
+ 'nog',
+ 'non',
+ 'nor',
+ 'nqo',
+ 'nso',
+ 'nub',
+ 'nwc',
+ 'nya',
+ 'nym',
+ 'nyn',
+ 'nyo',
+ 'nzi',
+ 'oci',
+ 'oji',
+ 'ori',
+ 'orm',
+ 'osa',
+ 'oss',
+ 'ota',
+ 'oto',
+ 'paa',
+ 'pag',
+ 'pal',
+ 'pam',
+ 'pan',
+ 'pap',
+ 'pau',
+ 'peo',
+ 'per',
+ 'phi',
+ 'phn',
+ 'pli',
+ 'pol',
+ 'pon',
+ 'por',
+ 'pra',
+ 'pro',
+ 'pus',
+ 'qaa',
+ 'que',
+ 'raj',
+ 'rap',
+ 'rar',
+ 'roa',
+ 'roh',
+ 'rom',
+ 'rum',
+ 'run',
+ 'rup',
+ 'rus',
+ 'sad',
+ 'sag',
+ 'sah',
+ 'sai',
+ 'sal',
+ 'sam',
+ 'san',
+ 'sas',
+ 'sat',
+ 'scn',
+ 'sco',
+ 'sel',
+ 'sem',
+ 'sga',
+ 'sgn',
+ 'shn',
+ 'sid',
+ 'sin',
+ 'sio',
+ 'sit',
+ 'sla',
+ 'slo',
+ 'slv',
+ 'sma',
+ 'sme',
+ 'smi',
+ 'smj',
+ 'smn',
+ 'smo',
+ 'sms',
+ 'sna',
+ 'snd',
+ 'snk',
+ 'sog',
+ 'som',
+ 'son',
+ 'sot',
+ 'spa',
+ 'srd',
+ 'srn',
+ 'srp',
+ 'srr',
+ 'ssa',
+ 'ssw',
+ 'suk',
+ 'sun',
+ 'sus',
+ 'sux',
+ 'swa',
+ 'swe',
+ 'syc',
+ 'syr',
+ 'tah',
+ 'tai',
+ 'tam',
+ 'tat',
+ 'tel',
+ 'tem',
+ 'ter',
+ 'tet',
+ 'tgk',
+ 'tgl',
+ 'tha',
+ 'tib',
+ 'tig',
+ 'tir',
+ 'tiv',
+ 'tkl',
+ 'tlh',
+ 'tli',
+ 'tmh',
+ 'tog',
+ 'ton',
+ 'tpi',
+ 'tsi',
+ 'tsn',
+ 'tso',
+ 'tuk',
+ 'tum',
+ 'tup',
+ 'tur',
+ 'tut',
+ 'tvl',
+ 'twi',
+ 'tyv',
+ 'udm',
+ 'uga',
+ 'uig',
+ 'ukr',
+ 'umb',
+ 'und',
+ 'urd',
+ 'uzb',
+ 'vai',
+ 'ven',
+ 'vie',
+ 'vol',
+ 'vot',
+ 'wak',
+ 'wal',
+ 'war',
+ 'was',
+ 'wel',
+ 'wen',
+ 'wln',
+ 'wol',
+ 'xal',
+ 'xho',
+ 'yao',
+ 'yap',
+ 'yid',
+ 'yor',
+ 'ypk',
+ 'zap',
+ 'zbl',
+ 'zen',
+ 'zgh',
+ 'zha',
+ 'znd',
+ 'zul',
+ 'zun',
+ 'zxx',
+ 'zza'
+);
+
+
+--
+-- Name: language_relation; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE public.language_relation AS ENUM (
+ 'original',
+ 'translated-from',
+ 'translated-into'
+);
+
+
+--
+-- Name: location_platform; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE public.location_platform AS ENUM (
+ 'Project MUSE',
+ 'OAPEN',
+ 'DOAB',
+ 'JSTOR',
+ 'EBSCO Host',
+ 'OCLC KB',
+ 'ProQuest KB',
+ 'ProQuest ExLibris',
+ 'EBSCO KB',
+ 'JISC KB',
+ 'Other',
+ 'Google Books',
+ 'Internet Archive',
+ 'ScienceOpen',
+ 'SciELO Books',
+ 'Publisher Website',
+ 'Zenodo',
+ 'Thoth'
+);
+
+
+--
+-- Name: publication_type; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE public.publication_type AS ENUM (
+ 'Paperback',
+ 'Hardback',
+ 'PDF',
+ 'HTML',
+ 'XML',
+ 'Epub',
+ 'Mobi',
+ 'AZW3',
+ 'DOCX',
+ 'FictionBook',
+ 'MP3',
+ 'WAV'
+);
+
+
+--
+-- Name: relation_type; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE public.relation_type AS ENUM (
+ 'replaces',
+ 'has-translation',
+ 'has-part',
+ 'has-child',
+ 'is-replaced-by',
+ 'is-translation-of',
+ 'is-part-of',
+ 'is-child-of'
+);
+
+
+--
+-- Name: series_type; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE public.series_type AS ENUM (
+ 'journal',
+ 'book-series'
+);
+
+
+--
+-- Name: subject_type; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE public.subject_type AS ENUM (
+ 'bic',
+ 'bisac',
+ 'thema',
+ 'lcc',
+ 'custom',
+ 'keyword'
+);
+
+
+--
+-- Name: work_status; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE public.work_status AS ENUM (
+ 'cancelled',
+ 'forthcoming',
+ 'postponed-indefinitely',
+ 'active',
+ 'withdrawn',
+ 'superseded'
+);
+
+
+--
+-- Name: work_type; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE public.work_type AS ENUM (
+ 'book-chapter',
+ 'monograph',
+ 'edited-book',
+ 'textbook',
+ 'journal-issue',
+ 'book-set'
+);
+
+
+--
+-- Name: affiliation_work_updated_at_with_relations(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.affiliation_work_updated_at_with_relations() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ FROM contribution
+ WHERE work.work_id = contribution.work_id AND contribution.contribution_id = OLD.contribution_id
+ OR work.work_id = contribution.work_id AND contribution.contribution_id = NEW.contribution_id;
+ END IF;
+ RETURN NULL;
+END;
+$$;
+
+
+--
+-- Name: contributor_work_updated_at_with_relations(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.contributor_work_updated_at_with_relations() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ FROM contribution
+ -- No need to check OLD.contributor_id, as this will be the same as NEW.contributor_id in all relevant cases
+ -- (contributor_id can't be changed on contributors which are referenced by existing contributions)
+ WHERE work.work_id = contribution.work_id AND contribution.contributor_id = NEW.contributor_id;
+ END IF;
+ RETURN NULL;
+END;
+$$;
+
+
+--
+-- Name: diesel_manage_updated_at(regclass); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.diesel_manage_updated_at(_tbl regclass) RETURNS void
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s
+ FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl);
+END;
+$$;
+
+
+--
+-- Name: diesel_set_updated_at(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.diesel_set_updated_at() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD AND
+ NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at
+ ) THEN
+ NEW.updated_at := current_timestamp;
+ END IF;
+ RETURN NEW;
+END;
+$$;
+
+
+--
+-- Name: imprint_work_updated_at_with_relations(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.imprint_work_updated_at_with_relations() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ WHERE imprint_id = NEW.imprint_id;
+ END IF;
+ RETURN NULL;
+END;
+$$;
+
+
+--
+-- Name: institution_work_updated_at_with_relations(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.institution_work_updated_at_with_relations() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ -- Same as contributor above (but can be connected to work via two different tables)
+ -- Use two separate UPDATE statements as this is much faster than combining the WHERE clauses
+ -- using OR (in tests, this caused several seconds' delay when saving institution updates)
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ FROM funding
+ WHERE work.work_id = funding.work_id AND funding.institution_id = NEW.institution_id;
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ FROM affiliation, contribution
+ WHERE work.work_id = contribution.work_id AND contribution.contribution_id = affiliation.contribution_id AND affiliation.institution_id = NEW.institution_id;
+ END IF;
+ RETURN NULL;
+END;
+$$;
+
+
+--
+-- Name: location_work_updated_at_with_relations(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.location_work_updated_at_with_relations() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ FROM publication
+ WHERE work.work_id = publication.work_id AND publication.publication_id = OLD.publication_id
+ OR work.work_id = publication.work_id AND publication.publication_id = NEW.publication_id;
+ END IF;
+ RETURN NULL;
+END;
+$$;
+
+
+--
+-- Name: price_work_updated_at_with_relations(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.price_work_updated_at_with_relations() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ FROM publication
+ WHERE work.work_id = publication.work_id AND publication.publication_id = OLD.publication_id
+ OR work.work_id = publication.work_id AND publication.publication_id = NEW.publication_id;
+ END IF;
+ RETURN NULL;
+END;
+$$;
+
+
+--
+-- Name: publication_chapter_no_dimensions(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.publication_chapter_no_dimensions() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ (SELECT work_type FROM work WHERE work.work_id = NEW.work_id) = 'book-chapter' AND (
+ NEW.width_mm IS NOT NULL OR
+ NEW.width_in IS NOT NULL OR
+ NEW.height_mm IS NOT NULL OR
+ NEW.height_in IS NOT NULL OR
+ NEW.depth_mm IS NOT NULL OR
+ NEW.depth_in IS NOT NULL OR
+ NEW.weight_g IS NOT NULL OR
+ NEW.weight_oz IS NOT NULL
+ )
+ ) THEN
+ RAISE EXCEPTION 'Chapters cannot have dimensions (Width/Height/Depth/Weight)';
+ END IF;
+ RETURN NEW;
+END;
+$$;
+
+
+--
+-- Name: publication_location_canonical_urls(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.publication_location_canonical_urls() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ NEW.publication_type <> 'Hardback' AND
+ NEW.publication_type <> 'Paperback' AND
+ (SELECT COUNT(*) FROM location
+ WHERE location.publication_id = NEW.publication_id
+ AND location.canonical
+ AND (location.landing_page IS NULL OR location.full_text_url IS NULL)
+ ) > 0
+ ) THEN
+ RAISE EXCEPTION 'Digital publications must have both Landing Page and Full Text URL in all their canonical locations';
+ END IF;
+ RETURN NEW;
+END;
+$$;
+
+
+--
+-- Name: publisher_work_updated_at_with_relations(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.publisher_work_updated_at_with_relations() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ FROM imprint
+ -- Same as contributor above
+ WHERE work.imprint_id = imprint.imprint_id AND imprint.publisher_id = NEW.publisher_id;
+ END IF;
+ RETURN NULL;
+END;
+$$;
+
+
+--
+-- Name: series_work_updated_at_with_relations(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.series_work_updated_at_with_relations() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ FROM issue
+ -- Same as contributor above (note that although series is also connected to work
+ -- via the imprint_id, changes to a series don't affect its imprint)
+ WHERE work.work_id = issue.work_id AND issue.series_id = NEW.series_id;
+ END IF;
+ RETURN NULL;
+END;
+$$;
+
+
+--
+-- Name: work_relation_work_updated_at_with_relations(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.work_relation_work_updated_at_with_relations() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ WHERE work_id = OLD.relator_work_id OR work_id = NEW.relator_work_id
+ OR work_id = OLD.related_work_id OR work_id = NEW.related_work_id;
+ END IF;
+ RETURN NULL;
+END;
+$$;
+
+
+--
+-- Name: work_set_updated_at(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.work_set_updated_at() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD AND
+ NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at AND
+ NEW.updated_at_with_relations IS NOT DISTINCT FROM OLD.updated_at_with_relations
+ ) THEN
+ NEW.updated_at := current_timestamp;
+ NEW.updated_at_with_relations := current_timestamp;
+ END IF;
+ RETURN NEW;
+END;
+$$;
+
+
+--
+-- Name: work_updated_at_with_relations(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.work_updated_at_with_relations() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ WHERE work_id = OLD.work_id OR work_id = NEW.work_id;
+ END IF;
+ RETURN NULL;
+END;
+$$;
+
+
+--
+-- Name: work_work_updated_at_with_relations(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.work_work_updated_at_with_relations() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ FROM work_relation
+ -- The positions of relator/related IDs in this statement don't matter, as
+ -- every work_relation record has a mirrored record with relator/related IDs swapped
+ WHERE work.work_id = work_relation.relator_work_id AND work_relation.related_work_id = NEW.work_id;
+ END IF;
+ RETURN NULL;
+END;
+$$;
+
+
+SET default_tablespace = '';
+
+SET default_table_access_method = heap;
+
+--
+-- Name: account; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.account (
+ account_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ name text NOT NULL,
+ surname text NOT NULL,
+ email text NOT NULL,
+ hash bytea NOT NULL,
+ salt text NOT NULL,
+ is_superuser boolean DEFAULT false NOT NULL,
+ is_bot boolean DEFAULT false NOT NULL,
+ is_active boolean DEFAULT true NOT NULL,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ token text,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ CONSTRAINT account_email_check CHECK ((octet_length(email) >= 1)),
+ CONSTRAINT account_name_check CHECK ((octet_length(name) >= 1)),
+ CONSTRAINT account_salt_check CHECK ((octet_length(salt) >= 1)),
+ CONSTRAINT account_surname_check CHECK ((octet_length(surname) >= 1)),
+ CONSTRAINT account_token_check CHECK ((octet_length(token) >= 1))
+);
+
+
+--
+-- Name: affiliation; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.affiliation (
+ affiliation_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ contribution_id uuid NOT NULL,
+ institution_id uuid NOT NULL,
+ affiliation_ordinal integer NOT NULL,
+ "position" text,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ CONSTRAINT affiliation_affiliation_ordinal_check CHECK ((affiliation_ordinal > 0)),
+ CONSTRAINT affiliation_position_check CHECK ((octet_length("position") >= 1))
+);
+
+
+--
+-- Name: affiliation_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.affiliation_history (
+ affiliation_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ affiliation_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: contribution; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.contribution (
+ work_id uuid NOT NULL,
+ contributor_id uuid NOT NULL,
+ contribution_type public.contribution_type NOT NULL,
+ main_contribution boolean DEFAULT true NOT NULL,
+ biography text,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ first_name text,
+ last_name text NOT NULL,
+ full_name text NOT NULL,
+ contribution_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ contribution_ordinal integer NOT NULL,
+ CONSTRAINT contribution_biography_check CHECK ((octet_length(biography) >= 1)),
+ CONSTRAINT contribution_contribution_ordinal_check CHECK ((contribution_ordinal > 0)),
+ CONSTRAINT contribution_first_name_check CHECK ((octet_length(first_name) >= 1)),
+ CONSTRAINT contribution_full_name_check CHECK ((octet_length(full_name) >= 1)),
+ CONSTRAINT contribution_last_name_check CHECK ((octet_length(last_name) >= 1))
+);
+
+
+--
+-- Name: contribution_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.contribution_history (
+ contribution_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ contribution_id uuid NOT NULL
+);
+
+
+--
+-- Name: contributor; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.contributor (
+ contributor_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ first_name text,
+ last_name text NOT NULL,
+ full_name text NOT NULL,
+ orcid text,
+ website text,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ CONSTRAINT contributor_first_name_check CHECK ((octet_length(first_name) >= 1)),
+ CONSTRAINT contributor_full_name_check CHECK ((octet_length(full_name) >= 1)),
+ CONSTRAINT contributor_last_name_check CHECK ((octet_length(last_name) >= 1)),
+ CONSTRAINT contributor_orcid_check CHECK ((orcid ~ '^https:\/\/orcid\.org\/\d{4}-\d{4}-\d{4}-\d{3}[\dX]$'::text)),
+ CONSTRAINT contributor_website_check CHECK ((octet_length(website) >= 1))
+);
+
+
+--
+-- Name: contributor_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.contributor_history (
+ contributor_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ contributor_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: funding; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.funding (
+ funding_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ work_id uuid NOT NULL,
+ institution_id uuid NOT NULL,
+ program text,
+ project_name text,
+ project_shortname text,
+ grant_number text,
+ jurisdiction text,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ CONSTRAINT funding_grant_number_check CHECK ((octet_length(grant_number) >= 1)),
+ CONSTRAINT funding_jurisdiction_check CHECK ((octet_length(jurisdiction) >= 1)),
+ CONSTRAINT funding_program_check CHECK ((octet_length(program) >= 1)),
+ CONSTRAINT funding_project_name_check CHECK ((octet_length(project_name) >= 1)),
+ CONSTRAINT funding_project_shortname_check CHECK ((octet_length(project_shortname) >= 1))
+);
+
+
+--
+-- Name: funding_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.funding_history (
+ funding_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ funding_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: imprint; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.imprint (
+ imprint_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ publisher_id uuid NOT NULL,
+ imprint_name text NOT NULL,
+ imprint_url text,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ crossmark_doi text,
+ CONSTRAINT imprint_crossmark_doi_check CHECK ((crossmark_doi ~* 'https:\/\/doi.org\/10.\d{4,9}\/[-._\;\(\)\/:a-zA-Z0-9]+$'::text)),
+ CONSTRAINT imprint_imprint_name_check CHECK ((octet_length(imprint_name) >= 1)),
+ CONSTRAINT imprint_imprint_url_check CHECK ((imprint_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'::text))
+);
+
+
+--
+-- Name: imprint_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.imprint_history (
+ imprint_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ imprint_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: institution; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.institution (
+ institution_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ institution_name text NOT NULL,
+ institution_doi text,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ ror text,
+ country_code public.country_code,
+ CONSTRAINT institution_institution_doi_check CHECK ((institution_doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._;()\/:a-zA-Z0-9<>+[\]]+$'::text)),
+ CONSTRAINT institution_institution_name_check CHECK ((octet_length(institution_name) >= 1)),
+ CONSTRAINT institution_ror_check CHECK ((ror ~ '^https:\/\/ror\.org\/0[a-hjkmnp-z0-9]{6}\d{2}$'::text))
+);
+
+
+--
+-- Name: institution_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.institution_history (
+ institution_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ institution_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: issue; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.issue (
+ series_id uuid NOT NULL,
+ work_id uuid NOT NULL,
+ issue_ordinal integer NOT NULL,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ issue_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ CONSTRAINT issue_issue_ordinal_check CHECK ((issue_ordinal > 0))
+);
+
+
+--
+-- Name: issue_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.issue_history (
+ issue_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ issue_id uuid NOT NULL
+);
+
+
+--
+-- Name: language; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.language (
+ language_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ work_id uuid NOT NULL,
+ language_code public.language_code NOT NULL,
+ language_relation public.language_relation NOT NULL,
+ main_language boolean DEFAULT false NOT NULL,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: language_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.language_history (
+ language_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ language_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: location; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.location (
+ location_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ publication_id uuid NOT NULL,
+ landing_page text,
+ full_text_url text,
+ location_platform public.location_platform DEFAULT 'Other'::public.location_platform NOT NULL,
+ canonical boolean DEFAULT false NOT NULL,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ CONSTRAINT location_full_text_url_check CHECK ((full_text_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'::text)),
+ CONSTRAINT location_landing_page_check CHECK ((landing_page ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'::text)),
+ CONSTRAINT location_url_check CHECK (((landing_page IS NOT NULL) OR (full_text_url IS NOT NULL)))
+);
+
+
+--
+-- Name: location_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.location_history (
+ location_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ location_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: price; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.price (
+ price_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ publication_id uuid NOT NULL,
+ currency_code public.currency_code NOT NULL,
+ unit_price double precision NOT NULL,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ CONSTRAINT price_unit_price_check CHECK ((unit_price > (0.0)::double precision))
+);
+
+
+--
+-- Name: price_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.price_history (
+ price_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ price_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: publication; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.publication (
+ publication_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ publication_type public.publication_type NOT NULL,
+ work_id uuid NOT NULL,
+ isbn text,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ width_mm double precision,
+ width_in double precision,
+ height_mm double precision,
+ height_in double precision,
+ depth_mm double precision,
+ depth_in double precision,
+ weight_g double precision,
+ weight_oz double precision,
+ CONSTRAINT publication_depth_in_check CHECK ((depth_in > (0.0)::double precision)),
+ CONSTRAINT publication_depth_in_not_missing CHECK (((depth_in IS NOT NULL) OR (depth_mm IS NULL))),
+ CONSTRAINT publication_depth_mm_check CHECK ((depth_mm > (0.0)::double precision)),
+ CONSTRAINT publication_depth_mm_not_missing CHECK (((depth_mm IS NOT NULL) OR (depth_in IS NULL))),
+ CONSTRAINT publication_height_in_check CHECK ((height_in > (0.0)::double precision)),
+ CONSTRAINT publication_height_in_not_missing CHECK (((height_in IS NOT NULL) OR (height_mm IS NULL))),
+ CONSTRAINT publication_height_mm_check CHECK ((height_mm > (0.0)::double precision)),
+ CONSTRAINT publication_height_mm_not_missing CHECK (((height_mm IS NOT NULL) OR (height_in IS NULL))),
+ CONSTRAINT publication_isbn_check CHECK ((octet_length(isbn) = 17)),
+ CONSTRAINT publication_non_physical_no_dimensions CHECK ((((width_mm IS NULL) AND (width_in IS NULL) AND (height_mm IS NULL) AND (height_in IS NULL) AND (depth_mm IS NULL) AND (depth_in IS NULL) AND (weight_g IS NULL) AND (weight_oz IS NULL)) OR (publication_type = 'Paperback'::public.publication_type) OR (publication_type = 'Hardback'::public.publication_type))),
+ CONSTRAINT publication_weight_g_check CHECK ((weight_g > (0.0)::double precision)),
+ CONSTRAINT publication_weight_g_not_missing CHECK (((weight_g IS NOT NULL) OR (weight_oz IS NULL))),
+ CONSTRAINT publication_weight_oz_check CHECK ((weight_oz > (0.0)::double precision)),
+ CONSTRAINT publication_weight_oz_not_missing CHECK (((weight_oz IS NOT NULL) OR (weight_g IS NULL))),
+ CONSTRAINT publication_width_in_check CHECK ((width_in > (0.0)::double precision)),
+ CONSTRAINT publication_width_in_not_missing CHECK (((width_in IS NOT NULL) OR (width_mm IS NULL))),
+ CONSTRAINT publication_width_mm_check CHECK ((width_mm > (0.0)::double precision)),
+ CONSTRAINT publication_width_mm_not_missing CHECK (((width_mm IS NOT NULL) OR (width_in IS NULL)))
+);
+
+
+--
+-- Name: publication_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.publication_history (
+ publication_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ publication_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: publisher; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.publisher (
+ publisher_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ publisher_name text NOT NULL,
+ publisher_shortname text,
+ publisher_url text,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ CONSTRAINT publisher_publisher_name_check CHECK ((octet_length(publisher_name) >= 1)),
+ CONSTRAINT publisher_publisher_shortname_check CHECK ((octet_length(publisher_shortname) >= 1)),
+ CONSTRAINT publisher_publisher_url_check CHECK ((publisher_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'::text))
+);
+
+
+--
+-- Name: publisher_account; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.publisher_account (
+ account_id uuid NOT NULL,
+ publisher_id uuid NOT NULL,
+ is_admin boolean DEFAULT false NOT NULL,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: publisher_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.publisher_history (
+ publisher_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ publisher_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: reference; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.reference (
+ reference_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ work_id uuid NOT NULL,
+ reference_ordinal integer NOT NULL,
+ doi text,
+ unstructured_citation text,
+ issn text,
+ isbn text,
+ journal_title text,
+ article_title text,
+ series_title text,
+ volume_title text,
+ edition integer,
+ author text,
+ volume text,
+ issue text,
+ first_page text,
+ component_number text,
+ standard_designator text,
+ standards_body_name text,
+ standards_body_acronym text,
+ url text,
+ publication_date date,
+ retrieval_date date,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ CONSTRAINT reference_article_title_check CHECK ((octet_length(article_title) >= 1)),
+ CONSTRAINT reference_author_check CHECK ((octet_length(author) >= 1)),
+ CONSTRAINT reference_component_number_check CHECK ((octet_length(component_number) >= 1)),
+ CONSTRAINT reference_doi_andor_unstructured_citation CHECK (((doi IS NOT NULL) OR (unstructured_citation IS NOT NULL))),
+ CONSTRAINT reference_doi_check CHECK ((doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._;()\/:a-zA-Z0-9<>+[\]]+$'::text)),
+ CONSTRAINT reference_edition_check CHECK ((edition > 0)),
+ CONSTRAINT reference_first_page_check CHECK ((octet_length(first_page) >= 1)),
+ CONSTRAINT reference_isbn_check CHECK ((octet_length(isbn) = 17)),
+ CONSTRAINT reference_issn_check CHECK ((issn ~* '\d{4}\-\d{3}(\d|X)'::text)),
+ CONSTRAINT reference_issue_check CHECK ((octet_length(issue) >= 1)),
+ CONSTRAINT reference_journal_title_check CHECK ((octet_length(journal_title) >= 1)),
+ CONSTRAINT reference_reference_ordinal_check CHECK ((reference_ordinal > 0)),
+ CONSTRAINT reference_series_title_check CHECK ((octet_length(series_title) >= 1)),
+ CONSTRAINT reference_standard_citation_required_fields CHECK ((((standard_designator IS NOT NULL) AND (standards_body_name IS NOT NULL) AND (standards_body_acronym IS NOT NULL)) OR ((standard_designator IS NULL) AND (standards_body_name IS NULL) AND (standards_body_acronym IS NULL)))),
+ CONSTRAINT reference_standard_designator_check CHECK ((octet_length(standard_designator) >= 1)),
+ CONSTRAINT reference_standards_body_acronym_check CHECK ((octet_length(standards_body_acronym) >= 1)),
+ CONSTRAINT reference_standards_body_name_check CHECK ((octet_length(standards_body_name) >= 1)),
+ CONSTRAINT reference_unstructured_citation_check CHECK ((octet_length(unstructured_citation) >= 1)),
+ CONSTRAINT reference_url_check CHECK ((url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'::text)),
+ CONSTRAINT reference_volume_check CHECK ((octet_length(volume) >= 1)),
+ CONSTRAINT reference_volume_title_check CHECK ((octet_length(volume_title) >= 1))
+);
+
+
+--
+-- Name: reference_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.reference_history (
+ reference_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ reference_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: series; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.series (
+ series_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ series_type public.series_type NOT NULL,
+ series_name text NOT NULL,
+ issn_print text,
+ issn_digital text,
+ series_url text,
+ imprint_id uuid NOT NULL,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ series_description text,
+ series_cfp_url text,
+ CONSTRAINT series_issn_digital_check CHECK ((issn_digital ~* '\d{4}\-\d{3}(\d|X)'::text)),
+ CONSTRAINT series_issn_print_check CHECK ((issn_print ~* '\d{4}\-\d{3}(\d|X)'::text)),
+ CONSTRAINT series_series_cfp_url_check CHECK ((series_cfp_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'::text)),
+ CONSTRAINT series_series_description_check CHECK ((octet_length(series_description) >= 1)),
+ CONSTRAINT series_series_name_check CHECK ((octet_length(series_name) >= 1)),
+ CONSTRAINT series_series_url_check CHECK ((series_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'::text))
+);
+
+
+--
+-- Name: series_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.series_history (
+ series_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ series_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: subject; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.subject (
+ subject_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ work_id uuid NOT NULL,
+ subject_type public.subject_type NOT NULL,
+ subject_code text NOT NULL,
+ subject_ordinal integer NOT NULL,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ CONSTRAINT subject_subject_code_check CHECK ((octet_length(subject_code) >= 1)),
+ CONSTRAINT subject_subject_ordinal_check CHECK ((subject_ordinal > 0))
+);
+
+
+--
+-- Name: subject_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.subject_history (
+ subject_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ subject_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: work; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.work (
+ work_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ work_type public.work_type NOT NULL,
+ work_status public.work_status NOT NULL,
+ full_title text NOT NULL,
+ title text NOT NULL,
+ subtitle text,
+ reference text,
+ edition integer,
+ imprint_id uuid NOT NULL,
+ doi text,
+ publication_date date,
+ place text,
+ page_count integer,
+ page_breakdown text,
+ image_count integer,
+ table_count integer,
+ audio_count integer,
+ video_count integer,
+ license text,
+ copyright_holder text,
+ landing_page text,
+ lccn text,
+ oclc text,
+ short_abstract text,
+ long_abstract text,
+ general_note text,
+ toc text,
+ cover_url text,
+ cover_caption text,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ first_page text,
+ last_page text,
+ page_interval text,
+ updated_at_with_relations timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ bibliography_note text,
+ withdrawn_date date,
+ CONSTRAINT work_active_publication_date_check CHECK ((((work_status = ANY (ARRAY['active'::public.work_status, 'withdrawn'::public.work_status, 'superseded'::public.work_status])) AND (publication_date IS NOT NULL)) OR (work_status <> ALL (ARRAY['active'::public.work_status, 'withdrawn'::public.work_status, 'superseded'::public.work_status])))),
+ CONSTRAINT work_active_withdrawn_date_check CHECK (((work_status = 'withdrawn'::public.work_status) OR (work_status = 'superseded'::public.work_status) OR ((work_status <> ALL (ARRAY['withdrawn'::public.work_status, 'superseded'::public.work_status])) AND (withdrawn_date IS NULL)))),
+ CONSTRAINT work_audio_count_check CHECK ((audio_count >= 0)),
+ CONSTRAINT work_bibliography_note_check CHECK ((octet_length(bibliography_note) >= 1)),
+ CONSTRAINT work_chapter_no_edition CHECK (((edition IS NULL) OR (work_type <> 'book-chapter'::public.work_type))),
+ CONSTRAINT work_chapter_no_lccn CHECK (((lccn IS NULL) OR (work_type <> 'book-chapter'::public.work_type))),
+ CONSTRAINT work_chapter_no_oclc CHECK (((oclc IS NULL) OR (work_type <> 'book-chapter'::public.work_type))),
+ CONSTRAINT work_chapter_no_toc CHECK (((toc IS NULL) OR (work_type <> 'book-chapter'::public.work_type))),
+ CONSTRAINT work_copyright_holder_check CHECK ((octet_length(copyright_holder) >= 1)),
+ CONSTRAINT work_cover_caption_check CHECK ((octet_length(cover_caption) >= 1)),
+ CONSTRAINT work_cover_url_check CHECK ((cover_url ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'::text)),
+ CONSTRAINT work_doi_check CHECK ((doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._;()\/:a-zA-Z0-9<>+[\]]+$'::text)),
+ CONSTRAINT work_edition_check CHECK ((edition > 0)),
+ CONSTRAINT work_first_page_check CHECK ((octet_length(first_page) >= 1)),
+ CONSTRAINT work_full_title_check CHECK ((octet_length(full_title) >= 1)),
+ CONSTRAINT work_general_note_check CHECK ((octet_length(general_note) >= 1)),
+ CONSTRAINT work_image_count_check CHECK ((image_count >= 0)),
+ CONSTRAINT work_inactive_no_withdrawn_date_check CHECK (((((work_status = 'withdrawn'::public.work_status) OR (work_status = 'superseded'::public.work_status)) AND (withdrawn_date IS NOT NULL)) OR (work_status <> ALL (ARRAY['withdrawn'::public.work_status, 'superseded'::public.work_status])))),
+ CONSTRAINT work_landing_page_check CHECK ((landing_page ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'::text)),
+ CONSTRAINT work_last_page_check CHECK ((octet_length(last_page) >= 1)),
+ CONSTRAINT work_lccn_check CHECK ((octet_length(lccn) >= 1)),
+ CONSTRAINT work_license_check CHECK ((license ~* '^[^:]*:\/\/(?:[^\/:]*:[^\/@]*@)?(?:[^\/:.]*\.)+([^:\/]+)'::text)),
+ CONSTRAINT work_long_abstract_check CHECK ((octet_length(long_abstract) >= 1)),
+ CONSTRAINT work_non_chapter_has_edition CHECK (((edition IS NOT NULL) OR (work_type = 'book-chapter'::public.work_type))),
+ CONSTRAINT work_non_chapter_no_first_page CHECK (((first_page IS NULL) OR (work_type = 'book-chapter'::public.work_type))),
+ CONSTRAINT work_non_chapter_no_last_page CHECK (((last_page IS NULL) OR (work_type = 'book-chapter'::public.work_type))),
+ CONSTRAINT work_non_chapter_no_page_interval CHECK (((page_interval IS NULL) OR (work_type = 'book-chapter'::public.work_type))),
+ CONSTRAINT work_oclc_check CHECK ((octet_length(oclc) >= 1)),
+ CONSTRAINT work_page_breakdown_check CHECK ((octet_length(page_breakdown) >= 1)),
+ CONSTRAINT work_page_count_check CHECK ((page_count > 0)),
+ CONSTRAINT work_page_interval_check CHECK ((octet_length(page_interval) >= 1)),
+ CONSTRAINT work_place_check CHECK ((octet_length(place) >= 1)),
+ CONSTRAINT work_reference_check CHECK ((octet_length(reference) >= 1)),
+ CONSTRAINT work_short_abstract_check CHECK ((octet_length(short_abstract) >= 1)),
+ CONSTRAINT work_subtitle_check CHECK ((octet_length(subtitle) >= 1)),
+ CONSTRAINT work_table_count_check CHECK ((table_count >= 0)),
+ CONSTRAINT work_title_check CHECK ((octet_length(title) >= 1)),
+ CONSTRAINT work_toc_check CHECK ((octet_length(toc) >= 1)),
+ CONSTRAINT work_video_count_check CHECK ((video_count >= 0)),
+ CONSTRAINT work_withdrawn_date_after_publication_date_check CHECK (((withdrawn_date IS NULL) OR (publication_date < withdrawn_date)))
+);
+
+
+--
+-- Name: work_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.work_history (
+ work_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ work_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: work_relation; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.work_relation (
+ work_relation_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ relator_work_id uuid NOT NULL,
+ related_work_id uuid NOT NULL,
+ relation_type public.relation_type NOT NULL,
+ relation_ordinal integer NOT NULL,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updated_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ CONSTRAINT work_relation_ids_check CHECK ((relator_work_id <> related_work_id)),
+ CONSTRAINT work_relation_relation_ordinal_check CHECK ((relation_ordinal > 0))
+);
+
+
+--
+-- Name: work_relation_history; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.work_relation_history (
+ work_relation_history_id uuid DEFAULT public.uuid_generate_v4() NOT NULL,
+ work_relation_id uuid NOT NULL,
+ account_id uuid NOT NULL,
+ data jsonb NOT NULL,
+ "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+
+--
+-- Name: account account_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.account
+ ADD CONSTRAINT account_pkey PRIMARY KEY (account_id);
+
+
+--
+-- Name: affiliation_history affiliation_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.affiliation_history
+ ADD CONSTRAINT affiliation_history_pkey PRIMARY KEY (affiliation_history_id);
+
+
+--
+-- Name: affiliation affiliation_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.affiliation
+ ADD CONSTRAINT affiliation_pkey PRIMARY KEY (affiliation_id);
+
+
+--
+-- Name: contribution contribution_contribution_ordinal_work_id_uniq; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.contribution
+ ADD CONSTRAINT contribution_contribution_ordinal_work_id_uniq UNIQUE (contribution_ordinal, work_id);
+
+
+--
+-- Name: contribution_history contribution_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.contribution_history
+ ADD CONSTRAINT contribution_history_pkey PRIMARY KEY (contribution_history_id);
+
+
+--
+-- Name: contribution contribution_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.contribution
+ ADD CONSTRAINT contribution_pkey PRIMARY KEY (contribution_id);
+
+
+--
+-- Name: contribution contribution_work_id_contributor_id_contribution_type_uniq; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.contribution
+ ADD CONSTRAINT contribution_work_id_contributor_id_contribution_type_uniq UNIQUE (work_id, contributor_id, contribution_type);
+
+
+--
+-- Name: contributor_history contributor_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.contributor_history
+ ADD CONSTRAINT contributor_history_pkey PRIMARY KEY (contributor_history_id);
+
+
+--
+-- Name: contributor contributor_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.contributor
+ ADD CONSTRAINT contributor_pkey PRIMARY KEY (contributor_id);
+
+
+--
+-- Name: institution_history funder_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.institution_history
+ ADD CONSTRAINT funder_history_pkey PRIMARY KEY (institution_history_id);
+
+
+--
+-- Name: funding_history funding_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.funding_history
+ ADD CONSTRAINT funding_history_pkey PRIMARY KEY (funding_history_id);
+
+
+--
+-- Name: funding funding_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.funding
+ ADD CONSTRAINT funding_pkey PRIMARY KEY (funding_id);
+
+
+--
+-- Name: imprint_history imprint_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.imprint_history
+ ADD CONSTRAINT imprint_history_pkey PRIMARY KEY (imprint_history_id);
+
+
+--
+-- Name: imprint imprint_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.imprint
+ ADD CONSTRAINT imprint_pkey PRIMARY KEY (imprint_id);
+
+
+--
+-- Name: institution institution_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.institution
+ ADD CONSTRAINT institution_pkey PRIMARY KEY (institution_id);
+
+
+--
+-- Name: issue_history issue_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.issue_history
+ ADD CONSTRAINT issue_history_pkey PRIMARY KEY (issue_history_id);
+
+
+--
+-- Name: issue issue_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.issue
+ ADD CONSTRAINT issue_pkey PRIMARY KEY (issue_id);
+
+
+--
+-- Name: issue issue_series_id_work_id_uniq; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.issue
+ ADD CONSTRAINT issue_series_id_work_id_uniq UNIQUE (series_id, work_id);
+
+
+--
+-- Name: language_history language_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.language_history
+ ADD CONSTRAINT language_history_pkey PRIMARY KEY (language_history_id);
+
+
+--
+-- Name: language language_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.language
+ ADD CONSTRAINT language_pkey PRIMARY KEY (language_id);
+
+
+--
+-- Name: location_history location_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.location_history
+ ADD CONSTRAINT location_history_pkey PRIMARY KEY (location_history_id);
+
+
+--
+-- Name: location location_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.location
+ ADD CONSTRAINT location_pkey PRIMARY KEY (location_id);
+
+
+--
+-- Name: price_history price_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.price_history
+ ADD CONSTRAINT price_history_pkey PRIMARY KEY (price_history_id);
+
+
+--
+-- Name: price price_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.price
+ ADD CONSTRAINT price_pkey PRIMARY KEY (price_id);
+
+
+--
+-- Name: price price_publication_id_currency_code_uniq; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.price
+ ADD CONSTRAINT price_publication_id_currency_code_uniq UNIQUE (publication_id, currency_code);
+
+
+--
+-- Name: publication_history publication_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.publication_history
+ ADD CONSTRAINT publication_history_pkey PRIMARY KEY (publication_history_id);
+
+
+--
+-- Name: publication publication_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.publication
+ ADD CONSTRAINT publication_pkey PRIMARY KEY (publication_id);
+
+
+--
+-- Name: publication publication_publication_type_work_id_uniq; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.publication
+ ADD CONSTRAINT publication_publication_type_work_id_uniq UNIQUE (publication_type, work_id);
+
+
+--
+-- Name: publisher_account publisher_account_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.publisher_account
+ ADD CONSTRAINT publisher_account_pkey PRIMARY KEY (account_id, publisher_id);
+
+
+--
+-- Name: publisher_history publisher_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.publisher_history
+ ADD CONSTRAINT publisher_history_pkey PRIMARY KEY (publisher_history_id);
+
+
+--
+-- Name: publisher publisher_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.publisher
+ ADD CONSTRAINT publisher_pkey PRIMARY KEY (publisher_id);
+
+
+--
+-- Name: reference_history reference_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.reference_history
+ ADD CONSTRAINT reference_history_pkey PRIMARY KEY (reference_history_id);
+
+
+--
+-- Name: reference reference_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.reference
+ ADD CONSTRAINT reference_pkey PRIMARY KEY (reference_id);
+
+
+--
+-- Name: reference reference_reference_ordinal_work_id_uniq; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.reference
+ ADD CONSTRAINT reference_reference_ordinal_work_id_uniq UNIQUE (work_id, reference_ordinal);
+
+
+--
+-- Name: series_history series_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.series_history
+ ADD CONSTRAINT series_history_pkey PRIMARY KEY (series_history_id);
+
+
+--
+-- Name: series series_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.series
+ ADD CONSTRAINT series_pkey PRIMARY KEY (series_id);
+
+
+--
+-- Name: subject_history subject_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.subject_history
+ ADD CONSTRAINT subject_history_pkey PRIMARY KEY (subject_history_id);
+
+
+--
+-- Name: subject subject_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.subject
+ ADD CONSTRAINT subject_pkey PRIMARY KEY (subject_id);
+
+
+--
+-- Name: work_history work_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.work_history
+ ADD CONSTRAINT work_history_pkey PRIMARY KEY (work_history_id);
+
+
+--
+-- Name: work work_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.work
+ ADD CONSTRAINT work_pkey PRIMARY KEY (work_id);
+
+
+--
+-- Name: work_relation_history work_relation_history_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.work_relation_history
+ ADD CONSTRAINT work_relation_history_pkey PRIMARY KEY (work_relation_history_id);
+
+
+--
+-- Name: work_relation work_relation_ordinal_type_uniq; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.work_relation
+ ADD CONSTRAINT work_relation_ordinal_type_uniq UNIQUE (relation_ordinal, relator_work_id, relation_type);
+
+
+--
+-- Name: work_relation work_relation_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.work_relation
+ ADD CONSTRAINT work_relation_pkey PRIMARY KEY (work_relation_id);
+
+
+--
+-- Name: work_relation work_relation_relator_related_uniq; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.work_relation
+ ADD CONSTRAINT work_relation_relator_related_uniq UNIQUE (relator_work_id, related_work_id);
+
+
+--
+-- Name: affiliation_uniq_ord_in_contribution_idx; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX affiliation_uniq_ord_in_contribution_idx ON public.affiliation USING btree (contribution_id, affiliation_ordinal);
+
+
+--
+-- Name: doi_uniq_idx; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX doi_uniq_idx ON public.work USING btree (lower(doi));
+
+
+--
+-- Name: email_uniq_idx; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX email_uniq_idx ON public.account USING btree (lower(email));
+
+
+--
+-- Name: idx_account_email; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_account_email ON public.account USING btree (email);
+
+
+--
+-- Name: idx_affiliation_contribution_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_affiliation_contribution_id ON public.affiliation USING btree (contribution_id);
+
+
+--
+-- Name: idx_affiliation_ordinal_asc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_affiliation_ordinal_asc ON public.affiliation USING btree (affiliation_ordinal, contribution_id);
+
+
+--
+-- Name: idx_contribution_contributor_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_contribution_contributor_id ON public.contribution USING btree (contributor_id);
+
+
+--
+-- Name: idx_contribution_ordinal_asc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_contribution_ordinal_asc ON public.contribution USING btree (contribution_ordinal, work_id);
+
+
+--
+-- Name: idx_contribution_work_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_contribution_work_id ON public.contribution USING btree (work_id);
+
+
+--
+-- Name: idx_contributor_full_name; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_contributor_full_name ON public.contributor USING btree (full_name);
+
+
+--
+-- Name: idx_contributor_last_name; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_contributor_last_name ON public.contributor USING btree (last_name);
+
+
+--
+-- Name: idx_contributor_orcid; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_contributor_orcid ON public.contributor USING btree (orcid);
+
+
+--
+-- Name: idx_funding_program; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_funding_program ON public.funding USING btree (program);
+
+
+--
+-- Name: idx_funding_work_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_funding_work_id ON public.funding USING btree (work_id);
+
+
+--
+-- Name: idx_imprint_imprint_name; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_imprint_imprint_name ON public.imprint USING btree (imprint_name);
+
+
+--
+-- Name: idx_imprint_imprint_url; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_imprint_imprint_url ON public.imprint USING btree (imprint_url);
+
+
+--
+-- Name: idx_imprint_publisher_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_imprint_publisher_id ON public.imprint USING btree (publisher_id);
+
+
+--
+-- Name: idx_institution_institution_doi; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_institution_institution_doi ON public.institution USING btree (institution_doi);
+
+
+--
+-- Name: idx_institution_institution_name; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_institution_institution_name ON public.institution USING btree (institution_name);
+
+
+--
+-- Name: idx_institution_ror; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_institution_ror ON public.institution USING btree (ror);
+
+
+--
+-- Name: idx_issue_ordinal_series_id_asc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_issue_ordinal_series_id_asc ON public.issue USING btree (issue_ordinal, series_id);
+
+
+--
+-- Name: idx_issue_ordinal_work_id_asc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_issue_ordinal_work_id_asc ON public.issue USING btree (issue_ordinal, work_id);
+
+
+--
+-- Name: idx_language_language_code_asc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_language_language_code_asc ON public.language USING btree (language_code, work_id);
+
+
+--
+-- Name: idx_location_location_platform_asc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_location_location_platform_asc ON public.location USING btree (location_platform, publication_id);
+
+
+--
+-- Name: idx_price_currency_code_asc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_price_currency_code_asc ON public.price USING btree (currency_code, publication_id);
+
+
+--
+-- Name: idx_publication_isbn; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_publication_isbn ON public.publication USING btree (isbn);
+
+
+--
+-- Name: idx_publication_publication_type; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_publication_publication_type ON public.publication USING btree (publication_type);
+
+
+--
+-- Name: idx_publication_work_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_publication_work_id ON public.publication USING btree (work_id);
+
+
+--
+-- Name: idx_publisher_account_account_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_publisher_account_account_id ON public.publisher_account USING btree (account_id);
+
+
+--
+-- Name: idx_publisher_publisher_name; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_publisher_publisher_name ON public.publisher USING btree (publisher_name);
+
+
+--
+-- Name: idx_publisher_publisher_shortname; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_publisher_publisher_shortname ON public.publisher USING btree (publisher_shortname);
+
+
+--
+-- Name: idx_reference_article_title; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_reference_article_title ON public.reference USING btree (article_title);
+
+
+--
+-- Name: idx_reference_author_substr; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_reference_author_substr ON public.reference USING btree ("substring"(author, 1, 255));
+
+
+--
+-- Name: idx_reference_doi; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_reference_doi ON public.reference USING btree (doi);
+
+
+--
+-- Name: idx_reference_isbn; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_reference_isbn ON public.reference USING btree (isbn);
+
+
+--
+-- Name: idx_reference_issn; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_reference_issn ON public.reference USING btree (issn);
+
+
+--
+-- Name: idx_reference_journal_title; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_reference_journal_title ON public.reference USING btree (journal_title);
+
+
+--
+-- Name: idx_reference_series_title; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_reference_series_title ON public.reference USING btree (series_title);
+
+
+--
+-- Name: idx_reference_standard_designator; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_reference_standard_designator ON public.reference USING btree (standard_designator);
+
+
+--
+-- Name: idx_reference_standards_body_acronym; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_reference_standards_body_acronym ON public.reference USING btree (standards_body_acronym);
+
+
+--
+-- Name: idx_reference_standards_body_name; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_reference_standards_body_name ON public.reference USING btree (standards_body_name);
+
+
+--
+-- Name: idx_reference_unstructured_citation; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_reference_unstructured_citation ON public.reference USING btree (unstructured_citation);
+
+
+--
+-- Name: idx_reference_volume_title; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_reference_volume_title ON public.reference USING btree (volume_title);
+
+
+--
+-- Name: idx_reference_work_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_reference_work_id ON public.reference USING btree (work_id);
+
+
+--
+-- Name: idx_series_imprint_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_series_imprint_id ON public.series USING btree (imprint_id);
+
+
+--
+-- Name: idx_series_issn_digital; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_series_issn_digital ON public.series USING btree (issn_digital);
+
+
+--
+-- Name: idx_series_issn_print; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_series_issn_print ON public.series USING btree (issn_print);
+
+
+--
+-- Name: idx_series_series_description; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_series_series_description ON public.series USING btree (series_description);
+
+
+--
+-- Name: idx_series_series_name; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_series_series_name ON public.series USING btree (series_name);
+
+
+--
+-- Name: idx_series_series_url; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_series_series_url ON public.series USING btree (series_url);
+
+
+--
+-- Name: idx_subject_subject_code_asc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_subject_subject_code_asc ON public.subject USING btree (subject_code, work_id);
+
+
+--
+-- Name: idx_subject_subject_ordinal_asc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_subject_subject_ordinal_asc ON public.subject USING btree (subject_ordinal, work_id);
+
+
+--
+-- Name: idx_work_books_pub_date_desc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_work_books_pub_date_desc ON public.work USING btree (publication_date DESC) WHERE ((work_type = ANY (ARRAY['monograph'::public.work_type, 'edited-book'::public.work_type, 'textbook'::public.work_type])) AND (work_status = 'active'::public.work_status));
+
+
+--
+-- Name: idx_work_doi; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_work_doi ON public.work USING btree (doi);
+
+
+--
+-- Name: idx_work_full_title_asc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_work_full_title_asc ON public.work USING btree (full_title, work_id);
+
+
+--
+-- Name: idx_work_imprint_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_work_imprint_id ON public.work USING btree (imprint_id);
+
+
+--
+-- Name: idx_work_landing_page; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_work_landing_page ON public.work USING btree (landing_page);
+
+
+--
+-- Name: idx_work_long_abstract_substr; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_work_long_abstract_substr ON public.work USING btree ("substring"(long_abstract, 1, 255));
+
+
+--
+-- Name: idx_work_publication_date_asc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_work_publication_date_asc ON public.work USING btree (publication_date, work_id);
+
+
+--
+-- Name: idx_work_publication_date_desc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_work_publication_date_desc ON public.work USING btree (publication_date DESC, work_id);
+
+
+--
+-- Name: idx_work_reference; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_work_reference ON public.work USING btree (reference);
+
+
+--
+-- Name: idx_work_relation_relation_ordinal_related_relation_type_asc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_work_relation_relation_ordinal_related_relation_type_asc ON public.work_relation USING btree (relation_ordinal, related_work_id, relation_type);
+
+
+--
+-- Name: idx_work_relation_relation_ordinal_relator_relation_type_asc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_work_relation_relation_ordinal_relator_relation_type_asc ON public.work_relation USING btree (relation_ordinal, relator_work_id, relation_type);
+
+
+--
+-- Name: idx_work_short_abstract_substr; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_work_short_abstract_substr ON public.work USING btree ("substring"(short_abstract, 1, 255));
+
+
+--
+-- Name: idx_work_type_status_pub_date_desc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_work_type_status_pub_date_desc ON public.work USING btree (work_type, work_status, publication_date DESC);
+
+
+--
+-- Name: idx_work_updated_at_with_relations_desc; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX idx_work_updated_at_with_relations_desc ON public.work USING btree (updated_at_with_relations DESC, work_id);
+
+
+--
+-- Name: imprint_uniq_idx; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX imprint_uniq_idx ON public.imprint USING btree (lower(imprint_name));
+
+
+--
+-- Name: institution_doi_uniq_idx; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX institution_doi_uniq_idx ON public.institution USING btree (lower(institution_doi));
+
+
+--
+-- Name: issue_uniq_ord_in_series_idx; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX issue_uniq_ord_in_series_idx ON public.issue USING btree (series_id, issue_ordinal);
+
+
+--
+-- Name: language_uniq_work_idx; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX language_uniq_work_idx ON public.language USING btree (work_id, language_code);
+
+
+--
+-- Name: location_uniq_canonical_true_idx; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX location_uniq_canonical_true_idx ON public.location USING btree (publication_id) WHERE canonical;
+
+
+--
+-- Name: location_uniq_platform_idx; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX location_uniq_platform_idx ON public.location USING btree (publication_id, location_platform) WHERE (NOT (location_platform = 'Other'::public.location_platform));
+
+
+--
+-- Name: orcid_uniq_idx; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX orcid_uniq_idx ON public.contributor USING btree (lower(orcid));
+
+
+--
+-- Name: publication_isbn_idx; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX publication_isbn_idx ON public.publication USING btree (isbn);
+
+
+--
+-- Name: publisher_uniq_idx; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX publisher_uniq_idx ON public.publisher USING btree (lower(publisher_name));
+
+
+--
+-- Name: series_issn_digital_idx; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX series_issn_digital_idx ON public.series USING btree (issn_digital);
+
+
+--
+-- Name: series_issn_print_idx; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX series_issn_print_idx ON public.series USING btree (issn_print);
+
+
+--
+-- Name: publication publication_chapter_no_dimensions_check; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER publication_chapter_no_dimensions_check BEFORE INSERT OR UPDATE ON public.publication FOR EACH ROW EXECUTE FUNCTION public.publication_chapter_no_dimensions();
+
+
+--
+-- Name: publication publication_location_canonical_urls_check; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER publication_location_canonical_urls_check BEFORE UPDATE ON public.publication FOR EACH ROW EXECUTE FUNCTION public.publication_location_canonical_urls();
+
+
+--
+-- Name: account set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.account FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: affiliation set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.affiliation FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: contribution set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.contribution FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: contributor set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.contributor FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: funding set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.funding FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: imprint set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.imprint FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: institution set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.institution FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: issue set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.issue FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: language set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.language FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: location set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.location FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: price set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.price FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: publication set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.publication FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: publisher set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.publisher FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: publisher_account set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.publisher_account FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: reference set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.reference FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: series set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.series FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: subject set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.subject FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: work set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.work FOR EACH ROW EXECUTE FUNCTION public.work_set_updated_at();
+
+
+--
+-- Name: work_relation set_updated_at; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.work_relation FOR EACH ROW EXECUTE FUNCTION public.diesel_set_updated_at();
+
+
+--
+-- Name: affiliation set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.affiliation FOR EACH ROW EXECUTE FUNCTION public.affiliation_work_updated_at_with_relations();
+
+
+--
+-- Name: contribution set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.contribution FOR EACH ROW EXECUTE FUNCTION public.work_updated_at_with_relations();
+
+
+--
+-- Name: contributor set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER UPDATE ON public.contributor FOR EACH ROW EXECUTE FUNCTION public.contributor_work_updated_at_with_relations();
+
+
+--
+-- Name: funding set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.funding FOR EACH ROW EXECUTE FUNCTION public.work_updated_at_with_relations();
+
+
+--
+-- Name: imprint set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER UPDATE ON public.imprint FOR EACH ROW EXECUTE FUNCTION public.imprint_work_updated_at_with_relations();
+
+
+--
+-- Name: institution set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER UPDATE ON public.institution FOR EACH ROW EXECUTE FUNCTION public.institution_work_updated_at_with_relations();
+
+
+--
+-- Name: issue set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.issue FOR EACH ROW EXECUTE FUNCTION public.work_updated_at_with_relations();
+
+
+--
+-- Name: language set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.language FOR EACH ROW EXECUTE FUNCTION public.work_updated_at_with_relations();
+
+
+--
+-- Name: location set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.location FOR EACH ROW EXECUTE FUNCTION public.location_work_updated_at_with_relations();
+
+
+--
+-- Name: price set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.price FOR EACH ROW EXECUTE FUNCTION public.price_work_updated_at_with_relations();
+
+
+--
+-- Name: publication set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.publication FOR EACH ROW EXECUTE FUNCTION public.work_updated_at_with_relations();
+
+
+--
+-- Name: publisher set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER UPDATE ON public.publisher FOR EACH ROW EXECUTE FUNCTION public.publisher_work_updated_at_with_relations();
+
+
+--
+-- Name: reference set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.reference FOR EACH ROW EXECUTE FUNCTION public.work_updated_at_with_relations();
+
+
+--
+-- Name: series set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER UPDATE ON public.series FOR EACH ROW EXECUTE FUNCTION public.series_work_updated_at_with_relations();
+
+
+--
+-- Name: subject set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.subject FOR EACH ROW EXECUTE FUNCTION public.work_updated_at_with_relations();
+
+
+--
+-- Name: work set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER UPDATE ON public.work FOR EACH ROW EXECUTE FUNCTION public.work_work_updated_at_with_relations();
+
+
+--
+-- Name: work_relation set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.work_relation FOR EACH ROW EXECUTE FUNCTION public.work_relation_work_updated_at_with_relations();
+
+
+--
+-- Name: affiliation affiliation_contribution_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.affiliation
+ ADD CONSTRAINT affiliation_contribution_id_fkey FOREIGN KEY (contribution_id) REFERENCES public.contribution(contribution_id) ON DELETE CASCADE;
+
+
+--
+-- Name: affiliation_history affiliation_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.affiliation_history
+ ADD CONSTRAINT affiliation_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: affiliation_history affiliation_history_affiliation_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.affiliation_history
+ ADD CONSTRAINT affiliation_history_affiliation_id_fkey FOREIGN KEY (affiliation_id) REFERENCES public.affiliation(affiliation_id) ON DELETE CASCADE;
+
+
+--
+-- Name: affiliation affiliation_institution_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.affiliation
+ ADD CONSTRAINT affiliation_institution_id_fkey FOREIGN KEY (institution_id) REFERENCES public.institution(institution_id) ON DELETE CASCADE;
+
+
+--
+-- Name: contribution contribution_contributor_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.contribution
+ ADD CONSTRAINT contribution_contributor_id_fkey FOREIGN KEY (contributor_id) REFERENCES public.contributor(contributor_id) ON DELETE CASCADE;
+
+
+--
+-- Name: contribution_history contribution_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.contribution_history
+ ADD CONSTRAINT contribution_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: contribution_history contribution_history_contribution_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.contribution_history
+ ADD CONSTRAINT contribution_history_contribution_id_fkey FOREIGN KEY (contribution_id) REFERENCES public.contribution(contribution_id) ON DELETE CASCADE;
+
+
+--
+-- Name: contribution contribution_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.contribution
+ ADD CONSTRAINT contribution_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.work(work_id) ON DELETE CASCADE;
+
+
+--
+-- Name: contributor_history contributor_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.contributor_history
+ ADD CONSTRAINT contributor_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: contributor_history contributor_history_contributor_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.contributor_history
+ ADD CONSTRAINT contributor_history_contributor_id_fkey FOREIGN KEY (contributor_id) REFERENCES public.contributor(contributor_id) ON DELETE CASCADE;
+
+
+--
+-- Name: institution_history funder_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.institution_history
+ ADD CONSTRAINT funder_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: institution_history funder_history_funder_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.institution_history
+ ADD CONSTRAINT funder_history_funder_id_fkey FOREIGN KEY (institution_id) REFERENCES public.institution(institution_id) ON DELETE CASCADE;
+
+
+--
+-- Name: funding funding_funder_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.funding
+ ADD CONSTRAINT funding_funder_id_fkey FOREIGN KEY (institution_id) REFERENCES public.institution(institution_id) ON DELETE CASCADE;
+
+
+--
+-- Name: funding_history funding_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.funding_history
+ ADD CONSTRAINT funding_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: funding_history funding_history_funding_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.funding_history
+ ADD CONSTRAINT funding_history_funding_id_fkey FOREIGN KEY (funding_id) REFERENCES public.funding(funding_id) ON DELETE CASCADE;
+
+
+--
+-- Name: funding funding_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.funding
+ ADD CONSTRAINT funding_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.work(work_id) ON DELETE CASCADE;
+
+
+--
+-- Name: imprint_history imprint_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.imprint_history
+ ADD CONSTRAINT imprint_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: imprint_history imprint_history_imprint_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.imprint_history
+ ADD CONSTRAINT imprint_history_imprint_id_fkey FOREIGN KEY (imprint_id) REFERENCES public.imprint(imprint_id) ON DELETE CASCADE;
+
+
+--
+-- Name: imprint imprint_publisher_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.imprint
+ ADD CONSTRAINT imprint_publisher_id_fkey FOREIGN KEY (publisher_id) REFERENCES public.publisher(publisher_id) ON DELETE CASCADE;
+
+
+--
+-- Name: issue_history issue_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.issue_history
+ ADD CONSTRAINT issue_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: issue_history issue_history_issue_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.issue_history
+ ADD CONSTRAINT issue_history_issue_id_fkey FOREIGN KEY (issue_id) REFERENCES public.issue(issue_id) ON DELETE CASCADE;
+
+
+--
+-- Name: issue issue_series_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.issue
+ ADD CONSTRAINT issue_series_id_fkey FOREIGN KEY (series_id) REFERENCES public.series(series_id) ON DELETE CASCADE;
+
+
+--
+-- Name: issue issue_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.issue
+ ADD CONSTRAINT issue_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.work(work_id) ON DELETE CASCADE;
+
+
+--
+-- Name: language_history language_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.language_history
+ ADD CONSTRAINT language_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: language_history language_history_language_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.language_history
+ ADD CONSTRAINT language_history_language_id_fkey FOREIGN KEY (language_id) REFERENCES public.language(language_id) ON DELETE CASCADE;
+
+
+--
+-- Name: language language_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.language
+ ADD CONSTRAINT language_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.work(work_id) ON DELETE CASCADE;
+
+
+--
+-- Name: location_history location_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.location_history
+ ADD CONSTRAINT location_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: location_history location_history_location_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.location_history
+ ADD CONSTRAINT location_history_location_id_fkey FOREIGN KEY (location_id) REFERENCES public.location(location_id) ON DELETE CASCADE;
+
+
+--
+-- Name: location location_publication_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.location
+ ADD CONSTRAINT location_publication_id_fkey FOREIGN KEY (publication_id) REFERENCES public.publication(publication_id) ON DELETE CASCADE;
+
+
+--
+-- Name: price_history price_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.price_history
+ ADD CONSTRAINT price_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: price_history price_history_price_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.price_history
+ ADD CONSTRAINT price_history_price_id_fkey FOREIGN KEY (price_id) REFERENCES public.price(price_id) ON DELETE CASCADE;
+
+
+--
+-- Name: price price_publication_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.price
+ ADD CONSTRAINT price_publication_id_fkey FOREIGN KEY (publication_id) REFERENCES public.publication(publication_id) ON DELETE CASCADE;
+
+
+--
+-- Name: publication_history publication_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.publication_history
+ ADD CONSTRAINT publication_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: publication_history publication_history_publication_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.publication_history
+ ADD CONSTRAINT publication_history_publication_id_fkey FOREIGN KEY (publication_id) REFERENCES public.publication(publication_id) ON DELETE CASCADE;
+
+
+--
+-- Name: publication publication_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.publication
+ ADD CONSTRAINT publication_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.work(work_id) ON DELETE CASCADE;
+
+
+--
+-- Name: publisher_account publisher_account_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.publisher_account
+ ADD CONSTRAINT publisher_account_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id) ON DELETE CASCADE;
+
+
+--
+-- Name: publisher_account publisher_account_publisher_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.publisher_account
+ ADD CONSTRAINT publisher_account_publisher_id_fkey FOREIGN KEY (publisher_id) REFERENCES public.publisher(publisher_id) ON DELETE CASCADE;
+
+
+--
+-- Name: publisher_history publisher_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.publisher_history
+ ADD CONSTRAINT publisher_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: publisher_history publisher_history_publisher_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.publisher_history
+ ADD CONSTRAINT publisher_history_publisher_id_fkey FOREIGN KEY (publisher_id) REFERENCES public.publisher(publisher_id) ON DELETE CASCADE;
+
+
+--
+-- Name: reference_history reference_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.reference_history
+ ADD CONSTRAINT reference_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: reference_history reference_history_reference_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.reference_history
+ ADD CONSTRAINT reference_history_reference_id_fkey FOREIGN KEY (reference_id) REFERENCES public.reference(reference_id) ON DELETE CASCADE;
+
+
+--
+-- Name: reference reference_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.reference
+ ADD CONSTRAINT reference_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.work(work_id) ON DELETE CASCADE;
+
+
+--
+-- Name: series_history series_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.series_history
+ ADD CONSTRAINT series_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: series_history series_history_series_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.series_history
+ ADD CONSTRAINT series_history_series_id_fkey FOREIGN KEY (series_id) REFERENCES public.series(series_id) ON DELETE CASCADE;
+
+
+--
+-- Name: series series_imprint_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.series
+ ADD CONSTRAINT series_imprint_id_fkey FOREIGN KEY (imprint_id) REFERENCES public.imprint(imprint_id) ON DELETE CASCADE;
+
+
+--
+-- Name: subject_history subject_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.subject_history
+ ADD CONSTRAINT subject_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: subject_history subject_history_subject_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.subject_history
+ ADD CONSTRAINT subject_history_subject_id_fkey FOREIGN KEY (subject_id) REFERENCES public.subject(subject_id) ON DELETE CASCADE;
+
+
+--
+-- Name: subject subject_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.subject
+ ADD CONSTRAINT subject_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.work(work_id) ON DELETE CASCADE;
+
+
+--
+-- Name: work_history work_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.work_history
+ ADD CONSTRAINT work_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: work_history work_history_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.work_history
+ ADD CONSTRAINT work_history_work_id_fkey FOREIGN KEY (work_id) REFERENCES public.work(work_id) ON DELETE CASCADE;
+
+
+--
+-- Name: work work_imprint_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.work
+ ADD CONSTRAINT work_imprint_id_fkey FOREIGN KEY (imprint_id) REFERENCES public.imprint(imprint_id) ON DELETE CASCADE;
+
+
+--
+-- Name: work_relation work_relation_active_passive_pair; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.work_relation
+ ADD CONSTRAINT work_relation_active_passive_pair FOREIGN KEY (relator_work_id, related_work_id) REFERENCES public.work_relation(related_work_id, relator_work_id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: work_relation_history work_relation_history_account_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.work_relation_history
+ ADD CONSTRAINT work_relation_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES public.account(account_id);
+
+
+--
+-- Name: work_relation_history work_relation_history_work_relation_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.work_relation_history
+ ADD CONSTRAINT work_relation_history_work_relation_id_fkey FOREIGN KEY (work_relation_id) REFERENCES public.work_relation(work_relation_id) ON DELETE CASCADE;
+
+
+--
+-- Name: work_relation work_relation_related_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.work_relation
+ ADD CONSTRAINT work_relation_related_work_id_fkey FOREIGN KEY (related_work_id) REFERENCES public.work(work_id) ON DELETE CASCADE;
+
+
+--
+-- Name: work_relation work_relation_relator_work_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.work_relation
+ ADD CONSTRAINT work_relation_relator_work_id_fkey FOREIGN KEY (relator_work_id) REFERENCES public.work(work_id) ON DELETE CASCADE;
+
diff --git a/thoth-api/migrations/20251203_v1.0.0/down.sql b/thoth-api/migrations/20251203_v1.0.0/down.sql
new file mode 100644
index 00000000..0c80e7a0
--- /dev/null
+++ b/thoth-api/migrations/20251203_v1.0.0/down.sql
@@ -0,0 +1,55 @@
+-------------------------------------------------------------------------------
+-- 1. Drop the current deterministic work_relation_work_updated_at_with_relations
+-- and its trigger
+-------------------------------------------------------------------------------
+
+DROP TRIGGER IF EXISTS set_work_relation_updated_at_with_relations ON work_relation;
+DROP FUNCTION IF EXISTS work_relation_work_updated_at_with_relations() CASCADE;
+
+-------------------------------------------------------------------------------
+-- 2. Restore the previous work_relation_work_updated_at_with_relations()
+-- that bumps all involved works whenever a relation row changes
+-------------------------------------------------------------------------------
+
+CREATE OR REPLACE FUNCTION work_relation_work_updated_at_with_relations() RETURNS trigger AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ WHERE work_id = OLD.relator_work_id OR work_id = NEW.relator_work_id
+ OR work_id = OLD.related_work_id OR work_id = NEW.related_work_id;
+ END IF;
+ RETURN NULL;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR UPDATE OR DELETE ON work_relation
+ FOR EACH ROW EXECUTE PROCEDURE work_relation_work_updated_at_with_relations();
+
+-------------------------------------------------------------------------------
+-- 3. Restore work_work_updated_at_with_relations() and its trigger on work
+-------------------------------------------------------------------------------
+
+CREATE OR REPLACE FUNCTION work_work_updated_at_with_relations() RETURNS trigger AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ FROM work_relation
+ -- The positions of relator/related IDs in this statement don't matter, as
+ -- every work_relation record has a mirrored record with relator/related IDs swapped
+ WHERE work.work_id = work_relation.relator_work_id AND work_relation.related_work_id = NEW.work_id;
+ END IF;
+ RETURN NULL;
+END;
+$$ LANGUAGE plpgsql;
+
+DROP TRIGGER IF EXISTS set_work_updated_at_with_relations ON work;
+
+CREATE TRIGGER set_work_updated_at_with_relations
+ AFTER UPDATE ON work
+ FOR EACH ROW EXECUTE PROCEDURE work_work_updated_at_with_relations();
diff --git a/thoth-api/migrations/20251203_v1.0.0/up.sql b/thoth-api/migrations/20251203_v1.0.0/up.sql
new file mode 100644
index 00000000..d08ed037
--- /dev/null
+++ b/thoth-api/migrations/20251203_v1.0.0/up.sql
@@ -0,0 +1,52 @@
+-------------------------------------------------------------------------------
+-- 1. Remove the helper function, and associated triggers, that propagates
+-- from work -> related works
+-------------------------------------------------------------------------------
+
+DROP FUNCTION IF EXISTS work_work_updated_at_with_relations() CASCADE;
+
+-------------------------------------------------------------------------------
+-- 2. Redefine work_relation_work_updated_at_with_relations() to update the
+-- two endpoint works in deterministic order (LEAST/ GREATEST).
+-------------------------------------------------------------------------------
+
+DROP FUNCTION IF EXISTS work_relation_work_updated_at_with_relations() CASCADE;
+
+CREATE OR REPLACE FUNCTION work_relation_work_updated_at_with_relations()
+ RETURNS trigger AS $$
+DECLARE
+ w1 uuid; -- smaller work_id
+ w2 uuid; -- larger work_id
+BEGIN
+ -- If nothing really changed, skip
+ IF NEW IS NOT DISTINCT FROM OLD THEN
+ RETURN NULL;
+ END IF;
+
+ -- Determine the two work IDs involved in this relation
+ IF TG_OP = 'DELETE' THEN
+ w1 := LEAST(OLD.relator_work_id, OLD.related_work_id);
+ w2 := GREATEST(OLD.relator_work_id, OLD.related_work_id);
+ ELSE
+ w1 := LEAST(NEW.relator_work_id, NEW.related_work_id);
+ w2 := GREATEST(NEW.relator_work_id, NEW.related_work_id);
+ END IF;
+
+ -- Always lock/update in deterministic order: smaller ID first, then larger
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ WHERE work_id = w1;
+
+ IF w2 IS DISTINCT FROM w1 THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ WHERE work_id = w2;
+ END IF;
+
+ RETURN NULL;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE TRIGGER set_work_relation_updated_at_with_relations
+ AFTER INSERT OR UPDATE OR DELETE ON work_relation
+ FOR EACH ROW EXECUTE PROCEDURE work_relation_work_updated_at_with_relations();
diff --git a/thoth-api/migrations/20251204_v1.0.0/down.sql b/thoth-api/migrations/20251204_v1.0.0/down.sql
new file mode 100644
index 00000000..a34cab43
--- /dev/null
+++ b/thoth-api/migrations/20251204_v1.0.0/down.sql
@@ -0,0 +1,24 @@
+ALTER TABLE affiliation
+ DROP CONSTRAINT affiliation_affiliation_ordinal_contribution_id_uniq;
+
+CREATE UNIQUE INDEX affiliation_uniq_ord_in_contribution_idx ON affiliation(contribution_id, affiliation_ordinal);
+
+ALTER TABLE contribution
+ DROP CONSTRAINT contribution_contribution_ordinal_work_id_uniq,
+ ADD CONSTRAINT contribution_contribution_ordinal_work_id_uniq UNIQUE (contribution_ordinal, work_id);
+
+ALTER TABLE issue
+ DROP CONSTRAINT issue_issue_ordinal_series_id_uniq;
+
+CREATE UNIQUE INDEX issue_uniq_ord_in_series_idx ON issue(series_id, issue_ordinal);
+
+ALTER TABLE reference
+ DROP CONSTRAINT reference_reference_ordinal_work_id_uniq,
+ ADD CONSTRAINT reference_reference_ordinal_work_id_uniq UNIQUE (work_id, reference_ordinal);
+
+ALTER TABLE subject
+ DROP CONSTRAINT subject_ordinal_type_uniq;
+
+ALTER TABLE work_relation
+ DROP CONSTRAINT work_relation_ordinal_type_uniq,
+ ADD CONSTRAINT work_relation_ordinal_type_uniq UNIQUE (relation_ordinal, relator_work_id, relation_type);
diff --git a/thoth-api/migrations/20251204_v1.0.0/up.sql b/thoth-api/migrations/20251204_v1.0.0/up.sql
new file mode 100644
index 00000000..6ab14fde
--- /dev/null
+++ b/thoth-api/migrations/20251204_v1.0.0/up.sql
@@ -0,0 +1,43 @@
+ALTER TABLE affiliation
+ ADD CONSTRAINT affiliation_affiliation_ordinal_contribution_id_uniq UNIQUE (contribution_id, affiliation_ordinal) DEFERRABLE INITIALLY IMMEDIATE;
+
+DROP INDEX IF EXISTS affiliation_uniq_ord_in_contribution_idx;
+
+ALTER TABLE contribution
+ DROP CONSTRAINT contribution_contribution_ordinal_work_id_uniq,
+ ADD CONSTRAINT contribution_contribution_ordinal_work_id_uniq UNIQUE (work_id, contribution_ordinal) DEFERRABLE INITIALLY IMMEDIATE;
+
+ALTER TABLE issue
+ ADD CONSTRAINT issue_issue_ordinal_series_id_uniq UNIQUE (series_id, issue_ordinal) DEFERRABLE INITIALLY IMMEDIATE;
+
+DROP INDEX IF EXISTS issue_uniq_ord_in_series_idx;
+
+ALTER TABLE reference
+ DROP CONSTRAINT reference_reference_ordinal_work_id_uniq,
+ ADD CONSTRAINT reference_reference_ordinal_work_id_uniq UNIQUE (work_id, reference_ordinal) DEFERRABLE INITIALLY IMMEDIATE;
+
+-- There were previously no database constraints on subject ordinals, so multiple subjects
+-- of the same type could have the same ordinal. We want to enforce a stricter hierarchy,
+-- which requires renumbering existing duplicates. Keep existing ordering where ordinals
+-- are distinctive, otherwise renumber them based on the order in which they were created.
+-- Note that records created prior to the introduction of `created_at` in v0.2.11 may have
+-- identical default values for the creation timestamp. Therefore, we perform a backup
+-- sort on the system column `ctid`; although this value is subject to change and
+-- should not be relied upon, it should give a suitable rough ordering here.
+-- !!! This is irreversible
+UPDATE subject
+ SET subject_ordinal = s.rownum
+ FROM (
+ SELECT
+ subject_id,
+ row_number() OVER (PARTITION BY work_id,subject_type ORDER BY subject_ordinal,created_at,ctid) AS rownum
+ FROM subject
+ ) s
+ WHERE subject.subject_id = s.subject_id;
+
+ALTER TABLE subject
+ ADD CONSTRAINT subject_ordinal_type_uniq UNIQUE (work_id, subject_ordinal, subject_type) DEFERRABLE INITIALLY IMMEDIATE;
+
+ALTER TABLE work_relation
+ DROP CONSTRAINT work_relation_ordinal_type_uniq,
+ ADD CONSTRAINT work_relation_ordinal_type_uniq UNIQUE (relator_work_id, relation_ordinal, relation_type) DEFERRABLE INITIALLY IMMEDIATE;
diff --git a/thoth-api/migrations/20251205_v1.0.0/down.sql b/thoth-api/migrations/20251205_v1.0.0/down.sql
new file mode 100644
index 00000000..1be09582
--- /dev/null
+++ b/thoth-api/migrations/20251205_v1.0.0/down.sql
@@ -0,0 +1,141 @@
+-- Add title-related columns back to the work table
+ALTER TABLE work
+ ADD COLUMN full_title TEXT CHECK (octet_length(full_title) >= 1),
+ ADD COLUMN title TEXT CHECK (octet_length(title) >= 1),
+ ADD COLUMN subtitle TEXT CHECK (octet_length(subtitle) >= 1);
+
+-- Migrate data back from title table to work table
+UPDATE work w
+SET
+ full_title = regexp_replace(t.full_title, '^(.*) $', '\\1'),
+ title = regexp_replace(t.title, '^(.*) $', '\\1'),
+ subtitle = CASE WHEN t.subtitle IS NOT NULL THEN regexp_replace(t.subtitle, '^(.*) $', '\\1') ELSE NULL END
+FROM title t
+WHERE w.work_id = t.work_id
+ AND t.canonical = TRUE;
+
+-- Drop the unique index for canonical titles
+DROP INDEX IF EXISTS title_uniq_locale_idx;
+-- Drop the unique index for locale codes
+DROP INDEX IF EXISTS title_unique_canonical_true_idx;
+
+-- Drop the title_history table
+DROP TABLE title_history;
+
+-- Drop the title table
+DROP TABLE title;
+
+-- Recreate short_abstract and long_abstract columns in the work table
+ALTER TABLE work
+ ADD COLUMN short_abstract TEXT CHECK (octet_length(short_abstract) >= 1),
+ ADD COLUMN long_abstract TEXT CHECK (octet_length(long_abstract) >= 1);
+
+-- -----------------------------------------------------------------------------
+-- Reverse Conversion Function
+-- -----------------------------------------------------------------------------
+-- This function attempts to convert a JATS XML string back into a format that
+-- resembles the original plaintext or Markdown. This is the reverse of the
+-- `convert_to_jats` function from the `up` migration.
+--
+-- NOTE: This is a best-effort reversal. The primary goal is to make the data
+-- readable and usable, not to restore the original format with 100% fidelity.
+-- -----------------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION convert_from_jats(jats_in TEXT)
+RETURNS TEXT AS $$
+DECLARE
+ processed_content TEXT := jats_in;
+BEGIN
+ -- Return NULL immediately if input is NULL or empty.
+ IF processed_content IS NULL OR processed_content = '' THEN
+ RETURN NULL;
+ END IF;
+
+ -- The order of replacements is important to handle nested tags correctly.
+
+ -- Convert JATS tags back to a Markdown-like format.
+ processed_content := regexp_replace(processed_content, '([^<]+) ', '[\2](\1)', 'gi');
+ processed_content := regexp_replace(processed_content, '([^<]+) ', '**\1**', 'gi');
+ processed_content := regexp_replace(processed_content, '([^<]+) ', '*\1*', 'gi');
+ processed_content := regexp_replace(processed_content, '([^<]+) ', '`\1`', 'gi');
+ processed_content := regexp_replace(processed_content, '([^<]+) ', '\1', 'gi'); -- Revert small-caps to original text
+ processed_content := regexp_replace(processed_content, ']*>([^<]+) ', '^\1^', 'gi'); -- A possible representation for superscript
+ processed_content := regexp_replace(processed_content, ']*>([^<]+) ', '~\1~', 'gi'); -- A possible representation for subscript
+ processed_content := regexp_replace(processed_content, ' ', E'\n', 'gi');
+
+ -- Remove paragraph tags and handle the spacing.
+ -- Replace closing tags with double newlines to separate paragraphs.
+ processed_content := regexp_replace(processed_content, '
', E'\n\n', 'gi');
+ -- Strip any remaining opening paragraph tags.
+ processed_content := regexp_replace(processed_content, '', '', 'gi');
+
+ -- Clean up any leftover simple HTML tags that were not converted.
+ processed_content := regexp_replace(processed_content, '<[^>]+>', '', 'g');
+
+ -- Trim leading/trailing whitespace that may result from tag removal.
+ processed_content := trim(processed_content);
+
+ RETURN processed_content;
+END;
+$$ LANGUAGE plpgsql;
+
+
+-- Migrate data back from the abstract table to the work table using the reverse conversion
+UPDATE work
+SET
+ short_abstract = convert_from_jats(abstract.content)
+FROM
+ abstract
+WHERE
+ abstract.work_id = work.work_id
+ AND abstract.abstract_type = 'short'
+ AND abstract.canonical = TRUE;
+
+UPDATE work
+SET
+ long_abstract = convert_from_jats(abstract.content)
+FROM
+ abstract
+WHERE
+ abstract.work_id = work.work_id
+ AND abstract.abstract_type = 'long'
+ AND abstract.canonical = TRUE;
+
+-- Drop unique indexes created for the abstract table
+DROP INDEX IF EXISTS abstract_unique_canonical_true_idx;
+DROP INDEX IF EXISTS abstract_uniq_locale_idx;
+
+-- Drop the abstract_history table
+DROP TABLE abstract_history;
+-- Drop the abstract table and its related objects
+DROP TABLE IF EXISTS abstract;
+
+-- Drop the AbstractType enum
+DROP TYPE IF EXISTS abstract_type;
+
+ALTER TABLE contribution
+ ADD COLUMN biography TEXT CHECK (octet_length(biography) >= 1);
+
+-- Migrate data back from the abstract table to the work table using the reverse conversion
+UPDATE contribution
+SET
+ biography = convert_from_jats(biography.content)
+FROM
+ biography
+WHERE
+ biography.contribution_id = contribution.contribution_id
+ AND biography.canonical = TRUE;
+
+-- Drop unique indexes created for the biography table
+DROP INDEX IF EXISTS biography_unique_canonical_true_idx;
+DROP INDEX IF EXISTS biography_uniq_locale_idx;
+
+-- Drop the biography_history table
+DROP TABLE biography_history;
+-- Drop the biography table and its related objects
+DROP TABLE IF EXISTS biography;
+
+-- Drop the locale_code enum type
+DROP TYPE locale_code;
+
+-- Clean up the reverse conversion function
+DROP FUNCTION convert_from_jats(TEXT);
\ No newline at end of file
diff --git a/thoth-api/migrations/20251205_v1.0.0/up.sql b/thoth-api/migrations/20251205_v1.0.0/up.sql
new file mode 100644
index 00000000..7ba9df84
--- /dev/null
+++ b/thoth-api/migrations/20251205_v1.0.0/up.sql
@@ -0,0 +1,390 @@
+-- Enable UUID extension
+CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
+
+-- Create locale enum type
+CREATE TYPE locale_code AS ENUM (
+ 'af', 'af_na', 'af_za', 'agq', 'agq_cm', 'ak', 'ak_gh', 'sq', 'sq_al', 'am', 'am_et', 'aig',
+ 'ar', 'ar_dz', 'ar_bh', 'ar_eg', 'ar_iq', 'ar_jo', 'ar_kw', 'ar_lb', 'ar_ly', 'ar_ma', 'ar_om',
+ 'ar_qa', 'ar_sa', 'ar_sd', 'ar_sy', 'ar_tn', 'ar_ae', 'ar_001', 'ar_ye', 'hy', 'hy_am', 'as',
+ 'as_in', 'ast', 'ast_es', 'asa', 'asa_tz', 'az', 'az_cyrl', 'az_cyrl_az', 'az_latn',
+ 'az_latn_az', 'ksf', 'ksf_cm', 'bah', 'bm', 'bm_ml', 'bas', 'bas_cm', 'eu', 'eu_es', 'be', 'be_by',
+ 'bem', 'bem_zm', 'bez', 'bez_tz', 'bn', 'bn_bd', 'bn_in', 'brx', 'brx_in', 'bs', 'bs_ba', 'br',
+ 'br_fr', 'bg', 'bg_bg', 'my', 'my_mm', 'ca', 'ca_es', 'ckb', 'kmr', 'sdh', 'tzm', 'tzm_latn',
+ 'tzm_latn_ma', 'chr', 'chr_us', 'cgg', 'cgg_ug', 'zh', 'zh_hans', 'zh_cn', 'zh_hans_cn',
+ 'zh_hans_hk', 'zh_hans_mo', 'zh_hans_sg', 'zh_hant', 'zh_hant_hk', 'zh_hant_mo', 'zh_hant_tw',
+ 'swc', 'swc_cd', 'kw', 'kw_gb', 'hr', 'hr_hr', 'cs', 'cs_cz', 'da', 'da_dk', 'dua', 'dua_cm',
+ 'dv', 'nl', 'nl_aw', 'nl_be', 'nl_cw', 'nl_nl', 'nl_sx', 'ebu', 'ebu_ke', 'en', 'en_ai',
+ 'en_as', 'en_au', 'en_at', 'en_bb', 'en_be', 'en_bz', 'en_bm', 'en_bw', 'en_io', 'en_bi', 'en_cm',
+ 'en_ca', 'en_ky', 'en_cx', 'en_cc', 'en_ck', 'en_cy', 'en_dk', 'en_dg', 'en_dm', 'en_eg', 'en_er',
+ 'en_eu', 'en_fk', 'en_fj', 'en_fi', 'en_gm', 'en_de', 'en_gh', 'en_gi', 'en_gd', 'en_gu', 'en_gg',
+ 'en_gy', 'en_hk', 'en_in', 'en_ie', 'en_im', 'en_il', 'en_jm', 'en_je', 'en_ke', 'en_ki', 'en_kw',
+ 'en_ls', 'en_mo', 'en_mg', 'en_mw', 'en_my', 'en_mt', 'en_mh', 'en_mu', 'en_fm', 'en_ms', 'en_na',
+ 'en_nr', 'en_nl', 'en_nz', 'en_ng', 'en_nu', 'en_nf', 'en_mp', 'en_no', 'en_pa', 'en_pk', 'en_pw',
+ 'en_pg', 'en_ph', 'en_pn', 'en_pr', 'en_rw', 'en_ws', 'en_sa', 'en_sc', 'en_sl', 'en_sg', 'en_sx',
+ 'en_si', 'en_sb', 'en_ss', 'en_sh', 'en_kn', 'en_lc', 'svc', 'vic', 'en_sd', 'en_sz', 'en_se',
+ 'en_ch', 'en_tz', 'en_tk', 'en_to', 'en_tt', 'en_tv', 'en_za', 'en_ae', 'en_um', 'en_vi',
+ 'en_us_posix', 'en_ug', 'en_gb', 'en_us', 'en_vu', 'en_zm', 'en_zw', 'eo', 'et', 'et_ee',
+ 'ee', 'ee_gh', 'ee_tg', 'ewo', 'ewo_cm', 'fo', 'fo_fo', 'fil', 'fil_ph', 'fi', 'fi_fi', 'fr',
+ 'fr_be', 'fr_bj', 'fr_bf', 'fr_bi', 'fr_cm', 'fr_ca', 'fr_cf', 'fr_td', 'fr_km', 'fr_cg', 'fr_cd',
+ 'fr_ci', 'fr_dj', 'fr_gq', 'fr_fr', 'fr_gf', 'fr_ga', 'fr_gp', 'fr_gn', 'fr_lu', 'fr_mg', 'fr_ml',
+ 'fr_mq', 'fr_yt', 'fr_mc', 'fr_ne', 'fr_rw', 'fr_re', 'fr_bl', 'fr_mf', 'fr_mu', 'fr_sn', 'fr_ch',
+ 'fr_tg', 'ff', 'ff_sn', 'gl', 'gl_es', 'lao', 'lg', 'lg_ug', 'ka', 'ka_ge', 'de', 'de_at', 'de_be',
+ 'de_de', 'de_li', 'de_lu', 'de_ch', 'el', 'el_cy', 'el_gr', 'gu', 'gu_in', 'guz', 'guz_ke', 'ha',
+ 'ha_latn', 'ha_latn_gh', 'ha_latn_ne', 'ha_latn_ng', 'haw', 'haw_us', 'he', 'he_il', 'hi', 'hi_in',
+ 'hu', 'hu_hu', 'is', 'is_is', 'ig', 'ig_ng', 'smn', 'smn_fi', 'id', 'id_id', 'ga', 'ga_ie', 'it',
+ 'it_it', 'it_ch', 'ja', 'ja_jp', 'dyo', 'dyo_sn', 'kea', 'kea_cv', 'kab', 'kab_dz', 'kl', 'kl_gl',
+ 'kln', 'kln_ke', 'kam', 'kam_ke', 'kn', 'kn_in', 'kaa', 'kk', 'kk_cyrl', 'kk_cyrl_kz', 'km', 'km_kh',
+ 'ki', 'ki_ke', 'rw', 'rw_rw', 'kok', 'kok_in', 'ko', 'ko_kr', 'khq', 'khq_ml', 'ses', 'ses_ml', 'nmg',
+ 'nmg_cm', 'ky', 'lag', 'lag_tz', 'lv', 'lv_lv', 'lir', 'ln', 'ln_cg', 'ln_cd', 'lt', 'lt_lt', 'lu',
+ 'lu_cd', 'luo', 'luo_ke', 'luy', 'luy_ke', 'mk', 'mk_mk', 'jmc', 'jmc_tz', 'mgh', 'mgh_mz', 'kde',
+ 'kde_tz', 'mg', 'mg_mg', 'ms', 'ms_bn', 'ms_my', 'ml', 'ml_in', 'mt', 'mt_mt', 'gv', 'gv_gb', 'mr',
+ 'mr_in', 'mas', 'mas_ke', 'mas_tz', 'mer', 'mer_ke', 'mn', 'mfe', 'mfe_mu', 'mua', 'mua_cm', 'naq',
+ 'naq_na', 'ne', 'ne_in', 'ne_np', 'se', 'se_fi', 'se_no', 'se_se', 'nd', 'nd_zw', 'nb', 'nb_no', 'nn',
+ 'nn_no', 'nus', 'nus_sd', 'nyn', 'nyn_ug', 'or', 'or_in', 'om', 'om_et', 'om_ke', 'ps', 'ps_af', 'fa',
+ 'fa_af', 'fa_ir', 'pl', 'pl_pl', 'pt', 'pt_ao', 'pt_br', 'pt_gw', 'pt_mz', 'pt_pt', 'pt_st', 'pa',
+ 'pa_arab', 'pa_arab_pk', 'pa_guru', 'pa_guru_in', 'ro', 'ro_md', 'ro_ro', 'rm', 'rm_ch', 'rof',
+ 'rof_tz', 'rn', 'rn_bi', 'ru', 'ru_md', 'ru_ru', 'ru_ua', 'rwk', 'rwk_tz', 'saq', 'saq_ke', 'sg',
+ 'sg_cf', 'sbp', 'sbp_tz', 'sa', 'gd', 'gd_gb', 'seh', 'seh_mz', 'sr', 'sr_cyrl', 'sr_cyrl_ba',
+ 'sr_cyrl_me', 'sr_cyrl_rs', 'sr_latn', 'sr_latn_ba', 'sr_latn_me', 'sr_latn_rs', 'ksb', 'ksb_tz',
+ 'sn', 'sn_zw', 'ii', 'ii_cn', 'si', 'si_lk', 'sk', 'sk_sk', 'sl', 'sl_si', 'xog', 'xog_ug', 'so',
+ 'so_dj', 'so_et', 'so_ke', 'so_so', 'es', 'es_ar', 'es_bo', 'es_cl', 'es_co', 'es_cr', 'es_do', 'es_ec',
+ 'es_sv', 'es_gq', 'es_gt', 'es_hn', 'es_419', 'es_mx', 'es_ni', 'es_pa', 'es_py', 'es_pe', 'es_pr',
+ 'es_es', 'es_us', 'es_uy', 'es_ve', 'sw', 'sw_ke', 'sw_tz', 'sv', 'sv_fi', 'sv_se', 'gsw', 'gsw_ch',
+ 'shi', 'shi_latn', 'shi_latn_ma', 'shi_tfng', 'shi_tfng_ma', 'dav', 'dav_ke', 'tg', 'ta', 'ta_in',
+ 'ta_lk', 'twq', 'twq_ne', 'mi', 'te', 'te_in', 'teo', 'teo_ke', 'teo_ug', 'th', 'th_th', 'bo', 'bo_cn',
+ 'bo_in', 'ti', 'ti_er', 'ti_et', 'to', 'to_to', 'tr', 'tk', 'tr_tr', 'tch', 'uk', 'uk_ua', 'ur', 'ur_in',
+ 'ur_pk', 'ug', 'ug_cn', 'uz', 'uz_arab', 'uz_arab_af', 'uz_cyrl', 'uz_cyrl_uz', 'uz_latn', 'uz_latn_uz',
+ 'vai', 'vai_latn', 'vai_latn_lr', 'vai_vaii', 'vai_vaii_lr', 'val', 'val_es', 'ca_es_valencia', 'vi',
+ 'vi_vn', 'vun', 'vun_tz', 'cy', 'cy_gb', 'wo', 'xh', 'yav', 'yav_cm', 'yo', 'yo_ng', 'dje', 'dje_ne',
+ 'zu', 'zu_za'
+);
+
+-- -----------------------------------------------------------------------------
+-- Conversion Function
+-- -----------------------------------------------------------------------------
+-- This function attempts to detect the format of the input text (HTML, Markdown,
+-- or Plaintext) and converts it into a basic JATS XML structure.
+-- NOTE: This function uses heuristics and regular expressions for conversion. It
+-- covers common cases but is not a full-fledged parser. It is designed to be
+-- sufficient for this one-time data migration.
+-- -----------------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION convert_to_jats(content_in TEXT)
+RETURNS TEXT AS $$
+DECLARE
+ processed_content TEXT := content_in;
+BEGIN
+ -- Return NULL immediately if input is NULL or empty.
+ IF processed_content IS NULL OR processed_content = '' THEN
+ RETURN NULL;
+ END IF;
+
+ -- The CASE statement detects the format and applies conversion rules.
+ CASE
+ -- A) HTML Detection: Looks for common HTML tags. Now includes .
+ WHEN processed_content ~* '<(p|em|i|strong|b|sup|sub|sc|code|a|br)\b' THEN
+ -- Convert HTML tags to their JATS equivalents.
+ processed_content := regexp_replace(processed_content, ']*>(.*?) ', '\2 ', 'gi');
+ processed_content := regexp_replace(processed_content, '<(strong|b)>(.*?)\1>', '\2 ', 'gi');
+ processed_content := regexp_replace(processed_content, '<(em|i)>(.*?)\1>', '\2 ', 'gi');
+ processed_content := regexp_replace(processed_content, '(.*?)', '\1 ', 'gi');
+ processed_content := regexp_replace(processed_content, ' ', ' ', 'gi');
+ -- , , and are valid in JATS, so they are left as is.
+
+ -- B) Markdown Detection: Looks for Markdown syntax like **, *, ``, etc.
+ WHEN processed_content ~ '(\*\*|__).+?\1' OR
+ processed_content ~ '(?\1', 'g');
+ processed_content := regexp_replace(processed_content, '\*\*(.+?)\*\*', '\1 ', 'g');
+ processed_content := regexp_replace(processed_content, '__(.+?)__', '\1 ', 'g');
+ processed_content := regexp_replace(processed_content, '\*(.+?)\*', '\1 ', 'g');
+ processed_content := regexp_replace(processed_content, '_(.+?)_', '\1 ', 'g');
+ processed_content := regexp_replace(processed_content, '`([^`]+)`', '\1 ', 'g');
+ processed_content := regexp_replace(processed_content, ' \n', ' \n', 'g');
+
+ -- Wrap the result in tags as Markdown is just a fragment.
+ processed_content := '
' || processed_content || '
';
+ -- Convert double newlines to paragraph breaks.
+ processed_content := regexp_replace(processed_content, '\n\n', '
', 'g');
+
+ -- C) Plaintext (Default Case)
+ ELSE
+ -- For plaintext, convert all-caps words to tags, then wrap in tags and handle newlines.
+ -- This rule assumes that words in all caps (e.g., "NASA") should be rendered in small-caps.
+ processed_content := regexp_replace(processed_content, '\b([A-Z]{2,})\b', '\1 ', 'g');
+
+ -- Wrap the content in
tags and convert newlines.
+ processed_content := '
' || processed_content || '
';
+ processed_content := regexp_replace(processed_content, E'\n\n', '
', 'g');
+ processed_content := regexp_replace(processed_content, E'\n', ' ', 'g');
+ END CASE;
+
+ -- Return the processed content without the wrapper.
+ RETURN processed_content;
+
+END;
+$$ LANGUAGE plpgsql;
+
+-- -----------------------------------------------------------------------------
+-- Title Conversion Function
+-- -----------------------------------------------------------------------------
+-- Similar to convert_to_jats but does NOT wrap content in tags.
+-- This is used specifically for titles which should not have paragraph wrappers.
+-- -----------------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION convert_to_jats_title(content_in TEXT)
+RETURNS TEXT AS $$
+DECLARE
+ processed_content TEXT := content_in;
+BEGIN
+ -- Return NULL immediately if input is NULL or empty.
+ IF processed_content IS NULL OR processed_content = '' THEN
+ RETURN NULL;
+ END IF;
+
+ -- The CASE statement detects the format and applies conversion rules.
+ CASE
+ -- A) HTML Detection: Looks for common HTML tags. Now includes .
+ WHEN processed_content ~* '<(p|em|i|strong|b|sup|sub|sc|code|a|br)\b' THEN
+ -- Convert HTML tags to their JATS equivalents.
+ processed_content := regexp_replace(processed_content, ']*>(.*?) ', '\2 ', 'gi');
+ processed_content := regexp_replace(processed_content, '<(strong|b)>(.*?)\1>', '\2 ', 'gi');
+ processed_content := regexp_replace(processed_content, '<(em|i)>(.*?)\1>', '\2 ', 'gi');
+ processed_content := regexp_replace(processed_content, '(.*?)', '\1 ', 'gi');
+ processed_content := regexp_replace(processed_content, ' ', ' ', 'gi');
+ -- Remove any existing tags that might wrap the content
+ processed_content := regexp_replace(processed_content, '^
(.*)
$', '\1', 'g');
+ -- , , and are valid in JATS, so they are left as is.
+
+ -- B) Markdown Detection: Looks for Markdown syntax like **, *, ``, etc.
+ WHEN processed_content ~ '(\*\*|__).+?\1' OR
+ processed_content ~ '(?\1', 'g');
+ processed_content := regexp_replace(processed_content, '\*\*(.+?)\*\*', '\1 ', 'g');
+ processed_content := regexp_replace(processed_content, '__(.+?)__', '\1 ', 'g');
+ processed_content := regexp_replace(processed_content, '\*(.+?)\*', '\1 ', 'g');
+ processed_content := regexp_replace(processed_content, '_(.+?)_', '\1 ', 'g');
+ processed_content := regexp_replace(processed_content, '`([^`]+)`', '\1 ', 'g');
+ processed_content := regexp_replace(processed_content, ' \n', ' \n', 'g');
+ -- Convert newlines to breaks (no paragraph wrapping)
+ processed_content := regexp_replace(processed_content, E'\n', ' ', 'g');
+
+ -- C) Plaintext (Default Case)
+ ELSE
+ -- For plaintext, convert all-caps words to tags, then handle newlines.
+ -- This rule assumes that words in all caps (e.g., "NASA") should be rendered in small-caps.
+ processed_content := regexp_replace(processed_content, '\b([A-Z]{2,})\b', '\1 ', 'g');
+
+ -- Convert newlines to breaks (no paragraph wrapping)
+ processed_content := regexp_replace(processed_content, E'\n', ' ', 'g');
+ END CASE;
+
+ -- Return the processed content without paragraph wrappers.
+ RETURN processed_content;
+
+END;
+$$ LANGUAGE plpgsql;
+
+-- Create the title table
+CREATE TABLE IF NOT EXISTS title (
+ title_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ work_id UUID NOT NULL REFERENCES work (work_id) ON DELETE CASCADE,
+ locale_code locale_code NOT NULL,
+ full_title TEXT NOT NULL CHECK (octet_length(full_title) >= 1),
+ title TEXT NOT NULL CHECK (octet_length(title) >= 1),
+ subtitle TEXT CHECK (octet_length(subtitle) >= 1),
+ canonical BOOLEAN NOT NULL DEFAULT FALSE
+);
+
+-- Create the title_history table
+CREATE TABLE IF NOT EXISTS title_history (
+ title_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ title_id UUID NOT NULL REFERENCES title (title_id) ON DELETE CASCADE,
+ account_id UUID NOT NULL REFERENCES account (account_id) ON DELETE CASCADE,
+ data JSONB NOT NULL,
+ timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW()
+);
+
+-- Migrate existing work titles to the title table with English locale
+INSERT INTO title (title_id, work_id, locale_code, full_title, title, subtitle, canonical)
+SELECT
+ uuid_generate_v4(),
+ work_id,
+ 'en'::locale_code,
+ convert_to_jats_title(full_title),
+ convert_to_jats_title(title),
+ CASE WHEN subtitle IS NOT NULL THEN convert_to_jats_title(subtitle) ELSE NULL END,
+ TRUE
+FROM work
+WHERE full_title IS NOT NULL
+ AND title IS NOT NULL;
+
+-- Only allow one canonical title per work
+CREATE UNIQUE INDEX IF NOT EXISTS title_unique_canonical_true_idx ON title(work_id)
+ WHERE canonical;
+
+-- Only allow one instance of each locale per work
+CREATE UNIQUE INDEX IF NOT EXISTS title_uniq_locale_idx ON title(work_id, locale_code);
+
+-- Drop title-related columns from the work table
+ALTER TABLE work
+ DROP COLUMN full_title,
+ DROP COLUMN title,
+ DROP COLUMN subtitle;
+
+-- Create AbstractType enum
+CREATE TYPE abstract_type AS ENUM (
+ 'short',
+ 'long'
+);
+
+-- Create the abstract table
+CREATE TABLE IF NOT EXISTS abstract (
+ abstract_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ work_id UUID NOT NULL REFERENCES work (work_id) ON DELETE CASCADE,
+ content TEXT NOT NULL CHECK (octet_length(content) >= 1),
+ locale_code locale_code NOT NULL,
+ abstract_type abstract_type NOT NULL DEFAULT 'short',
+ canonical BOOLEAN NOT NULL DEFAULT FALSE
+);
+
+-- Create the abstract_history table
+CREATE TABLE IF NOT EXISTS abstract_history (
+ abstract_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ abstract_id UUID NOT NULL REFERENCES abstract (abstract_id) ON DELETE CASCADE,
+ account_id UUID NOT NULL REFERENCES account (account_id) ON DELETE CASCADE,
+ data JSONB NOT NULL,
+ timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW()
+);
+
+-- Insert short abstracts into the abstract table using the conversion function
+INSERT INTO abstract (abstract_id, work_id, content, locale_code, abstract_type, canonical)
+SELECT
+ uuid_generate_v4() AS abstract_id,
+ work_id,
+ convert_to_jats(short_abstract) AS content,
+ 'en'::locale_code, -- Assuming 'en' as the default locale code
+ 'short'::abstract_type,
+ TRUE
+FROM
+ work
+WHERE
+ short_abstract IS NOT NULL AND short_abstract != '';
+
+-- Insert long abstracts into the abstract table using the conversion function
+INSERT INTO abstract (abstract_id, work_id, content, locale_code, abstract_type, canonical)
+SELECT
+ uuid_generate_v4() AS abstract_id,
+ work_id,
+ convert_to_jats(long_abstract) AS content,
+ 'en'::locale_code, -- Assuming 'en' as the default locale code
+ 'long'::abstract_type,
+ TRUE
+FROM
+ work
+WHERE
+ long_abstract IS NOT NULL AND long_abstract != '';
+
+-- Only allow one canonical abstract per work
+CREATE UNIQUE INDEX IF NOT EXISTS abstract_unique_canonical_true_idx
+ON abstract(work_id, abstract_type)
+WHERE canonical;
+
+-- Only allow one instance of each locale per work
+CREATE UNIQUE INDEX IF NOT EXISTS abstract_uniq_locale_idx
+ON abstract(work_id, locale_code, abstract_type);
+
+-- Drop title-related columns from the work table
+ALTER TABLE work
+ DROP COLUMN short_abstract,
+ DROP COLUMN long_abstract;
+
+-- Create the abstract table
+CREATE TABLE IF NOT EXISTS biography (
+ biography_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ contribution_id UUID NOT NULL REFERENCES contribution (contribution_id) ON DELETE CASCADE,
+ content TEXT NOT NULL CHECK (octet_length(content) >= 1),
+ canonical BOOLEAN NOT NULL DEFAULT FALSE,
+ locale_code locale_code NOT NULL
+);
+
+-- Create the biography_history table
+CREATE TABLE IF NOT EXISTS biography_history (
+ biography_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ biography_id UUID NOT NULL REFERENCES biography (biography_id) ON DELETE CASCADE,
+ account_id UUID NOT NULL REFERENCES account (account_id) ON DELETE CASCADE,
+ data JSONB NOT NULL,
+ timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW()
+);
+
+-- Migrate existing contribution biographies to the biography table with English locale
+INSERT INTO biography (biography_id, contribution_id, content, canonical, locale_code)
+SELECT
+ uuid_generate_v4(),
+ contribution_id,
+ convert_to_jats(biography) AS content,
+ TRUE,
+ 'en'::locale_code
+FROM contribution
+WHERE biography IS NOT NULL;
+
+-- Only allow one canonical biography per contribution
+CREATE UNIQUE INDEX IF NOT EXISTS biography_unique_canonical_true_idx
+ON biography(contribution_id)
+WHERE canonical;
+
+-- Only allow one instance of each locale per contribution
+CREATE UNIQUE INDEX IF NOT EXISTS biography_uniq_locale_idx
+ON biography(contribution_id, locale_code);
+
+-- Drop title-related columns from the work table
+ALTER TABLE contribution
+ DROP COLUMN biography;
+
+-- Clean up the conversion functions after the migration is complete
+DROP FUNCTION convert_to_jats(TEXT);
+DROP FUNCTION convert_to_jats_title(TEXT);
+
+--
+-- Name: biography_work_updated_at_with_relations(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION public.biography_work_updated_at_with_relations() RETURNS trigger
+ LANGUAGE plpgsql
+AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ FROM contribution
+ WHERE work.work_id = contribution.work_id AND contribution.contribution_id = OLD.contribution_id
+ OR work.work_id = contribution.work_id AND contribution.contribution_id = NEW.contribution_id;
+ END IF;
+ RETURN NULL;
+END;
+$$;
+
+--
+-- Name: affiliation set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.biography FOR EACH ROW EXECUTE FUNCTION public.biography_work_updated_at_with_relations();
+
+
+--
+-- Name: title set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.title FOR EACH ROW EXECUTE FUNCTION public.work_updated_at_with_relations();
+
+--
+-- Name: abstract set_work_updated_at_with_relations; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.abstract FOR EACH ROW EXECUTE FUNCTION public.work_updated_at_with_relations();
diff --git a/thoth-api/migrations/20251212_v1.0.0/down.sql b/thoth-api/migrations/20251212_v1.0.0/down.sql
new file mode 100644
index 00000000..f777d56f
--- /dev/null
+++ b/thoth-api/migrations/20251212_v1.0.0/down.sql
@@ -0,0 +1,19 @@
+DROP TABLE contact_history;
+DROP TABLE contact;
+
+ALTER TABLE publisher
+ DROP COLUMN accessibility_statement,
+ DROP COLUMN accessibility_report_url;
+
+ALTER TABLE publication
+ DROP CONSTRAINT check_accessibility_standard_rules,
+ DROP CONSTRAINT check_additional_standard_pdf_epub,
+ DROP CONSTRAINT check_standard_or_exception,
+ DROP COLUMN accessibility_standard,
+ DROP COLUMN accessibility_additional_standard,
+ DROP COLUMN accessibility_exception,
+ DROP COLUMN accessibility_report_url;
+
+DROP TYPE contact_type;
+DROP TYPE accessibility_exception;
+DROP TYPE accessibility_standard;
diff --git a/thoth-api/migrations/20251212_v1.0.0/up.sql b/thoth-api/migrations/20251212_v1.0.0/up.sql
new file mode 100644
index 00000000..6e62bb15
--- /dev/null
+++ b/thoth-api/migrations/20251212_v1.0.0/up.sql
@@ -0,0 +1,116 @@
+CREATE TYPE contact_type AS ENUM (
+ 'Accessibility'
+);
+
+CREATE TABLE contact (
+ contact_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ publisher_id UUID NOT NULL REFERENCES publisher(publisher_id) ON DELETE CASCADE,
+ contact_type contact_type NOT NULL DEFAULT 'Accessibility',
+ email TEXT NOT NULL CHECK (octet_length(email) >= 1),
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ CONSTRAINT contact_contact_type_publisher_id_uniq UNIQUE (publisher_id, contact_type)
+);
+SELECT diesel_manage_updated_at('contact');
+CREATE INDEX idx_contact_email ON contact (email);
+
+CREATE TABLE contact_history (
+ contact_history_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ contact_id UUID NOT NULL REFERENCES contact(contact_id) ON DELETE CASCADE,
+ account_id UUID NOT NULL REFERENCES account(account_id),
+ data JSONB NOT NULL,
+ timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+ALTER TABLE publisher
+ ADD COLUMN accessibility_statement TEXT CHECK (octet_length(accessibility_statement) >= 1),
+ ADD COLUMN accessibility_report_url TEXT CHECK (octet_length(accessibility_report_url) >= 1);
+
+CREATE TYPE accessibility_standard AS ENUM (
+ 'wcag-21-aa',
+ 'wcag-21-aaa',
+ 'wcag-22-aa',
+ 'wcag-22-aaa',
+ 'epub-a11y-10-aa',
+ 'epub-a11y-10-aaa',
+ 'epub-a11y-11-aa',
+ 'epub-a11y-11-aaa',
+ 'pdf-ua-1',
+ 'pdf-ua-2'
+);
+
+CREATE TYPE accessibility_exception AS ENUM (
+ 'micro-enterprises',
+ 'disproportionate-burden',
+ 'fundamental-alteration'
+);
+
+ALTER TABLE publication
+ ADD COLUMN accessibility_standard accessibility_standard, -- WCAG only
+ ADD COLUMN accessibility_additional_standard accessibility_standard, -- EPUB or PDF only
+ ADD COLUMN accessibility_exception accessibility_exception,
+ ADD COLUMN accessibility_report_url TEXT,
+
+ -- Either standards or exception (or none, for excluded types)
+ ADD CONSTRAINT check_standard_or_exception
+ CHECK (
+ (
+ accessibility_exception IS NULL
+ AND accessibility_standard IS NOT NULL
+ )
+ OR (
+ accessibility_exception IS NOT NULL
+ AND accessibility_standard IS NULL
+ AND accessibility_additional_standard IS NULL
+ )
+ OR (
+ accessibility_exception IS NULL
+ AND accessibility_standard IS NULL
+ AND accessibility_additional_standard IS NULL
+ )
+ ),
+
+ -- Ensure additional_standard is only used for PDFs or EPUBs
+ ADD CONSTRAINT check_additional_standard_pdf_epub
+ CHECK (
+ accessibility_additional_standard IS NULL
+ OR publication_type IN ('PDF', 'Epub')
+ ),
+
+ -- Ensure standards are valid per publication type
+ ADD CONSTRAINT check_accessibility_standard_rules
+ CHECK (
+ CASE publication_type
+ WHEN 'Paperback' THEN accessibility_standard IS NULL AND accessibility_additional_standard IS NULL AND accessibility_exception IS NULL
+ WHEN 'Hardback' THEN accessibility_standard IS NULL AND accessibility_additional_standard IS NULL AND accessibility_exception IS NULL
+ WHEN 'MP3' THEN accessibility_standard IS NULL AND accessibility_additional_standard IS NULL AND accessibility_exception IS NULL
+ WHEN 'WAV' THEN accessibility_standard IS NULL AND accessibility_additional_standard IS NULL AND accessibility_exception IS NULL
+ WHEN 'PDF' THEN (
+ (accessibility_standard IS NULL OR accessibility_standard IN (
+ 'wcag-21-aa','wcag-21-aaa',
+ 'wcag-22-aa','wcag-22-aaa'
+ ))
+ AND
+ (accessibility_additional_standard IS NULL OR accessibility_additional_standard IN ('pdf-ua-1','pdf-ua-2'))
+ )
+ WHEN 'Epub' THEN (
+ (accessibility_standard IS NULL OR accessibility_standard IN (
+ 'wcag-21-aa','wcag-21-aaa',
+ 'wcag-22-aa','wcag-22-aaa'
+ ))
+ AND
+ (accessibility_additional_standard IS NULL OR accessibility_additional_standard IN (
+ 'epub-a11y-10-aa','epub-a11y-10-aaa',
+ 'epub-a11y-11-aa','epub-a11y-11-aaa'
+ ))
+ )
+ ELSE (
+ (accessibility_standard IS NULL OR accessibility_standard IN (
+ 'wcag-21-aa','wcag-21-aaa',
+ 'wcag-22-aa','wcag-22-aaa'
+ ))
+ AND
+ accessibility_additional_standard IS NULL
+ )
+ END
+ );
diff --git a/thoth-api/migrations/20260107_v1.0.0/down.sql b/thoth-api/migrations/20260107_v1.0.0/down.sql
new file mode 100644
index 00000000..2cd2be6e
--- /dev/null
+++ b/thoth-api/migrations/20260107_v1.0.0/down.sql
@@ -0,0 +1,103 @@
+-- Recreate the `account` table
+CREATE TABLE account (
+ account_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ name TEXT NOT NULL CHECK (octet_length(name) >= 1),
+ surname TEXT NOT NULL CHECK (octet_length(surname) >= 1),
+ email TEXT NOT NULL CHECK (octet_length(email) >= 1),
+ hash BYTEA NOT NULL,
+ salt TEXT NOT NULL CHECK (octet_length(salt) >= 1),
+ is_superuser BOOLEAN NOT NULL DEFAULT False,
+ is_bot BOOLEAN NOT NULL DEFAULT False,
+ is_active BOOLEAN NOT NULL DEFAULT True,
+ token TEXT NULL CHECK (OCTET_LENGTH(token) >= 1),
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+SELECT diesel_manage_updated_at('account');
+
+-- case-insensitive UNIQ index on email
+CREATE UNIQUE INDEX email_uniq_idx ON account(lower(email));
+
+-- Recreate the `publisher_account` table
+CREATE TABLE publisher_account (
+ account_id UUID NOT NULL REFERENCES account(account_id) ON DELETE CASCADE,
+ publisher_id UUID NOT NULL REFERENCES publisher(publisher_id) ON DELETE CASCADE,
+ is_admin BOOLEAN NOT NULL DEFAULT False,
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (account_id, publisher_id)
+);
+SELECT diesel_manage_updated_at('publisher_account');
+
+-- Rename column user_id → account_id and change type to UUID
+ALTER TABLE abstract_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE affiliation_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE biography_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE contact_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE contribution_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE contributor_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE funding_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE imprint_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE institution_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE issue_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE language_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE location_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE price_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE publication_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE publisher_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE reference_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE series_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE subject_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE title_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE work_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+ALTER TABLE work_relation_history ALTER COLUMN user_id TYPE UUID USING user_id::uuid;
+
+ALTER TABLE abstract_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE affiliation_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE biography_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE contact_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE contribution_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE contributor_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE funding_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE imprint_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE institution_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE issue_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE language_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE location_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE price_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE publication_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE publisher_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE reference_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE series_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE subject_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE title_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE work_history RENAME COLUMN user_id TO account_id;
+ALTER TABLE work_relation_history RENAME COLUMN user_id TO account_id;
+
+-- Restore foreign key constraints
+ALTER TABLE abstract_history ADD CONSTRAINT abstract_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE affiliation_history ADD CONSTRAINT affiliation_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE biography_history ADD CONSTRAINT biography_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE contact_history ADD CONSTRAINT contact_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE contribution_history ADD CONSTRAINT contribution_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE contributor_history ADD CONSTRAINT contributor_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE funding_history ADD CONSTRAINT funding_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE imprint_history ADD CONSTRAINT imprint_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE institution_history ADD CONSTRAINT institution_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE issue_history ADD CONSTRAINT issue_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE language_history ADD CONSTRAINT language_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE location_history ADD CONSTRAINT location_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE price_history ADD CONSTRAINT price_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE publication_history ADD CONSTRAINT publication_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE publisher_history ADD CONSTRAINT publisher_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE reference_history ADD CONSTRAINT reference_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE series_history ADD CONSTRAINT series_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE subject_history ADD CONSTRAINT subject_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE title_history ADD CONSTRAINT title_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE work_history ADD CONSTRAINT work_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+ALTER TABLE work_relation_history ADD CONSTRAINT work_relation_history_account_id_fkey FOREIGN KEY (account_id) REFERENCES account(account_id);
+
+-- Remove ZITADEL organisation id column/index from publisher
+DROP INDEX IF EXISTS publisher_zitadel_id_key;
+ALTER TABLE publisher
+ DROP COLUMN IF EXISTS zitadel_id;
\ No newline at end of file
diff --git a/thoth-api/migrations/20260107_v1.0.0/up.sql b/thoth-api/migrations/20260107_v1.0.0/up.sql
new file mode 100644
index 00000000..d820af4d
--- /dev/null
+++ b/thoth-api/migrations/20260107_v1.0.0/up.sql
@@ -0,0 +1,81 @@
+-- Drop foreign key constraints
+ALTER TABLE abstract_history DROP CONSTRAINT IF EXISTS abstract_history_account_id_fkey;
+ALTER TABLE affiliation_history DROP CONSTRAINT IF EXISTS affiliation_history_account_id_fkey;
+ALTER TABLE biography_history DROP CONSTRAINT IF EXISTS biography_history_account_id_fkey;
+ALTER TABLE contact_history DROP CONSTRAINT IF EXISTS contact_history_account_id_fkey;
+ALTER TABLE contribution_history DROP CONSTRAINT IF EXISTS contribution_history_account_id_fkey;
+ALTER TABLE contributor_history DROP CONSTRAINT IF EXISTS contributor_history_account_id_fkey;
+ALTER TABLE funding_history DROP CONSTRAINT IF EXISTS funding_history_account_id_fkey;
+ALTER TABLE imprint_history DROP CONSTRAINT IF EXISTS imprint_history_account_id_fkey;
+ALTER TABLE institution_history DROP CONSTRAINT IF EXISTS institution_history_account_id_fkey;
+ALTER TABLE institution_history DROP CONSTRAINT IF EXISTS funder_history_account_id_fkey; -- historical
+ALTER TABLE issue_history DROP CONSTRAINT IF EXISTS issue_history_account_id_fkey;
+ALTER TABLE language_history DROP CONSTRAINT IF EXISTS language_history_account_id_fkey;
+ALTER TABLE location_history DROP CONSTRAINT IF EXISTS location_history_account_id_fkey;
+ALTER TABLE price_history DROP CONSTRAINT IF EXISTS price_history_account_id_fkey;
+ALTER TABLE publication_history DROP CONSTRAINT IF EXISTS publication_history_account_id_fkey;
+ALTER TABLE publisher_history DROP CONSTRAINT IF EXISTS publisher_history_account_id_fkey;
+ALTER TABLE reference_history DROP CONSTRAINT IF EXISTS reference_history_account_id_fkey;
+ALTER TABLE series_history DROP CONSTRAINT IF EXISTS series_history_account_id_fkey;
+ALTER TABLE subject_history DROP CONSTRAINT IF EXISTS subject_history_account_id_fkey;
+ALTER TABLE title_history DROP CONSTRAINT IF EXISTS title_history_account_id_fkey;
+ALTER TABLE work_history DROP CONSTRAINT IF EXISTS work_history_account_id_fkey;
+ALTER TABLE work_relation_history DROP CONSTRAINT IF EXISTS work_relation_history_account_id_fkey;
+
+-- Rename column account_id to user_id and change type to TEXT
+ALTER TABLE abstract_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE affiliation_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE biography_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE contact_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE contribution_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE contributor_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE funding_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE imprint_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE institution_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE issue_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE language_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE location_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE price_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE publication_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE publisher_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE reference_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE series_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE subject_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE title_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE work_history RENAME COLUMN account_id TO user_id;
+ALTER TABLE work_relation_history RENAME COLUMN account_id TO user_id;
+
+ALTER TABLE abstract_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE affiliation_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE biography_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE contact_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE contribution_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE contributor_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE funding_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE imprint_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE institution_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE issue_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE language_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE location_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE price_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE publication_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE publisher_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE reference_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE series_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE subject_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE title_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE work_history ALTER COLUMN user_id TYPE TEXT;
+ALTER TABLE work_relation_history ALTER COLUMN user_id TYPE TEXT;
+
+-- Drop the obsolete tables
+DROP TABLE IF EXISTS publisher_account;
+DROP TABLE IF EXISTS account;
+
+-- Store ZITADEL organisation id for publisher-scoped authorisation
+ALTER TABLE publisher
+ ADD COLUMN IF NOT EXISTS zitadel_id TEXT;
+
+-- Each publisher should map to at most one ZITADEL organisation
+CREATE UNIQUE INDEX IF NOT EXISTS publisher_zitadel_id_key
+ ON publisher (zitadel_id)
+ WHERE zitadel_id IS NOT NULL;
diff --git a/thoth-api/migrations/20260210_v1.0.0/down.sql b/thoth-api/migrations/20260210_v1.0.0/down.sql
new file mode 100644
index 00000000..d50a2dbb
--- /dev/null
+++ b/thoth-api/migrations/20260210_v1.0.0/down.sql
@@ -0,0 +1,11 @@
+DROP TABLE IF EXISTS file_upload;
+DROP TABLE IF EXISTS file;
+DROP TYPE IF EXISTS file_type;
+DROP FUNCTION IF EXISTS file_upload_work_updated_at_with_relations();
+DROP FUNCTION IF EXISTS file_work_updated_at_with_relations();
+
+ALTER TABLE imprint
+ DROP CONSTRAINT IF EXISTS imprint_storage_cfg_all_or_none,
+ DROP COLUMN IF EXISTS s3_bucket,
+ DROP COLUMN IF EXISTS cdn_domain,
+ DROP COLUMN IF EXISTS cloudfront_dist_id;
diff --git a/thoth-api/migrations/20260210_v1.0.0/up.sql b/thoth-api/migrations/20260210_v1.0.0/up.sql
new file mode 100644
index 00000000..978a5a66
--- /dev/null
+++ b/thoth-api/migrations/20260210_v1.0.0/up.sql
@@ -0,0 +1,134 @@
+ALTER TABLE imprint
+ ADD COLUMN s3_bucket TEXT,
+ ADD COLUMN cdn_domain TEXT,
+ ADD COLUMN cloudfront_dist_id TEXT;
+
+ALTER TABLE imprint
+ ADD CONSTRAINT imprint_storage_cfg_all_or_none
+ CHECK (
+ (
+ s3_bucket IS NULL AND
+ cdn_domain IS NULL AND
+ cloudfront_dist_id IS NULL
+ )
+ OR
+ (
+ s3_bucket IS NOT NULL AND
+ cdn_domain IS NOT NULL AND
+ cloudfront_dist_id IS NOT NULL
+ )
+ );
+
+
+CREATE TYPE file_type AS ENUM ('publication', 'frontcover');
+
+CREATE TABLE file (
+ file_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ file_type file_type NOT NULL,
+ work_id UUID REFERENCES work (work_id),
+ publication_id UUID REFERENCES publication (publication_id),
+ object_key TEXT NOT NULL,
+ cdn_url TEXT NOT NULL,
+ mime_type TEXT NOT NULL,
+ bytes BIGINT NOT NULL,
+ sha256 TEXT NOT NULL,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
+);
+
+ALTER TABLE file
+ ADD CONSTRAINT file_type_check
+ CHECK (
+ (file_type = 'frontcover' AND work_id IS NOT NULL AND publication_id IS NULL) OR
+ (file_type = 'publication' AND publication_id IS NOT NULL AND work_id IS NULL)
+ );
+
+CREATE UNIQUE INDEX file_frontcover_work_unique_idx
+ ON file (work_id)
+ WHERE file_type = 'frontcover';
+
+CREATE UNIQUE INDEX file_publication_unique_idx
+ ON file (publication_id)
+ WHERE file_type = 'publication';
+
+CREATE UNIQUE INDEX file_object_key_unique_idx
+ ON file (object_key);
+
+SELECT diesel_manage_updated_at('file');
+
+CREATE TABLE file_upload (
+ file_upload_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ file_type file_type NOT NULL,
+ work_id UUID REFERENCES work (work_id),
+ publication_id UUID REFERENCES publication (publication_id),
+ declared_mime_type TEXT NOT NULL,
+ declared_extension TEXT NOT NULL,
+ declared_sha256 TEXT NOT NULL,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
+);
+
+ALTER TABLE file_upload
+ ADD CONSTRAINT file_upload_type_check
+ CHECK (
+ (file_type = 'frontcover' AND work_id IS NOT NULL AND publication_id IS NULL) OR
+ (file_type = 'publication' AND publication_id IS NOT NULL AND work_id IS NULL)
+ );
+
+CREATE INDEX file_upload_work_idx
+ ON file_upload (work_id)
+ WHERE file_type = 'frontcover';
+
+CREATE INDEX file_upload_publication_idx
+ ON file_upload (publication_id)
+ WHERE file_type = 'publication';
+
+SELECT diesel_manage_updated_at('file_upload');
+
+CREATE FUNCTION public.file_work_updated_at_with_relations() RETURNS trigger
+ LANGUAGE plpgsql
+AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ WHERE work_id = OLD.work_id OR work_id = NEW.work_id;
+
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ FROM publication
+ WHERE work.work_id = publication.work_id
+ AND (publication.publication_id = OLD.publication_id OR publication.publication_id = NEW.publication_id);
+ END IF;
+ RETURN NULL;
+END;
+$$;
+
+CREATE FUNCTION public.file_upload_work_updated_at_with_relations() RETURNS trigger
+ LANGUAGE plpgsql
+AS $$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD
+ ) THEN
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ WHERE work_id = OLD.work_id OR work_id = NEW.work_id;
+
+ UPDATE work
+ SET updated_at_with_relations = current_timestamp
+ FROM publication
+ WHERE work.work_id = publication.work_id
+ AND (publication.publication_id = OLD.publication_id OR publication.publication_id = NEW.publication_id);
+ END IF;
+ RETURN NULL;
+END;
+$$;
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.file
+ FOR EACH ROW EXECUTE FUNCTION public.file_work_updated_at_with_relations();
+
+CREATE TRIGGER set_work_updated_at_with_relations AFTER INSERT OR DELETE OR UPDATE ON public.file_upload
+ FOR EACH ROW EXECUTE FUNCTION public.file_upload_work_updated_at_with_relations();
diff --git a/thoth-api/migrations/v0.11.12/down.sql b/thoth-api/migrations/v0.11.12/down.sql
deleted file mode 100644
index 299feb08..00000000
--- a/thoth-api/migrations/v0.11.12/down.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE price DROP CONSTRAINT price_publication_id_currency_code_uniq;
diff --git a/thoth-api/migrations/v0.11.12/up.sql b/thoth-api/migrations/v0.11.12/up.sql
deleted file mode 100644
index 531b5f8e..00000000
--- a/thoth-api/migrations/v0.11.12/up.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE price ADD CONSTRAINT price_publication_id_currency_code_uniq
- UNIQUE (publication_id, currency_code);
diff --git a/thoth-api/migrations/v0.11.14/down.sql b/thoth-api/migrations/v0.11.14/down.sql
deleted file mode 100644
index c4b2f997..00000000
--- a/thoth-api/migrations/v0.11.14/down.sql
+++ /dev/null
@@ -1,33 +0,0 @@
-UPDATE location SET location_platform = 'Other' WHERE location_platform IN (
- 'Google Books',
- 'Internet Archive',
- 'ScienceOpen',
- 'SciELO'
-);
-
--- Drop the default and unique constraint, otherwise it won't be able to cast to text
-ALTER TABLE location ALTER COLUMN location_platform DROP DEFAULT;
-DROP INDEX location_uniq_platform_idx;
-
-ALTER TABLE location ALTER COLUMN location_platform TYPE text;
-DROP TYPE location_platform;
-CREATE TYPE location_platform AS ENUM (
- 'Project MUSE',
- 'OAPEN',
- 'DOAB',
- 'JSTOR',
- 'EBSCO Host',
- 'OCLC KB',
- 'ProQuest KB',
- 'ProQuest ExLibris',
- 'EBSCO KB',
- 'JISC KB',
- 'Other'
- );
-ALTER TABLE location ALTER location_platform TYPE location_platform USING location_platform::location_platform;
-ALTER TABLE location
- ALTER COLUMN location_platform SET DEFAULT 'Other'::location_platform;
-
-CREATE UNIQUE INDEX location_uniq_platform_idx
- ON location (publication_id, location_platform)
- WHERE NOT location_platform = 'Other'::location_platform;
\ No newline at end of file
diff --git a/thoth-api/migrations/v0.11.14/up.sql b/thoth-api/migrations/v0.11.14/up.sql
deleted file mode 100644
index d6d61234..00000000
--- a/thoth-api/migrations/v0.11.14/up.sql
+++ /dev/null
@@ -1,4 +0,0 @@
-ALTER TYPE location_platform ADD VALUE 'Google Books';
-ALTER TYPE location_platform ADD VALUE 'Internet Archive';
-ALTER TYPE location_platform ADD VALUE 'ScienceOpen';
-ALTER TYPE location_platform ADD VALUE 'SciELO';
diff --git a/thoth-api/migrations/v0.11.15/down.sql b/thoth-api/migrations/v0.11.15/down.sql
deleted file mode 100644
index ca127880..00000000
--- a/thoth-api/migrations/v0.11.15/down.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TYPE location_platform RENAME VALUE 'SciELO Books' TO 'SciELO';
\ No newline at end of file
diff --git a/thoth-api/migrations/v0.11.15/up.sql b/thoth-api/migrations/v0.11.15/up.sql
deleted file mode 100644
index 597faa48..00000000
--- a/thoth-api/migrations/v0.11.15/up.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TYPE location_platform RENAME VALUE 'SciELO' TO 'SciELO Books';
diff --git a/thoth-api/migrations/v0.11.16/down.sql b/thoth-api/migrations/v0.11.16/down.sql
deleted file mode 100644
index 920646da..00000000
--- a/thoth-api/migrations/v0.11.16/down.sql
+++ /dev/null
@@ -1,34 +0,0 @@
-UPDATE location SET location_platform = 'Other' WHERE location_platform IN (
- 'Publisher Website'
-);
-
--- Drop the default and unique constraint, otherwise it won't be able to cast to text
-ALTER TABLE location ALTER COLUMN location_platform DROP DEFAULT;
-DROP INDEX location_uniq_platform_idx;
-
-ALTER TABLE location ALTER COLUMN location_platform TYPE text;
-DROP TYPE location_platform;
-CREATE TYPE location_platform AS ENUM (
- 'Project MUSE',
- 'OAPEN',
- 'DOAB',
- 'JSTOR',
- 'EBSCO Host',
- 'OCLC KB',
- 'ProQuest KB',
- 'ProQuest ExLibris',
- 'EBSCO KB',
- 'JISC KB',
- 'Google Books',
- 'Internet Archive',
- 'ScienceOpen',
- 'SciELO Books',
- 'Other'
- );
-ALTER TABLE location ALTER location_platform TYPE location_platform USING location_platform::location_platform;
-ALTER TABLE location
- ALTER COLUMN location_platform SET DEFAULT 'Other'::location_platform;
-
-CREATE UNIQUE INDEX location_uniq_platform_idx
- ON location (publication_id, location_platform)
- WHERE NOT location_platform = 'Other'::location_platform;
diff --git a/thoth-api/migrations/v0.11.16/up.sql b/thoth-api/migrations/v0.11.16/up.sql
deleted file mode 100644
index addc5d68..00000000
--- a/thoth-api/migrations/v0.11.16/up.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TYPE location_platform ADD VALUE 'Publisher Website';
diff --git a/thoth-api/migrations/v0.11.17/down.sql b/thoth-api/migrations/v0.11.17/down.sql
deleted file mode 100644
index 055b53a9..00000000
--- a/thoth-api/migrations/v0.11.17/down.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE contribution
- ALTER COLUMN main_contribution SET DEFAULT False;
diff --git a/thoth-api/migrations/v0.11.17/up.sql b/thoth-api/migrations/v0.11.17/up.sql
deleted file mode 100644
index 87fe07b7..00000000
--- a/thoth-api/migrations/v0.11.17/up.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE contribution
- ALTER COLUMN main_contribution SET DEFAULT True;
diff --git a/thoth-api/migrations/v0.11.7/down.sql b/thoth-api/migrations/v0.11.7/down.sql
deleted file mode 100644
index b9297c0c..00000000
--- a/thoth-api/migrations/v0.11.7/down.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-ALTER TABLE work DROP CONSTRAINT work_doi_check;
-ALTER TABLE work ADD CONSTRAINT work_doi_check
- CHECK (doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\[\]\/:a-zA-Z0-9]+$');
-
-ALTER TABLE reference DROP CONSTRAINT reference_doi_check;
-ALTER TABLE reference ADD CONSTRAINT reference_doi_check
- CHECK (doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\[\]\/:a-zA-Z0-9]+$');
-
-ALTER TABLE institution DROP CONSTRAINT institution_institution_doi_check;
-ALTER TABLE institution ADD CONSTRAINT institution_institution_doi_check
- CHECK (institution_doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\[\]\/:a-zA-Z0-9]+$');
diff --git a/thoth-api/migrations/v0.11.7/up.sql b/thoth-api/migrations/v0.11.7/up.sql
deleted file mode 100644
index 40680f44..00000000
--- a/thoth-api/migrations/v0.11.7/up.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-ALTER TABLE work DROP CONSTRAINT work_doi_check;
-ALTER TABLE work ADD CONSTRAINT work_doi_check
- CHECK (doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\[\]<>\/:a-zA-Z0-9]+$');
-
-ALTER TABLE reference DROP CONSTRAINT reference_doi_check;
-ALTER TABLE reference ADD CONSTRAINT reference_doi_check
- CHECK (doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\[\]<>\/:a-zA-Z0-9]+$');
-
-ALTER TABLE institution DROP CONSTRAINT institution_institution_doi_check;
-ALTER TABLE institution ADD CONSTRAINT institution_institution_doi_check
- CHECK (institution_doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\[\]<>\/:a-zA-Z0-9]+$');
diff --git a/thoth-api/migrations/v0.12.2/down.sql b/thoth-api/migrations/v0.12.2/down.sql
deleted file mode 100644
index f21aa271..00000000
--- a/thoth-api/migrations/v0.12.2/down.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE imprint
- DROP COLUMN crossmark_doi;
diff --git a/thoth-api/migrations/v0.12.2/up.sql b/thoth-api/migrations/v0.12.2/up.sql
deleted file mode 100644
index 9f2f56d9..00000000
--- a/thoth-api/migrations/v0.12.2/up.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE imprint
- ADD COLUMN crossmark_doi TEXT CHECK (crossmark_doi ~* 'https:\/\/doi.org\/10.\d{4,9}\/[-._\;\(\)\/:a-zA-Z0-9]+$');
diff --git a/thoth-api/migrations/v0.12.3/down.sql b/thoth-api/migrations/v0.12.3/down.sql
deleted file mode 100644
index 36c5925f..00000000
--- a/thoth-api/migrations/v0.12.3/down.sql
+++ /dev/null
@@ -1,12 +0,0 @@
-ALTER TABLE series
- ALTER COLUMN issn_print SET NOT NULL;
-
-ALTER TABLE series
- ALTER COLUMN issn_digital SET NOT NULL;
-
-ALTER TABLE work
- DROP CONSTRAINT work_active_withdrawn_date_check,
- DROP CONSTRAINT work_inactive_no_withdrawn_date_check,
- DROP CONSTRAINT work_withdrawn_date_after_publication_date_check,
- DROP COLUMN withdrawn_date;
-
diff --git a/thoth-api/migrations/v0.12.3/up.sql b/thoth-api/migrations/v0.12.3/up.sql
deleted file mode 100644
index daf55fb8..00000000
--- a/thoth-api/migrations/v0.12.3/up.sql
+++ /dev/null
@@ -1,25 +0,0 @@
-ALTER TABLE series
- ALTER COLUMN issn_print DROP NOT NULL;
-
-ALTER TABLE series
- ALTER COLUMN issn_digital DROP NOT NULL;
-
-ALTER TABLE work
- ADD COLUMN withdrawn_date DATE;
-
-UPDATE work
- SET withdrawn_date = updated_at
- WHERE (work_status = 'withdrawn-from-sale'
- OR work_status = 'out-of-print');
-
-ALTER TABLE work
- ADD CONSTRAINT work_active_withdrawn_date_check CHECK
- ((work_status = 'withdrawn-from-sale' OR work_status = 'out-of-print')
- OR (work_status NOT IN ('withdrawn-from-sale', 'out-of-print') AND withdrawn_date IS NULL)),
-
- ADD CONSTRAINT work_inactive_no_withdrawn_date_check CHECK
- (((work_status = 'withdrawn-from-sale' OR work_status = 'out-of-print') AND withdrawn_date IS NOT NULL)
- OR (work_status NOT IN ('withdrawn-from-sale', 'out-of-print'))),
-
- ADD CONSTRAINT work_withdrawn_date_after_publication_date_check CHECK
- (withdrawn_date IS NULL OR (publication_date < withdrawn_date));
diff --git a/thoth-api/migrations/v0.12.4/down.sql b/thoth-api/migrations/v0.12.4/down.sql
deleted file mode 100644
index 96df703e..00000000
--- a/thoth-api/migrations/v0.12.4/down.sql
+++ /dev/null
@@ -1,33 +0,0 @@
-UPDATE location SET location_platform = 'Other' WHERE location_platform = 'Zenodo';
-
--- Drop the default and unique constraint, otherwise it won't be able to cast to text
-ALTER TABLE location ALTER COLUMN location_platform DROP DEFAULT;
-DROP INDEX location_uniq_platform_idx;
-
-ALTER TABLE location ALTER COLUMN location_platform TYPE text;
-DROP TYPE location_platform;
-CREATE TYPE location_platform AS ENUM (
- 'Project MUSE',
- 'OAPEN',
- 'DOAB',
- 'JSTOR',
- 'EBSCO Host',
- 'OCLC KB',
- 'ProQuest KB',
- 'ProQuest ExLibris',
- 'EBSCO KB',
- 'JISC KB',
- 'Google Books',
- 'Internet Archive',
- 'ScienceOpen',
- 'SciELO Books',
- 'Publisher Website',
- 'Other'
- );
-ALTER TABLE location ALTER location_platform TYPE location_platform USING location_platform::location_platform;
-ALTER TABLE location
- ALTER COLUMN location_platform SET DEFAULT 'Other'::location_platform;
-
-CREATE UNIQUE INDEX location_uniq_platform_idx
- ON location (publication_id, location_platform)
- WHERE NOT location_platform = 'Other'::location_platform;
diff --git a/thoth-api/migrations/v0.12.4/up.sql b/thoth-api/migrations/v0.12.4/up.sql
deleted file mode 100644
index 6aadfa98..00000000
--- a/thoth-api/migrations/v0.12.4/up.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TYPE location_platform ADD VALUE IF NOT EXISTS 'Zenodo';
diff --git a/thoth-api/migrations/v0.12.6/down.sql b/thoth-api/migrations/v0.12.6/down.sql
deleted file mode 100644
index 40680f44..00000000
--- a/thoth-api/migrations/v0.12.6/down.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-ALTER TABLE work DROP CONSTRAINT work_doi_check;
-ALTER TABLE work ADD CONSTRAINT work_doi_check
- CHECK (doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\[\]<>\/:a-zA-Z0-9]+$');
-
-ALTER TABLE reference DROP CONSTRAINT reference_doi_check;
-ALTER TABLE reference ADD CONSTRAINT reference_doi_check
- CHECK (doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\[\]<>\/:a-zA-Z0-9]+$');
-
-ALTER TABLE institution DROP CONSTRAINT institution_institution_doi_check;
-ALTER TABLE institution ADD CONSTRAINT institution_institution_doi_check
- CHECK (institution_doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._\;\(\)\[\]<>\/:a-zA-Z0-9]+$');
diff --git a/thoth-api/migrations/v0.12.6/up.sql b/thoth-api/migrations/v0.12.6/up.sql
deleted file mode 100644
index c3f17d5b..00000000
--- a/thoth-api/migrations/v0.12.6/up.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-ALTER TABLE work DROP CONSTRAINT work_doi_check;
-ALTER TABLE work ADD CONSTRAINT work_doi_check
- CHECK (doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._;()\/:a-zA-Z0-9<>+[\]]+$');
-
-ALTER TABLE reference DROP CONSTRAINT reference_doi_check;
-ALTER TABLE reference ADD CONSTRAINT reference_doi_check
- CHECK (doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._;()\/:a-zA-Z0-9<>+[\]]+$');
-
-ALTER TABLE institution DROP CONSTRAINT institution_institution_doi_check;
-ALTER TABLE institution ADD CONSTRAINT institution_institution_doi_check
- CHECK (institution_doi ~ '^https:\/\/doi\.org\/10\.\d{4,9}\/[-._;()\/:a-zA-Z0-9<>+[\]]+$');
diff --git a/thoth-api/migrations/v0.12.7/down.sql b/thoth-api/migrations/v0.12.7/down.sql
deleted file mode 100644
index 49c63186..00000000
--- a/thoth-api/migrations/v0.12.7/down.sql
+++ /dev/null
@@ -1,33 +0,0 @@
--- We cannot drop individual enum values - we must drop the type and recreate it
-
--- Drop constraints, otherwise it won't be able to cast to text
-ALTER TABLE publication
- DROP CONSTRAINT IF EXISTS publication_publication_type_work_id_uniq,
- DROP CONSTRAINT IF EXISTS publication_non_physical_no_dimensions;
-
--- Delete publications with about-to-be-dropped types
-DELETE FROM publication WHERE publication_type IN ('MP3', 'WAV');
-ALTER TABLE publication ALTER COLUMN publication_type TYPE text;
-DROP TYPE publication_type;
-CREATE TYPE publication_type AS ENUM (
- 'Paperback',
- 'Hardback',
- 'PDF',
- 'HTML',
- 'XML',
- 'Epub',
- 'Mobi',
- 'AZW3',
- 'DOCX',
- 'FictionBook'
-);
-ALTER TABLE publication ALTER COLUMN publication_type TYPE publication_type USING publication_type::publication_type;
-
-ALTER TABLE publication
- ADD CONSTRAINT publication_publication_type_work_id_uniq UNIQUE (publication_type, work_id),
- ADD CONSTRAINT publication_non_physical_no_dimensions CHECK
- ((width_mm IS NULL AND width_in IS NULL
- AND height_mm IS NULL AND height_in IS NULL
- AND depth_mm IS NULL AND depth_in IS NULL
- AND weight_g IS NULL AND weight_oz IS NULL)
- OR publication_type = 'Paperback' OR publication_type = 'Hardback');
diff --git a/thoth-api/migrations/v0.12.7/up.sql b/thoth-api/migrations/v0.12.7/up.sql
deleted file mode 100644
index 47dc3682..00000000
--- a/thoth-api/migrations/v0.12.7/up.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TYPE publication_type ADD VALUE IF NOT EXISTS 'MP3';
-ALTER TYPE publication_type ADD VALUE IF NOT EXISTS 'WAV';
diff --git a/thoth-api/migrations/v0.12.9/down.sql b/thoth-api/migrations/v0.12.9/down.sql
deleted file mode 100644
index 8bd2d0ea..00000000
--- a/thoth-api/migrations/v0.12.9/down.sql
+++ /dev/null
@@ -1,51 +0,0 @@
-ALTER TYPE work_status RENAME VALUE 'withdrawn' TO 'withdrawn-from-sale';
-
-ALTER TABLE work
- -- Drop constraints originally from v0.12.3,
- -- otherwise it won't be able to cast to text
- DROP CONSTRAINT IF EXISTS work_inactive_no_withdrawn_date_check,
- DROP CONSTRAINT IF EXISTS work_active_withdrawn_date_check,
- -- Drop new constraint from v.0.12.9
- DROP CONSTRAINT IF EXISTS work_active_publication_date_check;
-
-ALTER TABLE work ALTER COLUMN work_status TYPE text;
-
--- !!! if this down migration is run, 'out-of-print' should
--- be treated as a placeholder work_status.
--- Works will need to be manually reassigned correct work_status:
--- out-of-print, out-of-stock-indefinitely, or inactive
--- This needs to be run because superseded is a new work_status
--- that is removed in this down migration.
-UPDATE work
- SET work_status = 'out-of-print'
- WHERE work_status = 'superseded';
-
-DROP TYPE work_status;
-
-CREATE TYPE work_status AS ENUM (
- 'unspecified',
- 'cancelled',
- 'forthcoming',
- 'postponed-indefinitely',
- 'active',
- 'no-longer-our-product',
- 'out-of-stock-indefinitely',
- 'out-of-print',
- 'inactive',
- 'unknown',
- 'remaindered',
- 'withdrawn-from-sale',
- 'recalled'
-);
-
-ALTER TABLE work ALTER COLUMN work_status TYPE work_status USING work_status::work_status;
-
--- add constraints back to work table
-ALTER TABLE work
- ADD CONSTRAINT work_active_withdrawn_date_check CHECK
- ((work_status = 'withdrawn-from-sale' OR work_status = 'out-of-print')
- OR (work_status NOT IN ('withdrawn-from-sale', 'out-of-print') AND withdrawn_date IS NULL)),
-
- ADD CONSTRAINT work_inactive_no_withdrawn_date_check CHECK
- (((work_status = 'withdrawn-from-sale' OR work_status = 'out-of-print') AND withdrawn_date IS NOT NULL)
- OR (work_status NOT IN ('withdrawn-from-sale', 'out-of-print')));
diff --git a/thoth-api/migrations/v0.12.9/up.sql b/thoth-api/migrations/v0.12.9/up.sql
deleted file mode 100644
index 08795bc8..00000000
--- a/thoth-api/migrations/v0.12.9/up.sql
+++ /dev/null
@@ -1,104 +0,0 @@
-ALTER TYPE work_status RENAME VALUE 'withdrawn-from-sale' TO 'withdrawn';
-
--- Assign 1900-01-01 as placeholder publication_date for
--- Active, withdrawn from sale, out of print, out of stock indefinitely works with no publication date
--- Required for work_active_publication_date_check constraint below
--- Affected works in production db with this status, 29-05-2024: 59 works (incl. chapters)
--- Before running migration, make a list of affected works
--- After running migration, publishers should be notified to add correct publication_date
--- !!! This is irreversible
-UPDATE work
- SET
- publication_date = '1900-01-01'
- WHERE
- work_status IN
- ('active', 'withdrawn', 'out-of-print', 'out-of-stock-indefinitely', 'inactive')
- AND publication_date IS NULL;
-
--- Drop constraints, otherwise it won't be able to cast to text
-ALTER TABLE work
- DROP CONSTRAINT IF EXISTS work_active_withdrawn_date_check,
- DROP CONSTRAINT IF EXISTS work_inactive_no_withdrawn_date_check;
-
-ALTER TABLE work ALTER COLUMN work_status TYPE text;
-
--- delete unused work_status enum
-DROP TYPE work_status;
-
--- Assign out of print/inactive/out of stock indefinitely works work_status 'superseded'
--- current counts in production db as of 29-05-2024:
--- 145 works (incl. chapters)
--- Before running migration, make a list of affected works
--- After running migration, publishers should be notified to add correct work_status
--- and remove withdrawn_date as necessary. Many OBP "out of print" works are actually first editions
--- for which superseded is the correct new work_status.
--- !!! This is irreversible
-UPDATE work
- SET
- work_status = 'superseded',
- -- assign a withdrawn_date, which is required for superseded works
- withdrawn_date = CASE
- WHEN withdrawn_date IS NOT NULL THEN withdrawn_date
- -- + INTERVAL '1 day' is necessary because at least one work has publication_date on
- -- the same day as updated_at, but updated_at has a timestamp, so it's
- -- greater than. Which then throws an error with the
- -- work_withdrawn_date_after_publication_date_check constraint.
- WHEN withdrawn_date IS NULL AND publication_date + INTERVAL '1 day' < updated_at THEN updated_at
- ELSE CURRENT_DATE
- END
- WHERE
- work_status = 'out-of-print'
- OR work_status = 'out-of-stock-indefinitely'
- OR work_status = 'inactive';
-
--- Assign unspecified/unkown works work_status 'forthcoming'
--- current counts in production db as of 29-05-2024:
--- unspecified, 0 works
--- unknown, 0 works
--- !!! This is irreversible
-UPDATE work
- SET work_status = 'forthcoming'
- WHERE work_status = 'unspecified' OR work_status = 'unknown';
-
--- Assign no longer our product/remaindered/recalled works work_status 'withdrawn-from-sale'
--- current counts in production db as of 29-05-2024:
--- no-longer-our-product, 0 works
--- remaindered, 0 works
--- recalled, 0 works
--- !!! This is irreversible
-UPDATE work
- SET
- work_status = 'withdrawn',
- withdrawn_date = COALESCE(withdrawn_date, updated_at)
- WHERE
- work_status = 'no-longer-our-product'
- OR work_status = 'remaindered'
- OR work_status = 'recalled';
-
--- create new work_status enum, adds superseded
-CREATE TYPE work_status AS ENUM (
- 'cancelled',
- 'forthcoming',
- 'postponed-indefinitely',
- 'active',
- 'withdrawn',
- 'superseded'
-);
-ALTER TABLE work ALTER COLUMN work_status TYPE work_status USING work_status::work_status;
-
--- add new constraints (with same names as in v0.12.3) to work table
-ALTER TABLE work
- -- withdrawn and superseded works must have withdrawn_date
- -- note that this constraint has the same name as migration from v.0.12.3,
- -- but changes previous constraint by adding superseded alongside withdrawn
- ADD CONSTRAINT work_inactive_no_withdrawn_date_check CHECK
- (((work_status = 'withdrawn' OR work_status = 'superseded') AND withdrawn_date IS NOT NULL)
- OR (work_status NOT IN ('withdrawn', 'superseded'))),
- -- all other work statuses must not have withdrawn_date; see above, adds superseded
- ADD CONSTRAINT work_active_withdrawn_date_check CHECK
- ((work_status = 'withdrawn' OR work_status = 'superseded')
- OR (work_status NOT IN ('withdrawn', 'superseded') AND withdrawn_date IS NULL)),
- -- active, withdrawn-from-sale, and superseded works must have publication_date
- ADD CONSTRAINT work_active_publication_date_check CHECK
- ((work_status IN ('active', 'withdrawn', 'superseded') AND publication_date IS NOT NULL)
- OR (work_status NOT IN ('active', 'withdrawn', 'superseded')));
diff --git a/thoth-api/migrations/v0.13.0/down.sql b/thoth-api/migrations/v0.13.0/down.sql
deleted file mode 100644
index 7207af34..00000000
--- a/thoth-api/migrations/v0.13.0/down.sql
+++ /dev/null
@@ -1,34 +0,0 @@
-UPDATE location SET location_platform = 'Other' WHERE location_platform = 'Thoth';
-
--- Drop the default and unique constraint, otherwise it won't be able to cast to text
-ALTER TABLE location ALTER COLUMN location_platform DROP DEFAULT;
-DROP INDEX location_uniq_platform_idx;
-
-ALTER TABLE location ALTER COLUMN location_platform TYPE text;
-DROP TYPE location_platform;
-CREATE TYPE location_platform AS ENUM (
- 'Project MUSE',
- 'OAPEN',
- 'DOAB',
- 'JSTOR',
- 'EBSCO Host',
- 'OCLC KB',
- 'ProQuest KB',
- 'ProQuest ExLibris',
- 'EBSCO KB',
- 'JISC KB',
- 'Google Books',
- 'Internet Archive',
- 'ScienceOpen',
- 'SciELO Books',
- 'Publisher Website',
- 'Zenodo',
- 'Other'
- );
-ALTER TABLE location ALTER location_platform TYPE location_platform USING location_platform::location_platform;
-ALTER TABLE location
- ALTER COLUMN location_platform SET DEFAULT 'Other'::location_platform;
-
-CREATE UNIQUE INDEX location_uniq_platform_idx
- ON location (publication_id, location_platform)
- WHERE NOT location_platform = 'Other'::location_platform;
diff --git a/thoth-api/migrations/v0.13.0/up.sql b/thoth-api/migrations/v0.13.0/up.sql
deleted file mode 100644
index 505e038b..00000000
--- a/thoth-api/migrations/v0.13.0/up.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TYPE location_platform ADD VALUE IF NOT EXISTS 'Thoth';
diff --git a/thoth-api/migrations/v0.13.1/down.sql b/thoth-api/migrations/v0.13.1/down.sql
deleted file mode 100644
index 1ce4f65e..00000000
--- a/thoth-api/migrations/v0.13.1/down.sql
+++ /dev/null
@@ -1,100 +0,0 @@
--- Remove indexes from account table
-DROP INDEX IF EXISTS idx_account_email;
-
--- Remove indexes from publisher_account table
-DROP INDEX IF EXISTS idx_publisher_account_account_id;
-
--- Remove indexes from work table
-DROP INDEX IF EXISTS idx_work_doi;
-DROP INDEX IF EXISTS idx_work_reference;
-DROP INDEX IF EXISTS idx_work_short_abstract_substr;
-DROP INDEX IF EXISTS idx_work_long_abstract_substr;
-DROP INDEX IF EXISTS idx_work_landing_page;
-DROP INDEX IF EXISTS idx_work_imprint_id;
-DROP INDEX IF EXISTS idx_work_updated_at_with_relations_desc;
-DROP INDEX IF EXISTS idx_work_full_title_asc;
-DROP INDEX IF EXISTS idx_work_publication_date_asc;
-DROP INDEX IF EXISTS idx_work_publication_date_desc;
-DROP INDEX IF EXISTS idx_work_type_status_pub_date_desc;
-DROP INDEX IF EXISTS idx_work_books_pub_date_desc;
-
--- Remove indexes from work_relation table
-DROP INDEX IF EXISTS idx_work_relation_relation_ordinal_relator_relation_type_asc;
-DROP INDEX IF EXISTS idx_work_relation_relation_ordinal_related_relation_type_asc;
-
--- Remove indexes from publisher table
-DROP INDEX IF EXISTS idx_publisher_publisher_name;
-DROP INDEX IF EXISTS idx_publisher_publisher_shortname;
-
--- Remove indexes from imprint table
-DROP INDEX IF EXISTS idx_imprint_imprint_name;
-DROP INDEX IF EXISTS idx_imprint_imprint_url;
-DROP INDEX IF EXISTS idx_imprint_publisher_id;
-
--- Remove indexes from subject table
-DROP INDEX IF EXISTS idx_subject_subject_code_asc;
-DROP INDEX IF EXISTS idx_subject_subject_ordinal_asc;
-
--- Remove indexes from publication table
-DROP INDEX IF EXISTS idx_publication_work_id;
-DROP INDEX IF EXISTS idx_publication_isbn;
-DROP INDEX IF EXISTS idx_publication_publication_type;
-
--- Remove indexes from location table
-DROP INDEX IF EXISTS idx_location_location_platform_asc;
-
--- Remove indexes from price table
-DROP INDEX IF EXISTS idx_price_currency_code_asc;
-
--- Remove indexes from contributor table
-DROP INDEX IF EXISTS idx_contributor_full_name;
-DROP INDEX IF EXISTS idx_contributor_last_name;
-DROP INDEX IF EXISTS idx_contributor_orcid;
-
--- Remove indexes from contribution table
-DROP INDEX IF EXISTS idx_contribution_work_id;
-DROP INDEX IF EXISTS idx_contribution_contributor_id;
-DROP INDEX IF EXISTS idx_contribution_ordinal_asc;
-
--- Remove indexes from affiliation table
-DROP INDEX IF EXISTS idx_affiliation_contribution_id;
-DROP INDEX IF EXISTS idx_affiliation_ordinal_asc;
-
--- Remove indexes from institution table
-DROP INDEX IF EXISTS idx_institution_institution_name;
-DROP INDEX IF EXISTS idx_institution_ror;
-DROP INDEX IF EXISTS idx_institution_institution_doi;
-
--- Remove indexes from funding table
-DROP INDEX IF EXISTS idx_funding_work_id;
-DROP INDEX IF EXISTS idx_funding_program;
-
--- Remove indexes from series table
-DROP INDEX IF EXISTS idx_series_series_name;
-DROP INDEX IF EXISTS idx_series_issn_print;
-DROP INDEX IF EXISTS idx_series_issn_digital;
-DROP INDEX IF EXISTS idx_series_series_url;
-DROP INDEX IF EXISTS idx_series_series_description;
-DROP INDEX IF EXISTS idx_series_imprint_id;
-
--- Remove indexes from issue table
-DROP INDEX IF EXISTS idx_issue_ordinal_work_id_asc;
-DROP INDEX IF EXISTS idx_issue_ordinal_series_id_asc;
-
--- Remove indexes from language table
-DROP INDEX IF EXISTS idx_language_language_code_asc;
-
--- Remove indexes from reference table
-DROP INDEX IF EXISTS idx_reference_work_id;
-DROP INDEX IF EXISTS idx_reference_doi;
-DROP INDEX IF EXISTS idx_reference_unstructured_citation;
-DROP INDEX IF EXISTS idx_reference_issn;
-DROP INDEX IF EXISTS idx_reference_isbn;
-DROP INDEX IF EXISTS idx_reference_journal_title;
-DROP INDEX IF EXISTS idx_reference_article_title;
-DROP INDEX IF EXISTS idx_reference_series_title;
-DROP INDEX IF EXISTS idx_reference_volume_title;
-DROP INDEX IF EXISTS idx_reference_author_substr;
-DROP INDEX IF EXISTS idx_reference_standard_designator;
-DROP INDEX IF EXISTS idx_reference_standards_body_name;
-DROP INDEX IF EXISTS idx_reference_standards_body_acronym;
diff --git a/thoth-api/migrations/v0.13.1/up.sql b/thoth-api/migrations/v0.13.1/up.sql
deleted file mode 100644
index c8e408b1..00000000
--- a/thoth-api/migrations/v0.13.1/up.sql
+++ /dev/null
@@ -1,105 +0,0 @@
--- Indexes account table
-CREATE INDEX idx_account_email ON account (email);
-
--- Indexes publisher_account table
-CREATE INDEX idx_publisher_account_account_id ON publisher_account (account_id);
-
--- Indexes work table
-CREATE INDEX idx_work_doi ON work (doi);
-CREATE INDEX idx_work_reference ON work (reference);
-CREATE INDEX idx_work_short_abstract_substr ON work (substring(short_abstract FROM 1 FOR 255));
-CREATE INDEX idx_work_long_abstract_substr ON work (substring(long_abstract FROM 1 FOR 255));
-CREATE INDEX idx_work_landing_page ON work (landing_page);
-CREATE INDEX idx_work_imprint_id ON work (imprint_id);
-CREATE INDEX idx_work_updated_at_with_relations_desc ON work (updated_at_with_relations DESC, work_id);
-CREATE INDEX idx_work_full_title_asc ON work (full_title ASC, work_id);
-CREATE INDEX idx_work_publication_date_asc ON work (publication_date ASC, work_id);
-CREATE INDEX idx_work_publication_date_desc ON work (publication_date DESC, work_id);
-CREATE INDEX idx_work_type_status_pub_date_desc
- ON work (work_type, work_status, publication_date DESC);
-CREATE INDEX idx_work_books_pub_date_desc
- ON work (publication_date DESC)
- WHERE work_type IN ('monograph', 'edited-book', 'textbook') AND work_status = 'active';
-
--- Indexes work_relation table
-CREATE INDEX idx_work_relation_relation_ordinal_relator_relation_type_asc
- ON work_relation (relation_ordinal ASC, relator_work_id, relation_type);
-CREATE INDEX idx_work_relation_relation_ordinal_related_relation_type_asc
- ON work_relation (relation_ordinal ASC, related_work_id, relation_type);
-
--- Indexes publisher table
-CREATE INDEX idx_publisher_publisher_name ON publisher (publisher_name);
-CREATE INDEX idx_publisher_publisher_shortname ON publisher (publisher_shortname);
-
--- Indexes imprint table
-CREATE INDEX idx_imprint_imprint_name ON imprint (imprint_name);
-CREATE INDEX idx_imprint_imprint_url ON imprint (imprint_url);
-CREATE INDEX idx_imprint_publisher_id ON imprint (publisher_id);
-
--- Indexes subject table
-CREATE INDEX idx_subject_subject_code_asc ON subject (subject_code ASC, work_id);
-CREATE INDEX idx_subject_subject_ordinal_asc ON subject (subject_ordinal ASC, work_id);
-
--- Indexes publication table
-CREATE INDEX idx_publication_work_id ON publication (work_id);
-CREATE INDEX idx_publication_isbn ON publication (isbn);
-CREATE INDEX idx_publication_publication_type ON publication (publication_type);
-
--- Indexes location table
-CREATE INDEX idx_location_location_platform_asc ON location (location_platform ASC, publication_id);
-
--- Indexes price table
-CREATE INDEX idx_price_currency_code_asc ON price (currency_code ASC, publication_id);
-
--- Indexes contributor table
-CREATE INDEX idx_contributor_full_name ON contributor (full_name);
-CREATE INDEX idx_contributor_last_name ON contributor (last_name);
-CREATE INDEX idx_contributor_orcid ON contributor (orcid);
-
--- Indexes contribution table
-CREATE INDEX idx_contribution_work_id ON contribution (work_id);
-CREATE INDEX idx_contribution_contributor_id ON contribution (contributor_id);
-CREATE INDEX idx_contribution_ordinal_asc ON contribution (contribution_ordinal ASC, work_id);
-
--- Indexes affiliation table
-CREATE INDEX idx_affiliation_contribution_id ON affiliation (contribution_id);
-CREATE INDEX idx_affiliation_ordinal_asc ON affiliation (affiliation_ordinal ASC, contribution_id);
-
--- Indexes contributor table
-CREATE INDEX idx_institution_institution_name ON institution (institution_name);
-CREATE INDEX idx_institution_ror ON institution (ror);
-CREATE INDEX idx_institution_institution_doi ON institution (institution_doi);
-
--- Indexes funding table
-CREATE INDEX idx_funding_work_id ON funding (work_id);
-CREATE INDEX idx_funding_program ON funding (program);
-
--- Indexes series table
-CREATE INDEX idx_series_series_name ON series (series_name);
-CREATE INDEX idx_series_issn_print ON series (issn_print);
-CREATE INDEX idx_series_issn_digital ON series (issn_digital);
-CREATE INDEX idx_series_series_url ON series (series_url);
-CREATE INDEX idx_series_series_description ON series (series_description);
-CREATE INDEX idx_series_imprint_id ON series (imprint_id);
-
--- Indexes issue table
-CREATE INDEX idx_issue_ordinal_work_id_asc ON issue (issue_ordinal ASC, work_id);
-CREATE INDEX idx_issue_ordinal_series_id_asc ON issue (issue_ordinal ASC, series_id);
-
--- Indexes language table
-CREATE INDEX idx_language_language_code_asc ON language (language_code ASC, work_id);
-
--- Indexes reference table
-CREATE INDEX idx_reference_work_id ON reference (work_id);
-CREATE INDEX idx_reference_doi ON reference (doi);
-CREATE INDEX idx_reference_unstructured_citation ON reference (unstructured_citation);
-CREATE INDEX idx_reference_issn ON reference (issn);
-CREATE INDEX idx_reference_isbn ON reference (isbn);
-CREATE INDEX idx_reference_journal_title ON reference (journal_title);
-CREATE INDEX idx_reference_article_title ON reference (article_title);
-CREATE INDEX idx_reference_series_title ON reference (series_title);
-CREATE INDEX idx_reference_volume_title ON reference (volume_title);
-CREATE INDEX idx_reference_author_substr ON reference ((substring(author FROM 1 FOR 255)));
-CREATE INDEX idx_reference_standard_designator ON reference (standard_designator);
-CREATE INDEX idx_reference_standards_body_name ON reference (standards_body_name);
-CREATE INDEX idx_reference_standards_body_acronym ON reference (standards_body_acronym);
diff --git a/thoth-api/src/account/handler.rs b/thoth-api/src/account/handler.rs
deleted file mode 100644
index dfa36608..00000000
--- a/thoth-api/src/account/handler.rs
+++ /dev/null
@@ -1,216 +0,0 @@
-use diesel::prelude::*;
-use dotenv::dotenv;
-use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
-use regex::Regex;
-use std::env;
-use std::time::SystemTime;
-use std::time::UNIX_EPOCH;
-use uuid::Uuid;
-
-use crate::account::{
- model::{
- Account, AccountAccess, AccountData, DecodedToken, LinkedPublisher, NewAccount,
- NewPassword, NewPublisherAccount, PublisherAccount, Token,
- },
- service::get_account,
- util::{make_hash, make_salt},
-};
-use crate::db::PgPool;
-use thoth_errors::{ThothError, ThothResult};
-
-impl Account {
- pub fn get_permissions(&self, pool: &PgPool) -> ThothResult> {
- let publisher_accounts = self.get_publisher_accounts(pool)?;
- let permissions: Vec =
- publisher_accounts.into_iter().map(|p| p.into()).collect();
- Ok(permissions)
- }
-
- pub fn get_publisher_accounts(&self, pool: &PgPool) -> ThothResult> {
- use crate::schema::publisher_account::dsl::*;
- let mut conn = pool.get()?;
-
- let publisher_accounts = publisher_account
- .filter(account_id.eq(self.account_id))
- .load::(&mut conn)
- .expect("Error loading publisher accounts");
- Ok(publisher_accounts)
- }
-
- pub fn add_publisher_account(
- &self,
- pool: &PgPool,
- linked_publisher: LinkedPublisher,
- ) -> ThothResult {
- use crate::schema::publisher_account::dsl::*;
- let mut conn = pool.get()?;
- let new_publisher_account = NewPublisherAccount {
- account_id: self.account_id,
- publisher_id: linked_publisher.publisher_id,
- is_admin: linked_publisher.is_admin,
- };
- diesel::insert_into(publisher_account)
- .values(&new_publisher_account)
- .get_result::(&mut conn)
- .map_err(Into::into)
- }
-
- pub fn get_account_access(&self, linked_publishers: Vec) -> AccountAccess {
- AccountAccess {
- is_superuser: self.is_superuser,
- is_bot: self.is_bot,
- linked_publishers,
- }
- }
-
- pub fn issue_token(&self, pool: &PgPool) -> ThothResult {
- const DEFAULT_TOKEN_VALIDITY: i64 = 24 * 60 * 60;
- let mut connection = pool.get()?;
- dotenv().ok();
- let linked_publishers: Vec =
- self.get_permissions(pool).unwrap_or_default();
- let namespace = self.get_account_access(linked_publishers);
- let secret_str = env::var("SECRET_KEY").expect("SECRET_KEY must be set");
- let secret: &[u8] = secret_str.as_bytes();
- let now = SystemTime::now()
- .duration_since(UNIX_EPOCH)
- .map_err(|_| ThothError::InternalError("Unable to set token iat".into()))?;
- let claim = Token {
- sub: self.email.clone(),
- exp: now.as_secs() as i64 + DEFAULT_TOKEN_VALIDITY,
- iat: now.as_secs() as i64,
- jti: Uuid::new_v4().to_string(),
- namespace,
- };
- let token = encode(
- &Header::default(),
- &claim,
- &EncodingKey::from_secret(secret),
- )
- .map_err(|_| ThothError::InternalError("Unable to create token".into()));
-
- use crate::schema::account::dsl;
- let updated_account = diesel::update(dsl::account.find(self.account_id))
- .set(dsl::token.eq(token?))
- .get_result::(&mut connection)
- .expect("Unable to set token");
- Ok(updated_account.token.unwrap())
- }
-}
-
-impl From for NewAccount {
- fn from(account_data: AccountData) -> Self {
- let AccountData {
- name,
- surname,
- email,
- password,
- is_superuser,
- is_bot,
- ..
- } = account_data;
-
- let salt = make_salt();
- let hash = make_hash(&password, &salt).to_vec();
- Self {
- name,
- surname,
- email,
- hash,
- salt,
- is_superuser,
- is_bot,
- }
- }
-}
-
-impl From for LinkedPublisher {
- fn from(publisher_account: PublisherAccount) -> Self {
- let PublisherAccount {
- publisher_id,
- is_admin,
- ..
- } = publisher_account;
- Self {
- publisher_id,
- is_admin,
- }
- }
-}
-
-impl Token {
- pub fn verify(token: &str) -> ThothResult {
- dotenv().ok();
- let secret_str = env::var("SECRET_KEY").expect("SECRET_KEY must be set");
- let secret: &[u8] = secret_str.as_bytes();
-
- let data = decode::(
- token,
- &DecodingKey::from_secret(secret),
- &Validation::default(),
- )
- .map_err(|_| ThothError::InvalidToken)?;
- Ok(data.claims)
- }
-
- pub fn account_id(&self, pool: &PgPool) -> Uuid {
- get_account(&self.sub, pool).unwrap().account_id
- }
-}
-
-lazy_static::lazy_static! {
- static ref BEARER_REGEXP : Regex = Regex::new(r"^Bearer\s(.*)$").expect("Bearer regexp failed!");
-}
-
-impl actix_web::FromRequest for DecodedToken {
- type Error = actix_web::Error;
- type Future = futures::future::Ready>;
-
- fn from_request(req: &actix_web::HttpRequest, _: &mut actix_web::dev::Payload) -> Self::Future {
- let token = req
- .headers()
- .get(actix_web::http::header::AUTHORIZATION)
- .and_then(|v| v.to_str().ok())
- .and_then(|authorization| {
- BEARER_REGEXP
- .captures(authorization)
- .and_then(|captures| captures.get(1))
- })
- .map(|v| v.as_str());
-
- futures::future::ready(Ok(match token {
- None => DecodedToken { jwt: None },
- Some(token) => match Token::verify(token) {
- Ok(decoded) => DecodedToken { jwt: Some(decoded) },
- Err(_) => DecodedToken { jwt: None },
- },
- }))
- }
-}
-
-impl NewPassword {
- pub fn new(email: String, password: String) -> Self {
- let salt = make_salt();
- let hash = make_hash(&password, &salt).to_vec();
- Self { email, hash, salt }
- }
-}
-
-impl PublisherAccount {
- pub fn delete(&self, pool: &PgPool) -> ThothResult<()> {
- use crate::schema::publisher_account::dsl::*;
-
- pool.get()?.transaction(|connection| {
- diesel::delete(
- publisher_account.filter(
- account_id
- .eq(self.account_id)
- .and(publisher_id.eq(self.publisher_id)),
- ),
- )
- .execute(connection)
- .map(|_| ())
- .map_err(Into::into)
- })
- }
-}
diff --git a/thoth-api/src/account/mod.rs b/thoth-api/src/account/mod.rs
deleted file mode 100644
index 225e37d9..00000000
--- a/thoth-api/src/account/mod.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#[cfg(feature = "backend")]
-pub mod handler;
-pub mod model;
-#[cfg(feature = "backend")]
-pub mod service;
-#[cfg(feature = "backend")]
-pub mod util;
diff --git a/thoth-api/src/account/model.rs b/thoth-api/src/account/model.rs
deleted file mode 100644
index 773c54cc..00000000
--- a/thoth-api/src/account/model.rs
+++ /dev/null
@@ -1,164 +0,0 @@
-use serde::{Deserialize, Serialize};
-use uuid::Uuid;
-
-use crate::model::Timestamp;
-#[cfg(feature = "backend")]
-use crate::schema::account;
-#[cfg(feature = "backend")]
-use crate::schema::publisher_account;
-use thoth_errors::ThothError;
-use thoth_errors::ThothResult;
-
-#[cfg_attr(feature = "backend", derive(Queryable))]
-#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
-pub struct Account {
- pub account_id: Uuid,
- pub name: String,
- pub surname: String,
- pub email: String,
- pub hash: Vec,
- pub salt: String,
- pub is_superuser: bool,
- pub is_bot: bool,
- pub is_active: bool,
- pub created_at: Timestamp,
- pub updated_at: Timestamp,
- pub token: Option,
-}
-
-#[cfg_attr(feature = "backend", derive(Insertable))]
-#[cfg_attr(feature = "backend", diesel(table_name = account))]
-pub struct NewAccount {
- pub name: String,
- pub surname: String,
- pub email: String,
- pub hash: Vec,
- pub salt: String,
- pub is_superuser: bool,
- pub is_bot: bool,
-}
-
-#[derive(Debug)]
-pub struct AccountData {
- pub name: String,
- pub surname: String,
- pub email: String,
- pub password: String,
- pub is_superuser: bool,
- pub is_bot: bool,
-}
-
-#[cfg_attr(feature = "backend", derive(Queryable))]
-pub struct PublisherAccount {
- pub account_id: Uuid,
- pub publisher_id: Uuid,
- pub is_admin: bool,
- pub created_at: Timestamp,
- pub updated_at: Timestamp,
-}
-
-#[cfg_attr(feature = "backend", derive(Insertable))]
-#[cfg_attr(feature = "backend", diesel(table_name = publisher_account))]
-pub struct NewPublisherAccount {
- pub account_id: Uuid,
- pub publisher_id: Uuid,
- pub is_admin: bool,
-}
-
-#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-#[serde(rename_all = "camelCase")]
-pub struct AccountAccess {
- pub is_superuser: bool,
- pub is_bot: bool,
- pub linked_publishers: Vec,
-}
-
-#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-#[serde(rename_all = "camelCase")]
-pub struct LinkedPublisher {
- pub publisher_id: Uuid,
- pub is_admin: bool,
-}
-
-#[derive(Debug, Clone, Deserialize, Serialize)]
-pub struct Token {
- pub sub: String,
- pub exp: i64,
- pub iat: i64,
- pub jti: String,
- #[serde(rename = "https://thoth.pub/resource_access")]
- pub namespace: AccountAccess,
-}
-
-#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
-#[serde(rename_all = "camelCase")]
-pub struct AccountDetails {
- pub account_id: Uuid,
- pub name: String,
- pub surname: String,
- pub email: String,
- pub token: Option,
- pub created_at: Timestamp,
- pub updated_at: Timestamp,
- pub resource_access: AccountAccess,
-}
-
-#[derive(Debug, Clone)]
-pub struct DecodedToken {
- pub jwt: Option,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Default)]
-pub struct LoginCredentials {
- pub email: String,
- pub password: String,
-}
-
-#[cfg_attr(feature = "backend", derive(AsChangeset), diesel(table_name = account))]
-pub struct NewPassword {
- pub email: String,
- pub hash: Vec,
- pub salt: String,
-}
-
-impl DecodedToken {
- pub fn get_user_permissions(&self) -> AccountAccess {
- if let Some(jwt) = &self.jwt {
- jwt.namespace.clone()
- } else {
- AccountAccess {
- is_superuser: false,
- is_bot: false,
- linked_publishers: vec![],
- }
- }
- }
-}
-
-impl AccountAccess {
- pub fn can_edit(&self, publisher_id: Uuid) -> ThothResult<()> {
- if self.is_superuser
- || self
- .linked_publishers
- .iter()
- .any(|publisher| publisher.publisher_id == publisher_id)
- {
- Ok(())
- } else {
- Err(ThothError::Unauthorised)
- }
- }
-
- pub fn restricted_to(&self) -> Option> {
- if self.is_superuser {
- None
- } else {
- Some(
- self.linked_publishers
- .iter()
- .map(|publisher| publisher.publisher_id.to_string())
- .collect(),
- )
- }
- }
-}
diff --git a/thoth-api/src/account/service.rs b/thoth-api/src/account/service.rs
deleted file mode 100644
index 45943391..00000000
--- a/thoth-api/src/account/service.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-use diesel::prelude::*;
-
-use crate::account::{
- model::{Account, AccountData, AccountDetails, LinkedPublisher, NewAccount, NewPassword},
- util::verify,
-};
-use crate::db::PgPool;
-use crate::model::publisher::Publisher;
-use thoth_errors::{ThothError, ThothResult};
-
-pub fn login(user_email: &str, user_password: &str, pool: &PgPool) -> ThothResult {
- use crate::schema::account::dsl;
-
- let mut conn = pool.get()?;
- let account = dsl::account
- .filter(dsl::email.eq(user_email))
- .first::(&mut conn)
- .map_err(|_| ThothError::Unauthorised)?;
-
- if verify(&account, user_password) {
- Ok(account)
- } else {
- Err(ThothError::Unauthorised)
- }
-}
-
-pub fn get_account(email: &str, pool: &PgPool) -> ThothResult {
- use crate::schema::account::dsl;
-
- let mut conn = pool.get()?;
- let account = dsl::account
- .filter(dsl::email.eq(email))
- .first::(&mut conn)
- .map_err(|_| ThothError::Unauthorised)?;
- Ok(account)
-}
-
-pub fn get_account_details(email: &str, pool: &PgPool) -> ThothResult {
- use crate::schema::account::dsl;
-
- let mut conn = pool.get()?;
- let account = dsl::account
- .filter(dsl::email.eq(email))
- .first::(&mut conn)
- .map_err(|_| ThothError::Unauthorised)?;
- let linked_publishers: Vec = account.get_permissions(pool).unwrap_or_default();
- let resource_access = account.get_account_access(linked_publishers);
- let account_details = AccountDetails {
- account_id: account.account_id,
- name: account.name,
- surname: account.surname,
- email: account.email,
- token: account.token,
- created_at: account.created_at,
- updated_at: account.updated_at,
- resource_access,
- };
- Ok(account_details)
-}
-
-pub fn register(
- pool: &PgPool,
- name: String,
- surname: String,
- email: String,
- password: String,
- is_superuser: bool,
- is_bot: bool,
-) -> ThothResult {
- use crate::schema::account::dsl;
-
- let mut connection = pool.get()?;
- let account: NewAccount = AccountData {
- name,
- surname,
- email,
- password,
- is_superuser,
- is_bot,
- }
- .into();
- let created_account: Account = diesel::insert_into(dsl::account)
- .values(&account)
- .get_result::(&mut connection)?;
- Ok(created_account)
-}
-
-pub fn all_emails(pool: &PgPool) -> ThothResult> {
- let mut connection = pool.get()?;
-
- use crate::schema::account::dsl;
- let emails = dsl::account
- .select((dsl::email, dsl::is_superuser, dsl::is_bot, dsl::is_active))
- .order(dsl::email.asc())
- .load::<(String, bool, bool, bool)>(&mut connection)
- .map_err(|_| ThothError::InternalError("Unable to load records".into()))?;
- Ok(emails)
-}
-
-pub fn all_publishers(pool: &PgPool) -> ThothResult> {
- let mut connection = pool.get()?;
-
- use crate::schema::publisher::dsl;
- let publishers = dsl::publisher
- .order(dsl::publisher_name.asc())
- .load::(&mut connection)
- .map_err(|_| ThothError::InternalError("Unable to load records".into()))?;
- Ok(publishers)
-}
-
-pub fn update_password(email: &str, password: &str, pool: &PgPool) -> ThothResult {
- let mut connection = pool.get()?;
-
- let new_password = NewPassword::new(email.to_string(), password.to_string());
- use crate::schema::account::dsl;
-
- let account_obj = dsl::account
- .filter(dsl::email.eq(email))
- .first::(&mut connection)
- .map_err(Into::::into)?;
-
- diesel::update(dsl::account.find(&account_obj.account_id))
- .set(&new_password)
- .get_result(&mut connection)
- .map_err(Into::into)
-}
diff --git a/thoth-api/src/account/util.rs b/thoth-api/src/account/util.rs
deleted file mode 100644
index 79d86dca..00000000
--- a/thoth-api/src/account/util.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-use argon2rs::argon2i_simple;
-
-use super::model::Account;
-
-pub fn make_salt() -> String {
- use rand::Rng;
- const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
- abcdefghijklmnopqrstuvwxyz\
- 0123456789)(*&^%$#@!~";
- const PASSWORD_LEN: usize = 128;
- let mut rng = rand::rng();
-
- let password: String = (0..PASSWORD_LEN)
- .map(|_| {
- let idx = rng.random_range(0..CHARSET.len());
- CHARSET[idx] as char
- })
- .collect();
- password
-}
-
-pub fn make_hash(password: &str, salt: &str) -> [u8; argon2rs::defaults::LENGTH] {
- argon2i_simple(password, salt)
-}
-
-pub fn verify(account: &Account, password: &str) -> bool {
- let Account { hash, salt, .. } = account;
-
- make_hash(password, salt) == hash.as_ref()
-}
diff --git a/thoth-api/src/graphql/mod.rs b/thoth-api/src/graphql/mod.rs
index 51e33363..10c37fb3 100644
--- a/thoth-api/src/graphql/mod.rs
+++ b/thoth-api/src/graphql/mod.rs
@@ -1,6 +1,22 @@
-#[cfg(feature = "backend")]
pub mod model;
-pub mod utils;
+pub mod types;
+
+mod mutation;
+mod query;
-#[cfg(feature = "backend")]
pub use juniper::http::GraphQLRequest;
+
+pub use model::Context;
+pub use mutation::MutationRoot;
+pub use query::QueryRoot;
+
+use juniper::{EmptySubscription, RootNode};
+
+pub type Schema = RootNode<'static, QueryRoot, MutationRoot, EmptySubscription>;
+
+pub fn create_schema() -> Schema {
+ Schema::new(QueryRoot {}, MutationRoot {}, EmptySubscription::new())
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/thoth-api/src/graphql/model.rs b/thoth-api/src/graphql/model.rs
index 8a157c52..1f86d622 100644
--- a/thoth-api/src/graphql/model.rs
+++ b/thoth-api/src/graphql/model.rs
@@ -1,2453 +1,270 @@
-use chrono::naive::NaiveDate;
-use juniper::RootNode;
-use juniper::{EmptySubscription, FieldResult};
use std::sync::Arc;
+
+use chrono::naive::NaiveDate;
+use juniper::{FieldError, FieldResult};
use uuid::Uuid;
+use zitadel::actix::introspection::IntrospectedUser;
-use crate::account::model::AccountAccess;
-use crate::account::model::DecodedToken;
+use super::types::inputs::{
+ ContributionOrderBy, Convert, Direction, FundingOrderBy, IssueOrderBy, LanguageOrderBy,
+ LengthUnit, PriceOrderBy, SubjectOrderBy, TimeExpression, WeightUnit,
+};
use crate::db::PgPool;
-use crate::model::affiliation::*;
-use crate::model::contribution::*;
-use crate::model::contributor::*;
-use crate::model::funding::*;
-use crate::model::imprint::*;
-use crate::model::institution::*;
-use crate::model::issue::*;
-use crate::model::language::*;
-use crate::model::location::*;
-use crate::model::price::*;
-use crate::model::publication::*;
-use crate::model::publisher::*;
-use crate::model::reference::*;
-use crate::model::series::*;
-use crate::model::subject::*;
-use crate::model::work::*;
-use crate::model::work_relation::*;
-use crate::model::Convert;
-use crate::model::Crud;
-use crate::model::Doi;
-use crate::model::Isbn;
-use crate::model::LengthUnit;
-use crate::model::Orcid;
-use crate::model::Ror;
-use crate::model::Timestamp;
-use crate::model::WeightUnit;
-use thoth_errors::{ThothError, ThothResult};
-
-use super::utils::{Direction, Expression};
+use crate::markup::{convert_from_jats, ConversionLimit, MarkupFormat};
+use crate::model::{
+ affiliation::{Affiliation, AffiliationOrderBy},
+ biography::{Biography, BiographyOrderBy},
+ contact::{Contact, ContactOrderBy, ContactType},
+ contribution::{Contribution, ContributionType},
+ contributor::Contributor,
+ file::{File, FileType},
+ funding::Funding,
+ imprint::{Imprint, ImprintField, ImprintOrderBy},
+ institution::{CountryCode, Institution},
+ issue::Issue,
+ language::{Language, LanguageCode, LanguageRelation},
+ locale::LocaleCode,
+ location::{Location, LocationOrderBy, LocationPlatform},
+ price::{CurrencyCode, Price},
+ publication::{
+ AccessibilityException, AccessibilityStandard, Publication, PublicationOrderBy,
+ PublicationType,
+ },
+ publisher::Publisher,
+ r#abstract::{Abstract, AbstractOrderBy, AbstractType},
+ reference::{Reference, ReferenceOrderBy},
+ series::{Series, SeriesType},
+ subject::{Subject, SubjectType},
+ title::{Title, TitleOrderBy},
+ work::{Work, WorkOrderBy, WorkStatus, WorkType},
+ work_relation::{RelationType, WorkRelation, WorkRelationOrderBy},
+ Crud, Doi, Isbn, Orcid, Ror, Timestamp,
+};
+use crate::policy::PolicyContext;
+use crate::storage::{CloudFrontClient, S3Client};
+use thoth_errors::ThothError;
impl juniper::Context for Context {}
-#[derive(Clone)]
pub struct Context {
pub db: Arc,
- pub account_access: AccountAccess,
- pub token: DecodedToken,
+ pub user: Option,
+ pub s3_client: Arc,
+ pub cloudfront_client: Arc,
}
impl Context {
- pub fn new(pool: Arc, token: DecodedToken) -> Self {
+ pub fn new(
+ pool: Arc,
+ user: Option,
+ s3_client: Arc,
+ cloudfront_client: Arc,
+ ) -> Self {
Self {
db: pool,
- account_access: token.get_user_permissions(),
- token,
- }
- }
-}
-
-#[derive(juniper::GraphQLInputObject)]
-#[graphql(description = "Field and order to use when sorting contributions list")]
-pub struct ContributionOrderBy {
- pub field: ContributionField,
- pub direction: Direction,
-}
-
-impl Default for ContributionOrderBy {
- fn default() -> ContributionOrderBy {
- ContributionOrderBy {
- field: ContributionField::ContributionType,
- direction: Default::default(),
+ user,
+ s3_client,
+ cloudfront_client,
}
}
-}
-
-#[derive(juniper::GraphQLInputObject)]
-#[graphql(description = "Field and order to use when sorting issues list")]
-pub struct IssueOrderBy {
- pub field: IssueField,
- pub direction: Direction,
-}
-impl Default for IssueOrderBy {
- fn default() -> IssueOrderBy {
- IssueOrderBy {
- field: IssueField::IssueOrdinal,
- direction: Default::default(),
- }
+ pub fn s3_client(&self) -> &S3Client {
+ self.s3_client.as_ref()
}
-}
-
-#[derive(juniper::GraphQLInputObject)]
-#[graphql(description = "Field and order to use when sorting languages list")]
-pub struct LanguageOrderBy {
- pub field: LanguageField,
- pub direction: Direction,
-}
-impl Default for LanguageOrderBy {
- fn default() -> LanguageOrderBy {
- LanguageOrderBy {
- field: LanguageField::LanguageCode,
- direction: Default::default(),
- }
+ pub fn cloudfront_client(&self) -> &CloudFrontClient {
+ self.cloudfront_client.as_ref()
}
}
-#[derive(juniper::GraphQLInputObject)]
-#[graphql(description = "Field and order to use when sorting prices list")]
-pub struct PriceOrderBy {
- pub field: PriceField,
- pub direction: Direction,
-}
-
-impl Default for PriceOrderBy {
- fn default() -> PriceOrderBy {
- PriceOrderBy {
- field: PriceField::CurrencyCode,
- direction: Default::default(),
- }
+impl PolicyContext for Context {
+ fn db(&self) -> &PgPool {
+ &self.db
}
-}
-
-#[derive(juniper::GraphQLInputObject)]
-#[graphql(description = "Field and order to use when sorting subjects list")]
-pub struct SubjectOrderBy {
- pub field: SubjectField,
- pub direction: Direction,
-}
-
-impl Default for SubjectOrderBy {
- fn default() -> SubjectOrderBy {
- SubjectOrderBy {
- field: SubjectField::SubjectType,
- direction: Default::default(),
- }
+ fn user(&self) -> Option<&IntrospectedUser> {
+ self.user.as_ref()
}
}
-#[derive(juniper::GraphQLInputObject)]
-#[graphql(description = "Field and order to use when sorting fundings list")]
-pub struct FundingOrderBy {
- pub field: FundingField,
- pub direction: Direction,
-}
-
-impl Default for FundingOrderBy {
- fn default() -> FundingOrderBy {
- FundingOrderBy {
- field: FundingField::Program,
- direction: Default::default(),
- }
+#[juniper::graphql_object(Context = Context, description = "A written text that can be published")]
+impl Work {
+ #[graphql(description = "Thoth ID of the work")]
+ pub fn work_id(&self) -> &Uuid {
+ &self.work_id
}
-}
-
-#[derive(juniper::GraphQLInputObject)]
-#[graphql(
- description = "Timestamp and choice out of greater than/less than to use when filtering by a time field (e.g. updated_at)"
-)]
-pub struct TimeExpression {
- pub timestamp: Timestamp,
- pub expression: Expression,
-}
-
-pub struct QueryRoot;
-#[juniper::graphql_object(Context = Context)]
-impl QueryRoot {
- #[allow(clippy::too_many_arguments)]
- #[graphql(description = "Query the full list of works")]
- fn works(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on full_title, doi, reference, short_abstract, long_abstract, and landing_page"
- )]
- filter: Option,
- #[graphql(
- default = WorkOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- #[graphql(
- default = vec![],
- description = "Specific types to filter by",
- )]
- work_types: Option>,
- #[graphql(description = "(deprecated) A specific status to filter by")] work_status: Option<
- WorkStatus,
- >,
- #[graphql(
- default = vec![],
- description = "Specific statuses to filter by"
- )]
- work_statuses: Option>,
- #[graphql(
- description = "Only show results updated either before (less than) or after (greater than) the specified timestamp"
- )]
- updated_at_with_relations: Option,
- ) -> FieldResult> {
- let mut statuses = work_statuses.unwrap_or_default();
- if let Some(status) = work_status {
- statuses.push(status);
- }
- Work::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- filter,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- work_types.unwrap_or_default(),
- statuses,
- updated_at_with_relations,
- )
- .map_err(|e| e.into())
+ #[graphql(description = "Type of the work")]
+ pub fn work_type(&self) -> &WorkType {
+ &self.work_type
}
- #[graphql(description = "Query a single work using its ID")]
- fn work(
- context: &Context,
- #[graphql(description = "Thoth work ID to search on")] work_id: Uuid,
- ) -> FieldResult {
- Work::from_id(&context.db, &work_id).map_err(|e| e.into())
+ #[graphql(description = "Publication status of the work")]
+ pub fn work_status(&self) -> &WorkStatus {
+ &self.work_status
}
- #[graphql(description = "Query a single work using its DOI")]
- fn work_by_doi(
- context: &Context,
- #[graphql(description = "Work DOI to search on")] doi: Doi,
- ) -> FieldResult {
- Work::from_doi(&context.db, doi, vec![]).map_err(|e| e.into())
+ #[graphql(description = "Concatenation of title and subtitle with punctuation mark")]
+ #[graphql(
+ deprecated = "Please use Work `titles` field instead to get the correct full title in a multilingual manner"
+ )]
+ pub fn full_title(&self, ctx: &Context) -> FieldResult {
+ Ok(Title::canonical_from_work_id(&ctx.db, &self.work_id)?.full_title)
}
- #[graphql(description = "Get the total number of works")]
- fn work_count(
- context: &Context,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on full_title, doi, reference, short_abstract, long_abstract, and landing_page",
- )]
- filter: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs",
- )]
- publishers: Option>,
- #[graphql(
- default = vec![],
- description = "Specific types to filter by",
- )]
- work_types: Option>,
- #[graphql(description = "(deprecated) A specific status to filter by")] work_status: Option<
- WorkStatus,
- >,
- #[graphql(
- default = vec![],
- description = "Specific statuses to filter by"
- )]
- work_statuses: Option>,
- #[graphql(
- description = "Only show results updated either before (less than) or after (greater than) the specified timestamp"
- )]
- updated_at_with_relations: Option,
- ) -> FieldResult {
- let mut statuses = work_statuses.unwrap_or_default();
- if let Some(status) = work_status {
- statuses.push(status);
- }
- Work::count(
- &context.db,
- filter,
- publishers.unwrap_or_default(),
- work_types.unwrap_or_default(),
- statuses,
- updated_at_with_relations,
- )
- .map_err(|e| e.into())
+ #[graphql(description = "Main title of the work (excluding subtitle)")]
+ #[graphql(
+ deprecated = "Please use Work `titles` field instead to get the correct title in a multilingual manner"
+ )]
+ pub fn title(&self, ctx: &Context) -> FieldResult {
+ Ok(Title::canonical_from_work_id(&ctx.db, &self.work_id)?.title)
}
- #[allow(clippy::too_many_arguments)]
- #[graphql(description = "Query the full list of books (a subset of the full list of works)")]
- fn books(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on full_title, doi, reference, short_abstract, long_abstract, and landing_page"
- )]
- filter: Option,
- #[graphql(
- default = WorkOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- #[graphql(description = "(deprecated) A specific status to filter by")] work_status: Option<
- WorkStatus,
- >,
- #[graphql(
- default = vec![],
- description = "Specific statuses to filter by"
- )]
- work_statuses: Option>,
- #[graphql(
- description = "Only show results updated either before (less than) or after (greater than) the specified timestamp"
- )]
- updated_at_with_relations: Option,
- ) -> FieldResult> {
- let mut statuses = work_statuses.unwrap_or_default();
- if let Some(status) = work_status {
- statuses.push(status);
- }
- Work::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- filter,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- vec![
- WorkType::Monograph,
- WorkType::EditedBook,
- WorkType::Textbook,
- WorkType::JournalIssue,
- ],
- statuses,
- updated_at_with_relations,
- )
- .map_err(|e| e.into())
+ #[graphql(description = "Secondary title of the work (excluding main title)")]
+ #[graphql(
+ deprecated = "Please use Work `titles` field instead to get the correct sub_title in a multilingual manner"
+ )]
+ pub fn subtitle(&self, ctx: &Context) -> FieldResult> {
+ Ok(Title::canonical_from_work_id(&ctx.db, &self.work_id)?.subtitle)
}
- #[graphql(description = "Query a single book using its DOI")]
- fn book_by_doi(
- context: &Context,
- #[graphql(description = "Book DOI to search on")] doi: Doi,
- ) -> FieldResult {
- Work::from_doi(
- &context.db,
- doi,
- vec![
- WorkType::Monograph,
- WorkType::EditedBook,
- WorkType::Textbook,
- WorkType::JournalIssue,
- ],
+ #[graphql(
+ description = "Short abstract of the work. Where a work has two different versions of the abstract, the truncated version should be entered here. Otherwise, it can be left blank. This field is not output in metadata formats; where relevant, Long Abstract is used instead."
+ )]
+ #[graphql(
+ deprecated = "Please use Work `abstracts` field instead to get the correct short abstract in a multilingual manner"
+ )]
+ pub fn short_abstract(&self, ctx: &Context) -> FieldResult> {
+ Ok(
+ Abstract::short_canonical_from_work_id(&ctx.db, &self.work_id)
+ .map(|a| a.content)
+ .ok(),
)
- .map_err(|e| e.into())
}
#[graphql(
- description = "Get the total number of books (a subset of the total number of works)"
+ description = "Abstract of the work. Where a work has only one abstract, it should be entered here, and Short Abstract can be left blank. Long Abstract is output in metadata formats, and Short Abstract is not."
)]
- fn book_count(
- context: &Context,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on full_title, doi, reference, short_abstract, long_abstract, and landing_page"
- )]
- filter: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- #[graphql(description = "(deprecated) A specific status to filter by")] work_status: Option<
- WorkStatus,
- >,
- #[graphql(
- default = vec![],
- description = "Specific statuses to filter by"
- )]
- work_statuses: Option>,
- #[graphql(
- description = "Only show results updated either before (less than) or after (greater than) the specified timestamp"
- )]
- updated_at_with_relations: Option,
- ) -> FieldResult {
- let mut statuses = work_statuses.unwrap_or_default();
- if let Some(status) = work_status {
- statuses.push(status);
- }
- Work::count(
- &context.db,
- filter,
- publishers.unwrap_or_default(),
- vec![
- WorkType::Monograph,
- WorkType::EditedBook,
- WorkType::Textbook,
- WorkType::JournalIssue,
- ],
- statuses,
- updated_at_with_relations,
+ #[graphql(
+ deprecated = "Please use Work `abstracts` field instead to get the correct long abstract in a multilingual manner"
+ )]
+ pub fn long_abstract(&self, ctx: &Context) -> FieldResult> {
+ Ok(
+ Abstract::long_canonical_from_work_id(&ctx.db, &self.work_id)
+ .map(|a| a.content)
+ .ok(),
)
- .map_err(|e| e.into())
}
#[allow(clippy::too_many_arguments)]
- #[graphql(description = "Query the full list of chapters (a subset of the full list of works)")]
- fn chapters(
+ #[graphql(description = "Query titles by work ID")]
+ fn titles(
+ &self,
context: &Context,
#[graphql(default = 100, description = "The number of items to return")] limit: Option,
#[graphql(default = 0, description = "The number of items to skip")] offset: Option,
#[graphql(
default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on full_title, doi, reference, short_abstract, long_abstract, and landing_page"
+ description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on title_, subtitle, full_title fields"
)]
filter: Option,
#[graphql(
- default = WorkOrderBy::default(),
+ default = TitleOrderBy::default(),
description = "The order in which to sort the results"
)]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- #[graphql(description = "(deprecated) A specific status to filter by")] work_status: Option<
- WorkStatus,
- >,
+ order: Option,
#[graphql(
default = vec![],
- description = "Specific statuses to filter by"
+ description = "If set, only shows results with these locale codes"
)]
- work_statuses: Option>,
+ locale_codes: Option>,
#[graphql(
- description = "Only show results updated either before (less than) or after (greater than) the specified timestamp"
+ default = MarkupFormat::JatsXml,
+ description = "If set, only shows results with this markup format"
)]
- updated_at_with_relations: Option,
- ) -> FieldResult> {
- let mut statuses = work_statuses.unwrap_or_default();
- if let Some(status) = work_status {
- statuses.push(status);
- }
- Work::all(
+ markup_format: Option,
+ ) -> FieldResult> {
+ let mut titles = Title::all(
&context.db,
limit.unwrap_or_default(),
offset.unwrap_or_default(),
filter,
order.unwrap_or_default(),
- publishers.unwrap_or_default(),
+ vec![],
+ Some(self.work_id),
+ None,
+ locale_codes.unwrap_or_default(),
+ vec![],
None,
None,
- vec![WorkType::BookChapter],
- statuses,
- updated_at_with_relations,
)
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single chapter using its DOI")]
- fn chapter_by_doi(
- context: &Context,
- #[graphql(description = "Chapter DOI to search on")] doi: Doi,
- ) -> FieldResult {
- Work::from_doi(&context.db, doi, vec![WorkType::BookChapter]).map_err(|e| e.into())
- }
-
- #[graphql(
- description = "Get the total number of chapters (a subset of the total number of works)"
- )]
- fn chapter_count(
- context: &Context,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on full_title, doi, reference, short_abstract, long_abstract, and landing_page"
- )]
- filter: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- #[graphql(description = "(deprecated) A specific status to filter by")] work_status: Option<
- WorkStatus,
- >,
- #[graphql(
- default = vec![],
- description = "Specific statuses to filter by"
- )]
- work_statuses: Option>,
- #[graphql(
- description = "Only show results updated either before (less than) or after (greater than) the specified timestamp"
- )]
- updated_at_with_relations: Option,
- ) -> FieldResult {
- let mut statuses = work_statuses.unwrap_or_default();
- if let Some(status) = work_status {
- statuses.push(status);
- }
- Work::count(
- &context.db,
- filter,
- publishers.unwrap_or_default(),
- vec![WorkType::BookChapter],
- statuses,
- updated_at_with_relations,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query the full list of publications")]
- fn publications(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on isbn"
- )]
- filter: Option,
- #[graphql(
- default = PublicationOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- #[graphql(
- default = vec![],
- description = "Specific types to filter by",
- )]
- publication_types: Option>,
- ) -> FieldResult> {
- Publication::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- filter,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- publication_types.unwrap_or_default(),
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single publication using its ID")]
- fn publication(
- context: &Context,
- #[graphql(description = "Thoth publication ID to search on")] publication_id: Uuid,
- ) -> FieldResult {
- Publication::from_id(&context.db, &publication_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of publications")]
- fn publication_count(
- context: &Context,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on isbn"
- )]
- filter: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- #[graphql(
- default = vec![],
- description = "Specific types to filter by",
- )]
- publication_types: Option>,
- ) -> FieldResult {
- Publication::count(
- &context.db,
- filter,
- publishers.unwrap_or_default(),
- publication_types.unwrap_or_default(),
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query the full list of publishers")]
- fn publishers(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on publisher_name and publisher_shortname"
- )]
- filter: Option,
- #[graphql(
- default = PublisherOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- ) -> FieldResult> {
- Publisher::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- filter,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- vec![],
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single publisher using its ID")]
- fn publisher(
- context: &Context,
- #[graphql(description = "Thoth publisher ID to search on")] publisher_id: Uuid,
- ) -> FieldResult {
- Publisher::from_id(&context.db, &publisher_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of publishers")]
- fn publisher_count(
- context: &Context,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on publisher_name and publisher_shortname"
- )]
- filter: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- ) -> FieldResult {
- Publisher::count(
- &context.db,
- filter,
- publishers.unwrap_or_default(),
- vec![],
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query the full list of imprints")]
- fn imprints(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on imprint_name and imprint_url"
- )]
- filter: Option,
- #[graphql(
- default = ImprintOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- ) -> FieldResult> {
- Imprint::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- filter,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- vec![],
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single imprint using its ID")]
- fn imprint(
- context: &Context,
- #[graphql(description = "Thoth imprint ID to search on")] imprint_id: Uuid,
- ) -> FieldResult {
- Imprint::from_id(&context.db, &imprint_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of imprints")]
- fn imprint_count(
- context: &Context,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on imprint_name and imprint_url"
- )]
- filter: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- ) -> FieldResult {
- Imprint::count(
- &context.db,
- filter,
- publishers.unwrap_or_default(),
- vec![],
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query the full list of contributors")]
- fn contributors(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on full_name, last_name and orcid"
- )]
- filter: Option,
- #[graphql(
- default = ContributorOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- ) -> FieldResult> {
- Contributor::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- filter,
- order.unwrap_or_default(),
- vec![],
- None,
- None,
- vec![],
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single contributor using its ID")]
- fn contributor(
- context: &Context,
- #[graphql(description = "Thoth contributor ID to search on")] contributor_id: Uuid,
- ) -> FieldResult {
- Contributor::from_id(&context.db, &contributor_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of contributors")]
- fn contributor_count(
- context: &Context,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on full_name, last_name and orcid"
- )]
- filter: Option,
- ) -> FieldResult {
- Contributor::count(&context.db, filter, vec![], vec![], vec![], None).map_err(|e| e.into())
- }
-
- #[graphql(description = "Query the full list of contributions")]
- fn contributions(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = ContributionOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- #[graphql(
- default = vec![],
- description = "Specific types to filter by",
- )]
- contribution_types: Option>,
- ) -> FieldResult> {
- Contribution::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- None,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- contribution_types.unwrap_or_default(),
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single contribution using its ID")]
- fn contribution(
- context: &Context,
- #[graphql(description = "Thoth contribution ID to search on")] contribution_id: Uuid,
- ) -> FieldResult {
- Contribution::from_id(&context.db, &contribution_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of contributions")]
- fn contribution_count(
- context: &Context,
- #[graphql(
- default = vec![],
- description = "Specific types to filter by",
- )]
- contribution_types: Option>,
- ) -> FieldResult {
- Contribution::count(
- &context.db,
- None,
- vec![],
- contribution_types.unwrap_or_default(),
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query the full list of series")]
- fn serieses(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on series_name, issn_print, issn_digital, series_url and series_description"
- )]
- filter: Option,
- #[graphql(
- default = SeriesOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- #[graphql(
- default = vec![],
- description = "Specific types to filter by",
- )]
- series_types: Option>,
- ) -> FieldResult> {
- Series::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- filter,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- series_types.unwrap_or_default(),
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single series using its ID")]
- fn series(
- context: &Context,
- #[graphql(description = "Thoth series ID to search on")] series_id: Uuid,
- ) -> FieldResult {
- Series::from_id(&context.db, &series_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of series")]
- fn series_count(
- context: &Context,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on series_name, issn_print, issn_digital, series_url and series_description"
- )]
- filter: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- #[graphql(
- default = vec![],
- description = "Specific types to filter by",
- )]
- series_types: Option>,
- ) -> FieldResult {
- Series::count(
- &context.db,
- filter,
- publishers.unwrap_or_default(),
- series_types.unwrap_or_default(),
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query the full list of issues")]
- fn issues(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = IssueOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- ) -> FieldResult> {
- Issue::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- None,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- vec![],
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single issue using its ID")]
- fn issue(
- context: &Context,
- #[graphql(description = "Thoth issue ID to search on")] issue_id: Uuid,
- ) -> FieldResult {
- Issue::from_id(&context.db, &issue_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of issues")]
- fn issue_count(context: &Context) -> FieldResult {
- Issue::count(&context.db, None, vec![], vec![], vec![], None).map_err(|e| e.into())
- }
-
- #[allow(clippy::too_many_arguments)]
- #[graphql(description = "Query the full list of languages")]
- fn languages(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = LanguageOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- #[graphql(
- default = vec![],
- description = "Specific languages to filter by"
- )]
- language_codes: Option>,
- #[graphql(
- description = "(deprecated) A specific relation to filter by"
- )]
- language_relation: Option,
- #[graphql(
- default = vec![],
- description = "Specific relations to filter by"
- )]
- language_relations: Option>,
- ) -> FieldResult> {
- let mut relations = language_relations.unwrap_or_default();
- if let Some(relation) = language_relation {
- relations.push(relation);
- }
- Language::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- None,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- language_codes.unwrap_or_default(),
- relations,
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single language using its ID")]
- fn language(
- context: &Context,
- #[graphql(description = "Thoth language ID to search on")] language_id: Uuid,
- ) -> FieldResult {
- Language::from_id(&context.db, &language_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of languages associated to works")]
- fn language_count(
- context: &Context,
- #[graphql(
- default = vec![],
- description = "Specific languages to filter by"
- )]
- language_codes: Option>,
- #[graphql(
- description = "(deprecated) A specific relation to filter by"
- )]
- language_relation: Option,
- #[graphql(
- default = vec![],
- description = "Specific relations to filter by"
- )]
- language_relations: Option>,
- ) -> FieldResult {
- let mut relations = language_relations.unwrap_or_default();
- if let Some(relation) = language_relation {
- relations.push(relation);
- }
- Language::count(
- &context.db,
- None,
- vec![],
- language_codes.unwrap_or_default(),
- relations,
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query the full list of locations")]
- fn locations(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = LocationOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- #[graphql(
- default = vec![],
- description = "Specific platforms to filter by"
- )]
- location_platforms: Option>,
- ) -> FieldResult> {
- Location::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- None,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- location_platforms.unwrap_or_default(),
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single location using its ID")]
- fn location(
- context: &Context,
- #[graphql(description = "Thoth location ID to search on")] location_id: Uuid,
- ) -> FieldResult {
- Location::from_id(&context.db, &location_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of locations associated to works")]
- fn location_count(
- context: &Context,
- #[graphql(
- default = vec![],
- description = "Specific platforms to filter by"
- )]
- location_platforms: Option>,
- ) -> FieldResult {
- Location::count(
- &context.db,
- None,
- vec![],
- location_platforms.unwrap_or_default(),
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query the full list of prices")]
- fn prices(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = PriceOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- #[graphql(
- default = vec![],
- description = "Specific currencies to filter by"
- )]
- currency_codes: Option>,
- ) -> FieldResult> {
- Price::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- None,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- currency_codes.unwrap_or_default(),
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single price using its ID")]
- fn price(
- context: &Context,
- #[graphql(description = "Thoth price ID to search on")] price_id: Uuid,
- ) -> FieldResult {
- Price::from_id(&context.db, &price_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of prices associated to works")]
- fn price_count(
- context: &Context,
- #[graphql(
- default = vec![],
- description = "Specific currencies to filter by"
- )]
- currency_codes: Option>,
- ) -> FieldResult {
- Price::count(
- &context.db,
- None,
- vec![],
- currency_codes.unwrap_or_default(),
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query the full list of subjects")]
- fn subjects(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on subject_code"
- )]
- filter: Option,
- #[graphql(
- default = SubjectOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- #[graphql(
- default = vec![],
- description = "Specific types to filter by",
- )]
- subject_types: Option>,
- ) -> FieldResult> {
- Subject::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- filter,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- subject_types.unwrap_or_default(),
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single subject using its ID")]
- fn subject(
- context: &Context,
- #[graphql(description = "Thoth subject ID to search on")] subject_id: Uuid,
- ) -> FieldResult {
- Subject::from_id(&context.db, &subject_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of subjects associated to works")]
- fn subject_count(
- context: &Context,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on subject_code"
- )]
- filter: Option,
- #[graphql(
- default = vec![],
- description = "Specific types to filter by",
- )]
- subject_types: Option>,
- ) -> FieldResult {
- Subject::count(
- &context.db,
- filter,
- vec![],
- subject_types.unwrap_or_default(),
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query the full list of institutions")]
- fn institutions(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on institution_name, ror and institution_doi"
- )]
- filter: Option,
- #[graphql(
- default = InstitutionOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- ) -> FieldResult> {
- Institution::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- filter,
- order.unwrap_or_default(),
- vec![],
- None,
- None,
- vec![],
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single institution using its ID")]
- fn institution(
- context: &Context,
- #[graphql(description = "Thoth institution ID to search on")] institution_id: Uuid,
- ) -> FieldResult {
- Institution::from_id(&context.db, &institution_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of institutions")]
- fn institution_count(
- context: &Context,
- #[graphql(
- default = "".to_string(),
- description = "A query string to search. This argument is a test, do not rely on it. At present it simply searches for case insensitive literals on institution_name, ror and institution_doi"
- )]
- filter: Option,
- ) -> FieldResult {
- Institution::count(&context.db, filter, vec![], vec![], vec![], None).map_err(|e| e.into())
- }
-
- #[graphql(description = "Query the full list of fundings")]
- fn fundings(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = FundingOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- ) -> FieldResult> {
- Funding::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- None,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- vec![],
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single funding using its ID")]
- fn funding(
- context: &Context,
- #[graphql(description = "Thoth funding ID to search on")] funding_id: Uuid,
- ) -> FieldResult {
- Funding::from_id(&context.db, &funding_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of funding instances associated to works")]
- fn funding_count(context: &Context) -> FieldResult {
- Funding::count(&context.db, None, vec![], vec![], vec![], None).map_err(|e| e.into())
- }
-
- #[graphql(description = "Query the full list of affiliations")]
- fn affiliations(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = AffiliationOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- ) -> FieldResult> {
- Affiliation::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- None,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- vec![],
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single affiliation using its ID")]
- fn affiliation(
- context: &Context,
- #[graphql(description = "Thoth affiliation ID to search on")] affiliation_id: Uuid,
- ) -> FieldResult {
- Affiliation::from_id(&context.db, &affiliation_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of affiliations")]
- fn affiliation_count(context: &Context) -> FieldResult {
- Affiliation::count(&context.db, None, vec![], vec![], vec![], None).map_err(|e| e.into())
- }
-
- #[graphql(description = "Query the full list of references")]
- fn references(
- context: &Context,
- #[graphql(default = 100, description = "The number of items to return")] limit: Option,
- #[graphql(default = 0, description = "The number of items to skip")] offset: Option,
- #[graphql(
- default = ReferenceOrderBy::default(),
- description = "The order in which to sort the results"
- )]
- order: Option,
- #[graphql(
- default = vec![],
- description = "If set, only shows results connected to publishers with these IDs"
- )]
- publishers: Option>,
- ) -> FieldResult> {
- Reference::all(
- &context.db,
- limit.unwrap_or_default(),
- offset.unwrap_or_default(),
- None,
- order.unwrap_or_default(),
- publishers.unwrap_or_default(),
- None,
- None,
- vec![],
- vec![],
- None,
- )
- .map_err(|e| e.into())
- }
-
- #[graphql(description = "Query a single reference using its ID")]
- fn reference(
- context: &Context,
- #[graphql(description = "Thoth reference ID to search on")] reference_id: Uuid,
- ) -> FieldResult {
- Reference::from_id(&context.db, &reference_id).map_err(|e| e.into())
- }
-
- #[graphql(description = "Get the total number of references")]
- fn reference_count(context: &Context) -> FieldResult {
- Reference::count(&context.db, None, vec![], vec![], vec![], None).map_err(|e| e.into())
- }
-}
-
-pub struct MutationRoot;
-
-#[juniper::graphql_object(Context = Context)]
-impl MutationRoot {
- #[graphql(description = "Create a new work with the specified values")]
- fn create_work(
- context: &Context,
- #[graphql(description = "Values for work to be created")] data: NewWork,
- ) -> FieldResult {
- context.token.jwt.as_ref().ok_or(ThothError::Unauthorised)?;
- context
- .account_access
- .can_edit(publisher_id_from_imprint_id(&context.db, data.imprint_id)?)?;
-
- data.validate()?;
-
- Work::create(&context.db, &data).map_err(|e| e.into())
- }
-
- #[graphql(description = "Create a new publisher with the specified values")]
- fn create_publisher(
- context: &Context,
- #[graphql(description = "Values for publisher to be created")] data: NewPublisher,
- ) -> FieldResult {
- context.token.jwt.as_ref().ok_or(ThothError::Unauthorised)?;
- // Only superusers can create new publishers - NewPublisher has no ID field
- if !context.account_access.is_superuser {
- return Err(ThothError::Unauthorised.into());
- }
-
- Publisher::create(&context.db, &data).map_err(|e| e.into())
- }
-
- #[graphql(description = "Create a new imprint with the specified values")]
- fn create_imprint(
- context: &Context,
- #[graphql(description = "Values for imprint to be created")] data: NewImprint,
- ) -> FieldResult {
- context.token.jwt.as_ref().ok_or(ThothError::Unauthorised)?;
- context.account_access.can_edit(data.publisher_id)?;
-
- Imprint::create(&context.db, &data).map_err(|e| e.into())
- }
-
- #[graphql(description = "Create a new contributor with the specified values")]
- fn create_contributor(
- context: &Context,
- #[graphql(description = "Values for contributor to be created")] data: NewContributor,
- ) -> FieldResult {
- context.token.jwt.as_ref().ok_or(ThothError::Unauthorised)?;
- Contributor::create(&context.db, &data).map_err(|e| e.into())
- }
-
- #[graphql(description = "Create a new contribution with the specified values")]
- fn create_contribution(
- context: &Context,
- #[graphql(description = "Values for contribution to be created")] data: NewContribution,
- ) -> FieldResult