diff --git a/.config/dictionaries/project.dic b/.config/dictionaries/project.dic index 0a2d74be760f..e913b7e83271 100644 --- a/.config/dictionaries/project.dic +++ b/.config/dictionaries/project.dic @@ -64,6 +64,7 @@ ciphertext ciphertexts CIPs CNFT +COAP COCOAPODS codegen codepoints @@ -173,6 +174,7 @@ iohk IPFS iphoneos iphonesimulator +IPLD jdbc jetbrains jlumbroso diff --git a/.earthlyignore b/.earthlyignore index 90b83f2543fd..0e08fa364b57 100644 --- a/.earthlyignore +++ b/.earthlyignore @@ -16,15 +16,10 @@ # Generated files from code generation tools **/*.g.dart **/*.freezed.dart -**/*.chopper.dart -**/*.swagger.dart -**/*.openapi.dart **/*.gen.dart -**/*.swagger.*.dart **/*.drift.dart -**/openapi/processed/ -**/catalyst_voices_localizations_*.dart -**/catalyst_voices_localizations.dart +**/generated/catalyst_voices_localizations_*.dart +**/generated/catalyst_voices_localizations.dart # node related diff --git a/catalyst_voices/.earthlyignore b/catalyst_voices/.earthlyignore index 0a9505a3048c..cdd029968109 100644 --- a/catalyst_voices/.earthlyignore +++ b/catalyst_voices/.earthlyignore @@ -16,15 +16,10 @@ # Generated files from code generation tools **/*.g.dart **/*.freezed.dart -**/*.chopper.dart -**/*.swagger.dart -**/*.openapi.dart **/*.gen.dart -**/*.swagger.*.dart **/*.drift.dart -**/openapi/processed/ -**/catalyst_voices_localizations_*.dart -**/catalyst_voices_localizations.dart +**/generated/catalyst_voices_localizations_*.dart +**/generated/catalyst_voices_localizations.dart # node related diff --git a/catalyst_voices/.gitignore b/catalyst_voices/.gitignore index a4b765cb31da..7bdf1d5ab4a8 100644 --- a/catalyst_voices/.gitignore +++ b/catalyst_voices/.gitignore @@ -8,27 +8,12 @@ docs/ # Generated files from code generation tools *.g.dart *.freezed.dart -*.chopper.dart -*.swagger.dart -*.openapi.dart *.gen.dart -*.swagger.*.dart *.drift.dart -**/generated/* -**/openapi/** - -# Un-ignore vit, cat-reviews and cat-gateway openapi spec as they're not generated -!**/openapi/vit.json -!**/openapi/cat-reviews.json -!**/openapi/cat-status.json -!**/openapi/cat-gateway.json # Un-ignore generated files in public packages !**/packages/libs/**/*.g.dart !**/packages/libs/**/*.freezed.dart -!**/packages/libs/**/*.chopper.dart -!**/packages/libs/**/*.swagger.dart -!**/packages/libs/**/*.openapi.dart !**/packages/libs/**/*.gen.dart # Localization (l10n) generated files diff --git a/catalyst_voices/Earthfile b/catalyst_voices/Earthfile index 16d617301452..c844c6317aaf 100644 --- a/catalyst_voices/Earthfile +++ b/catalyst_voices/Earthfile @@ -1,7 +1,6 @@ VERSION 0.8 IMPORT ../ AS repo-ci -IMPORT ../catalyst-gateway AS catalyst-gateway IMPORT github.com/input-output-hk/catalyst-ci/earthly/flutter:v3.6.3 AS flutter-ci # repo-catalyst-voices - Creates artifacts of all configuration files, @@ -22,37 +21,29 @@ builder: DO flutter-ci+BOOTSTRAP # Generates flutter code. -# Generates codes for Catalyst Gateway OpenAPI, Voices Localization and -# VoicesAssets and other packages that depend on code-generator. +# Generates codes for Voices Localization and VoicesAssets and other packages +# that depend on code-generator. # It accepts [save_locally] ARG that when true place the artifacts in the # proper folders code-generator: ARG save_locally=false FROM +builder - LET gen_code_path = lib/generated/api - LET local_gen_code_path = packages/internal/catalyst_voices_repositories/lib/generated/api/ - - WORKDIR packages/internal/catalyst_voices_repositories - WORKDIR /frontend RUN melos l10n RUN melos build-runner - RUN melos build-runner-repository IF [ $save_locally = true ] - # This step saves generated files other then OpenApi Services + # This step saves generated files RUN find . \ \( -name "*.g.dart" \ - -o -name "*.chopper.dart" \ -o -name "*.gen.dart" \ -o -name "catalyst_voices_localizations*.dart" \ -o -name "*.drift.dart" \) FOR generated_file IN $(find . \ \( -name "*.g.dart" \ - -o -name "*.chopper.dart" \ -o -name "*.gen.dart" \ -o -name "catalyst_voices_localizations*.dart" \ -o -name "*.drift.dart" \)) @@ -62,18 +53,6 @@ code-generator: SAVE ARTIFACT . END - WORKDIR packages/internal/catalyst_voices_repositories - - # Saves generated OpenApi Services - IF [ $save_locally = true ] - SAVE ARTIFACT "$gen_code_path/*" AS LOCAL $local_gen_code_path - ELSE - SAVE ARTIFACT $gen_code_path - END - - # restore current working directory to the root of the project - WORKDIR /frontend - # Runs code formatting checks. check-code-formatting: FROM +builder diff --git a/catalyst_voices/README.md b/catalyst_voices/README.md index c4ea20e55697..7406040e6d63 100644 --- a/catalyst_voices/README.md +++ b/catalyst_voices/README.md @@ -206,7 +206,6 @@ flutter run --dart-define=FEATURE_VOTING=false This project utilizes automatic code generation for the following components: -* Catalyst Gateway OpenAPI * Localization files * Asset files * Navigation route files diff --git a/catalyst_voices/apps/voices/lib/configs/bootstrap.dart b/catalyst_voices/apps/voices/lib/configs/bootstrap.dart index 27b00930a8c4..7ccae0c8946b 100644 --- a/catalyst_voices/apps/voices/lib/configs/bootstrap.dart +++ b/catalyst_voices/apps/voices/lib/configs/bootstrap.dart @@ -225,7 +225,7 @@ Future _doBootstrapAndRun( Future _getAppConfig({ required AppEnvironmentType env, }) async { - final api = ApiServices(env: env); + final api = ApiServices.dio(env: env); final source = ApiConfigSource(api); final service = ConfigService(ConfigRepository(source)); return service.getAppConfig(env: env); diff --git a/catalyst_voices/apps/voices/lib/dependency/dependencies.dart b/catalyst_voices/apps/voices/lib/dependency/dependencies.dart index 76a07955833c..0108ff4b3481 100644 --- a/catalyst_voices/apps/voices/lib/dependency/dependencies.dart +++ b/catalyst_voices/apps/voices/lib/dependency/dependencies.dart @@ -222,10 +222,10 @@ final class Dependencies extends DependencyProvider { void _registerNetwork() { registerLazySingleton( () { - return ApiServices( + return ApiServices.dio( env: get().type, authTokenProvider: get(), - httpClient: () => get().buildHttpClient(), + interceptClient: get().registerDio, ); }, dispose: (api) => api.dispose(), diff --git a/catalyst_voices/apps/voices/lib/pages/category/card_information.dart b/catalyst_voices/apps/voices/lib/pages/category/card_information.dart index 3325efacbad6..31cf73f39b4f 100644 --- a/catalyst_voices/apps/voices/lib/pages/category/card_information.dart +++ b/catalyst_voices/apps/voices/lib/pages/category/card_information.dart @@ -28,7 +28,7 @@ class CardInformation extends StatelessWidget { padding: padding, children: [ CategoryProposalsDetailsCard( - categoryId: category.id, + categoryRef: category.ref, categoryName: category.formattedName, categoryProposalsCount: category.proposalsCount, ), @@ -36,7 +36,7 @@ class CardInformation extends StatelessWidget { Offstage( offstage: !isActiveProposer, child: CreateProposalCard( - categoryId: category.id, + categoryRef: category.ref, categoryName: category.formattedName, categoryDos: category.dos, categoryDonts: category.donts, diff --git a/catalyst_voices/apps/voices/lib/pages/category/category_compact_detail_view.dart b/catalyst_voices/apps/voices/lib/pages/category/category_compact_detail_view.dart index b10f8a50b7c4..ebe730b44756 100644 --- a/catalyst_voices/apps/voices/lib/pages/category/category_compact_detail_view.dart +++ b/catalyst_voices/apps/voices/lib/pages/category/category_compact_detail_view.dart @@ -32,7 +32,7 @@ class CategoryCompactDetailView extends StatelessWidget { _CategoryBrief( categoryName: category.formattedName, categoryDescription: category.description, - categoryRef: category.id, + categoryRef: category.ref, ), FundsDetailCard( allFunds: category.availableFunds, diff --git a/catalyst_voices/apps/voices/lib/pages/category/category_detail_view.dart b/catalyst_voices/apps/voices/lib/pages/category/category_detail_view.dart index 92192e7c9a31..867c4a4768e4 100644 --- a/catalyst_voices/apps/voices/lib/pages/category/category_detail_view.dart +++ b/catalyst_voices/apps/voices/lib/pages/category/category_detail_view.dart @@ -32,7 +32,7 @@ class CategoryDetailView extends StatelessWidget { _CategoryBrief( categoryName: category.formattedName, categoryDescription: category.description, - categoryRef: category.id, + categoryRef: category.ref, image: category.image, proposalCount: category.proposalsCount, ), diff --git a/catalyst_voices/apps/voices/lib/pages/category/category_page.dart b/catalyst_voices/apps/voices/lib/pages/category/category_page.dart index e70f29b8f03d..52345f332672 100644 --- a/catalyst_voices/apps/voices/lib/pages/category/category_page.dart +++ b/catalyst_voices/apps/voices/lib/pages/category/category_page.dart @@ -16,9 +16,9 @@ import 'package:flutter/material.dart'; import 'package:skeletonizer/skeletonizer.dart'; class CategoryPage extends StatefulWidget { - final SignedDocumentRef categoryId; + final SignedDocumentRef categoryRef; - const CategoryPage({super.key, required this.categoryId}); + const CategoryPage({super.key, required this.categoryRef}); @override State createState() => _CategoryPageState(); @@ -102,9 +102,9 @@ class _BodySmall extends StatelessWidget { } class _CategoryDetailErrorSelector extends StatelessWidget { - final SignedDocumentRef categoryId; + final SignedDocumentRef categoryRef; - const _CategoryDetailErrorSelector({required this.categoryId}); + const _CategoryDetailErrorSelector({required this.categoryRef}); @override Widget build(BuildContext context) { @@ -128,7 +128,7 @@ class _CategoryDetailErrorSelector extends StatelessWidget { ? null : () { unawaited( - context.read().getCategoryDetail(categoryId), + context.read().getCategoryDetail(categoryRef), ); }, ), @@ -187,7 +187,7 @@ class _CategoryPageState extends State { children: [ const _CategoryDetailLoadingOrDataSelector(), _CategoryDetailErrorSelector( - categoryId: widget.categoryId, + categoryRef: widget.categoryRef, ), ].constrainedDelegate(), ), @@ -198,9 +198,9 @@ class _CategoryPageState extends State { void didUpdateWidget(CategoryPage oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.categoryId != oldWidget.categoryId) { + if (widget.categoryRef != oldWidget.categoryRef) { unawaited( - context.read().getCategoryDetail(widget.categoryId), + context.read().getCategoryDetail(widget.categoryRef), ); } } @@ -217,7 +217,7 @@ class _CategoryPageState extends State { super.initState(); unawaited(context.read().getCategories()); unawaited( - context.read().getCategoryDetail(widget.categoryId), + context.read().getCategoryDetail(widget.categoryRef), ); _listenForProposalRef(context.read()); } @@ -225,7 +225,7 @@ class _CategoryPageState extends State { void _listenForProposalRef(CategoryDetailCubit cubit) { // listen for updates _categoryRefSub = cubit.stream - .map((event) => event.category?.id) + .map((event) => event.category?.ref) .distinct() .listen(_onCategoryRefChanged); } diff --git a/catalyst_voices/apps/voices/lib/pages/category/change_category_button.dart b/catalyst_voices/apps/voices/lib/pages/category/change_category_button.dart index c46ce9c5c1f4..59cf17ef01bd 100644 --- a/catalyst_voices/apps/voices/lib/pages/category/change_category_button.dart +++ b/catalyst_voices/apps/voices/lib/pages/category/change_category_button.dart @@ -20,13 +20,13 @@ class ChangeCategoryButton extends StatelessWidget { List> >( selector: (state) { - final selectedCategory = state.category?.id ?? ''; + final selectedCategory = state.category?.ref ?? ''; return state.categories .map( (e) => DropdownMenuViewModel( - value: ProposalsRefCategoryFilter(ref: e.id), + value: ProposalsRefCategoryFilter(ref: e.ref), name: e.formattedName, - isSelected: e.id == selectedCategory, + isSelected: e.ref == selectedCategory, ), ) .toList(); diff --git a/catalyst_voices/apps/voices/lib/pages/proposal_builder/proposal_builder_page.dart b/catalyst_voices/apps/voices/lib/pages/proposal_builder/proposal_builder_page.dart index 39860ed675f1..16e0c78eec31 100644 --- a/catalyst_voices/apps/voices/lib/pages/proposal_builder/proposal_builder_page.dart +++ b/catalyst_voices/apps/voices/lib/pages/proposal_builder/proposal_builder_page.dart @@ -36,12 +36,12 @@ import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; class ProposalBuilderPage extends StatelessWidget { final DocumentRef? proposalId; - final SignedDocumentRef? categoryId; + final SignedDocumentRef? categoryRef; const ProposalBuilderPage({ super.key, this.proposalId, - this.categoryId, + this.categoryRef, }); @override @@ -50,7 +50,7 @@ class ProposalBuilderPage extends StatelessWidget { create: (context) => Dependencies.instance.get(), child: _ProposalBuilderBody( proposalId: proposalId, - categoryId: categoryId, + categoryRef: categoryRef, ), ); } @@ -58,11 +58,11 @@ class ProposalBuilderPage extends StatelessWidget { class _ProposalBuilderBody extends StatefulWidget { final DocumentRef? proposalId; - final SignedDocumentRef? categoryId; + final SignedDocumentRef? categoryRef; const _ProposalBuilderBody({ this.proposalId, - this.categoryId, + this.categoryRef, }); @override @@ -116,7 +116,7 @@ class _ProposalBuilderBodyState extends State<_ProposalBuilderBody> void didUpdateWidget(_ProposalBuilderBody oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.proposalId != oldWidget.proposalId || widget.categoryId != oldWidget.categoryId) { + if (widget.proposalId != oldWidget.proposalId || widget.categoryRef != oldWidget.categoryRef) { _loadProposal(); } } @@ -239,11 +239,11 @@ class _ProposalBuilderBodyState extends State<_ProposalBuilderBody> bloc ??= context.read(); final proposalId = widget.proposalId; - final categoryId = widget.categoryId; + final categoryRef = widget.categoryRef; if (proposalId != null) { bloc.add(LoadProposalEvent(proposalId: proposalId)); - } else if (categoryId != null) { - bloc.add(LoadProposalCategoryEvent(categoryId: categoryId)); + } else if (categoryRef != null) { + bloc.add(LoadProposalCategoryEvent(categoryRef: categoryRef)); } else { bloc.add(const LoadDefaultProposalCategoryEvent()); } diff --git a/catalyst_voices/apps/voices/lib/pages/proposals/proposals_page.dart b/catalyst_voices/apps/voices/lib/pages/proposals/proposals_page.dart index 028451fe8874..7d8a20a6f053 100644 --- a/catalyst_voices/apps/voices/lib/pages/proposals/proposals_page.dart +++ b/catalyst_voices/apps/voices/lib/pages/proposals/proposals_page.dart @@ -17,12 +17,12 @@ import 'package:flutter/material.dart'; import 'package:rxdart/rxdart.dart'; class ProposalsPage extends StatefulWidget { - final SignedDocumentRef? categoryId; + final SignedDocumentRef? categoryRef; final ProposalsPageTab? tab; const ProposalsPage({ super.key, - this.categoryId, + this.categoryRef, this.tab, }); @@ -58,10 +58,10 @@ class _ProposalsPageState extends State final tab = widget.tab ?? ProposalsPageTab.total; - if (widget.categoryId != oldWidget.categoryId || widget.tab != oldWidget.tab) { + if (widget.categoryRef != oldWidget.categoryRef || widget.tab != oldWidget.tab) { context.read().changeFilters( onlyMy: Optional(tab == ProposalsPageTab.my), - category: Optional(widget.categoryId), + category: Optional(widget.categoryRef), type: tab.filter, ); @@ -85,7 +85,7 @@ class _ProposalsPageState extends State void handleSignal(ProposalsSignal signal) { switch (signal) { case ChangeCategoryProposalsSignal(:final to): - _updateRoute(categoryId: Optional(to?.id)); + _updateRoute(categoryRef: Optional(to?.id)); case ChangeTabProposalsSignal(:final tab): _updateRoute(tab: tab); case ResetPaginationProposalsSignal(): @@ -129,7 +129,7 @@ class _ProposalsPageState extends State proposalsCubit.init( onlyMyProposals: selectedTab == ProposalsPageTab.my, - category: widget.categoryId, + category: widget.categoryRef, type: selectedTab.filter, order: const Alphabetical(), ); @@ -171,11 +171,11 @@ class _ProposalsPageState extends State } void _updateRoute({ - Optional? categoryId, + Optional? categoryRef, ProposalsPageTab? tab, }) { Router.neglect(context, () { - final effectiveCategoryId = categoryId.dataOr(widget.categoryId?.id); + final effectiveCategoryId = categoryRef.dataOr(widget.categoryRef?.id); final effectiveTab = tab?.name ?? widget.tab?.name; ProposalsRoute( diff --git a/catalyst_voices/apps/voices/lib/pages/voting/voting_page.dart b/catalyst_voices/apps/voices/lib/pages/voting/voting_page.dart index 079317469a4b..3ab4e2d0a5aa 100644 --- a/catalyst_voices/apps/voices/lib/pages/voting/voting_page.dart +++ b/catalyst_voices/apps/voices/lib/pages/voting/voting_page.dart @@ -21,13 +21,13 @@ import 'package:flutter/material.dart'; import 'package:rxdart/rxdart.dart'; class VotingPage extends StatefulWidget { - final SignedDocumentRef? categoryId; + final SignedDocumentRef? categoryRef; final VotingPageTab? tab; final bool keychainDeleted; const VotingPage({ super.key, - this.categoryId, + this.categoryRef, this.tab, this.keychainDeleted = false, }); @@ -80,10 +80,10 @@ class _VotingPageState extends State final tab = widget.tab ?? VotingPageTab.total; - if (widget.categoryId != oldWidget.categoryId || widget.tab != oldWidget.tab) { + if (widget.categoryRef != oldWidget.categoryRef || widget.tab != oldWidget.tab) { context.read().changeFilters( onlyMy: Optional(tab == VotingPageTab.my), - category: Optional(widget.categoryId), + category: Optional(widget.categoryRef), type: tab.filter, ); @@ -158,7 +158,7 @@ class _VotingPageState extends State votingCubit.init( onlyMyProposals: selectedTab == VotingPageTab.my, - category: widget.categoryId, + category: widget.categoryRef, type: selectedTab.filter, ); @@ -216,7 +216,7 @@ class _VotingPageState extends State VotingPageTab? tab, }) { Router.neglect(context, () { - final effectiveCategoryId = categoryId.dataOr(widget.categoryId?.id); + final effectiveCategoryId = categoryId.dataOr(widget.categoryRef?.id); final effectiveTab = tab?.name ?? widget.tab?.name; VotingRoute( diff --git a/catalyst_voices/apps/voices/lib/routes/routing/account_route.dart b/catalyst_voices/apps/voices/lib/routes/routing/account_route.dart index d36686271825..ad85cd46538f 100644 --- a/catalyst_voices/apps/voices/lib/routes/routing/account_route.dart +++ b/catalyst_voices/apps/voices/lib/routes/routing/account_route.dart @@ -15,7 +15,7 @@ part 'account_route.g.dart'; name: 'account', ) final class AccountRoute extends GoRouteData - with FadePageTransitionMixin, CompositeRouteGuardMixin { + with $AccountRoute, FadePageTransitionMixin, CompositeRouteGuardMixin { const AccountRoute(); @override diff --git a/catalyst_voices/apps/voices/lib/routes/routing/overall_spaces_route.dart b/catalyst_voices/apps/voices/lib/routes/routing/overall_spaces_route.dart index 3a58ea9cafd9..b6715a9022fe 100644 --- a/catalyst_voices/apps/voices/lib/routes/routing/overall_spaces_route.dart +++ b/catalyst_voices/apps/voices/lib/routes/routing/overall_spaces_route.dart @@ -13,7 +13,7 @@ part 'overall_spaces_route.g.dart'; name: 'spaces', ) final class OverallSpacesRoute extends GoRouteData - with FadePageTransitionMixin, CompositeRouteGuardMixin { + with $OverallSpacesRoute, FadePageTransitionMixin, CompositeRouteGuardMixin { const OverallSpacesRoute(); @override diff --git a/catalyst_voices/apps/voices/lib/routes/routing/proposal_builder_route.dart b/catalyst_voices/apps/voices/lib/routes/routing/proposal_builder_route.dart index 9cfe55cef65d..73fd1a92a1a7 100644 --- a/catalyst_voices/apps/voices/lib/routes/routing/proposal_builder_route.dart +++ b/catalyst_voices/apps/voices/lib/routes/routing/proposal_builder_route.dart @@ -15,7 +15,7 @@ part 'proposal_builder_route.g.dart'; name: 'proposal_builder_draft', ) final class ProposalBuilderDraftRoute extends GoRouteData - with FadePageTransitionMixin, CompositeRouteGuardMixin { + with $ProposalBuilderDraftRoute, FadePageTransitionMixin, CompositeRouteGuardMixin { final String? categoryId; const ProposalBuilderDraftRoute({ @@ -23,9 +23,9 @@ final class ProposalBuilderDraftRoute extends GoRouteData }); factory ProposalBuilderDraftRoute.fromRef({ - required SignedDocumentRef categoryId, + required SignedDocumentRef categoryRef, }) { - return ProposalBuilderDraftRoute(categoryId: categoryId.id); + return ProposalBuilderDraftRoute(categoryId: categoryRef.id); } @override @@ -38,7 +38,7 @@ final class ProposalBuilderDraftRoute extends GoRouteData Widget build(BuildContext context, GoRouterState state) { final categoryId = this.categoryId; final categoryRef = categoryId != null ? SignedDocumentRef(id: categoryId) : null; - return ProposalBuilderPage(categoryId: categoryRef); + return ProposalBuilderPage(categoryRef: categoryRef); } } @@ -47,7 +47,7 @@ final class ProposalBuilderDraftRoute extends GoRouteData name: 'proposal_builder_edit', ) final class ProposalBuilderRoute extends GoRouteData - with FadePageTransitionMixin, CompositeRouteGuardMixin { + with $ProposalBuilderRoute, FadePageTransitionMixin, CompositeRouteGuardMixin { final String proposalId; final String? proposalVersion; final bool local; diff --git a/catalyst_voices/apps/voices/lib/routes/routing/proposal_route.dart b/catalyst_voices/apps/voices/lib/routes/routing/proposal_route.dart index a058fd8fae28..ce1a757b5399 100644 --- a/catalyst_voices/apps/voices/lib/routes/routing/proposal_route.dart +++ b/catalyst_voices/apps/voices/lib/routes/routing/proposal_route.dart @@ -10,7 +10,7 @@ part 'proposal_route.g.dart'; path: '/proposal/:proposalId', name: 'proposal_viewer', ) -final class ProposalRoute extends GoRouteData with FadePageTransitionMixin { +final class ProposalRoute extends GoRouteData with $ProposalRoute, FadePageTransitionMixin { final String proposalId; final String? version; final bool local; diff --git a/catalyst_voices/apps/voices/lib/routes/routing/root_route.dart b/catalyst_voices/apps/voices/lib/routes/routing/root_route.dart index c14f7824e33c..a681ca9a51d1 100644 --- a/catalyst_voices/apps/voices/lib/routes/routing/root_route.dart +++ b/catalyst_voices/apps/voices/lib/routes/routing/root_route.dart @@ -9,7 +9,7 @@ import 'package:go_router/go_router.dart'; part 'root_route.g.dart'; @TypedGoRoute(path: '/') -final class RootRoute extends GoRouteData { +final class RootRoute extends GoRouteData with $RootRoute { const RootRoute(); @override diff --git a/catalyst_voices/apps/voices/lib/routes/routing/spaces_route.dart b/catalyst_voices/apps/voices/lib/routes/routing/spaces_route.dart index 5de7d387c5f8..b3d430f78f57 100644 --- a/catalyst_voices/apps/voices/lib/routes/routing/spaces_route.dart +++ b/catalyst_voices/apps/voices/lib/routes/routing/spaces_route.dart @@ -20,7 +20,8 @@ import 'package:sentry_flutter/sentry_flutter.dart'; part 'spaces_route.g.dart'; -final class CategoryDetailRoute extends GoRouteData with FadePageTransitionMixin { +final class CategoryDetailRoute extends GoRouteData + with $CategoryDetailRoute, FadePageTransitionMixin { final String categoryId; const CategoryDetailRoute({required this.categoryId}); @@ -34,12 +35,12 @@ final class CategoryDetailRoute extends GoRouteData with FadePageTransitionMixin @override Widget build(BuildContext context, GoRouterState state) { return CategoryPage( - categoryId: SignedDocumentRef(id: categoryId), + categoryRef: SignedDocumentRef(id: categoryId), ); } } -final class DiscoveryRoute extends GoRouteData with FadePageTransitionMixin { +final class DiscoveryRoute extends GoRouteData with $DiscoveryRoute, FadePageTransitionMixin { static const name = 'discovery'; final bool? $extra; @@ -55,7 +56,7 @@ final class DiscoveryRoute extends GoRouteData with FadePageTransitionMixin { } final class FundedProjectsRoute extends GoRouteData - with FadePageTransitionMixin, CompositeRouteGuardMixin { + with $FundedProjectsRoute, FadePageTransitionMixin, CompositeRouteGuardMixin { const FundedProjectsRoute(); @override @@ -70,7 +71,7 @@ final class FundedProjectsRoute extends GoRouteData } } -final class ProposalsRoute extends GoRouteData with FadePageTransitionMixin { +final class ProposalsRoute extends GoRouteData with $ProposalsRoute, FadePageTransitionMixin { final String? categoryId; final String? tab; @@ -95,7 +96,7 @@ final class ProposalsRoute extends GoRouteData with FadePageTransitionMixin { final tab = ProposalsPageTab.values.asNameMap()[this.tab]; return ProposalsPage( - categoryId: categoryRef, + categoryRef: categoryRef, tab: tab, ); } @@ -170,7 +171,7 @@ final class SpacesShellRouteData extends ShellRouteData { } final class TreasuryRoute extends GoRouteData - with FadePageTransitionMixin, CompositeRouteGuardMixin { + with $TreasuryRoute, FadePageTransitionMixin, CompositeRouteGuardMixin { const TreasuryRoute(); @override @@ -185,7 +186,8 @@ final class TreasuryRoute extends GoRouteData } } -final class VotingRoute extends GoRouteData with FadePageTransitionMixin, CompositeRouteGuardMixin { +final class VotingRoute extends GoRouteData + with $VotingRoute, FadePageTransitionMixin, CompositeRouteGuardMixin { final String? categoryId; final String? tab; final bool? $extra; @@ -216,7 +218,7 @@ final class VotingRoute extends GoRouteData with FadePageTransitionMixin, Compos final tab = VotingPageTab.values.asNameMap()[this.tab]; return VotingPage( - categoryId: categoryRef, + categoryRef: categoryRef, tab: tab, keychainDeleted: $extra ?? false, ); @@ -224,7 +226,7 @@ final class VotingRoute extends GoRouteData with FadePageTransitionMixin, Compos } final class WorkspaceRoute extends GoRouteData - with FadePageTransitionMixin, CompositeRouteGuardMixin { + with $WorkspaceRoute, FadePageTransitionMixin, CompositeRouteGuardMixin { static const name = 'workspace'; const WorkspaceRoute(); diff --git a/catalyst_voices/apps/voices/lib/widgets/cards/campaign_category_card.dart b/catalyst_voices/apps/voices/lib/widgets/cards/campaign_category_card.dart index 1ac46ebb8a6f..d4fdbac7b9a0 100644 --- a/catalyst_voices/apps/voices/lib/widgets/cards/campaign_category_card.dart +++ b/catalyst_voices/apps/voices/lib/widgets/cards/campaign_category_card.dart @@ -61,7 +61,7 @@ class CampaignCategoryCard extends StatelessWidget { ), ), _Buttons( - categoryRef: category.id, + categoryRef: category.ref, ), ], ), diff --git a/catalyst_voices/apps/voices/lib/widgets/cards/category_proposals_details_card.dart b/catalyst_voices/apps/voices/lib/widgets/cards/category_proposals_details_card.dart index c0db570edfce..76d65040dc42 100644 --- a/catalyst_voices/apps/voices/lib/widgets/cards/category_proposals_details_card.dart +++ b/catalyst_voices/apps/voices/lib/widgets/cards/category_proposals_details_card.dart @@ -8,13 +8,13 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:flutter/material.dart'; class CategoryProposalsDetailsCard extends StatelessWidget { - final SignedDocumentRef categoryId; + final SignedDocumentRef categoryRef; final String categoryName; final int categoryProposalsCount; const CategoryProposalsDetailsCard({ super.key, - required this.categoryId, + required this.categoryRef, required this.categoryName, required this.categoryProposalsCount, }); @@ -45,7 +45,7 @@ class CategoryProposalsDetailsCard extends StatelessWidget { child: VoicesOutlinedButton( child: Text(context.l10n.viewProposals), onTap: () { - ProposalsRoute.fromRef(categoryRef: categoryId).go(context); + ProposalsRoute.fromRef(categoryRef: categoryRef).go(context); }, ), ), diff --git a/catalyst_voices/apps/voices/lib/widgets/cards/create_proposal_card.dart b/catalyst_voices/apps/voices/lib/widgets/cards/create_proposal_card.dart index b56a72382382..93943ee23440 100644 --- a/catalyst_voices/apps/voices/lib/widgets/cards/create_proposal_card.dart +++ b/catalyst_voices/apps/voices/lib/widgets/cards/create_proposal_card.dart @@ -9,7 +9,7 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:flutter/material.dart'; class CreateProposalCard extends StatelessWidget { - final SignedDocumentRef categoryId; + final SignedDocumentRef categoryRef; final String categoryName; final List categoryDos; final List categoryDonts; @@ -17,7 +17,7 @@ class CreateProposalCard extends StatelessWidget { const CreateProposalCard({ super.key, - required this.categoryId, + required this.categoryRef, required this.categoryName, required this.categoryDos, required this.categoryDonts, @@ -51,7 +51,7 @@ class CreateProposalCard extends StatelessWidget { const SizedBox(height: 24), _SubmissionCloseAt(submissionCloseDate), const SizedBox(height: 24), - CreateProposalButton(categoryRef: categoryId), + CreateProposalButton(categoryRef: categoryRef), ], ), ); diff --git a/catalyst_voices/apps/voices/lib/widgets/modals/proposals/create_new_proposal_category_selection.dart b/catalyst_voices/apps/voices/lib/widgets/modals/proposals/create_new_proposal_category_selection.dart index 60ba400faf92..d526ef3b14c4 100644 --- a/catalyst_voices/apps/voices/lib/widgets/modals/proposals/create_new_proposal_category_selection.dart +++ b/catalyst_voices/apps/voices/lib/widgets/modals/proposals/create_new_proposal_category_selection.dart @@ -88,43 +88,48 @@ class _CreateNewProposalCategorySelectionState extends State element.id == widget.selectedCategory); + return widget.categories.firstWhereOrNull( + (element) => element.ref == widget.selectedCategory, + ); } @override Widget build(BuildContext context) { return Expanded( - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: ListView.separated( - itemBuilder: (context, index) => _CategoryCard( - name: widget.categories[index].formattedName, - description: widget.categories[index].shortDescription, - ref: widget.categories[index].id, - isSelected: widget.categories[index].id == widget.selectedCategory, - onCategorySelected: widget.onCategorySelected, + child: Padding( + padding: const EdgeInsets.only(bottom: 68), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: ListView.separated( + itemBuilder: (context, index) => _CategoryCard( + name: widget.categories[index].formattedName, + description: widget.categories[index].shortDescription, + ref: widget.categories[index].ref, + isSelected: widget.categories[index].ref == widget.selectedCategory, + onCategorySelected: widget.onCategorySelected, + ), + separatorBuilder: (context, index) => const SizedBox(height: 16), + itemCount: widget.categories.length, ), - separatorBuilder: (context, index) => const SizedBox(height: 16), - itemCount: widget.categories.length, ), - ), - const SizedBox(width: 16), - Expanded( - flex: 2, - child: _selectedCategory != null - ? VoicesScrollbar( - controller: _scrollController, - alwaysVisible: true, - child: SingleChildScrollView( + const SizedBox(width: 16), + Expanded( + flex: 2, + child: _selectedCategory != null + ? VoicesScrollbar( controller: _scrollController, - child: CategoryCompactDetailView(category: _selectedCategory!), - ), - ) - : const _NoneCategorySelected(), - ), - ], + alwaysVisible: true, + child: SingleChildScrollView( + controller: _scrollController, + child: CategoryCompactDetailView(category: _selectedCategory!), + ), + ) + : const _NoneCategorySelected(), + ), + ], + ), ), ); } diff --git a/catalyst_voices/apps/voices/pubspec.yaml b/catalyst_voices/apps/voices/pubspec.yaml index a24704b7552e..93e43dade902 100644 --- a/catalyst_voices/apps/voices/pubspec.yaml +++ b/catalyst_voices/apps/voices/pubspec.yaml @@ -87,13 +87,13 @@ dependencies: video_player: ^2.10.0 dev_dependencies: - build_runner: ^2.5.4 + build_runner: ^2.10.3 catalyst_analysis: ^3.0.0 flutter_driver: sdk: flutter flutter_test: sdk: flutter - go_router_builder: ^2.9.0 + go_router_builder: ^4.1.1 integration_test: sdk: flutter mocktail: ^1.0.4 diff --git a/catalyst_voices/apps/voices/test/widgets/cards/small_proposal_card_test.dart b/catalyst_voices/apps/voices/test/widgets/cards/small_proposal_card_test.dart index 6c20099eaa85..282206994257 100644 --- a/catalyst_voices/apps/voices/test/widgets/cards/small_proposal_card_test.dart +++ b/catalyst_voices/apps/voices/test/widgets/cards/small_proposal_card_test.dart @@ -30,6 +30,7 @@ void main() { localVersion = const Uuid().v7(); mockProposal = UsersProposalOverview( selfRef: SignedDocumentRef(id: proposalId, version: latestVersion), + parameters: DocumentParameters({SignedDocumentRef.generateFirstRef()}), title: 'Test Proposal', updateDate: DateTime.now(), fundsRequested: Money.zero(currency: Currencies.ada), @@ -66,7 +67,6 @@ void main() { fundNumber: 14, commentsCount: 0, category: 'Cardano Use Cases: Concept', - categoryId: SignedDocumentRef.generateFirstRef(), fromActiveCampaign: true, ); }); diff --git a/catalyst_voices/packages/internal/catalyst_voices_assets/pubspec.yaml b/catalyst_voices/packages/internal/catalyst_voices_assets/pubspec.yaml index c5675083c82a..fca9a26b2068 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_assets/pubspec.yaml +++ b/catalyst_voices/packages/internal/catalyst_voices_assets/pubspec.yaml @@ -15,9 +15,9 @@ dependencies: lottie: ^3.3.1 dev_dependencies: - build_runner: ^2.5.4 + build_runner: ^2.10.3 catalyst_analysis: ^3.0.0 - flutter_gen_runner: ^5.11.0 + flutter_gen_runner: ^5.12.0 flutter_test: sdk: flutter diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/category/category_detail_cubit.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/category/category_detail_cubit.dart index e83be7277518..7005db465e14 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/category/category_detail_cubit.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/category/category_detail_cubit.dart @@ -43,17 +43,15 @@ class CategoryDetailCubit extends Cubit { ); } - Future getCategoryDetail(SignedDocumentRef categoryId) async { - if (categoryId.id == state.category?.id.id) { - return emit(state.copyWith(isLoading: false)); - } + Future getCategoryDetail(SignedDocumentRef categoryRef) async { + if (categoryRef.id == state.category?.ref.id) return; if (!state.isLoading) { emit(state.copyWith(isLoading: true)); } try { - final category = await _campaignService.getCategory(categoryId); + final category = await _campaignService.getCategory(DocumentParameters({categoryRef})); emit( state.copyWith( isLoading: false, diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal/proposal_cubit.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal/proposal_cubit.dart index bd5506a5c906..c50e76381ee6 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal/proposal_cubit.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal/proposal_cubit.dart @@ -87,9 +87,9 @@ final class ProposalCubit extends Cubit emit(state.copyWith(isLoading: true)); final proposal = await _proposalService.getProposalDetail(ref: ref); - final category = await _campaignService.getCategory(proposal.document.metadata.categoryId); + final category = await _campaignService.getCategory(proposal.document.metadata.parameters); final commentTemplate = await _commentService.getCommentTemplateFor( - category: proposal.document.metadata.categoryId, + category: category.selfRef, ); final isFavorite = await _proposalService.watchIsFavoritesProposal(ref: ref).first; @@ -157,12 +157,10 @@ final class ProposalCubit extends Cubit SignedDocumentRef? reply, }) async { final proposalRef = _cache.ref; - final proposalCategoryId = _cache.proposal?.document.metadata.categoryId; + final proposalParameters = _cache.proposal?.document.metadata.parameters; assert(proposalRef != null, 'Proposal ref not found. Load document first!'); - assert( - proposalRef is SignedDocumentRef, - 'Can comment only on signed documents', - ); + assert(proposalRef is SignedDocumentRef, 'Can comment only on signed documents'); + assert(proposalParameters != null, 'Proposal parameters not found!'); final activeAccountId = _cache.activeAccountId; assert(activeAccountId != null, 'No active account found!'); @@ -170,16 +168,14 @@ final class ProposalCubit extends Cubit final commentTemplate = _cache.commentTemplate; assert(commentTemplate != null, 'No comment template found!'); - assert(proposalCategoryId != null, 'Proposal categoryId not found!'); - final commentRef = SignedDocumentRef.generateFirstRef(); final comment = CommentDocument( metadata: CommentMetadata( selfRef: commentRef, - ref: proposalRef! as SignedDocumentRef, - template: commentTemplate!.metadata.selfRef as SignedDocumentRef, + proposalRef: proposalRef! as SignedDocumentRef, + commentTemplate: commentTemplate!.metadata.selfRef as SignedDocumentRef, reply: reply, - categoryId: proposalCategoryId, + parameters: proposalParameters!, authorId: activeAccountId!, ), document: document, diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/new_proposal/new_proposal_cubit.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/new_proposal/new_proposal_cubit.dart index fc8db7cd088b..7110cd98d4ad 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/new_proposal/new_proposal_cubit.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/new_proposal/new_proposal_cubit.dart @@ -32,17 +32,14 @@ class NewProposalCubit extends Cubit emit(state.copyWith(isCreatingProposal: true)); final title = state.title.value; - final categoryId = state.categoryRef; + final categoryRef = state.categoryRef; - if (categoryId == null) { + if (categoryRef == null) { throw StateError('Cannot create draft, category not selected'); } - final category = await _campaignService.getCategory(categoryId); - final templateRef = category.proposalTemplateRef; - final template = await _proposalService.getProposalTemplate( - ref: templateRef, - ); + final template = await _proposalService.getProposalTemplate(category: categoryRef); + final parameters = template.metadata.parameters; final documentBuilder = DocumentBuilder.fromSchema(schema: template.schema) ..addChange( @@ -57,8 +54,8 @@ class NewProposalCubit extends Cubit return await _proposalService.createDraftProposal( content: documentContent, - template: templateRef, - categoryId: categoryId, + templateRef: template.metadata.selfRef.toSignedDocumentRef(), + parameters: parameters, ); } catch (error, stackTrace) { _logger.severe('Create draft', error, stackTrace); @@ -84,16 +81,10 @@ class NewProposalCubit extends Cubit // right now user can start creating proposal without selecting category. // Right now every category have the same requirements for title so we can do a fallback for // first category from the list. - final templateRef = campaign.categories - .cast() - .firstWhere( - (e) => e?.selfRef == categoryRef, - orElse: () => campaign.categories.firstOrNull, - ) - ?.proposalTemplateRef; - - final template = templateRef != null - ? await _proposalService.getProposalTemplate(ref: templateRef) + categoryRef ??= campaign.categories.firstOrNull?.selfRef; + + final template = categoryRef != null + ? await _proposalService.getProposalTemplate(category: categoryRef) : null; final titleRange = template?.title?.strLengthRange; diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/new_proposal/new_proposal_state.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/new_proposal/new_proposal_state.dart index d227d70d0de8..ddf017bf1e86 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/new_proposal/new_proposal_state.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/new_proposal/new_proposal_state.dart @@ -49,7 +49,7 @@ class NewProposalState extends Equatable { categories, ]; String? get selectedCategoryName => - categories.firstWhereOrNull((e) => e.id == categoryRef)?.formattedName; + categories.firstWhereOrNull((e) => e.ref == categoryRef)?.formattedName; bool get _isAgreementValid => isAgreeToCategoryCriteria && isAgreeToNoFurtherCategoryChange; diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/proposal_builder_bloc.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/proposal_builder_bloc.dart index 57bfba8e6689..edf89f5047a6 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/proposal_builder_bloc.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/proposal_builder_bloc.dart @@ -137,11 +137,11 @@ final class ProposalBuilderBloc extends Bloc emit, ) async { - final categoryId = state.metadata.categoryId; - final proposalRef = state.metadata.documentRef; try { emit(state.copyWith(isChanging: true)); + await _proposalService.forgetProposal( - proposalRef: proposalRef! as SignedDocumentRef, - categoryId: categoryId!, + proposalRef: state.metadata.documentRef! as SignedDocumentRef, + proposalParameters: state.metadata.parameters!, ); unawaited(_clearCache()); emitSignal(const ForgotProposalSuccessBuilderSignal()); @@ -464,20 +463,18 @@ final class ProposalBuilderBloc extends Bloc emit, ) async { - final categoryId = event.categoryId; - _logger.info('Loading proposal category: $categoryId'); + final categoryRef = event.categoryRef; + _logger.info('Loading proposal category: $categoryRef'); await _loadState(emit, () async { - final category = await _campaignService.getCategory(categoryId); - final templateRef = category.proposalTemplateRef; - final proposalTemplate = await _proposalService.getProposalTemplate( - ref: templateRef, - ); - + final category = await _campaignService.getCategory(DocumentParameters({categoryRef})); + final proposalTemplate = await _proposalService.getProposalTemplate(category: categoryRef); + final templateParameters = proposalTemplate.metadata.parameters; final documentBuilder = DocumentBuilder.fromSchema(schema: proposalTemplate.schema); return _cacheAndCreateState( proposalDocument: documentBuilder.build(), proposalBuilder: documentBuilder, proposalMetadata: ProposalBuilderMetadata.newDraft( - templateRef: templateRef, - categoryId: categoryId, + templateRef: proposalTemplate.metadata.selfRef.toSignedDocumentRef(), + parameters: templateParameters, ), category: category, ); @@ -742,7 +734,7 @@ final class ProposalBuilderBloc extends Bloc emit, ) async { final originalProposalRef = state.metadata.originalDocumentRef; - final originalProposalCategoryId = state.metadata.categoryId; assert( originalProposalRef != null, 'Proposal ref not found. Load document first!', @@ -1033,10 +1024,10 @@ final class ProposalBuilderBloc extends Bloc _upsertDraftProposal(DocumentDataContent document) async { final currentRef = state.metadata.documentRef!; final originalRef = state.metadata.originalDocumentRef; - final template = state.metadata.templateRef!; - final categoryId = state.metadata.categoryId!; + final templateRef = state.metadata.templateRef!; + final parameters = state.metadata.parameters!; DraftRef nextRef; if (originalRef == null) { nextRef = await _proposalService.createDraftProposal( content: document, - template: template, - categoryId: categoryId, + templateRef: templateRef, + parameters: parameters, ); } else { nextRef = currentRef.nextVersion(); await _proposalService.upsertDraftProposal( selfRef: nextRef, content: document, - template: template, - categoryId: categoryId, + templateRef: templateRef, + parameters: parameters, ); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/proposal_builder_event.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/proposal_builder_event.dart index 690a085c6cce..b7cfdf93621c 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/proposal_builder_event.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/proposal_builder_event.dart @@ -51,14 +51,14 @@ final class LoadDefaultProposalCategoryEvent extends ProposalBuilderEvent { } final class LoadProposalCategoryEvent extends ProposalBuilderEvent { - final SignedDocumentRef categoryId; + final SignedDocumentRef categoryRef; const LoadProposalCategoryEvent({ - required this.categoryId, + required this.categoryRef, }); @override - List get props => [categoryId]; + List get props => [categoryRef]; } final class LoadProposalEvent extends ProposalBuilderEvent { diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/proposal_builder_state.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/proposal_builder_state.dart index d62e53f19d8c..ecb279570df2 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/proposal_builder_state.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal_builder/proposal_builder_state.dart @@ -9,7 +9,7 @@ final class ProposalBuilderMetadata extends Equatable { final DocumentRef? documentRef; final DocumentRef? originalDocumentRef; final SignedDocumentRef? templateRef; - final SignedDocumentRef? categoryId; + final DocumentParameters? parameters; final List versions; final bool fromActiveCampaign; @@ -18,20 +18,20 @@ final class ProposalBuilderMetadata extends Equatable { this.documentRef, this.originalDocumentRef, this.templateRef, - this.categoryId, + this.parameters, this.versions = const [], this.fromActiveCampaign = true, }); factory ProposalBuilderMetadata.newDraft({ required SignedDocumentRef templateRef, - required SignedDocumentRef categoryId, + required DocumentParameters parameters, }) { final firstRef = DraftRef.generateFirstRef(); return ProposalBuilderMetadata( documentRef: firstRef, templateRef: templateRef, - categoryId: categoryId, + parameters: parameters, ); } @@ -43,7 +43,7 @@ final class ProposalBuilderMetadata extends Equatable { documentRef, originalDocumentRef, templateRef, - categoryId, + parameters, versions, fromActiveCampaign, ]; @@ -53,7 +53,7 @@ final class ProposalBuilderMetadata extends Equatable { Optional? documentRef, Optional? originalDocumentRef, Optional? templateRef, - Optional? categoryId, + Optional? parameters, List? versions, bool? fromActiveCampaign, }) { @@ -62,7 +62,7 @@ final class ProposalBuilderMetadata extends Equatable { documentRef: documentRef.dataOr(this.documentRef), originalDocumentRef: originalDocumentRef.dataOr(this.originalDocumentRef), templateRef: templateRef.dataOr(this.templateRef), - categoryId: categoryId.dataOr(this.categoryId), + parameters: parameters.dataOr(this.parameters), versions: versions ?? this.versions, fromActiveCampaign: fromActiveCampaign ?? this.fromActiveCampaign, ); diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposals/proposals_cubit.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposals/proposals_cubit.dart index bde0d77cd7d8..41c8bd76502f 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposals/proposals_cubit.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposals/proposals_cubit.dart @@ -109,8 +109,8 @@ final class ProposalsCubit extends Cubit } } - void changeSelectedCategory(SignedDocumentRef? categoryId) { - emitSignal(ChangeCategoryProposalsSignal(to: categoryId)); + void changeSelectedCategory(SignedDocumentRef? categoryRef) { + emitSignal(ChangeCategoryProposalsSignal(to: categoryRef)); } @override @@ -218,11 +218,11 @@ final class ProposalsCubit extends Cubit final mappedPage = page.map( // TODO(damian-molinski): refactor page to return ProposalWithContext instead. - (e) => ProposalBrief.fromProposal( - e.proposal, - isFavorite: state.favoritesIds.contains(e.proposal.selfRef.id), + (proposal) => ProposalBrief.fromProposal( + proposal.proposal, + isFavorite: state.favoritesIds.contains(proposal.proposal.selfRef.id), categoryName: campaign.categories - .firstWhere((element) => element.selfRef == e.proposal.categoryRef) + .firstWhere((category) => proposal.proposal.parameters.containsId(category.selfRef.id)) .formattedCategoryName, showComments: showComments, ), diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposals/proposals_state.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposals/proposals_state.dart index 489037855810..08cd4937bab1 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposals/proposals_state.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposals/proposals_state.dart @@ -11,7 +11,7 @@ final class ProposalsCategoryState extends Equatable { @override List get props => [items]; - SignedDocumentRef? get selectedCategoryId { + SignedDocumentRef? get selectedCategoryRef { return items.singleWhereOrNull((element) => element.isSelected)?.ref; } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/voting/voting_cubit.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/voting/voting_cubit.dart index 6a4ad63970c2..480becbbfad4 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/voting/voting_cubit.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/voting/voting_cubit.dart @@ -90,8 +90,8 @@ final class VotingCubit extends Cubit } } - void changeSelectedCategory(SignedDocumentRef? categoryId) { - emitSignal(ChangeCategoryVotingSignal(to: categoryId)); + void changeSelectedCategory(SignedDocumentRef? categoryRef) { + emitSignal(ChangeCategoryVotingSignal(to: categoryRef)); } @override diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/voting/voting_state.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/voting/voting_state.dart index e4ea08105d6b..579de1446588 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/voting/voting_state.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/voting/voting_state.dart @@ -57,7 +57,7 @@ class VotingState extends Equatable { categorySelectorItems, ]; - SignedDocumentRef? get selectedCategoryId { + SignedDocumentRef? get selectedCategoryRef { return categorySelectorItems.singleWhereOrNull((element) => element.isSelected)?.ref; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/workspace/workspace_bloc.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/workspace/workspace_bloc.dart index 45bdcbda8b49..ca7f195c69d0 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/workspace/workspace_bloc.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/workspace/workspace_bloc.dart @@ -57,15 +57,11 @@ final class WorkspaceBloc extends Bloc } DocumentDataMetadata _buildDocumentMetadata(ProposalDocument document) { - final selfRef = document.metadata.selfRef; - final categoryId = document.metadata.categoryId; - final templateRef = document.metadata.templateRef; - - return DocumentDataMetadata( - type: DocumentType.proposalDocument, - selfRef: selfRef, - template: templateRef, - categoryId: categoryId, + return DocumentDataMetadata.proposal( + selfRef: document.metadata.selfRef, + template: document.metadata.templateRef, + parameters: document.metadata.parameters, + authors: document.metadata.authors, ); } @@ -106,7 +102,10 @@ final class WorkspaceBloc extends Bloc final documentContent = _buildDocumentContent(docData.document.document); final encodedProposal = await _proposalService.encodeProposalForExport( - document: DocumentData(metadata: docMetadata, content: documentContent), + document: DocumentData( + metadata: docMetadata, + content: documentContent, + ), ); final filename = '${event.prefix}_${event.ref.id}'; @@ -128,7 +127,7 @@ final class WorkspaceBloc extends Bloc emit(state.copyWith(isLoading: true)); await _proposalService.forgetProposal( proposalRef: proposal.selfRef as SignedDocumentRef, - categoryId: proposal.categoryId, + proposalParameters: proposal.parameters, ); emit(state.copyWith(userProposals: _removeProposal(event.ref))); emitSignal(const ForgetProposalSuccessWorkspaceSignal()); @@ -192,7 +191,9 @@ final class WorkspaceBloc extends Bloc final campaigns = Campaign.all; final categories = campaigns.expand((element) => element.categories); - final category = categories.firstWhereOrNull((e) => e.selfRef.id == proposal.categoryRef.id); + final category = categories.firstWhereOrNull( + (e) => proposal.parameters.containsId(e.selfRef.id), + ); // TODO(damian-molinski): refactor it final fundNumber = category != null @@ -241,7 +242,7 @@ final class WorkspaceBloc extends Bloc } await _proposalService.unlockProposal( proposalRef: proposal.selfRef as SignedDocumentRef, - categoryId: proposal.categoryId, + proposalParameters: proposal.parameters, ); emitSignal(OpenProposalBuilderSignal(ref: event.ref)); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/test/session/session_cubit_test.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/test/session/session_cubit_test.dart index e2f486958057..1de260c68428 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/test/session/session_cubit_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/test/session/session_cubit_test.dart @@ -2,8 +2,7 @@ import 'package:catalyst_cardano/catalyst_cardano.dart'; import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_repositories/catalyst_voices_repositories.dart'; -import 'package:catalyst_voices_repositories/generated/api/cat_gateway.swagger.dart' - show RbacRegistrationChain; +import 'package:catalyst_voices_repositories/src/api/models/rbac_registration_chain.dart'; import 'package:catalyst_voices_services/catalyst_voices_services.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; import 'package:catalyst_voices_view_models/catalyst_voices_view_models.dart' hide Uuid; diff --git a/catalyst_voices/packages/internal/catalyst_voices_blocs/test/workspace/workspace_bloc_test.dart b/catalyst_voices/packages/internal/catalyst_voices_blocs/test/workspace/workspace_bloc_test.dart index dec5561e0a3d..5c62a6d284a1 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_blocs/test/workspace/workspace_bloc_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_blocs/test/workspace/workspace_bloc_test.dart @@ -19,13 +19,14 @@ void main() { final proposalRef = SignedDocumentRef.generateFirstRef(); final categoryRef = SignedDocumentRef.generateFirstRef(); + final authorId = CatalystId(host: 'test', role0Key: Uint8List(32)); final documentData = DocumentData( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadata.proposal( selfRef: proposalRef, template: SignedDocumentRef.generateFirstRef(), - categoryId: categoryRef, + parameters: DocumentParameters({categoryRef}), + authors: [authorId], ), content: const DocumentDataContent({}), ); @@ -73,7 +74,6 @@ void main() { categories: [ CampaignCategory( selfRef: categoryRef, - proposalTemplateRef: SignedDocumentRef.generateFirstRef(), campaignRef: SignedDocumentRef.generateFirstRef(), categoryName: 'Test Category', categorySubname: 'Test Subname', @@ -128,7 +128,6 @@ void main() { categories: [ CampaignCategory( selfRef: categoryRef, - proposalTemplateRef: SignedDocumentRef.generateFirstRef(), campaignRef: SignedDocumentRef.generateFirstRef(), categoryName: 'Test Category', categorySubname: 'Test Subname', diff --git a/catalyst_voices/packages/internal/catalyst_voices_brands/pubspec.yaml b/catalyst_voices/packages/internal/catalyst_voices_brands/pubspec.yaml index 8c3a6df7835f..ac58ecd8ef65 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_brands/pubspec.yaml +++ b/catalyst_voices/packages/internal/catalyst_voices_brands/pubspec.yaml @@ -22,4 +22,4 @@ dev_dependencies: path: ../catalyst_voices_blocs flutter_test: sdk: flutter - test: ^1.25.15 + test: ^1.27.0 diff --git a/catalyst_voices/packages/internal/catalyst_voices_localization/lib/l10n/intl_en.arb b/catalyst_voices/packages/internal/catalyst_voices_localization/lib/l10n/intl_en.arb index 02e241169ee1..cc251f554e0f 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_localization/lib/l10n/intl_en.arb +++ b/catalyst_voices/packages/internal/catalyst_voices_localization/lib/l10n/intl_en.arb @@ -133,6 +133,14 @@ "@anonymousUsername": { "description": "When account does not have specified username this text is shown" }, + "apiErrorBadCertificate": "Bad certificate", + "@apiErrorBadCertificate": { + "description": "Generic message when incorrect certificate is used for api requests" + }, + "apiErrorConnectionError": "Connection error", + "@apiErrorConnectionError": { + "description": "Message of an error when api is not reachable." + }, "apiErrorInternalServerError": "Internal server error", "@apiErrorInternalServerError": { "description": "Message of an error when api returns matching status code." @@ -145,10 +153,18 @@ "@apiErrorNotFound": { "description": "Message of an error when api returns not found status code, depends on context." }, + "apiErrorRequestCancelled": "Request cancelled", + "@apiErrorRequestCancelled": { + "description": "Message of an error when api request is cancelled." + }, "apiErrorServiceUnavailable": "Service Unavailable", "@apiErrorServiceUnavailable": { "description": "Message of an error when api returns matching status code." }, + "apiErrorTimeout": "Connection timeout", + "@apiErrorTimeout": { + "description": "Message of an error when api request times out." + }, "apiErrorTooManyRequests": "Too many requests, please try again in 10 minutes.", "@apiErrorTooManyRequests": { "description": "Message of an error when api returns matching status code." diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/api_response_status_code.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/api_response_status_code.dart index 64b584dcf972..f9ddbe03a3c9 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/api_response_status_code.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/api_response_status_code.dart @@ -2,7 +2,7 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; /// Defines well-known status codes. /// -/// See [ApiErrorResponseException]. +/// See [ApiBadResponseException]. abstract class ApiResponseStatusCode { /// The client has not sent valid request, could be an invalid HTTP in /// general or provided not correct headers, path or query arguments. diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_bad_certificate_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_bad_certificate_exception.dart new file mode 100644 index 000000000000..8aa793555832 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_bad_certificate_exception.dart @@ -0,0 +1,9 @@ +part of 'api_exception.dart'; + +final class ApiBadCertificateException extends ApiException { + const ApiBadCertificateException({ + super.message, + super.uri, + super.error, + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_bad_response_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_bad_response_exception.dart new file mode 100644 index 000000000000..e2d766fffb86 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_bad_response_exception.dart @@ -0,0 +1,29 @@ +part of 'api_exception.dart'; + +final class ApiBadResponseException extends ApiException { + /// Http response code + final int statusCode; + + /// Optional response body. + /// + /// It's dynamic changes base on endpoint and status code. That's why it's a [Object]. + final Object? responseBody; + + const ApiBadResponseException({ + required this.statusCode, + super.message, + super.uri, + super.error, + this.responseBody, + }); + + const ApiBadResponseException.notFound({ + super.message, + super.uri, + super.error, + this.responseBody, + }) : statusCode = ApiResponseStatusCode.notFound; + + @override + List get props => super.props + [statusCode, responseBody]; +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_connection_error_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_connection_error_exception.dart new file mode 100644 index 000000000000..8f03182f26b5 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_connection_error_exception.dart @@ -0,0 +1,9 @@ +part of 'api_exception.dart'; + +final class ApiConnectionErrorException extends ApiException { + const ApiConnectionErrorException({ + super.message, + super.uri, + super.error, + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_connection_timeout_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_connection_timeout_exception.dart new file mode 100644 index 000000000000..dd2a808234ef --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_connection_timeout_exception.dart @@ -0,0 +1,15 @@ +part of 'api_exception.dart'; + +final class ApiConnectionTimeoutException extends ApiException { + final Duration? duration; + + const ApiConnectionTimeoutException({ + super.message, + super.uri, + super.error, + this.duration, + }); + + @override + List get props => super.props + [duration]; +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_error_response_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_error_response_exception.dart deleted file mode 100644 index 961f8c59afeb..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_error_response_exception.dart +++ /dev/null @@ -1,31 +0,0 @@ -part of 'api_exception.dart'; - -/// Api did response but status code is not >=200 <300. -final class ApiErrorResponseException extends ApiException { - /// Http response code - final int statusCode; - - /// Optional response body. - /// - /// It's dynamic changes base on endpoint and status code. That's why it's a [Object]. - final Object? error; - - const ApiErrorResponseException({ - required this.statusCode, - this.error, - }); - - const ApiErrorResponseException.notFound([this.error]) - : statusCode = ApiResponseStatusCode.notFound; - - @override - List get props => [statusCode, error]; - - @override - String toString() { - final error = this.error; - return error == null - ? 'ApiErrorResponse with statusCode: $statusCode' - : 'ApiErrorResponse with statusCode: $statusCode and error $error'; - } -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_exception.dart index 85f3b189b8e0..99857aa6fceb 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_exception.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_exception.dart @@ -1,17 +1,38 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:equatable/equatable.dart'; +import 'package:meta/meta.dart'; -part 'api_error_response_exception.dart'; +part 'api_bad_certificate_exception.dart'; +part 'api_bad_response_exception.dart'; +part 'api_connection_error_exception.dart'; +part 'api_connection_timeout_exception.dart'; part 'api_malformed_body_exception.dart'; +part 'api_receive_timeout_exception.dart'; +part 'api_request_cancelled_exception.dart'; +part 'api_send_timeout_exception.dart'; +part 'api_unknown_exception.dart'; /// Specialized [Exception] for cases when API returns response but it's not successful or /// invalid for any reason. /// /// If maybe used when response body does not match what we're expecting. -/// -/// See: -/// - [ApiErrorResponseException] -/// - [ApiMalformedBodyException] sealed class ApiException extends Equatable implements Exception { - const ApiException(); + /// Optional human readable message. + final String? message; + + /// Request URI associated with the failure when available. + final Uri? uri; + + /// Underlying error of the failure if present. + final Object? error; + + const ApiException({ + this.message, + this.uri, + this.error, + }); + + @override + @mustCallSuper + List get props => [message, uri, error]; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_malformed_body_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_malformed_body_exception.dart index 2d0f4d9ef93b..8e2f73a18f5b 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_malformed_body_exception.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_malformed_body_exception.dart @@ -3,7 +3,4 @@ part of 'api_exception.dart'; /// Response body did not match what was expected. final class ApiMalformedBodyException extends ApiException { const ApiMalformedBodyException(); - - @override - List get props => []; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_receive_timeout_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_receive_timeout_exception.dart new file mode 100644 index 000000000000..1ad2686849c1 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_receive_timeout_exception.dart @@ -0,0 +1,15 @@ +part of 'api_exception.dart'; + +final class ApiReceiveTimeoutException extends ApiException { + final Duration? duration; + + const ApiReceiveTimeoutException({ + super.message, + super.uri, + super.error, + this.duration, + }); + + @override + List get props => super.props + [duration]; +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_request_cancelled_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_request_cancelled_exception.dart new file mode 100644 index 000000000000..8fb6108e8f61 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_request_cancelled_exception.dart @@ -0,0 +1,9 @@ +part of 'api_exception.dart'; + +final class ApiRequestCancelledException extends ApiException { + const ApiRequestCancelledException({ + super.message, + super.uri, + super.error, + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_send_timeout_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_send_timeout_exception.dart new file mode 100644 index 000000000000..31736b12d824 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_send_timeout_exception.dart @@ -0,0 +1,15 @@ +part of 'api_exception.dart'; + +final class ApiSendTimeoutException extends ApiException { + final Duration? duration; + + const ApiSendTimeoutException({ + super.message, + super.uri, + super.error, + this.duration, + }); + + @override + List get props => super.props + [duration]; +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_unknown_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_unknown_exception.dart new file mode 100644 index 000000000000..80f72df5e6cb --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/api/exception/api_unknown_exception.dart @@ -0,0 +1,9 @@ +part of 'api_exception.dart'; + +final class ApiUnknownException extends ApiException { + const ApiUnknownException({ + super.message, + super.uri, + super.error, + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/campaign_category.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/campaign_category.dart index 3186e890bd73..708bdbd6c58d 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/campaign_category.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/campaign_category.dart @@ -7,7 +7,6 @@ import 'package:equatable/equatable.dart'; /// Should have factory constructor from document representation. class CampaignCategory extends Equatable { final SignedDocumentRef selfRef; - final SignedDocumentRef proposalTemplateRef; final SignedDocumentRef campaignRef; final String categoryName; final String categorySubname; @@ -26,7 +25,6 @@ class CampaignCategory extends Equatable { const CampaignCategory({ required this.selfRef, - required this.proposalTemplateRef, required this.campaignRef, required this.categoryName, required this.categorySubname, @@ -49,7 +47,6 @@ class CampaignCategory extends Equatable { @override List get props => [ selfRef, - proposalTemplateRef, campaignRef, categoryName, categorySubname, @@ -68,7 +65,6 @@ class CampaignCategory extends Equatable { CampaignCategory copyWith({ SignedDocumentRef? selfRef, - SignedDocumentRef? proposalTemplateRef, SignedDocumentRef? campaignRef, String? categoryName, String? categorySubname, @@ -87,7 +83,6 @@ class CampaignCategory extends Equatable { }) { return CampaignCategory( selfRef: selfRef ?? this.selfRef, - proposalTemplateRef: proposalTemplateRef ?? this.proposalTemplateRef, campaignRef: campaignRef ?? this.campaignRef, categoryName: categoryName ?? this.categoryName, categorySubname: categorySubname ?? this.categorySubname, diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/campaign_filters.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/campaign_filters.dart index 9969674c7b5b..c3e522153062 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/campaign_filters.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/campaign_filters.dart @@ -13,6 +13,11 @@ final class CampaignFilters extends Equatable { return CampaignFilters(categoriesIds: categoriesIds); } + factory CampaignFilters.from(Campaign campaign) { + final categoriesIds = campaign.categories.map((e) => e.selfRef.id).toSet().toList(); + return CampaignFilters(categoriesIds: categoriesIds); + } + @override List get props => [categoriesIds]; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/constant/f14_static_campaign_categories.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/constant/f14_static_campaign_categories.dart index fe0dd0e86f9a..535be958ff3b 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/constant/f14_static_campaign_categories.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/constant/f14_static_campaign_categories.dart @@ -9,7 +9,6 @@ import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; final f14StaticCampaignCategories = [ CampaignCategory( selfRef: f14ConstDocumentsRefs[0].category, - proposalTemplateRef: f14ConstDocumentsRefs[0].proposal, campaignRef: Campaign.f14Ref, categoryName: 'Cardano Use Case:', categorySubname: 'Partners & Products', @@ -93,7 +92,6 @@ The following will **not** be funded: ), CampaignCategory( selfRef: f14ConstDocumentsRefs[1].category, - proposalTemplateRef: f14ConstDocumentsRefs[1].proposal, campaignRef: Campaign.f14Ref, categoryName: 'Cardano Use Case:', categorySubname: 'Concept', @@ -176,7 +174,6 @@ The following will **not** be funded: ), CampaignCategory( selfRef: f14ConstDocumentsRefs[2].category, - proposalTemplateRef: f14ConstDocumentsRefs[2].proposal, campaignRef: Campaign.f14Ref, categoryName: 'Cardano Open:', categorySubname: 'Developers', @@ -261,7 +258,6 @@ The following will **not** be funded: ), CampaignCategory( selfRef: f14ConstDocumentsRefs[3].category, - proposalTemplateRef: f14ConstDocumentsRefs[3].proposal, campaignRef: Campaign.f14Ref, categoryName: 'Cardano Open:', categorySubname: 'Ecosystem', diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/constant/f15_static_campaign_categories.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/constant/f15_static_campaign_categories.dart index 524469d21007..3392101cf108 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/constant/f15_static_campaign_categories.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/constant/f15_static_campaign_categories.dart @@ -10,8 +10,7 @@ final f15StaticCampaignCategories = [ //Tier-1 Enterprise Integrations CampaignCategory( selfRef: f15ConstDocumentsRefs[0].category, - proposalTemplateRef: f15ConstDocumentsRefs[0].proposal, - campaignRef: f15ConstDocumentsRefs[0].comment, + campaignRef: Campaign.f15Ref, categoryName: 'Cardano Partners:', categorySubname: 'Tier-1 Enterprise Integrations', description: @@ -139,8 +138,7 @@ Use this checklist to ensure your proposal meets all foundational and content re //Cardano Use Cases: Prototype & Launch CampaignCategory( selfRef: f15ConstDocumentsRefs[1].category, - proposalTemplateRef: f15ConstDocumentsRefs[1].proposal, - campaignRef: f15ConstDocumentsRefs[1].comment, + campaignRef: Campaign.f15Ref, categoryName: 'Cardano Use Cases:', categorySubname: 'Prototype & Launch', description: @@ -247,8 +245,7 @@ Use this checklist to ensure your proposal meets all foundational and content re // //Cardano Open: Ecosystem CampaignCategory( selfRef: f15ConstDocumentsRefs[2].category, - proposalTemplateRef: f15ConstDocumentsRefs[2].proposal, - campaignRef: f15ConstDocumentsRefs[2].comment, + campaignRef: Campaign.f15Ref, categoryName: 'Cardano Open:', categorySubname: 'Ecosystem', description: @@ -354,8 +351,7 @@ Use this checklist to ensure your proposal meets all foundational and content re //Midnight: Compact DApps CampaignCategory( selfRef: f15ConstDocumentsRefs[3].category, - proposalTemplateRef: f15ConstDocumentsRefs[3].proposal, - campaignRef: f15ConstDocumentsRefs[3].comment, + campaignRef: Campaign.f15Ref, categoryName: 'Midnight:', categorySubname: 'Compact DApps', description: diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/exception/active_campaign_not_found_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/exception/active_campaign_not_found_exception.dart new file mode 100644 index 000000000000..b9d4b368b438 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/exception/active_campaign_not_found_exception.dart @@ -0,0 +1,11 @@ +import 'package:equatable/equatable.dart'; + +final class ActiveCampaignNotFoundException extends Equatable implements Exception { + const ActiveCampaignNotFoundException(); + + @override + List get props => []; + + @override + String toString() => 'ActiveCampaignNotFoundException'; +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart index 14e224995d1a..447316f85f6f 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart @@ -12,6 +12,7 @@ export 'campaign/campaign_category.dart'; export 'campaign/campaign_filters.dart'; export 'campaign/campaign_phase.dart'; export 'campaign/campaign_timeline.dart'; +export 'campaign/exception/active_campaign_not_found_exception.dart'; export 'common/hi_lo/hi_lo.dart'; export 'common/hi_lo/uuid_hi_lo.dart'; export 'common/markdown_data.dart'; @@ -38,6 +39,7 @@ export 'document/constant/all_const_documents_refs.dart'; export 'document/constant/constant_documents_refs.dart'; export 'document/constant/f14_const_documents_refs.dart'; export 'document/constant/f15_const_documents_refs.dart'; +export 'document/data/document_content_type.dart'; export 'document/data/document_data.dart'; export 'document/data/document_data_content.dart'; export 'document/data/document_data_metadata.dart'; @@ -46,6 +48,7 @@ export 'document/data/proposal_document_data.dart'; export 'document/document.dart'; export 'document/document_mapper.dart'; export 'document/document_node_id.dart'; +export 'document/document_parameters.dart'; export 'document/document_ref.dart'; export 'document/enums/document_content_media_type.dart'; export 'document/enums/document_property_format.dart'; diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/constant/constant_documents_refs.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/constant/constant_documents_refs.dart index ad8515de7dda..d59250ec4389 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/constant/constant_documents_refs.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/constant/constant_documents_refs.dart @@ -4,16 +4,20 @@ import 'package:equatable/equatable.dart'; /// Groups related [proposal] and [comment] templates to given [category]. final class CategoryTemplatesRefs extends Equatable { final SignedDocumentRef category; - final SignedDocumentRef proposal; - final SignedDocumentRef comment; + final SignedDocumentRef? proposal; + final SignedDocumentRef? comment; const CategoryTemplatesRefs({ required this.category, - required this.proposal, - required this.comment, + this.proposal, + this.comment, }); - Iterable get all => [category, proposal, comment]; + Iterable get all => [ + category, + ?proposal, + ?comment, + ]; Iterable get allTyped { return [ @@ -21,11 +25,17 @@ final class CategoryTemplatesRefs extends Equatable { ref: category, type: DocumentType.categoryParametersDocument, ), - TypedDocumentRef(ref: proposal, type: DocumentType.proposalTemplate), - TypedDocumentRef(ref: comment, type: DocumentType.commentTemplate), + if (proposal case final value?) + TypedDocumentRef(ref: value, type: DocumentType.proposalTemplate), + if (comment case final value?) + TypedDocumentRef(ref: value, type: DocumentType.commentTemplate), ]; } @override - List get props => [category, proposal, comment]; + List get props => [ + category, + proposal, + comment, + ]; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/data/document_content_type.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/data/document_content_type.dart new file mode 100644 index 000000000000..078731351e17 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/data/document_content_type.dart @@ -0,0 +1,23 @@ +import 'package:catalyst_voices_models/src/document/data/document_data_content.dart'; + +/// Defines the content type of the [DocumentDataContent]. +enum DocumentContentType { + /// The document's content type is JSON. + json('application/json'), + + /// Unrecognized content type. + unknown('unknown'); + + final String value; + + const DocumentContentType(this.value); + + static DocumentContentType fromJson(String data) { + return DocumentContentType.values.firstWhere( + (element) => element.value == data, + orElse: () => DocumentContentType.unknown, + ); + } + + static String toJson(DocumentContentType type) => type.value; +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/data/document_data_metadata.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/data/document_data_metadata.dart index 15a8c133d19d..046d691d867b 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/data/document_data_metadata.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/data/document_data_metadata.dart @@ -1,9 +1,12 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:equatable/equatable.dart'; -/// Describes what [DocumentDataContent] is about. It only makes sens in -/// context of [type]. +/// Describes what [DocumentDataContent] is about. It only makes sense in +/// the context of [type]. final class DocumentDataMetadata extends Equatable { + /// The content type of the document payload this metadata is attached to. + final DocumentContentType contentType; + /// Type of this signed document final DocumentType type; @@ -14,9 +17,6 @@ final class DocumentDataMetadata extends Equatable { /// on the document type. final DocumentRef? ref; - /// This is a cryptographically secured reference to another document. - final SecuredDocumentRef? refHash; - /// If the document was formed from a template, this is a reference to that /// template document final SignedDocumentRef? template; @@ -27,93 +27,154 @@ final class DocumentDataMetadata extends Equatable { /// A reference to a section of a document. final String? section; - /// uuid-v4 - /// Represents a "brand" who is running the voting, e.g. Catalyst, Midnight. - final SignedDocumentRef? brandId; - - /// uuid-v4 - /// Defines a "campaign" of voting, e.g. "treasury campaign". - final SignedDocumentRef? campaignId; - - /// uuid-v4 - /// Defines an election, e.g. "Catalyst Fund 1", "Catalyst Fund 2". - final String? electionId; + /// A list of allowed Collaborators on the next subsequent version of a document. + final List? collaborators; - /// uuid-v4 - /// Defines a voting category as a collection of proposals, e.g. - /// "Development & Infrastructure", - /// "Products & Integrations". - final SignedDocumentRef? categoryId; + /// A list of referenced parameters like brand, category or campaign. + final DocumentParameters parameters; - /// List of authors represented by CatalystId + /// List of authors represented by CatalystId. + /// + /// Note. This list just represents who signed this version + /// Note. Can change from version to version when [collaborators] are non empty. final List? authors; - // TODO(damian-molinski): refactor with factory constructors for - // proposal/comment to centralize required fields for each type. + /// The default constructor for the [DocumentDataMetadata]. DocumentDataMetadata({ + required this.contentType, required this.type, required this.selfRef, this.ref, - this.refHash, this.template, this.reply, this.section, - this.brandId, - this.campaignId, - this.electionId, - this.categoryId, + this.collaborators, + this.parameters = const DocumentParameters(), this.authors, }) : assert( selfRef.isExact, 'selfRef have to be exact. Make sure version is not null', ); + /// Creates a [DocumentDataMetadata] representing a [DocumentType.commentDocument]. + /// + /// The [parameters] should be the ones assigned to the [proposalRef]. + factory DocumentDataMetadata.comment({ + required SignedDocumentRef selfRef, + required SignedDocumentRef proposalRef, + required SignedDocumentRef template, + required DocumentParameters parameters, + required List authors, + SignedDocumentRef? reply, + }) { + return DocumentDataMetadata( + contentType: DocumentContentType.json, + type: DocumentType.commentDocument, + selfRef: selfRef, + ref: proposalRef, + template: template, + reply: reply, + parameters: parameters, + authors: authors, + ); + } + + /// Creates a [DocumentDataMetadata] representing a [DocumentType.proposalDocument]. + /// + /// The [parameters] should be the ones assigned to the [template]. + factory DocumentDataMetadata.proposal({ + required DocumentRef selfRef, + required SignedDocumentRef template, + required DocumentParameters parameters, + required List authors, + List? collaborators, + }) { + return DocumentDataMetadata( + type: DocumentType.proposalDocument, + contentType: DocumentContentType.json, + selfRef: selfRef, + template: template, + parameters: parameters, + authors: authors, + collaborators: collaborators, + ); + } + + /// Creates a [DocumentDataMetadata] representing a [DocumentType.proposalActionDocument]. + /// + /// The [parameters] should be the ones assigned to the [proposalRef]. + factory DocumentDataMetadata.proposalAction({ + required SignedDocumentRef selfRef, + required SignedDocumentRef proposalRef, + required DocumentParameters parameters, + }) { + return DocumentDataMetadata( + type: DocumentType.proposalActionDocument, + contentType: DocumentContentType.json, + selfRef: selfRef, + ref: proposalRef, + parameters: parameters, + ); + } + + /// Creates a [DocumentDataMetadata] representing a [DocumentType.proposalTemplate]. + /// + /// The [parameters] should be the ones assigned to template's parent, most likely the category. + factory DocumentDataMetadata.proposalTemplate({ + required DocumentRef selfRef, + required DocumentParameters parameters, + }) { + return DocumentDataMetadata( + type: DocumentType.proposalTemplate, + contentType: DocumentContentType.json, + selfRef: selfRef, + parameters: parameters, + ); + } + String get id => selfRef.id; @override List get props => [ + contentType, type, selfRef, ref, - refHash, template, reply, section, - brandId, - campaignId, - electionId, - categoryId, + collaborators, + parameters, authors, ]; + /// Who signed this document version. Can change from version to version. + List? get signers => authors; + String get version => selfRef.version!; DocumentDataMetadata copyWith({ + DocumentContentType? contentType, DocumentType? type, DocumentRef? selfRef, Optional? ref, - Optional? refHash, Optional? template, Optional? reply, Optional? section, - Optional? brandId, - Optional? campaignId, - Optional? electionId, - Optional? categoryId, + Optional>? collaborators, + DocumentParameters? parameters, Optional>? authors, }) { return DocumentDataMetadata( + contentType: contentType ?? this.contentType, type: type ?? this.type, selfRef: selfRef ?? this.selfRef, ref: ref.dataOr(this.ref), - refHash: refHash.dataOr(this.refHash), template: template.dataOr(this.template), reply: reply.dataOr(this.reply), section: section.dataOr(this.section), - brandId: brandId.dataOr(this.brandId), - campaignId: campaignId.dataOr(this.campaignId), - electionId: electionId.dataOr(this.electionId), - categoryId: categoryId.dataOr(this.categoryId), + collaborators: collaborators.dataOr(this.collaborators), + parameters: parameters ?? this.parameters, authors: authors.dataOr(this.authors), ); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/document_metadata.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/document_metadata.dart index b64366787fca..12315f44a0e3 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/document_metadata.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/document_metadata.dart @@ -10,13 +10,18 @@ import 'package:meta/meta.dart'; abstract base class DocumentMetadata extends Equatable { final DocumentRef selfRef; + /// A list of referenced parameters like brand, campaign or category. + final DocumentParameters parameters; + DocumentMetadata({ required this.selfRef, + required this.parameters, }) : assert(selfRef.isExact, 'SelfRef have to be exact!'); @override @mustCallSuper List get props => [ selfRef, + parameters, ]; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/document_parameters.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/document_parameters.dart new file mode 100644 index 000000000000..dececa8c785f --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/document_parameters.dart @@ -0,0 +1,25 @@ +import 'package:catalyst_voices_models/src/document/document_ref.dart'; +import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; +import 'package:equatable/equatable.dart'; + +/// Parameters associated with a document, like brand, campaign or category. +final class DocumentParameters extends Equatable { + final Set set; + + const DocumentParameters([this.set = const {}]); + + bool get isEmpty => set.isEmpty; + + bool get isNotEmpty => set.isNotEmpty; + + @override + List get props => [set]; + + bool contains(SignedDocumentRef ref) { + return set.contains(ref); + } + + bool containsId(String id) { + return set.any((e) => e.id.equalsIgnoreCase(id)); + } +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/document_ref.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/document_ref.dart index 1c0ddabbfef2..78a392b5a99a 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/document_ref.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/document_ref.dart @@ -1,7 +1,6 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; import 'package:equatable/equatable.dart'; -import 'package:flutter/foundation.dart' show Uint8List; import 'package:uuid_plus/uuid_plus.dart'; /// Represents ref to any kind of document. Documents often have refs to other document @@ -150,20 +149,6 @@ final class DraftRef extends DocumentRef { String toString() => isExact ? 'ExactDraftRef($id.v$version)' : 'LooseDraftRef($id)'; } -/// -final class SecuredDocumentRef extends Equatable { - final DocumentRef ref; - final Uint8List hash; - - const SecuredDocumentRef({ - required this.ref, - required this.hash, - }); - - @override - List get props => [ref, hash]; -} - /// Ref to published document. final class SignedDocumentRef extends DocumentRef { const SignedDocumentRef({ diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/comment_document.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/comment_document.dart index b2d07dae8ddc..e369144a68ab 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/comment_document.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/comment_document.dart @@ -16,52 +16,38 @@ final class CommentDocument extends Equatable { @override List get props => [metadata, document]; - DocumentData toDocumentData({ - required DocumentMapper mapper, - }) { + DocumentData toDocumentData({required DocumentMapper mapper}) { return DocumentData( - metadata: DocumentDataMetadata( - type: DocumentType.commentDocument, - selfRef: metadata.selfRef, - ref: metadata.ref, - template: metadata.template, - reply: metadata.reply, - authors: [metadata.authorId], - categoryId: metadata.categoryId, - ), + metadata: metadata.toDocumentMetadata(), content: mapper.toContent(document), ); } } final class CommentMetadata extends DocumentMetadata { - /// [ref] is document ref that this comment refers to. Comment can not + /// [proposalRef] is document ref that this comment refers to. Comment can not /// exist on its own but just in a context of other documents. - final SignedDocumentRef ref; + final SignedDocumentRef proposalRef; - /// against which [CommentDocument] is valid. - final SignedDocumentRef template; + /// Against which [CommentDocument] is valid. + final SignedDocumentRef commentTemplate; /// [reply] equals other comment of this is a reply to it. final SignedDocumentRef? reply; - // Nullable only for backwards compatibility. - /// Pointer to category of proposal that [ref] points to. - final SignedDocumentRef? categoryId; - /// Creator of document. final CatalystId authorId; CommentMetadata({ // Note. no drafts for comments required SignedDocumentRef super.selfRef, - required this.ref, - required this.template, + required super.parameters, + required this.proposalRef, + required this.commentTemplate, this.reply, - required this.categoryId, required this.authorId, }) : assert( - ref.isExact, + proposalRef.isExact, 'Comments can refer only exact documents', ); @@ -69,13 +55,23 @@ final class CommentMetadata extends DocumentMetadata { List get props => super.props + [ - ref, - template, + proposalRef, + commentTemplate, reply, - categoryId, authorId, ]; @override SignedDocumentRef get selfRef => super.selfRef as SignedDocumentRef; + + DocumentDataMetadata toDocumentMetadata() { + return DocumentDataMetadata.comment( + selfRef: selfRef, + proposalRef: proposalRef, + template: commentTemplate, + reply: reply, + authors: [authorId], + parameters: parameters, + ); + } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/comment_template.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/comment_template.dart index 13ad8286bf16..5ccda41cd8ed 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/comment_template.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/comment_template.dart @@ -18,5 +18,6 @@ final class CommentTemplate extends Equatable { final class CommentTemplateMetadata extends DocumentMetadata { CommentTemplateMetadata({ required SignedDocumentRef super.selfRef, + required super.parameters, }); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/proposal_document.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/proposal_document.dart index 71949ba136ca..7d97ffe7bf32 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/proposal_document.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/proposal_document.dart @@ -163,20 +163,28 @@ final class ProposalDocument extends Equatable { } final class ProposalMetadata extends DocumentMetadata { + /// Proposal parameters like brand, campaign or category. + /// + /// Legacy documents stored them in separate fields, see [categoryIdNode]. + static const parametersNode = NodeId('parameters'); + + /// The id part of the [parametersNode]. + static const parametersIdNode = NodeId('parameters.*.id'); + + /// Legacy parameter name for the category. New format of the metadata uses [parameters]. static const categoryIdNode = NodeId('categoryId.id'); static const authorsNode = NodeId('authors'); final SignedDocumentRef templateRef; - final SignedDocumentRef categoryId; final List authors; ProposalMetadata({ required super.selfRef, + required super.parameters, required this.templateRef, - required this.categoryId, required this.authors, }); @override - List get props => super.props + [templateRef, categoryId, authors]; + List get props => super.props + [templateRef, authors]; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/proposal_template.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/proposal_template.dart index 60bde983410f..1f9d789c7c6e 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/proposal_template.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document/specialized/proposal_template.dart @@ -11,26 +11,21 @@ final class ProposalTemplate extends Equatable { required this.schema, }); - DocumentStringSchema? get title { - final property = schema.getPropertySchema(ProposalDocument.titleNodeId); - return property is DocumentStringSchema ? property : null; - } - @override List get props => [ metadata, schema, ]; + + DocumentStringSchema? get title { + final property = schema.getPropertySchema(ProposalDocument.titleNodeId); + return property is DocumentStringSchema ? property : null; + } } final class ProposalTemplateMetadata extends DocumentMetadata { - final SignedDocumentRef? categoryId; - ProposalTemplateMetadata({ required super.selfRef, - this.categoryId, + required super.parameters, }); - - @override - List get props => super.props + [categoryId]; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/errors/not_found_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/errors/not_found_exception.dart index 5259428f98f3..267909324ab2 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/errors/not_found_exception.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/errors/not_found_exception.dart @@ -6,7 +6,7 @@ final class NotFoundException extends Equatable implements Exception { const NotFoundException({this.message}); @override - List get props => []; + List get props => [message]; @override String toString() { diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/core_proposal.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/core_proposal.dart index 8620609c6e58..c7895db2259c 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/core_proposal.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/core_proposal.dart @@ -4,7 +4,7 @@ import 'package:equatable/equatable.dart'; base class CoreProposal extends Equatable implements Comparable { final DocumentRef selfRef; - final SignedDocumentRef categoryRef; + final DocumentParameters parameters; final String title; final String description; final Money fundsRequested; @@ -15,7 +15,7 @@ base class CoreProposal extends Equatable implements Comparable { const CoreProposal({ required this.selfRef, - required this.categoryRef, + required this.parameters, required this.title, required this.description, required this.fundsRequested, @@ -28,7 +28,7 @@ base class CoreProposal extends Equatable implements Comparable { @override List get props => [ selfRef, - categoryRef, + parameters, title, description, fundsRequested, @@ -53,7 +53,7 @@ base class CoreProposal extends Equatable implements Comparable { CoreProposal copyWith({ DocumentRef? selfRef, - SignedDocumentRef? categoryRef, + DocumentParameters? parameters, String? title, String? description, DateTime? updateDate, @@ -65,7 +65,7 @@ base class CoreProposal extends Equatable implements Comparable { }) { return CoreProposal( selfRef: selfRef ?? this.selfRef, - categoryRef: categoryRef ?? this.categoryRef, + parameters: parameters ?? this.parameters, title: title ?? this.title, description: description ?? this.description, fundsRequested: fundsRequested ?? this.fundsRequested, diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/detail_proposal.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/detail_proposal.dart index f3aa56aad129..b230f79a0a77 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/detail_proposal.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/detail_proposal.dart @@ -5,7 +5,7 @@ final class DetailProposal extends CoreProposal { factory DetailProposal({ required DocumentRef selfRef, - required SignedDocumentRef categoryRef, + required DocumentParameters parameters, required String title, required String description, required Money fundsRequested, @@ -19,7 +19,7 @@ final class DetailProposal extends CoreProposal { return DetailProposal._( selfRef: selfRef, - categoryRef: categoryRef, + parameters: parameters, title: title, description: description, fundsRequested: fundsRequested, @@ -37,7 +37,7 @@ final class DetailProposal extends CoreProposal { ) { return DetailProposal( selfRef: data.document.metadata.selfRef, - categoryRef: data.document.metadata.categoryId, + parameters: data.document.metadata.parameters, title: data.document.title ?? '', description: data.document.description ?? '', fundsRequested: data.document.fundsRequested ?? Money.zero(currency: Currencies.fallback), @@ -51,7 +51,7 @@ final class DetailProposal extends CoreProposal { const DetailProposal._({ required super.selfRef, - required super.categoryRef, + required super.parameters, required super.title, required super.description, required super.fundsRequested, @@ -78,7 +78,7 @@ extension ProposalWithVersionX on DetailProposal { id: '019584be-f0ef-7b01-8d36-422a3d6a0533', version: '019584be-2321-7a1a-9b68-ad33a97a7e84', ), - categoryRef: categoryRef ?? SignedDocumentRef.generateFirstRef(), + parameters: DocumentParameters({categoryRef ?? SignedDocumentRef.generateFirstRef()}), title: 'Dummy Proposal ver 2', description: 'Dummy description', fundsRequested: Money(currency: Currencies.ada, minorUnits: BigInt.from(100)), diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal.dart index 9ea54c49c0d3..4323c378eba3 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal.dart @@ -1,10 +1,12 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:collection/collection.dart'; final class Proposal extends CoreProposal { final int versionNumber; factory Proposal({ required DocumentRef selfRef, + required DocumentParameters parameters, required String title, required String description, required Money fundsRequested, @@ -13,12 +15,12 @@ final class Proposal extends CoreProposal { required int duration, required String? author, required int commentsCount, - required SignedDocumentRef categoryRef, }) { final versionNumber = versionsIds.versionNumber(selfRef.version!); return Proposal._( selfRef: selfRef, + parameters: parameters, title: title, fundsRequested: fundsRequested, publish: publish, @@ -27,7 +29,6 @@ final class Proposal extends CoreProposal { duration: duration, author: author, versionNumber: versionNumber, - categoryRef: categoryRef, ); } @@ -36,6 +37,7 @@ final class Proposal extends CoreProposal { return Proposal( selfRef: document.metadata.selfRef, + parameters: document.metadata.parameters, title: document.title ?? '', description: document.description ?? '', fundsRequested: document.fundsRequested ?? Money.zero(currency: Currencies.fallback), @@ -43,14 +45,13 @@ final class Proposal extends CoreProposal { duration: document.duration ?? 0, author: document.authorName, commentsCount: data.commentsCount, - categoryRef: data.document.metadata.categoryId, versionsIds: versionsIds, ); } const Proposal._({ required super.selfRef, - required super.categoryRef, + required super.parameters, required super.title, required super.description, required super.fundsRequested, @@ -64,7 +65,7 @@ final class Proposal extends CoreProposal { extension ProposalVersionsNumber on List { int versionNumber(String version) { - sort((versionA, versionB) => versionB.compareTo(versionA)); - return length - indexWhere((element) => element == version); + final list = sorted((versionA, versionB) => versionB.compareTo(versionA)); + return list.length - list.indexWhere((element) => element == version); } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/registration/registration_certificate.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/registration/registration_certificate.dart index 90b835f16661..a243ba0a4cd8 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/registration/registration_certificate.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/registration/registration_certificate.dart @@ -1,7 +1,20 @@ +import 'package:json_annotation/json_annotation.dart'; + +@JsonEnum(valueField: 'value') +enum CertificateType { + pubkey('pubkey'), + x509('x509'), + c509('c509'); + + final String value; + + const CertificateType(this.value); +} + /// Holds common constants about the certificates used in user registration. final class RegistrationCertificate { /// The type of the certificate used in the registration. - static const certificateType = 'x509'; + static const certificateType = CertificateType.x509; const RegistrationCertificate._(); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/signed_document/signed_document.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/signed_document/signed_document.dart index 6e1c5cde8ea5..124fc9c22385 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/signed_document/signed_document.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/signed_document/signed_document.dart @@ -2,11 +2,9 @@ import 'dart:typed_data'; -import 'package:catalyst_voices_models/src/document/data/document_type.dart'; -import 'package:catalyst_voices_models/src/document/document_ref.dart'; +import 'package:catalyst_voices_models/src/document/data/document_data_metadata.dart'; import 'package:catalyst_voices_models/src/signed_document/signed_document_payload.dart'; import 'package:catalyst_voices_models/src/user/catalyst_id.dart'; -import 'package:equatable/equatable.dart'; /// Represents an abstract document that is protected /// with cryptographic signature. @@ -18,7 +16,7 @@ abstract interface class SignedDocument { const SignedDocument(); /// A getter returning the metadata related to the signed document. - SignedDocumentMetadata get metadata; + DocumentDataMetadata get metadata; /// A getter that returns a parsed document payload. SignedDocumentPayload get payload; @@ -33,142 +31,3 @@ abstract interface class SignedDocument { /// that belongs to the given [catalystId]. Future verifySignature(CatalystId catalystId); } - -/// Defines the content type of the [SignedDocumentPayload]. -enum SignedDocumentContentType { - /// The document's content type is JSON. - json, - - /// Unrecognized content type. - unknown, -} - -final class SignedDocumentMetadata extends Equatable { - /// The document content type. - final SignedDocumentContentType contentType; - - /// The type of document this signed document encodes. - final DocumentType documentType; - - /// Unique identifier for the entity - final String? id; - - /// Version ID for the Proposal. - final String? ver; - - /// This is a reference to another document. - /// - /// The purpose of the ref will vary depending on the document type. - final SignedDocumentMetadataRef? ref; - - /// This is a cryptographically secured reference to another document. - final SignedDocumentMetadataRefHash? refHash; - - /// If the document was formed from a template, - /// this is a reference to that template document. - final SignedDocumentMetadataRef? template; - - /// A reply to another document. - final SignedDocumentMetadataRef? reply; - - /// A reference to a section of a document. - final String? section; - - /// A list of entities other than the original author that may also - /// publish versions of this document. - /// - /// This may be updated by the original author, - /// or any collaborator that is given "author" privileges. - final List? collabs; - - /// A reference to the brand targeted by the document. - final SignedDocumentMetadataRef? brandId; - - /// A reference to the campaign targeted by the document. - final SignedDocumentMetadataRef? campaignId; - - /// A reference to the election (fund) targeted by the document. - final String? electionId; - - /// A reference to the category targeted by the document. - final SignedDocumentMetadataRef? categoryId; - - const SignedDocumentMetadata({ - required this.contentType, - required this.documentType, - this.id, - this.ver, - this.ref, - this.refHash, - this.template, - this.reply, - this.section, - this.collabs, - this.brandId, - this.campaignId, - this.electionId, - this.categoryId, - }); - - @override - List get props => [ - contentType, - documentType, - id, - ver, - ref, - refHash, - template, - reply, - collabs, - brandId, - campaignId, - electionId, - categoryId, - ]; -} - -/// A reference to an entity represented by the [id]. -/// Optionally the version of the entity may be specified by the [ver]. -final class SignedDocumentMetadataRef extends Equatable { - /// The referenced entity uuid. - final String id; - - /// The version of the referenced entity. - final String? ver; - - /// The default constructor for the [SignedDocumentMetadataRef]. - const SignedDocumentMetadataRef({ - required this.id, - this.ver, - }); - - /// Creates an instance of [SignedDocumentMetadataRef] from [DocumentRef]. - factory SignedDocumentMetadataRef.fromDocumentRef(DocumentRef ref) { - return SignedDocumentMetadataRef( - id: ref.id, - ver: ref.version, - ); - } - - @override - List get props => [id, ver]; -} - -/// A cryptographically secured reference to another document. -final class SignedDocumentMetadataRefHash extends Equatable { - /// Simple reference to the document. - final SignedDocumentMetadataRef ref; - - /// Hash of the referenced document CBOR bytes. - final Uint8List hash; - - /// The default constructor for the [SignedDocumentMetadataRefHash]. - const SignedDocumentMetadataRefHash({ - required this.ref, - required this.hash, - }); - - @override - List get props => [ref, hash]; -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/signed_document/signed_document_payload.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/signed_document/signed_document_payload.dart index 76337bbd6dc8..c8d2a8a6d35e 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/signed_document/signed_document_payload.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/signed_document/signed_document_payload.dart @@ -23,7 +23,7 @@ final class SignedDocumentJsonPayload extends SignedDocumentPayload { } /// Represents [SignedDocument] payload. Type of payload depends on a -/// [SignedDocumentMetadata.contentType] and subclasses +/// [DocumentDataMetadata.contentType] and subclasses /// of [SignedDocumentPayload] are meant to reflect that. /// /// Use [SignedDocumentPayload.fromBytes] factory to create correct @@ -36,11 +36,11 @@ sealed class SignedDocumentPayload extends Equatable { /// which keeps [bytes] as is. factory SignedDocumentPayload.fromBytes( Uint8List bytes, { - required SignedDocumentContentType contentType, + required DocumentContentType contentType, }) { return switch (contentType) { - SignedDocumentContentType.json => SignedDocumentJsonPayload.fromBytes(bytes), - SignedDocumentContentType.unknown => SignedDocumentUnknownPayload(bytes), + DocumentContentType.json => SignedDocumentJsonPayload.fromBytes(bytes), + DocumentContentType.unknown => SignedDocumentUnknownPayload(bytes), }; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/user/account_role.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/user/account_role.dart index 09fba3e8b7c3..420b510a73cc 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/user/account_role.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/user/account_role.dart @@ -54,7 +54,7 @@ enum AccountRole { return values.firstWhereOrNull((e) => e.registrationOffset == registrationOffset); } - static AccountRole? maybeFromNumber(int? number) { + static AccountRole? maybeFromNumber(int number) { for (final value in values) { if (value.number == number) { return value; diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/pubspec.yaml b/catalyst_voices/packages/internal/catalyst_voices_models/pubspec.yaml index de086e8a810a..c0d43bb96829 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/pubspec.yaml +++ b/catalyst_voices/packages/internal/catalyst_voices_models/pubspec.yaml @@ -30,9 +30,9 @@ dependencies: uuid_plus: ^0.1.0 dev_dependencies: - build_runner: ^2.5.4 + build_runner: ^2.10.3 catalyst_analysis: ^3.0.0 flutter_test: sdk: flutter - json_serializable: ^6.9.5 - test: ^1.25.15 + json_serializable: ^6.11.1 + test: ^1.27.0 diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/document/data/document_data_metadata_test.dart b/catalyst_voices/packages/internal/catalyst_voices_models/test/document/data/document_data_metadata_test.dart index e5e05480196d..372c04129652 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/test/document/data/document_data_metadata_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/document/data/document_data_metadata_test.dart @@ -11,6 +11,7 @@ void main() { // When DocumentDataMetadata buildFun() { return DocumentDataMetadata( + contentType: DocumentContentType.json, type: DocumentType.proposalDocument, selfRef: selfRef, ); @@ -30,6 +31,7 @@ void main() { // When DocumentDataMetadata buildFun() { return DocumentDataMetadata( + contentType: DocumentContentType.json, type: DocumentType.proposalDocument, selfRef: selfRef, ); diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_with_versions_test.dart b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_with_versions_test.dart index 87ac6a1d9717..38936b35d6c6 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_with_versions_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_with_versions_test.dart @@ -18,7 +18,7 @@ void main() { isDraft: true, version: versionId2, ), - categoryRef: SignedDocumentRef.generateFirstRef(), + parameters: DocumentParameters({SignedDocumentRef.generateFirstRef()}), title: 'Title ver 1', description: 'Description ver 1', fundsRequested: Money(currency: Currencies.ada, minorUnits: BigInt.from(100)), @@ -85,7 +85,7 @@ void main() { isDraft: true, version: versionId1, ), - categoryRef: SignedDocumentRef.generateFirstRef(), + parameters: DocumentParameters({SignedDocumentRef.generateFirstRef()}), title: 'Title ver 1', description: 'Description ver 1', fundsRequested: Money(currency: Currencies.ada, minorUnits: BigInt.from(100)), diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/README.md b/catalyst_voices/packages/internal/catalyst_voices_repositories/README.md index c8e4195cbec0..0f9be93fae60 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/README.md +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/README.md @@ -1,36 +1,5 @@ # Catalyst Voices Repositories -## Automated Code Generation - -This package is used for the code generation from the OpenAPI specifications. -It leverages `swagger_dart_code_generator` library and the artifacts generated -for the documentation of the `catalyst-gateway` backend. -The process consists in 3 simple steps: - -1. The OpenAPI specification is picked from the artifact generated in the - `Earthfile` of `catalyst-gateway`. -2. The code is generated and saved as an artifact in the `Earthfile` of - `catalyst_voices` -3. Generated code is placed in the proper location within the `catalyst_voices` - project (`packages/internal/catalyst_voices_repository/lib/generated/api`) - and it's ready for local usage. - -This process can be achieved by executing from the `catalyst_voices` root -folder: - -```sh -earthly +code-generator --platform=linux/amd64 --save_locally=true -``` - -The `--platform=linux/amd64` flag is necessary only when running the command from -a different platform such as **Windows** or **macOS**. -It ensures that the code generation process is compatible with the target platform. -If you are running the command on a **Linux** platform, you can omit this flag. - -In this way it's possible to locally generate the code using the same version of -OpenAPI specs defined in the backend code and developers have full control of -what should be committed. - ## Database **CatalystDatabase** depends on jsonb queries, which was introduced in sqlite 3.45.0. @@ -42,15 +11,13 @@ This means we need to ensure minimum version. Files have to be generated with build runner command. ```bash -dart run build_runner clean && \ -dart run process_openapi.dart && \ dart run build_runner build --delete-conflicting-outputs ``` or melos ```bash -melos build-runner-repository +melos build-runner ``` Build migration test files with diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/build.yaml b/catalyst_voices/packages/internal/catalyst_voices_repositories/build.yaml index 38de56fc8f2c..f307b1e950d3 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/build.yaml +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/build.yaml @@ -2,35 +2,12 @@ targets: $default: sources: - lib/** - - openapi/** - $package$ - pubspec.* builders: - swagger_dart_code_generator: - options: - input_folder: "openapi/processed" - output_folder: "lib/generated/api" - separate_models: true - include_if_null: false - exclude_paths: - - /api/draft/* - - /api/v1/health/* - # turn it off when we can get rid of vit. atm its generating classes incorrectly with it. - use_path_for_request_names: true - additional_headers: - - "Authorization" - - "Content-Type" - response_override_value_map: - - url: /api/gateway/v1/document/index - method: post - overridden_value: "DocumentIndexList" json_serializable: options: explicit_to_json: true - chopper_generator: - options: - header: "// Generated code" - drift_dev: # disable drift's default builder, we're using the modular setup instead. enabled: false diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/api.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/api.dart index 974706f5258a..805d49ef1fb5 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/api.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/api.dart @@ -1,3 +1,4 @@ -export 'package:catalyst_voices_repositories/generated/api/client_index.dart'; - export 'api_services.dart'; +export 'dio_cat_gateway_service.dart'; +export 'dio_cat_reviews_service.dart'; +export 'dio_cat_status_service.dart'; diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/api_services.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/api_services.dart index e4b6b92a68cf..7f8849d78039 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/api_services.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/api_services.dart @@ -1,72 +1,65 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart' show AppEnvironmentType; -import 'package:catalyst_voices_repositories/generated/api/cat_gateway.swagger.dart'; -import 'package:catalyst_voices_repositories/generated/api/client_index.dart'; -import 'package:catalyst_voices_repositories/generated/api/client_mapping.dart'; -import 'package:catalyst_voices_repositories/src/api/converters/cbor_or_json_converter.dart'; -import 'package:catalyst_voices_repositories/src/api/converters/cbor_serializable_converter.dart'; -import 'package:catalyst_voices_repositories/src/api/interceptors/path_trim_interceptor.dart'; +import 'package:catalyst_voices_repositories/catalyst_voices_repositories.dart'; import 'package:catalyst_voices_repositories/src/api/interceptors/rbac_auth_interceptor.dart'; -import 'package:catalyst_voices_repositories/src/auth/auth_token_provider.dart'; -import 'package:chopper/chopper.dart'; +import 'package:catalyst_voices_repositories/src/common/content_types.dart'; +import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; -import 'package:http/http.dart' as http; +import 'package:logging/logging.dart'; -// swagger_dart_code_generator does not add this model to mapping list. -// TODO(damian-molinski): investigate if this can be removed. -void _fixModelsMapping() { - generatedMapping.putIfAbsent( - DocumentIndexList, - () => DocumentIndexList.fromJsonFactory, - ); -} +typedef InterceptClient = void Function(Dio dio); /// An interface for accessing Catalyst Voices API. /// /// It provides access to the following services: -/// - [CatGateway] -/// - [CatReviews] +/// - [CatGatewayService] +/// - [CatReviewsService] +/// - [CatStatusService] final class ApiServices { - final CatGateway gateway; - final CatReviews reviews; - final CatStatus status; + final CatGatewayService gateway; + final CatReviewsService reviews; + final CatStatusService status; - factory ApiServices({ + factory ApiServices.dio({ required AppEnvironmentType env, AuthTokenProvider? authTokenProvider, - ValueGetter? httpClient, + InterceptClient? interceptClient, }) { - _fixModelsMapping(); + final catApiServiceLogger = Logger('CatApiServices'); + final catDioOptions = BaseOptions(contentType: ContentTypes.applicationJson); + final rbacAuthInterceptor = authTokenProvider != null + ? RbacAuthInterceptor(authTokenProvider) + : null; + final catLogInterceptor = kDebugMode + ? LogInterceptor(logPrint: catApiServiceLogger.fine) + : null; + final gateway = CatGatewayService.dio( + baseUrl: env.app.replace(path: '/api/gateway').toString(), + options: catDioOptions, + interceptClient: interceptClient, + interceptors: [ + ?rbacAuthInterceptor, + ?catLogInterceptor, + ], + ); + final reviews = CatReviewsService.dio( + baseUrl: env.app.replace(path: '/api/reviews').toString(), + options: catDioOptions, + interceptClient: interceptClient, + interceptors: [ + ?rbacAuthInterceptor, + ?catLogInterceptor, + ], + ); + final status = CatStatusService.dio( + baseUrl: env.status.toString(), + interceptClient: interceptClient, + interceptors: [?catLogInterceptor], + ); return ApiServices.internal( - gateway: CatGateway.create( - httpClient: httpClient?.call(), - baseUrl: env.app.replace(path: '/api/gateway'), - converter: CborOrJsonDelegateConverter( - cborConverter: CborSerializableConverter(), - jsonConverter: $JsonSerializableConverter(), - ), - interceptors: [ - PathTrimInterceptor(), - if (authTokenProvider != null) RbacAuthInterceptor(authTokenProvider), - if (kDebugMode) HttpLoggingInterceptor(onlyErrors: true), - ], - ), - reviews: CatReviews.create( - httpClient: httpClient?.call(), - baseUrl: env.app.replace(path: '/api/reviews'), - interceptors: [ - PathTrimInterceptor(), - if (authTokenProvider != null) RbacAuthInterceptor(authTokenProvider), - if (kDebugMode) HttpLoggingInterceptor(onlyErrors: true), - ], - ), - status: CatStatus.create( - httpClient: httpClient?.call(), - baseUrl: env.status, - interceptors: [ - if (kDebugMode) HttpLoggingInterceptor(onlyErrors: true), - ], - ), + gateway: gateway, + reviews: reviews, + status: status, ); } @@ -77,9 +70,9 @@ final class ApiServices { required this.status, }); - Future dispose() async { - gateway.client.dispose(); - reviews.client.dispose(); - status.client.dispose(); + void dispose() { + gateway.close(); + reviews.close(); + status.close(); } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/converters/cbor_or_json_converter.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/converters/cbor_or_json_converter.dart deleted file mode 100644 index 986db8a38b26..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/converters/cbor_or_json_converter.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'dart:async'; - -import 'package:catalyst_voices_repositories/src/common/content_types.dart'; -import 'package:catalyst_voices_repositories/src/common/http_headers.dart'; -import 'package:chopper/chopper.dart'; -import 'package:http/http.dart' as http; - -/// A [Converter] which decodes json/cbor depending on content-type header. -/// -/// If the request does not have a content-type header -/// then the converter will fallback to json serialization. -/// -/// The swagger_dart_code_generator package incorrectly generates -/// request handlers for application/cbor requests therefore we are -/// mapping out these requests to a proper converter type. -class CborOrJsonDelegateConverter implements Converter { - final Converter cborConverter; - final Converter jsonConverter; - - CborOrJsonDelegateConverter({ - required this.cborConverter, - required this.jsonConverter, - }); - - @override - FutureOr convertRequest(Request request) { - if (_isCborRequest(request)) { - return cborConverter.convertRequest(request); - } else { - return jsonConverter.convertRequest(request); - } - } - - @override - FutureOr> convertResponse( - Response response, - ) { - if (_isCborResponse(response)) { - return cborConverter.convertResponse(response); - } else { - return jsonConverter.convertResponse(response); - } - } - - bool _isCborContentType(Map headers) { - final lowercaseHeaders = headers.map( - (key, value) => MapEntry(key.toLowerCase(), value.toLowerCase()), - ); - final contentType = lowercaseHeaders[HttpHeaders.contentType.toLowerCase()]; - return contentType != null && contentType.contains(ContentTypes.applicationCbor.toLowerCase()); - } - - bool _isCborRequest(http.BaseRequest request) { - return _isCborContentType(request.headers); - } - - bool _isCborResponse(Response response) { - return _isCborContentType(response.headers); - } -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/converters/cbor_serializable_converter.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/converters/cbor_serializable_converter.dart deleted file mode 100644 index a4bb53b68d8a..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/converters/cbor_serializable_converter.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'dart:async'; - -import 'package:catalyst_voices_repositories/src/common/content_types.dart'; -import 'package:catalyst_voices_repositories/src/common/http_headers.dart'; -import 'package:chopper/chopper.dart'; - -/// A [Converter] which converts requests -/// according to `application/cbor` content type. -class CborSerializableConverter implements Converter { - @override - FutureOr convertRequest(Request request) { - return applyHeader( - request, - HttpHeaders.contentType, - ContentTypes.applicationCbor, - ); - } - - @override - FutureOr> convertResponse( - Response response, - ) { - return response as Response; - } -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/dio_cat_gateway_service.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/dio_cat_gateway_service.dart new file mode 100644 index 000000000000..e05832b5173c --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/dio_cat_gateway_service.dart @@ -0,0 +1,251 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:catalyst_voices_repositories/src/api/api_services.dart'; +import 'package:catalyst_voices_repositories/src/api/dio_client.dart'; +import 'package:catalyst_voices_repositories/src/api/models/current_page.dart'; +import 'package:catalyst_voices_repositories/src/api/models/document_index_list.dart'; +import 'package:catalyst_voices_repositories/src/api/models/document_index_query_filter.dart'; +import 'package:catalyst_voices_repositories/src/api/models/full_stake_info.dart'; +import 'package:catalyst_voices_repositories/src/api/models/network.dart'; +import 'package:catalyst_voices_repositories/src/api/models/rbac_registration_chain.dart'; +import 'package:catalyst_voices_repositories/src/common/content_types.dart'; +import 'package:catalyst_voices_repositories/src/common/http_headers.dart'; +import 'package:catalyst_voices_repositories/src/dto/config/remote_config.dart'; +import 'package:dio/dio.dart'; + +/// # Catalyst Gateway API. +/// The Catalyst Gateway API provides realtime data for all prior, current and future Catalyst Voices voting events. +/// +/// Based on OpenAPI Catalyst Gateway API version 0.7.0 +/// catalyst-openapi/v0.7.0 - https://github.com/input-output-hk/catalyst-voices/releases/tag/catalyst-openapi%2Fv0.7.0 +abstract interface class CatGatewayService { + factory CatGatewayService.dio({ + required String baseUrl, + BaseOptions? options, + List interceptors = const [], + InterceptClient? interceptClient, + }) { + final dio = Dio( + options?.copyWith(baseUrl: baseUrl) ?? BaseOptions(baseUrl: baseUrl), + )..interceptors.addAll(interceptors); + interceptClient?.call(dio); + final dioClient = DioClient(dio); + return DioCatGatewayService(dioClient); + } + + void close(); + + /// Post A Signed Document Index Query for Newer Versions of v0.0.4. + /// Produces a summary of signed documents that meet the criteria + /// defined in the request body for new signed document versions of v0.0.4. + /// + /// It does not return the actual documents, just an index of the document identifiers + /// which allows the documents to be retrieved by the `GET document` endpoint. + /// + /// [page] The page number of the data. + /// The size of each page, and its offset within the complete data set is determined by the [limit] parameter. + /// [limit] The size [limit] of each [page] of results. + /// Determines the maximum amount of data that can be returned in a valid response. + /// + /// This [limit] of records of data will always be returned unless there is less data to return + /// than allowed for by the [limit] and [page]. + /// + /// *Exceeding the [page]/[limit] of all available records will not return `404`, it will return an + /// empty response.* + /// + /// [filter] Document Index Query Filter + /// A Query Filter which causes documents whose metadata matches the provided + /// fields to be returned in the index list response. + /// + /// Fields which are not set, are not used to filter documents based on those metadata + /// fields. This is equivalent to returning documents where those metadata fields either + /// do not exist, or do exist, but have any value. + Future documentIndex({ + required DocumentIndexQueryFilter filter, + int? page, + int? limit, + }); + + /// Get the configuration for the frontend. + /// Get the frontend configuration for the requesting client. + /// + /// ### Security + /// + /// Does not require any Catalyst RBAC Token to access. + Future frontendConfig(); + + /// Get A Signed Document. + /// This endpoint returns either a specific or latest version of a registered signed document. + /// + /// [documentId] UUIDv7 Document ID to retrieve. + /// [version] UUIDv7 Version of the Document to retrieve, if omitted, returns the latest version. + Future getDocument({ + required String documentId, + String? version, + }); + + /// Get RBAC registrations V2. + /// This endpoint returns RBAC registrations by provided auth Catalyst Id credentials + /// or by the [lookup] argument if provided. + /// + /// [lookup] Stake address or Catalyst ID to get the RBAC registration for. + /// [showAllInvalid] If this parameter is set to `true`, then all the invalid registrations are + /// returned. Otherwise, only the invalid registrations after the last valid one + /// are shown. Defaults to `false` if not present. + Future rbacRegistration({ + String? lookup, + bool? showAllInvalid, + }); + + /// Get staked assets v2. + /// This endpoint returns the total Cardano's staked assets to the corresponded + /// user's stake address. + /// + /// [stakeAddress] Cardano stake address, also known as a reward address. An optional stake address of the user. + /// Should be a valid Bech32 encoded address followed by the https://cips.cardano.org/cip/CIP-19/#stake-addresses. + /// If missing, a list of associated stake addresses is taken using the RBAC token (for one RBAC registration + /// chain could be assigned multiple different cardano stake addresses). An aggregated response would be returned + /// (total ADA sum across all stake addresses, an aggregated native tokens list across all stake addresses etc.) + /// [network] Cardano network type. + /// If omitted network type is identified from the stake address. + /// If specified it must be correspondent to the network type encoded in the stake address. + /// As `preprod` and `preview` network types in the stake address encoded as a + /// `testnet`, to specify `preprod` or `preview` network type use this + /// query parameter. + /// [asat] A time point at which the assets should be calculated. + /// If omitted latest slot number is used. + Future stakeAssets({ + String? stakeAddress, + Network? network, + String? asat, + String? authorization, + }); + + /// Put A Signed Document. + /// This endpoint returns OK if the document is valid, able to be put by the + /// submitter, and if it already exists, is identical to the existing document. + Future uploadDocument({ + required Uint8List body, + }); +} + +final class DioCatGatewayService implements CatGatewayService { + final DioClient _dio; + + const DioCatGatewayService(this._dio); + + @override + void close() => _dio.close(); + + @override + Future documentIndex({ + required DocumentIndexQueryFilter filter, + int? limit, + int? page, + }) { + return _dio.post( + '/v2/document/index', + queryParameters: { + 'limit': ?limit, + 'page': ?page, + }, + body: filter.toJson(), + mapper: (response) { + if (response is Map) { + return DocumentIndexList.fromJson(response); + } + + return const DocumentIndexList( + docs: [], + page: CurrentPage(page: 0, limit: 0, remaining: 0), + ); + }, + ); + } + + @override + Future frontendConfig() { + return _dio.get( + '/v1/config/frontend', + mapper: (response) { + if (response is Map) { + return RemoteConfig.fromJson(response); + } + + if (response is String) { + return RemoteConfig.fromJson(jsonDecode(response) as Map); + } + + return const RemoteConfig(); + }, + ); + } + + @override + Future getDocument({ + required String documentId, + String? version, + }) { + return _dio.get( + '/v1/document/$documentId', + queryParameters: {'version': ?version}, + options: Options(responseType: ResponseType.bytes), + mapper: (response) => response, + ); + } + + @override + Future rbacRegistration({ + String? lookup, + bool? showAllInvalid = false, + }) { + return _dio.get, RbacRegistrationChain>( + '/v2/rbac/registration', + queryParameters: { + 'lookup': ?lookup, + 'show_all_invalid': ?showAllInvalid, + }, + mapper: RbacRegistrationChain.fromJson, + ); + } + + @override + Future stakeAssets({ + String? stakeAddress, + Network? network, + String? asat, + String? authorization, + }) { + return _dio.get, FullStakeInfo>( + '/v2/cardano/assets', + queryParameters: { + 'stake_address': ?stakeAddress, + 'network': ?network?.value, + 'asat': ?asat, + }, + options: Options( + headers: { + HttpHeaders.authorization: ?authorization, + }, + ), + mapper: FullStakeInfo.fromJson, + ); + } + + @override + Future uploadDocument({ + required Uint8List body, + }) { + return _dio.put( + '/v1/document', + body: body, + options: Options( + headers: { + Headers.contentTypeHeader: ContentTypes.applicationCbor, + }, + ), + mapper: (response) {}, + ); + } +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/dio_cat_reviews_service.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/dio_cat_reviews_service.dart new file mode 100644 index 000000000000..8e929166e098 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/dio_cat_reviews_service.dart @@ -0,0 +1,76 @@ +import 'package:catalyst_voices_repositories/src/api/api_services.dart'; +import 'package:catalyst_voices_repositories/src/api/dio_client.dart'; +import 'package:catalyst_voices_repositories/src/api/models/catalyst_id_create.dart'; +import 'package:catalyst_voices_repositories/src/api/models/catalyst_id_public.dart'; +import 'package:catalyst_voices_repositories/src/common/http_headers.dart'; +import 'package:dio/dio.dart'; + +/// # Catalyst Reviews API. +/// +/// Based on OpenAPI Catalyst Reviews API version 0.1.0 +/// reviews-api/v1.2.5 - https://github.com/input-output-hk/catalyst-reviews/releases/tag/reviews-api%2Fv1.2.5 +abstract interface class CatReviewsService { + factory CatReviewsService.dio({ + required String baseUrl, + BaseOptions? options, + InterceptClient? interceptClient, + List interceptors = const [], + }) { + final dio = Dio( + options?.copyWith(baseUrl: baseUrl) ?? BaseOptions(baseUrl: baseUrl), + )..interceptors.addAll(interceptors); + interceptClient?.call(dio); + final dioClient = DioClient(dio); + return DioCatReviewsService(dioClient); + } + + void close(); + + /// Get a catalyst id from request. + Future getPublicProfile({String? authorization}); + + /// Update info associated with a catalyst id. + Future upsertPublicProfile({ + required CatalystIdCreate body, + String? authorization, + }); +} + +final class DioCatReviewsService implements CatReviewsService { + final DioClient _dio; + + const DioCatReviewsService(this._dio); + + @override + void close() => _dio.close(); + + @override + Future getPublicProfile({String? authorization}) { + return _dio.get, CatalystIdPublic>( + '/catalyst-ids/me', + options: Options( + headers: { + HttpHeaders.authorization: ?authorization, + }, + ), + mapper: CatalystIdPublic.fromJson, + ); + } + + @override + Future upsertPublicProfile({ + required CatalystIdCreate body, + String? authorization, + }) { + return _dio.post, CatalystIdPublic>( + '/catalyst-ids/me', + body: body.toJson(), + options: Options( + headers: { + HttpHeaders.authorization: ?authorization, + }, + ), + mapper: CatalystIdPublic.fromJson, + ); + } +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/dio_cat_status_service.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/dio_cat_status_service.dart new file mode 100644 index 000000000000..8dcd8806e97e --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/dio_cat_status_service.dart @@ -0,0 +1,41 @@ +import 'package:catalyst_voices_repositories/src/api/api_services.dart'; +import 'package:catalyst_voices_repositories/src/api/dio_client.dart'; +import 'package:catalyst_voices_repositories/src/api/models/components.dart'; +import 'package:dio/dio.dart'; + +abstract interface class CatStatusService { + factory CatStatusService.dio({ + required String baseUrl, + BaseOptions? options, + InterceptClient? interceptClient, + List interceptors = const [], + }) { + final dio = Dio( + options?.copyWith(baseUrl: baseUrl) ?? BaseOptions(baseUrl: baseUrl), + )..interceptors.addAll(interceptors); + interceptClient?.call(dio); + final dioClient = DioClient(dio); + return DioCatStatusService(dioClient); + } + + void close(); + + Future componentStatuses(); +} + +final class DioCatStatusService implements CatStatusService { + final DioClient _dio; + + const DioCatStatusService(this._dio); + + @override + void close() => _dio.close(); + + @override + Future componentStatuses({String? authorization}) { + return _dio.get, Components>( + '/v2/components.json', + mapper: Components.fromJson, + ); + } +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/dio_client.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/dio_client.dart new file mode 100644 index 000000000000..eb4a978d6de5 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/dio_client.dart @@ -0,0 +1,341 @@ +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:dio/dio.dart'; + +ApiException _mapDioException(DioException exception) { + final requestOptions = exception.requestOptions; + final uri = requestOptions.uri; + final message = exception.message; + final error = exception.error; + final response = exception.response; + + switch (exception.type) { + case DioExceptionType.connectionTimeout: + return ApiConnectionTimeoutException( + message: message, + uri: uri, + error: error, + duration: requestOptions.connectTimeout, + ); + case DioExceptionType.sendTimeout: + return ApiSendTimeoutException( + message: message, + uri: uri, + error: error, + duration: requestOptions.sendTimeout, + ); + case DioExceptionType.receiveTimeout: + return ApiReceiveTimeoutException( + message: message, + uri: uri, + error: error, + duration: requestOptions.receiveTimeout, + ); + case DioExceptionType.badCertificate: + return ApiBadCertificateException( + message: message, + uri: uri, + error: error, + ); + case DioExceptionType.badResponse: + return ApiBadResponseException( + message: message, + uri: uri, + error: error, + statusCode: response?.statusCode ?? ApiResponseStatusCode.badRequest, + responseBody: response?.data, + ); + case DioExceptionType.cancel: + return ApiRequestCancelledException( + message: message, + uri: uri, + error: error, + ); + case DioExceptionType.connectionError: + return ApiConnectionErrorException( + message: message, + uri: uri, + error: error, + ); + case DioExceptionType.unknown: + return ApiUnknownException( + message: message, + uri: uri, + error: error, + ); + } +} + +typedef Mapper = T Function(R response); + +abstract interface class DioClient { + factory DioClient(Dio dio) = DioClientImpl; + + void close(); + + Future delete( + String urlPath, { + required Mapper mapper, + Map? queryParameters, + Object? body, + Options? options, + CancelToken? cancelToken, + }); + + Future download( + String urlPath, { + required String savePath, + required Mapper mapper, + Map? queryParameters, + Object? body, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onReceiveProgress, + bool deleteOnError, + String lengthHeader, + }); + + Future get( + String urlPath, { + required Mapper mapper, + Map? queryParameters, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onReceiveProgress, + }); + + Future head( + String urlPath, { + required Mapper mapper, + Map? queryParameters, + Object? body, + Options? options, + CancelToken? cancelToken, + }); + + Future patch( + String urlPath, { + required Mapper mapper, + Map? queryParameters, + Object? body, + Options? options, + CancelToken? cancelToken, + }); + + Future post( + String urlPath, { + required Mapper mapper, + Map? queryParameters, + Object? body, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onSendProgress, + }); + + Future put( + String urlPath, { + required Mapper mapper, + Map? queryParameters, + Object? body, + Options? options, + CancelToken? cancelToken, + }); +} + +final class DioClientImpl implements DioClient { + final Dio _dio; + + const DioClientImpl(this._dio); + + @override + void close() => _dio.close(); + + @override + Future delete( + String urlPath, { + required Mapper mapper, + Map? queryParameters, + Object? body, + Options? options, + CancelToken? cancelToken, + }) { + return _request( + urlPath: urlPath, + mapper: mapper, + method: _RequestMethod.delete, + queryParameters: queryParameters, + body: body, + options: options, + cancelToken: cancelToken, + ); + } + + @override + Future download( + String urlPath, { + required String savePath, + required Mapper mapper, + Map? queryParameters, + Object? body, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onReceiveProgress, + bool deleteOnError = true, + String lengthHeader = Headers.contentLengthHeader, + }) async { + final requestOptions = (options ?? Options()).copyWith( + method: _RequestMethod.get.name.toUpperCase(), + ); + + try { + final response = await _dio.download( + urlPath, + savePath, + onReceiveProgress: onReceiveProgress, + queryParameters: queryParameters, + cancelToken: cancelToken, + deleteOnError: deleteOnError, + lengthHeader: lengthHeader, + data: body, + options: requestOptions, + ); + return mapper(response.data); + } on DioException catch (error, stackTrace) { + Error.throwWithStackTrace(_mapDioException(error), stackTrace); + } + } + + @override + Future get( + String urlPath, { + required Mapper mapper, + Map? queryParameters, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onReceiveProgress, + }) { + return _request( + urlPath: urlPath, + mapper: mapper, + method: _RequestMethod.get, + queryParameters: queryParameters, + options: options, + cancelToken: cancelToken, + onReceiveProgress: onReceiveProgress, + ); + } + + @override + Future head( + String urlPath, { + required Mapper mapper, + Map? queryParameters, + Object? body, + Options? options, + CancelToken? cancelToken, + }) { + return _request( + urlPath: urlPath, + mapper: mapper, + method: _RequestMethod.head, + queryParameters: queryParameters, + body: body, + options: options, + cancelToken: cancelToken, + ); + } + + @override + Future patch( + String urlPath, { + required Mapper mapper, + Map? queryParameters, + Object? body, + Options? options, + CancelToken? cancelToken, + }) { + return _request( + urlPath: urlPath, + mapper: mapper, + method: _RequestMethod.patch, + queryParameters: queryParameters, + body: body, + options: options, + cancelToken: cancelToken, + ); + } + + @override + Future post( + String urlPath, { + required Mapper mapper, + Map? queryParameters, + Object? body, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onSendProgress, + }) { + return _request( + urlPath: urlPath, + mapper: mapper, + method: _RequestMethod.post, + queryParameters: queryParameters, + body: body, + options: options, + cancelToken: cancelToken, + onSendProgress: onSendProgress, + ); + } + + @override + Future put( + String urlPath, { + required Mapper mapper, + Map? queryParameters, + Object? body, + Options? options, + CancelToken? cancelToken, + }) { + return _request( + urlPath: urlPath, + mapper: mapper, + method: _RequestMethod.put, + queryParameters: queryParameters, + body: body, + options: options, + cancelToken: cancelToken, + ); + } + + Future _request({ + required String urlPath, + required Mapper mapper, + required _RequestMethod method, + Map? queryParameters, + Object? body, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onSendProgress, + ProgressCallback? onReceiveProgress, + }) async { + final requestOptions = (options ?? Options()).copyWith( + method: method.name.toUpperCase(), + ); + + try { + final response = await _dio.request( + urlPath, + queryParameters: queryParameters, + data: body, + options: requestOptions, + cancelToken: cancelToken, + onSendProgress: onSendProgress, + onReceiveProgress: onReceiveProgress, + ); + return mapper(response.data as R); + } on DioException catch (error, stackTrace) { + Error.throwWithStackTrace(_mapDioException(error), stackTrace); + } + } +} + +enum _RequestMethod { post, get, put, patch, head, delete } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/interceptors/path_trim_interceptor.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/interceptors/path_trim_interceptor.dart deleted file mode 100644 index f1204a2241c1..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/interceptors/path_trim_interceptor.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'dart:async'; - -import 'package:chopper/chopper.dart'; - -/// Workaround interceptor which only job is to get rid of unnecessary /api/ from request path -/// because base url already have it. -/// -/// See https://github.com/input-output-hk/catalyst-internal-docs/issues/178 -final class PathTrimInterceptor implements Interceptor { - @override - FutureOr> intercept(Chain chain) { - final request = chain.request; - final uri = request.uri; - final pathSegments = List.of(uri.pathSegments); - - if (pathSegments.firstOrNull == 'api') { - pathSegments.removeAt(0); - } - - final updatedUri = uri.replace(pathSegments: pathSegments); - final updatedRequest = request.copyWith(uri: updatedUri); - - return chain.proceed(updatedRequest); - } -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/interceptors/rbac_auth_interceptor.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/interceptors/rbac_auth_interceptor.dart index 853f6e34c4c9..682c50a02539 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/interceptors/rbac_auth_interceptor.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/interceptors/rbac_auth_interceptor.dart @@ -1,12 +1,10 @@ import 'dart:async'; -import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_repositories/src/auth/auth_token_provider.dart'; import 'package:catalyst_voices_repositories/src/common/http_headers.dart'; import 'package:catalyst_voices_repositories/src/common/rbac_token_ext.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; -import 'package:chopper/chopper.dart' as utils show applyHeader; -import 'package:chopper/chopper.dart' hide applyHeader; +import 'package:dio/dio.dart'; final _logger = Logger('RbacAuthInterceptor'); @@ -17,7 +15,7 @@ final _logger = Logger('RbacAuthInterceptor'); /// (likely they have not registered on chain). /// - 403: The token is valid, we know who they are but either the timestamp is /// wrong (out of date) or the signature is wrong. -final class RbacAuthInterceptor implements Interceptor { +final class RbacAuthInterceptor extends Interceptor { static const _retryCountHeaderName = 'Retry-Count'; static const _retryStatusCodes = [401, 403]; static const _maxRetries = 1; @@ -27,75 +25,59 @@ final class RbacAuthInterceptor implements Interceptor { const RbacAuthInterceptor(this._authTokenProvider); @override - FutureOr> intercept( - Chain chain, + Future onError(DioException err, ErrorInterceptorHandler handler) async { + final statusCode = err.response?.statusCode; + if (statusCode != null && _retryStatusCodes.contains(statusCode)) { + try { + final options = err.requestOptions; + final rawRetryCount = options.headers[_retryCountHeaderName]; + final retryCount = int.tryParse(rawRetryCount?.toString() ?? '') ?? 0; + + if (retryCount >= _maxRetries) { + _logger.severe('Giving up on ${options.uri} auth retry[$retryCount]'); + return handler.next(err); + } + + final newToken = await _authTokenProvider.createRbacToken(forceRefresh: true); + + if (newToken == null) { + throw StateError( + 'Could not create a new RBAC token, ' + 'did the keychain become locked in the meantime?', + ); + } + + options.headers[HttpHeaders.authorization] = newToken.authHeader(); + options.headers[_retryCountHeaderName] = '${retryCount + 1}'; + + final response = await Dio().fetch(options); + return handler.resolve(response); + } catch (error, stack) { + _logger.severe('Re-authentication failed', error, stack); + return handler.next(err); + } + } + + handler.next(err); + } + + @override + Future onRequest( + RequestOptions options, + RequestInterceptorHandler handler, ) async { - if (chain.request.headers[HttpHeaders.authorization] != null) { + if (options.headers[HttpHeaders.authorization] != null) { // token is already added - return chain.proceed(chain.request); + return handler.next(options); } final token = await _authTokenProvider.createRbacToken(); if (token == null) { // keychain locked or not existing - return chain.proceed(chain.request); + return handler.next(options); } - final updatedRequest = chain.request.applyAuthToken(token); - final response = await chain.proceed(updatedRequest); - - if (_retryStatusCodes.contains(response.statusCode)) { - final retryRequest = await _retryRequest(chain.request); - if (retryRequest != null) { - return await chain.proceed(retryRequest); - } - } - - return response; - } - - Future _retryRequest(Request request) async { - try { - final rawRetryCount = request.headers[_retryCountHeaderName]; - final retryCount = int.tryParse(rawRetryCount ?? '') ?? 0; - if (retryCount >= _maxRetries) { - _logger.severe('Giving up on ${request.uri} auth retry[$retryCount]'); - return null; - } - - final newToken = await _authTokenProvider.createRbacToken( - forceRefresh: true, - ); - - if (newToken == null) { - throw StateError( - 'Could not create a new RBAC token, ' - 'did the keychain become locked in the meantime?', - ); - } - - return request - .applyAuthToken(newToken) - .applyHeader(name: _retryCountHeaderName, value: '${retryCount + 1}'); - } catch (error, stack) { - _logger.severe('Re-authentication failed', error, stack); - return null; - } - } -} - -extension on Request { - Request applyAuthToken(RbacToken token) { - return applyHeader( - name: HttpHeaders.authorization, - value: token.authHeader(), - ); - } - - Request applyHeader({ - required String name, - required String value, - }) { - return utils.applyHeader(this, name, value); + options.headers[HttpHeaders.authorization] = token.authHeader(); + handler.next(options); } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/catalyst_id_create.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/catalyst_id_create.dart new file mode 100644 index 000000000000..717887940a9c --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/catalyst_id_create.dart @@ -0,0 +1,25 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'catalyst_id_create.g.dart'; + +/// Model for the creation and the update of the email in DB. +/// +/// Used as request body for POST /api/catalyst-ids/me +@JsonSerializable() +final class CatalystIdCreate { + /// The email address. + final String email; + + /// The catalyst Id Uri. + @JsonKey(name: 'catalyst_id_uri') + final String catalystIdUri; + + const CatalystIdCreate({ + required this.email, + required this.catalystIdUri, + }); + + factory CatalystIdCreate.fromJson(Map json) => _$CatalystIdCreateFromJson(json); + + Map toJson() => _$CatalystIdCreateToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/catalyst_id_public.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/catalyst_id_public.dart new file mode 100644 index 000000000000..b01dd031ffca --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/catalyst_id_public.dart @@ -0,0 +1,42 @@ +import 'package:catalyst_voices_repositories/src/api/models/catalyst_id_status.dart'; +import 'package:catalyst_voices_repositories/src/api/models/catalyst_rbac_registration_status.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'catalyst_id_public.g.dart'; + +/// Model for the CatalystID to expose publicly. +/// +/// Used as response for: +/// - GET /api/catalyst-ids/me +/// - POST /api/catalyst-ids/me +@JsonSerializable() +final class CatalystIdPublic { + /// The catalyst ID. + @JsonKey(name: '_cid') + final String? cid; + + /// The email address. + final String? email; + + /// The username. + final String? username; + + /// The status of the catalyst ID. + final CatalystIdStatus status; + + /// The RBAC registration status. + @JsonKey(name: 'rbac_reg_status') + final CatalystRbacRegistrationStatus rbacRegStatus; + + const CatalystIdPublic({ + this.cid, + this.email, + this.username, + this.status = CatalystIdStatus.inactive, + this.rbacRegStatus = CatalystRbacRegistrationStatus.initialized, + }); + + factory CatalystIdPublic.fromJson(Map json) => _$CatalystIdPublicFromJson(json); + + Map toJson() => _$CatalystIdPublicToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/catalyst_id_status.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/catalyst_id_status.dart new file mode 100644 index 000000000000..7fe581a66fdf --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/catalyst_id_status.dart @@ -0,0 +1,14 @@ +import 'package:json_annotation/json_annotation.dart'; + +/// Enum to describe the catalyst_id status. +@JsonEnum(valueField: 'value') +enum CatalystIdStatus { + inactive(0), + emailVerified(1), + active(2), + banned(3); + + final int value; + + const CatalystIdStatus(this.value); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/catalyst_rbac_registration_status.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/catalyst_rbac_registration_status.dart new file mode 100644 index 000000000000..a5d29bd9ec5e --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/catalyst_rbac_registration_status.dart @@ -0,0 +1,14 @@ +import 'package:json_annotation/json_annotation.dart'; + +/// Enum to describe the rbac registration status. +@JsonEnum(valueField: 'value') +enum CatalystRbacRegistrationStatus { + initialized(0), + notFound(1), + volatile(2), + persistent(3); + + final int value; + + const CatalystRbacRegistrationStatus(this.value); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/component.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/component.dart new file mode 100644 index 000000000000..bc44a0f8411b --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/component.dart @@ -0,0 +1,25 @@ +import 'package:catalyst_voices_repositories/src/api/models/component_status.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'component.g.dart'; + +@JsonSerializable(createToJson: false) +final class Component { + final String id; + final String name; + final String description; + final ComponentStatus status; + final String? group; + final bool? isParent; + + const Component({ + required this.id, + required this.name, + required this.description, + required this.status, + this.group, + this.isParent, + }); + + factory Component.fromJson(Map json) => _$ComponentFromJson(json); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/component_status.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/component_status.dart new file mode 100644 index 000000000000..54b6c608c0e7 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/component_status.dart @@ -0,0 +1,15 @@ +import 'package:json_annotation/json_annotation.dart'; + +@JsonEnum(valueField: 'value') +enum ComponentStatus { + /* cSpell:disable */ + operational('OPERATIONAL'), + partialOutage('PARTIALOUTAGE'), + minorOutage('MINOROUTAGE'), + majorOutage('MAJOROUTAGE'); + /* cSpell:enable */ + + final String value; + + const ComponentStatus(this.value); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/components.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/components.dart new file mode 100644 index 000000000000..c09f2a192efe --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/components.dart @@ -0,0 +1,13 @@ +import 'package:catalyst_voices_repositories/src/api/models/component.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'components.g.dart'; + +@JsonSerializable(createToJson: false) +final class Components { + final List components; + + const Components(this.components); + + factory Components.fromJson(Map json) => _$ComponentsFromJson(json); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/current_page.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/current_page.dart new file mode 100644 index 000000000000..744732b5a0f0 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/current_page.dart @@ -0,0 +1,35 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'current_page.g.dart'; + +/// Current Page of data being returned. +@JsonSerializable() +final class CurrentPage { + /// The page number of the data. + /// The size of each page, and its offset within the complete data set is determined by the [limit] parameter. + final int page; + + /// The size [limit] of each [page] of results. + /// Determines the maximum amount of data that can be returned in a valid response. + /// + /// This [limit] of records of data will always be returned unless there is less data to return + /// than allowed for by the [limit] and [page]. + /// + /// *Exceeding the [page]/[limit] of all available records will not return `404`, it will return an + /// empty response.* + final int limit; + + /// The number of items remaining to be returned after this page. + /// This is the absolute number of items remaining, and not the number of Pages. + final int remaining; + + const CurrentPage({ + required this.page, + required this.limit, + required this.remaining, + }); + + factory CurrentPage.fromJson(Map json) => _$CurrentPageFromJson(json); + + Map toJson() => _$CurrentPageToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/document_index_list.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/document_index_list.dart new file mode 100644 index 000000000000..284b72c2ae83 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/document_index_list.dart @@ -0,0 +1,30 @@ +import 'package:catalyst_voices_repositories/src/api/models/current_page.dart'; +import 'package:catalyst_voices_repositories/src/api/models/indexed_document.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'document_index_list.g.dart'; + +/// A single page of documents. +/// +/// The page limit is defined by the number of document versions, +/// not the number of Document IDs. +@JsonSerializable() +class DocumentIndexList { + /// List of documents that matched the filter. + /// + /// Documents are listed in ascending order. + final List docs; + + /// The Page of Document Index List. + final CurrentPage page; + + const DocumentIndexList({ + required this.docs, + required this.page, + }); + + factory DocumentIndexList.fromJson(Map json) => + _$DocumentIndexListFromJson(json); + + Map toJson() => _$DocumentIndexListToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/document_index_query_filter.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/document_index_query_filter.dart new file mode 100644 index 000000000000..c90f257c305d --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/document_index_query_filter.dart @@ -0,0 +1,152 @@ +import 'package:catalyst_voices_repositories/src/api/models/eq_or_ranged_id.dart'; +import 'package:catalyst_voices_repositories/src/api/models/eq_or_ranged_ver.dart'; +import 'package:catalyst_voices_repositories/src/api/models/id_and_ver_ref.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'document_index_query_filter.g.dart'; + +/// Query Filter for the generation of a signed document index. +/// +/// The Query works as a filter which acts like a sieve to filter out documents +/// which do not strictly match the metadata or payload fields included in the query +/// itself. +/// +/// Used as request body for POST /api/v2/document/index +@JsonSerializable(createFactory: false, includeIfNull: false) +final class DocumentIndexQueryFilter { + /// ## Signed Document Type. + /// + /// The document type must match one of the + /// [Registered Document Types](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/types/) + /// + /// UUIDv4 Formatted 128bit value. + /// + /// Max items 10 + final List? type; + + /// ## Document ID + /// + /// Either an absolute single Document ID or a range of + /// [Document IDs](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id) + /// + /// Max items 10 + final List? id; + + /// ## Document Version + /// + /// Either an absolute single Document Version or a range of + /// [Document Versions](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver) + /// + /// Max items 10 + final List? ver; + + /// ## Document Reference + /// + /// A [reference](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/meta/#ref-document-reference) + /// to another signed document. This fields can match any reference that matches the + /// defined [Document IDs](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id) + /// and/or + /// [Document Versions](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver) + /// + /// The kind of document that the reference refers to is defined by the + /// [Document Type](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/types/) + /// + /// Max items 10 + final List? ref; + + /// ## Document Template + /// + /// Documents that are created based on a template include the + /// [template reference](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/meta/#template-template-reference) + /// to another signed document. This fields can match any template reference that + /// matches the defined [Document IDs](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id) + /// and/or + /// [Document Versions](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver) + /// + /// The kind of document that the reference refers to is defined by the + /// [Document Type](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/types/) + /// however, it will always be a template type document that matches the document + /// itself. + /// + /// Max items 10 + final List? template; + + /// ## Document Reply + /// + /// This is a + /// [reply reference](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/meta/#reply-reply-reference) + /// which links one document to another, when acting as a reply to it. + /// Replies typically reference the same kind of document. + /// This fields can match any reply reference that matches the defined + /// [Document IDs](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id) + /// and/or + /// [Document Versions](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver) + /// + /// The kind of document that the reference refers to is defined by the + /// [Document Type](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/types/). + /// + /// Max items 10 + final List? reply; + + /// ## Brand + /// + /// This is a + /// [brand reference](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/meta/#brand_id) + /// to a brand document which defines the brand the document falls under. + /// This fields can match any brand reference that matches the defined + /// [Document IDs](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id) + /// and/or + /// [Document Versions](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver) + /// + /// Whether a Document Type has a brand reference is defined by its + /// [Document Type](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/types/). + /// + /// Max items 10 + final List? brand; + + /// ## Campaign + /// + /// This is a + /// [campaign reference](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/meta/#campaign_id) + /// to a campaign document which defines the campaign the document falls under. + /// This fields can match any campaign reference that matches the defined + /// [Document IDs](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id) + /// and/or + /// [Document Versions](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver) + /// + /// Whether a Document Type has a campaign reference is defined by its + /// [Document Type](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/types/). + /// + /// Max items 10 + final List? campaign; + + /// ## Category + /// + /// This is a + /// [category reference](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/meta/#category_id) + /// to a category document which defines the category the document falls under. + /// This fields can match any category reference that matches the defined + /// [Document IDs](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id) + /// and/or + /// [Document Versions](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver) + /// + /// Whether a Document Type has a category reference is defined by its + /// [Document Type](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/types/). + /// + /// Max items 10 + final List? category; + + const DocumentIndexQueryFilter({ + this.type, + this.id, + this.ver, + this.ref, + this.template, + this.reply, + this.brand, + this.campaign, + this.category, + }); + + Map toJson() => _$DocumentIndexQueryFilterToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/document_reference.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/document_reference.dart new file mode 100644 index 000000000000..2ec0bea02f12 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/document_reference.dart @@ -0,0 +1,27 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'document_reference.g.dart'; + +/// A Reference to another Signed Document +@JsonSerializable() +final class DocumentReference { + /// Signed Document ID + final String id; + + /// Signed Document Version + final String ver; + + /// Signed Document Locator + final String? cid; + + const DocumentReference({ + required this.id, + required this.ver, + this.cid, + }); + + factory DocumentReference.fromJson(Map json) => + _$DocumentReferenceFromJson(json); + + Map toJson() => _$DocumentReferenceToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/eq_or_ranged_id.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/eq_or_ranged_id.dart new file mode 100644 index 000000000000..e5d4cb384926 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/eq_or_ranged_id.dart @@ -0,0 +1,30 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'eq_or_ranged_id.g.dart'; + +/// Either a Single Document ID, or a Range of Document IDs +@JsonSerializable(createFactory: false, includeIfNull: false) +final class EqOrRangedId { + /// Signed Document ID + /// The exact Document ID to match against. + final String? eq; + + /// Signed Document ID + /// Minimum Document ID to find (inclusive) + final String? min; + + /// Signed Document ID + /// Maximum Document ID to find (inclusive) + final String? max; + + /// A single Document IDs. + const EqOrRangedId.eq(String this.eq) : min = null, max = null; + + /// A range of Document IDs. + const EqOrRangedId.range({ + required String this.min, + required String this.max, + }) : eq = null; + + Map toJson() => _$EqOrRangedIdToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/eq_or_ranged_ver.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/eq_or_ranged_ver.dart new file mode 100644 index 000000000000..763c6f2d19ef --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/eq_or_ranged_ver.dart @@ -0,0 +1,35 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'eq_or_ranged_ver.g.dart'; + +/// Document or Range of Documents +/// +/// Either a Single Document Version, or a Range of Document Versions +@JsonSerializable(createFactory: false, includeIfNull: false) +final class EqOrRangedVer { + /// Signed Document Version + /// The exact Document ID to match against. + final String? eq; + + /// Signed Document Version + /// Minimum Document Version to find (inclusive) + final String? min; + + /// Signed Document Version + /// Maximum Document Version to find (inclusive) + final String? max; + + /// A single Document IDs. + /// The exact Document ID to match against. + const EqOrRangedVer.eq(String this.eq) : min = null, max = null; + + /// Version Range + /// + /// A Range of document versions from minimum to maximum inclusive. + const EqOrRangedVer.range({ + required String this.min, + required String this.max, + }) : eq = null; + + Map toJson() => _$EqOrRangedVerToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/extended_data.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/extended_data.dart new file mode 100644 index 000000000000..cb23349a1452 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/extended_data.dart @@ -0,0 +1,22 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'extended_data.g.dart'; + +/// A role extended data. +@JsonSerializable() +final class ExtendedData { + /// Extended data key + final int key; + + /// Extended data value + final String value; + + const ExtendedData({ + required this.key, + required this.value, + }); + + factory ExtendedData.fromJson(Map json) => _$ExtendedDataFromJson(json); + + Map toJson() => _$ExtendedDataToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/full_stake_info.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/full_stake_info.dart new file mode 100644 index 000000000000..8d678ff6147e --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/full_stake_info.dart @@ -0,0 +1,25 @@ +import 'package:catalyst_voices_repositories/src/api/models/stake_info.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'full_stake_info.g.dart'; + +/// Full user's cardano stake info. +/// +/// Used as response for GET /api/v1/cardano/assets/{stake_address}. +@JsonSerializable() +final class FullStakeInfo { + /// Volatile stake information. + final StakeInfo volatile; + + /// "Persistent stake information. + final StakeInfo persistent; + + const FullStakeInfo({ + required this.volatile, + required this.persistent, + }); + + factory FullStakeInfo.fromJson(Map json) => _$FullStakeInfoFromJson(json); + + Map toJson() => _$FullStakeInfoToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/id_and_ver_ref.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/id_and_ver_ref.dart new file mode 100644 index 000000000000..a9a44f23e9de --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/id_and_ver_ref.dart @@ -0,0 +1,40 @@ +import 'package:catalyst_voices_repositories/src/api/models/eq_or_ranged_id.dart'; +import 'package:catalyst_voices_repositories/src/api/models/eq_or_ranged_ver.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'id_and_ver_ref.g.dart'; + +/// Either a Single Document ID, or a Range of Document IDs +@JsonSerializable(createFactory: false, includeIfNull: false) +final class IdAndVerRef { + /// Document ID Reference + /// A Reference to the Document ID Only. + /// + /// This will match any document that matches the defined Document ID only. + /// The Document Version is not considered, and will match any version. + final EqOrRangedId? id; + + /// Document Version Selector + /// Document Version, or Range of Document Versions + final EqOrRangedVer? ver; + + /// Document ID Reference + /// A Reference to the Document ID Only. + /// + /// This will match any document that matches the defined Document ID only. + /// The Document Version is not considered, and will match any version. + const IdAndVerRef.idOnly(EqOrRangedId this.id) : ver = null; + + /// A Reference to the Document Version, and optionally also the Document ID. + /// + /// This will match any document that matches the defined Document Version and if + /// specified the Document ID. + /// If the Document ID is not specified, then all documents that match the version will be + /// returned in the index. + const IdAndVerRef.verWithOptionalId({ + required EqOrRangedVer this.ver, + this.id, + }); + + Map toJson() => _$IdAndVerRefToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/indexed_document.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/indexed_document.dart new file mode 100644 index 000000000000..d2e61773c43b --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/indexed_document.dart @@ -0,0 +1,25 @@ +import 'package:catalyst_voices_repositories/src/api/models/indexed_document_version.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'indexed_document.g.dart'; + +/// List of Documents that matched the filter +@JsonSerializable() +final class IndexedDocument { + /// Signed Document ID + /// Document ID that matches the filter + final String id; + + /// List of matching versions of the document. + /// Versions are listed in ascending order. + final List ver; + + IndexedDocument({ + required this.id, + required this.ver, + }); + + factory IndexedDocument.fromJson(Map json) => _$IndexedDocumentFromJson(json); + + Map toJson() => _$IndexedDocumentToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/indexed_document_version.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/indexed_document_version.dart new file mode 100644 index 000000000000..674e3940e4db --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/indexed_document_version.dart @@ -0,0 +1,47 @@ +import 'package:catalyst_voices_repositories/src/api/models/document_reference.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'indexed_document_version.g.dart'; + +/// List of Documents that matched the filter +@JsonSerializable() +final class IndexedDocumentVersion { + /// Signed Document Version + /// Document Version that matches the filter + final String ver; + + /// Signed Document Type + /// Document Type that matches the filter + final String type; + + /// Document Reference that matches the filter + /// Max items 10 + final List? ref; + + /// DDocument Reply Reference that matches the filter + /// Max items 10 + final List? reply; + + /// Document Template Reference that matches the filter + /// Max items 10 + final List? template; + + /// Document Parameter Reference that matches the filter + /// Max items 10 + @JsonKey(name: 'doc_parameters') + final List? parameters; + + IndexedDocumentVersion({ + required this.ver, + required this.type, + this.ref, + this.reply, + this.template, + this.parameters, + }); + + factory IndexedDocumentVersion.fromJson(Map json) => + _$IndexedDocumentVersionFromJson(json); + + Map toJson() => _$IndexedDocumentVersionToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/invalid_registration.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/invalid_registration.dart new file mode 100644 index 000000000000..616a7c2c6d6a --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/invalid_registration.dart @@ -0,0 +1,51 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'invalid_registration.g.dart'; + +/// An invalid RBAC registration. +@JsonSerializable() +final class InvalidRegistration { + /// A time of the registration transaction. + final DateTime time; + + /// Transaction Id/Hash + /// A transaction identifier (hash). + @JsonKey(name: 'txn_id') + final String txnId; + + /// Cardano Blockchain Slot Number + /// A block slot number. + final int slot; + + /// Transaction Index + @JsonKey(name: 'txn_index') + final int txnIndex; + + /// Error Message + /// A problem report. + final String report; + + /// Transaction Id/Hash + /// A previous transaction ID. + @JsonKey(name: 'previous_txn') + final String? previousTxn; + + /// UUIDv4 + /// A registration purpose. + final String? purpose; + + const InvalidRegistration({ + required this.time, + required this.txnId, + required this.slot, + required this.txnIndex, + required this.report, + this.previousTxn, + this.purpose, + }); + + factory InvalidRegistration.fromJson(Map json) => + _$InvalidRegistrationFromJson(json); + + Map toJson() => _$InvalidRegistrationToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/key_data.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/key_data.dart new file mode 100644 index 000000000000..31c02837123a --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/key_data.dart @@ -0,0 +1,53 @@ +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:catalyst_voices_repositories/src/api/models/key_value.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'key_data.g.dart'; + +/// A role data key information. +@JsonSerializable() +final class KeyData { + /// Indicates if the data is persistent or volatile. + @JsonKey(name: 'is_persistent') + final bool isPersistent; + + /// A time when the data was added. + final DateTime time; + + /// Cardano Blockchain Slot Number + /// A block slot number. + final int slot; + + /// Transaction Index + @JsonKey(name: 'txn_index') + final int txnIndex; + + /// A key type for role data. + @JsonKey(name: 'key_type') + final CertificateType keyType; + + /// A key value for role data. + /// A value of the key. + /// The key was deleted if this field is absent or nil. + @JsonKey(name: 'key_value') + final KeyValue? keyValue; + + const KeyData({ + required this.isPersistent, + required this.time, + required this.slot, + required this.txnIndex, + required this.keyType, + this.keyValue, + }); + + factory KeyData.fromJson(Map json) => _$KeyDataFromJson(json); + + String? get effectiveKeyValue => switch (keyType) { + CertificateType.pubkey => keyValue?.pubkey, + CertificateType.x509 => keyValue?.x509, + CertificateType.c509 => keyValue?.c509, + }; + + Map toJson() => _$KeyDataToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/key_value.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/key_value.dart new file mode 100644 index 000000000000..6308b65ce0ec --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/key_value.dart @@ -0,0 +1,33 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'key_value.g.dart'; + +/// A key value for role data. +@JsonSerializable(constructor: '_fromJson') +final class KeyValue { + /// Ed25519 Public Key + /// A hex encoded public key. + final String? pubkey; + + /// A PEM encoded X509 certificate. + final String? x509; + + /// A hex encoded C509 certificate. + final String? c509; + + const KeyValue.c509(String this.c509) : pubkey = null, x509 = null; + + factory KeyValue.fromJson(Map json) => _$KeyValueFromJson(json); + + const KeyValue.pubkey(String this.pubkey) : x509 = null, c509 = null; + + const KeyValue.x509(String this.x509) : pubkey = null, c509 = null; + + const KeyValue._fromJson({ + this.pubkey, + this.x509, + this.c509, + }); + + Map toJson() => _$KeyValueToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/network.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/network.dart new file mode 100644 index 000000000000..9449f192208a --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/network.dart @@ -0,0 +1,15 @@ +import 'package:json_annotation/json_annotation.dart'; + +/// Cardano network type. +/// +/// Used as query parameter for GET /v1/cardano/assets/{stake_address}. +@JsonEnum(valueField: 'value') +enum Network { + mainnet('mainnet'), + preprod('preprod'), + preview('preview'); + + final String value; + + const Network(this.value); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/payment_data.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/payment_data.dart new file mode 100644 index 000000000000..a2025754ad3d --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/payment_data.dart @@ -0,0 +1,39 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'payment_data.g.dart'; + +/// A role payment address information. +@JsonSerializable() +final class PaymentData { + /// Indicates if the data is persistent or volatile. + @JsonKey(name: 'is_persistent') + final bool isPersistent; + + /// A time when the address was added. + final DateTime time; + + /// Cardano Blockchain Slot Number + /// A block slot number. + final int slot; + + /// Transaction Index + @JsonKey(name: 'txn_index') + final int txnIndex; + + /// Cardano Payment Address + /// An option payment address. + /// CIP-19 - Cardano Addresses - https://cips.cardano.org/cip/CIP-19 + final String? address; + + const PaymentData({ + required this.isPersistent, + required this.time, + required this.slot, + required this.txnIndex, + this.address, + }); + + factory PaymentData.fromJson(Map json) => _$PaymentDataFromJson(json); + + Map toJson() => _$PaymentDataToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/rbac_registration_chain.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/rbac_registration_chain.dart new file mode 100644 index 000000000000..9d2196f9e343 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/rbac_registration_chain.dart @@ -0,0 +1,50 @@ +import 'package:catalyst_voices_repositories/src/api/models/invalid_registration.dart'; +import 'package:catalyst_voices_repositories/src/api/models/rbac_role_data.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'rbac_registration_chain.g.dart'; + +/// A chain of valid RBAC registrations. +/// A unified data of multiple RBAC registrations. +/// +/// Used as response for GET /api/v2/rbac/registration +@JsonSerializable() +final class RbacRegistrationChain { + /// Catalyst ID + @JsonKey(name: 'catalyst_id') + final String catalystId; + + /// Transaction Id/Hash + /// An ID of the last persistent transaction. + @JsonKey(name: 'last_persistent_txn') + final String? lastPersistentTxn; + + /// Transaction Id/Hash + /// An ID of the last volatile transaction. + @JsonKey(name: 'last_volatile_txn') + final String? lastVolatileTxn; + + /// A list of registration purposes. + /// 128 Bit UUID Version 4 - Random + final List purpose; + + /// A list of role data. + final List roles; + + /// A list of invalid registrations. + final List invalid; + + const RbacRegistrationChain({ + required this.catalystId, + this.lastPersistentTxn, + this.lastVolatileTxn, + this.purpose = const [], + this.roles = const [], + this.invalid = const [], + }); + + factory RbacRegistrationChain.fromJson(Map json) => + _$RbacRegistrationChainFromJson(json); + + Map toJson() => _$RbacRegistrationChainToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/rbac_role_data.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/rbac_role_data.dart new file mode 100644 index 000000000000..9bc97c77d469 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/rbac_role_data.dart @@ -0,0 +1,43 @@ +import 'package:catalyst_voices_repositories/src/api/models/extended_data.dart'; +import 'package:catalyst_voices_repositories/src/api/models/key_data.dart'; +import 'package:catalyst_voices_repositories/src/api/models/payment_data.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'rbac_role_data.g.dart'; + +/// A RBAC registration role data. +@JsonSerializable() +final class RbacRoleData { + /// A Catalyst user role identifier. + @JsonKey(name: 'role_id') + final int roleId; + + /// A list of role signing keys. + @JsonKey(name: 'signing_keys') + final List signingKeys; + + /// A list of role encryption keys. + @JsonKey(name: 'encryption_keys') + final List encryptionKeys; + + /// A list of role payment addresses. + @JsonKey(name: 'payment_addresses') + final List paymentAddresses; + + /// A map of the extended data. + /// Unlike other fields, we don't track history for this data. + @JsonKey(name: 'extended_data') + final List extendedData; + + const RbacRoleData({ + required this.roleId, + required this.signingKeys, + required this.encryptionKeys, + required this.paymentAddresses, + required this.extendedData, + }); + + factory RbacRoleData.fromJson(Map json) => _$RbacRoleDataFromJson(json); + + Map toJson() => _$RbacRoleDataToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/stake_info.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/stake_info.dart new file mode 100644 index 000000000000..fae1fe35bb8c --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/stake_info.dart @@ -0,0 +1,31 @@ +import 'package:catalyst_voices_repositories/src/api/models/staked_txo_asset_info.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'stake_info.g.dart'; + +/// User's cardano stake info. +@JsonSerializable() +final class StakeInfo { + /// Cardano Blockchain ADA coins value + /// Total stake amount. + @JsonKey(name: 'ada_amount') + final int adaAmount; + + /// Cardano Blockchain Slot Number + /// Block's slot number which contains the latest unspent UTXO. + @JsonKey(name: 'slot_number') + final int? slotNumber; + + /// TXO assets infos. + final List assets; + + const StakeInfo({ + required this.adaAmount, + this.slotNumber, + this.assets = const [], + }); + + factory StakeInfo.fromJson(Map json) => _$StakeInfoFromJson(json); + + Map toJson() => _$StakeInfoToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/staked_txo_asset_info.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/staked_txo_asset_info.dart new file mode 100644 index 000000000000..9703802d1088 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/api/models/staked_txo_asset_info.dart @@ -0,0 +1,30 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'staked_txo_asset_info.g.dart'; + +/// User's staked txo asset info. +@JsonSerializable() +final class StakedTxoAssetInfo { + /// 28 Byte Hash + /// Asset policy hash (28 bytes). + @JsonKey(name: 'policy_hash') + final String policyHash; + + /// Cardano Native Asset Name + @JsonKey(name: 'asset_name') + final String assetName; + + /// Cardano native Asset Value + final int amount; + + const StakedTxoAssetInfo({ + required this.policyHash, + required this.assetName, + required this.amount, + }); + + factory StakedTxoAssetInfo.fromJson(Map json) => + _$StakedTxoAssetInfoFromJson(json); + + Map toJson() => _$StakedTxoAssetInfoToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/campaign/campaign_repository.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/campaign/campaign_repository.dart index 540d26d46fa2..58ed0557eb7a 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/campaign/campaign_repository.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/campaign/campaign_repository.dart @@ -9,7 +9,7 @@ abstract interface class CampaignRepository { required String id, }); - Future getCategory(SignedDocumentRef ref); + Future getCategory(DocumentParameters parameters); } final class CampaignRepositoryImpl implements CampaignRepository { @@ -29,9 +29,9 @@ final class CampaignRepositoryImpl implements CampaignRepository { } @override - Future getCategory(SignedDocumentRef ref) async { + Future getCategory(DocumentParameters parameters) async { return Campaign.all .expand((element) => element.categories) - .firstWhereOrNull((e) => e.selfRef.id == ref.id); + .firstWhereOrNull((e) => parameters.containsId(e.selfRef.id)); } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/comment/comment_repository.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/comment/comment_repository.dart index 31b0e28e7caf..34be64ef4668 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/comment/comment_repository.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/comment/comment_repository.dart @@ -54,35 +54,14 @@ final class DocumentsCommentRepository implements CommentRepository { required CatalystId catalystId, required CatalystPrivateKey privateKey, }) async { - final ref = document.metadata.ref; - final reply = document.metadata.reply; - final categoryId = document.metadata.categoryId; - - assert(ref != null, 'CommentDocument have to have a ref to other document'); - // TODO(damian-molinski): creating SignedDocumentMetadata with correct refs - // have to be captured single place. assert( - categoryId != null, - 'CommentDocument have to have categoryId because proposals always have categoryId', - ); - - final payload = SignedDocumentJsonPayload(document.content.data); - final metadata = SignedDocumentMetadata( - contentType: SignedDocumentContentType.json, - documentType: DocumentType.commentDocument, - id: document.metadata.id, - ver: document.metadata.version, - ref: SignedDocumentMetadataRef.fromDocumentRef(ref!), - template: SignedDocumentMetadataRef.fromDocumentRef( - document.metadata.template!, - ), - reply: reply != null ? SignedDocumentMetadataRef.fromDocumentRef(reply) : null, - categoryId: SignedDocumentMetadataRef.fromDocumentRef(categoryId!), + document.metadata.ref != null, + 'CommentDocument have to have a ref to other document', ); final signedDocument = await _signedDocumentManager.signDocument( - payload, - metadata: metadata, + SignedDocumentJsonPayload(document.content.data), + metadata: document.metadata, catalystId: catalystId, privateKey: privateKey, ); @@ -144,10 +123,10 @@ final class DocumentsCommentRepository implements CommentRepository { final authors = documentData.metadata.authors; final metadata = CommentMetadata( selfRef: documentData.metadata.selfRef as SignedDocumentRef, - ref: documentData.metadata.ref! as SignedDocumentRef, - template: templateData.metadata.selfRef as SignedDocumentRef, + proposalRef: documentData.metadata.ref! as SignedDocumentRef, + commentTemplate: templateData.metadata.selfRef as SignedDocumentRef, reply: documentData.metadata.reply, - categoryId: documentData.metadata.categoryId, + parameters: documentData.metadata.parameters, authorId: authors!.single, ); final content = DocumentDataContentDto.fromModel( @@ -176,6 +155,7 @@ final class DocumentsCommentRepository implements CommentRepository { final metadata = CommentTemplateMetadata( selfRef: documentData.metadata.selfRef as SignedDocumentRef, + parameters: documentData.metadata.parameters, ); final contentData = documentData.content.data; diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/common/future_response_mapper.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/common/future_response_mapper.dart new file mode 100644 index 000000000000..f8f6155c8a13 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/common/future_response_mapper.dart @@ -0,0 +1,28 @@ +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; + +extension FutureResponseMapper on Future { + /// Returns the [T] body from the response + /// or throws an exception if the response wasn't successful. + Future successBodyOrThrow() async { + try { + final response = await this; + return response; + } catch (e) { + if (e case ApiBadResponseException(:final statusCode)) { + final message = _extractExceptionMessage(e); + if (statusCode == ApiResponseStatusCode.notFound) { + throw NotFoundException(message: message); + } else if (statusCode == ApiResponseStatusCode.unauthorized) { + throw UnauthorizedException(message: message); + } else if (statusCode == ApiResponseStatusCode.conflict) { + throw ResourceConflictException(message: message); + } + } + rethrow; + } + } + + String? _extractExceptionMessage(ApiException exception) { + return exception.message ?? exception.error?.toString(); + } +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/common/response_mapper.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/common/response_mapper.dart deleted file mode 100644 index 611fa031e013..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/common/response_mapper.dart +++ /dev/null @@ -1,80 +0,0 @@ -import 'dart:typed_data'; - -import 'package:catalyst_voices_models/catalyst_voices_models.dart'; -import 'package:chopper/chopper.dart' as chopper; - -/// Handles [Future] API responses. -extension FutureResponseMapper on Future> { - /// Returns [Uint8List] body bytes from the response - /// or throws an exception if the response wasn't successful. - Future successBodyBytesOrThrow() async { - final response = await this; - return response.successBodyBytesOrThrow(); - } - - /// Returns the [T] body from the response - /// or throws an exception if the response wasn't successful. - Future successBodyOrThrow() async { - final response = await this; - return response.successBodyOrThrow(); - } - - /// Completes successfully if the response was successful - /// or throws an exception if it wasn't. - Future successOrThrow() async { - final response = await this; - return response.successOrThrow(); - } -} - -/// Handles API responses. -extension ResponseMapper on chopper.Response { - Uint8List successBodyBytesOrThrow() { - if (isSuccessful) { - return bodyBytes; - } else if (statusCode == ApiResponseStatusCode.notFound) { - throw NotFoundException(message: error.toString()); - } else if (statusCode == ApiResponseStatusCode.conflict) { - throw ResourceConflictException(message: _extractErrorMessage(error)); - } else { - throw toApiException(); - } - } - - T successBodyOrThrow() { - if (isSuccessful) { - return bodyOrThrow; - } else if (statusCode == ApiResponseStatusCode.notFound) { - throw NotFoundException(message: _extractErrorMessage(error)); - } else if (statusCode == ApiResponseStatusCode.unauthorized) { - throw UnauthorizedException(message: error.toString()); - } else if (statusCode == ApiResponseStatusCode.conflict) { - throw ResourceConflictException(message: _extractErrorMessage(error)); - } else { - throw toApiException(); - } - } - - void successOrThrow() { - if (isSuccessful) { - return; - } else if (statusCode == ApiResponseStatusCode.notFound) { - throw NotFoundException(message: _extractErrorMessage(error)); - } else if (statusCode == ApiResponseStatusCode.conflict) { - throw ResourceConflictException(message: _extractErrorMessage(error)); - } else { - throw toApiException(); - } - } - - ApiErrorResponseException toApiException() { - return ApiErrorResponseException( - statusCode: statusCode, - error: error, - ); - } - - String? _extractErrorMessage(Object? error) { - return error?.toString(); - } -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/config/remote_config_source.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/config/remote_config_source.dart index f90bf9347b23..361651c67c36 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/config/remote_config_source.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/config/remote_config_source.dart @@ -1,32 +1,22 @@ //ignore_for_file: one_member_abstracts -import 'dart:convert'; - import 'package:catalyst_voices_repositories/catalyst_voices_repositories.dart'; -import 'package:catalyst_voices_repositories/src/common/response_mapper.dart'; -import 'package:catalyst_voices_repositories/src/dto/config/config.dart'; +import 'package:catalyst_voices_repositories/src/api/api_services.dart'; +import 'package:catalyst_voices_repositories/src/common/future_response_mapper.dart'; +import 'package:catalyst_voices_repositories/src/dto/config/remote_config.dart'; final class ApiConfigSource implements RemoteConfigSource { final ApiServices _api; - ApiConfigSource( - this._api, - ); + ApiConfigSource(this._api); @override - Future get() { - return _api.gateway - .apiV1ConfigFrontendGet() - .successBodyOrThrow() - .then((value) { - if (value is Map) { - return value; - } - final encoded = value is String ? value : '{}'; - return jsonDecode(encoded) as Map; - }) - .catchError((_) => {}) - .then(RemoteConfig.fromJson); + Future get() async { + try { + return _api.gateway.frontendConfig().successBodyOrThrow(); + } catch (_) { + return const RemoteConfig(); + } } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/database/dao/documents_dao.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/database/dao/documents_dao.dart index 2d936c72b3ca..28193a8a7dd8 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/database/dao/documents_dao.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/database/dao/documents_dao.dart @@ -58,13 +58,16 @@ abstract interface class DocumentsDao { Future> queryAll({ DocumentRef? ref, DocumentType? type, + CampaignFilters? campaign, }); /// Returns all known document refs. Future> queryAllTypedRefs(); Future queryLatestDocumentData({ + DocumentType? type, CatalystId? authorId, + DocumentRef? category, }); /// Returns document with matching refTo and type. @@ -219,6 +222,7 @@ class DriftDocumentsDao extends DatabaseAccessor Future> queryAll({ DocumentRef? ref, DocumentType? type, + CampaignFilters? campaign, }) { final query = select(documents); @@ -228,6 +232,9 @@ class DriftDocumentsDao extends DatabaseAccessor if (type != null) { query.where((doc) => doc.type.equals(type.uuid)); } + if (campaign != null) { + query.where((tbl) => tbl.metadata.isInCategoryList(campaign.categoriesIds)); + } return query.get(); } @@ -269,7 +276,7 @@ class DriftDocumentsDao extends DatabaseAccessor }) async { final query = select(documents) ..where( - (tbl) => BaseJsonQueryExpression( + (tbl) => JsonQuerySearchExpression( jsonContent: content, nodeId: nodeId, searchValue: value, @@ -285,16 +292,26 @@ class DriftDocumentsDao extends DatabaseAccessor @override Future queryLatestDocumentData({ + DocumentType? type, CatalystId? authorId, + DocumentRef? category, }) { final query = select(documents) ..orderBy([(t) => OrderingTerm.desc(t.verHi)]) ..limit(1); + if (type != null) { + query.where((tbl) => tbl.type.equalsValue(type)); + } + if (authorId != null) { query.where((tbl) => tbl.metadata.isAuthor(authorId)); } + if (category != null) { + query.where((tbl) => tbl.metadata.isInCategoryList([category.id])); + } + return query.getSingleOrNull(); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/database/dao/proposals_dao.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/database/dao/proposals_dao.dart index 64275ad1558b..782762800d7d 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/database/dao/proposals_dao.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/database/dao/proposals_dao.dart @@ -87,11 +87,12 @@ class DriftProposalsDao extends DatabaseAccessor Expression.and([ proposal.type.equalsValue(DocumentType.proposalDocument), proposal.metadata.jsonExtract(r'$.template').isNotNull(), - proposal.metadata.jsonExtract(r'$.categoryId.id').isNotNull(), + Expression.or([ + proposal.metadata.jsonExtract(r'$.categoryId').isNotNull(), + proposal.metadata.jsonExtract(r'$.parameters').isNotNull(), + ]), if (filters.campaign != null) - proposal.metadata - .jsonExtract(r'$.categoryId.id') - .isIn(filters.campaign!.categoriesIds), + proposal.metadata.isInCategoryList(filters.campaign!.categoriesIds), ]), ) ..orderBy([OrderingTerm.asc(proposal.verHi)]); @@ -176,11 +177,12 @@ class DriftProposalsDao extends DatabaseAccessor proposal.type.equalsValue(DocumentType.proposalDocument), // Safe check for invalid proposals proposal.metadata.jsonExtract(r'$.template').isNotNull(), - proposal.metadata.jsonExtract(r'$.categoryId').isNotNull(), + Expression.or([ + proposal.metadata.jsonExtract(r'$.categoryId').isNotNull(), + proposal.metadata.jsonExtract(r'$.parameters').isNotNull(), + ]), if (filters.campaign != null) - proposal.metadata - .jsonExtract(r'$.categoryId.id') - .isIn(filters.campaign!.categoriesIds), + proposal.metadata.isInCategoryList(filters.campaign!.categoriesIds), ]), ) ..orderBy(order.terms(proposal)) @@ -535,12 +537,12 @@ class DriftProposalsDao extends DatabaseAccessor Expression.and([ documents.type.equalsValue(DocumentType.proposalDocument), // Safe check for invalid proposals - documents.metadata.jsonExtract(r'$.template').isNotNull(), - documents.metadata.jsonExtract(r'$.categoryId').isNotNull(), + Expression.or([ + documents.metadata.jsonExtract(r'$.categoryId').isNotNull(), + documents.metadata.jsonExtract(r'$.parameters').isNotNull(), + ]), if (filters?.campaign != null) - documents.metadata - .jsonExtract(r'$.categoryId.id') - .isIn(filters!.campaign!.categoriesIds), + documents.metadata.isInCategoryList(filters!.campaign!.categoriesIds), ]), ) ..orderBy([OrderingTerm.desc(documents.verHi)]) diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/database/query/jsonb_expressions.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/database/query/jsonb_expressions.dart index 8365e339f5e4..9a2679b41fae 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/database/query/jsonb_expressions.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/database/query/jsonb_expressions.dart @@ -5,32 +5,7 @@ import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; import 'package:drift/drift.dart'; import 'package:drift/extensions/json1.dart'; -class BaseJsonQueryExpression extends Expression { - final String jsonContent; - final NodeId nodeId; - final String searchValue; - final bool useExactMatch; - - const BaseJsonQueryExpression({ - required this.jsonContent, - required this.nodeId, - required this.searchValue, - this.useExactMatch = false, - }); - - @override - void writeInto(GenerationContext context) { - final sql = JsonBExpressions.generateSqlForJsonQuery( - jsonContent: jsonContent, - nodeId: nodeId, - searchValue: searchValue, - ); - - context.buffer.write(sql); - } -} - -final class ContainsAuthorId extends BaseJsonQueryExpression { +final class ContainsAuthorId extends JsonQuerySearchExpression { ContainsAuthorId({ required CatalystId id, }) : super( @@ -40,7 +15,7 @@ final class ContainsAuthorId extends BaseJsonQueryExpression { ); } -final class ContainsContentAuthorName extends BaseJsonQueryExpression { +final class ContainsContentAuthorName extends JsonQuerySearchExpression { ContainsContentAuthorName({ required String query, }) : super( @@ -50,7 +25,7 @@ final class ContainsContentAuthorName extends BaseJsonQueryExpression { ); } -final class ContainsMetadataAuthorName extends BaseJsonQueryExpression { +final class ContainsMetadataAuthorName extends JsonQuerySearchExpression { ContainsMetadataAuthorName({ required String query, }) : super( @@ -60,7 +35,28 @@ final class ContainsMetadataAuthorName extends BaseJsonQueryExpression { ); } -final class ContainsTitle extends BaseJsonQueryExpression { +final class ContainsParameterId extends JsonQuerySearchExpression { + ContainsParameterId({ + required String parameterId, + }) : super( + searchValue: parameterId, + nodeId: ProposalMetadata.parametersIdNode, + jsonContent: 'metadata', + useExactMatch: true, + ); +} + +final class ContainsParameterIdInList extends JsonQuerySearchMultiExpression { + ContainsParameterIdInList({ + required List ids, + }) : super( + searchValues: ids, + jsonContent: 'metadata', + nodeId: ProposalMetadata.parametersIdNode, + ); +} + +final class ContainsTitle extends JsonQuerySearchExpression { ContainsTitle({ required String query, }) : super( @@ -73,6 +69,50 @@ final class ContainsTitle extends BaseJsonQueryExpression { class JsonBExpressions { const JsonBExpressions(); + static String generateSqlForJsonMultiQuery({ + required String jsonContent, + required NodeId nodeId, + required List searchValues, + }) { + final valueComparison = "IN (${searchValues.map((e) => "'$e'").join(',')})"; + final handler = WildcardPathHandler.fromNodeId(nodeId); + final wildcardPaths = handler.getWildcardPaths; + + if (!handler.hasWildcard || wildcardPaths == null) { + return _queryJsonExtract( + jsonContent: jsonContent, + nodeId: nodeId, + valueComparison: valueComparison, + ); + } + + final arrayPath = wildcardPaths.prefix.value.isEmpty ? '' : wildcardPaths.prefix.asPath; + final fieldName = wildcardPaths.suffix?.asPath; + + if (wildcardPaths.prefix.value.isEmpty) { + return _queryJsonTreeForKey( + jsonContent: jsonContent, + fieldName: fieldName?.substring(2), + valueComparison: valueComparison, + ); + } + + if (fieldName != null) { + return _queryJsonEachForWildcard( + jsonContent: jsonContent, + arrayPath: arrayPath, + fieldName: fieldName, + valueComparison: valueComparison, + ); + } + + return _queryJsonTreeForWildcard( + jsonContent: jsonContent, + arrayPath: arrayPath, + valueComparison: valueComparison, + ); + } + static String generateSqlForJsonQuery({ required String jsonContent, required NodeId nodeId, @@ -152,6 +192,54 @@ class JsonBExpressions { } } +class JsonQuerySearchExpression extends Expression { + final String jsonContent; + final NodeId nodeId; + final String searchValue; + final bool useExactMatch; + + const JsonQuerySearchExpression({ + required this.jsonContent, + required this.nodeId, + required this.searchValue, + this.useExactMatch = false, + }); + + @override + void writeInto(GenerationContext context) { + final sql = JsonBExpressions.generateSqlForJsonQuery( + jsonContent: jsonContent, + nodeId: nodeId, + searchValue: searchValue, + ); + + context.buffer.write(sql); + } +} + +class JsonQuerySearchMultiExpression extends Expression { + final String jsonContent; + final NodeId nodeId; + final List searchValues; + + const JsonQuerySearchMultiExpression({ + required this.jsonContent, + required this.nodeId, + required this.searchValues, + }); + + @override + void writeInto(GenerationContext context) { + final sql = JsonBExpressions.generateSqlForJsonMultiQuery( + jsonContent: jsonContent, + nodeId: nodeId, + searchValues: searchValues, + ); + + context.buffer.write(sql); + } +} + extension on NodeId { /// Converts [NodeId] into jsonb well-formatted path argument. /// @@ -195,6 +283,16 @@ extension MetadataColumnExt on GeneratedColumnWithTypeConverter isAuthor(CatalystId id) => ContainsAuthorId(id: id); Expression isCategory(SignedDocumentRef ref) { - return jsonExtract(ProposalMetadata.categoryIdNode.asPath).equals(ref.id); + return Expression.or([ + jsonExtract(ProposalMetadata.categoryIdNode.asPath).equals(ref.id), + ContainsParameterId(parameterId: ref.id), + ]); + } + + Expression isInCategoryList(List ids) { + return Expression.or([ + jsonExtract(ProposalMetadata.categoryIdNode.asPath).isIn(ids), + ContainsParameterIdInList(ids: ids), + ]); } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/document_data_factory.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/document_data_factory.dart index 170282d491a4..502dc657f8c2 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/document_data_factory.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/document_data_factory.dart @@ -7,64 +7,19 @@ final class DocumentDataFactory { /// Creates correct [DocumentData] from [document]. /// - /// Throws [SignedDocumentMetadataMalformed] in case of any required fields - /// missing. - /// - /// Throws [UnknownSignedDocumentContentType] in case of not supported + /// Throws [UnknownDocumentContentTypeException] in case of not supported /// [document] contentType. static DocumentData create(SignedDocument document) { - final malformedReasons = []; - final id = document.metadata.id; - if (id == null) { - malformedReasons.add('id is missing'); - } - final ver = document.metadata.ver; - if (ver == null) { - malformedReasons.add('version is missing'); - } - - if (malformedReasons.isNotEmpty) { - throw SignedDocumentMetadataMalformed(reasons: malformedReasons); - } - - final metadata = DocumentDataMetadata( - type: document.metadata.documentType, - selfRef: SignedDocumentRef(id: id!, version: ver), - ref: document.metadata.ref?.toModel(), - refHash: document.metadata.refHash?.toModel(), - template: document.metadata.template?.toModel(), - reply: document.metadata.reply?.toModel(), - section: document.metadata.section, - brandId: document.metadata.brandId?.toModel(), - campaignId: document.metadata.campaignId?.toModel(), - electionId: document.metadata.electionId, - categoryId: document.metadata.categoryId?.toModel(), - authors: document.signers, - ); - final content = switch (document.payload) { SignedDocumentJsonPayload(:final data) => DocumentDataContent(data), - SignedDocumentUnknownPayload() => throw UnknownSignedDocumentContentType( + SignedDocumentUnknownPayload() => throw UnknownDocumentContentTypeException( type: document.metadata.contentType, ), }; return DocumentData( - metadata: metadata, + metadata: document.metadata, content: content, ); } } - -extension on SignedDocumentMetadataRef { - SignedDocumentRef toModel() => SignedDocumentRef(id: id, version: ver); -} - -extension on SignedDocumentMetadataRefHash { - SecuredDocumentRef toModel() { - return SecuredDocumentRef( - ref: ref.toModel(), - hash: hash, - ); - } -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/document_repository.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/document_repository.dart index 1283b2c032c6..53270285e06c 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/document_repository.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/document_repository.dart @@ -85,7 +85,9 @@ abstract interface class DocumentRepository { /// latest [DocumentData] which of [authorId] and check /// username used in [CatalystId] in that document. Future getLatestDocument({ + DocumentType? type, CatalystId? authorId, + DocumentRef? category, }); /// Returns count of documents matching [ref] id and [type]. @@ -94,6 +96,14 @@ abstract interface class DocumentRepository { required DocumentType type, }); + /// Returns list of known refs given provided filters. + Future> getRefs({ + DocumentType? type, + CampaignFilters? campaign, + int limit, + int offset, + }); + Future getRefToDocumentData({ required DocumentRef refTo, required DocumentType type, @@ -328,11 +338,19 @@ final class DocumentRepositoryImpl implements DocumentRepository { }; } + // TODO(damian-molinski): this will be removed and replaced on performance branch so + // i'm not implementing drafts now. @override Future getLatestDocument({ + DocumentType? type, CatalystId? authorId, + DocumentRef? category, }) async { - final latestDocument = await _localDocuments.getLatest(authorId: authorId); + final latestDocument = await _localDocuments.getLatest( + type: type, + authorId: authorId, + category: category, + ); final latestDraft = await _drafts.getLatest(authorId: authorId); return [latestDocument, latestDraft].nonNulls.sorted((a, b) => a.compareTo(b)).firstOrNull; @@ -346,6 +364,21 @@ final class DocumentRepositoryImpl implements DocumentRepository { return _localDocuments.getRefCount(ref: ref, type: type); } + @override + Future> getRefs({ + DocumentType? type, + CampaignFilters? campaign, + int limit = 100, + int offset = 0, + }) { + return _localDocuments.getRefs( + type: type, + campaign: campaign, + limit: limit, + offset: offset, + ); + } + @override Future getRefToDocumentData({ required DocumentRef refTo, @@ -658,13 +691,11 @@ final class DocumentRepositoryImpl implements DocumentRepository { bool _isDocumentMetadataValid(DocumentData document) { final template = document.metadata.template; - final category = document.metadata.categoryId; final documentType = document.metadata.type; final isInvalidTemplate = template == null || !template.isValid; - final isInvalidCategory = category == null || !category.isValid; final isInvalidType = documentType == DocumentType.unknown; - final isInvalidProposal = isInvalidTemplate || isInvalidType || isInvalidCategory; + final isInvalidProposal = isInvalidTemplate || isInvalidType; return !isInvalidProposal; } @@ -736,7 +767,7 @@ final class DocumentRepositoryImpl implements DocumentRepository { void _validateDocumentMetadata(DocumentData document) { if (!_isDocumentMetadataValid(document)) { - throw const DocumentImportInvalidDataException(SignedDocumentMetadataMalformed); + throw const DocumentImportInvalidDataException(DocumentMetadataMalformedException); } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/exception/document_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/exception/document_exception.dart index cf59f7cf891c..635bbed4d869 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/exception/document_exception.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/exception/document_exception.dart @@ -3,6 +3,16 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; /// Base class for all document exceptions. sealed class DocumentException implements Exception {} +/// Exception thrown when signed document metadata is malformed. +final class DocumentMetadataMalformedException implements DocumentException { + final List reasons; + + const DocumentMetadataMalformedException({required this.reasons}); + + @override + String toString() => 'SignedDocument malformed because of $reasons'; +} + /// Exception thrown when document is not found. final class DocumentNotFoundException implements DocumentException { final DocumentRef ref; @@ -23,22 +33,21 @@ final class DraftNotFoundException implements DocumentException { String toString() => 'Draft matching $ref not found'; } -/// Exception thrown when signed document metadata is malformed. -final class SignedDocumentMetadataMalformed implements DocumentException { - final List reasons; +final class ProposalTemplateNotFoundException implements DocumentException { + final DocumentRef category; - const SignedDocumentMetadataMalformed({required this.reasons}); + const ProposalTemplateNotFoundException({required this.category}); @override - String toString() => 'SignedDocument malformed because of $reasons'; + String toString() => 'Proposal template for category $category not found'; } /// Exception thrown when signed document content type is unknown. -final class UnknownSignedDocumentContentType implements DocumentException { - final SignedDocumentContentType type; +final class UnknownDocumentContentTypeException implements DocumentException { + final DocumentContentType type; - const UnknownSignedDocumentContentType({required this.type}); + const UnknownDocumentContentTypeException({required this.type}); @override - String toString() => 'Unknown SignedDocument contentType($type)'; + String toString() => 'Unknown Document contentType($type)'; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/source/database_documents_data_source.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/source/database_documents_data_source.dart index 4d64c93f8014..e196c7e1e361 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/source/database_documents_data_source.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/source/database_documents_data_source.dart @@ -44,10 +44,12 @@ final class DatabaseDocumentsDataSource @override Future getLatest({ + DocumentType? type, CatalystId? authorId, + DocumentRef? category, }) { return _database.documentsDao - .queryLatestDocumentData(authorId: authorId) + .queryLatestDocumentData(type: type, authorId: authorId, category: category) .then((value) => value?.toModel()); } @@ -83,6 +85,19 @@ final class DatabaseDocumentsDataSource return _database.documentsDao.countRefDocumentByType(ref: ref, type: type); } + @override + Future> getRefs({ + DocumentType? type, + CampaignFilters? campaign, + int limit = 100, + int offset = 0, + }) { + // TODO(damian-molinski): This implementation will be replaced at performance branch + return _database.documentsDao + .queryAll(type: type, campaign: campaign) + .then((value) => value.map((e) => e.metadata.selfRef.toSignedDocumentRef()).toList()); + } + @override Future getRefToDocumentData({ required DocumentRef refTo, diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/source/document_data_local_source.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/source/document_data_local_source.dart index 9080c261f433..bb40fd9e8e6f 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/source/document_data_local_source.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/source/document_data_local_source.dart @@ -47,11 +47,25 @@ abstract interface class DraftDataSource implements DocumentDataLocalSource { abstract interface class SignedDocumentDataSource implements DocumentDataLocalSource { Future deleteAllRespectingLocalDrafts(); + @override + Future getLatest({ + DocumentType? type, + CatalystId? authorId, + DocumentRef? category, + }); + Future getRefCount({ required DocumentRef ref, required DocumentType type, }); + Future> getRefs({ + DocumentType? type, + CampaignFilters? campaign, + int limit, + int offset, + }); + Future getRefToDocumentData({ required DocumentRef refTo, required DocumentType type, diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/source/document_data_remote_source.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/source/document_data_remote_source.dart index 17fa23f43582..e5ca7a6d2638 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/source/document_data_remote_source.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/document/source/document_data_remote_source.dart @@ -1,11 +1,12 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_repositories/catalyst_voices_repositories.dart'; -import 'package:catalyst_voices_repositories/generated/api/cat_gateway.models.swagger.dart'; -import 'package:catalyst_voices_repositories/src/common/content_types.dart'; -import 'package:catalyst_voices_repositories/src/common/response_mapper.dart'; +import 'package:catalyst_voices_repositories/src/api/models/document_index_list.dart'; +import 'package:catalyst_voices_repositories/src/api/models/document_index_query_filter.dart'; +import 'package:catalyst_voices_repositories/src/api/models/document_reference.dart'; +import 'package:catalyst_voices_repositories/src/api/models/eq_or_ranged_id.dart'; +import 'package:catalyst_voices_repositories/src/api/models/id_and_ver_ref.dart'; +import 'package:catalyst_voices_repositories/src/common/future_response_mapper.dart'; import 'package:catalyst_voices_repositories/src/document/document_data_factory.dart'; -import 'package:catalyst_voices_repositories/src/dto/api/document_index_list_dto.dart'; -import 'package:catalyst_voices_repositories/src/dto/api/document_index_query_filters_dto.dart'; import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; @@ -24,11 +25,11 @@ final class CatGatewayDocumentDataSource implements DocumentDataRemoteSource { @override Future get({required DocumentRef ref}) async { final bytes = await _api.gateway - .apiV1DocumentDocumentIdGet( + .getDocument( documentId: ref.id, version: ref.version, ) - .successBodyBytesOrThrow(); + .successBodyOrThrow(); final signedDocument = await _signedDocumentManager.parseDocument(bytes); return DocumentDataFactory.create(signedDocument); @@ -47,26 +48,18 @@ final class CatGatewayDocumentDataSource implements DocumentDataRemoteSource { try { final index = await _api.gateway - .apiV1DocumentIndexPost( - body: DocumentIndexQueryFilter(id: IdSelectorDto.eq(id)), + .documentIndex( + filter: DocumentIndexQueryFilter(id: [EqOrRangedId.eq(id)]), limit: 1, ) - .successBodyOrThrow() - .then(_mapDynamicResponseValue); + .successBodyOrThrow(); final docs = index.docs; if (docs.isEmpty) { return null; } - return docs - .sublist(0, 1) - .cast>() - .map(DocumentIndexListDto.fromJson) - .firstOrNull - ?.ver - .firstOrNull - ?.ver; + return docs.sublist(0, 1).firstOrNull?.ver.firstOrNull?.ver; } on NotFoundException { return null; } @@ -83,28 +76,15 @@ final class CatGatewayDocumentDataSource implements DocumentDataRemoteSource { var remaining = 0; do { - final response = - await _getDocumentIndexList( - page: page, - limit: maxPerPage, - campaign: campaign, - ) - // TODO(damian-molinski): Remove this workaround when migrated to V2 endpoint. - // https://github.com/input-output-hk/catalyst-voices/issues/3199#issuecomment-3204803465 - .onError( - (_, _) { - return DocumentIndexList( - docs: [], - page: CurrentPage(page: page, limit: maxPerPage, remaining: 0), - ); - }, - ); + final response = await _getDocumentIndexList( + page: page, + limit: maxPerPage, + campaign: campaign, + ); allRefs.addAll(response.refs); - // TODO(damian-molinski): Remove this workaround when migrated to V2 endpoint. - // https://github.com/input-output-hk/catalyst-voices/issues/3199#issuecomment-3204803465 - remaining = response.docs.length < maxPerPage ? 0 : response.page.remaining; + remaining = response.page.remaining; page = response.page.page + 1; } while (remaining > 0); @@ -114,12 +94,7 @@ final class CatGatewayDocumentDataSource implements DocumentDataRemoteSource { @override Future publish(SignedDocument document) async { final bytes = document.toBytes(); - await _api.gateway - .apiV1DocumentPut( - body: bytes, - contentType: ContentTypes.applicationCbor, - ) - .successOrThrow(); + await _api.gateway.uploadDocument(body: bytes).successBodyOrThrow(); } Future _getDocumentIndexList({ @@ -127,30 +102,21 @@ final class CatGatewayDocumentDataSource implements DocumentDataRemoteSource { required int limit, required Campaign campaign, }) async { - final categoriesIds = campaign.categories.map((e) => e.selfRef.id).toList(); + assert(campaign.categories.length <= 10, 'Max 10 categories are allowed in the filter.'); + + final categoryFilter = campaign.categories + .take(10) + .map((e) => IdAndVerRef.idOnly(EqOrRangedId.eq(e.selfRef.id))) + .toList(); + final documentFilter = DocumentIndexQueryFilter(category: categoryFilter); return _api.gateway - .apiV1DocumentIndexPost( - body: DocumentIndexQueryFilter( - parameters: IdRefOnly(id: IdSelectorDto.inside(categoriesIds)).toJson(), - ), + .documentIndex( + filter: documentFilter, limit: limit, page: page, ) - .successBodyOrThrow() - .then(_mapDynamicResponseValue); - } - - DocumentIndexList _mapDynamicResponseValue(dynamic value) { - if (value is DocumentIndexList) { - return value; - } - - if (value is Map) { - return DocumentIndexList.fromJson(value); - } - - return const DocumentIndexList(docs: [], page: CurrentPage(page: 0, limit: 0, remaining: 0)); + .successBodyOrThrow(); } } @@ -165,8 +131,6 @@ abstract interface class DocumentDataRemoteSource implements DocumentDataSource extension on DocumentIndexList { List get refs { return docs - .cast>() - .map(DocumentIndexListDto.fromJson) .map((ref) { return [ ...ref.ver @@ -178,40 +142,33 @@ extension on DocumentIndexList { ref: SignedDocumentRef(id: ref.id, version: ver.ver), type: documentType, ), - if (ver.ref != null) - TypedDocumentRef( - ref: ver.ref!.toRef(), - type: DocumentType.unknown, - ), - if (ver.reply != null) - TypedDocumentRef( - ref: ver.reply!.toRef(), - type: DocumentType.unknown, - ), - if (ver.parameters != null) - TypedDocumentRef( - ref: ver.parameters!.toRef(), - type: DocumentType.categoryParametersDocument, - ), - if (ver.template != null) - TypedDocumentRef( - ref: ver.template!.toRef(), - type: documentType.template ?? DocumentType.unknown, + if (ver.ref case final ref?) + ...ref.map( + (ref) => TypedDocumentRef( + ref: ref.toRef(), + type: DocumentType.unknown, + ), ), - if (ver.brand != null) - TypedDocumentRef( - ref: ver.brand!.toRef(), - type: DocumentType.brandParametersDocument, + if (ver.reply case final reply?) + ...reply.map( + (reply) => TypedDocumentRef( + ref: reply.toRef(), + type: DocumentType.unknown, + ), ), - if (ver.campaign != null) - TypedDocumentRef( - ref: ver.campaign!.toRef(), - type: DocumentType.campaignParametersDocument, + if (ver.parameters case final parameters?) + ...parameters.map( + (parameters) => TypedDocumentRef( + ref: parameters.toRef(), + type: DocumentType.categoryParametersDocument, + ), ), - if (ver.category != null) - TypedDocumentRef( - ref: ver.category!.toRef(), - type: DocumentType.categoryParametersDocument, + if (ver.template case final template?) + ...template.map( + (template) => TypedDocumentRef( + ref: template.toRef(), + type: documentType.template ?? DocumentType.unknown, + ), ), ]; }) @@ -223,6 +180,6 @@ extension on DocumentIndexList { } } -extension on DocumentRefForFilteredDocuments { +extension on DocumentReference { SignedDocumentRef toRef() => SignedDocumentRef(id: id, version: ver); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/api/document_index_list_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/api/document_index_list_dto.dart deleted file mode 100644 index ae5736221b41..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/api/document_index_list_dto.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:json_annotation/json_annotation.dart'; - -part 'document_index_list_dto.g.dart'; - -// Note. OpenAPI spec is incorrect at the moment. This dto is here as -// temporary workaround. -@JsonSerializable() -final class DocumentIndexListDto { - final String id; - final List ver; - - DocumentIndexListDto({ - required this.id, - required this.ver, - }); - - factory DocumentIndexListDto.fromJson(Map json) { - return _$DocumentIndexListDtoFromJson(json); - } - - @visibleForTesting - Map toJson() => _$DocumentIndexListDtoToJson(this); -} - -@JsonSerializable() -final class DocumentRefForFilteredDocuments { - final String id; - final String? ver; - - DocumentRefForFilteredDocuments({ - required this.id, - this.ver, - }); - - factory DocumentRefForFilteredDocuments.fromJson(Map json) { - return _$DocumentRefForFilteredDocumentsFromJson(json); - } - - @visibleForTesting - Map toJson() { - return _$DocumentRefForFilteredDocumentsToJson(this); - } -} - -@JsonSerializable() -final class IndividualDocumentVersion { - final String ver; - final String type; - final DocumentRefForFilteredDocuments? ref; - final DocumentRefForFilteredDocuments? reply; - @JsonKey(name: 'doc_parameters') - final DocumentRefForFilteredDocuments? parameters; - final DocumentRefForFilteredDocuments? template; - final DocumentRefForFilteredDocuments? brand; - final DocumentRefForFilteredDocuments? campaign; - final DocumentRefForFilteredDocuments? category; - - IndividualDocumentVersion({ - required this.ver, - required this.type, - this.ref, - this.reply, - this.parameters, - this.template, - this.brand, - this.campaign, - this.category, - }); - - factory IndividualDocumentVersion.fromJson(Map json) { - return _$IndividualDocumentVersionFromJson(json); - } - - @visibleForTesting - Map toJson() => _$IndividualDocumentVersionToJson(this); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/api/document_index_query_filters_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/api/document_index_query_filters_dto.dart deleted file mode 100644 index 6fbf0cfafd5d..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/api/document_index_query_filters_dto.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:catalyst_voices_repositories/generated/api/cat_gateway.models.swagger.dart' - show IdSelector; -import 'package:json_annotation/json_annotation.dart'; - -part 'document_index_query_filters_dto.g.dart'; - -// Note. OpenAPI spec is incorrect at the moment. This dto is here as -// temporary workaround. -@JsonSerializable(createFactory: false, includeIfNull: false) -final class IdSelectorDto extends IdSelector { - final String? eq; - final String? min; - final String? max; - @JsonKey(name: 'in') - final List? inside; - - const IdSelectorDto.eq(this.eq) : min = null, max = null, inside = null; - - const IdSelectorDto.range({ - required this.min, - required this.max, - }) : eq = null, - inside = null; - - const IdSelectorDto.inside(List data) : eq = null, min = null, max = null, inside = data; - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - // ignore: hash_and_equals, avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => super.hashCode; - - @override - Map toJson() => _$IdSelectorDtoToJson(this); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/blockchain/network_id_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/blockchain/network_id_ext.dart similarity index 61% rename from catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/blockchain/network_id_dto.dart rename to catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/blockchain/network_id_ext.dart index ec23dbd44e1e..58e5b6b584cb 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/blockchain/network_id_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/blockchain/network_id_ext.dart @@ -1,8 +1,8 @@ import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart'; -import 'package:catalyst_voices_repositories/generated/api/cat_gateway.enums.swagger.dart'; +import 'package:catalyst_voices_repositories/src/api/models/network.dart'; -extension NetworkIdDto on NetworkId { - Network toDto() { +extension NetworkIdExt on NetworkId { + Network toApiValue() { switch (this) { case NetworkId.mainnet: return Network.mainnet; diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/component_status/component_ext.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/component_status/component_ext.dart index 35c2e7fbe3e6..7c6917ef29dc 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/component_status/component_ext.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/component_status/component_ext.dart @@ -1,11 +1,12 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; -import 'package:catalyst_voices_repositories/generated/api/cat_status.swagger.dart' as swagger; +import 'package:catalyst_voices_repositories/src/api/models/component.dart'; +import 'package:catalyst_voices_repositories/src/api/models/component_status.dart' as api_enum; -extension ComponentExt on swagger.Component { +extension ComponentExt on Component { ComponentStatus toModel() { return ComponentStatus( name: name, - isOperational: status == swagger.ComponentStatus.operational, + isOperational: status == api_enum.ComponentStatus.operational, ); } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document/document_data_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document/document_data_dto.dart index 9d9c898f404a..762698f1aa0d 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document/document_data_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document/document_data_dto.dart @@ -1,6 +1,7 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_repositories/src/dto/document/document_ref_dto.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; +import 'package:collection/collection.dart'; import 'package:json_annotation/json_annotation.dart'; part 'document_data_dto.g.dart'; @@ -76,6 +77,11 @@ final class DocumentDataDto { @JsonSerializable() final class DocumentDataMetadataDto { + @JsonKey( + toJson: DocumentContentType.toJson, + fromJson: DocumentContentType.fromJson, + ) + final DocumentContentType contentType; @JsonKey( toJson: DocumentType.toJson, fromJson: DocumentType.fromJson, @@ -83,51 +89,46 @@ final class DocumentDataMetadataDto { final DocumentType type; final DocumentRefDto selfRef; final DocumentRefDto? ref; - final SecuredDocumentRefDto? refHash; final DocumentRefDto? template; final DocumentRefDto? reply; final String? section; - final DocumentRefDto? brandId; - final DocumentRefDto? campaignId; - final String? electionId; - final DocumentRefDto? categoryId; + final List? collaborators; + final List parameters; final List? authors; DocumentDataMetadataDto({ + required this.contentType, required this.type, required this.selfRef, this.ref, - this.refHash, this.template, this.reply, this.section, - this.brandId, - this.campaignId, - this.electionId, - this.categoryId, + this.collaborators, + this.parameters = const [], this.authors, }); factory DocumentDataMetadataDto.fromJson(Map json) { var migrated = _migrateJson1(json); migrated = _migrateJson2(migrated); + migrated = _migrateJson3(migrated); + migrated = _migrateJson4(migrated); return _$DocumentDataMetadataDtoFromJson(migrated); } DocumentDataMetadataDto.fromModel(DocumentDataMetadata data) : this( + contentType: data.contentType, type: data.type, selfRef: data.selfRef.toDto(), ref: data.ref?.toDto(), - refHash: data.refHash?.toDto(), template: data.template?.toDto(), reply: data.reply?.toDto(), section: data.section, - brandId: data.brandId?.toDto(), - campaignId: data.campaignId?.toDto(), - electionId: data.electionId, - categoryId: data.categoryId?.toDto(), + collaborators: data.collaborators?.map((e) => e.toString()).toList(), + parameters: data.parameters.set.map((e) => e.toDto()).toList(), authors: data.authors?.map((e) => e.toString()).toList(), ); @@ -135,23 +136,23 @@ final class DocumentDataMetadataDto { DocumentDataMetadata toModel() { return DocumentDataMetadata( + contentType: contentType, type: type, selfRef: selfRef.toModel(), ref: ref?.toModel(), - refHash: refHash?.toModel(), template: template?.toModel().toSignedDocumentRef(), reply: reply?.toModel().toSignedDocumentRef(), section: section, - brandId: brandId?.toModel().toSignedDocumentRef(), - campaignId: campaignId?.toModel().toSignedDocumentRef(), - electionId: electionId, - categoryId: categoryId?.toModel().toSignedDocumentRef(), + collaborators: collaborators?.map((e) => CatalystId.fromUri(e.getUri())).toList(), + parameters: DocumentParameters( + parameters.map((e) => e.toModel().toSignedDocumentRef()).toSet(), + ), authors: authors?.map((e) => CatalystId.fromUri(e.getUri())).toList(), ); } static Map _migrateJson1(Map json) { - final modified = Map.from(json); + final modified = Map.of(json); if (modified.containsKey('id') && modified.containsKey('version')) { final id = modified.remove('id') as String; @@ -168,7 +169,7 @@ final class DocumentDataMetadataDto { } static Map _migrateJson2(Map json) { - final modified = Map.from(json); + final modified = Map.of(json); if (modified['brandId'] is String) { final id = modified.remove('brandId') as String; @@ -189,14 +190,41 @@ final class DocumentDataMetadataDto { return modified; } + + /// v0.0.1 -> v0.0.4 spec: https://github.com/input-output-hk/catalyst-libs/pull/341/files#diff-2827956d681587dfd09dc733aca731165ff44812f8322792bf6c4a61cf2d3b85 + static Map _migrateJson3(Map json) { + final parametersKeys = ['brandId', 'campaignId', 'categoryId']; + + if (parametersKeys.none(json.containsKey)) { + return json; + } else { + final modified = Map.of(json); + final parameters = []; + + for (final key in parametersKeys) { + final value = modified.remove(key); + if (value is Map) { + parameters.add(DocumentRefDto.fromJson(value)); + } + } + + modified['parameters'] = parameters.map((e) => e.toJson()).toList(); + return modified; + } + } + + /// Adds missing contentType field. + static Map _migrateJson4(Map json) { + if (json.containsKey('contentType')) { + return json; + } else { + final modified = Map.of(json); + modified['contentType'] = DocumentContentType.toJson(DocumentContentType.json); + return modified; + } + } } extension on DocumentRef { DocumentRefDto toDto() => DocumentRefDto.fromModel(this); } - -extension on SecuredDocumentRef { - SecuredDocumentRefDto toDto() { - return SecuredDocumentRefDto.fromModel(this); - } -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document/document_ref_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document/document_ref_dto.dart index a06df2edec77..33add7c38f96 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document/document_ref_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document/document_ref_dto.dart @@ -1,7 +1,4 @@ -import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; -import 'package:convert/convert.dart' show hex; -import 'package:flutter/foundation.dart'; import 'package:json_annotation/json_annotation.dart'; part 'document_ref_dto.g.dart'; @@ -47,33 +44,3 @@ final class DocumentRefDto { } enum DocumentRefDtoType { signed, draft } - -@JsonSerializable() -final class SecuredDocumentRefDto { - final DocumentRefDto ref; - final String hash; - - const SecuredDocumentRefDto({ - required this.ref, - required this.hash, - }); - - factory SecuredDocumentRefDto.fromJson(Map json) { - return _$SecuredDocumentRefDtoFromJson(json); - } - - SecuredDocumentRefDto.fromModel(SecuredDocumentRef data) - : this( - ref: DocumentRefDto.fromModel(data.ref), - hash: hex.encode(data.hash), - ); - - Map toJson() => _$SecuredDocumentRefDtoToJson(this); - - SecuredDocumentRef toModel() { - return SecuredDocumentRef( - ref: ref.toModel(), - hash: Uint8List.fromList(hexDecode(hash)), - ); - } -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/user/catalyst_id_public_ext.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/user/catalyst_id_public_ext.dart index 76cf8c23c586..44aba751f625 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/user/catalyst_id_public_ext.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/user/catalyst_id_public_ext.dart @@ -1,6 +1,7 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; -import 'package:catalyst_voices_repositories/generated/api/cat_reviews.enums.swagger.dart'; -import 'package:catalyst_voices_repositories/generated/api/cat_reviews.models.swagger.dart'; +import 'package:catalyst_voices_repositories/src/api/models/catalyst_id_public.dart'; +import 'package:catalyst_voices_repositories/src/api/models/catalyst_id_status.dart'; +import 'package:catalyst_voices_repositories/src/api/models/catalyst_rbac_registration_status.dart'; String? _tryDecodeUsername(dynamic source) { if (source is! String) { @@ -16,39 +17,30 @@ String? _tryDecodeUsername(dynamic source) { } } -extension on CatalystIDStatus? { - // inactive = 0 - // email_verified = 1 - // active = 2 - // banned = 3 +extension on CatalystIdStatus? { AccountPublicStatus toModel() { return switch (this) { - null || CatalystIDStatus.swaggerGeneratedUnknown => AccountPublicStatus.unknown, - CatalystIDStatus.value_0 => AccountPublicStatus.verifying, - CatalystIDStatus.value_1 || CatalystIDStatus.value_2 => AccountPublicStatus.verified, - CatalystIDStatus.value_3 => AccountPublicStatus.banned, + null => AccountPublicStatus.unknown, + CatalystIdStatus.inactive => AccountPublicStatus.verifying, + CatalystIdStatus.emailVerified || CatalystIdStatus.active => AccountPublicStatus.verified, + CatalystIdStatus.banned => AccountPublicStatus.banned, }; } } -extension on CatalystRBACRegistrationStatus? { - // initialized = 0 - // not_found = 1 - // volatile = 2 - // persistent = 3 +extension on CatalystRbacRegistrationStatus? { AccountPublicRbacStatus toModel() { return switch (this) { - null || - CatalystRBACRegistrationStatus.swaggerGeneratedUnknown => AccountPublicRbacStatus.unknown, - CatalystRBACRegistrationStatus.value_0 => AccountPublicRbacStatus.initialized, - CatalystRBACRegistrationStatus.value_1 => AccountPublicRbacStatus.notFound, - CatalystRBACRegistrationStatus.value_2 => AccountPublicRbacStatus.volatile, - CatalystRBACRegistrationStatus.value_3 => AccountPublicRbacStatus.persistent, + null => AccountPublicRbacStatus.unknown, + CatalystRbacRegistrationStatus.initialized => AccountPublicRbacStatus.initialized, + CatalystRbacRegistrationStatus.notFound => AccountPublicRbacStatus.notFound, + CatalystRbacRegistrationStatus.volatile => AccountPublicRbacStatus.volatile, + CatalystRbacRegistrationStatus.persistent => AccountPublicRbacStatus.persistent, }; } } -extension CatalystIdPublicExt on CatalystIDPublic { +extension CatalystIdPublicExt on CatalystIdPublic { AccountPublicProfile toModel() { final email = this.email; final decodedEmail = email is String ? email : ''; diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/user/rbac_registration_chain_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/user/rbac_registration_chain_dto.dart index 20928da2bdf9..bb3614dc519b 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/user/rbac_registration_chain_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/user/rbac_registration_chain_dto.dart @@ -1,28 +1,29 @@ import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; -import 'package:catalyst_voices_repositories/generated/api/cat_gateway.models.swagger.dart'; +import 'package:catalyst_voices_repositories/src/api/models/rbac_registration_chain.dart'; +import 'package:catalyst_voices_repositories/src/api/models/rbac_role_data.dart'; import 'package:collection/collection.dart'; /// DTO utils for [RbacRegistrationChain], mostly helpers to decode **complex** /// data types that can't just be json deserialized. extension RbacRegistrationChainExt on RbacRegistrationChain { Set get accountRoles { - final roleNumbers = _roleData.keys.map(int.tryParse); - final accountRoles = roleNumbers.map(AccountRole.maybeFromNumber).nonNulls.toSet(); + final accountRoles = _roles + .map((role) => AccountRole.maybeFromNumber(role.roleId)) + .nonNulls + .toSet(); return accountRoles; } ShelleyAddress get stakeAddress { - final rootRoleData = _roleData[_rootRoleKey] as Map; - final signingKeys = rootRoleData['signing_keys'] as List; - final signingKey = signingKeys.firstOrNull as Map?; + final signingKeys = _rootRoleData.signingKeys; + final signingKey = signingKeys.firstOrNull; if (signingKey == null) { throw ArgumentError.notNull('signingKey'); } - final signingKeyType = signingKey['key_type'] as String; - final signingKeyValue = signingKey['key_value'] as String; + final signingKeyType = signingKey.keyType; if (signingKeyType != RegistrationCertificate.certificateType) { throw ArgumentError.value( @@ -32,24 +33,37 @@ extension RbacRegistrationChainExt on RbacRegistrationChain { ); } - final x509Certificate = _decodeX509Certificate(signingKeyValue); + final signingKeyValue = signingKey.keyValue?.x509; + + if (signingKeyValue == null) { + throw ArgumentError.value( + signingKeyValue, + 'signingKeyValue', + 'Was null for $signingKeyType key (the value was deleted or key type mismatch).', + ); + } + + final x509Certificate = X509Certificate.fromPem(signingKeyValue); return _decodeStakeAddressFromCertificate(x509Certificate); } - Map get _roleData { - final roleData = roles as Map; - if (!roleData.containsKey(_rootRoleKey)) { + List get _roles { + final hasRootRole = roles.any((role) => role.roleId == _rootRoleKey); + if (!hasRootRole) { throw ArgumentError.value( - roleData, - 'roleData', + roles, + 'roles', 'Did not contain mandatory root role.', ); } - return roleData; + return roles; } - String get _rootRoleKey => AccountRole.root.number.toString(); + /// The root role data. If missing [ArgumentError] is thrown. + RbacRoleData get _rootRoleData => _roles.firstWhere((role) => role.roleId == _rootRoleKey); + + int get _rootRoleKey => AccountRole.root.number; ShelleyAddress _decodeStakeAddressFromCertificate( X509Certificate certificate, @@ -74,10 +88,4 @@ extension RbacRegistrationChainExt on RbacRegistrationChain { return CardanoAddressUri.fromString(stakeAddressUri).address; } - - X509Certificate _decodeX509Certificate(String hexString) { - final certificateBytes = hexDecode(hexString); - final derCertificate = X509DerCertificate.fromBytes(bytes: certificateBytes); - return X509Certificate.fromDer(derCertificate); - } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/proposal/proposal_repository.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/proposal/proposal_repository.dart index 19697fea1fbb..c480b7672798 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/proposal/proposal_repository.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/proposal/proposal_repository.dart @@ -45,11 +45,11 @@ abstract interface class ProposalRepository { required ProposalsOrder order, }); - /// Returns [ProposalTemplate] for matching [ref]. + /// Returns [ProposalTemplate] which belongs to [category]. /// - /// Source of data depends whether [ref] is [SignedDocumentRef] or [DraftRef]. - Future getProposalTemplate({ - required DocumentRef ref, + /// Returns null if no matching template is found. + Future getProposalTemplate({ + required DocumentRef category, }); Future publishProposal({ @@ -59,9 +59,7 @@ abstract interface class ProposalRepository { }); Future publishProposalAction({ - required SignedDocumentRef actionRef, - required SignedDocumentRef proposalRef, - required SignedDocumentRef categoryId, + required DocumentDataMetadata metadata, required ProposalSubmissionAction action, required CatalystId catalystId, required CatalystPrivateKey privateKey, @@ -191,12 +189,19 @@ final class ProposalRepositoryImpl implements ProposalRepository { } @override - Future getProposalTemplate({ - required DocumentRef ref, + Future getProposalTemplate({ + required DocumentRef category, }) async { - final proposalDocument = await _documentRepository.getDocumentData(ref: ref); + final document = await _documentRepository.getLatestDocument( + type: DocumentType.proposalTemplate, + category: category, + ); - return _buildProposalTemplate(documentData: proposalDocument); + if (document == null) { + return null; + } + + return _buildProposalTemplate(documentData: document); } @override @@ -207,7 +212,7 @@ final class ProposalRepositoryImpl implements ProposalRepository { }) async { final signedDocument = await _signedDocumentManager.signDocument( SignedDocumentJsonPayload(document.content.data), - metadata: _createProposalMetadata(document.metadata), + metadata: document.metadata, catalystId: catalystId, privateKey: privateKey, ); @@ -217,9 +222,7 @@ final class ProposalRepositoryImpl implements ProposalRepository { @override Future publishProposalAction({ - required SignedDocumentRef actionRef, - required SignedDocumentRef proposalRef, - required SignedDocumentRef categoryId, + required DocumentDataMetadata metadata, required ProposalSubmissionAction action, required CatalystId catalystId, required CatalystPrivateKey privateKey, @@ -227,16 +230,10 @@ final class ProposalRepositoryImpl implements ProposalRepository { final dto = ProposalSubmissionActionDocumentDto( action: ProposalSubmissionActionDto.fromModel(action), ); + final signedDocument = await _signedDocumentManager.signDocument( SignedDocumentJsonPayload(dto.toJson()), - metadata: SignedDocumentMetadata( - contentType: SignedDocumentContentType.json, - documentType: DocumentType.proposalActionDocument, - id: actionRef.id, - ver: actionRef.version, - ref: SignedDocumentMetadataRef.fromDocumentRef(proposalRef), - categoryId: SignedDocumentMetadataRef.fromDocumentRef(categoryId), - ), + metadata: metadata, catalystId: catalystId, privateKey: privateKey, ); @@ -410,7 +407,7 @@ final class ProposalRepositoryImpl implements ProposalRepository { final metadata = ProposalMetadata( selfRef: documentData.metadata.selfRef, templateRef: documentData.metadata.template!, - categoryId: documentData.metadata.categoryId!, + parameters: documentData.metadata.parameters, authors: documentData.metadata.authors ?? [], ); @@ -435,6 +432,7 @@ final class ProposalRepositoryImpl implements ProposalRepository { final metadata = ProposalTemplateMetadata( selfRef: documentData.metadata.selfRef, + parameters: documentData.metadata.parameters, ); final contentData = documentData.content.data; @@ -446,22 +444,6 @@ final class ProposalRepositoryImpl implements ProposalRepository { ); } - SignedDocumentMetadata _createProposalMetadata( - DocumentDataMetadata metadata, - ) { - final template = metadata.template; - final categoryId = metadata.categoryId; - - return SignedDocumentMetadata( - contentType: SignedDocumentContentType.json, - documentType: DocumentType.proposalDocument, - id: metadata.id, - ver: metadata.version, - template: template == null ? null : SignedDocumentMetadataRef.fromDocumentRef(template), - categoryId: categoryId == null ? null : SignedDocumentMetadataRef.fromDocumentRef(categoryId), - ); - } - ProposalPublish? _getProposalPublish({ required DocumentRef ref, required ProposalSubmissionAction? action, diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/signed_document/signed_document_manager.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/signed_document/signed_document_manager.dart index dfd7e5b22d11..baed96ac8803 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/signed_document/signed_document_manager.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/signed_document/signed_document_manager.dart @@ -1,5 +1,6 @@ import 'package:catalyst_compression/catalyst_compression.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:catalyst_voices_repositories/src/document/exception/document_exception.dart'; import 'package:catalyst_voices_repositories/src/signed_document/signed_document_manager_impl.dart'; import 'package:flutter/foundation.dart'; @@ -16,6 +17,9 @@ abstract interface class SignedDocumentManager { /// /// The implementation of this method must be able to understand the [bytes] /// that are obtained from the [SignedDocument.toBytes] method. + /// + /// Throws [DocumentMetadataMalformedException] in case of any required fields + /// missing. Future parseDocument(Uint8List bytes); /// Signs the [document] with a single [privateKey]. @@ -24,7 +28,7 @@ abstract interface class SignedDocumentManager { /// so that it's easier to identify who signed it. Future signDocument( SignedDocumentPayload document, { - required SignedDocumentMetadata metadata, + required DocumentDataMetadata metadata, required CatalystId catalystId, required CatalystPrivateKey privateKey, }); diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/signed_document/signed_document_manager_impl.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/signed_document/signed_document_manager_impl.dart index 36c0b0ca2af0..4b1b90b386bb 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/signed_document/signed_document_manager_impl.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/signed_document/signed_document_manager_impl.dart @@ -1,15 +1,13 @@ -import 'dart:convert'; import 'dart:typed_data'; import 'package:catalyst_compression/catalyst_compression.dart'; import 'package:catalyst_cose/catalyst_cose.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_repositories/src/signed_document/signed_document_manager.dart'; +import 'package:catalyst_voices_repositories/src/signed_document/signed_document_mapper.dart'; import 'package:cbor/cbor.dart'; import 'package:equatable/equatable.dart'; -const _brotliEncoding = StringValue(CoseValues.brotliContentEncoding); - final class SignedDocumentManagerImpl implements SignedDocumentManager { final CatalystCompressor brotli; final CatalystCompressor zstd; @@ -22,37 +20,24 @@ final class SignedDocumentManagerImpl implements SignedDocumentManager { @override Future parseDocument(Uint8List bytes) async { final coseSign = CoseSign.fromCbor(cbor.decode(bytes)); - final metadata = _SignedDocumentMetadataExt.fromCose( - protectedHeaders: coseSign.protectedHeaders, - unprotectedHeaders: coseSign.unprotectedHeaders, - ); - final payloadBytes = await _brotliDecompressPayload(coseSign); - final payload = SignedDocumentPayload.fromBytes( - payloadBytes, - contentType: metadata.contentType, - ); + final rawPayload = await _decompressPayload(coseSign); - return _CoseSignedDocument( - coseSign: coseSign, - payload: payload, - metadata: metadata, - signers: coseSign.signatures.map((e) => e.decodeCatalystId()).nonNulls.toList(), - ); + return _CoseSignedDocument.fromCose(coseSign, rawPayload: rawPayload); } @override Future signDocument( SignedDocumentPayload document, { - required SignedDocumentMetadata metadata, + required DocumentDataMetadata metadata, required CatalystId catalystId, required CatalystPrivateKey privateKey, }) async { - final compressedPayload = await _brotliCompressPayload(document.toBytes()); + final compressedPayload = await _compressPayload(document.toBytes()); final coseSign = await CoseSign.sign( - protectedHeaders: metadata.asCoseProtectedHeaders, - unprotectedHeaders: metadata.asCoseUnprotectedHeaders, + protectedHeaders: SignedDocumentMapper.buildCoseProtectedHeaders(metadata), + unprotectedHeaders: const CoseHeaders.unprotected(), payload: compressedPayload, signers: [_CatalystSigner(catalystId, privateKey)], ); @@ -65,13 +50,13 @@ final class SignedDocumentManagerImpl implements SignedDocumentManager { ); } - Future _brotliCompressPayload(Uint8List payload) async { + Future _compressPayload(Uint8List payload) async { final compressed = await brotli.compress(payload); return Uint8List.fromList(compressed); } - Future _brotliDecompressPayload(CoseSign coseSign) async { - if (coseSign.protectedHeaders.contentEncoding == _brotliEncoding) { + Future _decompressPayload(CoseSign coseSign) async { + if (coseSign.protectedHeaders.contentEncoding == CoseHttpContentEncoding.brotli) { final decompressed = await brotli.decompress(coseSign.payload); return Uint8List.fromList(decompressed); } else { @@ -90,12 +75,11 @@ final class _CatalystSigner implements CatalystCoseSigner { ); @override - StringOrInt? get alg => null; + CoseStringOrInt? get alg => null; @override - Future get kid async { - final string = _catalystId.toUri().toString(); - return utf8.encode(string); + Future get kid async { + return CatalystIdKid.fromString(_catalystId.toString()); } @override @@ -111,9 +95,8 @@ final class _CatalystVerifier implements CatalystCoseVerifier { const _CatalystVerifier(this._catalystId); @override - Future get kid async { - final string = _catalystId.toUri().toString(); - return utf8.encode(string); + Future get kid async { + return CatalystIdKid.fromString(_catalystId.toString()); } @override @@ -135,7 +118,7 @@ final class _CoseSignedDocument with EquatableMixin implements SignedDocument { final SignedDocumentPayload payload; @override - final SignedDocumentMetadata metadata; + final DocumentDataMetadata metadata; @override final List signers; @@ -147,6 +130,34 @@ final class _CoseSignedDocument with EquatableMixin implements SignedDocument { required this.signers, }) : _coseSign = coseSign; + factory _CoseSignedDocument.fromCose( + CoseSign coseSign, { + required Uint8List rawPayload, + }) { + final signers = coseSign.signatures + .map((e) => e.protectedHeaders.kid) + .nonNulls + .cast() + .toList(); + + final metadata = SignedDocumentMapper.buildMetadata( + protectedHeaders: coseSign.protectedHeaders, + unprotectedHeaders: coseSign.unprotectedHeaders, + signers: signers, + ); + final payload = SignedDocumentPayload.fromBytes( + rawPayload, + contentType: metadata.contentType, + ); + + return _CoseSignedDocument( + coseSign: coseSign, + payload: payload, + metadata: metadata, + signers: metadata.signers ?? [], + ); + } + @override List get props => [_coseSign, payload, metadata, signers]; @@ -161,132 +172,3 @@ final class _CoseSignedDocument with EquatableMixin implements SignedDocument { return _coseSign.verify(verifier: _CatalystVerifier(catalystId)); } } - -extension _CoseSignatureExt on CoseSignature { - CatalystId? decodeCatalystId() { - final kid = protectedHeaders.kid; - if (kid == null) return null; - - final string = utf8.decode(kid); - final uri = Uri.tryParse(string); - if (uri == null) return null; - - return CatalystId.fromUri(uri); - } -} - -extension _SignedDocumentContentTypeExt on SignedDocumentContentType { - /// Maps the [SignedDocumentContentType] into COSE representation. - StringOrInt? get asCose { - switch (this) { - case SignedDocumentContentType.json: - return const IntValue(CoseValues.jsonContentType); - case SignedDocumentContentType.unknown: - return null; - } - } - - static SignedDocumentContentType fromCose(StringOrInt? contentType) { - switch (contentType) { - case IntValue(): - return switch (contentType.value) { - CoseValues.jsonContentType => SignedDocumentContentType.json, - _ => SignedDocumentContentType.unknown, - }; - case StringValue(): - case null: - return SignedDocumentContentType.unknown; - } - } -} - -extension _SignedDocumentMetadataExt on SignedDocumentMetadata { - CoseHeaders get asCoseProtectedHeaders { - return CoseHeaders.protected( - contentType: contentType.asCose, - contentEncoding: _brotliEncoding, - type: documentType.uuid.asUuid, - id: id?.asUuid, - ver: ver?.asUuid, - ref: ref?.asCose, - refHash: refHash?.asCose, - template: template?.asCose, - reply: reply?.asCose, - section: section, - collabs: collabs, - brandId: brandId?.asCose, - campaignId: campaignId?.asCose, - electionId: electionId, - categoryId: categoryId?.asCose, - ); - } - - CoseHeaders get asCoseUnprotectedHeaders { - return const CoseHeaders.unprotected(); - } - - static SignedDocumentMetadata fromCose({ - required CoseHeaders protectedHeaders, - required CoseHeaders unprotectedHeaders, - }) { - final type = protectedHeaders.type?.value; - final ref = protectedHeaders.ref; - final refHash = protectedHeaders.refHash; - final template = protectedHeaders.template; - final reply = protectedHeaders.reply; - final brandId = protectedHeaders.brandId; - final campaignId = protectedHeaders.campaignId; - final categoryId = protectedHeaders.categoryId; - - return SignedDocumentMetadata( - contentType: _SignedDocumentContentTypeExt.fromCose( - protectedHeaders.contentType, - ), - documentType: type == null ? DocumentType.unknown : DocumentType.fromJson(type), - id: protectedHeaders.id?.value, - ver: protectedHeaders.ver?.value, - ref: ref == null ? null : _SignedDocumentMetadataRefExt.fromCose(ref), - refHash: refHash == null ? null : _SignedDocumentMetadataRefHashExt.fromCose(refHash), - template: template == null ? null : _SignedDocumentMetadataRefExt.fromCose(template), - reply: reply == null ? null : _SignedDocumentMetadataRefExt.fromCose(reply), - section: protectedHeaders.section, - collabs: protectedHeaders.collabs, - brandId: brandId == null ? null : _SignedDocumentMetadataRefExt.fromCose(brandId), - campaignId: campaignId == null ? null : _SignedDocumentMetadataRefExt.fromCose(campaignId), - electionId: protectedHeaders.electionId, - categoryId: categoryId == null ? null : _SignedDocumentMetadataRefExt.fromCose(categoryId), - ); - } -} - -extension _SignedDocumentMetadataRefExt on SignedDocumentMetadataRef { - ReferenceUuid get asCose => ReferenceUuid( - id: id.asUuid, - ver: ver?.asUuid, - ); - - static SignedDocumentMetadataRef fromCose(ReferenceUuid ref) { - return SignedDocumentMetadataRef( - id: ref.id.value, - ver: ref.ver?.value, - ); - } -} - -extension _SignedDocumentMetadataRefHashExt on SignedDocumentMetadataRefHash { - ReferenceUuidHash get asCose => ReferenceUuidHash( - ref: ref.asCose, - hash: hash, - ); - - static SignedDocumentMetadataRefHash fromCose(ReferenceUuidHash ref) { - return SignedDocumentMetadataRefHash( - ref: _SignedDocumentMetadataRefExt.fromCose(ref.ref), - hash: ref.hash, - ); - } -} - -extension _UuidExt on String { - Uuid get asUuid => Uuid(this); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/signed_document/signed_document_mapper.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/signed_document/signed_document_mapper.dart new file mode 100644 index 000000000000..3d0da6ef7064 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/signed_document/signed_document_mapper.dart @@ -0,0 +1,155 @@ +import 'dart:convert'; + +import 'package:catalyst_cose/catalyst_cose.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:catalyst_voices_repositories/catalyst_voices_repositories.dart'; + +final class SignedDocumentMapper { + SignedDocumentMapper._(); + + /// Maps domain [DocumentDataMetadata] into [CoseHeaders]. + /// + /// Unprotected headers are not permitted by the specification, + /// so this method focuses strictly on the Protected Headers. + static CoseHeaders buildCoseProtectedHeaders(DocumentDataMetadata metadata) { + return CoseHeaders.protected( + mediaType: _mapContentTypeToCose(metadata.contentType), + contentEncoding: CoseHttpContentEncoding.brotli, + type: CoseDocumentType(metadata.type.uuid.asUuidV4), + id: CoseDocumentId(metadata.id.asUuidV7), + ver: CoseDocumentVer(metadata.version.asUuidV7), + ref: _mapRefToCoseList(metadata.ref), + template: _mapRefToCoseList(metadata.template), + reply: _mapRefToCoseList(metadata.reply), + section: metadata.section != null ? CoseSectionRef(CoseJsonPointer(metadata.section!)) : null, + collaborators: _mapCollaboratorsToCose(metadata.collaborators), + parameters: _mapRefsToCose(metadata.parameters.set.toList()), + ); + } + + /// Maps COSE headers and signers back into domain [DocumentDataMetadata]. + static DocumentDataMetadata buildMetadata({ + required CoseHeaders protectedHeaders, + required CoseHeaders unprotectedHeaders, + required List signers, + }) { + // Validation: ID and Version are required fields. + final typeStr = protectedHeaders.type?.value.format(); + final idStr = protectedHeaders.id?.value.format(); + final verStr = protectedHeaders.ver?.value.format(); + + final malformedReasons = []; + if (idStr == null) malformedReasons.add('id is missing'); + if (verStr == null) malformedReasons.add('version is missing'); + + if (malformedReasons.isNotEmpty) { + throw DocumentMetadataMalformedException(reasons: malformedReasons); + } + + return DocumentDataMetadata( + contentType: _mapContentTypeFromCose(protectedHeaders.mediaType), + type: typeStr == null ? DocumentType.unknown : DocumentType.fromJson(typeStr), + selfRef: SignedDocumentRef(id: idStr!, version: verStr), + // The domain model expects single references for these fields, + // even though COSE supports lists. + ref: _mapRefsFromCose(protectedHeaders.ref).firstOrNull, + template: _mapRefsFromCose(protectedHeaders.template).firstOrNull, + reply: _mapRefsFromCose(protectedHeaders.reply).firstOrNull, + section: protectedHeaders.section?.value.text, + collaborators: _mapCollaboratorsFromCose(protectedHeaders.collaborators), + parameters: DocumentParameters(_mapRefsFromCose(protectedHeaders.parameters).toSet()), + authors: _mapSignersFromCose(signers), + ); + } + + static CatalystId? _catalystIdFromKid(CatalystIdKid kid) { + try { + final string = utf8.decode(kid.bytes); + final uri = Uri.tryParse(string); + if (uri == null) return null; + return CatalystId.fromUri(uri); + } catch (_) { + return null; + } + } + + static List? _mapCollaboratorsFromCose( + CoseCollaborators? collaborators, + ) { + if (collaborators == null) return null; + return _mapSignersFromCose(collaborators.list); + } + + static CoseCollaborators? _mapCollaboratorsToCose( + List? collaborators, + ) { + if (collaborators == null) return null; + return CoseCollaborators( + collaborators.map((e) => CatalystIdKid.fromString(e.toString())).toList(), + ); + } + + static DocumentContentType _mapContentTypeFromCose(CoseMediaType? type) { + return switch (type) { + CoseMediaType.json => DocumentContentType.json, + // Note: Spec supports Markdown/HTML, but Domain model currently treats them as unknown. + CoseMediaType.cbor || + CoseMediaType.cddl || + CoseMediaType.schemaJson || + CoseMediaType.css || + CoseMediaType.cssHandlebars || + CoseMediaType.html || + CoseMediaType.htmlHandlebars || + CoseMediaType.markdown || + CoseMediaType.markdownHandlebars || + CoseMediaType.plain || + CoseMediaType.plainHandlebars || + null => DocumentContentType.unknown, + }; + } + + static CoseMediaType? _mapContentTypeToCose(DocumentContentType type) { + return switch (type) { + DocumentContentType.json => CoseMediaType.json, + DocumentContentType.unknown => null, + }; + } + + static List _mapRefsFromCose(CoseDocumentRefs? coseRefs) { + if (coseRefs == null) return const []; + return coseRefs.refs.map((e) { + return SignedDocumentRef( + id: e.documentId.format(), + version: e.documentVer.format(), + ); + }).toList(); + } + + static CoseDocumentRefs? _mapRefsToCose(List refs) { + if (refs.isEmpty) return null; + return CoseDocumentRefs(refs.map(_mapRefToCose).toList()); + } + + static CoseDocumentRef _mapRefToCose(DocumentRef ref) { + return CoseDocumentRef.optional( + documentId: ref.id.asUuidV7, + documentVer: (ref.version ?? ref.id).asUuidV7, + documentLocator: CoseDocumentLocator.fallback(), + ); + } + + static CoseDocumentRefs? _mapRefToCoseList(DocumentRef? ref) { + if (ref == null) return null; + return CoseDocumentRefs([_mapRefToCose(ref)]); + } + + static List _mapSignersFromCose(List kids) { + return kids.map(_catalystIdFromKid).nonNulls.toList(); + } +} + +extension _UuidStringExt on String { + CoseUuidV4 get asUuidV4 => CoseUuidV4.fromString(this); + + CoseUuidV7 get asUuidV7 => CoseUuidV7.fromString(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/system_status/system_status_repository.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/system_status/system_status_repository.dart index 96f9abe87efd..c216b523ff46 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/system_status/system_status_repository.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/system_status/system_status_repository.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_repositories/src/api/api.dart'; -import 'package:catalyst_voices_repositories/src/common/response_mapper.dart'; +import 'package:catalyst_voices_repositories/src/common/future_response_mapper.dart'; import 'package:catalyst_voices_repositories/src/dto/component_status/component_ext.dart'; import 'package:rxdart/rxdart.dart'; @@ -21,7 +21,7 @@ final class SystemStatusRepositoryImpl implements SystemStatusRepository { @override Future> getComponentStatuses() { - return _apiServices.status.v2ComponentsJsonGet().successBodyOrThrow().then( + return _apiServices.status.componentStatuses().successBodyOrThrow().then( (e) => e.components.map((c) => c.toModel()).toList(), ); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/user/user_repository.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/user/user_repository.dart index d664ca26ab76..192ea7e819d1 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/user/user_repository.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/user/user_repository.dart @@ -1,11 +1,11 @@ import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_repositories/catalyst_voices_repositories.dart'; -import 'package:catalyst_voices_repositories/generated/api/cat_gateway.swagger.dart' - show RbacRegistrationChain; -import 'package:catalyst_voices_repositories/generated/api/cat_reviews.models.swagger.dart'; +import 'package:catalyst_voices_repositories/src/api/models/catalyst_id_create.dart'; +import 'package:catalyst_voices_repositories/src/api/models/catalyst_id_public.dart'; +import 'package:catalyst_voices_repositories/src/api/models/rbac_registration_chain.dart'; +import 'package:catalyst_voices_repositories/src/common/future_response_mapper.dart'; import 'package:catalyst_voices_repositories/src/common/rbac_token_ext.dart'; -import 'package:catalyst_voices_repositories/src/common/response_mapper.dart'; import 'package:catalyst_voices_repositories/src/dto/user/catalyst_id_public_ext.dart'; import 'package:catalyst_voices_repositories/src/dto/user/rbac_registration_chain_dto.dart'; import 'package:catalyst_voices_repositories/src/dto/user/user_dto.dart'; @@ -80,7 +80,7 @@ final class UserRepositoryImpl implements UserRepository { @override Future getRbacRegistration({CatalystId? catalystId}) { return _apiServices.gateway - .apiV1RbacRegistrationGet(lookup: catalystId?.toUri().toStringWithoutScheme()) + .rbacRegistration(lookup: catalystId?.toUri().toStringWithoutScheme()) .successBodyOrThrow(); } @@ -102,16 +102,14 @@ final class UserRepositoryImpl implements UserRepository { required String email, }) { return _apiServices.reviews - .apiCatalystIdsMePost( - body: CatalystIDCreate( + .upsertPublicProfile( + body: CatalystIdCreate( catalystIdUri: catalystId.toUri().toStringWithoutScheme(), email: email, ), ) .successBodyOrThrow() - .onError( - (error, stackTrace) => throw const EmailAlreadyUsedException(), - ) + .onError((_, _) => throw const EmailAlreadyUsedException()) .then((value) => value.toModel()); } @@ -149,9 +147,9 @@ final class UserRepositoryImpl implements UserRepository { /// account if [token] is not specified. Future _getAccountPublicProfile({RbacToken? token}) async { return _apiServices.reviews - .apiCatalystIdsMeGet(authorization: token?.authHeader()) + .getPublicProfile(authorization: token?.authHeader()) .successBodyOrThrow() - .then((value) => value) + .then((value) => value) .onError((error, stackTrace) => null) // Review module returns 401 Registration not found for the auth token .onError((error, stackTrace) => null) diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/wallet/blockchain_repository.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/wallet/blockchain_repository.dart index aa6f1c9e58b0..247d97e74426 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/wallet/blockchain_repository.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/wallet/blockchain_repository.dart @@ -1,9 +1,9 @@ import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_repositories/src/api/api_services.dart'; +import 'package:catalyst_voices_repositories/src/common/future_response_mapper.dart'; import 'package:catalyst_voices_repositories/src/common/rbac_token_ext.dart'; -import 'package:catalyst_voices_repositories/src/common/response_mapper.dart'; -import 'package:catalyst_voices_repositories/src/dto/blockchain/network_id_dto.dart'; +import 'package:catalyst_voices_repositories/src/dto/blockchain/network_id_ext.dart'; // TODO(dt-iohk): move wallet related repository code here // ignore: one_member_abstracts @@ -29,9 +29,9 @@ final class BlockchainRepositoryImpl implements BlockchainRepository { RbacToken? rbacToken, }) { return _apiServices.gateway - .apiV1CardanoAssetsStakeAddressGet( + .stakeAssets( stakeAddress: stakeAddress.toBech32(), - network: networkId.toDto(), + network: networkId.toApiValue(), authorization: rbacToken?.authHeader(), ) .successBodyOrThrow() diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/openapi/cat-gateway.json b/catalyst_voices/packages/internal/catalyst_voices_repositories/openapi/cat-gateway.json deleted file mode 100644 index 23d5c945373f..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/openapi/cat-gateway.json +++ /dev/null @@ -1,5995 +0,0 @@ -{ - "openapi": "3.0.0", - "info": { - "title": "Catalyst Gateway", - "description": "# Catalyst Gateway API.\n\nThe Catalyst Gateway API provides realtime data for all prior, current and future Catalyst Voices voting events.\n\n⚠️ Warning: This API is currently unstable and may change at any time without prior notice. Backwards compatibility is not guaranteed, and future versions may introduce breaking changes. It is intended for experimental or internal use only. Use at your own risk.\n", - "version": "0.3.0", - "termsOfService": "https://github.com/input-output-hk/catalyst-voices/blob/main/CODE_OF_CONDUCT.md", - "contact": { - "name": "Project Catalyst Team", - "url": "https://projectcatalyst.io", - "email": "contact@projectcatalyst.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://www.apache.org/licenses/LICENSE-2.0" - } - }, - "servers": [ - { - "url": "http://MacBook-Pro-Alexey.local:3030", - "description": "Server at localhost name." - }, - { - "url": "http://[fe80::c8f:3689:db77:cbdb]:3030", - "description": "Server at local IPv6 address." - }, - { - "url": "http://192.168.0.102:3030", - "description": "Server at local IPv4 address." - } - ], - "tags": [ - { - "name": "Cardano", - "description": "General Cardano Blockchain Information." - }, - { - "name": "Config", - "description": "Service Configuration and Status." - }, - { - "name": "Documents", - "description": "Signed Document endpoints" - }, - { - "name": "Health", - "description": "Service Health and Readiness." - } - ], - "paths": { - "/api/v1/health/started": { - "get": { - "tags": [ - "Health" - ], - "summary": "Service Started", - "description": "This endpoint is used to determine if the service has started properly\nand is able to serve requests.\n\n## Note\n\n*This endpoint is for internal use of the service deployment infrastructure.\nIt may not be exposed publicly.*", - "responses": { - "204": { - "description": "## No Content\n\nService is Started and can serve requests.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "412": { - "description": "## Precondition Failed\n\nThe client has not sent valid data in its request, headers, parameters or body.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PreconditionFailed" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "429": { - "description": "## Too Many Requests\n\nThe client has sent too many requests in a given amount of time.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TooManyRequests" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - }, - "RETRY-AFTER": { - "required": true, - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - }, - "503": { - "description": "## Service Unavailable\n\nThe service is not available, try again later.\n\n*This is returned when the service either has not started,\nor has become unavailable.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ServiceUnavailable" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RETRY-AFTER": { - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - }, - "400": { - "description": "## Bad Request\n\nThe client has not sent valid request, could be an invalid HTTP in general or\nprovided not correct headers, path or query arguments.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "500": { - "description": "## Internal Server Error.\n\nAn internal server error occurred.\n\n*The contents of this response should be reported to the projects issue tracker.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/InternalServerError" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - } - } - }, - "431": { - "description": "## Request Header Fields Too Large\n\nThe client sent a request with too large header fields.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "414": { - "description": "## URI Too Long\n\nThe client sent a request with the URI is longer than the server is willing to\ninterpret", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "401": { - "description": "## Unauthorized\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Unauthorized" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "403": { - "description": "## Forbidden\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Forbidden" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - } - }, - "security": [ - { - "NoAuthorization": [] - } - ], - "operationId": "healthStarted" - } - }, - "/api/v1/health/ready": { - "get": { - "tags": [ - "Health" - ], - "summary": "Service Ready", - "description": "This endpoint is used to determine if the service is ready and able to serve\nrequests.\n\n## Note\n\n*This endpoint is for internal use of the service deployment infrastructure.\nIt may not be exposed publicly.*", - "responses": { - "204": { - "description": "## No Content\n\nService is Started and can serve requests.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "403": { - "description": "## Forbidden\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Forbidden" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "400": { - "description": "## Bad Request\n\nThe client has not sent valid request, could be an invalid HTTP in general or\nprovided not correct headers, path or query arguments.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "500": { - "description": "## Internal Server Error.\n\nAn internal server error occurred.\n\n*The contents of this response should be reported to the projects issue tracker.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/InternalServerError" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - } - } - }, - "401": { - "description": "## Unauthorized\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Unauthorized" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "431": { - "description": "## Request Header Fields Too Large\n\nThe client sent a request with too large header fields.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "503": { - "description": "## Service Unavailable\n\nThe service is not available, try again later.\n\n*This is returned when the service either has not started,\nor has become unavailable.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ServiceUnavailable" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RETRY-AFTER": { - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - }, - "412": { - "description": "## Precondition Failed\n\nThe client has not sent valid data in its request, headers, parameters or body.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PreconditionFailed" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "414": { - "description": "## URI Too Long\n\nThe client sent a request with the URI is longer than the server is willing to\ninterpret", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "429": { - "description": "## Too Many Requests\n\nThe client has sent too many requests in a given amount of time.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TooManyRequests" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - }, - "RETRY-AFTER": { - "required": true, - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - } - }, - "security": [ - { - "NoAuthorization": [] - } - ], - "operationId": "healthReady" - } - }, - "/api/v1/health/live": { - "get": { - "tags": [ - "Health" - ], - "summary": "Service Live", - "description": "This endpoint is used to determine if the service is live.\n\n## Note\n\n*This endpoint is for internal use of the service deployment infrastructure.\nIt may not be exposed publicly. Refer to []*", - "responses": { - "503": { - "description": "## Service Unavailable\n\nThe service is not available, try again later.\n\n*This is returned when the service either has not started,\nor has become unavailable.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ServiceUnavailable" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RETRY-AFTER": { - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - }, - "403": { - "description": "## Forbidden\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Forbidden" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "412": { - "description": "## Precondition Failed\n\nThe client has not sent valid data in its request, headers, parameters or body.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PreconditionFailed" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "204": { - "description": "## No Content\n\nService is OK and can keep running.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "500": { - "description": "## Internal Server Error.\n\nAn internal server error occurred.\n\n*The contents of this response should be reported to the projects issue tracker.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/InternalServerError" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - } - } - }, - "401": { - "description": "## Unauthorized\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Unauthorized" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "431": { - "description": "## Request Header Fields Too Large\n\nThe client sent a request with too large header fields.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "414": { - "description": "## URI Too Long\n\nThe client sent a request with the URI is longer than the server is willing to\ninterpret", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "429": { - "description": "## Too Many Requests\n\nThe client has sent too many requests in a given amount of time.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TooManyRequests" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - }, - "RETRY-AFTER": { - "required": true, - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - }, - "400": { - "description": "## Bad Request\n\nThe client has not sent valid request, could be an invalid HTTP in general or\nprovided not correct headers, path or query arguments.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - } - }, - "security": [ - { - "NoAuthorization": [] - } - ], - "operationId": "healthLive" - } - }, - "/api/v1/rbac/registration": { - "get": { - "tags": [ - "Cardano" - ], - "summary": "Get RBAC registrations", - "description": "This endpoint returns RBAC registrations by provided auth Catalyst Id credentials\nor by the `lookup` argument if provided.", - "parameters": [ - { - "name": "lookup", - "schema": { - "type": "string", - "format": "catalyst_id|cardano:cip19-address", - "title": "Catalyst Id or Stake Address.", - "description": "Restrict the query to this Catalyst Id or Stake Address. If neither are defined, the auth token is used.", - "example": "stake_test1uqehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gssrtvn", - "pattern": "^(.+\\/[A-Za-z0-9_-]{43})|(^(stake|stake_test)1[a,c-h,j-n,p-z,0,2-9]{53}$)$" - }, - "in": "query", - "description": "Stake address or Catalyst ID to get the RBAC registration for.", - "required": false, - "deprecated": false, - "explode": true - } - ], - "responses": { - "431": { - "description": "## Request Header Fields Too Large\n\nThe client sent a request with too large header fields.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "422": { - "description": "Response for unprocessable content.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/RbacUnprocessableContent" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "403": { - "description": "## Forbidden\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Forbidden" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "412": { - "description": "## Precondition Failed\n\nThe client has not sent valid data in its request, headers, parameters or body.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PreconditionFailed" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "200": { - "description": "## Ok\n\nSuccess returns a list of registration transaction ids.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/RbacRegistrationChain" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "404": { - "description": "No valid registration.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "400": { - "description": "## Bad Request\n\nThe client has not sent valid request, could be an invalid HTTP in general or\nprovided not correct headers, path or query arguments.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "429": { - "description": "## Too Many Requests\n\nThe client has sent too many requests in a given amount of time.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TooManyRequests" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - }, - "RETRY-AFTER": { - "required": true, - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - }, - "401": { - "description": "## Unauthorized\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Unauthorized" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "414": { - "description": "## URI Too Long\n\nThe client sent a request with the URI is longer than the server is willing to\ninterpret", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "500": { - "description": "## Internal Server Error.\n\nAn internal server error occurred.\n\n*The contents of this response should be reported to the projects issue tracker.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/InternalServerError" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - } - } - }, - "503": { - "description": "## Service Unavailable\n\nThe service is not available, try again later.\n\n*This is returned when the service either has not started,\nor has become unavailable.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ServiceUnavailable" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RETRY-AFTER": { - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - } - }, - "security": [ - { - "CatalystRBACSecurityScheme": [] - }, - { - "NoAuthorization": [] - } - ], - "operationId": "rbacRegistrations" - } - }, - "/api/v1/cardano/assets/{stake_address}": { - "get": { - "tags": [ - "Cardano" - ], - "summary": "Get staked assets.", - "description": "This endpoint returns the total Cardano's staked assets to the corresponded\nuser's stake address.", - "parameters": [ - { - "name": "stake_address", - "schema": { - "type": "string", - "format": "cardano:cip19-address", - "title": "Cardano stake address", - "description": "Cardano stake address, also known as a reward address.", - "externalDocs": { - "url": "https://cips.cardano.org/cip/CIP-19", - "description": "CIP-19 - Cardano Addresses" - }, - "example": "stake_test1uqehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gssrtvn", - "maxLength": 64, - "minLength": 59, - "pattern": "^(stake|stake_test)1[a,c-h,j-n,p-z,0,2-9]{53}$" - }, - "in": "path", - "description": "The stake address of the user.\nShould be a valid Bech32 encoded address followed by the https://cips.cardano.org/cip/CIP-19/#stake-addresses.", - "required": true, - "deprecated": false, - "explode": true - }, - { - "name": "network", - "schema": { - "$ref": "#/components/schemas/Network" - }, - "in": "query", - "description": "Cardano network type.\nIf omitted network type is identified from the stake address.\nIf specified it must be correspondent to the network type encoded in the stake\naddress.\nAs `preprod` and `preview` network types in the stake address encoded as a\n`testnet`, to specify `preprod` or `preview` network type use this\nquery parameter.", - "required": false, - "deprecated": false, - "explode": true - }, - { - "name": "asat", - "schema": { - "type": "string", - "format": "slot or time", - "title": "As At this Time OR Slot.", - "description": "Restrict the query to this time.\nTime can be represented as either the blockchains slot number, \nor the number of seconds since midnight 1970, UTC.\n\nIf this parameter is not defined, the query will retrieve data up to the current time.", - "example": "TIME:1730861339", - "maxLength": 25, - "minLength": 6, - "pattern": "^(SLOT|TIME):(\\d{1,20})$" - }, - "in": "query", - "description": "A time point at which the assets should be calculated.\nIf omitted latest slot number is used.", - "required": false, - "deprecated": false, - "explode": true - } - ], - "responses": { - "500": { - "description": "## Internal Server Error.\n\nAn internal server error occurred.\n\n*The contents of this response should be reported to the projects issue tracker.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/InternalServerError" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - } - } - }, - "431": { - "description": "## Request Header Fields Too Large\n\nThe client sent a request with too large header fields.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "503": { - "description": "## Service Unavailable\n\nThe service is not available, try again later.\n\n*This is returned when the service either has not started,\nor has become unavailable.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ServiceUnavailable" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RETRY-AFTER": { - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - }, - "400": { - "description": "## Bad Request\n\nThe client has not sent valid request, could be an invalid HTTP in general or\nprovided not correct headers, path or query arguments.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "414": { - "description": "## URI Too Long\n\nThe client sent a request with the URI is longer than the server is willing to\ninterpret", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "200": { - "description": "## Ok\n\nThe amount of ADA staked by the queried stake address, as at the indicated slot.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/FullStakeInfo" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "403": { - "description": "## Forbidden\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Forbidden" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "401": { - "description": "## Unauthorized\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Unauthorized" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "412": { - "description": "## Precondition Failed\n\nThe client has not sent valid data in its request, headers, parameters or body.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PreconditionFailed" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "404": { - "description": "## Not Found\n\nThe queried stake address was not found at the requested slot number.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "429": { - "description": "## Too Many Requests\n\nThe client has sent too many requests in a given amount of time.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TooManyRequests" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - }, - "RETRY-AFTER": { - "required": true, - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - } - }, - "security": [ - { - "CatalystRBACSecurityScheme": [] - }, - { - "NoAuthorization": [] - } - ], - "operationId": "stakedAssetsGet" - } - }, - "/api/v1/config/frontend": { - "get": { - "tags": [ - "Config" - ], - "summary": "Get the configuration for the frontend.", - "description": "Get the frontend configuration for the requesting client.\n\n### Security\n\nDoes not require any Catalyst RBAC Token to access.", - "responses": { - "404": { - "description": "No frontend config defined.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "400": { - "description": "## Bad Request\n\nThe client has not sent valid request, could be an invalid HTTP in general or\nprovided not correct headers, path or query arguments.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "401": { - "description": "## Unauthorized\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Unauthorized" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "429": { - "description": "## Too Many Requests\n\nThe client has sent too many requests in a given amount of time.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TooManyRequests" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - }, - "RETRY-AFTER": { - "required": true, - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - }, - "431": { - "description": "## Request Header Fields Too Large\n\nThe client sent a request with too large header fields.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "500": { - "description": "## Internal Server Error.\n\nAn internal server error occurred.\n\n*The contents of this response should be reported to the projects issue tracker.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/InternalServerError" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - } - } - }, - "503": { - "description": "## Service Unavailable\n\nThe service is not available, try again later.\n\n*This is returned when the service either has not started,\nor has become unavailable.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ServiceUnavailable" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RETRY-AFTER": { - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - }, - "200": { - "description": "Configuration result.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "type": "object", - "example": { - "name": "Alex" - } - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "403": { - "description": "## Forbidden\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Forbidden" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "414": { - "description": "## URI Too Long\n\nThe client sent a request with the URI is longer than the server is willing to\ninterpret", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "412": { - "description": "## Precondition Failed\n\nThe client has not sent valid data in its request, headers, parameters or body.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PreconditionFailed" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - } - }, - "security": [ - { - "CatalystRBACSecurityScheme": [] - }, - { - "NoAuthorization": [] - } - ], - "operationId": "get_config_frontend" - } - }, - "/api/v1/document/{document_id}": { - "get": { - "tags": [ - "Documents" - ], - "summary": "Get A Signed Document.", - "description": "This endpoint returns either a specific or latest version of a registered signed\ndocument.", - "parameters": [ - { - "name": "document_id", - "schema": { - "type": "string", - "format": "uuidv7", - "title": "UUIDv7", - "description": "128 Bit UUID Version 7 - Timestamp + Random", - "example": "01943a32-9f35-7a14-b364-36ad693465e6", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - }, - "in": "path", - "description": "UUIDv7 Document ID to retrieve", - "required": true, - "deprecated": false, - "explode": true - }, - { - "name": "version", - "schema": { - "type": "string", - "format": "uuidv7", - "title": "UUIDv7", - "description": "128 Bit UUID Version 7 - Timestamp + Random", - "example": "01943a32-9f35-7a14-b364-36ad693465e6", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - }, - "in": "query", - "description": "UUIDv7 Version of the Document to retrieve, if omitted, returns the latest\nversion.", - "required": false, - "deprecated": false, - "explode": true - } - ], - "responses": { - "200": { - "description": "## OK\n\nThe Document that was requested.", - "content": { - "application/cbor": { - "schema": { - "type": "string", - "format": "binary", - "example": "(binary data)" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "503": { - "description": "## Service Unavailable\n\nThe service is not available, try again later.\n\n*This is returned when the service either has not started,\nor has become unavailable.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ServiceUnavailable" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RETRY-AFTER": { - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - }, - "414": { - "description": "## URI Too Long\n\nThe client sent a request with the URI is longer than the server is willing to\ninterpret", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "500": { - "description": "## Internal Server Error.\n\nAn internal server error occurred.\n\n*The contents of this response should be reported to the projects issue tracker.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/InternalServerError" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - } - } - }, - "400": { - "description": "## Bad Request\n\nThe client has not sent valid request, could be an invalid HTTP in general or\nprovided not correct headers, path or query arguments.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "412": { - "description": "## Precondition Failed\n\nThe client has not sent valid data in its request, headers, parameters or body.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PreconditionFailed" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "404": { - "description": "## Not Found\n\nThe document could not be found.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "429": { - "description": "## Too Many Requests\n\nThe client has sent too many requests in a given amount of time.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TooManyRequests" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - }, - "RETRY-AFTER": { - "required": true, - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - }, - "403": { - "description": "## Forbidden\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Forbidden" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "401": { - "description": "## Unauthorized\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Unauthorized" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "431": { - "description": "## Request Header Fields Too Large\n\nThe client sent a request with too large header fields.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - } - }, - "security": [ - { - "CatalystRBACSecurityScheme": [] - }, - { - "NoAuthorization": [] - } - ], - "operationId": "getDocument" - } - }, - "/api/v1/document": { - "put": { - "tags": [ - "Documents" - ], - "summary": "Put A Signed Document.", - "description": "This endpoint returns OK if the document is valid, able to be put by the\nsubmitter, and if it already exists, is identical to the existing document.", - "requestBody": { - "description": "The document to PUT", - "content": { - "application/cbor": { - "schema": { - "type": "string", - "format": "binary", - "example": "(binary data)" - } - } - }, - "required": true - }, - "responses": { - "412": { - "description": "## Precondition Failed\n\nThe client has not sent valid data in its request, headers, parameters or body.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PreconditionFailed" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "431": { - "description": "## Request Header Fields Too Large\n\nThe client sent a request with too large header fields.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "503": { - "description": "## Service Unavailable\n\nThe service is not available, try again later.\n\n*This is returned when the service either has not started,\nor has become unavailable.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ServiceUnavailable" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RETRY-AFTER": { - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - }, - "500": { - "description": "## Internal Server Error.\n\nAn internal server error occurred.\n\n*The contents of this response should be reported to the projects issue tracker.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/InternalServerError" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - } - } - }, - "204": { - "description": "## No Content\n\nThe Document was already stored, and has not changed.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "413": { - "description": "## Content Too Large\n\nPayload Too Large. The document exceeds the maximum size of a legitimate single\ndocument.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "422": { - "description": "## Unprocessable Content\n\nError Response. The document submitted is invalid.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PutDocumentUnprocessableContent" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "414": { - "description": "## URI Too Long\n\nThe client sent a request with the URI is longer than the server is willing to\ninterpret", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "201": { - "description": "## Created\n\nThe Document was stored OK for the first time.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "401": { - "description": "## Unauthorized\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Unauthorized" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "403": { - "description": "## Forbidden\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Forbidden" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "400": { - "description": "## Bad Request\n\nThe client has not sent valid request, could be an invalid HTTP in general or\nprovided not correct headers, path or query arguments.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "429": { - "description": "## Too Many Requests\n\nThe client has sent too many requests in a given amount of time.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TooManyRequests" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - }, - "RETRY-AFTER": { - "required": true, - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - } - }, - "security": [ - { - "CatalystRBACSecurityScheme": [] - } - ], - "operationId": "putDocument" - } - }, - "/api/v1/document/index": { - "post": { - "tags": [ - "Documents" - ], - "summary": "Post A Signed Document Index Query.", - "description": "This endpoint produces a summary of signed documents that meet the criteria\ndefined in the request body.\n\nIt does not return the actual documents, just an index of the document identifiers\nwhich allows the documents to be retrieved by the `GET document` endpoint.", - "parameters": [ - { - "name": "page", - "schema": { - "type": "integer", - "format": "u32", - "title": "Page", - "description": "The page number of the data.\nThe size of each page, and its offset within the complete data set is determined by the `limit` parameter.", - "default": 0, - "example": 5, - "maximum": 4294967295.0, - "minimum": 0.0 - }, - "in": "query", - "required": false, - "deprecated": false, - "explode": true - }, - { - "name": "limit", - "schema": { - "type": "integer", - "format": "u32", - "title": "Limit", - "description": "The size `limit` of each `page` of results.\nDetermines the maximum amount of data that can be returned in a valid response.\n\nThis `limit` of records of data will always be returned unless there is less data to return \nthan allowed for by the `limit` and `page`.\n\n*Exceeding the `page`/`limit` of all available records will not return `404`, it will return an \nempty response.*", - "default": 100, - "example": 10, - "maximum": 100.0, - "minimum": 1.0 - }, - "in": "query", - "required": false, - "deprecated": false, - "explode": true - } - ], - "requestBody": { - "description": "The Query Filter Specification", - "content": { - "application/json; charset=utf-8": { - "schema": { - "title": "Document Index Query Filter", - "description": "A Query Filter which causes documents whose metadata matches the provided\nfields to be returned in the index list response.\n\nFields which are not set, are not used to filter documents based on those metadata\nfields. This is equivalent to returning documents where those metadata fields either\ndo not exist, or do exist, but have any value.", - "allOf": [ - { - "$ref": "#/components/schemas/DocumentIndexQueryFilter" - }, - { - "title": "Document Index Query Filter", - "description": "A Query Filter which causes documents whose metadata matches the provided\nfields to be returned in the index list response.\n\nFields which are not set, are not used to filter documents based on those metadata\nfields. This is equivalent to returning documents where those metadata fields either\ndo not exist, or do exist, but have any value.", - "example": { - "id": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "ref": { - "id": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - "reply": { - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - }, - "template": { - "id": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - }, - "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - } - ], - "example": { - "id": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "ref": { - "id": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - "reply": { - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - }, - "template": { - "id": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - }, - "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - } - } - }, - "required": true - }, - "responses": { - "500": { - "description": "## Internal Server Error.\n\nAn internal server error occurred.\n\n*The contents of this response should be reported to the projects issue tracker.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/InternalServerError" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - } - } - }, - "401": { - "description": "## Unauthorized\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Unauthorized" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "431": { - "description": "## Request Header Fields Too Large\n\nThe client sent a request with too large header fields.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "403": { - "description": "## Forbidden\n\nThe client has not sent valid authentication credentials for the requested\nresource.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Forbidden" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "400": { - "description": "## Bad Request\n\nThe client has not sent valid request, could be an invalid HTTP in general or\nprovided not correct headers, path or query arguments.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "404": { - "description": "## Not Found\n\nNo documents were found which match the query filter.", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "503": { - "description": "## Service Unavailable\n\nThe service is not available, try again later.\n\n*This is returned when the service either has not started,\nor has become unavailable.*", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ServiceUnavailable" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RETRY-AFTER": { - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - }, - "429": { - "description": "## Too Many Requests\n\nThe client has sent too many requests in a given amount of time.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TooManyRequests" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - }, - "RETRY-AFTER": { - "required": true, - "deprecated": false, - "schema": { - "type": "string", - "format": "http-date || integer", - "title": "Retry-After Header", - "description": "Http Date or Interval in seconds.\nValid formats:\n\n* `Retry-After: `\n* `Retry-After: `\n\nSee: ", - "example": "300" - } - } - } - }, - "200": { - "description": "## OK\n\nThe Index of documents which match the query filter.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "title": "Document Index List", - "description": "A list of all matching documents, limited by the paging parameters.\nDocuments are listed in Ascending order.\nThe Paging limit refers to the number fo document versions, not the number\nof unique Document IDs.", - "allOf": [ - { - "$ref": "#/components/schemas/DocumentIndexList" - }, - { - "title": "Document Index List", - "description": "A list of all matching documents, limited by the paging parameters.\nDocuments are listed in Ascending order.\nThe Paging limit refers to the number fo document versions, not the number\nof unique Document IDs.", - "example": { - "docs": [ - { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": [ - { - "ref": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - ] - } - ], - "page": { - "limit": 10, - "page": 5, - "remaining": 16384 - } - } - } - ], - "example": { - "docs": [ - { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": [ - { - "ref": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - ] - } - ], - "page": { - "limit": 10, - "page": 5, - "remaining": 16384 - } - } - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "414": { - "description": "## URI Too Long\n\nThe client sent a request with the URI is longer than the server is willing to\ninterpret", - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - }, - "412": { - "description": "## Precondition Failed\n\nThe client has not sent valid data in its request, headers, parameters or body.", - "content": { - "application/json; charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PreconditionFailed" - } - } - }, - "headers": { - "Access-Control-Allow-Origin": { - "description": "Access-Control-Allow-Origin Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "origin", - "title": "Access-Control-Allow-Origin header.", - "description": "Valid formats:\n\n* `Access-Control-Allow-Origin: *`\n* `Access-Control-Allow-Origin: `\n* `Access-Control-Allow-Origin: null`\n", - "externalDocs": { - "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin", - "description": "MDB Web Docs - Access-Control-Allow-Origin" - }, - "example": "*" - } - }, - "RateLimit": { - "description": "RateLimit Header.", - "deprecated": false, - "schema": { - "type": "string", - "format": "rate-limit", - "title": "RateLimit HTTP header.", - "description": "Allows this server to advertise its quota policies and the current\nservice limits, thereby allowing clients to avoid being throttled.", - "externalDocs": { - "url": "https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/", - "description": "IETF Draft - RateLimit header fields for HTTP" - }, - "example": "\"default\";q=100;w=10" - } - } - } - } - }, - "security": [ - { - "CatalystRBACSecurityScheme": [] - }, - { - "NoAuthorization": [] - } - ], - "operationId": "postDocument" - } - } - }, - "components": { - "schemas": { - "ContentErrorDetail": { - "type": "object", - "description": "Individual details of a single error that was detected with the content of the\nrequest.", - "properties": { - "loc": { - "type": "array", - "description": "The location of the error", - "items": { - "type": "string", - "format": "error", - "title": "Error Message", - "description": "This is an error message.", - "example": "An error has occurred, the details of the error are ...", - "maxLength": 60000, - "minLength": 1, - "pattern": "^(.){1,60000}$" - }, - "example": [ - "An error has occurred, the details of the error are ..." - ], - "maxItems": 10 - }, - "msg": { - "type": "string", - "format": "error", - "title": "Error Message", - "description": "The error message.", - "example": "An error has occurred, the details of the error are ...", - "maxLength": 60000, - "minLength": 1, - "pattern": "^(.){1,60000}$" - }, - "type": { - "type": "string", - "format": "error", - "title": "Error Message", - "description": "The type of error", - "example": "An error has occurred, the details of the error are ...", - "maxLength": 60000, - "minLength": 1, - "pattern": "^(.){1,60000}$" - } - }, - "example": { - "loc": [ - "body" - ], - "msg": "Value is not a valid dict.", - "type": "type_error.dict" - } - }, - "CurrentPage": { - "type": "object", - "description": "Current Page of data being returned.", - "required": [ - "page", - "limit", - "remaining" - ], - "properties": { - "page": { - "type": "integer", - "format": "u32", - "title": "Page", - "description": "The page number of the data.\nThe size of each page, and its offset within the complete data set is determined by the `limit` parameter.", - "default": 0, - "example": 5, - "maximum": 4294967295.0, - "minimum": 0.0 - }, - "limit": { - "type": "integer", - "format": "u32", - "title": "Limit", - "description": "The size `limit` of each `page` of results.\nDetermines the maximum amount of data that can be returned in a valid response.\n\nThis `limit` of records of data will always be returned unless there is less data to return \nthan allowed for by the `limit` and `page`.\n\n*Exceeding the `page`/`limit` of all available records will not return `404`, it will return an \nempty response.*", - "default": 100, - "example": 10, - "maximum": 100.0, - "minimum": 1.0 - }, - "remaining": { - "type": "integer", - "format": "u32", - "title": "Remaining", - "description": "The number of items remaining to be returned after this page.\nThis is the absolute number of items remaining, and not the number of Pages.", - "example": 16384, - "maximum": 4294967295.0, - "minimum": 0.0 - } - }, - "example": { - "limit": 10, - "page": 5, - "remaining": 16384 - } - }, - "DocumentIndexList": { - "type": "object", - "description": "A single page of documents.\n\nThe page limit is defined by the number of document versions,\nnot the number of Document IDs.", - "required": [ - "docs", - "page" - ], - "properties": { - "docs": { - "type": "array", - "description": "List of documents that matched the filter.\n\nDocuments are listed in ascending order.", - "items": { - "title": "Individual Indexed Document", - "description": "An Individual Indexed Document and its Versions.\nDocument Versions are listed in Ascending order.", - "allOf": [ - { - "$ref": "#/components/schemas/IndexedDocument" - }, - { - "title": "Individual Indexed Document", - "description": "An Individual Indexed Document and its Versions.\nDocument Versions are listed in Ascending order.", - "example": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": [ - { - "ref": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - ] - } - } - ], - "example": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": [ - { - "ref": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - ] - } - }, - "example": [ - { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": [ - { - "ref": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - ] - } - ], - "maxItems": 4294967295 - }, - "page": { - "title": "The Page of Document Index List.", - "description": "Current Page", - "allOf": [ - { - "$ref": "#/components/schemas/CurrentPage" - }, - { - "title": "The Page of Document Index List.", - "example": { - "limit": 10, - "page": 5, - "remaining": 16384 - } - } - ], - "example": { - "limit": 10, - "page": 5, - "remaining": 16384 - } - } - }, - "example": { - "docs": [ - { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": [ - { - "ref": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - ] - } - ], - "page": { - "limit": 10, - "page": 5, - "remaining": 16384 - } - } - }, - "DocumentIndexQueryFilter": { - "type": "object", - "description": "Query Filter for the generation of a signed document index.\n\nThe Query works as a filter which acts like a sieve to filter out documents\nwhich do not strictly match the metadata or payload fields included in the query\nitself.", - "properties": { - "type": { - "type": "string", - "format": "uuid", - "title": "Signed Document Type", - "description": "## Signed Document Type.\n\nThe document type must match one of the\n[Registered Document Types](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/types/)\n\nUUIDv4 Formatted 128bit value.", - "externalDocs": { - "url": "https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#type", - "description": "Specification" - }, - "example": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - }, - "id": { - "title": "Document ID Selector", - "description": "## Document ID\n\nEither an absolute single Document ID or a range of\n[Document IDs](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id)", - "allOf": [ - { - "$ref": "#/components/schemas/IdSelector" - }, - { - "title": "Document ID Selector", - "description": "Either a Single Document ID, or a Range of Document IDs, or Inclusion from the List of\nIDs", - "example": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - ], - "example": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - "ver": { - "title": "Document Version Selector", - "description": "## Document Version\n\nEither an absolute single Document Version or a range of\n[Document Versions](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver)", - "allOf": [ - { - "$ref": "#/components/schemas/EqOrRangedVer" - }, - { - "title": "Document Version Selector", - "description": "Either a absolute single Document Version or a range of Document Versions", - "example": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - ], - "example": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - }, - "ref": { - "title": "Document Reference", - "description": "## Document Reference\n\nA [reference](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/meta/#ref-document-reference)\nto another signed document. This fields can match any reference that matches the\ndefined [Document IDs](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id)\nand/or\n[Document Versions](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver)\n\nThe kind of document that the reference refers to is defined by the\n[Document Type](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/types/)", - "allOf": [ - { - "$ref": "#/components/schemas/IdAndVerRef" - }, - { - "title": "Document Reference", - "description": "A Signed Documents\n[Reference](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/meta/#ref-document-reference)\nto another Documents ID and/or Version.\n\n*Note: at least one of `id` or `ver` must be defined.*", - "example": { - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - } - ], - "example": { - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - }, - "template": { - "title": "Document Reference", - "description": "## Document Template\n\nDocuments that are created based on a template include the\n[template reference](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/meta/#template-template-reference)\nto another signed document. This fields can match any template reference that\nmatches the defined [Document IDs](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id)\nand/or\n[Document Versions](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver)\n\nThe kind of document that the reference refers to is defined by the\n[Document Type](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/types/)\nhowever, it will always be a template type document that matches the document\nitself.", - "allOf": [ - { - "$ref": "#/components/schemas/IdAndVerRef" - }, - { - "title": "Document Reference", - "description": "A Signed Documents\n[Reference](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/meta/#ref-document-reference)\nto another Documents ID and/or Version.\n\n*Note: at least one of `id` or `ver` must be defined.*", - "example": { - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - } - ], - "example": { - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - }, - "reply": { - "title": "Document Reference", - "description": "## Document Reply\n\nThis is a\n[reply reference](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/meta/#reply-reply-reference)\nwhich links one document to another, when acting as a reply to it.\nReplies typically reference the same kind of document.\nThis fields can match any reply reference that matches the defined\n[Document IDs](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id)\nand/or\n[Document Versions](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver)\n\nThe kind of document that the reference refers to is defined by the\n[Document Type](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/types/).", - "allOf": [ - { - "$ref": "#/components/schemas/IdAndVerRef" - }, - { - "title": "Document Reference", - "description": "A Signed Documents\n[Reference](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/meta/#ref-document-reference)\nto another Documents ID and/or Version.\n\n*Note: at least one of `id` or `ver` must be defined.*", - "example": { - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - } - ], - "example": { - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - }, - "parameters": { - "title": "Document Reference", - "description": "## Parameters\n\nThis is a reference to a configuration document.\nThis fields can match any reference that matches the defined\n[Document IDs](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id)\nand/or\n[Document Versions](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver)\n\nWhether a Document Type has a brand, campaign, category etc. reference is defined\nby its [Document Type](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/types/).", - "allOf": [ - { - "$ref": "#/components/schemas/IdAndVerRef" - }, - { - "title": "Document Reference", - "description": "A Signed Documents\n[Reference](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/meta/#ref-document-reference)\nto another Documents ID and/or Version.\n\n*Note: at least one of `id` or `ver` must be defined.*", - "example": { - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - } - ], - "example": { - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - } - }, - "example": { - "id": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "ref": { - "id": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - "reply": { - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - }, - "template": { - "id": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - }, - "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - }, - "DocumentReference": { - "type": "object", - "description": "A Reference to another Signed Document", - "required": [ - "id", - "ver" - ], - "properties": { - "id": { - "type": "string", - "format": "uuidv7", - "title": "Signed Document ID", - "description": "Document ID Reference", - "externalDocs": { - "url": "https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id", - "description": "Specification" - }, - "example": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - }, - "ver": { - "type": "string", - "format": "uuidv7", - "title": "Signed Document Version", - "description": "Document Version", - "externalDocs": { - "url": "https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver", - "description": "Specification" - }, - "example": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - } - }, - "example": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - "EqOrRangedVer": { - "type": "object", - "description": "Document or Range of Documents\n\nEither a Single Document Version, or a Range of Document Versions", - "oneOf": [ - { - "title": "Version Equals", - "description": "A specific single\n[Document Version](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver).", - "allOf": [ - { - "$ref": "#/components/schemas/VerEq" - }, - { - "title": "Version Equals", - "description": "A specific single\n[Document Version](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver).", - "example": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - ], - "example": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - { - "title": "Version Range", - "description": "A range of [Document Versions]().", - "allOf": [ - { - "$ref": "#/components/schemas/VerRange" - }, - { - "title": "Version Range", - "description": "A range of [Document Versions]().", - "example": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - ], - "example": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - ] - }, - "Forbidden": { - "type": "object", - "description": "The client has not sent valid authentication credentials for the requested\nresource.", - "required": [ - "id", - "msg" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "title": "Error Unique ID", - "description": "Unique ID of this Server Error so that it can be located easily for debugging.", - "example": "574d5ebe-dd5e-4e8b-9e06-0166ab5c5fa6" - }, - "msg": { - "type": "string", - "format": "error", - "title": "Error Message", - "description": "Error message.", - "example": "An error has occurred, the details of the error are ...", - "maxLength": 60000, - "minLength": 1, - "pattern": "^(.){1,60000}$" - }, - "required": { - "type": "array", - "description": "List or Roles required to access the resource.", - "items": { - "type": "string", - "maxLength": 100, - "pattern": "^[0-9a-zA-Z].*$" - }, - "example": [ - "VOTER", - "PROPOSER" - ], - "maxItems": 100 - } - }, - "example": { - "id": "743fcc8c-5b46-411a-9845-d6b4b2b6233d", - "msg": "Your request was not successful because your authentication credentials do not have the required roles for the requested resource.", - "required": [ - "VOTER", - "PROPOSER" - ] - } - }, - "FullStakeInfo": { - "type": "object", - "description": "Full user's cardano stake info.", - "required": [ - "volatile", - "persistent" - ], - "properties": { - "volatile": { - "title": "Volatile stake information.", - "description": "Volatile stake information.", - "allOf": [ - { - "$ref": "#/components/schemas/StakeInfo" - }, - { - "title": "Volatile stake information.", - "example": { - "ada_amount": 1234567, - "assets": [], - "slot_number": 1234567 - } - } - ], - "example": { - "ada_amount": 1234567, - "assets": [], - "slot_number": 1234567 - } - }, - "persistent": { - "title": "Persistent stake information.", - "description": "Persistent stake information.", - "allOf": [ - { - "$ref": "#/components/schemas/StakeInfo" - }, - { - "title": "Persistent stake information.", - "example": { - "ada_amount": 1234567, - "assets": [], - "slot_number": 1234567 - } - } - ], - "example": { - "ada_amount": 1234567, - "assets": [], - "slot_number": 1234567 - } - } - }, - "example": { - "persistent": { - "ada_amount": 1234567, - "assets": [], - "slot_number": 1234567 - }, - "volatile": { - "ada_amount": 1234567, - "assets": [], - "slot_number": 1234567 - } - } - }, - "IdAndVerRef": { - "type": "object", - "description": "Either a Single Document ID, or a Range of Document IDs", - "anyOf": [ - { - "title": "Document ID Reference", - "description": "A Reference to the Document ID Only.\n\nThis will match any document that matches the defined Document ID only.\nThe Document Version is not considered, and will match any version.", - "allOf": [ - { - "$ref": "#/components/schemas/IdRefOnly" - }, - { - "title": "Document ID Reference", - "description": "A Reference to the Document ID Only.\n\nThis will match any document that matches the defined Document ID only.\nThe Document Version is not considered, and will match any version.", - "example": { - "id": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - } - ], - "example": { - "id": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - }, - { - "title": "Document Version Reference", - "description": "A Reference to the Document Version, and optionally also the Document ID.\n\nThis will match any document that matches the defined Document Version and if\nspecified the Document ID.\nIf the Document ID is not specified, then all documents that match the version will be\nreturned in the index.", - "allOf": [ - { - "$ref": "#/components/schemas/VerRefWithOptionalId" - }, - { - "title": "Document Version Reference", - "description": "A Reference to the Document Version, and optionally also the Document ID.\n\nThis will match any document that matches the defined Document Version and if\nspecified the Document ID.\nIf the Document ID is not specified, then all documents that match the version will be\nreturned in the index.", - "example": { - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - } - ], - "example": { - "ver": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - } - ] - }, - "IdEq": { - "type": "object", - "description": "A single Document IDs.", - "required": [ - "eq" - ], - "properties": { - "eq": { - "type": "string", - "format": "uuidv7", - "title": "Signed Document ID", - "description": "The exact Document ID to match against.", - "externalDocs": { - "url": "https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id", - "description": "Specification" - }, - "example": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - } - }, - "example": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - "IdIn": { - "type": "object", - "description": "Any Document IDs from the list", - "required": [ - "in" - ], - "properties": { - "in": { - "type": "array", - "description": "Matching any Document IDs from the list", - "items": { - "type": "string", - "format": "uuidv7", - "title": "Signed Document ID", - "description": "Unique [Document ID](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id).\n\nUUIDv7 Formatted 128bit value.", - "externalDocs": { - "url": "https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id", - "description": "Specification" - }, - "example": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - }, - "example": [ - "01944e87-e68c-7f22-9df1-816863cfa5ff" - ], - "maxItems": 1000 - } - }, - "example": { - "in": [ - "01944e87-e68c-7f22-9df1-816863cfa5ff" - ] - } - }, - "IdRange": { - "type": "object", - "description": "A range of Document IDs.", - "required": [ - "min", - "max" - ], - "properties": { - "min": { - "type": "string", - "format": "uuidv7", - "title": "Signed Document ID", - "description": "Minimum Document ID to find (inclusive)", - "externalDocs": { - "url": "https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id", - "description": "Specification" - }, - "example": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - }, - "max": { - "type": "string", - "format": "uuidv7", - "title": "Signed Document ID", - "description": "Maximum Document ID to find (inclusive)", - "externalDocs": { - "url": "https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id", - "description": "Specification" - }, - "example": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - } - }, - "example": { - "max": "01944e87-e68c-7fff-bfff-ffffffffffff", - "min": "01944e87-e68c-7000-8000-000000000000" - } - }, - "IdRefOnly": { - "type": "object", - "description": "A Reference to a Document ID/s and their version/s.", - "required": [ - "id" - ], - "properties": { - "id": { - "title": "Document ID Selector", - "description": "Document ID, or range of Document IDs", - "allOf": [ - { - "$ref": "#/components/schemas/IdSelector" - }, - { - "title": "Document ID Selector", - "description": "Either a Single Document ID, or a Range of Document IDs, or Inclusion from the List of\nIDs", - "example": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - ], - "example": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - }, - "example": { - "id": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - }, - "IdSelector": { - "type": "object", - "description": "Either a Single Document ID, or a Range of Document IDs, or Inclusion from the List of\nIDs", - "oneOf": [ - { - "title": "ID Equals", - "description": "A specific single\n[Document ID](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id).", - "allOf": [ - { - "$ref": "#/components/schemas/IdEq" - }, - { - "title": "ID Equals", - "description": "A specific single\n[Document ID](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id).", - "example": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - ], - "example": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - { - "title": "ID Range", - "description": "A range of\n[Document IDs](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id).", - "allOf": [ - { - "$ref": "#/components/schemas/IdRange" - }, - { - "title": "ID Range", - "description": "A range of\n[Document IDs](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id).", - "example": { - "max": "01944e87-e68c-7fff-bfff-ffffffffffff", - "min": "01944e87-e68c-7000-8000-000000000000" - } - } - ], - "example": { - "max": "01944e87-e68c-7fff-bfff-ffffffffffff", - "min": "01944e87-e68c-7000-8000-000000000000" - } - }, - { - "title": "ID Inclusion", - "description": "A list of\n[Document ID](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id).", - "allOf": [ - { - "$ref": "#/components/schemas/IdIn" - }, - { - "title": "ID Inclusion", - "description": "A list of\n[Document ID](https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id).", - "example": { - "in": [ - "01944e87-e68c-7f22-9df1-816863cfa5ff" - ] - } - } - ], - "example": { - "in": [ - "01944e87-e68c-7f22-9df1-816863cfa5ff" - ] - } - } - ] - }, - "IndexedDocument": { - "type": "object", - "description": "List of Documents that matched the filter", - "required": [ - "id", - "ver" - ], - "properties": { - "id": { - "type": "string", - "format": "uuidv7", - "title": "Signed Document ID", - "description": "Document ID that matches the filter", - "externalDocs": { - "url": "https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#id", - "description": "Specification" - }, - "example": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - }, - "ver": { - "type": "array", - "description": "List of matching versions of the document.\n\nVersions are listed in ascending order.", - "items": { - "title": "Individual Document Version", - "description": "A Matching version of the document.\n\nMetadata fields which are not set in the document, are not included in the version\ninformation. used to filter documents based on those metadata fields.\nThis is equivalent to returning documents where those metadata fields either do not\nexist, or do exist, but have any value.", - "allOf": [ - { - "$ref": "#/components/schemas/IndexedDocumentVersion" - }, - { - "title": "Individual Document Version", - "description": "A Matching version of the document.\n\nMetadata fields which are not set in the document, are not included in the version\ninformation. used to filter documents based on those metadata fields.\nThis is equivalent to returning documents where those metadata fields either do not\nexist, or do exist, but have any value.", - "example": { - "ref": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - ], - "example": { - "ref": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - "example": [ - { - "ref": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - ], - "maxItems": 100 - } - }, - "example": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": [ - { - "ref": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - ] - } - }, - "IndexedDocumentVersion": { - "type": "object", - "description": "List of Documents that matched the filter", - "required": [ - "ver", - "type" - ], - "properties": { - "ver": { - "type": "string", - "format": "uuidv7", - "title": "Signed Document Version", - "description": "Document Version that matches the filter", - "externalDocs": { - "url": "https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver", - "description": "Specification" - }, - "example": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - }, - "type": { - "type": "string", - "format": "uuid", - "title": "Signed Document Type", - "description": "Document Type that matches the filter", - "externalDocs": { - "url": "https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#type", - "description": "Specification" - }, - "example": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - }, - "ref": { - "title": "Document Reference for filtered Documents.", - "description": "Document Reference that matches the filter", - "allOf": [ - { - "$ref": "#/components/schemas/DocumentReference" - }, - { - "title": "Document Reference for filtered Documents.", - "example": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - ], - "example": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - "reply": { - "title": "Document Reference for filtered Documents.", - "description": "Document Reply Reference that matches the filter", - "allOf": [ - { - "$ref": "#/components/schemas/DocumentReference" - }, - { - "title": "Document Reference for filtered Documents.", - "example": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - ], - "example": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - "template": { - "title": "Document Reference for filtered Documents.", - "description": "Document Template Reference that matches the filter", - "allOf": [ - { - "$ref": "#/components/schemas/DocumentReference" - }, - { - "title": "Document Reference for filtered Documents.", - "example": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - ], - "example": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - "doc_parameters": { - "title": "Document Reference for filtered Documents.", - "description": "Document Parameter Reference that matches the filter", - "allOf": [ - { - "$ref": "#/components/schemas/DocumentReference" - }, - { - "title": "Document Reference for filtered Documents.", - "example": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - ], - "example": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - }, - "example": { - "ref": { - "id": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - }, - "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", - "ver": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - "InternalServerError": { - "type": "object", - "description": "An internal server error occurred.\n\n*The contents of this response should be reported to the projects issue tracker.*", - "required": [ - "id", - "msg" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "title": "Error Unique ID", - "description": "Unique ID of this Server Error so that it can be located easily for debugging.", - "example": "b074a6f8-fb46-4944-8aa9-61e9e1b23bee" - }, - "msg": { - "type": "string", - "format": "error", - "title": "Error Message", - "description": "Error message.", - "example": "An error has occurred, the details of the error are ...", - "maxLength": 60000, - "minLength": 1, - "pattern": "^(.){1,60000}$" - }, - "issue": { - "type": "string", - "format": "url", - "title": "URL String", - "description": "A URL to report an issue.", - "example": "https://example.com/" - } - }, - "example": { - "id": "ef6907ae-bed1-4a36-8788-a500d46dee46", - "issue": "https://github.com/input-output-hk/catalyst-voices/issues/new?template=bug_report.yml&title=Internal+Server+Error+-+ef6907ae-bed1-4a36-8788-a500d46dee46", - "msg": "Internal Server Error. Please report the issue to the service owner." - } - }, - "Network": { - "type": "string", - "description": "Cardano network type.", - "enum": [ - "mainnet", - "preprod", - "preview" - ] - }, - "PreconditionFailed": { - "type": "object", - "description": "The client has not sent valid data in its request, headers, parameters or body.", - "required": [ - "detail" - ], - "properties": { - "detail": { - "type": "array", - "description": "Details of each error in the content that was detected.\n\nNote: This may not be ALL errors in the content, as validation of content can stop\nat any point an error is detected.", - "items": { - "$ref": "#/components/schemas/ContentErrorDetail" - }, - "example": [ - { - "loc": [ - "body" - ], - "msg": "Value is not a valid dict.", - "type": "type_error.dict" - } - ], - "maxItems": 1000, - "minItems": 1 - } - }, - "example": { - "detail": [ - { - "loc": [ - "body" - ], - "msg": "Value is not a valid dict.", - "type": "type_error.dict" - } - ] - } - }, - "PutDocumentUnprocessableContent": { - "type": "object", - "description": "Put Document Validation Error.", - "required": [ - "error" - ], - "properties": { - "error": { - "type": "string", - "format": "error", - "title": "Error Message", - "description": "Error messages.", - "example": "An error has occurred, the details of the error are ...", - "maxLength": 60000, - "minLength": 1, - "pattern": "^(.){1,60000}$" - }, - "report": { - "type": "object", - "description": "Error report JSON object.", - "example": {} - } - }, - "example": { - "error": "Missing Document in request body", - "report": {} - } - }, - "RbacRegistrationChain": { - "type": "object", - "description": "A chain of valid RBAC registrations.\n\nA unified data of multiple RBAC registrations.", - "required": [ - "catalyst_id", - "purpose", - "roles" - ], - "properties": { - "catalyst_id": { - "type": "string", - "format": "catalyst_id", - "title": "Catalyst ID", - "description": "A Catalyst ID.", - "example": "preprod.cardano/11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", - "pattern": ".+\\/[A-Za-z0-9_-]{43}" - }, - "last_persistent_txn": { - "type": "string", - "format": "hex:hash(32)", - "title": "Transaction Id/Hash", - "description": "An ID of the last persistent transaction.", - "example": "0x27d0350039fb3d068cccfae902bf2e72583fc553e0aafb960bd9d76d5bff777b", - "maxLength": 66, - "minLength": 66, - "pattern": "^0x[A-Fa-f0-9]{64}$" - }, - "last_volatile_txn": { - "type": "string", - "format": "hex:hash(32)", - "title": "Transaction Id/Hash", - "description": "An ID of the last volatile transaction.", - "example": "0x27d0350039fb3d068cccfae902bf2e72583fc553e0aafb960bd9d76d5bff777b", - "maxLength": 66, - "minLength": 66, - "pattern": "^0x[A-Fa-f0-9]{64}$" - }, - "purpose": { - "type": "array", - "description": "A list of registration purposes.", - "items": { - "type": "string", - "format": "uuid", - "title": "UUIDv4", - "description": "128 Bit UUID Version 4 - Random", - "example": "c9993e54-1ee1-41f7-ab99-3fdec865c744", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - }, - "example": [ - "c9993e54-1ee1-41f7-ab99-3fdec865c744" - ], - "maxItems": 10000, - "minItems": 1 - }, - "roles": { - "type": "object", - "format": "map", - "title": "RBAC role data map", - "description": "A map of role number to role data.", - "example": { - "0": { - "encryption_keys": [ - { - "is_persistent": true, - "key_type": "x509", - "key_value": "0x56CDD154355E078A0990F9E633F9553F7D43A68B2FF9BEF78B9F5C71C808A7C8", - "time": "2024-04-09T15:28:21+00:00" - } - ], - "extended_data": { - "10": [ - 1, - 2, - 3 - ] - }, - "payment_addresses": [ - { - "address": "addr_test1qz2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgs68faae", - "is_persistent": true, - "time": "2024-04-09T15:28:21+00:00" - } - ], - "signing_keys": [ - { - "is_persistent": true, - "key_type": "x509", - "key_value": "0x56CDD154355E078A0990F9E633F9553F7D43A68B2FF9BEF78B9F5C71C808A7C8", - "time": "2024-04-09T15:28:21+00:00" - } - ] - } - } - } - }, - "example": { - "catalyst_id": "preprod.cardano/11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", - "last_persistent_txn": "0x27d0350039fb3d068cccfae902bf2e72583fc553e0aafb960bd9d76d5bff777b", - "last_volatile_txn": "0x27d0350039fb3d068cccfae902bf2e72583fc553e0aafb960bd9d76d5bff777b", - "purpose": [ - "c9993e54-1ee1-41f7-ab99-3fdec865c744" - ], - "roles": { - "0": { - "encryption_keys": [ - { - "is_persistent": true, - "key_type": "x509", - "key_value": "0x56CDD154355E078A0990F9E633F9553F7D43A68B2FF9BEF78B9F5C71C808A7C8", - "time": "2024-04-09T15:28:21+00:00" - } - ], - "extended_data": { - "10": [ - 1, - 2, - 3 - ] - }, - "payment_addresses": [ - { - "address": "addr_test1qz2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgs68faae", - "is_persistent": true, - "time": "2024-04-09T15:28:21+00:00" - } - ], - "signing_keys": [ - { - "is_persistent": true, - "key_type": "x509", - "key_value": "0x56CDD154355E078A0990F9E633F9553F7D43A68B2FF9BEF78B9F5C71C808A7C8", - "time": "2024-04-09T15:28:21+00:00" - } - ] - } - } - } - }, - "RbacUnprocessableContent": { - "type": "object", - "description": "Rbac Registration Validation Error.", - "required": [ - "error" - ], - "properties": { - "error": { - "type": "string", - "format": "error", - "title": "Error Message", - "description": "Error message.", - "example": "An error has occurred, the details of the error are ...", - "maxLength": 60000, - "minLength": 1, - "pattern": "^(.){1,60000}$" - } - }, - "example": { - "error": "Invalid request query parameters" - } - }, - "ServiceUnavailable": { - "type": "object", - "description": "The service is not available, try again later.\n\n*This is returned when the service either has not started,\nor has become unavailable.*", - "required": [ - "id", - "msg" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "title": "Error Unique ID", - "description": "Unique ID of this Server Error so that it can be located easily for debugging.", - "example": "6689f242-36ab-4919-b6d3-b3dc9e5172d6" - }, - "msg": { - "type": "string", - "format": "error", - "title": "Error Message", - "description": "Error message.", - "example": "An error has occurred, the details of the error are ...", - "maxLength": 60000, - "minLength": 1, - "pattern": "^(.){1,60000}$" - } - }, - "example": { - "id": "e531ac31-0b13-4c16-9942-493e91561f75", - "msg": "Service Unavailable. Indicates that the server is not ready to handle the request." - } - }, - "StakeInfo": { - "type": "object", - "description": "User's cardano stake info.", - "required": [ - "ada_amount", - "slot_number", - "assets" - ], - "properties": { - "ada_amount": { - "type": "integer", - "format": "u64", - "title": "Cardano Blockchain ADA coins value", - "description": "Total stake amount.", - "example": 1234567, - "maximum": 1.8446744073709552e19, - "minimum": 0.0 - }, - "slot_number": { - "type": "integer", - "format": "u64", - "title": "Cardano Blockchain Slot Number", - "description": "Block's slot number which contains the latest unspent UTXO.", - "example": 1234567, - "maximum": 9.223372036854776e18, - "minimum": 0.0 - }, - "assets": { - "type": "array", - "description": "TXO assets infos.", - "items": { - "$ref": "#/components/schemas/StakedTxoAssetInfo" - }, - "example": [ - { - "amount": 1234567, - "asset_name": "My Cool\nAsset", - "policy_hash": "0x8eee77e5894c22268d5d12e6484ba713e7ddd595abba308d88d36943" - } - ], - "maxItems": 1000 - } - }, - "example": { - "ada_amount": 1234567, - "assets": [], - "slot_number": 1234567 - } - }, - "StakedTxoAssetInfo": { - "type": "object", - "description": "User's staked txo asset info.", - "required": [ - "policy_hash", - "asset_name", - "amount" - ], - "properties": { - "policy_hash": { - "type": "string", - "format": "hex:hash(28)", - "title": "28 Byte Hash", - "description": "Asset policy hash (28 bytes).", - "example": "0x8eee77e5894c22268d5d12e6484ba713e7ddd595abba308d88d36943", - "maxLength": 58, - "minLength": 58, - "pattern": "^0x[A-Fa-f0-9]{56}$" - }, - "asset_name": { - "type": "string", - "format": "cardano:asset_name", - "title": "Cardano Native Asset Name", - "description": "Token policies Asset Name.", - "example": "My Cool\nAsset", - "maxLength": 128, - "minLength": 0, - "pattern": "^[\\S\\s]{0,128}$" - }, - "amount": { - "type": "integer", - "format": "i128", - "title": "Cardano native Asset Value", - "description": "Token Asset Value.", - "example": 1234567, - "maximum": 9.223372036854776e18, - "minimum": -9.223372036854776e18 - } - }, - "example": { - "amount": 1234567, - "asset_name": "My Cool\nAsset", - "policy_hash": "0x8eee77e5894c22268d5d12e6484ba713e7ddd595abba308d88d36943" - } - }, - "TooManyRequests": { - "type": "object", - "description": "The client has sent too many requests in a given amount of time.", - "required": [ - "id", - "msg" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "title": "Error Unique ID", - "description": "Unique ID of this Server Error so that it can be located easily for debugging.", - "example": "3bea8f8c-62bd-4f2a-ad45-f80524b09426" - }, - "msg": { - "type": "string", - "format": "error", - "title": "Error Message", - "description": "Error message.", - "example": "An error has occurred, the details of the error are ...", - "maxLength": 60000, - "minLength": 1, - "pattern": "^(.){1,60000}$" - } - }, - "example": { - "id": "58a8b428-8691-4045-b4bc-db3decd56460", - "msg": "Too Many Requests. You have exceeded the rate limit for this endpoint." - } - }, - "Unauthorized": { - "type": "object", - "description": "The client has not sent valid authentication credentials for the requested\nresource.", - "required": [ - "id", - "msg" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "title": "Error Unique ID", - "description": "Unique ID of this Server Error so that it can be located easily for debugging.", - "example": "a91449f9-12fe-449b-b653-dd2dc0762ece" - }, - "msg": { - "type": "string", - "format": "error", - "title": "Error Message", - "description": "Error message.", - "example": "An error has occurred, the details of the error are ...", - "maxLength": 60000, - "minLength": 1, - "pattern": "^(.){1,60000}$" - } - }, - "example": { - "id": "1671d673-c466-4102-95b5-53d79fc9875c", - "msg": "Your request was not successful because it lacks valid authentication credentials for the requested resource." - } - }, - "VerEq": { - "type": "object", - "description": "A single Document IDs.", - "required": [ - "eq" - ], - "properties": { - "eq": { - "type": "string", - "format": "uuidv7", - "title": "Signed Document Version", - "description": "The exact Document ID to match against.", - "externalDocs": { - "url": "https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver", - "description": "Specification" - }, - "example": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - } - }, - "example": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - "VerRange": { - "type": "object", - "description": "Version Range\n\nA Range of document versions from minimum to maximum inclusive.", - "required": [ - "min", - "max" - ], - "properties": { - "min": { - "type": "string", - "format": "uuidv7", - "title": "Signed Document Version", - "description": "Minimum Document Version to find (inclusive)", - "externalDocs": { - "url": "https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver", - "description": "Specification" - }, - "example": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - }, - "max": { - "type": "string", - "format": "uuidv7", - "title": "Signed Document Version", - "description": "Maximum Document Version to find (inclusive)", - "externalDocs": { - "url": "https://input-output-hk.github.io/catalyst-libs/architecture/08_concepts/signed_doc/spec/#ver", - "description": "Specification" - }, - "example": "01944e87-e68c-7f22-9df1-816863cfa5ff", - "maxLength": 36, - "minLength": 36, - "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" - } - }, - "example": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - }, - "VerRefWithOptionalId": { - "type": "object", - "description": "A Reference to a Document ID/s and their version/s.", - "required": [ - "ver" - ], - "properties": { - "id": { - "title": "Document ID Selector", - "description": "Document ID, or range of Document IDs", - "allOf": [ - { - "$ref": "#/components/schemas/IdSelector" - }, - { - "title": "Document ID Selector", - "description": "Either a Single Document ID, or a Range of Document IDs, or Inclusion from the List of\nIDs", - "example": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - } - ], - "example": { - "eq": "01944e87-e68c-7f22-9df1-816863cfa5ff" - } - }, - "ver": { - "title": "Document Version Selector", - "description": "Document Version, or Range of Document Versions", - "allOf": [ - { - "$ref": "#/components/schemas/EqOrRangedVer" - }, - { - "title": "Document Version Selector", - "description": "Either a absolute single Document Version or a range of Document Versions", - "example": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - ], - "example": { - "max": "01944e87-e68c-7f22-9df1-000000000000", - "min": "01944e87-e68c-7f22-9df1-ffffffffffff" - } - } - } - } - }, - "securitySchemes": { - "CatalystRBACSecurityScheme": { - "type": "http", - "description": "Catalyst RBAC Access Token", - "scheme": "bearer", - "bearerFormat": "catalyst-rbac-token" - }, - "NoAuthorization": { - "type": "http", - "description": "Endpoint can be used without any authorization.", - "scheme": "none" - } - } - } -} \ No newline at end of file diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/openapi/cat-reviews.json b/catalyst_voices/packages/internal/catalyst_voices_repositories/openapi/cat-reviews.json deleted file mode 100644 index 541a3cd4137d..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/openapi/cat-reviews.json +++ /dev/null @@ -1,6433 +0,0 @@ -{ - "openapi": "3.1.0", - "info": { - "title": "Catalyst Reviews", - "version": "0.1.0" - }, - "paths": { - "/api/moderations/": { - "post": { - "tags": [ - "moderations" - ], - "summary": "Moderations:Create-Moderation", - "description": "Create a new moderation.", - "operationId": "moderations_create_moderation_api_moderations__post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_moderations_create_moderation_api_moderations__post" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModerationPublic" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/moderations/{id}/": { - "put": { - "tags": [ - "moderations" - ], - "summary": "Moderations:Update-Moderation-By-Id", - "description": "Update a moderation given an id.", - "operationId": "moderations_update_moderation_by_id_api_moderations__id___put", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The ID of the moderation to update." - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_moderations_update_moderation_by_id_api_moderations__id___put" - } - } - } - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModerationPublic" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - }, - "delete": { - "tags": [ - "moderations" - ], - "summary": "Moderations:Delete-Moderation-By-Id", - "description": "Delete a moderation given an id.", - "operationId": "moderations_delete_moderation_by_id_api_moderations__id___delete", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The ID of the moderation to delete." - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "integer", - "title": "Response Moderations Delete Moderation By Id Api Moderations Id Delete" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/moderations/stats/": { - "get": { - "tags": [ - "moderations" - ], - "summary": "Moderations:Get-Stats", - "description": "Get the stats for the moderations.", - "operationId": "moderations_get_stats_api_moderations_stats__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModerationStatsPublic" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/moderations/moderator-stats/": { - "get": { - "tags": [ - "moderations" - ], - "summary": "Moderations:Get-Moderator-Stats", - "description": "Get the stats for the moderators.", - "operationId": "moderations_get_moderator_stats_api_moderations_moderator_stats__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/ModeratorStatsPublic" - }, - "type": "array", - "title": "Response Moderations Get Moderator Stats Api Moderations Moderator Stats Get" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/moderations/export/csv": { - "get": { - "tags": [ - "moderations" - ], - "summary": "Moderations:Csv Export", - "description": "Export the reviews with moderation info.", - "operationId": "moderations_csv_export_api_moderations_export_csv_get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/ModerationInDB" - }, - "type": "array", - "title": "Response Moderations Csv Export Api Moderations Export Csv Get" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/moderations/by-review/{review_id}/": { - "get": { - "tags": [ - "moderations" - ], - "summary": "Moderations:Get-Moderations-By-Review", - "description": "Get all moderations for a specific review.", - "operationId": "moderations_get_moderations_by_review_api_moderations_by_review__review_id___get", - "parameters": [ - { - "name": "review_id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The ID of the review to get moderations for." - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ModerationPublic" - }, - "title": "Response Moderations Get Moderations By Review Api Moderations By Review Review Id Get" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/moderations/generate-allocations": { - "post": { - "tags": [ - "moderations" - ], - "summary": "Moderations:Generate-Allocations", - "description": "Generate moderation allocations.", - "operationId": "moderations_generate_allocations_api_moderations_generate_allocations_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_moderations_generate_allocations_api_moderations_generate_allocations_post" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModerationAllocationStats" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/categories/": { - "get": { - "tags": [ - "categories" - ], - "summary": "Categories:Get-All-Categories", - "description": "Get all categories.", - "operationId": "categories_get_all_categories_api_categories__get", - "parameters": [ - { - "name": "event_id", - "in": "query", - "required": false, - "schema": { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "null" - } - ], - "description": "Used to determine the page to display", - "title": "Event Id" - }, - "description": "Used to determine the page to display" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CategoryPublic" - }, - "title": "Response Categories Get All Categories Api Categories Get" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposals/count/": { - "get": { - "tags": [ - "proposals" - ], - "summary": "Proposals:Get-All-Proposals-Count", - "description": "Get count of all proposals.", - "operationId": "proposals_get_all_proposals_count_api_proposals_count__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "integer", - "title": "Response Proposals Get All Proposals Count Api Proposals Count Get" - } - } - } - } - } - } - }, - "/api/proposals/{id}/": { - "get": { - "tags": [ - "proposals" - ], - "summary": "Proposals:Get-Proposal-By-Id", - "description": "Get a proposal by id.", - "operationId": "proposals_get_proposal_by_id_api_proposals__id___get", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The ID of the proposal to get." - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProposalPublic" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposals/{id}/submitted-review/": { - "get": { - "tags": [ - "proposals" - ], - "summary": "Proposals:Get-Submitted-Review-By-Proposal-Id", - "description": "Get a review submitted for a proposal by proposal_id.", - "operationId": "proposals_get_submitted_review_by_proposal_id_api_proposals__id__submitted_review__get", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The ID of the proposal to get the review for." - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProposalReviewPublic" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposals/": { - "get": { - "tags": [ - "proposals" - ], - "summary": "Proposals:Get-All-Proposals", - "description": "Get all proposals.", - "operationId": "proposals_get_all_proposals_api_proposals__get", - "parameters": [ - { - "name": "size", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "maximum": 50, - "minimum": 1, - "description": "Used to determine how many proposals returns in the response", - "default": 20, - "title": "Size" - }, - "description": "Used to determine how many proposals returns in the response" - }, - { - "name": "page", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "minimum": 0, - "description": "Used to determine the page to display", - "default": 0, - "title": "Page" - }, - "description": "Used to determine the page to display" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProposalPublic" - }, - "title": "Response Proposals Get All Proposals Api Proposals Get" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposals/allocated": { - "get": { - "tags": [ - "proposals" - ], - "summary": "Proposals:Get-Allocated-Proposals", - "description": "Get all proposals allocated to the current user.", - "operationId": "proposals_get_allocated_proposals_api_proposals_allocated_get", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "size", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "maximum": 50, - "minimum": 1, - "description": "Used to determine how many allocated proposals returns in the response", - "default": 20, - "title": "Size" - }, - "description": "Used to determine how many allocated proposals returns in the response" - }, - { - "name": "page", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "minimum": 0, - "description": "Used to determine the page to display", - "default": 0, - "title": "Page" - }, - "description": "Used to determine the page to display" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProposalPublic" - }, - "title": "Response Proposals Get Allocated Proposals Api Proposals Allocated Get" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposals/allocated/count": { - "get": { - "tags": [ - "proposals" - ], - "summary": "Proposals:Get-Allocated-Proposals-Count", - "description": "Get count of all proposals allocated to the current user.", - "operationId": "proposals_get_allocated_proposals_count_api_proposals_allocated_count_get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "integer", - "title": "Response Proposals Get Allocated Proposals Count Api Proposals Allocated Count Get" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/proposals/import/{event}": { - "post": { - "tags": [ - "proposals" - ], - "summary": "Proposals:Import", - "description": "Import proposals in a specific event.", - "operationId": "proposals_import_api_proposals_import__event__post", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "event", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The event where to store proposals and categories." - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "boolean", - "title": "Response Proposals Import Api Proposals Import Event Post" - } - } - } - }, - "401": { - "description": "Not authorized." - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposals/generate-results": { - "post": { - "tags": [ - "proposals" - ], - "summary": "Proposals:Generate-Results", - "description": "Generate reviews results.", - "operationId": "proposals_generate_results_api_proposals_generate_results_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_proposals_generate_results_api_proposals_generate_results_post" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProposalResultsPublic" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/proposal-reviews/": { - "post": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Create-Proposal-Review", - "description": "Create a new proposal_review.", - "operationId": "proposal_reviews_create_proposal_review_api_proposal_reviews__post", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_proposal_reviews_create_proposal_review_api_proposal_reviews__post" - } - } - } - }, - "responses": { - "201": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProposalReviewPublic" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - }, - "get": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Get-All-Proposal-Reviews", - "description": "Get all proposal_reviews.", - "operationId": "proposal_reviews_get_all_proposal_reviews_api_proposal_reviews__get", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "size", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "maximum": 50, - "minimum": 1, - "description": "Used to determine how many reviews returns in the response", - "default": 20, - "title": "Size" - }, - "description": "Used to determine how many reviews returns in the response" - }, - { - "name": "page", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "minimum": 0, - "description": "Used to determine the page to display", - "default": 0, - "title": "Page" - }, - "description": "Used to determine the page to display" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProposalReviewPublic" - }, - "title": "Response Proposal Reviews Get All Proposal Reviews Api Proposal Reviews Get" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposal-reviews/count/": { - "get": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Get-Proposal-Reviews-Count", - "description": "Get the count of all proposal_reviews allocated for moderation to the current user.", - "operationId": "proposal_reviews_get_proposal_reviews_count_api_proposal_reviews_count__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "integer", - "title": "Response Proposal Reviews Get Proposal Reviews Count Api Proposal Reviews Count Get" - } - } - } - } - } - } - }, - "/api/proposal-reviews/moderated/": { - "get": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Get-Moderated-Proposal-Reviews", - "description": "Get all proposal_reviews moderated by the current user.", - "operationId": "proposal_reviews_get_moderated_proposal_reviews_api_proposal_reviews_moderated__get", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "size", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "maximum": 50, - "minimum": 1, - "description": "Used to determine how many reviews returns in the response", - "default": 20, - "title": "Size" - }, - "description": "Used to determine how many reviews returns in the response" - }, - { - "name": "page", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "minimum": 0, - "description": "Used to determine the page to display", - "default": 0, - "title": "Page" - }, - "description": "Used to determine the page to display" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProposalReviewPublic" - }, - "title": "Response Proposal Reviews Get Moderated Proposal Reviews Api Proposal Reviews Moderated Get" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposal-reviews/moderated/count/": { - "get": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Get-Moderated-Proposal-Reviews-Count", - "description": "Get the count of all proposal_reviews moderated by the current user.", - "operationId": "proposal_reviews_get_moderated_proposal_reviews_count_api_proposal_reviews_moderated_count__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "integer", - "title": "Response Proposal Reviews Get Moderated Proposal Reviews Count Api Proposal Reviews Moderated Count Get" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/proposal-reviews/allocated/": { - "get": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Get-Allocated-Proposal-Reviews", - "description": "Get all proposal_reviews allocated to the current user for moderation.", - "operationId": "proposal_reviews_get_allocated_proposal_reviews_api_proposal_reviews_allocated__get", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "size", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "maximum": 50, - "minimum": 1, - "description": "Used to determine how many reviews returns in the response", - "default": 20, - "title": "Size" - }, - "description": "Used to determine how many reviews returns in the response" - }, - { - "name": "page", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "minimum": 0, - "description": "Used to determine the page to display", - "default": 0, - "title": "Page" - }, - "description": "Used to determine the page to display" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProposalReviewPublic" - }, - "title": "Response Proposal Reviews Get Allocated Proposal Reviews Api Proposal Reviews Allocated Get" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposal-reviews/allocated/count/": { - "get": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Get-Allocated-Proposal-Reviews-Count", - "description": "Get the count of all proposal_reviews allocated for moderation to the current user.", - "operationId": "proposal_reviews_get_allocated_proposal_reviews_count_api_proposal_reviews_allocated_count__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "integer", - "title": "Response Proposal Reviews Get Allocated Proposal Reviews Count Api Proposal Reviews Allocated Count Get" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/proposal-reviews/by-ids/": { - "get": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Get-Proposal-Reviews-By-Ids", - "description": "Get proposal_reviews by ids.", - "operationId": "proposal_reviews_get_proposal_reviews_by_ids_api_proposal_reviews_by_ids__get", - "parameters": [ - { - "name": "ids", - "in": "query", - "required": false, - "schema": { - "type": "array", - "items": { - "type": "integer" - }, - "description": "Used to indicated the ids to fetch", - "default": [], - "title": "Ids" - }, - "description": "Used to indicated the ids to fetch" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProposalReviewPublic" - }, - "title": "Response Proposal Reviews Get Proposal Reviews By Ids Api Proposal Reviews By Ids Get" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposal-reviews/filtered/": { - "get": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Get-All-Proposal-Reviews-Filtered", - "description": "Get all proposal_reviews.", - "operationId": "proposal_reviews_get_all_proposal_reviews_filtered_api_proposal_reviews_filtered__get", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "size", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "maximum": 50, - "minimum": 1, - "description": "Used to determine how many reviews returns in the response", - "default": 20, - "title": "Size" - }, - "description": "Used to determine how many reviews returns in the response" - }, - { - "name": "page", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "minimum": 0, - "description": "Used to determine the page to display", - "default": 0, - "title": "Page" - }, - "description": "Used to determine the page to display" - }, - { - "name": "assessor", - "in": "query", - "required": false, - "schema": { - "type": "string", - "description": "Used to filter by assessor", - "title": "Assessor" - }, - "description": "Used to filter by assessor" - }, - { - "name": "proposal", - "in": "query", - "required": false, - "schema": { - "type": "string", - "description": "Used to filter by proposal title", - "title": "Proposal" - }, - "description": "Used to filter by proposal title" - }, - { - "name": "proposal_id", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "description": "Used to filter by proposal ID", - "title": "Proposal Id" - }, - "description": "Used to filter by proposal ID" - }, - { - "name": "objective", - "in": "query", - "required": false, - "schema": { - "type": "string", - "description": "Used to filter by objective", - "title": "Objective" - }, - "description": "Used to filter by objective" - }, - { - "name": "rankings_included", - "in": "query", - "required": false, - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProposalReviewRanking" - }, - "description": "Rankings to include in the filter", - "default": [ - 1 - ], - "title": "Rankings Included" - }, - "description": "Rankings to include in the filter" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProposalReviewPublic" - }, - "title": "Response Proposal Reviews Get All Proposal Reviews Filtered Api Proposal Reviews Filtered Get" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposal-reviews/filtered/count/": { - "get": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Get-All-Proposal-Reviews-Filtered-Count", - "description": "Get all proposal_reviews.", - "operationId": "proposal_reviews_get_all_proposal_reviews_filtered_count_api_proposal_reviews_filtered_count__get", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "assessor", - "in": "query", - "required": false, - "schema": { - "type": "string", - "description": "Used to filter by assessor", - "title": "Assessor" - }, - "description": "Used to filter by assessor" - }, - { - "name": "proposal", - "in": "query", - "required": false, - "schema": { - "type": "string", - "description": "Used to filter by proposal title", - "title": "Proposal" - }, - "description": "Used to filter by proposal title" - }, - { - "name": "proposal_id", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "description": "Used to filter by proposal ID", - "title": "Proposal Id" - }, - "description": "Used to filter by proposal ID" - }, - { - "name": "objective", - "in": "query", - "required": false, - "schema": { - "type": "string", - "description": "Used to filter by objective", - "title": "Objective" - }, - "description": "Used to filter by objective" - }, - { - "name": "rankings_included", - "in": "query", - "required": false, - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProposalReviewRanking" - }, - "description": "Rankings to include in the filter", - "default": [ - 1 - ], - "title": "Rankings Included" - }, - "description": "Rankings to include in the filter" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "integer", - "title": "Response Proposal Reviews Get All Proposal Reviews Filtered Count Api Proposal Reviews Filtered Count Get" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposal-reviews/{id}/": { - "get": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Get-Proposal-Review-By-Id", - "description": "Get a proposal_review by id.", - "operationId": "proposal_reviews_get_proposal_review_by_id_api_proposal_reviews__id___get", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The ID of the proposal_review to get." - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProposalReviewPublic" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - }, - "put": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Update-Proposal-Review-By-Id", - "description": "Update a proposal_review given an id.", - "operationId": "proposal_reviews_update_proposal_review_by_id_api_proposal_reviews__id___put", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The ID of the proposal_review to update." - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_proposal_reviews_update_proposal_review_by_id_api_proposal_reviews__id___put" - } - } - } - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProposalReviewPublic" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - }, - "delete": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Delete-Proposal-Review-By-Id", - "description": "Delete a proposal_review given an id.", - "operationId": "proposal_reviews_delete_proposal_review_by_id_api_proposal_reviews__id___delete", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The ID of the proposal review to delete." - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "integer", - "title": "Response Proposal Reviews Delete Proposal Review By Id Api Proposal Reviews Id Delete" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposal-reviews/export/csv/{event}/": { - "get": { - "tags": [ - "proposal reviews" - ], - "summary": "Moderations:Csv Export", - "description": "Export the reviews with moderation info.", - "operationId": "moderations_csv_export_api_proposal_reviews_export_csv__event___get", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "event", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The ID of the event to fetch." - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/LightProposalReviewModerated" - }, - "title": "Response Moderations Csv Export Api Proposal Reviews Export Csv Event Get" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposal-reviews/export/full-csv/{event}": { - "get": { - "tags": [ - "proposal reviews" - ], - "summary": "Moderations:Csv Export", - "description": "Export the full reviews with moderation info.", - "operationId": "moderations_csv_export_api_proposal_reviews_export_full_csv__event__get", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "event", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The ID of the event to fetch." - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProposalReviewModerated" - }, - "title": "Response Moderations Csv Export Api Proposal Reviews Export Full Csv Event Get" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/proposal-reviews/generate-allocations": { - "post": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Generate-Allocations", - "description": "Generate reviews allocations.", - "operationId": "proposal_reviews_generate_allocations_api_proposal_reviews_generate_allocations_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_proposal_reviews_generate_allocations_api_proposal_reviews_generate_allocations_post" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReviewsAllocationStats" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/proposal-reviews/generate-results": { - "post": { - "tags": [ - "proposal reviews" - ], - "summary": "Proposal-Reviews:Generate-Results", - "description": "Generate reviews results.", - "operationId": "proposal_reviews_generate_results_api_proposal_reviews_generate_results_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_proposal_reviews_generate_results_api_proposal_reviews_generate_results_post" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProposalReviewResults" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/users/": { - "post": { - "tags": [ - "users" - ], - "summary": "Users:Register-New-User", - "description": "Register a new user.", - "operationId": "users_register_new_user_api_users__post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_users_register_new_user_api_users__post" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "boolean", - "title": "Response Users Register New User Api Users Post" - } - } - } - }, - "501": { - "description": "Not implemented." - }, - "404": { - "description": "CatalystID not found." - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/users/token/login": { - "post": { - "tags": [ - "users" - ], - "summary": "Users:Login-Email-And-Password", - "description": "Login with email and password and return access token.", - "operationId": "users_login_email_and_password_api_users_token_login_post", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/Body_users_login_email_and_password_api_users_token_login_post" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccessToken" - } - } - } - }, - "401": { - "description": "Not authorized." - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/users/token/refresh": { - "get": { - "tags": [ - "users" - ], - "summary": "Users:Refresh-Token", - "description": "Get the refresh token for an authorized user.", - "operationId": "users_refresh_token_api_users_token_refresh_get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccessToken" - } - } - } - }, - "401": { - "description": "Not authorized." - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/users/me/": { - "get": { - "tags": [ - "users" - ], - "summary": "Users:Get-Current-User", - "description": "Get the currently authenticated user (if any).", - "operationId": "users_get_current_user_api_users_me__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserInfo" - } - } - } - }, - "401": { - "description": "Not authorized." - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/users/password/update": { - "post": { - "tags": [ - "users" - ], - "summary": "Users:Update-Password", - "description": "Update the password of a user.", - "operationId": "users_update_password_api_users_password_update_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_users_update_password_api_users_password_update_post" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccessToken" - } - } - } - }, - "401": { - "description": "Not authorized." - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/users/password/reset": { - "post": { - "tags": [ - "users" - ], - "summary": "Users:Reset-Password", - "description": "Update the password of a user.", - "operationId": "users_reset_password_api_users_password_reset_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_users_reset_password_api_users_password_reset_post" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "boolean", - "title": "Response Users Reset Password Api Users Password Reset Post" - } - } - } - }, - "404": { - "description": "User not found." - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/users/activate": { - "post": { - "tags": [ - "users" - ], - "summary": "Users:Activate", - "description": "Activate the current user.", - "operationId": "users_activate_api_users_activate_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_users_activate_api_users_activate_post" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "boolean", - "title": "Response Users Activate Api Users Activate Post" - } - } - } - }, - "401": { - "description": "Not authorized." - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/users/password/reset-request": { - "post": { - "tags": [ - "users" - ], - "summary": "Users:Password-Reset-Request", - "description": "Request the password reset for a new user.", - "operationId": "users_password_reset_request_api_users_password_reset_request_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_users_password_reset_request_api_users_password_reset_request_post" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "boolean", - "title": "Response Users Password Reset Request Api Users Password Reset Request Post" - } - } - } - }, - "501": { - "description": "Not implemented." - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/email/send/": { - "post": { - "tags": [ - "emails" - ], - "summary": "Emails:Send", - "description": "Endpoint to be used to send out HTML emails. Acts as email gateway only for admins.", - "operationId": "emails_send_api_email_send__post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_emails_send_api_email_send__post" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "boolean", - "title": "Response Emails Send Api Email Send Post" - } - } - } - }, - "401": { - "description": "Not authorized." - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/configs/current-event/": { - "get": { - "tags": [ - "config" - ], - "summary": "Configs:Current-Event", - "description": "Get the current active event.", - "operationId": "configs_current_event_api_configs_current_event__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CurrentEventPublic" - } - } - } - } - } - } - }, - "/api/configs/current-event/{event}/": { - "put": { - "tags": [ - "config" - ], - "summary": "Configs:Edit-Current-Event", - "description": "Edit current event config.", - "operationId": "configs_edit_current_event_api_configs_current_event__event___put", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "event", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The event of the reviews config to get." - } - } - ], - "responses": { - "201": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CurrentEventPublic" - } - } - } - }, - "501": { - "description": "Not implemented." - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/configs/reviews/{event}/": { - "put": { - "tags": [ - "config" - ], - "summary": "Configs:Edit-Reviews", - "description": "Edit moderation config.", - "operationId": "configs_edit_reviews_api_configs_reviews__event___put", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "event", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The event of the reviews config to update." - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_configs_edit_reviews_api_configs_reviews__event___put" - } - } - } - }, - "responses": { - "201": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ConfigPublic" - } - } - } - }, - "501": { - "description": "Not implemented." - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - }, - "get": { - "tags": [ - "config" - ], - "summary": "Configs:Get-Reviews", - "description": "Get a proposal by id.", - "operationId": "configs_get_reviews_api_configs_reviews__event___get", - "parameters": [ - { - "name": "event", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The event of the reviews config to get." - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ConfigPublic" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/configs/reviews-level-qualifiers/{event}/": { - "get": { - "tags": [ - "config" - ], - "summary": "Configs:Get-Level-Qualifiers", - "description": "Get a proposal by id.", - "operationId": "configs_get_level_qualifiers_api_configs_reviews_level_qualifiers__event___get", - "parameters": [ - { - "name": "event", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The event of the reviews config to get." - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReviewsLevelQualifiersPublic" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - }, - "put": { - "tags": [ - "config" - ], - "summary": "Configs:Edit-Reviews-Level-Qualifiers", - "description": "Edit level qualifiers config.", - "operationId": "configs_edit_reviews_level_qualifiers_api_configs_reviews_level_qualifiers__event___put", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "event", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The event of the reviews level qualifiers config to update." - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_configs_edit_reviews_level_qualifiers_api_configs_reviews_level_qualifiers__event___put" - } - } - } - }, - "responses": { - "201": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ConfigPublic" - } - } - } - }, - "501": { - "description": "Not implemented." - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/configs/allocations/{event}/": { - "get": { - "tags": [ - "config" - ], - "summary": "Configs:Get-Allocation-Generation", - "description": "Get a proposal by id.", - "operationId": "configs_get_allocation_generation_api_configs_allocations__event___get", - "parameters": [ - { - "name": "event", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The event of the reviews config to get." - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AllocationGenerationPublic" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/sumsub/webhook/": { - "post": { - "tags": [ - "sumsub" - ], - "summary": "Sumsub:Webhook", - "description": "Endpoint to be used to receive Webhooks from SumSub.", - "operationId": "sumsub_webhook_api_sumsub_webhook__post", - "parameters": [ - { - "name": "x-payload-digest-alg", - "in": "header", - "required": false, - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SumSubDigestAlg" - }, - { - "type": "null" - } - ], - "title": "X-Payload-Digest-Alg" - } - }, - { - "name": "x-payload-digest", - "in": "header", - "required": false, - "schema": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "X-Payload-Digest" - } - } - ], - "responses": { - "201": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "401": { - "description": "Not authorized." - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/subscriptions/": { - "post": { - "tags": [ - "reviewers subscriptions" - ], - "summary": "Reviewer-Subscription:Create", - "description": "Endpoint to be create a reviewer subscription.", - "operationId": "reviewer_subscription_create_api_subscriptions__post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_reviewer_subscription_create_api_subscriptions__post" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/ReviewerSubscriptionPublic" - }, - "type": "array", - "title": "Response Reviewer Subscription Create Api Subscriptions Post" - } - } - } - }, - "401": { - "description": "Not authorized." - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/subscriptions/invitation": { - "post": { - "tags": [ - "reviewers subscriptions" - ], - "summary": "Reviewer-Subscription:Invitation", - "description": "Endpoint to be accept/refuse a reviewer subscription invitation.", - "operationId": "reviewer_subscription_invitation_api_subscriptions_invitation_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_reviewer_subscription_invitation_api_subscriptions_invitation_post" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/ReviewerSubscriptionPublic" - }, - "type": "array", - "title": "Response Reviewer Subscription Invitation Api Subscriptions Invitation Post" - } - } - } - }, - "401": { - "description": "Not authorized." - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/catalyst-ids/me": { - "get": { - "tags": [ - "catalyst ids" - ], - "summary": "Catalyst-Ids:Get-By-Current-User", - "description": "Get a catalyst id from request.", - "operationId": "catalyst_ids_get_by_current_user_api_catalyst_ids_me_get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalystIDPublic" - } - } - } - } - }, - "security": [ - { - "HTTPBearer": [] - } - ] - }, - "post": { - "tags": [ - "catalyst ids" - ], - "summary": "Catalyst-Ids:Post-Info", - "description": "Update info associated with a catalyst id.", - "operationId": "catalyst_ids_post_info_api_catalyst_ids_me_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalystIDCreate" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalystIDPublic" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - }, - "security": [ - { - "HTTPBearer": [] - } - ] - } - }, - "/api/catalyst-ids/verify-email": { - "post": { - "tags": [ - "catalyst ids" - ], - "summary": "Catalyst-Ids:Verify-Email", - "description": "Verify the email address for a user.", - "operationId": "catalyst_ids_verify_email_api_catalyst_ids_verify_email_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_catalyst_ids_verify_email_api_catalyst_ids_verify_email_post" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "boolean", - "title": "Response Catalyst Ids Verify Email Api Catalyst Ids Verify Email Post" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/events/": { - "get": { - "tags": [ - "events" - ], - "summary": "Events:Get-All-Events", - "description": "Get all events.", - "operationId": "events_get_all_events_api_events__get", - "parameters": [ - { - "name": "size", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "maximum": 50, - "minimum": 1, - "description": "Used to determine how many events returns in the response", - "default": 20, - "title": "Size" - }, - "description": "Used to determine how many events returns in the response" - }, - { - "name": "page", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "minimum": 0, - "description": "Used to determine the page to display", - "default": 0, - "title": "Page" - }, - "description": "Used to determine the page to display" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EventPublic" - }, - "title": "Response Events Get All Events Api Events Get" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - }, - "post": { - "tags": [ - "events" - ], - "summary": "Events-Reviews:Create-Event", - "description": "Create a new event.", - "operationId": "events_reviews_create_event_api_events__post", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_events_reviews_create_event_api_events__post" - } - } - } - }, - "responses": { - "201": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EventPublic" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/events/count/": { - "get": { - "tags": [ - "events" - ], - "summary": "Events:Get-All-Events-Count", - "description": "Get all events count.", - "operationId": "events_get_all_events_count_api_events_count__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "type": "integer", - "title": "Response Events Get All Events Count Api Events Count Get" - } - } - } - } - } - } - }, - "/api/events/current/": { - "get": { - "tags": [ - "events" - ], - "summary": "Events:Get-Current-Events", - "description": "Get all current events.", - "operationId": "events_get_current_events_api_events_current__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/EventPublic" - }, - "type": "array", - "title": "Response Events Get Current Events Api Events Current Get" - } - } - } - } - } - } - }, - "/api/events/{id}/": { - "put": { - "tags": [ - "events" - ], - "summary": "Events-Reviews:Update-Event", - "description": "Update an event.", - "operationId": "events_reviews_update_event_api_events__id___put", - "security": [ - { - "OAuth2PasswordBearer": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "minimum": 1, - "title": "The ID of the event to update." - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_events_reviews_update_event_api_events__id___put" - } - } - } - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EventPublic" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/admin/vitss-export": { - "post": { - "tags": [ - "admin" - ], - "summary": "Admin:Vitss-Export", - "description": "Generate export files for VITss.", - "operationId": "admin_vitss_export_api_admin_vitss_export_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Body_admin_vitss_export_api_admin_vitss_export_post" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - }, - "security": [ - { - "OAuth2PasswordBearer": [] - } - ] - } - }, - "/api/healthz": { - "get": { - "summary": "Endpoint", - "operationId": "endpoint_api_healthz_get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - } - } - } - } - }, - "components": { - "schemas": { - "AccessToken": { - "properties": { - "access_token": { - "type": "string", - "title": "Access Token" - }, - "token_type": { - "type": "string", - "title": "Token Type" - } - }, - "type": "object", - "required": [ - "access_token", - "token_type" - ], - "title": "AccessToken", - "description": "Access token model." - }, - "AllocationGeneration": { - "properties": { - "moderation_allocation_generated": { - "type": "boolean", - "title": "Moderation Allocation Generated", - "default": false - }, - "proposal_allocation_generated": { - "type": "boolean", - "title": "Proposal Allocation Generated", - "default": false - } - }, - "type": "object", - "title": "AllocationGeneration", - "description": "Submodel to store allocation generation per event." - }, - "AllocationGenerationPublic": { - "properties": { - "row_id": { - "type": "integer", - "title": "Row Id" - }, - "config_type": { - "type": "string", - "title": "Config Type" - }, - "event": { - "type": "string", - "title": "Event" - }, - "value": { - "$ref": "#/components/schemas/AllocationGeneration", - "default": { - "moderation_allocation_generated": false, - "proposal_allocation_generated": false - } - } - }, - "type": "object", - "required": [ - "row_id", - "config_type", - "event" - ], - "title": "AllocationGenerationPublic", - "description": "Attributes for ReviewsLevelQualifiers public model in responses." - }, - "AllocationStatsAverages": { - "properties": { - "avg": { - "type": "number", - "title": "Avg", - "default": 0 - }, - "min": { - "type": "integer", - "title": "Min", - "default": 0 - }, - "max": { - "type": "integer", - "title": "Max", - "default": 0 - } - }, - "type": "object", - "title": "AllocationStatsAverages", - "description": "Model for generic averages." - }, - "AllocationStatsReviewers": { - "properties": { - "tot": { - "type": "integer", - "title": "Tot", - "default": 0 - }, - "lv0": { - "type": "integer", - "title": "Lv0", - "default": 0 - }, - "lv1": { - "type": "integer", - "title": "Lv1", - "default": 0 - } - }, - "type": "object", - "title": "AllocationStatsReviewers", - "description": "Model for stats of reviewers." - }, - "AllocationWeights": { - "properties": { - "allocated": { - "type": "number", - "title": "Allocated", - "default": 0.2 - }, - "not_allocated": { - "type": "number", - "title": "Not Allocated", - "default": 0.8 - } - }, - "type": "object", - "title": "AllocationWeights", - "description": "Attributes for the weights to assign to allocation." - }, - "Body_admin_vitss_export_api_admin_vitss_export_post": { - "properties": { - "export_config": { - "$ref": "#/components/schemas/VITssExportConfig" - } - }, - "type": "object", - "required": [ - "export_config" - ], - "title": "Body_admin_vitss_export_api_admin_vitss_export_post" - }, - "Body_catalyst_ids_verify_email_api_catalyst_ids_verify_email_post": { - "properties": { - "email_verification": { - "$ref": "#/components/schemas/UserActivation" - } - }, - "type": "object", - "required": [ - "email_verification" - ], - "title": "Body_catalyst_ids_verify_email_api_catalyst_ids_verify_email_post" - }, - "Body_configs_edit_reviews_api_configs_reviews__event___put": { - "properties": { - "record_update": { - "$ref": "#/components/schemas/ReviewsConfigCreate" - } - }, - "type": "object", - "required": [ - "record_update" - ], - "title": "Body_configs_edit_reviews_api_configs_reviews__event___put" - }, - "Body_configs_edit_reviews_level_qualifiers_api_configs_reviews_level_qualifiers__event___put": { - "properties": { - "record_update": { - "$ref": "#/components/schemas/ReviewsLevelQualifiersCreate" - } - }, - "type": "object", - "required": [ - "record_update" - ], - "title": "Body_configs_edit_reviews_level_qualifiers_api_configs_reviews_level_qualifiers__event___put" - }, - "Body_emails_send_api_email_send__post": { - "properties": { - "new_email": { - "$ref": "#/components/schemas/EmailMsg" - } - }, - "type": "object", - "required": [ - "new_email" - ], - "title": "Body_emails_send_api_email_send__post" - }, - "Body_events_reviews_create_event_api_events__post": { - "properties": { - "new_event": { - "$ref": "#/components/schemas/EventCreate" - } - }, - "type": "object", - "required": [ - "new_event" - ], - "title": "Body_events_reviews_create_event_api_events__post" - }, - "Body_events_reviews_update_event_api_events__id___put": { - "properties": { - "event_update": { - "$ref": "#/components/schemas/EventUpdate" - } - }, - "type": "object", - "required": [ - "event_update" - ], - "title": "Body_events_reviews_update_event_api_events__id___put" - }, - "Body_moderations_create_moderation_api_moderations__post": { - "properties": { - "new_moderation": { - "$ref": "#/components/schemas/ModerationCreate" - } - }, - "type": "object", - "required": [ - "new_moderation" - ], - "title": "Body_moderations_create_moderation_api_moderations__post" - }, - "Body_moderations_generate_allocations_api_moderations_generate_allocations_post": { - "properties": { - "allocation_params": { - "$ref": "#/components/schemas/ModerationAllocationCreate" - } - }, - "type": "object", - "required": [ - "allocation_params" - ], - "title": "Body_moderations_generate_allocations_api_moderations_generate_allocations_post" - }, - "Body_moderations_update_moderation_by_id_api_moderations__id___put": { - "properties": { - "record_update": { - "$ref": "#/components/schemas/ModerationUpdate" - } - }, - "type": "object", - "required": [ - "record_update" - ], - "title": "Body_moderations_update_moderation_by_id_api_moderations__id___put" - }, - "Body_proposal_reviews_create_proposal_review_api_proposal_reviews__post": { - "properties": { - "new_proposal_review": { - "$ref": "#/components/schemas/ProposalReviewCreate" - } - }, - "type": "object", - "required": [ - "new_proposal_review" - ], - "title": "Body_proposal_reviews_create_proposal_review_api_proposal_reviews__post" - }, - "Body_proposal_reviews_generate_allocations_api_proposal_reviews_generate_allocations_post": { - "properties": { - "allocation_params": { - "$ref": "#/components/schemas/ReviewsAllocationCreate" - } - }, - "type": "object", - "required": [ - "allocation_params" - ], - "title": "Body_proposal_reviews_generate_allocations_api_proposal_reviews_generate_allocations_post" - }, - "Body_proposal_reviews_generate_results_api_proposal_reviews_generate_results_post": { - "properties": { - "results_params": { - "$ref": "#/components/schemas/ProposalReviewResultsCreate" - } - }, - "type": "object", - "required": [ - "results_params" - ], - "title": "Body_proposal_reviews_generate_results_api_proposal_reviews_generate_results_post" - }, - "Body_proposal_reviews_update_proposal_review_by_id_api_proposal_reviews__id___put": { - "properties": { - "proposal_review_update": { - "$ref": "#/components/schemas/ProposalReviewUpdate" - } - }, - "type": "object", - "required": [ - "proposal_review_update" - ], - "title": "Body_proposal_reviews_update_proposal_review_by_id_api_proposal_reviews__id___put" - }, - "Body_proposals_generate_results_api_proposals_generate_results_post": { - "properties": { - "results_params": { - "$ref": "#/components/schemas/ProposalResultsCreate" - } - }, - "type": "object", - "required": [ - "results_params" - ], - "title": "Body_proposals_generate_results_api_proposals_generate_results_post" - }, - "Body_reviewer_subscription_create_api_subscriptions__post": { - "properties": { - "new_subscription": { - "$ref": "#/components/schemas/ReviewerSubscriptionCreate" - } - }, - "type": "object", - "required": [ - "new_subscription" - ], - "title": "Body_reviewer_subscription_create_api_subscriptions__post" - }, - "Body_reviewer_subscription_invitation_api_subscriptions_invitation_post": { - "properties": { - "invitation_answer": { - "$ref": "#/components/schemas/ReviewerSubscriptionInvitationAnswerCreate" - } - }, - "type": "object", - "required": [ - "invitation_answer" - ], - "title": "Body_reviewer_subscription_invitation_api_subscriptions_invitation_post" - }, - "Body_users_activate_api_users_activate_post": { - "properties": { - "user_activation": { - "$ref": "#/components/schemas/UserActivation" - } - }, - "type": "object", - "required": [ - "user_activation" - ], - "title": "Body_users_activate_api_users_activate_post" - }, - "Body_users_login_email_and_password_api_users_token_login_post": { - "properties": { - "username": { - "type": "string", - "title": "Username" - }, - "password": { - "type": "string", - "title": "Password" - }, - "scope": { - "type": "string", - "title": "Scope", - "default": "" - }, - "client_id": { - "type": "string", - "title": "Client Id" - }, - "client_secret": { - "type": "string", - "title": "Client Secret" - } - }, - "type": "object", - "required": [ - "username", - "password" - ], - "title": "Body_users_login_email_and_password_api_users_token_login_post" - }, - "Body_users_password_reset_request_api_users_password_reset_request_post": { - "properties": { - "new_user": { - "$ref": "#/components/schemas/UserRequestResetPassword" - } - }, - "type": "object", - "required": [ - "new_user" - ], - "title": "Body_users_password_reset_request_api_users_password_reset_request_post" - }, - "Body_users_register_new_user_api_users__post": { - "properties": { - "new_user": { - "$ref": "#/components/schemas/UserCreate" - } - }, - "type": "object", - "required": [ - "new_user" - ], - "title": "Body_users_register_new_user_api_users__post" - }, - "Body_users_reset_password_api_users_password_reset_post": { - "properties": { - "user_reset": { - "$ref": "#/components/schemas/UserResetPassword" - } - }, - "type": "object", - "required": [ - "user_reset" - ], - "title": "Body_users_reset_password_api_users_password_reset_post" - }, - "Body_users_update_password_api_users_password_update_post": { - "properties": { - "update_user": { - "$ref": "#/components/schemas/UserUpdate" - } - }, - "type": "object", - "required": [ - "update_user" - ], - "title": "Body_users_update_password_api_users_password_update_post" - }, - "CatalystIDCreate": { - "properties": { - "email": { - "type": "string", - "format": "email", - "title": "Email" - }, - "catalyst_id_uri": { - "type": "string", - "title": "Catalyst Id Uri" - } - }, - "type": "object", - "required": [ - "email", - "catalyst_id_uri" - ], - "title": "CatalystIDCreate", - "description": "Model for the creation and the update of the email in DB." - }, - "CatalystIDPublic": { - "properties": { - "_cid": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Cid" - }, - "email": { - "anyOf": [ - { - "type": "string", - "format": "email" - }, - { - "type": "null" - } - ], - "title": "Email" - }, - "username": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Username" - }, - "status": { - "$ref": "#/components/schemas/CatalystIDStatus", - "default": 0 - }, - "rbac_reg_status": { - "$ref": "#/components/schemas/CatalystRBACRegistrationStatus", - "default": 0 - } - }, - "type": "object", - "title": "CatalystIDPublic", - "description": "Model for the CatalystID to expose publicly." - }, - "CatalystIDStatus": { - "type": "integer", - "enum": [ - 0, - 1, - 2, - 3 - ], - "title": "CatalystIDStatus", - "description": "Enum to describe the catalyst_id status.\n\ninactive = 0\nemail_verified = 1\nactive = 2\nbanned = 3" - }, - "CatalystRBACRegistrationStatus": { - "type": "integer", - "enum": [ - 0, - 1, - 2, - 3 - ], - "title": "CatalystRBACRegistrationStatus", - "description": "Enum to describe the rbac registration status.\n\ninitialized = 0\nnot_found = 1\nvolatile = 2\npersistent = 3" - }, - "CategoryInDB": { - "properties": { - "id": { - "type": "string", - "format": "uuid7", - "title": "Id" - }, - "event": { - "type": "integer", - "title": "Event" - }, - "category": { - "$ref": "#/components/schemas/CategoryType", - "default": "simple" - }, - "title": { - "type": "string", - "title": "Title" - }, - "description": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Description", - "default": "" - }, - "rewards_currency": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Rewards Currency" - }, - "proposers_rewards": { - "type": "integer", - "title": "Proposers Rewards", - "default": 0 - }, - "row_id": { - "type": "integer", - "title": "Row Id" - } - }, - "type": "object", - "required": [ - "id", - "event", - "title", - "row_id" - ], - "title": "CategoryInDB", - "description": "Category representation in DB." - }, - "CategoryPublic": { - "properties": { - "id": { - "type": "string", - "format": "uuid7", - "title": "Id" - }, - "event": { - "type": "integer", - "title": "Event" - }, - "category": { - "$ref": "#/components/schemas/CategoryType", - "default": "simple" - }, - "title": { - "type": "string", - "title": "Title" - }, - "description": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Description", - "default": "" - }, - "rewards_currency": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Rewards Currency" - }, - "proposers_rewards": { - "type": "integer", - "title": "Proposers Rewards", - "default": 0 - }, - "row_id": { - "type": "integer", - "title": "Row Id" - } - }, - "type": "object", - "required": [ - "id", - "event", - "title", - "row_id" - ], - "title": "CategoryPublic", - "description": "Publicly exposed attributes." - }, - "CategoryType": { - "type": "string", - "enum": [ - "simple", - "community-choice", - "native" - ], - "title": "CategoryType", - "description": "Enum for available category types." - }, - "ClassificationType": { - "type": "integer", - "enum": [ - 0, - 1 - ], - "title": "ClassificationType", - "description": "Enum to describe possible classification types." - }, - "ConfigPublic": { - "properties": { - "id": { - "type": "string", - "title": "Id" - }, - "id2": { - "type": "string", - "title": "Id2" - }, - "value": { - "$ref": "#/components/schemas/ReviewsSwitches", - "default": { - "user_registration_enabled": false, - "reviewer_subscription_enabled": false, - "review_submission_enabled": false, - "moderation_submission_enabled": false - } - }, - "row_id": { - "type": "integer", - "title": "Row Id" - } - }, - "type": "object", - "required": [ - "id", - "id2", - "row_id" - ], - "title": "ConfigPublic", - "description": "Attributes for the creation/update of configs." - }, - "CurrentEventPublic": { - "properties": { - "row_id": { - "type": "integer", - "title": "Row Id" - }, - "config_type": { - "type": "string", - "title": "Config Type" - }, - "value": { - "type": "integer", - "title": "Value", - "default": 9 - } - }, - "type": "object", - "required": [ - "row_id", - "config_type" - ], - "title": "CurrentEventPublic", - "description": "Attributes for CurrentEvent public model in responses." - }, - "DueDiligence": { - "properties": { - "status": { - "$ref": "#/components/schemas/DueDiligenceStatus", - "default": 0 - }, - "url": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Url" - }, - "applicant_id": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Applicant Id" - }, - "external_id": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "External Id" - }, - "updated_at": { - "type": "number", - "title": "Updated At", - "default": 1744992225.207126 - } - }, - "type": "object", - "title": "DueDiligence", - "description": "Submodel to store data related to the Due Diligence." - }, - "DueDiligencePublic": { - "properties": { - "status": { - "$ref": "#/components/schemas/DueDiligenceStatus", - "default": 0 - }, - "url": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Url" - } - }, - "type": "object", - "title": "DueDiligencePublic", - "description": "Submodel to store data related to the Due Diligence." - }, - "DueDiligenceStatus": { - "type": "integer", - "enum": [ - 0, - 1, - 2, - 3, - 4 - ], - "title": "DueDiligenceStatus", - "description": "Enum to describe possible user roles." - }, - "EmailMsg": { - "properties": { - "subject": { - "type": "string", - "title": "Subject" - }, - "text": { - "type": "string", - "title": "Text" - }, - "html": { - "type": "string", - "title": "Html" - }, - "recipients": { - "items": { - "type": "string", - "format": "email" - }, - "type": "array", - "title": "Recipients" - } - }, - "type": "object", - "required": [ - "subject", - "text", - "html", - "recipients" - ], - "title": "EmailMsg", - "description": "Represents an email message." - }, - "EventCreate": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "description": { - "type": "string", - "title": "Description" - }, - "active": { - "type": "boolean", - "title": "Active" - } - }, - "type": "object", - "required": [ - "name", - "description", - "active" - ], - "title": "EventCreate", - "description": "Model for event creation." - }, - "EventPublic": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "description": { - "type": "string", - "title": "Description" - }, - "active": { - "type": "boolean", - "title": "Active" - }, - "row_id": { - "type": "integer", - "title": "Row Id" - } - }, - "type": "object", - "required": [ - "name", - "description", - "active", - "row_id" - ], - "title": "EventPublic", - "description": "Publicly exposed attributes." - }, - "EventUpdate": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "description": { - "type": "string", - "title": "Description" - }, - "active": { - "type": "boolean", - "title": "Active" - } - }, - "type": "object", - "required": [ - "name", - "description", - "active" - ], - "title": "EventUpdate", - "description": "Model for event update." - }, - "FlagType": { - "type": "integer", - "enum": [ - 0, - 1, - 2 - ], - "title": "FlagType", - "description": "Enum to describe possible flag types." - }, - "HTTPValidationError": { - "properties": { - "detail": { - "items": { - "$ref": "#/components/schemas/ValidationError" - }, - "type": "array", - "title": "Detail" - } - }, - "type": "object", - "title": "HTTPValidationError" - }, - "HistoricStats": { - "properties": { - "reviews": { - "$ref": "#/components/schemas/ReviewHistoricStats", - "default": { - "active_funds": 0, - "submitted": 0, - "blank": 0, - "valid": 0 - } - }, - "moderations": { - "$ref": "#/components/schemas/ModerationsHistoricStats", - "default": { - "active_funds": 0, - "submitted": 0 - } - } - }, - "type": "object", - "title": "HistoricStats", - "description": "Submodel to describe the historic stats." - }, - "LevelQualifier": { - "properties": { - "min_valid_reviews": { - "type": "integer", - "title": "Min Valid Reviews", - "default": 0 - }, - "max_valid_reviews": { - "type": "integer", - "title": "Max Valid Reviews", - "default": 10 - }, - "min_perc_valid_reviews": { - "type": "number", - "title": "Min Perc Valid Reviews", - "default": 0.8 - }, - "max_perc_valid_reviews": { - "type": "number", - "title": "Max Perc Valid Reviews", - "default": 1 - }, - "min_active_funds": { - "type": "integer", - "title": "Min Active Funds", - "default": 0 - }, - "max_active_funds": { - "type": "integer", - "title": "Max Active Funds", - "default": 10 - } - }, - "type": "object", - "title": "LevelQualifier", - "description": "Submodel to store a single level qualifier." - }, - "LevelWeights": { - "properties": { - "level_0": { - "type": "number", - "title": "Level 0", - "default": 1 - }, - "level_1": { - "type": "number", - "title": "Level 1", - "default": 1 - } - }, - "type": "object", - "title": "LevelWeights", - "description": "Attributes for the weights to assign to each level." - }, - "LightProposalReviewModerated": { - "properties": { - "valid": { - "type": "boolean", - "title": "Valid" - }, - "row_id": { - "type": "integer", - "title": "Row Id" - }, - "user_id": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "User Id" - }, - "moderations_tot": { - "type": "integer", - "title": "Moderations Tot" - }, - "moderations_as_valid": { - "type": "integer", - "title": "Moderations As Valid" - } - }, - "type": "object", - "required": [ - "valid", - "row_id", - "moderations_tot", - "moderations_as_valid" - ], - "title": "LightProposalReviewModerated", - "description": "Attributes used to export moderated results." - }, - "ModeratedStatsPublic": { - "properties": { - "by_0": { - "type": "integer", - "title": "By 0" - }, - "by_1": { - "type": "integer", - "title": "By 1" - }, - "by_2": { - "type": "integer", - "title": "By 2" - }, - "by_3": { - "type": "integer", - "title": "By 3" - }, - "by_more": { - "type": "integer", - "title": "By More" - } - }, - "type": "object", - "required": [ - "by_0", - "by_1", - "by_2", - "by_3", - "by_more" - ], - "title": "ModeratedStatsPublic", - "description": "Attributes for the statistic of progressing moderation stage." - }, - "ModerationAllocationCreate": { - "properties": { - "event_id": { - "type": "integer", - "title": "Event Id" - }, - "moderation_seed": { - "type": "integer", - "title": "Moderation Seed", - "default": 42 - }, - "nr_of_moderations_per_review": { - "type": "integer", - "title": "Nr Of Moderations Per Review", - "default": 5 - }, - "min_spot_check_per_reviewer": { - "type": "integer", - "title": "Min Spot Check Per Reviewer", - "default": 10 - }, - "dry_run": { - "type": "boolean", - "title": "Dry Run", - "default": true - } - }, - "type": "object", - "required": [ - "event_id" - ], - "title": "ModerationAllocationCreate", - "description": "Model for the creation of moderators allocation." - }, - "ModerationAllocationStats": { - "properties": { - "tot": { - "type": "integer", - "title": "Tot" - }, - "nr_of_moderators": { - "type": "integer", - "title": "Nr Of Moderators" - }, - "per_reviewer": { - "$ref": "#/components/schemas/AllocationStatsAverages", - "default": { - "avg": 0.0, - "min": 0, - "max": 0 - } - }, - "per_review": { - "$ref": "#/components/schemas/AllocationStatsAverages", - "default": { - "avg": 0.0, - "min": 0, - "max": 0 - } - }, - "per_moderator": { - "$ref": "#/components/schemas/AllocationStatsAverages", - "default": { - "avg": 0.0, - "min": 0, - "max": 0 - } - } - }, - "type": "object", - "required": [ - "tot", - "nr_of_moderators" - ], - "title": "ModerationAllocationStats", - "description": "Model for stats of the allocation for moderators." - }, - "ModerationCreate": { - "properties": { - "review_id": { - "type": "integer", - "title": "Review Id" - }, - "classification": { - "$ref": "#/components/schemas/ClassificationType" - }, - "rationale": { - "type": "string", - "title": "Rationale" - } - }, - "type": "object", - "required": [ - "review_id", - "classification", - "rationale" - ], - "title": "ModerationCreate", - "description": "Attributes required to create a new Moderation.\n\nUsed at POST request." - }, - "ModerationInDB": { - "properties": { - "review_id": { - "type": "integer", - "title": "Review Id" - }, - "classification": { - "$ref": "#/components/schemas/ClassificationType" - }, - "rationale": { - "type": "string", - "title": "Rationale" - }, - "row_id": { - "type": "integer", - "title": "Row Id" - }, - "user_id": { - "type": "integer", - "title": "User Id" - }, - "public_contact": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Public Contact" - } - }, - "type": "object", - "required": [ - "review_id", - "classification", - "rationale", - "row_id", - "user_id" - ], - "title": "ModerationInDB", - "description": "Attributes on any ProposalReview coming from Database." - }, - "ModerationPublic": { - "properties": { - "review_id": { - "type": "integer", - "title": "Review Id" - }, - "classification": { - "$ref": "#/components/schemas/ClassificationType" - }, - "rationale": { - "type": "string", - "title": "Rationale" - }, - "row_id": { - "type": "integer", - "title": "Row Id" - } - }, - "type": "object", - "required": [ - "review_id", - "classification", - "rationale", - "row_id" - ], - "title": "ModerationPublic", - "description": "Attributes that will be returned at any public request." - }, - "ModerationStatsPublic": { - "properties": { - "moderations": { - "type": "integer", - "title": "Moderations" - }, - "allocations": { - "type": "integer", - "title": "Allocations" - }, - "flagged_reviews": { - "type": "integer", - "title": "Flagged Reviews" - }, - "reviews_moderated": { - "$ref": "#/components/schemas/ModeratedStatsPublic" - } - }, - "type": "object", - "required": [ - "moderations", - "allocations", - "flagged_reviews", - "reviews_moderated" - ], - "title": "ModerationStatsPublic", - "description": "Stats for the moderation status." - }, - "ModerationUpdate": { - "properties": { - "review_id": { - "type": "integer", - "title": "Review Id" - }, - "classification": { - "$ref": "#/components/schemas/ClassificationType" - }, - "rationale": { - "type": "string", - "title": "Rationale" - } - }, - "type": "object", - "required": [ - "review_id", - "classification", - "rationale" - ], - "title": "ModerationUpdate", - "description": "Attributes required to update a Moderation.\n\nUsed at PUT request." - }, - "ModerationsHistoricStats": { - "properties": { - "active_funds": { - "type": "integer", - "title": "Active Funds", - "default": 0 - }, - "submitted": { - "type": "integer", - "title": "Submitted", - "default": 0 - } - }, - "type": "object", - "title": "ModerationsHistoricStats", - "description": "Submodel to describe the historic stats as a reviewer." - }, - "ModeratorStatsPublic": { - "properties": { - "user_id": { - "type": "integer", - "title": "User Id" - }, - "reviews_moderated": { - "type": "integer", - "title": "Reviews Moderated" - } - }, - "type": "object", - "required": [ - "user_id", - "reviews_moderated" - ], - "title": "ModeratorStatsPublic", - "description": "Stats for the moderation status." - }, - "PolicyAcknowledgment": { - "properties": { - "privacy_policy": { - "type": "boolean", - "title": "Privacy Policy", - "default": false - }, - "terms_and_conditions": { - "type": "boolean", - "title": "Terms And Conditions", - "default": false - } - }, - "type": "object", - "title": "PolicyAcknowledgment", - "description": "Submodel to store the policy acknowledgments." - }, - "ProposalExtra": { - "properties": { - "fields": { - "items": { - "$ref": "#/components/schemas/ProposalExtraField" - }, - "type": "array", - "title": "Fields", - "default": [] - } - }, - "type": "object", - "title": "ProposalExtra", - "description": "Submodel to store extra info." - }, - "ProposalExtraField": { - "properties": { - "ref": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Ref" - }, - "title": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Title" - }, - "description": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Description" - }, - "answer": { - "anyOf": [ - {}, - { - "type": "null" - } - ], - "title": "Answer" - }, - "sub_fields": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/ProposalExtraField" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Sub Fields" - } - }, - "type": "object", - "title": "ProposalExtraField", - "description": "Submodel to store extra fields." - }, - "ProposalInDB": { - "properties": { - "pr_id": { - "type": "string", - "format": "uuid7", - "title": "Pr Id" - }, - "title": { - "type": "string", - "title": "Title" - }, - "objective": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Objective" - }, - "objective_title": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Objective Title" - }, - "summary": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Summary" - }, - "solution": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Solution" - }, - "proposer_name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Proposer Name" - }, - "proposer_relevant_experience": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Proposer Relevant Experience" - }, - "url": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Url" - }, - "funds": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Funds" - }, - "extra": { - "anyOf": [ - { - "$ref": "#/components/schemas/ProposalExtra" - }, - { - "type": "null" - } - ] - }, - "links": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Links" - }, - "open_source": { - "type": "boolean", - "title": "Open Source", - "default": false - }, - "score": { - "anyOf": [ - { - "$ref": "#/components/schemas/ProposalScore" - }, - { - "type": "null" - } - ] - }, - "public_key": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Public Key" - }, - "files_url": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Files Url" - }, - "row_id": { - "type": "integer", - "title": "Row Id" - } - }, - "type": "object", - "required": [ - "pr_id", - "title", - "row_id" - ], - "title": "ProposalInDB", - "description": "Attributes on any Proposal coming from Database." - }, - "ProposalPublic": { - "properties": { - "pr_id": { - "type": "string", - "format": "uuid7", - "title": "Pr Id" - }, - "title": { - "type": "string", - "title": "Title" - }, - "objective": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Objective" - }, - "objective_title": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Objective Title" - }, - "summary": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Summary" - }, - "solution": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Solution" - }, - "proposer_name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Proposer Name" - }, - "proposer_relevant_experience": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Proposer Relevant Experience" - }, - "url": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Url" - }, - "funds": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Funds" - }, - "extra": { - "anyOf": [ - { - "$ref": "#/components/schemas/ProposalExtra" - }, - { - "type": "null" - } - ] - }, - "links": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Links" - }, - "open_source": { - "type": "boolean", - "title": "Open Source", - "default": false - }, - "score": { - "anyOf": [ - { - "$ref": "#/components/schemas/ProposalScore" - }, - { - "type": "null" - } - ] - }, - "public_key": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Public Key" - }, - "files_url": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Files Url" - }, - "row_id": { - "type": "integer", - "title": "Row Id" - } - }, - "type": "object", - "required": [ - "pr_id", - "title", - "row_id" - ], - "title": "ProposalPublic", - "description": "Attributes that will be returned at any public request." - }, - "ProposalResultPublic": { - "properties": { - "proposal": { - "$ref": "#/components/schemas/ProposalPublic" - }, - "nr_reviews": { - "type": "integer", - "title": "Nr Reviews", - "default": 0 - }, - "nr_allocated_reviews": { - "type": "integer", - "title": "Nr Allocated Reviews", - "default": 0 - }, - "nr_pending_reviews": { - "type": "integer", - "title": "Nr Pending Reviews", - "default": 0 - }, - "nr_included_reviews": { - "type": "integer", - "title": "Nr Included Reviews", - "default": 0 - }, - "nr_excluded_reviews": { - "type": "integer", - "title": "Nr Excluded Reviews", - "default": 0 - }, - "nr_excluded_by_moderation_reviews": { - "type": "integer", - "title": "Nr Excluded By Moderation Reviews", - "default": 0 - }, - "nr_excluded_by_threshold_reviews": { - "type": "integer", - "title": "Nr Excluded By Threshold Reviews", - "default": 0 - }, - "score_avg": { - "anyOf": [ - { - "$ref": "#/components/schemas/ProposalScore" - }, - { - "type": "null" - } - ] - }, - "score_weighted_avg": { - "anyOf": [ - { - "$ref": "#/components/schemas/ProposalScore" - }, - { - "type": "null" - } - ] - } - }, - "type": "object", - "required": [ - "proposal" - ], - "title": "ProposalResultPublic", - "description": "Public attributes for the score of a single proposal." - }, - "ProposalResultsCreate": { - "properties": { - "event_id": { - "type": "integer", - "title": "Event Id" - }, - "allocation_weights": { - "$ref": "#/components/schemas/AllocationWeights" - }, - "level_weights": { - "$ref": "#/components/schemas/LevelWeights" - }, - "dry_run": { - "type": "boolean", - "title": "Dry Run", - "default": true - } - }, - "type": "object", - "required": [ - "event_id", - "allocation_weights", - "level_weights" - ], - "title": "ProposalResultsCreate", - "description": "Attributes for parameters of the generation of proposal results." - }, - "ProposalResultsPublic": { - "properties": { - "event_id": { - "type": "integer", - "title": "Event Id" - }, - "allocation_weights": { - "$ref": "#/components/schemas/AllocationWeights" - }, - "level_weights": { - "$ref": "#/components/schemas/LevelWeights" - }, - "dry_run": { - "type": "boolean", - "title": "Dry Run", - "default": true - }, - "proposals": { - "items": { - "$ref": "#/components/schemas/ProposalResultPublic" - }, - "type": "array", - "title": "Proposals", - "default": [] - } - }, - "type": "object", - "required": [ - "event_id", - "allocation_weights", - "level_weights" - ], - "title": "ProposalResultsPublic", - "description": "Public Attributes for result score of proposals." - }, - "ProposalReviewCreate": { - "properties": { - "proposal_id": { - "type": "integer", - "title": "Proposal Id" - }, - "impact_alignment_rating_given": { - "type": "integer", - "maximum": 5.0, - "minimum": 1.0, - "title": "Impact Alignment Rating Given" - }, - "impact_alignment_note": { - "type": "string", - "maxLength": 3000, - "minLength": 200, - "title": "Impact Alignment Note" - }, - "feasibility_rating_given": { - "type": "integer", - "maximum": 5.0, - "minimum": 1.0, - "title": "Feasibility Rating Given" - }, - "feasibility_note": { - "type": "string", - "maxLength": 3000, - "minLength": 200, - "title": "Feasibility Note" - }, - "auditability_rating_given": { - "type": "integer", - "maximum": 5.0, - "minimum": 1.0, - "title": "Auditability Rating Given" - }, - "auditability_note": { - "type": "string", - "maxLength": 3000, - "minLength": 200, - "title": "Auditability Note" - } - }, - "type": "object", - "required": [ - "proposal_id", - "impact_alignment_rating_given", - "impact_alignment_note", - "feasibility_rating_given", - "feasibility_note", - "auditability_rating_given", - "auditability_note" - ], - "title": "ProposalReviewCreate", - "description": "Attributes required to create a new ProposalReview.\n\nUsed at POST request." - }, - "ProposalReviewFlag": { - "properties": { - "flag_type": { - "$ref": "#/components/schemas/FlagType" - }, - "score": { - "type": "number", - "title": "Score" - }, - "related_reviews": { - "items": { - "type": "integer" - }, - "type": "array", - "title": "Related Reviews" - }, - "related_criteria": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Related Criteria" - } - }, - "type": "object", - "required": [ - "flag_type", - "score", - "related_reviews" - ], - "title": "ProposalReviewFlag", - "description": "Submodel to store reviews flags." - }, - "ProposalReviewModerated": { - "properties": { - "valid": { - "type": "boolean", - "title": "Valid" - }, - "row_id": { - "type": "integer", - "title": "Row Id" - }, - "user_id": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "User Id" - }, - "moderations_tot": { - "type": "integer", - "title": "Moderations Tot" - }, - "moderations_as_valid": { - "type": "integer", - "title": "Moderations As Valid" - }, - "proposal_id": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Proposal Id" - }, - "assessor": { - "type": "string", - "title": "Assessor" - }, - "impact_alignment_rating_given": { - "type": "integer", - "title": "Impact Alignment Rating Given" - }, - "impact_alignment_note": { - "type": "string", - "title": "Impact Alignment Note" - }, - "feasibility_rating_given": { - "type": "integer", - "title": "Feasibility Rating Given" - }, - "feasibility_note": { - "type": "string", - "title": "Feasibility Note" - }, - "auditability_rating_given": { - "type": "integer", - "title": "Auditability Rating Given" - }, - "auditability_note": { - "type": "string", - "title": "Auditability Note" - }, - "assessor_level": { - "type": "integer", - "title": "Assessor Level" - }, - "ranking": { - "anyOf": [ - { - "$ref": "#/components/schemas/ProposalReviewRanking" - }, - { - "type": "null" - } - ] - }, - "proposal": { - "anyOf": [ - { - "$ref": "#/components/schemas/ProposalInDB" - }, - { - "type": "null" - } - ] - } - }, - "type": "object", - "required": [ - "valid", - "row_id", - "moderations_tot", - "moderations_as_valid", - "assessor", - "impact_alignment_rating_given", - "impact_alignment_note", - "feasibility_rating_given", - "feasibility_note", - "auditability_rating_given", - "auditability_note", - "assessor_level" - ], - "title": "ProposalReviewModerated", - "description": "Attributes used to export full review with moderation results." - }, - "ProposalReviewPublic": { - "properties": { - "proposal_id": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Proposal Id" - }, - "assessor": { - "type": "string", - "title": "Assessor" - }, - "impact_alignment_rating_given": { - "type": "integer", - "title": "Impact Alignment Rating Given" - }, - "impact_alignment_note": { - "type": "string", - "title": "Impact Alignment Note" - }, - "feasibility_rating_given": { - "type": "integer", - "title": "Feasibility Rating Given" - }, - "feasibility_note": { - "type": "string", - "title": "Feasibility Note" - }, - "auditability_rating_given": { - "type": "integer", - "title": "Auditability Rating Given" - }, - "auditability_note": { - "type": "string", - "title": "Auditability Note" - }, - "assessor_level": { - "type": "integer", - "title": "Assessor Level" - }, - "ranking": { - "anyOf": [ - { - "$ref": "#/components/schemas/ProposalReviewRanking" - }, - { - "type": "null" - } - ] - }, - "row_id": { - "type": "integer", - "title": "Row Id" - }, - "flags": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/ProposalReviewFlag" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Flags" - }, - "moderation": { - "anyOf": [ - { - "$ref": "#/components/schemas/ModerationPublic" - }, - { - "type": "null" - } - ] - }, - "proposal": { - "anyOf": [ - { - "$ref": "#/components/schemas/ProposalPublic" - }, - { - "type": "null" - } - ] - }, - "moderated": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Moderated" - }, - "allocated": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Allocated" - }, - "allocated_for_moderation": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Allocated For Moderation" - }, - "next_allocation": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Next Allocation" - } - }, - "type": "object", - "required": [ - "assessor", - "impact_alignment_rating_given", - "impact_alignment_note", - "feasibility_rating_given", - "feasibility_note", - "auditability_rating_given", - "auditability_note", - "assessor_level", - "row_id" - ], - "title": "ProposalReviewPublic", - "description": "Attributes that will be returned at any public request." - }, - "ProposalReviewRanking": { - "type": "integer", - "enum": [ - 0, - 1, - 2, - 3 - ], - "title": "ProposalReviewRanking", - "description": "Enum to describe possible review output." - }, - "ProposalReviewResults": { - "properties": { - "dry_run": { - "type": "boolean", - "title": "Dry Run" - }, - "event_id": { - "type": "integer", - "title": "Event Id" - }, - "nr_of_reviewers": { - "type": "integer", - "title": "Nr Of Reviewers" - }, - "nr_of_accepted_reviewers": { - "type": "integer", - "title": "Nr Of Accepted Reviewers" - }, - "nr_of_excluded_reviewers": { - "type": "integer", - "title": "Nr Of Excluded Reviewers" - }, - "nr_of_reviews": { - "type": "integer", - "title": "Nr Of Reviews" - }, - "nr_of_accepted_reviews": { - "type": "integer", - "title": "Nr Of Accepted Reviews" - }, - "nr_of_excluded_reviews": { - "type": "integer", - "title": "Nr Of Excluded Reviews" - }, - "nr_of_excluded_reviews_by_moderation": { - "type": "integer", - "title": "Nr Of Excluded Reviews By Moderation" - }, - "nr_of_excluded_reviews_by_threshold": { - "type": "integer", - "title": "Nr Of Excluded Reviews By Threshold" - }, - "excluded_reviewers": { - "items": { - "$ref": "#/components/schemas/ReviewerSubscriptionPublic" - }, - "type": "array", - "title": "Excluded Reviewers" - } - }, - "type": "object", - "required": [ - "dry_run", - "event_id", - "nr_of_reviewers", - "nr_of_accepted_reviewers", - "nr_of_excluded_reviewers", - "nr_of_reviews", - "nr_of_accepted_reviews", - "nr_of_excluded_reviews", - "nr_of_excluded_reviews_by_moderation", - "nr_of_excluded_reviews_by_threshold", - "excluded_reviewers" - ], - "title": "ProposalReviewResults", - "description": "Attributes for result of the generation of reviews results." - }, - "ProposalReviewResultsCreate": { - "properties": { - "event_id": { - "type": "integer", - "title": "Event Id" - }, - "validity_threshold": { - "type": "number", - "maximum": 1.0, - "minimum": 0.0, - "title": "Validity Threshold" - }, - "acceptance_threshold": { - "type": "number", - "maximum": 1.0, - "minimum": 0.0, - "title": "Acceptance Threshold" - }, - "minimum_sample": { - "type": "integer", - "title": "Minimum Sample", - "default": 10 - }, - "dry_run": { - "type": "boolean", - "title": "Dry Run", - "default": true - } - }, - "type": "object", - "required": [ - "event_id", - "validity_threshold", - "acceptance_threshold" - ], - "title": "ProposalReviewResultsCreate", - "description": "Attributes for parameters of the generation of reviews results." - }, - "ProposalReviewUpdate": { - "properties": { - "impact_alignment_rating_given": { - "type": "integer", - "maximum": 5.0, - "minimum": 1.0, - "title": "Impact Alignment Rating Given" - }, - "impact_alignment_note": { - "type": "string", - "maxLength": 3000, - "minLength": 200, - "title": "Impact Alignment Note" - }, - "feasibility_rating_given": { - "type": "integer", - "maximum": 5.0, - "minimum": 1.0, - "title": "Feasibility Rating Given" - }, - "feasibility_note": { - "type": "string", - "maxLength": 3000, - "minLength": 200, - "title": "Feasibility Note" - }, - "auditability_rating_given": { - "type": "integer", - "maximum": 5.0, - "minimum": 1.0, - "title": "Auditability Rating Given" - }, - "auditability_note": { - "type": "string", - "maxLength": 3000, - "minLength": 200, - "title": "Auditability Note" - } - }, - "type": "object", - "required": [ - "impact_alignment_rating_given", - "impact_alignment_note", - "feasibility_rating_given", - "feasibility_note", - "auditability_rating_given", - "auditability_note" - ], - "title": "ProposalReviewUpdate", - "description": "Attributes required to update a ProposalReview.\n\nUsed at PUT request." - }, - "ProposalScore": { - "properties": { - "overall": { - "type": "number", - "title": "Overall", - "default": 0 - }, - "impact": { - "type": "number", - "title": "Impact", - "default": 0 - }, - "feasibility": { - "type": "number", - "title": "Feasibility", - "default": 0 - }, - "value_for_money": { - "type": "number", - "title": "Value For Money", - "default": 0 - } - }, - "type": "object", - "title": "ProposalScore", - "description": "Submodel to store the score." - }, - "ReviewHistoricStats": { - "properties": { - "active_funds": { - "type": "integer", - "title": "Active Funds", - "default": 0 - }, - "submitted": { - "type": "integer", - "title": "Submitted", - "default": 0 - }, - "blank": { - "type": "integer", - "title": "Blank", - "default": 0 - }, - "valid": { - "type": "integer", - "title": "Valid", - "default": 0 - } - }, - "type": "object", - "title": "ReviewHistoricStats", - "description": "Submodel to describe the historic stats as a reviewer." - }, - "ReviewerSubscriptionCreate": { - "properties": { - "fund_rules_acceptance": { - "type": "boolean", - "title": "Fund Rules Acceptance" - }, - "preferred_categories": { - "items": { - "type": "string", - "format": "uuid7" - }, - "type": "array", - "title": "Preferred Categories" - }, - "event_id": { - "type": "integer", - "title": "Event Id" - } - }, - "type": "object", - "required": [ - "fund_rules_acceptance", - "preferred_categories", - "event_id" - ], - "title": "ReviewerSubscriptionCreate", - "description": "Attributes for the creation of a Reviewer Subscription." - }, - "ReviewerSubscriptionExtra": { - "properties": { - "anonymous_id": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Anonymous Id" - }, - "subscribed_at": { - "type": "string", - "format": "date-time", - "title": "Subscribed At", - "default": "2025-04-18T16:03:45.190105" - }, - "public_contact": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Public Contact" - }, - "reward_address": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Reward Address" - }, - "preferred_categories": { - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/CategoryInDB" - }, - { - "type": "string", - "format": "uuid7" - } - ] - }, - "type": "array", - "title": "Preferred Categories", - "default": [] - } - }, - "type": "object", - "title": "ReviewerSubscriptionExtra", - "description": "Extra attributes for a reviewer subscription." - }, - "ReviewerSubscriptionInvitationAnswerCreate": { - "properties": { - "acknowledge_public_contact": { - "type": "boolean", - "title": "Acknowledge Public Contact" - }, - "public_contact": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Public Contact" - }, - "reward_address": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Reward Address" - }, - "role": { - "anyOf": [ - { - "$ref": "#/components/schemas/ReviewerSubscriptionRole" - }, - { - "type": "null" - } - ] - }, - "status": { - "$ref": "#/components/schemas/ReviewerSubscriptionInvitationAnswerStatus" - }, - "event_id": { - "type": "integer", - "title": "Event Id" - } - }, - "type": "object", - "required": [ - "acknowledge_public_contact", - "status", - "event_id" - ], - "title": "ReviewerSubscriptionInvitationAnswerCreate", - "description": "Attributes for the answer to an invitation of a Reviewer Subscription." - }, - "ReviewerSubscriptionInvitationAnswerStatus": { - "type": "integer", - "enum": [ - 0, - 1 - ], - "title": "ReviewerSubscriptionInvitationAnswerStatus", - "description": "List of possible status for ReviewerSubscriptionInvitationAnswer." - }, - "ReviewerSubscriptionPublic": { - "properties": { - "event_id": { - "type": "integer", - "title": "Event Id" - }, - "user_id": { - "type": "integer", - "title": "User Id" - }, - "role": { - "anyOf": [ - { - "$ref": "#/components/schemas/ReviewerSubscriptionRole" - }, - { - "type": "null" - } - ] - }, - "status": { - "$ref": "#/components/schemas/ReviewerSubscriptionStatus", - "default": 0 - }, - "extra": { - "$ref": "#/components/schemas/ReviewerSubscriptionExtra", - "default": { - "subscribed_at": "2025-04-18T16:03:45.190105", - "preferred_categories": [] - } - }, - "row_id": { - "type": "integer", - "title": "Row Id" - }, - "event": { - "$ref": "#/components/schemas/EventPublic" - } - }, - "type": "object", - "required": [ - "event_id", - "user_id", - "row_id", - "event" - ], - "title": "ReviewerSubscriptionPublic", - "description": "Publicly exposed attributes." - }, - "ReviewerSubscriptionRole": { - "type": "integer", - "enum": [ - 0, - 1, - 2 - ], - "title": "ReviewerSubscriptionRole", - "description": "List of possible roles for Reviewers." - }, - "ReviewerSubscriptionStatus": { - "type": "integer", - "enum": [ - 0, - 1, - 2, - 3, - 4 - ], - "title": "ReviewerSubscriptionStatus", - "description": "List of possible status for ReviewerSubscription." - }, - "ReviewsAllocationCreate": { - "properties": { - "event_id": { - "type": "integer", - "title": "Event Id" - }, - "allocation_seed": { - "type": "integer", - "title": "Allocation Seed", - "default": 42 - }, - "nr_of_proposals_lv0": { - "type": "integer", - "title": "Nr Of Proposals Lv0", - "default": 30 - }, - "nr_of_proposals_lv1": { - "type": "integer", - "title": "Nr Of Proposals Lv1", - "default": 80 - }, - "categories": { - "items": { - "type": "integer" - }, - "type": "array", - "title": "Categories", - "default": [] - }, - "dry_run": { - "type": "boolean", - "title": "Dry Run", - "default": true - } - }, - "type": "object", - "required": [ - "event_id" - ], - "title": "ReviewsAllocationCreate", - "description": "Model for the creation of reviewers allocation." - }, - "ReviewsAllocationStats": { - "properties": { - "tot": { - "type": "integer", - "title": "Tot", - "default": 0 - }, - "nr_of_reviewers": { - "$ref": "#/components/schemas/AllocationStatsReviewers", - "default": { - "tot": 0, - "lv0": 0, - "lv1": 0 - } - }, - "per_reviewer": { - "$ref": "#/components/schemas/AllocationStatsAverages", - "default": { - "avg": 0.0, - "min": 0, - "max": 0 - } - }, - "per_proposal": { - "$ref": "#/components/schemas/AllocationStatsAverages", - "default": { - "avg": 0.0, - "min": 0, - "max": 0 - } - } - }, - "type": "object", - "title": "ReviewsAllocationStats", - "description": "Model for stats of the allocation for reviewers." - }, - "ReviewsConfigCreate": { - "properties": { - "user_registration_enabled": { - "type": "boolean", - "title": "User Registration Enabled", - "default": false - }, - "reviewer_subscription_enabled": { - "type": "boolean", - "title": "Reviewer Subscription Enabled", - "default": false - }, - "review_submission_enabled": { - "type": "boolean", - "title": "Review Submission Enabled", - "default": false - }, - "moderation_submission_enabled": { - "type": "boolean", - "title": "Moderation Submission Enabled", - "default": false - }, - "reviewer_subscription_starts_at": { - "type": "string", - "format": "date-time", - "title": "Reviewer Subscription Starts At" - }, - "reviewer_subscription_ends_at": { - "type": "string", - "format": "date-time", - "title": "Reviewer Subscription Ends At" - }, - "review_submission_starts_at": { - "type": "string", - "format": "date-time", - "title": "Review Submission Starts At" - }, - "review_submission_ends_at": { - "type": "string", - "format": "date-time", - "title": "Review Submission Ends At" - }, - "moderation_submission_starts_at": { - "type": "string", - "format": "date-time", - "title": "Moderation Submission Starts At" - }, - "moderation_submission_ends_at": { - "type": "string", - "format": "date-time", - "title": "Moderation Submission Ends At" - } - }, - "type": "object", - "title": "ReviewsConfigCreate", - "description": "Attributes for the creation/update of reviews configs." - }, - "ReviewsLevelQualifiers": { - "properties": { - "lv1": { - "$ref": "#/components/schemas/LevelQualifier", - "default": { - "min_valid_reviews": 0, - "max_valid_reviews": 10, - "min_perc_valid_reviews": 0.8, - "max_perc_valid_reviews": 1.0, - "min_active_funds": 0, - "max_active_funds": 10 - } - }, - "lv2": { - "$ref": "#/components/schemas/LevelQualifier", - "default": { - "min_valid_reviews": 0, - "max_valid_reviews": 10, - "min_perc_valid_reviews": 0.8, - "max_perc_valid_reviews": 1.0, - "min_active_funds": 0, - "max_active_funds": 10 - } - } - }, - "type": "object", - "title": "ReviewsLevelQualifiers", - "description": "Submodel to store config values for the level qualifiers of the reviews." - }, - "ReviewsLevelQualifiersCreate": { - "properties": { - "lv1": { - "$ref": "#/components/schemas/LevelQualifier", - "default": { - "min_valid_reviews": 0, - "max_valid_reviews": 10, - "min_perc_valid_reviews": 0.8, - "max_perc_valid_reviews": 1.0, - "min_active_funds": 0, - "max_active_funds": 10 - } - }, - "lv2": { - "$ref": "#/components/schemas/LevelQualifier", - "default": { - "min_valid_reviews": 0, - "max_valid_reviews": 10, - "min_perc_valid_reviews": 0.8, - "max_perc_valid_reviews": 1.0, - "min_active_funds": 0, - "max_active_funds": 10 - } - } - }, - "type": "object", - "title": "ReviewsLevelQualifiersCreate", - "description": "Attributes for the creation/update of reviews level qualifiers configs." - }, - "ReviewsLevelQualifiersPublic": { - "properties": { - "row_id": { - "type": "integer", - "title": "Row Id" - }, - "id": { - "type": "string", - "title": "Id" - }, - "id2": { - "type": "string", - "title": "Id2" - }, - "value": { - "$ref": "#/components/schemas/ReviewsLevelQualifiers", - "default": { - "lv1": { - "max_active_funds": 10, - "max_perc_valid_reviews": 1.0, - "max_valid_reviews": 10, - "min_active_funds": 0, - "min_perc_valid_reviews": 0.8, - "min_valid_reviews": 0 - }, - "lv2": { - "max_active_funds": 10, - "max_perc_valid_reviews": 1.0, - "max_valid_reviews": 10, - "min_active_funds": 0, - "min_perc_valid_reviews": 0.8, - "min_valid_reviews": 0 - } - } - } - }, - "type": "object", - "required": [ - "row_id", - "id", - "id2" - ], - "title": "ReviewsLevelQualifiersPublic", - "description": "Attributes for ReviewsLevelQualifiers public model in responses." - }, - "ReviewsSwitches": { - "properties": { - "user_registration_enabled": { - "type": "boolean", - "title": "User Registration Enabled", - "default": false - }, - "reviewer_subscription_enabled": { - "type": "boolean", - "title": "Reviewer Subscription Enabled", - "default": false - }, - "review_submission_enabled": { - "type": "boolean", - "title": "Review Submission Enabled", - "default": false - }, - "moderation_submission_enabled": { - "type": "boolean", - "title": "Moderation Submission Enabled", - "default": false - }, - "reviewer_subscription_starts_at": { - "type": "string", - "format": "date-time", - "title": "Reviewer Subscription Starts At" - }, - "reviewer_subscription_ends_at": { - "type": "string", - "format": "date-time", - "title": "Reviewer Subscription Ends At" - }, - "review_submission_starts_at": { - "type": "string", - "format": "date-time", - "title": "Review Submission Starts At" - }, - "review_submission_ends_at": { - "type": "string", - "format": "date-time", - "title": "Review Submission Ends At" - }, - "moderation_submission_starts_at": { - "type": "string", - "format": "date-time", - "title": "Moderation Submission Starts At" - }, - "moderation_submission_ends_at": { - "type": "string", - "format": "date-time", - "title": "Moderation Submission Ends At" - } - }, - "type": "object", - "title": "ReviewsSwitches", - "description": "Submodel to store config values for the statuses of the Reviews." - }, - "SumSubDigestAlg": { - "type": "string", - "enum": [ - "HMAC_SHA1_HEX", - "HMAC_SHA256_HEX", - "HMAC_SHA512_HEX" - ], - "title": "SumSubDigestAlg", - "description": "Enum for signature verification algorithms." - }, - "UserActivation": { - "properties": { - "confirmation_token": { - "type": "string", - "title": "Confirmation Token" - } - }, - "type": "object", - "required": [ - "confirmation_token" - ], - "title": "UserActivation", - "description": "Model to complete user activation." - }, - "UserCreate": { - "properties": { - "catalyst_id": { - "type": "string", - "title": "Catalyst Id" - }, - "password": { - "type": "string", - "maxLength": 100, - "minLength": 7, - "title": "Password" - }, - "password_confirmation": { - "type": "string", - "maxLength": 100, - "minLength": 7, - "title": "Password Confirmation" - }, - "extra": { - "$ref": "#/components/schemas/UserCreateExtra" - } - }, - "type": "object", - "required": [ - "catalyst_id", - "password", - "password_confirmation", - "extra" - ], - "title": "UserCreate", - "description": "Attributes required to create a new User.\n\nUsed at POST request." - }, - "UserCreateExtra": { - "properties": { - "policy_acknowledgments": { - "$ref": "#/components/schemas/PolicyAcknowledgment", - "default": { - "privacy_policy": false, - "terms_and_conditions": false - } - }, - "due_diligence": { - "$ref": "#/components/schemas/DueDiligence", - "default": { - "status": 0, - "updated_at": 1744992225.207126 - } - }, - "historic_stats": { - "$ref": "#/components/schemas/HistoricStats", - "default": { - "reviews": { - "active_funds": 0, - "blank": 0, - "submitted": 0, - "valid": 0 - }, - "moderations": { - "active_funds": 0, - "submitted": 0 - } - } - } - }, - "type": "object", - "title": "UserCreateExtra", - "description": "Submodel to store the extra at user creation." - }, - "UserExtraPublic": { - "properties": { - "force_reset": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Force Reset", - "default": false - }, - "role": { - "anyOf": [ - { - "$ref": "#/components/schemas/UserRole" - }, - { - "type": "null" - } - ], - "default": 0 - }, - "due_diligence": { - "$ref": "#/components/schemas/DueDiligencePublic", - "default": { - "status": 0 - } - }, - "policy_acknowledgments": { - "$ref": "#/components/schemas/PolicyAcknowledgment", - "default": { - "privacy_policy": false, - "terms_and_conditions": false - } - }, - "historic_stats": { - "$ref": "#/components/schemas/HistoricStats", - "default": { - "reviews": { - "active_funds": 0, - "blank": 0, - "submitted": 0, - "valid": 0 - }, - "moderations": { - "active_funds": 0, - "submitted": 0 - } - } - }, - "subscriptions": { - "items": { - "$ref": "#/components/schemas/ReviewerSubscriptionPublic" - }, - "type": "array", - "title": "Subscriptions", - "default": [] - }, - "registered_at": { - "type": "string", - "format": "date-time", - "title": "Registered At", - "default": "2025-04-18T16:03:45.209307" - } - }, - "type": "object", - "title": "UserExtraPublic", - "description": "Submodel to store user extra." - }, - "UserInfo": { - "properties": { - "extra": { - "anyOf": [ - { - "$ref": "#/components/schemas/UserExtraPublic" - }, - { - "type": "null" - } - ] - }, - "catalyst_id": { - "$ref": "#/components/schemas/CatalystIDPublic" - } - }, - "type": "object", - "required": [ - "catalyst_id" - ], - "title": "UserInfo", - "description": "Attributes for generic user info." - }, - "UserRequestResetPassword": { - "properties": { - "catalyst_id": { - "type": "string", - "title": "Catalyst Id" - } - }, - "type": "object", - "required": [ - "catalyst_id" - ], - "title": "UserRequestResetPassword", - "description": "Attributes required to create a new password request User.\n\nUsed at POST request." - }, - "UserResetPassword": { - "properties": { - "catalyst_id": { - "type": "string", - "title": "Catalyst Id" - }, - "password": { - "type": "string", - "maxLength": 100, - "minLength": 7, - "title": "Password" - }, - "password_confirmation": { - "type": "string", - "maxLength": 100, - "minLength": 7, - "title": "Password Confirmation" - }, - "confirmation_token": { - "type": "string", - "title": "Confirmation Token" - } - }, - "type": "object", - "required": [ - "catalyst_id", - "password", - "password_confirmation", - "confirmation_token" - ], - "title": "UserResetPassword", - "description": "Fields accepted to allow users to change their info." - }, - "UserRole": { - "type": "integer", - "enum": [ - 0, - 100 - ], - "title": "UserRole", - "description": "Enum to describe possible user roles." - }, - "UserUpdate": { - "properties": { - "password": { - "type": "string", - "maxLength": 100, - "minLength": 7, - "title": "Password" - }, - "password_confirmation": { - "type": "string", - "maxLength": 100, - "minLength": 7, - "title": "Password Confirmation" - }, - "old_password": { - "type": "string", - "maxLength": 100, - "minLength": 7, - "title": "Old Password" - } - }, - "type": "object", - "required": [ - "password", - "password_confirmation", - "old_password" - ], - "title": "UserUpdate", - "description": "Fields accepted to allow users to change their info." - }, - "VITssExportConfig": { - "properties": { - "events_id": { - "items": { - "type": "integer" - }, - "type": "array", - "title": "Events Id" - }, - "fund_id": { - "type": "integer", - "title": "Fund Id" - }, - "fund_name": { - "type": "string", - "title": "Fund Name" - }, - "threshold": { - "type": "integer", - "title": "Threshold", - "default": 25 - }, - "themes": { - "items": { - "type": "string" - }, - "type": "array", - "title": "Themes", - "default": [] - }, - "chain_vote_options": { - "type": "string", - "title": "Chain Vote Options", - "default": "blank,yes,no" - }, - "chain_vote_type": { - "type": "string", - "title": "Chain Vote Type", - "default": "private" - } - }, - "type": "object", - "required": [ - "events_id", - "fund_id", - "fund_name" - ], - "title": "VITssExportConfig", - "description": "The configuration for the VITss export." - }, - "ValidationError": { - "properties": { - "loc": { - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "integer" - } - ] - }, - "type": "array", - "title": "Location" - }, - "msg": { - "type": "string", - "title": "Message" - }, - "type": { - "type": "string", - "title": "Error Type" - } - }, - "type": "object", - "required": [ - "loc", - "msg", - "type" - ], - "title": "ValidationError" - } - }, - "securitySchemes": { - "OAuth2PasswordBearer": { - "type": "oauth2", - "flows": { - "password": { - "scopes": {}, - "tokenUrl": "/api/users/token/login" - } - } - }, - "HTTPBearer": { - "type": "http", - "scheme": "bearer" - } - } - } -} \ No newline at end of file diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/openapi/cat-status.json b/catalyst_voices/packages/internal/catalyst_voices_repositories/openapi/cat-status.json deleted file mode 100644 index 967eacad9180..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/openapi/cat-status.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "openapi": "3.1.0", - "info": { - "title": "Project Catalyst Status API", - "version": "0.0.1", - "description": "Public API for Project Catalyst Status Page" - }, - "servers": [ - { - "url": "https://status.projectcatalyst.io", - "description": "Production server" - } - ], - "paths": { - "/v2/components.json": { - "get": { - "summary": "Get components", - "description": "Get your status page components, and active issues affecting them.", - "operationId": "getComponents", - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ComponentsResponse" - } - } - } - } - } - } - } - }, - "components": { - "schemas": { - "ComponentsResponse": { - "type": "object", - "properties": { - "components": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Component" - } - } - }, - "required": [ - "components" - ] - }, - "Component": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "cmen3fgre004cb9js0dkuzat8" - }, - "name": { - "type": "string", - "example": "Catalyst App" - }, - "description": { - "type": "string", - "example": "" - }, - "status": { - "type": "string", - "enum": [ - "OPERATIONAL", - "PARTIALOUTAGE", - "MINOROUTAGE", - "MAJOROUTAGE" - ], - "example": "OPERATIONAL" - }, - "group": { - "type": "string" - }, - "isParent": { - "type": "boolean" - } - }, - "required": [ - "id", - "name", - "description", - "status" - ] - } - } - } -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/process_openapi.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/process_openapi.dart deleted file mode 100644 index f9befd6a4307..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/process_openapi.dart +++ /dev/null @@ -1,145 +0,0 @@ -// ignore_for_file: avoid_print - -import 'dart:convert'; -import 'dart:io'; - -import 'package:path/path.dart' as path; - -/// Adapts OpenAPI specs produced by backend to something that code -/// generators can work with. -/// -/// For example this bug: -/// - https://github.com/epam-cross-platform-lab/swagger-dart-code-generator/issues/721 -void main() { - // Ensure the processed directory exists - final sourceDir = Directory('openapi'); - final processedDir = Directory('openapi/processed'); - if (!processedDir.existsSync()) { - processedDir.createSync(recursive: true); - } - - final oldProcessedFiles = processedDir.listSync().whereType().where( - (element) => element.path.endsWith('.json'), - ); - - // Delete any .json files from processedDir - for (final file in oldProcessedFiles) { - file.deleteSync(); - } - - final sourceFiles = sourceDir.listSync().whereType().where( - (element) => element.path.endsWith('.json'), - ); - - // Decode each source file, process and save processed version. - for (final source in sourceFiles) { - final baseName = path.basenameWithoutExtension(source.path); - - final json = source.readAsStringSync(); - final decodedJson = jsonDecode(json) as Map; - - final version = decodedJson['openapi']?.toString(); - if (version == null) { - print('[$baseName] Missing OpenAPI version'); - continue; - } - - if (!_supportedOpenApiVersions.contains(version)) { - print('[$baseName] Unsupported OpenApi version[$version]'); - continue; - } - - final processedJson = OpenApiProcessor.filterAllOf( - decodedJson, - source: baseName, - ); - final encodedProcessedJson = jsonEncode(processedJson); - - final fileName = '$baseName.json'; - final filePath = path.join(processedDir.path, fileName); - - File(filePath) - ..createSync() - ..writeAsStringSync(encodedProcessedJson); - - print('Processed [$baseName] --> [$fileName]'); - } -} - -const _supportedOpenApiVersions = ['3.0.0', '3.1.0']; - -/// Processor for OpenAPI specifications -class OpenApiProcessor { - /// Filters and processes allOf nodes in OpenAPI specifications - static Map filterAllOf( - Map data, { - required String source, - }) { - final visitor = _FilterAllOfVisitor(source: source); - final result = visitor.visit(data); - return result as Map; - } -} - -class _FilterAllOfVisitor { - final String source; - final bool verbose; - - _FilterAllOfVisitor({ - required this.source, - // ignore: unused_element_parameter - this.verbose = false, - }); - - dynamic visit(dynamic value) { - if (value == null) return null; - - if (value is List) return _visitList(value); - if (value is Map) return _visitMap(value as Map); - return value; - } - - bool _isAllOfNode(Map map) { - return map.containsKey('allOf') && map['allOf'] is List; - } - - bool _isRefNode(dynamic node) { - return node is Map && node.containsKey(r'$ref'); - } - - Map _processAllOfNode(Map map) { - final allOfList = map['allOf'] as List; - final hasRefs = allOfList.any(_isRefNode); - - if (hasRefs) { - // https://github.com/epam-cross-platform-lab/swagger-dart-code-generator/issues/721 - if (verbose) { - print( - '[$source] Found allOf and title. ' - 'Removing title[${map['title']}]', - ); - } - - return { - ...map, - 'allOf': allOfList.where(_isRefNode).toList(), - }..remove('title'); - } - - return { - ...map, - 'allOf': visit(allOfList), - }; - } - - List _visitList(List list) { - return list.map(visit).toList(); - } - - Map _visitMap(Map map) { - if (_isAllOfNode(map)) { - return _processAllOfNode(map); - } - return map.map((key, value) => MapEntry(key, visit(value))); - } -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/pubspec.yaml b/catalyst_voices/packages/internal/catalyst_voices_repositories/pubspec.yaml index b2f55eb696b1..214c859407d1 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/pubspec.yaml +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/pubspec.yaml @@ -10,7 +10,6 @@ environment: dependencies: async: ^2.13.0 - build: ^2.4.1 catalyst_cardano_serialization: ^1.0.0 catalyst_compression: ^1.0.0 catalyst_cose: ^1.0.0 @@ -23,9 +22,9 @@ dependencies: catalyst_voices_shared: path: ../catalyst_voices_shared cbor: 6.3.7 - chopper: ^8.3.0 collection: ^1.19.1 convert: ^3.1.2 + dio: ^5.9.0 drift: ^2.28.1 drift_flutter: ^0.2.5 equatable: ^2.0.7 @@ -45,14 +44,13 @@ dependencies: uuid_plus: ^0.1.0 dev_dependencies: - build_runner: ^2.5.4 + build_runner: ^2.10.3 catalyst_analysis: ^3.0.0 - chopper_generator: ^8.2.0 drift_dev: ^2.24.0 flutter_test: sdk: flutter - json_serializable: ^6.9.5 + json_serializable: ^6.11.1 mocktail: ^1.0.4 shared_preferences_platform_interface: ^2.4.1 sqlite3: ^2.8.0 - swagger_dart_code_generator: ^3.0.3 + diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/exported_proposal_v0_0_1.json b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/exported_proposal_v0_0_1.json new file mode 100644 index 000000000000..3aaaf5d2f6b8 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/exported_proposal_v0_0_1.json @@ -0,0 +1,165 @@ +{ + "metadata": { + "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", + "selfRef": { + "id": "019a00a6-0a67-7722-9af4-f4b0a1f77fac", + "version": "019a00a6-0a67-7722-9af4-f4b0a1f77fac", + "type": "draft" + }, + "ref": null, + "refHash": null, + "template": { + "id": "0199802c-21b4-717d-9619-11357877f471", + "version": "0199802c-21b4-717d-9619-11357877f471", + "type": "signed" + }, + "reply": null, + "section": null, + "brandId": null, + "campaignId": null, + "electionId": null, + "categoryId": { + "id": "0199802c-21b4-721f-aa1d-5123b006879e", + "version": "0199802c-21b4-721f-aa1d-5123b006879e", + "type": "signed" + }, + "authors": null + }, + "content": { + "$schema": "./0199802c-21b4-717d-9619-11357877f471.schema.json", + "setup": { + "title": { + "title": "Test" + }, + "proposer": { + "applicant": "Test", + "type": "Entity (Incorporated)" + } + }, + "summary": { + "budget": { + "requestedFunds": 250000 + }, + "time": { + "duration": 2 + }, + "translation": { + "isTranslated": true, + "originalLanguage": "en" + }, + "problem": { + "statement": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test " + }, + "solution": { + "summary": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test " + }, + "supportingLinks": { + "links": [] + }, + "dependencies": { + "hasDependency": false, + "dependencyDetail": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test " + }, + "open_source": { + "isOpenSource": false, + "licenseInformation": "Test Test Test " + } + }, + "theme": { + "theme": { + "grouped_tag": { + "group": "Governance", + "tag": "Governance" + } + } + }, + "campaign_category": { + "category_questions": { + "established_partnership": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "funding_commitments": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "performance_metrics": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test" + } + }, + "details": { + "solution": { + "solution": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test" + }, + "impact": { + "impact": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test" + }, + "feasibility": { + "feasibility": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test" + } + }, + "milestones": { + "milestones": { + "milestone_list": [ + { + "title": "Test", + "outputs": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "acceptance_criteria": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "evidence": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "delivery_month": 1, + "cost": 123, + "progress": "40 %" + }, + { + "title": "Test", + "outputs": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "acceptance_criteria": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "evidence": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "delivery_month": 1, + "cost": 123, + "progress": "60 %" + }, + { + "title": "Test", + "outputs": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "acceptance_criteria": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "evidence": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "delivery_month": 1, + "cost": 123, + "progress": "70 %" + } + ] + } + }, + "pitch": { + "team": { + "who": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test" + }, + "budget": { + "costs": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test" + }, + "value": { + "note": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test" + } + }, + "self_assessment": { + "self_assessment_checklist": { + "legal_entity": true, + "track_record": true, + "tier_one_collaboration": true, + "catalyst_standing": true, + "scope_fit": true, + "mature_product_path": true, + "partner_identification": true, + "partner_commitment": true, + "verifiable_credentials": true, + "measurable_adoption": true, + "timeline": true, + "visibility_engagement": true, + "budget_compliance": true + } + }, + "agreements": { + "ongoing_projects": { + "has_ongoing_projects": true, + "projects": [] + }, + "consent_confirmation": { + "terms_and_conditions": true + } + } + } +} \ No newline at end of file diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/exported_proposal_v0_0_4.json b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/exported_proposal_v0_0_4.json new file mode 100644 index 000000000000..8a62f4b1556b --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/exported_proposal_v0_0_4.json @@ -0,0 +1,163 @@ +{ + "metadata": { + "type": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", + "selfRef": { + "id": "019a0091-2097-7ec0-98a7-e8e20ddb5559", + "version": "019a0091-2097-7ec0-98a7-e8e20ddb5559", + "type": "draft" + }, + "ref": null, + "template": { + "id": "0199802c-21b4-717d-9619-11357877f471", + "version": "0199802c-21b4-717d-9619-11357877f471", + "type": "signed" + }, + "reply": null, + "section": null, + "parameters": [ + { + "id": "0199802c-21b4-721f-aa1d-5123b006879e", + "version": "0199802c-21b4-721f-aa1d-5123b006879e", + "type": "signed" + } + ], + "authors": null + }, + "content": { + "$schema": "./0199802c-21b4-717d-9619-11357877f471.schema.json", + "setup": { + "title": { + "title": "Test" + }, + "proposer": { + "applicant": "Test", + "type": "Entity (Incorporated)" + } + }, + "summary": { + "budget": { + "requestedFunds": 250000 + }, + "time": { + "duration": 2 + }, + "translation": { + "isTranslated": true, + "originalLanguage": "en" + }, + "problem": { + "statement": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test " + }, + "solution": { + "summary": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test " + }, + "supportingLinks": { + "links": [] + }, + "dependencies": { + "hasDependency": false, + "dependencyDetail": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test " + }, + "open_source": { + "isOpenSource": false, + "licenseInformation": "Test Test Test " + } + }, + "theme": { + "theme": { + "grouped_tag": { + "group": "Governance", + "tag": "Governance" + } + } + }, + "campaign_category": { + "category_questions": { + "established_partnership": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "funding_commitments": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "performance_metrics": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test" + } + }, + "details": { + "solution": { + "solution": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test" + }, + "impact": { + "impact": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test" + }, + "feasibility": { + "feasibility": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test" + } + }, + "milestones": { + "milestones": { + "milestone_list": [ + { + "title": "Test", + "outputs": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "acceptance_criteria": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "evidence": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "delivery_month": 1, + "cost": 123, + "progress": "40 %" + }, + { + "title": "Test", + "outputs": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "acceptance_criteria": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "evidence": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "delivery_month": 1, + "cost": 123, + "progress": "60 %" + }, + { + "title": "Test", + "outputs": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "acceptance_criteria": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "evidence": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test", + "delivery_month": 1, + "cost": 123, + "progress": "70 %" + } + ] + } + }, + "pitch": { + "team": { + "who": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test" + }, + "budget": { + "costs": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test" + }, + "value": { + "note": "Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test" + } + }, + "self_assessment": { + "self_assessment_checklist": { + "legal_entity": true, + "track_record": true, + "tier_one_collaboration": true, + "catalyst_standing": true, + "scope_fit": true, + "mature_product_path": true, + "partner_identification": true, + "partner_commitment": true, + "verifiable_credentials": true, + "measurable_adoption": true, + "timeline": true, + "visibility_engagement": true, + "budget_compliance": true + } + }, + "agreements": { + "ongoing_projects": { + "has_ongoing_projects": true, + "projects": [] + }, + "consent_confirmation": { + "terms_and_conditions": true + } + } + } +} \ No newline at end of file diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/signed_document_test_data.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/signed_document_test_data.dart new file mode 100644 index 000000000000..b911e24481de --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/signed_document_test_data.dart @@ -0,0 +1,40 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:convert/convert.dart'; + +/// v0.0.1 -> v0.0.4 spec: https://github.com/input-output-hk/catalyst-libs/pull/341/files#diff-2827956d681587dfd09dc733aca731165ff44812f8322792bf6c4a61cf2d3b85 +final class SignedDocumentTestData { + /// A hex encoded cbor of proposal document created with v0.0.1 spec. + static final Future signedDocumentV0_0_1Bytes = _getBytesFromHexFile( + 'test/fixture/signed_document/signed_document_v0_0_1.hex', + ); + + /// A hex encoded cbor of proposal document created with v0.0.4 spec. + static final Future signedDocumentV0_0_4Bytes = _getBytesFromHexFile( + 'test/fixture/signed_document/signed_document_v0_0_4.hex', + ); + + /// A json file with exported proposal with v0.0.1 spec. + static final Future exportedProposalV0_0_1Bytes = _getBytesFromJsonFile( + 'test/fixture/signed_document/exported_proposal_v0_0_1.json', + ); + + /// A json file with exported proposal with v0.0.4 spec. + static final Future exportedProposalV0_0_4Bytes = _getBytesFromJsonFile( + 'test/fixture/signed_document/exported_proposal_v0_0_4.json', + ); + + static Future _getBytesFromHexFile(String path) async { + final file = File(path); + final data = await file.readAsString(); + return Uint8List.fromList(hex.decode(data.trim())); + } + + static Future _getBytesFromJsonFile(String path) async { + final file = File(path); + final data = await file.readAsString(); + return Uint8List.fromList(utf8.encode(data.trim())); + } +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/signed_document_v0_0_1.hex b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/signed_document_v0_0_1.hex new file mode 100644 index 000000000000..fbec22a1f8d7 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/signed_document_v0_0_1.hex @@ -0,0 +1 @@ +d8628458aca60318326474797065d825507808d2bad51140af84e8c0d1625fdfdc626964d82550019a00ca53a37e33a4ebe23576b0440f63766572d82550019a00ca674d7050859cb2dc43095bc96874656d706c61746582d825500199802c21b4717d961911357877f471d825500199802c21b4717d961911357877f4716b63617465676f72795f696482d825500199802c21b4721faa1d5123b006879ed825500199802c21b4721faa1d5123b006879ea05919667b2224736368656d61223a222e2f30313939383032632d323162342d373137642d393631392d3131333537383737663437312e736368656d612e6a736f6e222c227365747570223a7b227469746c65223a7b227469746c65223a2254657374227d2c2270726f706f736572223a7b226170706c6963616e74223a2254657374222c2274797065223a22456e746974792028496e636f72706f726174656429227d7d2c2273756d6d617279223a7b22627564676574223a7b2272657175657374656446756e6473223a3235303030307d2c2274696d65223a7b226475726174696f6e223a327d2c227472616e736c6174696f6e223a7b2269735472616e736c61746564223a747275652c226f726967696e616c4c616e6775616765223a22656e227d2c2270726f626c656d223a7b2273746174656d656e74223a22546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420227d2c22736f6c7574696f6e223a7b2273756d6d617279223a22546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420227d2c22737570706f7274696e674c696e6b73223a7b226c696e6b73223a5b5d7d2c22646570656e64656e63696573223a7b22686173446570656e64656e6379223a66616c73652c22646570656e64656e637944657461696c223a22546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420227d2c226f70656e5f736f75726365223a7b2269734f70656e536f75726365223a66616c73652c226c6963656e7365496e666f726d6174696f6e223a22546573742054657374205465737420227d7d2c227468656d65223a7b227468656d65223a7b2267726f757065645f746167223a7b2267726f7570223a22476f7665726e616e6365222c22746167223a22476f7665726e616e6365227d7d7d2c2263616d706169676e5f63617465676f7279223a7b2263617465676f72795f7175657374696f6e73223a7b2265737461626c69736865645f706172746e657273686970223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c2266756e64696e675f636f6d6d69746d656e7473223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c22706572666f726d616e63655f6d657472696373223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374227d7d2c2264657461696c73223a7b22736f6c7574696f6e223a7b22736f6c7574696f6e223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374227d2c22696d70616374223a7b22696d70616374223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374227d2c22666561736962696c697479223a7b22666561736962696c697479223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374227d7d2c226d696c6573746f6e6573223a7b226d696c6573746f6e6573223a7b226d696c6573746f6e655f6c697374223a5b7b227469746c65223a2254657374222c226f757470757473223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c22616363657074616e63655f6372697465726961223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c2265766964656e6365223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c2264656c69766572795f6d6f6e7468223a312c22636f7374223a3132332c2270726f6772657373223a2234302025227d2c7b227469746c65223a2254657374222c226f757470757473223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c22616363657074616e63655f6372697465726961223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c2265766964656e6365223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c2264656c69766572795f6d6f6e7468223a312c22636f7374223a3132332c2270726f6772657373223a2236302025227d2c7b227469746c65223a2254657374222c226f757470757473223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c22616363657074616e63655f6372697465726961223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c2265766964656e6365223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c2264656c69766572795f6d6f6e7468223a312c22636f7374223a3132332c2270726f6772657373223a2237302025227d5d7d7d2c227069746368223a7b227465616d223a7b2277686f223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374227d2c22627564676574223a7b22636f737473223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374227d2c2276616c7565223a7b226e6f7465223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374227d7d2c2273656c665f6173736573736d656e74223a7b2273656c665f6173736573736d656e745f636865636b6c697374223a7b226c6567616c5f656e74697479223a747275652c22747261636b5f7265636f7264223a747275652c22746965725f6f6e655f636f6c6c61626f726174696f6e223a747275652c22636174616c7973745f7374616e64696e67223a747275652c2273636f70655f666974223a747275652c226d61747572655f70726f647563745f70617468223a747275652c22706172746e65725f6964656e74696669636174696f6e223a747275652c22706172746e65725f636f6d6d69746d656e74223a747275652c2276657269666961626c655f63726564656e7469616c73223a747275652c226d656173757261626c655f61646f7074696f6e223a747275652c2274696d656c696e65223a747275652c227669736962696c6974795f656e676167656d656e74223a747275652c226275646765745f636f6d706c69616e6365223a747275657d7d2c2261677265656d656e7473223a7b226f6e676f696e675f70726f6a65637473223a7b226861735f6f6e676f696e675f70726f6a65637473223a747275652c2270726f6a65637473223a5b5d7d2c22636f6e73656e745f636f6e6669726d6174696f6e223a7b227465726d735f616e645f636f6e646974696f6e73223a747275657d7d7d81835858a104585469642e636174616c7973743a2f2f44616d69616e4070726570726f642e63617264616e6f2f6b6f75474a754d6e366f313872527044415a316f695a61644b31373166355f2d6867634854594447626f302f332f30a05840a3f29c60fb6a7304efc8f2439200903a4a1c28dca1a5ae4b7e7193ddd72df3f029df05dd9ce00162aae2d7f8ff40b7aef1791db12dc2f11862d928ee4d83590e \ No newline at end of file diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/signed_document_v0_0_4.hex b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/signed_document_v0_0_4.hex new file mode 100644 index 000000000000..011f651a56ae --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/signed_document/signed_document_v0_0_4.hex @@ -0,0 +1 @@ +d8628458bda60318326474797065d825507808d2bad51140af84e8c0d1625fdfdc626964d82550019a00c613687767a6c0b60e08bd8fc763766572d82550019a00c63bd879a2a6835279d8919a086874656d706c6174658183d825500199802c21b4717d961911357877f471d825500199802c21b4717d961911357877f471a163636964d82a406a706172616d65746572738183d825500199802c21b4721faa1d5123b006879ed825500199802c21b4721faa1d5123b006879ea163636964d82a40a05919667b2224736368656d61223a222e2f30313939383032632d323162342d373137642d393631392d3131333537383737663437312e736368656d612e6a736f6e222c227365747570223a7b227469746c65223a7b227469746c65223a2254657374227d2c2270726f706f736572223a7b226170706c6963616e74223a2254657374222c2274797065223a22456e746974792028496e636f72706f726174656429227d7d2c2273756d6d617279223a7b22627564676574223a7b2272657175657374656446756e6473223a3235303030307d2c2274696d65223a7b226475726174696f6e223a327d2c227472616e736c6174696f6e223a7b2269735472616e736c61746564223a747275652c226f726967696e616c4c616e6775616765223a22656e227d2c2270726f626c656d223a7b2273746174656d656e74223a22546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420227d2c22736f6c7574696f6e223a7b2273756d6d617279223a22546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420227d2c22737570706f7274696e674c696e6b73223a7b226c696e6b73223a5b5d7d2c22646570656e64656e63696573223a7b22686173446570656e64656e6379223a66616c73652c22646570656e64656e637944657461696c223a22546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420227d2c226f70656e5f736f75726365223a7b2269734f70656e536f75726365223a66616c73652c226c6963656e7365496e666f726d6174696f6e223a22546573742054657374205465737420227d7d2c227468656d65223a7b227468656d65223a7b2267726f757065645f746167223a7b2267726f7570223a22476f7665726e616e6365222c22746167223a22476f7665726e616e6365227d7d7d2c2263616d706169676e5f63617465676f7279223a7b2263617465676f72795f7175657374696f6e73223a7b2265737461626c69736865645f706172746e657273686970223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c2266756e64696e675f636f6d6d69746d656e7473223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c22706572666f726d616e63655f6d657472696373223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374227d7d2c2264657461696c73223a7b22736f6c7574696f6e223a7b22736f6c7574696f6e223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374227d2c22696d70616374223a7b22696d70616374223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374227d2c22666561736962696c697479223a7b22666561736962696c697479223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374227d7d2c226d696c6573746f6e6573223a7b226d696c6573746f6e6573223a7b226d696c6573746f6e655f6c697374223a5b7b227469746c65223a2254657374222c226f757470757473223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c22616363657074616e63655f6372697465726961223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c2265766964656e6365223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c2264656c69766572795f6d6f6e7468223a312c22636f7374223a3132332c2270726f6772657373223a2234302025227d2c7b227469746c65223a2254657374222c226f757470757473223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c22616363657074616e63655f6372697465726961223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c2265766964656e6365223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c2264656c69766572795f6d6f6e7468223a312c22636f7374223a3132332c2270726f6772657373223a2236302025227d2c7b227469746c65223a2254657374222c226f757470757473223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c22616363657074616e63655f6372697465726961223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c2265766964656e6365223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374222c2264656c69766572795f6d6f6e7468223a312c22636f7374223a3132332c2270726f6772657373223a2237302025227d5d7d7d2c227069746368223a7b227465616d223a7b2277686f223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374227d2c22627564676574223a7b22636f737473223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374227d2c2276616c7565223a7b226e6f7465223a225465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374205465737420546573742054657374227d7d2c2273656c665f6173736573736d656e74223a7b2273656c665f6173736573736d656e745f636865636b6c697374223a7b226c6567616c5f656e74697479223a747275652c22747261636b5f7265636f7264223a747275652c22746965725f6f6e655f636f6c6c61626f726174696f6e223a747275652c22636174616c7973745f7374616e64696e67223a747275652c2273636f70655f666974223a747275652c226d61747572655f70726f647563745f70617468223a747275652c22706172746e65725f6964656e74696669636174696f6e223a747275652c22706172746e65725f636f6d6d69746d656e74223a747275652c2276657269666961626c655f63726564656e7469616c73223a747275652c226d656173757261626c655f61646f7074696f6e223a747275652c2274696d656c696e65223a747275652c227669736962696c6974795f656e676167656d656e74223a747275652c226275646765745f636f6d706c69616e6365223a747275657d7d2c2261677265656d656e7473223a7b226f6e676f696e675f70726f6a65637473223a7b226861735f6f6e676f696e675f70726f6a65637473223a747275652c2270726f6a65637473223a5b5d7d2c22636f6e73656e745f636f6e6669726d6174696f6e223a7b227465726d735f616e645f636f6e646974696f6e73223a747275657d7d7d81835858a104585469642e636174616c7973743a2f2f44616d69616e4070726570726f642e63617264616e6f2f6b6f75474a754d6e366f313872527044415a316f695a61644b31373166355f2d6867634854594447626f302f332f30a05840aee0ffd51781511e92bbfa236577d7af723c90a927c1715522d38baf85f2f28405e0648483ab26d0418ef87864e09df49aae1dd14d3ab71d3683521d02b5c406 \ No newline at end of file diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/voices_document_templates.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/voices_document_templates.dart index 424993a066a7..e6e500e81554 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/voices_document_templates.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/fixture/voices_document_templates.dart @@ -23,8 +23,11 @@ class VoicesDocumentsTemplates { static Future _getDocsRoot() async { var dir = Directory.current; + final blacklisted = ['catalyst_voices']; + while (true) { - final list = dir.listSync(); + final skip = blacklisted.any((path) => dir.path.endsWith(path)); + final list = skip ? [] : dir.listSync(); final docs = list.firstWhereOrNull((e) => e.path.endsWith('/docs')); if (docs != null) { return Directory(docs.path); diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/converters/cbor_or_json_converter_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/converters/cbor_or_json_converter_test.dart deleted file mode 100644 index c4e3ab09128e..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/converters/cbor_or_json_converter_test.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'package:catalyst_voices_repositories/src/api/converters/cbor_or_json_converter.dart'; -import 'package:catalyst_voices_repositories/src/common/content_types.dart'; -import 'package:catalyst_voices_repositories/src/common/http_headers.dart'; -import 'package:chopper/chopper.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:http/http.dart' as http; -import 'package:mocktail/mocktail.dart'; - -import '../interceptors/mock_response.dart'; - -void main() { - group(CborOrJsonDelegateConverter, () { - late MockConverter cborConverter; - late MockConverter jsonConverter; - late CborOrJsonDelegateConverter delegateConverter; - - setUpAll(() { - registerFallbackValue(Request('X', Uri(), Uri())); - }); - - setUp(() { - cborConverter = MockConverter(); - jsonConverter = MockConverter(); - delegateConverter = CborOrJsonDelegateConverter( - cborConverter: cborConverter, - jsonConverter: jsonConverter, - ); - }); - - test('delegates CBOR request to cborConverter', () async { - final request = Request( - 'PUT', - Uri.parse('https://example.com/api/v1/document'), - Uri.parse('https://example.com/'), - headers: {HttpHeaders.contentType: ContentTypes.applicationCbor}, - ); - - when(() => cborConverter.convertRequest(any())).thenAnswer((_) => Future.value(request)); - - final convertedRequest = await delegateConverter.convertRequest(request); - expect(convertedRequest, equals(request)); - verify(() => cborConverter.convertRequest(request)).called(1); - verifyNever(() => jsonConverter.convertRequest(request)); - }); - - test('delegates non-CBOR request to jsonConverter', () async { - final request = Request( - 'GET', - Uri.parse('https://example.com/api/v1/other'), - Uri.parse('https://example.com/'), - headers: {HttpHeaders.contentType: ContentTypes.applicationJson}, - ); - - when(() => jsonConverter.convertRequest(any())).thenAnswer((_) => Future.value(request)); - - final convertedRequest = await delegateConverter.convertRequest(request); - expect(convertedRequest, equals(request)); - verify(() => jsonConverter.convertRequest(request)).called(1); - verifyNever(() => cborConverter.convertRequest(request)); - }); - - test('delegates CBOR response to cborConverter', () async { - final request = Request( - 'PUT', - Uri.parse('https://example.com/api/v1/document'), - Uri.parse('https://example.com/'), - ); - - final baseResponse = MockBaseResponse(); - final response = MockResponse(); - when( - () => response.headers, - ).thenReturn({HttpHeaders.contentType: ContentTypes.applicationCbor}); - when(() => response.base).thenReturn(baseResponse); - when(() => baseResponse.request).thenReturn(request); - when(() => cborConverter.convertResponse(response)).thenReturn(response); - - final convertedResponse = delegateConverter.convertResponse(response); - expect(convertedResponse, equals(response)); - verify(() => cborConverter.convertResponse(response)).called(1); - verifyNever(() => jsonConverter.convertResponse(response)); - }); - - test('delegates non-CBOR response to jsonConverter', () async { - final request = Request( - 'GET', - Uri.parse('https://example.com/api/v1/other'), - Uri.parse('https://example.com/'), - ); - - final baseResponse = MockBaseResponse(); - final response = MockResponse(); - when( - () => response.headers, - ).thenReturn({HttpHeaders.contentType: ContentTypes.applicationJson}); - when(() => response.base).thenReturn(baseResponse); - when(() => baseResponse.request).thenReturn(request); - when(() => jsonConverter.convertResponse(response)).thenReturn(response); - - final convertedResponse = delegateConverter.convertResponse(response); - expect(convertedResponse, equals(response)); - verifyNever(() => cborConverter.convertResponse(response)); - verify(() => jsonConverter.convertResponse(response)).called(1); - }); - }); -} - -class MockBaseResponse extends Mock implements http.BaseResponse {} - -class MockConverter extends Mock implements Converter {} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/interceptors/mock_chain.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/interceptors/mock_chain.dart deleted file mode 100644 index 7e3eacd1501f..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/interceptors/mock_chain.dart +++ /dev/null @@ -1,4 +0,0 @@ -import 'package:chopper/chopper.dart'; -import 'package:mocktail/mocktail.dart'; - -class MockChain extends Mock implements Chain {} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/interceptors/mock_response.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/interceptors/mock_response.dart deleted file mode 100644 index d2384279b4cf..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/interceptors/mock_response.dart +++ /dev/null @@ -1,4 +0,0 @@ -import 'package:chopper/chopper.dart'; -import 'package:mocktail/mocktail.dart'; - -final class MockResponse extends Mock with MockResponseMixin {} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/interceptors/rbac_auth_interceptor_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/interceptors/rbac_auth_interceptor_test.dart index 593cb7502f8c..231a3bca8983 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/interceptors/rbac_auth_interceptor_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/interceptors/rbac_auth_interceptor_test.dart @@ -2,297 +2,140 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_repositories/src/api/interceptors/rbac_auth_interceptor.dart'; import 'package:catalyst_voices_repositories/src/auth/auth_token_provider.dart'; import 'package:catalyst_voices_repositories/src/common/http_headers.dart'; -import 'package:catalyst_voices_repositories/src/common/rbac_token_ext.dart'; -import 'package:chopper/chopper.dart'; +import 'package:dio/dio.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:uuid_plus/uuid_plus.dart'; -import '../matcher/request_matchers.dart'; -import 'mock_chain.dart'; -import 'mock_response.dart'; - void main() { group(RbacAuthInterceptor, () { - late final AuthTokenProvider authTokenProvider; - late final RbacAuthInterceptor interceptor; - late final Chain chain; + late AuthTokenProvider authTokenProvider; + late RbacAuthInterceptor interceptor; + late RequestInterceptorHandler requestHandler; + late ErrorInterceptorHandler errorHandler; - setUpAll(() { + setUp(() { authTokenProvider = _MockAuthTokenProvider(); interceptor = RbacAuthInterceptor(authTokenProvider); + requestHandler = _MockRequestInterceptorHandler(); + errorHandler = _MockErrorInterceptorHandler(); - chain = MockChain(); - - registerFallbackValue(Request('X', Uri(), Uri())); - }); - - setUp(() { when( - // ignore: discarded_futures () => authTokenProvider.createRbacToken( forceRefresh: any(named: 'forceRefresh'), ), ).thenAnswer((_) => Future(() => RbacToken(const Uuid().v4()))); }); - tearDown(() { - reset(chain); - }); - - test('when active account keychain is ' - 'unlocked auth header is added', () async { - // Given - final request = Request('GET', Uri(), Uri()); - final requestResponse = MockResponse(); - - // When - when(() => chain.request).thenReturn(request); - when(() => chain.proceed(any())).thenAnswer((_) => requestResponse); - when(() => requestResponse.statusCode).thenAnswer((_) => 200); - - await interceptor.intercept(chain); + test( + 'when active account keychain is ' + 'unlocked auth header is added', + () async { + // Given + final options = RequestOptions(path: '/test'); - // Then - final captured = verify(() => chain.proceed(captureAny())).captured; + // When + await interceptor.onRequest(options, requestHandler); - expect( - (captured.single as Request).headers.containsKey(HttpHeaders.authorization), - isTrue, - ); - }); + // Then + verify(() => requestHandler.next(options)).called(1); + expect(options.headers[HttpHeaders.authorization], isNotNull); + }, + ); test('auth header value start with bearer', () async { // Given - final request = Request('GET', Uri(), Uri()); - final requestResponse = MockResponse(); + final options = RequestOptions(path: '/test'); // When - when(() => chain.request).thenReturn(request); - when(() => chain.proceed(any())).thenAnswer((_) => requestResponse); - when(() => requestResponse.statusCode).thenAnswer((_) => 200); - - await interceptor.intercept(chain); + await interceptor.onRequest(options, requestHandler); // Then - final captured = verify(() => chain.proceed(captureAny())).captured; - - expect( - (captured.single as Request).headers[HttpHeaders.authorization], - startsWith('Bearer'), - ); + expect(options.headers[HttpHeaders.authorization], startsWith('Bearer ')); }); - test('when active account keychain is ' - 'locked auth header is not added', () async { - // Given - final request = Request('GET', Uri(), Uri()); - final requestResponse = MockResponse(); + test( + 'when active account keychain is ' + 'locked auth header is not added', + () async { + // Given + final options = RequestOptions(path: '/test'); - // When - when(() => authTokenProvider.createRbacToken()).thenAnswer((_) => Future.value()); - when(() => chain.request).thenReturn(request); - when(() => chain.proceed(any())).thenAnswer((_) => requestResponse); - when(() => requestResponse.statusCode).thenAnswer((_) => 200); + // When + when(() => authTokenProvider.createRbacToken()).thenAnswer((_) async => null); + await interceptor.onRequest(options, requestHandler); - await interceptor.intercept(chain); - - // Then - final captured = verify(() => chain.proceed(captureAny())).captured; - - expect( - (captured.single as Request).headers.containsKey(HttpHeaders.authorization), - isFalse, - ); - }); + // Then + verify(() => requestHandler.next(options)).called(1); + expect(options.headers.containsKey(HttpHeaders.authorization), isFalse); + }, + ); test('401 response code triggers force token update', () async { // Given - const originalToken = RbacToken('expired_token'); - const refreshedToken = RbacToken('refreshed_token'); - - final request = Request('GET', Uri(), Uri()); - - final originalResponse = MockResponse(); - final retryResponse = MockResponse(); - - // When - when(() => chain.request).thenReturn(request); - - // Original token - when( - () => authTokenProvider.createRbacToken( - forceRefresh: any(named: 'forceRefresh'), + final options = RequestOptions(path: '/test'); + final dioError = DioException( + requestOptions: options, + response: Response( + requestOptions: options, + statusCode: 401, ), - ).thenAnswer((_) => Future.value(originalToken)); - when(() { - return chain.proceed( - any( - that: containsHeaderValue(originalToken.authHeader()), - ), - ); - }).thenAnswer((_) => originalResponse); - - // Refreshed token - when( - () => authTokenProvider.createRbacToken(forceRefresh: true), - ).thenAnswer((_) => Future.value(refreshedToken)); - when(() { - return chain.proceed( - any( - that: containsHeaderValue(refreshedToken.authHeader()), - ), - ); - }).thenAnswer((_) => retryResponse); - - // Responses - when(() => originalResponse.statusCode).thenAnswer((_) => 401); - when(() => retryResponse.statusCode).thenAnswer((_) => 200); + ); - await interceptor.intercept(chain); + // When + await interceptor.onError(dioError, errorHandler); // Then - final captured = verify(() => chain.proceed(captureAny())).captured; - - expect(captured, hasLength(2)); - - expect( - captured.first, - allOf( - isA(), - containsHeaderValue(originalToken.authHeader()), - isNot(containsHeaderKey('Retry-Count')), - ), - ); - expect( - captured[1], - allOf( - isA(), - containsHeaderValue(refreshedToken.authHeader()), - containsHeaderKey('Retry-Count'), - containsHeaderValue('1'), - ), - ); + verify(() => authTokenProvider.createRbacToken(forceRefresh: true)).called(1); + expect(options.headers['Retry-Count'], '1'); }); test('403 response code triggers force token update', () async { // Given - const originalToken = RbacToken('expired_token'); - const refreshedToken = RbacToken('refreshed_token'); - - final request = Request('GET', Uri(), Uri()); - - final originalResponse = MockResponse(); - final retryResponse = MockResponse(); - - // When - when(() => chain.request).thenReturn(request); - - // Original token - when( - () => authTokenProvider.createRbacToken( - forceRefresh: any(named: 'forceRefresh'), + final options = RequestOptions(path: '/test'); + final dioError = DioException( + requestOptions: options, + response: Response( + requestOptions: options, + statusCode: 403, ), - ).thenAnswer((_) => Future.value(originalToken)); - when(() { - return chain.proceed( - any( - that: containsHeaderValue(originalToken.authHeader()), - ), - ); - }).thenAnswer((_) => originalResponse); - - // Refreshed token - when( - () => authTokenProvider.createRbacToken(forceRefresh: true), - ).thenAnswer((_) => Future.value(refreshedToken)); - when(() { - return chain.proceed( - any( - that: containsHeaderValue(refreshedToken.authHeader()), - ), - ); - }).thenAnswer((_) => retryResponse); - - // Responses - when(() => originalResponse.statusCode).thenAnswer((_) => 403); - when(() => retryResponse.statusCode).thenAnswer((_) => 200); + ); - await interceptor.intercept(chain); + // When + await interceptor.onError(dioError, errorHandler); // Then - final captured = verify(() => chain.proceed(captureAny())).captured; - - expect(captured, hasLength(2)); - - expect( - captured.first, - allOf( - isA(), - containsHeaderValue(originalToken.authHeader()), - isNot(containsHeaderKey('Retry-Count')), - ), - ); - expect( - captured[1], - allOf( - isA(), - containsHeaderValue(refreshedToken.authHeader()), - containsHeaderKey('Retry-Count'), - containsHeaderValue('1'), - ), - ); + verify(() => authTokenProvider.createRbacToken(forceRefresh: true)).called(1); + expect(options.headers['Retry-Count'], '1'); }); test('token refresh gives up after 1st try', () async { // Given - const originalToken = RbacToken('expired_token'); - final request = Request( - 'GET', - Uri(), - Uri(), + final options = RequestOptions( + path: '/test', headers: {'Retry-Count': '1'}, ); - final originalResponse = MockResponse(); - - // When - when(() => chain.request).thenReturn(request); - - // Original token - when( - () => authTokenProvider.createRbacToken( - forceRefresh: any(named: 'forceRefresh'), + final dioError = DioException( + requestOptions: options, + response: Response( + requestOptions: options, + statusCode: 401, ), - ).thenAnswer((_) => Future.value(originalToken)); - when(() { - return chain.proceed( - any( - that: containsHeaderValue(originalToken.authHeader()), - ), - ); - }).thenAnswer((_) => originalResponse); - - // Responses - when(() => originalResponse.statusCode).thenAnswer((_) => 403); + ); - await interceptor.intercept(chain); + // When + await interceptor.onError(dioError, errorHandler); // Then - final captured = verify(() => chain.proceed(captureAny())).captured; - - expect(captured, hasLength(1)); - - expect( - captured.first, - allOf( - isA(), - containsHeaderValue(originalToken.authHeader()), - containsHeaderKey('Retry-Count'), - containsHeaderValue('1'), - ), - ); + verify(() => errorHandler.next(dioError)).called(1); + verifyNever(() => authTokenProvider.createRbacToken(forceRefresh: true)); + expect(options.headers['Retry-Count'], '1'); }); }); } class _MockAuthTokenProvider extends Mock implements AuthTokenProvider {} + +class _MockErrorInterceptorHandler extends Mock implements ErrorInterceptorHandler {} + +class _MockRequestInterceptorHandler extends Mock implements RequestInterceptorHandler {} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/matcher/request_matchers.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/matcher/request_matchers.dart deleted file mode 100644 index cb92f077c64a..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/api/matcher/request_matchers.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:chopper/chopper.dart'; -import 'package:flutter_test/flutter_test.dart'; - -Matcher containsHeaderKey(String expected) => _HeaderKey(expected); - -Matcher containsHeaderValue(String expected) => _HeaderValue(expected); - -class _HeaderKey extends Matcher { - final String value; - - _HeaderKey(this.value); - - @override - Description describe(Description description) { - return description.add('contains header key ').addDescriptionOf(value); - } - - @override - bool matches(dynamic item, Map matchState) { - if (item is! Request) { - return false; - } - - return item.headers.containsKey(value); - } -} - -class _HeaderValue extends Matcher { - final String value; - - _HeaderValue(this.value); - - @override - Description describe(Description description) { - return description.add('contains header value ').addDescriptionOf(value); - } - - @override - bool matches(dynamic item, Map matchState) { - if (item is! Request) { - return false; - } - - return item.headers.containsValue(value); - } -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/common/future_response_mapper_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/common/future_response_mapper_test.dart new file mode 100644 index 000000000000..8191c6281b47 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/common/future_response_mapper_test.dart @@ -0,0 +1,99 @@ +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:catalyst_voices_repositories/src/common/future_response_mapper.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('FutureResponseMapper', () { + test('successBodyOrThrow returns body when successful', () async { + const body = 'Success!'; + final futureResponse = Future.value(body); + + final result = await futureResponse.successBodyOrThrow(); + expect(result, equals(body)); + }); + + test('successBodyOrThrow throws NotFoundException for 404', () async { + final futureResponse = Future.error( + const ApiBadResponseException( + statusCode: ApiResponseStatusCode.notFound, + message: 'Not found', + ), + ); + + await expectLater( + futureResponse.successBodyOrThrow(), + throwsA(isA()), + ); + }); + + test('successBodyOrThrow throws UnauthorizedException for 401', () async { + final futureResponse = Future.error( + const ApiBadResponseException( + statusCode: ApiResponseStatusCode.unauthorized, + message: 'Unauthorized', + ), + ); + + await expectLater( + futureResponse.successBodyOrThrow(), + throwsA(isA()), + ); + }); + + test('successBodyOrThrow throws ResourceConflictException for 409', () async { + final futureResponse = Future.error( + const ApiBadResponseException( + statusCode: ApiResponseStatusCode.conflict, + message: 'Conflict', + ), + ); + + await expectLater( + futureResponse.successBodyOrThrow(), + throwsA(isA()), + ); + }); + + test('successBodyOrThrow rethrows other ApiBadResponseException', () async { + final futureResponse = Future.error( + const ApiBadResponseException( + statusCode: ApiResponseStatusCode.internalServerError, + message: 'Internal Error', + ), + ); + + await expectLater( + futureResponse.successBodyOrThrow(), + throwsA(isA()), + ); + }); + + test('successBodyOrThrow rethrows non-ApiBadResponseException errors', () async { + final futureResponse = Future.error( + Exception('Some other error'), + ); + + await expectLater( + futureResponse.successBodyOrThrow(), + throwsA(isA()), + ); + }); + + test('successBodyOrThrow extracts message from exception', () async { + const errorMessage = 'Resource not found'; + final futureResponse = Future.error( + const ApiBadResponseException( + statusCode: ApiResponseStatusCode.notFound, + message: errorMessage, + ), + ); + + try { + await futureResponse.successBodyOrThrow(); + fail('Should have thrown NotFoundException'); + } on NotFoundException catch (e) { + expect(e.message, equals(errorMessage)); + } + }); + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/common/response_mapper_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/common/response_mapper_test.dart deleted file mode 100644 index 41df29c1d4eb..000000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/common/response_mapper_test.dart +++ /dev/null @@ -1,189 +0,0 @@ -// test/response_mapper_test.dart -import 'dart:io'; -import 'dart:typed_data'; - -import 'package:catalyst_voices_models/catalyst_voices_models.dart'; -import 'package:catalyst_voices_repositories/src/common/response_mapper.dart'; -import 'package:chopper/chopper.dart' as chopper; -import 'package:flutter_test/flutter_test.dart'; -import 'package:http/http.dart' as http; - -void main() { - chopper.Response mockResponse({ - int statusCode = HttpStatus.ok, - String body = '', - Object? error, - }) { - return chopper.Response( - http.Response(body, statusCode), - body, - error: error, - ); - } - - chopper.Response mockBinaryResponse({ - int statusCode = HttpStatus.ok, - List body = const [], - Object? error, - }) { - return chopper.Response( - http.Response.bytes(body, statusCode), - Uint8List.fromList(body), - error: error, - ); - } - - group('ResponseMapper', () { - test('successBodyBytesOrThrow returns bodyBytes when successful', () { - final bytes = Uint8List.fromList([1, 2, 3]); - final response = mockBinaryResponse(body: bytes); - - final result = response.successBodyBytesOrThrow(); - expect(result, equals(bytes)); - }); - - test('successBodyBytesOrThrow throws $NotFoundException for 404', () { - final response = mockBinaryResponse( - statusCode: HttpStatus.notFound, - ); - - expect( - response.successBodyBytesOrThrow, - throwsA(isA()), - ); - }); - - test('successBodyBytesOrThrow throws $ResourceConflictException for 409', () { - final response = mockBinaryResponse( - statusCode: HttpStatus.conflict, - ); - - expect( - response.successBodyBytesOrThrow, - throwsA(const ResourceConflictException()), - ); - }); - - test('successBodyBytesOrThrow throws $ApiErrorResponseException otherwise', () { - final response = mockBinaryResponse( - statusCode: HttpStatus.internalServerError, - error: 'Internal Error', - ); - - expect( - response.successBodyBytesOrThrow, - throwsA(isA()), - ); - }); - - test('successBodyOrThrow returns body when successful', () { - const body = 'Success!'; - final response = mockResponse(body: body); - - final result = response.successBodyOrThrow(); - expect(result, equals(body)); - }); - - test('successBodyOrThrow throws $NotFoundException for 404', () { - final response = mockResponse(statusCode: HttpStatus.notFound); - - expect( - response.successBodyOrThrow, - throwsA(isA()), - ); - }); - - test('successBodyOrThrow throws $ResourceConflictException for 409', () { - final response = mockResponse( - statusCode: HttpStatus.conflict, - ); - - expect( - response.successBodyOrThrow, - throwsA(const ResourceConflictException()), - ); - }); - - test('successBodyOrThrow throws $ApiErrorResponseException otherwise', () { - final response = mockResponse( - statusCode: HttpStatus.internalServerError, - error: 'Internal Error', - ); - - expect( - response.successBodyOrThrow, - throwsA(isA()), - ); - }); - - test('successOrThrow returns normally when successful', () { - const body = 'Success!'; - final response = mockResponse(body: body); - - expect(response.successOrThrow, returnsNormally); - }); - - test('successOrThrow throws $NotFoundException for 404', () { - final response = mockResponse(statusCode: HttpStatus.notFound); - - expect( - response.successOrThrow, - throwsA(isA()), - ); - }); - - test('successOrThrow throws $ResourceConflictException for 409', () { - final response = mockResponse( - statusCode: HttpStatus.conflict, - ); - - expect( - response.successOrThrow, - throwsA(const ResourceConflictException()), - ); - }); - - test('successOrThrow throws $ApiErrorResponseException otherwise', () { - final response = mockResponse( - statusCode: HttpStatus.internalServerError, - error: 'Internal Error', - ); - - expect( - response.successOrThrow, - throwsA(isA()), - ); - }); - }); - - group('FutureResponseMapper', () { - test('successBodyBytesOrThrow awaits and returns result', () async { - final bytes = Uint8List.fromList([1, 2, 3]); - final response = mockBinaryResponse(body: bytes); - - final futureResponse = Future.value(response); - final result = await futureResponse.successBodyBytesOrThrow(); - expect(result, equals(bytes)); - }); - - test('successBodyOrThrow awaits and returns result', () async { - const body = 'Hello!'; - final response = mockResponse(body: body); - - final futureResponse = Future.value(response); - final result = await futureResponse.successBodyOrThrow(); - expect(result, equals(body)); - }); - - test('successOrThrow awaits and returns normally', () async { - const body = 'Hello!'; - final response = mockResponse(body: body); - - final futureResponse = Future.value(response); - expect( - futureResponse.successBodyOrThrow, - returnsNormally, - ); - }); - }); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/config/remote_config_source_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/config/remote_config_source_test.dart index 81032643528a..b1a1483bd193 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/config/remote_config_source_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/config/remote_config_source_test.dart @@ -1,16 +1,15 @@ import 'package:catalyst_voices_repositories/catalyst_voices_repositories.dart'; -import 'package:chopper/chopper.dart'; +import 'package:catalyst_voices_repositories/src/dto/config/remote_blockchain_config.dart'; +import 'package:catalyst_voices_repositories/src/dto/config/remote_config.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:http/http.dart' as http; import 'package:mocktail/mocktail.dart'; void main() { - final CatGateway gateway = _MockedCatGateway(); - final CatReviews reviews = _MockedCatReviews(); - final CatStatus status = _MockedCatStatus(); + final CatGatewayService gateway = _MockedCatGateway(); + final CatReviewsService reviews = _MockedCatReviews(); + final CatStatusService status = _MockedCatStatus(); late final ApiServices apiServices; - late final ApiConfigSource source; setUpAll(() { @@ -32,11 +31,10 @@ void main() { group(ApiConfigSource, () { test('empty config is parsed correctly', () async { // Given - const configJson = '{}'; - final response = Response(http.Response('', 200), configJson); + const remoteConfig = RemoteConfig(); // When - when(gateway.apiV1ConfigFrontendGet).thenAnswer((_) => Future.value(response)); + when(gateway.frontendConfig).thenAnswer((_) async => remoteConfig); // Then final config = await source.get(); @@ -46,29 +44,9 @@ void main() { expect(config.cache, isNull); }); - test('invalid type is falling back to empty', () async { - // Given - const configJson = '1'; - final response = Response(http.Response('', 200), configJson); - - // When - when(gateway.apiV1ConfigFrontendGet).thenAnswer((_) => Future.value(response)); - - // Then - final config = await source.get(); - - expect(config.blockchain, isNull); - expect(config.sentry, isNull); - expect(config.cache, isNull); - }); - - test('invalid json is falling back to empty', () async { - // Given - const configJson = '[]'; - final response = Response(http.Response('', 200), configJson); - + test('error is falling back to empty', () async { // When - when(gateway.apiV1ConfigFrontendGet).thenAnswer((_) => Future.value(response)); + when(gateway.frontendConfig).thenThrow(Exception('network error')); // Then final config = await source.get(); @@ -78,17 +56,14 @@ void main() { expect(config.cache, isNull); }); - test('a json map is passed through not changed', () async { + test('config with blockchain data is parsed correctly', () async { // Given - const configJson = { - 'blockchain': { - 'networkId': 'mainnet', - }, - }; - final response = Response(http.Response('', 200), configJson); + final remoteConfig = RemoteConfig( + blockchain: RemoteBlockchainConfig(networkId: 'mainnet'), + ); // When - when(gateway.apiV1ConfigFrontendGet).thenAnswer((_) => Future.value(response)); + when(gateway.frontendConfig).thenAnswer((_) async => remoteConfig); // Then final config = await source.get(); @@ -98,8 +73,8 @@ void main() { }); } -class _MockedCatGateway extends Mock implements CatGateway {} +class _MockedCatGateway extends Mock implements CatGatewayService {} -class _MockedCatReviews extends Mock implements CatReviews {} +class _MockedCatReviews extends Mock implements CatReviewsService {} -class _MockedCatStatus extends Mock implements CatStatus {} +class _MockedCatStatus extends Mock implements CatStatusService {} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/dao/documents_dao_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/dao/documents_dao_test.dart index 62651b5912e0..c7be645a2093 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/dao/documents_dao_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/dao/documents_dao_test.dart @@ -146,8 +146,7 @@ void main() { final documentsWithMetadata = [ DocumentWithMetadataFactory.build( content: const DocumentDataContent({'title': 'D'}), - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: SignedDocumentRef( id: id, version: firstVersionId, @@ -156,8 +155,7 @@ void main() { ), DocumentWithMetadataFactory.build( content: secondContent, - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: SignedDocumentRef( id: id, version: secondVersionId, @@ -212,10 +210,7 @@ void main() { final documentsWithMetadata = refs.map((ref) { return DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, - selfRef: ref, - ), + metadata: DocumentDataMetadataFactory.proposal(selfRef: ref), ); }); final typedRefs = refs.map((e) => e.toTyped(DocumentType.proposalDocument)).toList(); @@ -242,14 +237,12 @@ void main() { final version2 = DocumentRefFactory.randomUuidV7(); final document = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: SignedDocumentRef(id: id, version: version), ), ); final document2 = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: SignedDocumentRef(id: id, version: version2), ), ); @@ -337,8 +330,7 @@ void main() { final v2 = DocumentRefFactory.randomUuidV7(); final documentsWithMetadata = [v1, v2].map((version) { - final metadata = DocumentDataMetadata( - type: DocumentType.proposalDocument, + final metadata = DocumentDataMetadataFactory.proposal( selfRef: SignedDocumentRef( id: id, version: version, @@ -380,8 +372,7 @@ void main() { final v2 = DocumentRefFactory.randomUuidV7(); final documentsWithMetadata = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: SignedDocumentRef( id: id, version: v1, @@ -390,8 +381,7 @@ void main() { ); final newVersion = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: SignedDocumentRef( id: id, version: v2, @@ -432,8 +422,7 @@ void main() { final v2 = DocumentRefFactory.randomUuidV7(); final document1 = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: SignedDocumentRef( id: id1, version: v1, @@ -442,8 +431,7 @@ void main() { ); final document2 = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: SignedDocumentRef( id: id2, version: v2, @@ -481,17 +469,13 @@ void main() { final updatedId = originalId.copyWith(username: const Optional('dev')); final document1 = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, - selfRef: DocumentRefFactory.signedDocumentRef(), + metadata: DocumentDataMetadataFactory.proposal( authors: [originalId], ), ); final document2 = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, - selfRef: DocumentRefFactory.signedDocumentRef(), + metadata: DocumentDataMetadataFactory.proposal( authors: [updatedId], ), ); @@ -526,16 +510,12 @@ void main() { 'queryRefToDocumentData returns correct document', () async { final document1 = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, - selfRef: DocumentRefFactory.signedDocumentRef(), - ), + metadata: DocumentDataMetadataFactory.proposal(), ); final document2 = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, - selfRef: DocumentRefFactory.signedDocumentRef(), - ref: document1.document.metadata.selfRef, + metadata: DocumentDataMetadataFactory.comment( + proposalRef: document1.document.metadata.selfRef as SignedDocumentRef, + parameters: document1.document.metadata.parameters, ), ); @@ -543,7 +523,7 @@ void main() { final document = await database.documentsDao.queryRefToDocumentData( refTo: document1.document.metadata.selfRef, - type: DocumentType.proposalDocument, + type: DocumentType.commentDocument, ); expect( @@ -559,28 +539,23 @@ void main() { () async { // Given final baseDocument = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, - selfRef: DocumentRefFactory.signedDocumentRef(), - ), + metadata: DocumentDataMetadataFactory.proposal(), ); final referencingDocument = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.commentTemplate, + metadata: DocumentDataMetadataFactory.comment( selfRef: DocumentRefFactory.signedDocumentRef(), - ref: baseDocument.document.metadata.selfRef, + proposalRef: baseDocument.document.metadata.selfRef as SignedDocumentRef, ), ); final newerVersion = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.commentTemplate, + metadata: DocumentDataMetadataFactory.comment( selfRef: SignedDocumentRef( id: referencingDocument.document.metadata.id, version: DocumentRefFactory.randomUuidV7(), ), - ref: baseDocument.document.metadata.selfRef, + proposalRef: baseDocument.document.metadata.selfRef as SignedDocumentRef, ), ); @@ -588,7 +563,7 @@ void main() { final documentsStream = database.documentsDao .watchRefToDocumentData( refTo: baseDocument.document.metadata.selfRef, - type: DocumentType.commentTemplate, + type: DocumentType.commentDocument, ) .asBroadcastStream(); @@ -673,8 +648,7 @@ void main() { final doc1 = DocumentWithMetadataFactory.build( content: content1, - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: ref1, template: SignedDocumentRef(id: templateRef, version: templateRef), ), @@ -682,8 +656,7 @@ void main() { final doc2 = DocumentWithMetadataFactory.build( content: content2, - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: ref2, template: SignedDocumentRef(id: templateRef, version: templateRef), ), @@ -744,8 +717,7 @@ void main() { final doc1 = DocumentWithMetadataFactory.build( content: content1, - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: ref1, template: SignedDocumentRef(id: templateRef, version: templateRef), ), @@ -826,8 +798,7 @@ void main() { final doc1 = DocumentWithMetadataFactory.build( content: content1, - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: ref1, template: SignedDocumentRef(id: templateRef, version: templateRef), ), @@ -835,8 +806,7 @@ void main() { final doc2 = DocumentWithMetadataFactory.build( content: content2, - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: ref2, template: SignedDocumentRef(id: templateRef, version: templateRef), ), @@ -873,8 +843,7 @@ void main() { final documentsWithMetadata = List.generate( 20, (index) => DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: _buildRefAt(dateTime.add(Duration(seconds: index))), ), ), @@ -899,8 +868,7 @@ void main() { final documentsWithMetadata = List.generate( 2, (index) { - final metadata = DocumentDataMetadata( - type: DocumentType.proposalDocument, + final metadata = DocumentDataMetadataFactory.proposal( selfRef: SignedDocumentRef(id: id, version: DocumentRefFactory.randomUuidV7()), ); return DocumentWithMetadataFactory.build(metadata: metadata); @@ -926,8 +894,7 @@ void main() { final documentsWithMetadata = List.generate( 2, (index) { - final metadata = DocumentDataMetadata( - type: DocumentType.proposalDocument, + final metadata = DocumentDataMetadataFactory.proposal( selfRef: SignedDocumentRef(id: id, version: DocumentRefFactory.randomUuidV7()), ); return DocumentWithMetadataFactory.build(metadata: metadata); @@ -956,8 +923,7 @@ void main() { final documentsWithMetadata = List.generate( 2, (index) { - final metadata = DocumentDataMetadata( - type: DocumentType.proposalDocument, + final metadata = DocumentDataMetadataFactory.proposal( selfRef: SignedDocumentRef(id: id, version: DocumentRefFactory.randomUuidV7()), ); return DocumentWithMetadataFactory.build(metadata: metadata); @@ -985,10 +951,7 @@ void main() { final documentsWithMetadata = List.generate( 10, (index) { - final metadata = DocumentDataMetadata( - type: DocumentType.proposalDocument, - selfRef: DocumentRefFactory.signedDocumentRef(), - ); + final metadata = DocumentDataMetadataFactory.proposal(); return DocumentWithMetadataFactory.build(metadata: metadata); }, ); @@ -1018,8 +981,7 @@ void main() { version: versionId, ); final proposal = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: proposalRef, ), ); @@ -1029,20 +991,18 @@ void main() { final comments = List.generate( 10, (index) => DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.commentTemplate, + metadata: DocumentDataMetadataFactory.comment( selfRef: DocumentRefFactory.signedDocumentRef(), - ref: proposalRef, + proposalRef: proposalRef, ), ), ); final otherComments = List.generate( 5, (index) => DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.commentTemplate, + metadata: DocumentDataMetadataFactory.comment( selfRef: DocumentRefFactory.signedDocumentRef(), - ref: DocumentRefFactory.signedDocumentRef(), + proposalRef: DocumentRefFactory.signedDocumentRef(), ), ), ); @@ -1050,7 +1010,7 @@ void main() { final count = await database.documentsDao.countRefDocumentByType( ref: proposalRef, - type: DocumentType.commentTemplate, + type: DocumentType.commentDocument, ); expect(count, equals(10)); @@ -1068,8 +1028,7 @@ void main() { version: versionId, ); final proposal = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: proposalRef, ), ); @@ -1080,13 +1039,11 @@ void main() { 10, (index) { return DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: SignedDocumentRef( id: proposalId, version: DocumentRefFactory.randomUuidV7(), ), - ref: proposalRef, ), ); }, @@ -1115,8 +1072,7 @@ void main() { version: versionId, ); final proposal = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: proposalRef, ), ); @@ -1130,19 +1086,17 @@ void main() { final comments = List.generate(2, (index) { return DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.commentTemplate, + metadata: DocumentDataMetadataFactory.comment( selfRef: DocumentRefFactory.signedDocumentRef(), - ref: proposalRef, + proposalRef: proposalRef, ), ); }); final otherComment = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.commentTemplate, + metadata: DocumentDataMetadataFactory.comment( selfRef: DocumentRefFactory.signedDocumentRef(), - ref: proposalRef2, + proposalRef: proposalRef2, ), ); @@ -1151,7 +1105,7 @@ void main() { final documentCount = database.documentsDao .watchCount( refTo: proposalRef, - type: DocumentType.commentTemplate, + type: DocumentType.commentDocument, ) .asBroadcastStream(); @@ -1221,15 +1175,11 @@ void main() { () async { // Given final template = DocumentWithMetadataFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalTemplate, - selfRef: DocumentRefFactory.signedDocumentRef(), - ), + metadata: DocumentDataMetadataFactory.proposal(), ); final localDraft = DraftFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: DocumentRefFactory.draftRef(), template: template.document.metadata.selfRef as SignedDocumentRef, ), diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/dao/drafts_dao_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/dao/drafts_dao_test.dart index 45947d03b1d4..1b395fb9c60e 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/dao/drafts_dao_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/dao/drafts_dao_test.dart @@ -75,14 +75,12 @@ void main() { final drafts = [ DraftFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: DraftRef(id: id, version: firstVersionId), ), ), DraftFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: DraftRef(id: id, version: secondVersionId), ), ), @@ -134,8 +132,7 @@ void main() { ); final drafts = refs.map((ref) { return DraftFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: ref, ), ); @@ -165,8 +162,7 @@ void main() { final ref = DocumentRefFactory.draftRef(); // Given final draft = DraftFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: ref, authors: [ authorId1, @@ -197,8 +193,7 @@ void main() { final ref = DocumentRefFactory.draftRef(); // Given final draft = DraftFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: ref, authors: [ authorId1, @@ -246,15 +241,13 @@ void main() { final updatedId = originalId.copyWith(username: const Optional('dev')); final draft1 = DraftFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: DocumentRefFactory.signedDocumentRef(), authors: [originalId], ), ); final draft2 = DraftFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: DocumentRefFactory.signedDocumentRef(), authors: [updatedId], ), @@ -297,8 +290,7 @@ void main() { 2, (index) { return DraftFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: DraftRef( id: id, version: DocumentRefFactory.randomUuidV7(), @@ -328,14 +320,12 @@ void main() { final version = DocumentRefFactory.randomUuidV7(); final drafts = [ DraftFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: DraftRef(id: id, version: version), ), ), DraftFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: DraftRef.first(id), ), ), @@ -413,8 +403,7 @@ void main() { final drafts = List.generate( 5, (index) => DraftFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: DraftRef(id: id, version: const Uuid().v7()), ), ), @@ -450,8 +439,7 @@ void main() { final ref = DocumentRefFactory.draftRef(); final draft = DraftFactory.build( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadataFactory.proposal( selfRef: ref, ), ); diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/dao/proposals_dao_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/dao/proposals_dao_test.dart index af6f21da204d..6e1204fe4218 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/dao/proposals_dao_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/dao/proposals_dao_test.dart @@ -411,19 +411,19 @@ void main() { () async { // Given final userId = DummyCatalystIdFactory.create(username: 'damian'); - final categoryId = _getCategoryId(); + final categoryRef = _getCategoryRef(); final proposalOneRef = DocumentRefFactory.signedDocumentRef(); final proposalTwoRef = DocumentRefFactory.signedDocumentRef(); final proposals = [ _buildProposal( selfRef: proposalOneRef, - categoryId: _getCategoryId(index: 1), + categoryRef: _getCategoryRef(index: 1), ), _buildProposal( selfRef: proposalTwoRef, author: userId, - categoryId: categoryId, + categoryRef: categoryRef, ), ]; final favorites = [ @@ -433,10 +433,11 @@ void main() { _buildProposalAction( action: ProposalSubmissionActionDto.aFinal, proposalRef: proposalTwoRef, + categoryRef: categoryRef, ), ]; - final filters = ProposalsCountFilters(category: categoryId); + final filters = ProposalsCountFilters(category: categoryRef); const expectedCount = ProposalsCount( total: 1, finals: 1, @@ -761,7 +762,7 @@ void main() { () async { // Given final templateRef = DocumentRefFactory.signedDocumentRef(); - final categoryId = _getCategoryId(); + final categoryRef = _getCategoryRef(); final templates = [ _buildProposalTemplate(selfRef: templateRef), @@ -771,21 +772,21 @@ void main() { _buildProposal( selfRef: _buildRefAt(DateTime(2025, 4)), template: templateRef, - categoryId: categoryId, + categoryRef: categoryRef, ), _buildProposal( selfRef: _buildRefAt(DateTime(2025, 4, 2)), template: templateRef, - categoryId: categoryId, + categoryRef: categoryRef, ), _buildProposal( selfRef: _buildRefAt(DateTime(2025, 4, 3)), template: templateRef, - categoryId: categoryId, + categoryRef: categoryRef, ), _buildProposal( template: templateRef, - categoryId: _getCategoryId(index: 1), + categoryRef: _getCategoryRef(index: 1), ), ]; @@ -794,7 +795,7 @@ void main() { .map((proposal) => proposal.document.ref) .toList(); - final filters = ProposalsFilters(category: categoryId); + final filters = ProposalsFilters(category: categoryRef); const order = UpdateDate(isAscending: true); // When @@ -1671,18 +1672,18 @@ void main() { _buildProposal( selfRef: _buildRefAt(DateTime(2025, 4, 2)), template: templateRef, - categoryId: _getCategoryId(index: 1), + categoryRef: _getCategoryRef(index: 1), ), _buildProposal( selfRef: _buildRefAt(DateTime(2025, 4, 3)), template: templateRef, - categoryId: _getCategoryId(index: 1), + categoryRef: _getCategoryRef(index: 1), ), ]; final expectedRefs = proposals .where( - (p) => p.document.metadata.categoryId == _getCategoryId(index: 1), + (p) => p.document.metadata.parameters.contains(_getCategoryRef(index: 1)), ) .map((proposal) => proposal.document.ref) .toList(); @@ -1692,7 +1693,7 @@ void main() { // Then final result = await database.proposalsDao.queryProposals( - categoryRef: _getCategoryId(index: 1), + categoryRef: _getCategoryRef(index: 1), filters: const ProposalsFilters(), ); @@ -2001,17 +2002,16 @@ DocumentEntityWithMetadata _buildProposal({ String? title, CatalystId? author, String? contentAuthorName, - SignedDocumentRef? categoryId, + SignedDocumentRef? categoryRef, Coin? requestedFunds, }) { - final metadata = DocumentDataMetadata( - type: DocumentType.proposalDocument, - selfRef: selfRef ?? DocumentRefFactory.signedDocumentRef(), - template: template ?? DocumentRefFactory.signedDocumentRef(), + final metadata = DocumentDataMetadataFactory.proposal( + selfRef: selfRef, + template: template, authors: [ if (author != null) author, ], - categoryId: categoryId ?? _getCategoryId(), + parameters: DocumentParameters({categoryRef ?? _getCategoryRef()}), ); final content = DocumentDataContent({ if (title != null || contentAuthorName != null) @@ -2051,14 +2051,15 @@ DocumentEntityWithMetadata _buildProposal({ } DocumentEntityWithMetadata _buildProposalAction({ - DocumentRef? selfRef, + SignedDocumentRef? selfRef, required ProposalSubmissionActionDto action, - required DocumentRef proposalRef, + required SignedDocumentRef proposalRef, + SignedDocumentRef? categoryRef, }) { - final metadata = DocumentDataMetadata( - type: DocumentType.proposalActionDocument, - selfRef: selfRef ?? DocumentRefFactory.signedDocumentRef(), - ref: proposalRef, + final metadata = DocumentDataMetadataFactory.proposalAction( + selfRef: selfRef, + proposalRef: proposalRef, + parameters: DocumentParameters({categoryRef ?? _getCategoryRef()}), ); final dto = ProposalSubmissionActionDocumentDto(action: action); final content = DocumentDataContent(dto.toJson()); @@ -2075,12 +2076,11 @@ DocumentEntityWithMetadata _buildProposalAction({ DocumentEntityWithMetadata _buildProposalComment({ SignedDocumentRef? selfRef, - required DocumentRef proposalRef, + required SignedDocumentRef proposalRef, }) { - final metadata = DocumentDataMetadata( - type: DocumentType.commentDocument, + final metadata = DocumentDataMetadataFactory.comment( selfRef: selfRef ?? DocumentRefFactory.signedDocumentRef(), - ref: proposalRef, + proposalRef: proposalRef, ); const content = DocumentDataContent({}); @@ -2109,10 +2109,7 @@ DocumentFavoriteEntity _buildProposalFavorite({ DocumentEntityWithMetadata _buildProposalTemplate({ SignedDocumentRef? selfRef, }) { - final metadata = DocumentDataMetadata( - type: DocumentType.proposalTemplate, - selfRef: selfRef ?? DocumentRefFactory.signedDocumentRef(), - ); + final metadata = DocumentDataMetadataFactory.proposalTemplate(selfRef: selfRef); const content = DocumentDataContent({}); final document = DocumentFactory.build( @@ -2134,7 +2131,7 @@ String _buildUuidAt(DateTime dateTime) { return const Uuid().v7(config: config); } -SignedDocumentRef _getCategoryId({ +SignedDocumentRef _getCategoryRef({ int index = 0, }) { return activeConstantDocumentRefs.elementAtOrNull(index)?.category ?? diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/migration/catalyst_database/generated/schema.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/migration/catalyst_database/generated/schema.dart new file mode 100644 index 000000000000..8312cc63ab7e --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/migration/catalyst_database/generated/schema.dart @@ -0,0 +1,23 @@ +// dart format width=80 +// GENERATED CODE, DO NOT EDIT BY HAND. +// ignore_for_file: type=lint +import 'package:drift/drift.dart'; +import 'package:drift/internal/migrations.dart'; +import 'schema_v3.dart' as v3; +import 'schema_v4.dart' as v4; + +class GeneratedHelper implements SchemaInstantiationHelper { + @override + GeneratedDatabase databaseForVersion(QueryExecutor db, int version) { + switch (version) { + case 3: + return v3.DatabaseAtV3(db); + case 4: + return v4.DatabaseAtV4(db); + default: + throw MissingSchemaException(version, versions); + } + } + + static const versions = const [3, 4]; +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/migration/catalyst_database/generated/schema_v3.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/migration/catalyst_database/generated/schema_v3.dart new file mode 100644 index 000000000000..1538a61d588d --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/migration/catalyst_database/generated/schema_v3.dart @@ -0,0 +1,1363 @@ +// dart format width=80 +import 'dart:typed_data' as i2; +// GENERATED CODE, DO NOT EDIT BY HAND. +// ignore_for_file: type=lint +import 'package:drift/drift.dart'; + +class Documents extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Documents(this.attachedDatabase, [this._alias]); + late final GeneratedColumn idHi = GeneratedColumn( + 'id_hi', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn idLo = GeneratedColumn( + 'id_lo', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn verHi = GeneratedColumn( + 'ver_hi', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn verLo = GeneratedColumn( + 'ver_lo', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn content = + GeneratedColumn( + 'content', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + late final GeneratedColumn metadata = + GeneratedColumn( + 'metadata', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + idHi, + idLo, + verHi, + verLo, + content, + metadata, + type, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'documents'; + @override + Set get $primaryKey => {idHi, idLo, verHi, verLo}; + @override + DocumentsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return DocumentsData( + idHi: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}id_hi'], + )!, + idLo: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}id_lo'], + )!, + verHi: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}ver_hi'], + )!, + verLo: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}ver_lo'], + )!, + content: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}content'], + )!, + metadata: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}metadata'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + Documents createAlias(String alias) { + return Documents(attachedDatabase, alias); + } +} + +class DocumentsData extends DataClass implements Insertable { + final BigInt idHi; + final BigInt idLo; + final BigInt verHi; + final BigInt verLo; + final i2.Uint8List content; + final i2.Uint8List metadata; + final String type; + final DateTime createdAt; + const DocumentsData({ + required this.idHi, + required this.idLo, + required this.verHi, + required this.verLo, + required this.content, + required this.metadata, + required this.type, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id_hi'] = Variable(idHi); + map['id_lo'] = Variable(idLo); + map['ver_hi'] = Variable(verHi); + map['ver_lo'] = Variable(verLo); + map['content'] = Variable(content); + map['metadata'] = Variable(metadata); + map['type'] = Variable(type); + map['created_at'] = Variable(createdAt); + return map; + } + + factory DocumentsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return DocumentsData( + idHi: serializer.fromJson(json['idHi']), + idLo: serializer.fromJson(json['idLo']), + verHi: serializer.fromJson(json['verHi']), + verLo: serializer.fromJson(json['verLo']), + content: serializer.fromJson(json['content']), + metadata: serializer.fromJson(json['metadata']), + type: serializer.fromJson(json['type']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'idHi': serializer.toJson(idHi), + 'idLo': serializer.toJson(idLo), + 'verHi': serializer.toJson(verHi), + 'verLo': serializer.toJson(verLo), + 'content': serializer.toJson(content), + 'metadata': serializer.toJson(metadata), + 'type': serializer.toJson(type), + 'createdAt': serializer.toJson(createdAt), + }; + } + + DocumentsData copyWith({ + BigInt? idHi, + BigInt? idLo, + BigInt? verHi, + BigInt? verLo, + i2.Uint8List? content, + i2.Uint8List? metadata, + String? type, + DateTime? createdAt, + }) => DocumentsData( + idHi: idHi ?? this.idHi, + idLo: idLo ?? this.idLo, + verHi: verHi ?? this.verHi, + verLo: verLo ?? this.verLo, + content: content ?? this.content, + metadata: metadata ?? this.metadata, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + ); + DocumentsData copyWithCompanion(DocumentsCompanion data) { + return DocumentsData( + idHi: data.idHi.present ? data.idHi.value : this.idHi, + idLo: data.idLo.present ? data.idLo.value : this.idLo, + verHi: data.verHi.present ? data.verHi.value : this.verHi, + verLo: data.verLo.present ? data.verLo.value : this.verLo, + content: data.content.present ? data.content.value : this.content, + metadata: data.metadata.present ? data.metadata.value : this.metadata, + type: data.type.present ? data.type.value : this.type, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('DocumentsData(') + ..write('idHi: $idHi, ') + ..write('idLo: $idLo, ') + ..write('verHi: $verHi, ') + ..write('verLo: $verLo, ') + ..write('content: $content, ') + ..write('metadata: $metadata, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + idHi, + idLo, + verHi, + verLo, + $driftBlobEquality.hash(content), + $driftBlobEquality.hash(metadata), + type, + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is DocumentsData && + other.idHi == this.idHi && + other.idLo == this.idLo && + other.verHi == this.verHi && + other.verLo == this.verLo && + $driftBlobEquality.equals(other.content, this.content) && + $driftBlobEquality.equals(other.metadata, this.metadata) && + other.type == this.type && + other.createdAt == this.createdAt); +} + +class DocumentsCompanion extends UpdateCompanion { + final Value idHi; + final Value idLo; + final Value verHi; + final Value verLo; + final Value content; + final Value metadata; + final Value type; + final Value createdAt; + final Value rowid; + const DocumentsCompanion({ + this.idHi = const Value.absent(), + this.idLo = const Value.absent(), + this.verHi = const Value.absent(), + this.verLo = const Value.absent(), + this.content = const Value.absent(), + this.metadata = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + DocumentsCompanion.insert({ + required BigInt idHi, + required BigInt idLo, + required BigInt verHi, + required BigInt verLo, + required i2.Uint8List content, + required i2.Uint8List metadata, + required String type, + required DateTime createdAt, + this.rowid = const Value.absent(), + }) : idHi = Value(idHi), + idLo = Value(idLo), + verHi = Value(verHi), + verLo = Value(verLo), + content = Value(content), + metadata = Value(metadata), + type = Value(type), + createdAt = Value(createdAt); + static Insertable custom({ + Expression? idHi, + Expression? idLo, + Expression? verHi, + Expression? verLo, + Expression? content, + Expression? metadata, + Expression? type, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (idHi != null) 'id_hi': idHi, + if (idLo != null) 'id_lo': idLo, + if (verHi != null) 'ver_hi': verHi, + if (verLo != null) 'ver_lo': verLo, + if (content != null) 'content': content, + if (metadata != null) 'metadata': metadata, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + DocumentsCompanion copyWith({ + Value? idHi, + Value? idLo, + Value? verHi, + Value? verLo, + Value? content, + Value? metadata, + Value? type, + Value? createdAt, + Value? rowid, + }) { + return DocumentsCompanion( + idHi: idHi ?? this.idHi, + idLo: idLo ?? this.idLo, + verHi: verHi ?? this.verHi, + verLo: verLo ?? this.verLo, + content: content ?? this.content, + metadata: metadata ?? this.metadata, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (idHi.present) { + map['id_hi'] = Variable(idHi.value); + } + if (idLo.present) { + map['id_lo'] = Variable(idLo.value); + } + if (verHi.present) { + map['ver_hi'] = Variable(verHi.value); + } + if (verLo.present) { + map['ver_lo'] = Variable(verLo.value); + } + if (content.present) { + map['content'] = Variable(content.value); + } + if (metadata.present) { + map['metadata'] = Variable(metadata.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('DocumentsCompanion(') + ..write('idHi: $idHi, ') + ..write('idLo: $idLo, ') + ..write('verHi: $verHi, ') + ..write('verLo: $verLo, ') + ..write('content: $content, ') + ..write('metadata: $metadata, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class DocumentsMetadata extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + DocumentsMetadata(this.attachedDatabase, [this._alias]); + late final GeneratedColumn verHi = GeneratedColumn( + 'ver_hi', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn verLo = GeneratedColumn( + 'ver_lo', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn fieldKey = GeneratedColumn( + 'field_key', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn fieldValue = GeneratedColumn( + 'field_value', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [verHi, verLo, fieldKey, fieldValue]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'documents_metadata'; + @override + Set get $primaryKey => {verHi, verLo, fieldKey}; + @override + DocumentsMetadataData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return DocumentsMetadataData( + verHi: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}ver_hi'], + )!, + verLo: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}ver_lo'], + )!, + fieldKey: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}field_key'], + )!, + fieldValue: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}field_value'], + )!, + ); + } + + @override + DocumentsMetadata createAlias(String alias) { + return DocumentsMetadata(attachedDatabase, alias); + } +} + +class DocumentsMetadataData extends DataClass + implements Insertable { + final BigInt verHi; + final BigInt verLo; + final String fieldKey; + final String fieldValue; + const DocumentsMetadataData({ + required this.verHi, + required this.verLo, + required this.fieldKey, + required this.fieldValue, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['ver_hi'] = Variable(verHi); + map['ver_lo'] = Variable(verLo); + map['field_key'] = Variable(fieldKey); + map['field_value'] = Variable(fieldValue); + return map; + } + + factory DocumentsMetadataData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return DocumentsMetadataData( + verHi: serializer.fromJson(json['verHi']), + verLo: serializer.fromJson(json['verLo']), + fieldKey: serializer.fromJson(json['fieldKey']), + fieldValue: serializer.fromJson(json['fieldValue']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'verHi': serializer.toJson(verHi), + 'verLo': serializer.toJson(verLo), + 'fieldKey': serializer.toJson(fieldKey), + 'fieldValue': serializer.toJson(fieldValue), + }; + } + + DocumentsMetadataData copyWith({ + BigInt? verHi, + BigInt? verLo, + String? fieldKey, + String? fieldValue, + }) => DocumentsMetadataData( + verHi: verHi ?? this.verHi, + verLo: verLo ?? this.verLo, + fieldKey: fieldKey ?? this.fieldKey, + fieldValue: fieldValue ?? this.fieldValue, + ); + DocumentsMetadataData copyWithCompanion(DocumentsMetadataCompanion data) { + return DocumentsMetadataData( + verHi: data.verHi.present ? data.verHi.value : this.verHi, + verLo: data.verLo.present ? data.verLo.value : this.verLo, + fieldKey: data.fieldKey.present ? data.fieldKey.value : this.fieldKey, + fieldValue: data.fieldValue.present + ? data.fieldValue.value + : this.fieldValue, + ); + } + + @override + String toString() { + return (StringBuffer('DocumentsMetadataData(') + ..write('verHi: $verHi, ') + ..write('verLo: $verLo, ') + ..write('fieldKey: $fieldKey, ') + ..write('fieldValue: $fieldValue') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(verHi, verLo, fieldKey, fieldValue); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is DocumentsMetadataData && + other.verHi == this.verHi && + other.verLo == this.verLo && + other.fieldKey == this.fieldKey && + other.fieldValue == this.fieldValue); +} + +class DocumentsMetadataCompanion + extends UpdateCompanion { + final Value verHi; + final Value verLo; + final Value fieldKey; + final Value fieldValue; + final Value rowid; + const DocumentsMetadataCompanion({ + this.verHi = const Value.absent(), + this.verLo = const Value.absent(), + this.fieldKey = const Value.absent(), + this.fieldValue = const Value.absent(), + this.rowid = const Value.absent(), + }); + DocumentsMetadataCompanion.insert({ + required BigInt verHi, + required BigInt verLo, + required String fieldKey, + required String fieldValue, + this.rowid = const Value.absent(), + }) : verHi = Value(verHi), + verLo = Value(verLo), + fieldKey = Value(fieldKey), + fieldValue = Value(fieldValue); + static Insertable custom({ + Expression? verHi, + Expression? verLo, + Expression? fieldKey, + Expression? fieldValue, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (verHi != null) 'ver_hi': verHi, + if (verLo != null) 'ver_lo': verLo, + if (fieldKey != null) 'field_key': fieldKey, + if (fieldValue != null) 'field_value': fieldValue, + if (rowid != null) 'rowid': rowid, + }); + } + + DocumentsMetadataCompanion copyWith({ + Value? verHi, + Value? verLo, + Value? fieldKey, + Value? fieldValue, + Value? rowid, + }) { + return DocumentsMetadataCompanion( + verHi: verHi ?? this.verHi, + verLo: verLo ?? this.verLo, + fieldKey: fieldKey ?? this.fieldKey, + fieldValue: fieldValue ?? this.fieldValue, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (verHi.present) { + map['ver_hi'] = Variable(verHi.value); + } + if (verLo.present) { + map['ver_lo'] = Variable(verLo.value); + } + if (fieldKey.present) { + map['field_key'] = Variable(fieldKey.value); + } + if (fieldValue.present) { + map['field_value'] = Variable(fieldValue.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('DocumentsMetadataCompanion(') + ..write('verHi: $verHi, ') + ..write('verLo: $verLo, ') + ..write('fieldKey: $fieldKey, ') + ..write('fieldValue: $fieldValue, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class DocumentsFavorites extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + DocumentsFavorites(this.attachedDatabase, [this._alias]); + late final GeneratedColumn idHi = GeneratedColumn( + 'id_hi', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn idLo = GeneratedColumn( + 'id_lo', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn isFavorite = GeneratedColumn( + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [idHi, idLo, isFavorite, type]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'documents_favorites'; + @override + Set get $primaryKey => {idHi, idLo}; + @override + DocumentsFavoritesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return DocumentsFavoritesData( + idHi: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}id_hi'], + )!, + idLo: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}id_lo'], + )!, + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + ); + } + + @override + DocumentsFavorites createAlias(String alias) { + return DocumentsFavorites(attachedDatabase, alias); + } +} + +class DocumentsFavoritesData extends DataClass + implements Insertable { + final BigInt idHi; + final BigInt idLo; + final bool isFavorite; + final String type; + const DocumentsFavoritesData({ + required this.idHi, + required this.idLo, + required this.isFavorite, + required this.type, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id_hi'] = Variable(idHi); + map['id_lo'] = Variable(idLo); + map['is_favorite'] = Variable(isFavorite); + map['type'] = Variable(type); + return map; + } + + factory DocumentsFavoritesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return DocumentsFavoritesData( + idHi: serializer.fromJson(json['idHi']), + idLo: serializer.fromJson(json['idLo']), + isFavorite: serializer.fromJson(json['isFavorite']), + type: serializer.fromJson(json['type']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'idHi': serializer.toJson(idHi), + 'idLo': serializer.toJson(idLo), + 'isFavorite': serializer.toJson(isFavorite), + 'type': serializer.toJson(type), + }; + } + + DocumentsFavoritesData copyWith({ + BigInt? idHi, + BigInt? idLo, + bool? isFavorite, + String? type, + }) => DocumentsFavoritesData( + idHi: idHi ?? this.idHi, + idLo: idLo ?? this.idLo, + isFavorite: isFavorite ?? this.isFavorite, + type: type ?? this.type, + ); + DocumentsFavoritesData copyWithCompanion(DocumentsFavoritesCompanion data) { + return DocumentsFavoritesData( + idHi: data.idHi.present ? data.idHi.value : this.idHi, + idLo: data.idLo.present ? data.idLo.value : this.idLo, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + type: data.type.present ? data.type.value : this.type, + ); + } + + @override + String toString() { + return (StringBuffer('DocumentsFavoritesData(') + ..write('idHi: $idHi, ') + ..write('idLo: $idLo, ') + ..write('isFavorite: $isFavorite, ') + ..write('type: $type') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(idHi, idLo, isFavorite, type); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is DocumentsFavoritesData && + other.idHi == this.idHi && + other.idLo == this.idLo && + other.isFavorite == this.isFavorite && + other.type == this.type); +} + +class DocumentsFavoritesCompanion + extends UpdateCompanion { + final Value idHi; + final Value idLo; + final Value isFavorite; + final Value type; + final Value rowid; + const DocumentsFavoritesCompanion({ + this.idHi = const Value.absent(), + this.idLo = const Value.absent(), + this.isFavorite = const Value.absent(), + this.type = const Value.absent(), + this.rowid = const Value.absent(), + }); + DocumentsFavoritesCompanion.insert({ + required BigInt idHi, + required BigInt idLo, + required bool isFavorite, + required String type, + this.rowid = const Value.absent(), + }) : idHi = Value(idHi), + idLo = Value(idLo), + isFavorite = Value(isFavorite), + type = Value(type); + static Insertable custom({ + Expression? idHi, + Expression? idLo, + Expression? isFavorite, + Expression? type, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (idHi != null) 'id_hi': idHi, + if (idLo != null) 'id_lo': idLo, + if (isFavorite != null) 'is_favorite': isFavorite, + if (type != null) 'type': type, + if (rowid != null) 'rowid': rowid, + }); + } + + DocumentsFavoritesCompanion copyWith({ + Value? idHi, + Value? idLo, + Value? isFavorite, + Value? type, + Value? rowid, + }) { + return DocumentsFavoritesCompanion( + idHi: idHi ?? this.idHi, + idLo: idLo ?? this.idLo, + isFavorite: isFavorite ?? this.isFavorite, + type: type ?? this.type, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (idHi.present) { + map['id_hi'] = Variable(idHi.value); + } + if (idLo.present) { + map['id_lo'] = Variable(idLo.value); + } + if (isFavorite.present) { + map['is_favorite'] = Variable(isFavorite.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('DocumentsFavoritesCompanion(') + ..write('idHi: $idHi, ') + ..write('idLo: $idLo, ') + ..write('isFavorite: $isFavorite, ') + ..write('type: $type, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class Drafts extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Drafts(this.attachedDatabase, [this._alias]); + late final GeneratedColumn idHi = GeneratedColumn( + 'id_hi', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn idLo = GeneratedColumn( + 'id_lo', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn verHi = GeneratedColumn( + 'ver_hi', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn verLo = GeneratedColumn( + 'ver_lo', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn content = + GeneratedColumn( + 'content', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + late final GeneratedColumn metadata = + GeneratedColumn( + 'metadata', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn title = GeneratedColumn( + 'title', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + idHi, + idLo, + verHi, + verLo, + content, + metadata, + type, + title, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'drafts'; + @override + Set get $primaryKey => {idHi, idLo, verHi, verLo}; + @override + DraftsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return DraftsData( + idHi: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}id_hi'], + )!, + idLo: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}id_lo'], + )!, + verHi: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}ver_hi'], + )!, + verLo: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}ver_lo'], + )!, + content: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}content'], + )!, + metadata: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}metadata'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + title: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}title'], + )!, + ); + } + + @override + Drafts createAlias(String alias) { + return Drafts(attachedDatabase, alias); + } +} + +class DraftsData extends DataClass implements Insertable { + final BigInt idHi; + final BigInt idLo; + final BigInt verHi; + final BigInt verLo; + final i2.Uint8List content; + final i2.Uint8List metadata; + final String type; + final String title; + const DraftsData({ + required this.idHi, + required this.idLo, + required this.verHi, + required this.verLo, + required this.content, + required this.metadata, + required this.type, + required this.title, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id_hi'] = Variable(idHi); + map['id_lo'] = Variable(idLo); + map['ver_hi'] = Variable(verHi); + map['ver_lo'] = Variable(verLo); + map['content'] = Variable(content); + map['metadata'] = Variable(metadata); + map['type'] = Variable(type); + map['title'] = Variable(title); + return map; + } + + factory DraftsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return DraftsData( + idHi: serializer.fromJson(json['idHi']), + idLo: serializer.fromJson(json['idLo']), + verHi: serializer.fromJson(json['verHi']), + verLo: serializer.fromJson(json['verLo']), + content: serializer.fromJson(json['content']), + metadata: serializer.fromJson(json['metadata']), + type: serializer.fromJson(json['type']), + title: serializer.fromJson(json['title']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'idHi': serializer.toJson(idHi), + 'idLo': serializer.toJson(idLo), + 'verHi': serializer.toJson(verHi), + 'verLo': serializer.toJson(verLo), + 'content': serializer.toJson(content), + 'metadata': serializer.toJson(metadata), + 'type': serializer.toJson(type), + 'title': serializer.toJson(title), + }; + } + + DraftsData copyWith({ + BigInt? idHi, + BigInt? idLo, + BigInt? verHi, + BigInt? verLo, + i2.Uint8List? content, + i2.Uint8List? metadata, + String? type, + String? title, + }) => DraftsData( + idHi: idHi ?? this.idHi, + idLo: idLo ?? this.idLo, + verHi: verHi ?? this.verHi, + verLo: verLo ?? this.verLo, + content: content ?? this.content, + metadata: metadata ?? this.metadata, + type: type ?? this.type, + title: title ?? this.title, + ); + DraftsData copyWithCompanion(DraftsCompanion data) { + return DraftsData( + idHi: data.idHi.present ? data.idHi.value : this.idHi, + idLo: data.idLo.present ? data.idLo.value : this.idLo, + verHi: data.verHi.present ? data.verHi.value : this.verHi, + verLo: data.verLo.present ? data.verLo.value : this.verLo, + content: data.content.present ? data.content.value : this.content, + metadata: data.metadata.present ? data.metadata.value : this.metadata, + type: data.type.present ? data.type.value : this.type, + title: data.title.present ? data.title.value : this.title, + ); + } + + @override + String toString() { + return (StringBuffer('DraftsData(') + ..write('idHi: $idHi, ') + ..write('idLo: $idLo, ') + ..write('verHi: $verHi, ') + ..write('verLo: $verLo, ') + ..write('content: $content, ') + ..write('metadata: $metadata, ') + ..write('type: $type, ') + ..write('title: $title') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + idHi, + idLo, + verHi, + verLo, + $driftBlobEquality.hash(content), + $driftBlobEquality.hash(metadata), + type, + title, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is DraftsData && + other.idHi == this.idHi && + other.idLo == this.idLo && + other.verHi == this.verHi && + other.verLo == this.verLo && + $driftBlobEquality.equals(other.content, this.content) && + $driftBlobEquality.equals(other.metadata, this.metadata) && + other.type == this.type && + other.title == this.title); +} + +class DraftsCompanion extends UpdateCompanion { + final Value idHi; + final Value idLo; + final Value verHi; + final Value verLo; + final Value content; + final Value metadata; + final Value type; + final Value title; + final Value rowid; + const DraftsCompanion({ + this.idHi = const Value.absent(), + this.idLo = const Value.absent(), + this.verHi = const Value.absent(), + this.verLo = const Value.absent(), + this.content = const Value.absent(), + this.metadata = const Value.absent(), + this.type = const Value.absent(), + this.title = const Value.absent(), + this.rowid = const Value.absent(), + }); + DraftsCompanion.insert({ + required BigInt idHi, + required BigInt idLo, + required BigInt verHi, + required BigInt verLo, + required i2.Uint8List content, + required i2.Uint8List metadata, + required String type, + required String title, + this.rowid = const Value.absent(), + }) : idHi = Value(idHi), + idLo = Value(idLo), + verHi = Value(verHi), + verLo = Value(verLo), + content = Value(content), + metadata = Value(metadata), + type = Value(type), + title = Value(title); + static Insertable custom({ + Expression? idHi, + Expression? idLo, + Expression? verHi, + Expression? verLo, + Expression? content, + Expression? metadata, + Expression? type, + Expression? title, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (idHi != null) 'id_hi': idHi, + if (idLo != null) 'id_lo': idLo, + if (verHi != null) 'ver_hi': verHi, + if (verLo != null) 'ver_lo': verLo, + if (content != null) 'content': content, + if (metadata != null) 'metadata': metadata, + if (type != null) 'type': type, + if (title != null) 'title': title, + if (rowid != null) 'rowid': rowid, + }); + } + + DraftsCompanion copyWith({ + Value? idHi, + Value? idLo, + Value? verHi, + Value? verLo, + Value? content, + Value? metadata, + Value? type, + Value? title, + Value? rowid, + }) { + return DraftsCompanion( + idHi: idHi ?? this.idHi, + idLo: idLo ?? this.idLo, + verHi: verHi ?? this.verHi, + verLo: verLo ?? this.verLo, + content: content ?? this.content, + metadata: metadata ?? this.metadata, + type: type ?? this.type, + title: title ?? this.title, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (idHi.present) { + map['id_hi'] = Variable(idHi.value); + } + if (idLo.present) { + map['id_lo'] = Variable(idLo.value); + } + if (verHi.present) { + map['ver_hi'] = Variable(verHi.value); + } + if (verLo.present) { + map['ver_lo'] = Variable(verLo.value); + } + if (content.present) { + map['content'] = Variable(content.value); + } + if (metadata.present) { + map['metadata'] = Variable(metadata.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (title.present) { + map['title'] = Variable(title.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('DraftsCompanion(') + ..write('idHi: $idHi, ') + ..write('idLo: $idLo, ') + ..write('verHi: $verHi, ') + ..write('verLo: $verLo, ') + ..write('content: $content, ') + ..write('metadata: $metadata, ') + ..write('type: $type, ') + ..write('title: $title, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class DatabaseAtV3 extends GeneratedDatabase { + DatabaseAtV3(QueryExecutor e) : super(e); + late final Documents documents = Documents(this); + late final DocumentsMetadata documentsMetadata = DocumentsMetadata(this); + late final DocumentsFavorites documentsFavorites = DocumentsFavorites(this); + late final Drafts drafts = Drafts(this); + late final Index idxDocType = Index( + 'idx_doc_type', + 'CREATE INDEX idx_doc_type ON documents (type)', + ); + late final Index idxUniqueVer = Index( + 'idx_unique_ver', + 'CREATE UNIQUE INDEX idx_unique_ver ON documents (ver_hi, ver_lo)', + ); + late final Index idxDocMetadataKeyValue = Index( + 'idx_doc_metadata_key_value', + 'CREATE INDEX idx_doc_metadata_key_value ON documents_metadata (field_key, field_value)', + ); + late final Index idxFavType = Index( + 'idx_fav_type', + 'CREATE INDEX idx_fav_type ON documents_favorites (type)', + ); + late final Index idxFavUniqueId = Index( + 'idx_fav_unique_id', + 'CREATE UNIQUE INDEX idx_fav_unique_id ON documents_favorites (id_hi, id_lo)', + ); + late final Index idxDraftType = Index( + 'idx_draft_type', + 'CREATE INDEX idx_draft_type ON drafts (type)', + ); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + documents, + documentsMetadata, + documentsFavorites, + drafts, + idxDocType, + idxUniqueVer, + idxDocMetadataKeyValue, + idxFavType, + idxFavUniqueId, + idxDraftType, + ]; + @override + int get schemaVersion => 3; + @override + DriftDatabaseOptions get options => + const DriftDatabaseOptions(storeDateTimeAsText: true); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/migration/catalyst_database/generated/schema_v4.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/migration/catalyst_database/generated/schema_v4.dart new file mode 100644 index 000000000000..8191c4e9ca11 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/database/migration/catalyst_database/generated/schema_v4.dart @@ -0,0 +1,3265 @@ +// dart format width=80 +import 'dart:typed_data' as i2; +// GENERATED CODE, DO NOT EDIT BY HAND. +// ignore_for_file: type=lint +import 'package:drift/drift.dart'; + +class Documents extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Documents(this.attachedDatabase, [this._alias]); + late final GeneratedColumn idHi = GeneratedColumn( + 'id_hi', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn idLo = GeneratedColumn( + 'id_lo', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn verHi = GeneratedColumn( + 'ver_hi', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn verLo = GeneratedColumn( + 'ver_lo', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn content = + GeneratedColumn( + 'content', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + late final GeneratedColumn metadata = + GeneratedColumn( + 'metadata', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + idHi, + idLo, + verHi, + verLo, + content, + metadata, + type, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'documents'; + @override + Set get $primaryKey => {idHi, idLo, verHi, verLo}; + @override + DocumentsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return DocumentsData( + idHi: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}id_hi'], + )!, + idLo: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}id_lo'], + )!, + verHi: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}ver_hi'], + )!, + verLo: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}ver_lo'], + )!, + content: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}content'], + )!, + metadata: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}metadata'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + Documents createAlias(String alias) { + return Documents(attachedDatabase, alias); + } +} + +class DocumentsData extends DataClass implements Insertable { + final BigInt idHi; + final BigInt idLo; + final BigInt verHi; + final BigInt verLo; + final i2.Uint8List content; + final i2.Uint8List metadata; + final String type; + final DateTime createdAt; + const DocumentsData({ + required this.idHi, + required this.idLo, + required this.verHi, + required this.verLo, + required this.content, + required this.metadata, + required this.type, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id_hi'] = Variable(idHi); + map['id_lo'] = Variable(idLo); + map['ver_hi'] = Variable(verHi); + map['ver_lo'] = Variable(verLo); + map['content'] = Variable(content); + map['metadata'] = Variable(metadata); + map['type'] = Variable(type); + map['created_at'] = Variable(createdAt); + return map; + } + + factory DocumentsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return DocumentsData( + idHi: serializer.fromJson(json['idHi']), + idLo: serializer.fromJson(json['idLo']), + verHi: serializer.fromJson(json['verHi']), + verLo: serializer.fromJson(json['verLo']), + content: serializer.fromJson(json['content']), + metadata: serializer.fromJson(json['metadata']), + type: serializer.fromJson(json['type']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'idHi': serializer.toJson(idHi), + 'idLo': serializer.toJson(idLo), + 'verHi': serializer.toJson(verHi), + 'verLo': serializer.toJson(verLo), + 'content': serializer.toJson(content), + 'metadata': serializer.toJson(metadata), + 'type': serializer.toJson(type), + 'createdAt': serializer.toJson(createdAt), + }; + } + + DocumentsData copyWith({ + BigInt? idHi, + BigInt? idLo, + BigInt? verHi, + BigInt? verLo, + i2.Uint8List? content, + i2.Uint8List? metadata, + String? type, + DateTime? createdAt, + }) => DocumentsData( + idHi: idHi ?? this.idHi, + idLo: idLo ?? this.idLo, + verHi: verHi ?? this.verHi, + verLo: verLo ?? this.verLo, + content: content ?? this.content, + metadata: metadata ?? this.metadata, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + ); + DocumentsData copyWithCompanion(DocumentsCompanion data) { + return DocumentsData( + idHi: data.idHi.present ? data.idHi.value : this.idHi, + idLo: data.idLo.present ? data.idLo.value : this.idLo, + verHi: data.verHi.present ? data.verHi.value : this.verHi, + verLo: data.verLo.present ? data.verLo.value : this.verLo, + content: data.content.present ? data.content.value : this.content, + metadata: data.metadata.present ? data.metadata.value : this.metadata, + type: data.type.present ? data.type.value : this.type, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('DocumentsData(') + ..write('idHi: $idHi, ') + ..write('idLo: $idLo, ') + ..write('verHi: $verHi, ') + ..write('verLo: $verLo, ') + ..write('content: $content, ') + ..write('metadata: $metadata, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + idHi, + idLo, + verHi, + verLo, + $driftBlobEquality.hash(content), + $driftBlobEquality.hash(metadata), + type, + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is DocumentsData && + other.idHi == this.idHi && + other.idLo == this.idLo && + other.verHi == this.verHi && + other.verLo == this.verLo && + $driftBlobEquality.equals(other.content, this.content) && + $driftBlobEquality.equals(other.metadata, this.metadata) && + other.type == this.type && + other.createdAt == this.createdAt); +} + +class DocumentsCompanion extends UpdateCompanion { + final Value idHi; + final Value idLo; + final Value verHi; + final Value verLo; + final Value content; + final Value metadata; + final Value type; + final Value createdAt; + final Value rowid; + const DocumentsCompanion({ + this.idHi = const Value.absent(), + this.idLo = const Value.absent(), + this.verHi = const Value.absent(), + this.verLo = const Value.absent(), + this.content = const Value.absent(), + this.metadata = const Value.absent(), + this.type = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + DocumentsCompanion.insert({ + required BigInt idHi, + required BigInt idLo, + required BigInt verHi, + required BigInt verLo, + required i2.Uint8List content, + required i2.Uint8List metadata, + required String type, + required DateTime createdAt, + this.rowid = const Value.absent(), + }) : idHi = Value(idHi), + idLo = Value(idLo), + verHi = Value(verHi), + verLo = Value(verLo), + content = Value(content), + metadata = Value(metadata), + type = Value(type), + createdAt = Value(createdAt); + static Insertable custom({ + Expression? idHi, + Expression? idLo, + Expression? verHi, + Expression? verLo, + Expression? content, + Expression? metadata, + Expression? type, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (idHi != null) 'id_hi': idHi, + if (idLo != null) 'id_lo': idLo, + if (verHi != null) 'ver_hi': verHi, + if (verLo != null) 'ver_lo': verLo, + if (content != null) 'content': content, + if (metadata != null) 'metadata': metadata, + if (type != null) 'type': type, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + DocumentsCompanion copyWith({ + Value? idHi, + Value? idLo, + Value? verHi, + Value? verLo, + Value? content, + Value? metadata, + Value? type, + Value? createdAt, + Value? rowid, + }) { + return DocumentsCompanion( + idHi: idHi ?? this.idHi, + idLo: idLo ?? this.idLo, + verHi: verHi ?? this.verHi, + verLo: verLo ?? this.verLo, + content: content ?? this.content, + metadata: metadata ?? this.metadata, + type: type ?? this.type, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (idHi.present) { + map['id_hi'] = Variable(idHi.value); + } + if (idLo.present) { + map['id_lo'] = Variable(idLo.value); + } + if (verHi.present) { + map['ver_hi'] = Variable(verHi.value); + } + if (verLo.present) { + map['ver_lo'] = Variable(verLo.value); + } + if (content.present) { + map['content'] = Variable(content.value); + } + if (metadata.present) { + map['metadata'] = Variable(metadata.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('DocumentsCompanion(') + ..write('idHi: $idHi, ') + ..write('idLo: $idLo, ') + ..write('verHi: $verHi, ') + ..write('verLo: $verLo, ') + ..write('content: $content, ') + ..write('metadata: $metadata, ') + ..write('type: $type, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class DocumentsMetadata extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + DocumentsMetadata(this.attachedDatabase, [this._alias]); + late final GeneratedColumn verHi = GeneratedColumn( + 'ver_hi', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn verLo = GeneratedColumn( + 'ver_lo', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn fieldKey = GeneratedColumn( + 'field_key', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn fieldValue = GeneratedColumn( + 'field_value', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [verHi, verLo, fieldKey, fieldValue]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'documents_metadata'; + @override + Set get $primaryKey => {verHi, verLo, fieldKey}; + @override + DocumentsMetadataData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return DocumentsMetadataData( + verHi: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}ver_hi'], + )!, + verLo: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}ver_lo'], + )!, + fieldKey: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}field_key'], + )!, + fieldValue: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}field_value'], + )!, + ); + } + + @override + DocumentsMetadata createAlias(String alias) { + return DocumentsMetadata(attachedDatabase, alias); + } +} + +class DocumentsMetadataData extends DataClass + implements Insertable { + final BigInt verHi; + final BigInt verLo; + final String fieldKey; + final String fieldValue; + const DocumentsMetadataData({ + required this.verHi, + required this.verLo, + required this.fieldKey, + required this.fieldValue, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['ver_hi'] = Variable(verHi); + map['ver_lo'] = Variable(verLo); + map['field_key'] = Variable(fieldKey); + map['field_value'] = Variable(fieldValue); + return map; + } + + factory DocumentsMetadataData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return DocumentsMetadataData( + verHi: serializer.fromJson(json['verHi']), + verLo: serializer.fromJson(json['verLo']), + fieldKey: serializer.fromJson(json['fieldKey']), + fieldValue: serializer.fromJson(json['fieldValue']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'verHi': serializer.toJson(verHi), + 'verLo': serializer.toJson(verLo), + 'fieldKey': serializer.toJson(fieldKey), + 'fieldValue': serializer.toJson(fieldValue), + }; + } + + DocumentsMetadataData copyWith({ + BigInt? verHi, + BigInt? verLo, + String? fieldKey, + String? fieldValue, + }) => DocumentsMetadataData( + verHi: verHi ?? this.verHi, + verLo: verLo ?? this.verLo, + fieldKey: fieldKey ?? this.fieldKey, + fieldValue: fieldValue ?? this.fieldValue, + ); + DocumentsMetadataData copyWithCompanion(DocumentsMetadataCompanion data) { + return DocumentsMetadataData( + verHi: data.verHi.present ? data.verHi.value : this.verHi, + verLo: data.verLo.present ? data.verLo.value : this.verLo, + fieldKey: data.fieldKey.present ? data.fieldKey.value : this.fieldKey, + fieldValue: data.fieldValue.present + ? data.fieldValue.value + : this.fieldValue, + ); + } + + @override + String toString() { + return (StringBuffer('DocumentsMetadataData(') + ..write('verHi: $verHi, ') + ..write('verLo: $verLo, ') + ..write('fieldKey: $fieldKey, ') + ..write('fieldValue: $fieldValue') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(verHi, verLo, fieldKey, fieldValue); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is DocumentsMetadataData && + other.verHi == this.verHi && + other.verLo == this.verLo && + other.fieldKey == this.fieldKey && + other.fieldValue == this.fieldValue); +} + +class DocumentsMetadataCompanion + extends UpdateCompanion { + final Value verHi; + final Value verLo; + final Value fieldKey; + final Value fieldValue; + final Value rowid; + const DocumentsMetadataCompanion({ + this.verHi = const Value.absent(), + this.verLo = const Value.absent(), + this.fieldKey = const Value.absent(), + this.fieldValue = const Value.absent(), + this.rowid = const Value.absent(), + }); + DocumentsMetadataCompanion.insert({ + required BigInt verHi, + required BigInt verLo, + required String fieldKey, + required String fieldValue, + this.rowid = const Value.absent(), + }) : verHi = Value(verHi), + verLo = Value(verLo), + fieldKey = Value(fieldKey), + fieldValue = Value(fieldValue); + static Insertable custom({ + Expression? verHi, + Expression? verLo, + Expression? fieldKey, + Expression? fieldValue, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (verHi != null) 'ver_hi': verHi, + if (verLo != null) 'ver_lo': verLo, + if (fieldKey != null) 'field_key': fieldKey, + if (fieldValue != null) 'field_value': fieldValue, + if (rowid != null) 'rowid': rowid, + }); + } + + DocumentsMetadataCompanion copyWith({ + Value? verHi, + Value? verLo, + Value? fieldKey, + Value? fieldValue, + Value? rowid, + }) { + return DocumentsMetadataCompanion( + verHi: verHi ?? this.verHi, + verLo: verLo ?? this.verLo, + fieldKey: fieldKey ?? this.fieldKey, + fieldValue: fieldValue ?? this.fieldValue, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (verHi.present) { + map['ver_hi'] = Variable(verHi.value); + } + if (verLo.present) { + map['ver_lo'] = Variable(verLo.value); + } + if (fieldKey.present) { + map['field_key'] = Variable(fieldKey.value); + } + if (fieldValue.present) { + map['field_value'] = Variable(fieldValue.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('DocumentsMetadataCompanion(') + ..write('verHi: $verHi, ') + ..write('verLo: $verLo, ') + ..write('fieldKey: $fieldKey, ') + ..write('fieldValue: $fieldValue, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class DocumentsFavorites extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + DocumentsFavorites(this.attachedDatabase, [this._alias]); + late final GeneratedColumn idHi = GeneratedColumn( + 'id_hi', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn idLo = GeneratedColumn( + 'id_lo', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn isFavorite = GeneratedColumn( + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [idHi, idLo, isFavorite, type]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'documents_favorites'; + @override + Set get $primaryKey => {idHi, idLo}; + @override + DocumentsFavoritesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return DocumentsFavoritesData( + idHi: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}id_hi'], + )!, + idLo: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}id_lo'], + )!, + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + ); + } + + @override + DocumentsFavorites createAlias(String alias) { + return DocumentsFavorites(attachedDatabase, alias); + } +} + +class DocumentsFavoritesData extends DataClass + implements Insertable { + final BigInt idHi; + final BigInt idLo; + final bool isFavorite; + final String type; + const DocumentsFavoritesData({ + required this.idHi, + required this.idLo, + required this.isFavorite, + required this.type, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id_hi'] = Variable(idHi); + map['id_lo'] = Variable(idLo); + map['is_favorite'] = Variable(isFavorite); + map['type'] = Variable(type); + return map; + } + + factory DocumentsFavoritesData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return DocumentsFavoritesData( + idHi: serializer.fromJson(json['idHi']), + idLo: serializer.fromJson(json['idLo']), + isFavorite: serializer.fromJson(json['isFavorite']), + type: serializer.fromJson(json['type']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'idHi': serializer.toJson(idHi), + 'idLo': serializer.toJson(idLo), + 'isFavorite': serializer.toJson(isFavorite), + 'type': serializer.toJson(type), + }; + } + + DocumentsFavoritesData copyWith({ + BigInt? idHi, + BigInt? idLo, + bool? isFavorite, + String? type, + }) => DocumentsFavoritesData( + idHi: idHi ?? this.idHi, + idLo: idLo ?? this.idLo, + isFavorite: isFavorite ?? this.isFavorite, + type: type ?? this.type, + ); + DocumentsFavoritesData copyWithCompanion(DocumentsFavoritesCompanion data) { + return DocumentsFavoritesData( + idHi: data.idHi.present ? data.idHi.value : this.idHi, + idLo: data.idLo.present ? data.idLo.value : this.idLo, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + type: data.type.present ? data.type.value : this.type, + ); + } + + @override + String toString() { + return (StringBuffer('DocumentsFavoritesData(') + ..write('idHi: $idHi, ') + ..write('idLo: $idLo, ') + ..write('isFavorite: $isFavorite, ') + ..write('type: $type') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(idHi, idLo, isFavorite, type); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is DocumentsFavoritesData && + other.idHi == this.idHi && + other.idLo == this.idLo && + other.isFavorite == this.isFavorite && + other.type == this.type); +} + +class DocumentsFavoritesCompanion + extends UpdateCompanion { + final Value idHi; + final Value idLo; + final Value isFavorite; + final Value type; + final Value rowid; + const DocumentsFavoritesCompanion({ + this.idHi = const Value.absent(), + this.idLo = const Value.absent(), + this.isFavorite = const Value.absent(), + this.type = const Value.absent(), + this.rowid = const Value.absent(), + }); + DocumentsFavoritesCompanion.insert({ + required BigInt idHi, + required BigInt idLo, + required bool isFavorite, + required String type, + this.rowid = const Value.absent(), + }) : idHi = Value(idHi), + idLo = Value(idLo), + isFavorite = Value(isFavorite), + type = Value(type); + static Insertable custom({ + Expression? idHi, + Expression? idLo, + Expression? isFavorite, + Expression? type, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (idHi != null) 'id_hi': idHi, + if (idLo != null) 'id_lo': idLo, + if (isFavorite != null) 'is_favorite': isFavorite, + if (type != null) 'type': type, + if (rowid != null) 'rowid': rowid, + }); + } + + DocumentsFavoritesCompanion copyWith({ + Value? idHi, + Value? idLo, + Value? isFavorite, + Value? type, + Value? rowid, + }) { + return DocumentsFavoritesCompanion( + idHi: idHi ?? this.idHi, + idLo: idLo ?? this.idLo, + isFavorite: isFavorite ?? this.isFavorite, + type: type ?? this.type, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (idHi.present) { + map['id_hi'] = Variable(idHi.value); + } + if (idLo.present) { + map['id_lo'] = Variable(idLo.value); + } + if (isFavorite.present) { + map['is_favorite'] = Variable(isFavorite.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('DocumentsFavoritesCompanion(') + ..write('idHi: $idHi, ') + ..write('idLo: $idLo, ') + ..write('isFavorite: $isFavorite, ') + ..write('type: $type, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class Drafts extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Drafts(this.attachedDatabase, [this._alias]); + late final GeneratedColumn idHi = GeneratedColumn( + 'id_hi', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn idLo = GeneratedColumn( + 'id_lo', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn verHi = GeneratedColumn( + 'ver_hi', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn verLo = GeneratedColumn( + 'ver_lo', + aliasedName, + false, + type: DriftSqlType.bigInt, + requiredDuringInsert: true, + ); + late final GeneratedColumn content = + GeneratedColumn( + 'content', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + late final GeneratedColumn metadata = + GeneratedColumn( + 'metadata', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn title = GeneratedColumn( + 'title', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + idHi, + idLo, + verHi, + verLo, + content, + metadata, + type, + title, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'drafts'; + @override + Set get $primaryKey => {idHi, idLo, verHi, verLo}; + @override + DraftsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return DraftsData( + idHi: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}id_hi'], + )!, + idLo: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}id_lo'], + )!, + verHi: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}ver_hi'], + )!, + verLo: attachedDatabase.typeMapping.read( + DriftSqlType.bigInt, + data['${effectivePrefix}ver_lo'], + )!, + content: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}content'], + )!, + metadata: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}metadata'], + )!, + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + title: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}title'], + )!, + ); + } + + @override + Drafts createAlias(String alias) { + return Drafts(attachedDatabase, alias); + } +} + +class DraftsData extends DataClass implements Insertable { + final BigInt idHi; + final BigInt idLo; + final BigInt verHi; + final BigInt verLo; + final i2.Uint8List content; + final i2.Uint8List metadata; + final String type; + final String title; + const DraftsData({ + required this.idHi, + required this.idLo, + required this.verHi, + required this.verLo, + required this.content, + required this.metadata, + required this.type, + required this.title, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id_hi'] = Variable(idHi); + map['id_lo'] = Variable(idLo); + map['ver_hi'] = Variable(verHi); + map['ver_lo'] = Variable(verLo); + map['content'] = Variable(content); + map['metadata'] = Variable(metadata); + map['type'] = Variable(type); + map['title'] = Variable(title); + return map; + } + + factory DraftsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return DraftsData( + idHi: serializer.fromJson(json['idHi']), + idLo: serializer.fromJson(json['idLo']), + verHi: serializer.fromJson(json['verHi']), + verLo: serializer.fromJson(json['verLo']), + content: serializer.fromJson(json['content']), + metadata: serializer.fromJson(json['metadata']), + type: serializer.fromJson(json['type']), + title: serializer.fromJson(json['title']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'idHi': serializer.toJson(idHi), + 'idLo': serializer.toJson(idLo), + 'verHi': serializer.toJson(verHi), + 'verLo': serializer.toJson(verLo), + 'content': serializer.toJson(content), + 'metadata': serializer.toJson(metadata), + 'type': serializer.toJson(type), + 'title': serializer.toJson(title), + }; + } + + DraftsData copyWith({ + BigInt? idHi, + BigInt? idLo, + BigInt? verHi, + BigInt? verLo, + i2.Uint8List? content, + i2.Uint8List? metadata, + String? type, + String? title, + }) => DraftsData( + idHi: idHi ?? this.idHi, + idLo: idLo ?? this.idLo, + verHi: verHi ?? this.verHi, + verLo: verLo ?? this.verLo, + content: content ?? this.content, + metadata: metadata ?? this.metadata, + type: type ?? this.type, + title: title ?? this.title, + ); + DraftsData copyWithCompanion(DraftsCompanion data) { + return DraftsData( + idHi: data.idHi.present ? data.idHi.value : this.idHi, + idLo: data.idLo.present ? data.idLo.value : this.idLo, + verHi: data.verHi.present ? data.verHi.value : this.verHi, + verLo: data.verLo.present ? data.verLo.value : this.verLo, + content: data.content.present ? data.content.value : this.content, + metadata: data.metadata.present ? data.metadata.value : this.metadata, + type: data.type.present ? data.type.value : this.type, + title: data.title.present ? data.title.value : this.title, + ); + } + + @override + String toString() { + return (StringBuffer('DraftsData(') + ..write('idHi: $idHi, ') + ..write('idLo: $idLo, ') + ..write('verHi: $verHi, ') + ..write('verLo: $verLo, ') + ..write('content: $content, ') + ..write('metadata: $metadata, ') + ..write('type: $type, ') + ..write('title: $title') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + idHi, + idLo, + verHi, + verLo, + $driftBlobEquality.hash(content), + $driftBlobEquality.hash(metadata), + type, + title, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is DraftsData && + other.idHi == this.idHi && + other.idLo == this.idLo && + other.verHi == this.verHi && + other.verLo == this.verLo && + $driftBlobEquality.equals(other.content, this.content) && + $driftBlobEquality.equals(other.metadata, this.metadata) && + other.type == this.type && + other.title == this.title); +} + +class DraftsCompanion extends UpdateCompanion { + final Value idHi; + final Value idLo; + final Value verHi; + final Value verLo; + final Value content; + final Value metadata; + final Value type; + final Value title; + final Value rowid; + const DraftsCompanion({ + this.idHi = const Value.absent(), + this.idLo = const Value.absent(), + this.verHi = const Value.absent(), + this.verLo = const Value.absent(), + this.content = const Value.absent(), + this.metadata = const Value.absent(), + this.type = const Value.absent(), + this.title = const Value.absent(), + this.rowid = const Value.absent(), + }); + DraftsCompanion.insert({ + required BigInt idHi, + required BigInt idLo, + required BigInt verHi, + required BigInt verLo, + required i2.Uint8List content, + required i2.Uint8List metadata, + required String type, + required String title, + this.rowid = const Value.absent(), + }) : idHi = Value(idHi), + idLo = Value(idLo), + verHi = Value(verHi), + verLo = Value(verLo), + content = Value(content), + metadata = Value(metadata), + type = Value(type), + title = Value(title); + static Insertable custom({ + Expression? idHi, + Expression? idLo, + Expression? verHi, + Expression? verLo, + Expression? content, + Expression? metadata, + Expression? type, + Expression? title, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (idHi != null) 'id_hi': idHi, + if (idLo != null) 'id_lo': idLo, + if (verHi != null) 'ver_hi': verHi, + if (verLo != null) 'ver_lo': verLo, + if (content != null) 'content': content, + if (metadata != null) 'metadata': metadata, + if (type != null) 'type': type, + if (title != null) 'title': title, + if (rowid != null) 'rowid': rowid, + }); + } + + DraftsCompanion copyWith({ + Value? idHi, + Value? idLo, + Value? verHi, + Value? verLo, + Value? content, + Value? metadata, + Value? type, + Value? title, + Value? rowid, + }) { + return DraftsCompanion( + idHi: idHi ?? this.idHi, + idLo: idLo ?? this.idLo, + verHi: verHi ?? this.verHi, + verLo: verLo ?? this.verLo, + content: content ?? this.content, + metadata: metadata ?? this.metadata, + type: type ?? this.type, + title: title ?? this.title, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (idHi.present) { + map['id_hi'] = Variable(idHi.value); + } + if (idLo.present) { + map['id_lo'] = Variable(idLo.value); + } + if (verHi.present) { + map['ver_hi'] = Variable(verHi.value); + } + if (verLo.present) { + map['ver_lo'] = Variable(verLo.value); + } + if (content.present) { + map['content'] = Variable(content.value); + } + if (metadata.present) { + map['metadata'] = Variable(metadata.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (title.present) { + map['title'] = Variable(title.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('DraftsCompanion(') + ..write('idHi: $idHi, ') + ..write('idLo: $idLo, ') + ..write('verHi: $verHi, ') + ..write('verLo: $verLo, ') + ..write('content: $content, ') + ..write('metadata: $metadata, ') + ..write('type: $type, ') + ..write('title: $title, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class DocumentsV2 extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + DocumentsV2(this.attachedDatabase, [this._alias]); + late final GeneratedColumn content = + GeneratedColumn( + 'content', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + late final GeneratedColumn authors = GeneratedColumn( + 'authors', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn categoryId = GeneratedColumn( + 'category_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn categoryVer = GeneratedColumn( + 'category_ver', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn refId = GeneratedColumn( + 'ref_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn refVer = GeneratedColumn( + 'ref_ver', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn replyId = GeneratedColumn( + 'reply_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn replyVer = GeneratedColumn( + 'reply_ver', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn section = GeneratedColumn( + 'section', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn templateId = GeneratedColumn( + 'template_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn templateVer = GeneratedColumn( + 'template_ver', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn ver = GeneratedColumn( + 'ver', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + content, + authors, + categoryId, + categoryVer, + id, + refId, + refVer, + replyId, + replyVer, + section, + templateId, + templateVer, + type, + ver, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'documents_v2'; + @override + Set get $primaryKey => {id, ver}; + @override + DocumentsV2Data map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return DocumentsV2Data( + content: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}content'], + )!, + authors: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}authors'], + )!, + categoryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}category_id'], + ), + categoryVer: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}category_ver'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + refId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}ref_id'], + ), + refVer: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}ref_ver'], + ), + replyId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}reply_id'], + ), + replyVer: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}reply_ver'], + ), + section: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}section'], + ), + templateId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}template_id'], + ), + templateVer: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}template_ver'], + ), + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + ver: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}ver'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + DocumentsV2 createAlias(String alias) { + return DocumentsV2(attachedDatabase, alias); + } +} + +class DocumentsV2Data extends DataClass implements Insertable { + final i2.Uint8List content; + final String authors; + final String? categoryId; + final String? categoryVer; + final String id; + final String? refId; + final String? refVer; + final String? replyId; + final String? replyVer; + final String? section; + final String? templateId; + final String? templateVer; + final String type; + final String ver; + final DateTime createdAt; + const DocumentsV2Data({ + required this.content, + required this.authors, + this.categoryId, + this.categoryVer, + required this.id, + this.refId, + this.refVer, + this.replyId, + this.replyVer, + this.section, + this.templateId, + this.templateVer, + required this.type, + required this.ver, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['content'] = Variable(content); + map['authors'] = Variable(authors); + if (!nullToAbsent || categoryId != null) { + map['category_id'] = Variable(categoryId); + } + if (!nullToAbsent || categoryVer != null) { + map['category_ver'] = Variable(categoryVer); + } + map['id'] = Variable(id); + if (!nullToAbsent || refId != null) { + map['ref_id'] = Variable(refId); + } + if (!nullToAbsent || refVer != null) { + map['ref_ver'] = Variable(refVer); + } + if (!nullToAbsent || replyId != null) { + map['reply_id'] = Variable(replyId); + } + if (!nullToAbsent || replyVer != null) { + map['reply_ver'] = Variable(replyVer); + } + if (!nullToAbsent || section != null) { + map['section'] = Variable(section); + } + if (!nullToAbsent || templateId != null) { + map['template_id'] = Variable(templateId); + } + if (!nullToAbsent || templateVer != null) { + map['template_ver'] = Variable(templateVer); + } + map['type'] = Variable(type); + map['ver'] = Variable(ver); + map['created_at'] = Variable(createdAt); + return map; + } + + factory DocumentsV2Data.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return DocumentsV2Data( + content: serializer.fromJson(json['content']), + authors: serializer.fromJson(json['authors']), + categoryId: serializer.fromJson(json['categoryId']), + categoryVer: serializer.fromJson(json['categoryVer']), + id: serializer.fromJson(json['id']), + refId: serializer.fromJson(json['refId']), + refVer: serializer.fromJson(json['refVer']), + replyId: serializer.fromJson(json['replyId']), + replyVer: serializer.fromJson(json['replyVer']), + section: serializer.fromJson(json['section']), + templateId: serializer.fromJson(json['templateId']), + templateVer: serializer.fromJson(json['templateVer']), + type: serializer.fromJson(json['type']), + ver: serializer.fromJson(json['ver']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'content': serializer.toJson(content), + 'authors': serializer.toJson(authors), + 'categoryId': serializer.toJson(categoryId), + 'categoryVer': serializer.toJson(categoryVer), + 'id': serializer.toJson(id), + 'refId': serializer.toJson(refId), + 'refVer': serializer.toJson(refVer), + 'replyId': serializer.toJson(replyId), + 'replyVer': serializer.toJson(replyVer), + 'section': serializer.toJson(section), + 'templateId': serializer.toJson(templateId), + 'templateVer': serializer.toJson(templateVer), + 'type': serializer.toJson(type), + 'ver': serializer.toJson(ver), + 'createdAt': serializer.toJson(createdAt), + }; + } + + DocumentsV2Data copyWith({ + i2.Uint8List? content, + String? authors, + Value categoryId = const Value.absent(), + Value categoryVer = const Value.absent(), + String? id, + Value refId = const Value.absent(), + Value refVer = const Value.absent(), + Value replyId = const Value.absent(), + Value replyVer = const Value.absent(), + Value section = const Value.absent(), + Value templateId = const Value.absent(), + Value templateVer = const Value.absent(), + String? type, + String? ver, + DateTime? createdAt, + }) => DocumentsV2Data( + content: content ?? this.content, + authors: authors ?? this.authors, + categoryId: categoryId.present ? categoryId.value : this.categoryId, + categoryVer: categoryVer.present ? categoryVer.value : this.categoryVer, + id: id ?? this.id, + refId: refId.present ? refId.value : this.refId, + refVer: refVer.present ? refVer.value : this.refVer, + replyId: replyId.present ? replyId.value : this.replyId, + replyVer: replyVer.present ? replyVer.value : this.replyVer, + section: section.present ? section.value : this.section, + templateId: templateId.present ? templateId.value : this.templateId, + templateVer: templateVer.present ? templateVer.value : this.templateVer, + type: type ?? this.type, + ver: ver ?? this.ver, + createdAt: createdAt ?? this.createdAt, + ); + DocumentsV2Data copyWithCompanion(DocumentsV2Companion data) { + return DocumentsV2Data( + content: data.content.present ? data.content.value : this.content, + authors: data.authors.present ? data.authors.value : this.authors, + categoryId: data.categoryId.present + ? data.categoryId.value + : this.categoryId, + categoryVer: data.categoryVer.present + ? data.categoryVer.value + : this.categoryVer, + id: data.id.present ? data.id.value : this.id, + refId: data.refId.present ? data.refId.value : this.refId, + refVer: data.refVer.present ? data.refVer.value : this.refVer, + replyId: data.replyId.present ? data.replyId.value : this.replyId, + replyVer: data.replyVer.present ? data.replyVer.value : this.replyVer, + section: data.section.present ? data.section.value : this.section, + templateId: data.templateId.present + ? data.templateId.value + : this.templateId, + templateVer: data.templateVer.present + ? data.templateVer.value + : this.templateVer, + type: data.type.present ? data.type.value : this.type, + ver: data.ver.present ? data.ver.value : this.ver, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('DocumentsV2Data(') + ..write('content: $content, ') + ..write('authors: $authors, ') + ..write('categoryId: $categoryId, ') + ..write('categoryVer: $categoryVer, ') + ..write('id: $id, ') + ..write('refId: $refId, ') + ..write('refVer: $refVer, ') + ..write('replyId: $replyId, ') + ..write('replyVer: $replyVer, ') + ..write('section: $section, ') + ..write('templateId: $templateId, ') + ..write('templateVer: $templateVer, ') + ..write('type: $type, ') + ..write('ver: $ver, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + $driftBlobEquality.hash(content), + authors, + categoryId, + categoryVer, + id, + refId, + refVer, + replyId, + replyVer, + section, + templateId, + templateVer, + type, + ver, + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is DocumentsV2Data && + $driftBlobEquality.equals(other.content, this.content) && + other.authors == this.authors && + other.categoryId == this.categoryId && + other.categoryVer == this.categoryVer && + other.id == this.id && + other.refId == this.refId && + other.refVer == this.refVer && + other.replyId == this.replyId && + other.replyVer == this.replyVer && + other.section == this.section && + other.templateId == this.templateId && + other.templateVer == this.templateVer && + other.type == this.type && + other.ver == this.ver && + other.createdAt == this.createdAt); +} + +class DocumentsV2Companion extends UpdateCompanion { + final Value content; + final Value authors; + final Value categoryId; + final Value categoryVer; + final Value id; + final Value refId; + final Value refVer; + final Value replyId; + final Value replyVer; + final Value section; + final Value templateId; + final Value templateVer; + final Value type; + final Value ver; + final Value createdAt; + final Value rowid; + const DocumentsV2Companion({ + this.content = const Value.absent(), + this.authors = const Value.absent(), + this.categoryId = const Value.absent(), + this.categoryVer = const Value.absent(), + this.id = const Value.absent(), + this.refId = const Value.absent(), + this.refVer = const Value.absent(), + this.replyId = const Value.absent(), + this.replyVer = const Value.absent(), + this.section = const Value.absent(), + this.templateId = const Value.absent(), + this.templateVer = const Value.absent(), + this.type = const Value.absent(), + this.ver = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + DocumentsV2Companion.insert({ + required i2.Uint8List content, + required String authors, + this.categoryId = const Value.absent(), + this.categoryVer = const Value.absent(), + required String id, + this.refId = const Value.absent(), + this.refVer = const Value.absent(), + this.replyId = const Value.absent(), + this.replyVer = const Value.absent(), + this.section = const Value.absent(), + this.templateId = const Value.absent(), + this.templateVer = const Value.absent(), + required String type, + required String ver, + required DateTime createdAt, + this.rowid = const Value.absent(), + }) : content = Value(content), + authors = Value(authors), + id = Value(id), + type = Value(type), + ver = Value(ver), + createdAt = Value(createdAt); + static Insertable custom({ + Expression? content, + Expression? authors, + Expression? categoryId, + Expression? categoryVer, + Expression? id, + Expression? refId, + Expression? refVer, + Expression? replyId, + Expression? replyVer, + Expression? section, + Expression? templateId, + Expression? templateVer, + Expression? type, + Expression? ver, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (content != null) 'content': content, + if (authors != null) 'authors': authors, + if (categoryId != null) 'category_id': categoryId, + if (categoryVer != null) 'category_ver': categoryVer, + if (id != null) 'id': id, + if (refId != null) 'ref_id': refId, + if (refVer != null) 'ref_ver': refVer, + if (replyId != null) 'reply_id': replyId, + if (replyVer != null) 'reply_ver': replyVer, + if (section != null) 'section': section, + if (templateId != null) 'template_id': templateId, + if (templateVer != null) 'template_ver': templateVer, + if (type != null) 'type': type, + if (ver != null) 'ver': ver, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + DocumentsV2Companion copyWith({ + Value? content, + Value? authors, + Value? categoryId, + Value? categoryVer, + Value? id, + Value? refId, + Value? refVer, + Value? replyId, + Value? replyVer, + Value? section, + Value? templateId, + Value? templateVer, + Value? type, + Value? ver, + Value? createdAt, + Value? rowid, + }) { + return DocumentsV2Companion( + content: content ?? this.content, + authors: authors ?? this.authors, + categoryId: categoryId ?? this.categoryId, + categoryVer: categoryVer ?? this.categoryVer, + id: id ?? this.id, + refId: refId ?? this.refId, + refVer: refVer ?? this.refVer, + replyId: replyId ?? this.replyId, + replyVer: replyVer ?? this.replyVer, + section: section ?? this.section, + templateId: templateId ?? this.templateId, + templateVer: templateVer ?? this.templateVer, + type: type ?? this.type, + ver: ver ?? this.ver, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (content.present) { + map['content'] = Variable(content.value); + } + if (authors.present) { + map['authors'] = Variable(authors.value); + } + if (categoryId.present) { + map['category_id'] = Variable(categoryId.value); + } + if (categoryVer.present) { + map['category_ver'] = Variable(categoryVer.value); + } + if (id.present) { + map['id'] = Variable(id.value); + } + if (refId.present) { + map['ref_id'] = Variable(refId.value); + } + if (refVer.present) { + map['ref_ver'] = Variable(refVer.value); + } + if (replyId.present) { + map['reply_id'] = Variable(replyId.value); + } + if (replyVer.present) { + map['reply_ver'] = Variable(replyVer.value); + } + if (section.present) { + map['section'] = Variable(section.value); + } + if (templateId.present) { + map['template_id'] = Variable(templateId.value); + } + if (templateVer.present) { + map['template_ver'] = Variable(templateVer.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (ver.present) { + map['ver'] = Variable(ver.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('DocumentsV2Companion(') + ..write('content: $content, ') + ..write('authors: $authors, ') + ..write('categoryId: $categoryId, ') + ..write('categoryVer: $categoryVer, ') + ..write('id: $id, ') + ..write('refId: $refId, ') + ..write('refVer: $refVer, ') + ..write('replyId: $replyId, ') + ..write('replyVer: $replyVer, ') + ..write('section: $section, ') + ..write('templateId: $templateId, ') + ..write('templateVer: $templateVer, ') + ..write('type: $type, ') + ..write('ver: $ver, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class DocumentAuthors extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + DocumentAuthors(this.attachedDatabase, [this._alias]); + late final GeneratedColumn authorId = GeneratedColumn( + 'author_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn authorIdSignificant = + GeneratedColumn( + 'author_id_significant', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn authorUsername = GeneratedColumn( + 'author_username', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn documentId = GeneratedColumn( + 'document_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn documentVer = GeneratedColumn( + 'document_ver', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + authorId, + authorIdSignificant, + authorUsername, + documentId, + documentVer, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'document_authors'; + @override + Set get $primaryKey => {documentId, documentVer, authorId}; + @override + DocumentAuthorsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return DocumentAuthorsData( + authorId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}author_id'], + )!, + authorIdSignificant: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}author_id_significant'], + )!, + authorUsername: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}author_username'], + ), + documentId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}document_id'], + )!, + documentVer: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}document_ver'], + )!, + ); + } + + @override + DocumentAuthors createAlias(String alias) { + return DocumentAuthors(attachedDatabase, alias); + } + + @override + List get customConstraints => const [ + 'FOREIGN KEY (document_id, document_ver) REFERENCES documents_v2(id, ver) ON DELETE CASCADE', + ]; +} + +class DocumentAuthorsData extends DataClass + implements Insertable { + final String authorId; + final String authorIdSignificant; + final String? authorUsername; + final String documentId; + final String documentVer; + const DocumentAuthorsData({ + required this.authorId, + required this.authorIdSignificant, + this.authorUsername, + required this.documentId, + required this.documentVer, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['author_id'] = Variable(authorId); + map['author_id_significant'] = Variable(authorIdSignificant); + if (!nullToAbsent || authorUsername != null) { + map['author_username'] = Variable(authorUsername); + } + map['document_id'] = Variable(documentId); + map['document_ver'] = Variable(documentVer); + return map; + } + + factory DocumentAuthorsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return DocumentAuthorsData( + authorId: serializer.fromJson(json['authorId']), + authorIdSignificant: serializer.fromJson( + json['authorIdSignificant'], + ), + authorUsername: serializer.fromJson(json['authorUsername']), + documentId: serializer.fromJson(json['documentId']), + documentVer: serializer.fromJson(json['documentVer']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'authorId': serializer.toJson(authorId), + 'authorIdSignificant': serializer.toJson(authorIdSignificant), + 'authorUsername': serializer.toJson(authorUsername), + 'documentId': serializer.toJson(documentId), + 'documentVer': serializer.toJson(documentVer), + }; + } + + DocumentAuthorsData copyWith({ + String? authorId, + String? authorIdSignificant, + Value authorUsername = const Value.absent(), + String? documentId, + String? documentVer, + }) => DocumentAuthorsData( + authorId: authorId ?? this.authorId, + authorIdSignificant: authorIdSignificant ?? this.authorIdSignificant, + authorUsername: authorUsername.present + ? authorUsername.value + : this.authorUsername, + documentId: documentId ?? this.documentId, + documentVer: documentVer ?? this.documentVer, + ); + DocumentAuthorsData copyWithCompanion(DocumentAuthorsCompanion data) { + return DocumentAuthorsData( + authorId: data.authorId.present ? data.authorId.value : this.authorId, + authorIdSignificant: data.authorIdSignificant.present + ? data.authorIdSignificant.value + : this.authorIdSignificant, + authorUsername: data.authorUsername.present + ? data.authorUsername.value + : this.authorUsername, + documentId: data.documentId.present + ? data.documentId.value + : this.documentId, + documentVer: data.documentVer.present + ? data.documentVer.value + : this.documentVer, + ); + } + + @override + String toString() { + return (StringBuffer('DocumentAuthorsData(') + ..write('authorId: $authorId, ') + ..write('authorIdSignificant: $authorIdSignificant, ') + ..write('authorUsername: $authorUsername, ') + ..write('documentId: $documentId, ') + ..write('documentVer: $documentVer') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + authorId, + authorIdSignificant, + authorUsername, + documentId, + documentVer, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is DocumentAuthorsData && + other.authorId == this.authorId && + other.authorIdSignificant == this.authorIdSignificant && + other.authorUsername == this.authorUsername && + other.documentId == this.documentId && + other.documentVer == this.documentVer); +} + +class DocumentAuthorsCompanion extends UpdateCompanion { + final Value authorId; + final Value authorIdSignificant; + final Value authorUsername; + final Value documentId; + final Value documentVer; + final Value rowid; + const DocumentAuthorsCompanion({ + this.authorId = const Value.absent(), + this.authorIdSignificant = const Value.absent(), + this.authorUsername = const Value.absent(), + this.documentId = const Value.absent(), + this.documentVer = const Value.absent(), + this.rowid = const Value.absent(), + }); + DocumentAuthorsCompanion.insert({ + required String authorId, + required String authorIdSignificant, + this.authorUsername = const Value.absent(), + required String documentId, + required String documentVer, + this.rowid = const Value.absent(), + }) : authorId = Value(authorId), + authorIdSignificant = Value(authorIdSignificant), + documentId = Value(documentId), + documentVer = Value(documentVer); + static Insertable custom({ + Expression? authorId, + Expression? authorIdSignificant, + Expression? authorUsername, + Expression? documentId, + Expression? documentVer, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (authorId != null) 'author_id': authorId, + if (authorIdSignificant != null) + 'author_id_significant': authorIdSignificant, + if (authorUsername != null) 'author_username': authorUsername, + if (documentId != null) 'document_id': documentId, + if (documentVer != null) 'document_ver': documentVer, + if (rowid != null) 'rowid': rowid, + }); + } + + DocumentAuthorsCompanion copyWith({ + Value? authorId, + Value? authorIdSignificant, + Value? authorUsername, + Value? documentId, + Value? documentVer, + Value? rowid, + }) { + return DocumentAuthorsCompanion( + authorId: authorId ?? this.authorId, + authorIdSignificant: authorIdSignificant ?? this.authorIdSignificant, + authorUsername: authorUsername ?? this.authorUsername, + documentId: documentId ?? this.documentId, + documentVer: documentVer ?? this.documentVer, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (authorId.present) { + map['author_id'] = Variable(authorId.value); + } + if (authorIdSignificant.present) { + map['author_id_significant'] = Variable( + authorIdSignificant.value, + ); + } + if (authorUsername.present) { + map['author_username'] = Variable(authorUsername.value); + } + if (documentId.present) { + map['document_id'] = Variable(documentId.value); + } + if (documentVer.present) { + map['document_ver'] = Variable(documentVer.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('DocumentAuthorsCompanion(') + ..write('authorId: $authorId, ') + ..write('authorIdSignificant: $authorIdSignificant, ') + ..write('authorUsername: $authorUsername, ') + ..write('documentId: $documentId, ') + ..write('documentVer: $documentVer, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class DocumentsLocalMetadata extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + DocumentsLocalMetadata(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn isFavorite = GeneratedColumn( + 'is_favorite', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("is_favorite" IN (0, 1))', + ), + ); + @override + List get $columns => [id, isFavorite]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'documents_local_metadata'; + @override + Set get $primaryKey => {id}; + @override + DocumentsLocalMetadataData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return DocumentsLocalMetadataData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + isFavorite: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}is_favorite'], + )!, + ); + } + + @override + DocumentsLocalMetadata createAlias(String alias) { + return DocumentsLocalMetadata(attachedDatabase, alias); + } +} + +class DocumentsLocalMetadataData extends DataClass + implements Insertable { + final String id; + final bool isFavorite; + const DocumentsLocalMetadataData({ + required this.id, + required this.isFavorite, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['is_favorite'] = Variable(isFavorite); + return map; + } + + factory DocumentsLocalMetadataData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return DocumentsLocalMetadataData( + id: serializer.fromJson(json['id']), + isFavorite: serializer.fromJson(json['isFavorite']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'isFavorite': serializer.toJson(isFavorite), + }; + } + + DocumentsLocalMetadataData copyWith({String? id, bool? isFavorite}) => + DocumentsLocalMetadataData( + id: id ?? this.id, + isFavorite: isFavorite ?? this.isFavorite, + ); + DocumentsLocalMetadataData copyWithCompanion( + DocumentsLocalMetadataCompanion data, + ) { + return DocumentsLocalMetadataData( + id: data.id.present ? data.id.value : this.id, + isFavorite: data.isFavorite.present + ? data.isFavorite.value + : this.isFavorite, + ); + } + + @override + String toString() { + return (StringBuffer('DocumentsLocalMetadataData(') + ..write('id: $id, ') + ..write('isFavorite: $isFavorite') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, isFavorite); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is DocumentsLocalMetadataData && + other.id == this.id && + other.isFavorite == this.isFavorite); +} + +class DocumentsLocalMetadataCompanion + extends UpdateCompanion { + final Value id; + final Value isFavorite; + final Value rowid; + const DocumentsLocalMetadataCompanion({ + this.id = const Value.absent(), + this.isFavorite = const Value.absent(), + this.rowid = const Value.absent(), + }); + DocumentsLocalMetadataCompanion.insert({ + required String id, + required bool isFavorite, + this.rowid = const Value.absent(), + }) : id = Value(id), + isFavorite = Value(isFavorite); + static Insertable custom({ + Expression? id, + Expression? isFavorite, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (isFavorite != null) 'is_favorite': isFavorite, + if (rowid != null) 'rowid': rowid, + }); + } + + DocumentsLocalMetadataCompanion copyWith({ + Value? id, + Value? isFavorite, + Value? rowid, + }) { + return DocumentsLocalMetadataCompanion( + id: id ?? this.id, + isFavorite: isFavorite ?? this.isFavorite, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (isFavorite.present) { + map['is_favorite'] = Variable(isFavorite.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('DocumentsLocalMetadataCompanion(') + ..write('id: $id, ') + ..write('isFavorite: $isFavorite, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class LocalDocumentsDrafts extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + LocalDocumentsDrafts(this.attachedDatabase, [this._alias]); + late final GeneratedColumn content = + GeneratedColumn( + 'content', + aliasedName, + false, + type: DriftSqlType.blob, + requiredDuringInsert: true, + ); + late final GeneratedColumn authors = GeneratedColumn( + 'authors', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn categoryId = GeneratedColumn( + 'category_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn categoryVer = GeneratedColumn( + 'category_ver', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn refId = GeneratedColumn( + 'ref_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn refVer = GeneratedColumn( + 'ref_ver', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn replyId = GeneratedColumn( + 'reply_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn replyVer = GeneratedColumn( + 'reply_ver', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn section = GeneratedColumn( + 'section', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn templateId = GeneratedColumn( + 'template_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn templateVer = GeneratedColumn( + 'template_ver', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + late final GeneratedColumn type = GeneratedColumn( + 'type', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn ver = GeneratedColumn( + 'ver', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + content, + authors, + categoryId, + categoryVer, + id, + refId, + refVer, + replyId, + replyVer, + section, + templateId, + templateVer, + type, + ver, + createdAt, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'local_documents_drafts'; + @override + Set get $primaryKey => {id, ver}; + @override + LocalDocumentsDraftsData map( + Map data, { + String? tablePrefix, + }) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return LocalDocumentsDraftsData( + content: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}content'], + )!, + authors: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}authors'], + )!, + categoryId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}category_id'], + ), + categoryVer: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}category_ver'], + ), + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + refId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}ref_id'], + ), + refVer: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}ref_ver'], + ), + replyId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}reply_id'], + ), + replyVer: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}reply_ver'], + ), + section: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}section'], + ), + templateId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}template_id'], + ), + templateVer: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}template_ver'], + ), + type: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}type'], + )!, + ver: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}ver'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, + ); + } + + @override + LocalDocumentsDrafts createAlias(String alias) { + return LocalDocumentsDrafts(attachedDatabase, alias); + } +} + +class LocalDocumentsDraftsData extends DataClass + implements Insertable { + final i2.Uint8List content; + final String authors; + final String? categoryId; + final String? categoryVer; + final String id; + final String? refId; + final String? refVer; + final String? replyId; + final String? replyVer; + final String? section; + final String? templateId; + final String? templateVer; + final String type; + final String ver; + final DateTime createdAt; + const LocalDocumentsDraftsData({ + required this.content, + required this.authors, + this.categoryId, + this.categoryVer, + required this.id, + this.refId, + this.refVer, + this.replyId, + this.replyVer, + this.section, + this.templateId, + this.templateVer, + required this.type, + required this.ver, + required this.createdAt, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['content'] = Variable(content); + map['authors'] = Variable(authors); + if (!nullToAbsent || categoryId != null) { + map['category_id'] = Variable(categoryId); + } + if (!nullToAbsent || categoryVer != null) { + map['category_ver'] = Variable(categoryVer); + } + map['id'] = Variable(id); + if (!nullToAbsent || refId != null) { + map['ref_id'] = Variable(refId); + } + if (!nullToAbsent || refVer != null) { + map['ref_ver'] = Variable(refVer); + } + if (!nullToAbsent || replyId != null) { + map['reply_id'] = Variable(replyId); + } + if (!nullToAbsent || replyVer != null) { + map['reply_ver'] = Variable(replyVer); + } + if (!nullToAbsent || section != null) { + map['section'] = Variable(section); + } + if (!nullToAbsent || templateId != null) { + map['template_id'] = Variable(templateId); + } + if (!nullToAbsent || templateVer != null) { + map['template_ver'] = Variable(templateVer); + } + map['type'] = Variable(type); + map['ver'] = Variable(ver); + map['created_at'] = Variable(createdAt); + return map; + } + + factory LocalDocumentsDraftsData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return LocalDocumentsDraftsData( + content: serializer.fromJson(json['content']), + authors: serializer.fromJson(json['authors']), + categoryId: serializer.fromJson(json['categoryId']), + categoryVer: serializer.fromJson(json['categoryVer']), + id: serializer.fromJson(json['id']), + refId: serializer.fromJson(json['refId']), + refVer: serializer.fromJson(json['refVer']), + replyId: serializer.fromJson(json['replyId']), + replyVer: serializer.fromJson(json['replyVer']), + section: serializer.fromJson(json['section']), + templateId: serializer.fromJson(json['templateId']), + templateVer: serializer.fromJson(json['templateVer']), + type: serializer.fromJson(json['type']), + ver: serializer.fromJson(json['ver']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'content': serializer.toJson(content), + 'authors': serializer.toJson(authors), + 'categoryId': serializer.toJson(categoryId), + 'categoryVer': serializer.toJson(categoryVer), + 'id': serializer.toJson(id), + 'refId': serializer.toJson(refId), + 'refVer': serializer.toJson(refVer), + 'replyId': serializer.toJson(replyId), + 'replyVer': serializer.toJson(replyVer), + 'section': serializer.toJson(section), + 'templateId': serializer.toJson(templateId), + 'templateVer': serializer.toJson(templateVer), + 'type': serializer.toJson(type), + 'ver': serializer.toJson(ver), + 'createdAt': serializer.toJson(createdAt), + }; + } + + LocalDocumentsDraftsData copyWith({ + i2.Uint8List? content, + String? authors, + Value categoryId = const Value.absent(), + Value categoryVer = const Value.absent(), + String? id, + Value refId = const Value.absent(), + Value refVer = const Value.absent(), + Value replyId = const Value.absent(), + Value replyVer = const Value.absent(), + Value section = const Value.absent(), + Value templateId = const Value.absent(), + Value templateVer = const Value.absent(), + String? type, + String? ver, + DateTime? createdAt, + }) => LocalDocumentsDraftsData( + content: content ?? this.content, + authors: authors ?? this.authors, + categoryId: categoryId.present ? categoryId.value : this.categoryId, + categoryVer: categoryVer.present ? categoryVer.value : this.categoryVer, + id: id ?? this.id, + refId: refId.present ? refId.value : this.refId, + refVer: refVer.present ? refVer.value : this.refVer, + replyId: replyId.present ? replyId.value : this.replyId, + replyVer: replyVer.present ? replyVer.value : this.replyVer, + section: section.present ? section.value : this.section, + templateId: templateId.present ? templateId.value : this.templateId, + templateVer: templateVer.present ? templateVer.value : this.templateVer, + type: type ?? this.type, + ver: ver ?? this.ver, + createdAt: createdAt ?? this.createdAt, + ); + LocalDocumentsDraftsData copyWithCompanion( + LocalDocumentsDraftsCompanion data, + ) { + return LocalDocumentsDraftsData( + content: data.content.present ? data.content.value : this.content, + authors: data.authors.present ? data.authors.value : this.authors, + categoryId: data.categoryId.present + ? data.categoryId.value + : this.categoryId, + categoryVer: data.categoryVer.present + ? data.categoryVer.value + : this.categoryVer, + id: data.id.present ? data.id.value : this.id, + refId: data.refId.present ? data.refId.value : this.refId, + refVer: data.refVer.present ? data.refVer.value : this.refVer, + replyId: data.replyId.present ? data.replyId.value : this.replyId, + replyVer: data.replyVer.present ? data.replyVer.value : this.replyVer, + section: data.section.present ? data.section.value : this.section, + templateId: data.templateId.present + ? data.templateId.value + : this.templateId, + templateVer: data.templateVer.present + ? data.templateVer.value + : this.templateVer, + type: data.type.present ? data.type.value : this.type, + ver: data.ver.present ? data.ver.value : this.ver, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('LocalDocumentsDraftsData(') + ..write('content: $content, ') + ..write('authors: $authors, ') + ..write('categoryId: $categoryId, ') + ..write('categoryVer: $categoryVer, ') + ..write('id: $id, ') + ..write('refId: $refId, ') + ..write('refVer: $refVer, ') + ..write('replyId: $replyId, ') + ..write('replyVer: $replyVer, ') + ..write('section: $section, ') + ..write('templateId: $templateId, ') + ..write('templateVer: $templateVer, ') + ..write('type: $type, ') + ..write('ver: $ver, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + $driftBlobEquality.hash(content), + authors, + categoryId, + categoryVer, + id, + refId, + refVer, + replyId, + replyVer, + section, + templateId, + templateVer, + type, + ver, + createdAt, + ); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is LocalDocumentsDraftsData && + $driftBlobEquality.equals(other.content, this.content) && + other.authors == this.authors && + other.categoryId == this.categoryId && + other.categoryVer == this.categoryVer && + other.id == this.id && + other.refId == this.refId && + other.refVer == this.refVer && + other.replyId == this.replyId && + other.replyVer == this.replyVer && + other.section == this.section && + other.templateId == this.templateId && + other.templateVer == this.templateVer && + other.type == this.type && + other.ver == this.ver && + other.createdAt == this.createdAt); +} + +class LocalDocumentsDraftsCompanion + extends UpdateCompanion { + final Value content; + final Value authors; + final Value categoryId; + final Value categoryVer; + final Value id; + final Value refId; + final Value refVer; + final Value replyId; + final Value replyVer; + final Value section; + final Value templateId; + final Value templateVer; + final Value type; + final Value ver; + final Value createdAt; + final Value rowid; + const LocalDocumentsDraftsCompanion({ + this.content = const Value.absent(), + this.authors = const Value.absent(), + this.categoryId = const Value.absent(), + this.categoryVer = const Value.absent(), + this.id = const Value.absent(), + this.refId = const Value.absent(), + this.refVer = const Value.absent(), + this.replyId = const Value.absent(), + this.replyVer = const Value.absent(), + this.section = const Value.absent(), + this.templateId = const Value.absent(), + this.templateVer = const Value.absent(), + this.type = const Value.absent(), + this.ver = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + LocalDocumentsDraftsCompanion.insert({ + required i2.Uint8List content, + required String authors, + this.categoryId = const Value.absent(), + this.categoryVer = const Value.absent(), + required String id, + this.refId = const Value.absent(), + this.refVer = const Value.absent(), + this.replyId = const Value.absent(), + this.replyVer = const Value.absent(), + this.section = const Value.absent(), + this.templateId = const Value.absent(), + this.templateVer = const Value.absent(), + required String type, + required String ver, + required DateTime createdAt, + this.rowid = const Value.absent(), + }) : content = Value(content), + authors = Value(authors), + id = Value(id), + type = Value(type), + ver = Value(ver), + createdAt = Value(createdAt); + static Insertable custom({ + Expression? content, + Expression? authors, + Expression? categoryId, + Expression? categoryVer, + Expression? id, + Expression? refId, + Expression? refVer, + Expression? replyId, + Expression? replyVer, + Expression? section, + Expression? templateId, + Expression? templateVer, + Expression? type, + Expression? ver, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (content != null) 'content': content, + if (authors != null) 'authors': authors, + if (categoryId != null) 'category_id': categoryId, + if (categoryVer != null) 'category_ver': categoryVer, + if (id != null) 'id': id, + if (refId != null) 'ref_id': refId, + if (refVer != null) 'ref_ver': refVer, + if (replyId != null) 'reply_id': replyId, + if (replyVer != null) 'reply_ver': replyVer, + if (section != null) 'section': section, + if (templateId != null) 'template_id': templateId, + if (templateVer != null) 'template_ver': templateVer, + if (type != null) 'type': type, + if (ver != null) 'ver': ver, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + LocalDocumentsDraftsCompanion copyWith({ + Value? content, + Value? authors, + Value? categoryId, + Value? categoryVer, + Value? id, + Value? refId, + Value? refVer, + Value? replyId, + Value? replyVer, + Value? section, + Value? templateId, + Value? templateVer, + Value? type, + Value? ver, + Value? createdAt, + Value? rowid, + }) { + return LocalDocumentsDraftsCompanion( + content: content ?? this.content, + authors: authors ?? this.authors, + categoryId: categoryId ?? this.categoryId, + categoryVer: categoryVer ?? this.categoryVer, + id: id ?? this.id, + refId: refId ?? this.refId, + refVer: refVer ?? this.refVer, + replyId: replyId ?? this.replyId, + replyVer: replyVer ?? this.replyVer, + section: section ?? this.section, + templateId: templateId ?? this.templateId, + templateVer: templateVer ?? this.templateVer, + type: type ?? this.type, + ver: ver ?? this.ver, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (content.present) { + map['content'] = Variable(content.value); + } + if (authors.present) { + map['authors'] = Variable(authors.value); + } + if (categoryId.present) { + map['category_id'] = Variable(categoryId.value); + } + if (categoryVer.present) { + map['category_ver'] = Variable(categoryVer.value); + } + if (id.present) { + map['id'] = Variable(id.value); + } + if (refId.present) { + map['ref_id'] = Variable(refId.value); + } + if (refVer.present) { + map['ref_ver'] = Variable(refVer.value); + } + if (replyId.present) { + map['reply_id'] = Variable(replyId.value); + } + if (replyVer.present) { + map['reply_ver'] = Variable(replyVer.value); + } + if (section.present) { + map['section'] = Variable(section.value); + } + if (templateId.present) { + map['template_id'] = Variable(templateId.value); + } + if (templateVer.present) { + map['template_ver'] = Variable(templateVer.value); + } + if (type.present) { + map['type'] = Variable(type.value); + } + if (ver.present) { + map['ver'] = Variable(ver.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('LocalDocumentsDraftsCompanion(') + ..write('content: $content, ') + ..write('authors: $authors, ') + ..write('categoryId: $categoryId, ') + ..write('categoryVer: $categoryVer, ') + ..write('id: $id, ') + ..write('refId: $refId, ') + ..write('refVer: $refVer, ') + ..write('replyId: $replyId, ') + ..write('replyVer: $replyVer, ') + ..write('section: $section, ') + ..write('templateId: $templateId, ') + ..write('templateVer: $templateVer, ') + ..write('type: $type, ') + ..write('ver: $ver, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class DatabaseAtV4 extends GeneratedDatabase { + DatabaseAtV4(QueryExecutor e) : super(e); + late final Documents documents = Documents(this); + late final DocumentsMetadata documentsMetadata = DocumentsMetadata(this); + late final DocumentsFavorites documentsFavorites = DocumentsFavorites(this); + late final Drafts drafts = Drafts(this); + late final DocumentsV2 documentsV2 = DocumentsV2(this); + late final DocumentAuthors documentAuthors = DocumentAuthors(this); + late final DocumentsLocalMetadata documentsLocalMetadata = + DocumentsLocalMetadata(this); + late final LocalDocumentsDrafts localDocumentsDrafts = LocalDocumentsDrafts( + this, + ); + late final Index idxDocType = Index( + 'idx_doc_type', + 'CREATE INDEX idx_doc_type ON documents (type)', + ); + late final Index idxUniqueVer = Index( + 'idx_unique_ver', + 'CREATE UNIQUE INDEX idx_unique_ver ON documents (ver_hi, ver_lo)', + ); + late final Index idxDocMetadataKeyValue = Index( + 'idx_doc_metadata_key_value', + 'CREATE INDEX idx_doc_metadata_key_value ON documents_metadata (field_key, field_value)', + ); + late final Index idxFavType = Index( + 'idx_fav_type', + 'CREATE INDEX idx_fav_type ON documents_favorites (type)', + ); + late final Index idxFavUniqueId = Index( + 'idx_fav_unique_id', + 'CREATE UNIQUE INDEX idx_fav_unique_id ON documents_favorites (id_hi, id_lo)', + ); + late final Index idxDraftType = Index( + 'idx_draft_type', + 'CREATE INDEX idx_draft_type ON drafts (type)', + ); + late final Index idxDocumentsV2TypeId = Index( + 'idx_documents_v2_type_id', + 'CREATE INDEX idx_documents_v2_type_id ON documents_v2 (type, id)', + ); + late final Index idxDocumentsV2TypeIdVer = Index( + 'idx_documents_v2_type_id_ver', + 'CREATE INDEX idx_documents_v2_type_id_ver ON documents_v2 (type, id, ver)', + ); + late final Index idxDocumentsV2TypeRefId = Index( + 'idx_documents_v2_type_ref_id', + 'CREATE INDEX idx_documents_v2_type_ref_id ON documents_v2 (type, ref_id)', + ); + late final Index idxDocumentsV2TypeRefIdVer = Index( + 'idx_documents_v2_type_ref_id_ver', + 'CREATE INDEX idx_documents_v2_type_ref_id_ver ON documents_v2 (type, ref_id, ver)', + ); + late final Index idxDocumentsV2RefIdVer = Index( + 'idx_documents_v2_ref_id_ver', + 'CREATE INDEX idx_documents_v2_ref_id_ver ON documents_v2 (ref_id, ver)', + ); + late final Index idxDocumentsV2TypeIdCreatedAt = Index( + 'idx_documents_v2_type_id_created_at', + 'CREATE INDEX idx_documents_v2_type_id_created_at ON documents_v2 (type, id, created_at)', + ); + late final Index idxDocumentsV2TypeCategoryId = Index( + 'idx_documents_v2_type_category_id', + 'CREATE INDEX idx_documents_v2_type_category_id ON documents_v2 (type, category_id)', + ); + late final Index idxDocumentsV2TypeRefIdRefVer = Index( + 'idx_documents_v2_type_ref_id_ref_ver', + 'CREATE INDEX idx_documents_v2_type_ref_id_ref_ver ON documents_v2 (type, ref_id, ref_ver)', + ); + late final Index idxDocumentAuthorsComposite = Index( + 'idx_document_authors_composite', + 'CREATE INDEX idx_document_authors_composite ON document_authors (document_id, document_ver, author_id_significant)', + ); + late final Index idxDocumentAuthorsIdentity = Index( + 'idx_document_authors_identity', + 'CREATE INDEX idx_document_authors_identity ON document_authors (author_id_significant)', + ); + late final Index idxDocumentAuthorsUsername = Index( + 'idx_document_authors_username', + 'CREATE INDEX idx_document_authors_username ON document_authors (author_username)', + ); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + documents, + documentsMetadata, + documentsFavorites, + drafts, + documentsV2, + documentAuthors, + documentsLocalMetadata, + localDocumentsDrafts, + idxDocType, + idxUniqueVer, + idxDocMetadataKeyValue, + idxFavType, + idxFavUniqueId, + idxDraftType, + idxDocumentsV2TypeId, + idxDocumentsV2TypeIdVer, + idxDocumentsV2TypeRefId, + idxDocumentsV2TypeRefIdVer, + idxDocumentsV2RefIdVer, + idxDocumentsV2TypeIdCreatedAt, + idxDocumentsV2TypeCategoryId, + idxDocumentsV2TypeRefIdRefVer, + idxDocumentAuthorsComposite, + idxDocumentAuthorsIdentity, + idxDocumentAuthorsUsername, + ]; + @override + int get schemaVersion => 4; + @override + DriftDatabaseOptions get options => + const DriftDatabaseOptions(storeDateTimeAsText: true); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document/document_repository_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document/document_repository_test.dart index 26dc53f39b6b..fe3c56553829 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document/document_repository_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document/document_repository_test.dart @@ -7,6 +7,7 @@ import 'package:collection/collection.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; +import '../../fixture/signed_document/signed_document_test_data.dart'; import '../../fixture/voices_document_templates.dart'; import '../database/connection/test_connection.dart'; import '../database/drift_test_platforms.dart'; @@ -57,13 +58,14 @@ void main() { final templateRef = SignedDocumentRef.first(DocumentRefFactory.randomUuidV7()); final template = DocumentDataFactory.build( - selfRef: templateRef, - type: DocumentType.proposalTemplate, + metadata: DocumentDataMetadataFactory.proposalTemplate(selfRef: templateRef), content: DocumentDataContent(templateData), ); final proposal = DocumentDataFactory.build( - selfRef: SignedDocumentRef.first(DocumentRefFactory.randomUuidV7()), - template: templateRef, + metadata: DocumentDataMetadataFactory.proposal( + selfRef: SignedDocumentRef.first(DocumentRefFactory.randomUuidV7()), + template: templateRef, + ), content: DocumentDataContent(proposalData), ); @@ -95,8 +97,9 @@ void main() { // Given final templateRef = DocumentRefFactory.signedDocumentRef(); final proposal = DocumentDataFactory.build( - selfRef: SignedDocumentRef.first(DocumentRefFactory.randomUuidV7()), - template: templateRef, + metadata: DocumentDataMetadataFactory.proposal( + template: templateRef, + ), ); when(() => remoteDocuments.get(ref: templateRef)).thenAnswer( @@ -130,7 +133,9 @@ void main() { final version = id; final documentData = DocumentDataFactory.build( - selfRef: SignedDocumentRef(id: id, version: version), + metadata: DocumentDataMetadataFactory.proposal( + selfRef: SignedDocumentRef(id: id, version: version), + ), ); final ref = documentData.ref; @@ -155,7 +160,9 @@ void main() { final version = id; final documentData = DocumentDataFactory.build( - selfRef: SignedDocumentRef(id: id, version: version), + metadata: DocumentDataMetadataFactory.proposal( + selfRef: SignedDocumentRef(id: id, version: version), + ), ); final ref = SignedDocumentRef(id: id); @@ -185,10 +192,11 @@ void main() { // Given final templateRef = DocumentRefFactory.signedDocumentRef(); final template = DocumentDataFactory.build( - type: DocumentType.proposalTemplate, - selfRef: templateRef, + metadata: DocumentDataMetadataFactory.proposalTemplate(selfRef: templateRef), + ); + final proposal = DocumentDataFactory.build( + metadata: DocumentDataMetadataFactory.proposal(template: templateRef), ); - final proposal = DocumentDataFactory.build(template: templateRef); when( () => remoteDocuments.get(ref: template.ref), @@ -228,11 +236,16 @@ void main() { // Given final templateRef = DocumentRefFactory.signedDocumentRef(); final template = DocumentDataFactory.build( - type: DocumentType.proposalTemplate, - selfRef: templateRef, + metadata: DocumentDataMetadataFactory.proposalTemplate( + selfRef: templateRef, + ), + ); + final proposal1 = DocumentDataFactory.build( + metadata: DocumentDataMetadataFactory.proposal(template: templateRef), + ); + final proposal2 = DocumentDataFactory.build( + metadata: DocumentDataMetadataFactory.proposal(template: templateRef), ); - final proposal1 = DocumentDataFactory.build(template: templateRef); - final proposal2 = DocumentDataFactory.build(template: templateRef); when( () => remoteDocuments.get(ref: template.ref), @@ -276,7 +289,9 @@ void main() { () async { // Given final documentDataToSave = DocumentDataFactory.build( - selfRef: DocumentRefFactory.draftRef(), + metadata: DocumentDataMetadataFactory.proposal( + selfRef: DocumentRefFactory.draftRef(), + ), ); // When @@ -393,9 +408,10 @@ void main() { final constTemplatesRefs = activeConstantDocumentRefs .expand( (element) => [ - element.proposal.toTyped(DocumentType.proposalTemplate), + element.proposal?.toTyped(DocumentType.proposalTemplate), ], ) + .nonNulls .toList(); final docsRefs = List.generate( @@ -510,19 +526,22 @@ void main() { final templateRef = DocumentRefFactory.signedDocumentRef(); final templateData = DocumentDataFactory.build( - selfRef: templateRef, - type: DocumentType.proposalTemplate, + metadata: DocumentDataMetadataFactory.proposalTemplate(selfRef: templateRef), ); final draftRef = DocumentRefFactory.draftRef(); final draftData = DocumentDataFactory.build( - selfRef: draftRef, - template: templateRef, + metadata: DocumentDataMetadataFactory.proposal( + selfRef: draftRef, + template: templateRef, + ), ); final updatedData = DocumentDataFactory.build( - selfRef: draftRef, - template: templateRef, + metadata: DocumentDataMetadataFactory.proposal( + selfRef: draftRef, + template: templateRef, + ), content: updatedContent, ); @@ -558,16 +577,16 @@ void main() { () async { final templateRef = DocumentRefFactory.signedDocumentRef(); final templateData = DocumentDataFactory.build( - selfRef: templateRef, - type: DocumentType.proposalTemplate, + metadata: DocumentDataMetadataFactory.proposalTemplate(selfRef: templateRef), ); const publicDraftContent = DocumentDataContent({'title': 'My proposal'}); final publicDraftRef = DocumentRefFactory.signedDocumentRef(); final publicDraftData = DocumentDataFactory.build( - selfRef: publicDraftRef, - template: templateRef, - categoryId: DocumentRefFactory.signedDocumentRef(), + metadata: DocumentDataMetadataFactory.proposal( + selfRef: publicDraftRef, + template: templateRef, + ), content: publicDraftContent, ); @@ -593,6 +612,24 @@ void main() { }, onPlatform: driftOnPlatforms, ); + + test('parseDocumentForImport exported with v0.0.1 signed document spec', () async { + final bytes = await SignedDocumentTestData.exportedProposalV0_0_1Bytes; + final document = await repository.parseDocumentForImport(data: bytes); + + expect(document.metadata.type, equals(DocumentType.proposalDocument)); + expect(document.metadata.template, isNotNull); + expect(document.metadata.parameters, isNotEmpty); + }); + + test('parseDocumentForImport exported with v0.0.4 signed document spec', () async { + final bytes = await SignedDocumentTestData.exportedProposalV0_0_4Bytes; + final document = await repository.parseDocumentForImport(data: bytes); + + expect(document.metadata.type, equals(DocumentType.proposalDocument)); + expect(document.metadata.template, isNotNull); + expect(document.metadata.parameters, isNotEmpty); + }); }); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document/source/document_data_remote_source_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document/source/document_data_remote_source_test.dart index 9b7e64bbd28f..c68abc2c56fe 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document/source/document_data_remote_source_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document/source/document_data_remote_source_test.dart @@ -1,18 +1,20 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_repositories/catalyst_voices_repositories.dart'; -import 'package:catalyst_voices_repositories/generated/api/cat_gateway.models.swagger.dart'; -import 'package:catalyst_voices_repositories/src/dto/api/document_index_list_dto.dart'; -import 'package:chopper/chopper.dart'; +import 'package:catalyst_voices_repositories/src/api/models/current_page.dart'; +import 'package:catalyst_voices_repositories/src/api/models/document_index_list.dart'; +import 'package:catalyst_voices_repositories/src/api/models/document_index_query_filter.dart'; +import 'package:catalyst_voices_repositories/src/api/models/document_reference.dart'; +import 'package:catalyst_voices_repositories/src/api/models/indexed_document.dart'; +import 'package:catalyst_voices_repositories/src/api/models/indexed_document_version.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:http/http.dart' as http; import 'package:mocktail/mocktail.dart'; import '../../utils/test_factories.dart'; void main() { - final CatGateway gateway = _MockedCatGateway(); - final CatReviews reviews = _MockedCatReviews(); - final CatStatus status = _MockedCatStatus(); + final CatGatewayService gateway = _MockedCatGateway(); + final CatReviewsService reviews = _MockedCatReviews(); + final CatStatusService status = _MockedCatStatus(); final SignedDocumentManager signedDocumentManager = _MockedSignedDocumentManager(); late final ApiServices apiServices; @@ -21,6 +23,8 @@ void main() { const maxPageSize = CatGatewayDocumentDataSource.indexPageSize; setUpAll(() { + registerFallbackValue(const DocumentIndexQueryFilter()); + apiServices = ApiServices.internal( gateway: gateway, reviews: reviews, @@ -40,50 +44,45 @@ void main() { group(CatGatewayDocumentDataSource, () { group('index', () { test('loops thru all pages until there is no remaining refs ' - 'and exacts refs from them', () async { - // Given + 'and extracts refs from them', () async { final pageZero = DocumentIndexList( docs: List.generate( maxPageSize, - (_) => _buildDocumentIndexList().toJson(), + (_) => _buildDocumentIndexList(), ), page: const CurrentPage(page: 0, limit: maxPageSize, remaining: 5), ); final pageOne = DocumentIndexList( docs: List.generate( 5, - (_) => _buildDocumentIndexList().toJson(), + (_) => _buildDocumentIndexList(), ), page: const CurrentPage(page: 1, limit: maxPageSize, remaining: 0), ); - final pageZeroResponse = Response(http.Response('', 200), pageZero); - final pageOneResponse = Response(http.Response('', 200), pageOne); - - // When when( - () => gateway.apiV1DocumentIndexPost( - body: any(named: 'body'), + () => gateway.documentIndex( + filter: any(named: 'filter'), limit: maxPageSize, page: 0, ), - ).thenAnswer((_) => Future.value(pageZeroResponse)); + ).thenAnswer((_) async => pageZero); + when( - () => gateway.apiV1DocumentIndexPost( - body: any(named: 'body'), + () => gateway.documentIndex( + filter: any(named: 'filter'), limit: maxPageSize, page: 1, ), - ).thenAnswer((_) => Future.value(pageOneResponse)); + ).thenAnswer((_) async => pageOne); final refs = await source.index(campaign: Campaign.f14()); - // Then expect(refs, isNotEmpty); verify( - () => gateway.apiV1DocumentIndexPost( - body: any(named: 'body'), + () => gateway.documentIndex( + filter: any(named: 'filter'), limit: any(named: 'limit'), page: any(named: 'page'), ), @@ -91,7 +90,6 @@ void main() { }); test('expands all page refs correctly', () async { - // Given final proposalId = DocumentRefFactory.randomUuidV7(); final proposalRefs = [ SignedDocumentRef(id: proposalId, version: DocumentRefFactory.randomUuidV7()), @@ -101,41 +99,40 @@ void main() { final page = DocumentIndexList( docs: [ - DocumentIndexListDto( + IndexedDocument( id: proposalId, ver: proposalRefs.map((e) { - return IndividualDocumentVersion( + return IndexedDocumentVersion( ver: e.version!, type: DocumentType.proposalDocument.uuid, - template: DocumentRefForFilteredDocuments( - id: templateRef.id, - ver: templateRef.version, - ), + template: [ + DocumentReference( + id: templateRef.id, + ver: templateRef.version!, + ), + ], ); }).toList(), - ).toJson(), + ), ], page: const CurrentPage(page: 0, limit: maxPageSize, remaining: 0), ); - final response = Response(http.Response('', 200), page); final expectedRefs = [ ...proposalRefs.map((e) => e.toTyped(DocumentType.proposalDocument)), templateRef.toTyped(DocumentType.proposalTemplate), ]; - // When when( - () => gateway.apiV1DocumentIndexPost( - body: any(named: 'body'), + () => gateway.documentIndex( + filter: any(named: 'filter'), limit: maxPageSize, page: 0, ), - ).thenAnswer((_) => Future.value(response)); + ).thenAnswer((_) async => page); final refs = await source.index(campaign: Campaign.f14()); - // Then expect( refs, allOf(hasLength(expectedRefs.length), containsAll(expectedRefs)), @@ -145,17 +142,17 @@ void main() { }); } -DocumentIndexListDto _buildDocumentIndexList({ +IndexedDocument _buildDocumentIndexList({ int verCount = 2, - DocumentRefForFilteredDocuments? template, - DocumentRefForFilteredDocuments? ref, + List? template, + List? ref, }) { - return DocumentIndexListDto( + return IndexedDocument( id: DocumentRefFactory.randomUuidV7(), ver: List.generate( verCount, (index) { - return IndividualDocumentVersion( + return IndexedDocumentVersion( ver: DocumentRefFactory.randomUuidV7(), type: DocumentRefFactory.randomUuidV7(), template: template, @@ -166,10 +163,10 @@ DocumentIndexListDto _buildDocumentIndexList({ ); } -class _MockedCatGateway extends Mock implements CatGateway {} +class _MockedCatGateway extends Mock implements CatGatewayService {} -class _MockedCatReviews extends Mock implements CatReviews {} +class _MockedCatReviews extends Mock implements CatReviewsService {} -class _MockedCatStatus extends Mock implements CatStatus {} +class _MockedCatStatus extends Mock implements CatStatusService {} class _MockedSignedDocumentManager extends Mock implements SignedDocumentManager {} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/dto/document/document_data_dto_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/dto/document/document_data_dto_test.dart index 6741bf2e187a..560f09e735e2 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/dto/document/document_data_dto_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/dto/document/document_data_dto_test.dart @@ -24,6 +24,77 @@ void main() { expect(dto.selfRef.id, id); expect(dto.selfRef.version, version); }); + + test('parameters migration works as expected', () { + // Given + final selfRef = DocumentRefFactory.signedDocumentRef(); + final brandRef = DocumentRefFactory.signedDocumentRef(); + final campaignRef = DocumentRefFactory.signedDocumentRef(); + final categoryRef = DocumentRefFactory.signedDocumentRef(); + + final oldJson = { + 'type': DocumentType.proposalDocument.uuid, + 'selfRef': { + 'id': selfRef.id, + 'version': selfRef.version, + 'type': 'signed', + }, + 'brandId': { + 'id': brandRef.id, + 'version': brandRef.version, + 'type': 'signed', + }, + 'campaignId': { + 'id': campaignRef.id, + 'version': campaignRef.version, + 'type': 'signed', + }, + 'categoryId': { + 'id': categoryRef.id, + 'version': categoryRef.version, + 'type': 'signed', + }, + }; + + // When + final dto = DocumentDataMetadataDto.fromJson(oldJson); + final model = dto.toModel(); + + // Then + expect( + model.parameters, + equals(DocumentParameters({brandRef, campaignRef, categoryRef})), + ); + }); + + test('content type migration works as expected', () { + // Given + final selfRef = DocumentRefFactory.signedDocumentRef(); + final categoryRef = DocumentRefFactory.signedDocumentRef(); + + final oldJson = { + 'type': DocumentType.proposalDocument.uuid, + 'selfRef': { + 'id': selfRef.id, + 'version': selfRef.version, + 'type': 'signed', + }, + 'parameters': [ + { + 'id': categoryRef.id, + 'version': categoryRef.version, + 'type': 'signed', + }, + ], + }; + + // When + final dto = DocumentDataMetadataDto.fromJson(oldJson); + final model = dto.toModel(); + + // Then + expect(model.contentType, equals(DocumentContentType.json)); + }); }); }); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/dto/user/catalyst_id_public_ext_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/dto/user/catalyst_id_public_ext_test.dart index 38dcf850bb7f..28e6af984b0d 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/dto/user/catalyst_id_public_ext_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/dto/user/catalyst_id_public_ext_test.dart @@ -1,5 +1,5 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; -import 'package:catalyst_voices_repositories/generated/api/cat_reviews.models.swagger.dart'; +import 'package:catalyst_voices_repositories/src/api/models/catalyst_id_public.dart'; import 'package:catalyst_voices_repositories/src/dto/user/catalyst_id_public_ext.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -22,7 +22,7 @@ void main() { ); // When - final publicCatId = CatalystIDPublic.fromJson(json); + final publicCatId = CatalystIdPublic.fromJson(json); final publicProfile = publicCatId.toModel(); // Then @@ -35,7 +35,7 @@ void main() { // Given const sourceUsername = 'First%20Last'; const expectedUsername = 'First Last'; - const id = CatalystIDPublic(username: sourceUsername); + const id = CatalystIdPublic(username: sourceUsername); // When final model = id.toModel(); @@ -48,7 +48,7 @@ void main() { // Given const sourceUsername = 'First Ląst'; const expectedUsername = 'First Ląst'; - const id = CatalystIDPublic(username: sourceUsername); + const id = CatalystIdPublic(username: sourceUsername); // When final model = id.toModel(); @@ -61,7 +61,7 @@ void main() { // Given const sourceUsername = 'First%20Ląst'; const expectedUsername = 'First Ląst'; - const id = CatalystIDPublic(username: sourceUsername); + const id = CatalystIdPublic(username: sourceUsername); // When final model = id.toModel(); diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/dto/user/rbac_registration_chain_dto_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/dto/user/rbac_registration_chain_dto_test.dart index 00ca1d414d6f..2c730aba2515 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/dto/user/rbac_registration_chain_dto_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/dto/user/rbac_registration_chain_dto_test.dart @@ -3,7 +3,7 @@ import 'dart:convert'; import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart'; import 'package:catalyst_key_derivation/catalyst_key_derivation.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; -import 'package:catalyst_voices_repositories/generated/api/cat_gateway.models.swagger.dart'; +import 'package:catalyst_voices_repositories/src/api/models/rbac_registration_chain.dart'; import 'package:catalyst_voices_repositories/src/dto/user/rbac_registration_chain_dto.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -39,6 +39,26 @@ void main() { ); }); + test('can decode lastVolatileTxn', () { + final registrationChain = getRegistrationChain(_voterAndProposerJson); + + expect( + registrationChain.lastVolatileTxn, + equals( + '0x95f781a3db75af41d1dde5a997b9f9ab3e20035882d4a2ccafdc81cfda6f52a2', + ), + ); + }); + + test('can decode purpose', () { + final registrationChain = getRegistrationChain(_voterAndProposerJson); + + expect( + registrationChain.purpose, + equals(['ca7a1457-ef9f-4c7f-9c74-7f8c4a4cfa6c']), + ); + }); + test('can decode voter & proposer roles', () { final registrationChain = getRegistrationChain(_voterAndProposerJson); @@ -91,142 +111,186 @@ const _noRoleJson = ''' "purpose": [ "ca7a1457-ef9f-4c7f-9c74-7f8c4a4cfa6c" ], - "roles": {} + "roles": [] } '''; -const _voterAndProposerJson = ''' +const _voterAndProposerJson = r''' { - "catalyst_id": "preprod.cardano/QhSfGm8dpD_PBmpHPhJRW1tiFv7fxSuHvuCRRWmB2cY", - "last_persistent_txn": "0x95f781a3db75af41d1dde5a997b9f9ab3e20035882d4a2ccafdc81cfda6f52a2", - "purpose": [ - "ca7a1457-ef9f-4c7f-9c74-7f8c4a4cfa6c" - ], - "roles": { - "0": { - "extended_data": { - "10": [ - 111, - 82, - 101, - 103, - 105, - 115, - 116, - 101, - 114, - 32, - 114, - 111, - 108, - 101, - 32, - 48 - ] - }, - "payment_addresses": [ - { - "address": "addr_test1qr3f7dmpr59t8vtp8an9ptrxvetvd4t7mzxwdp9tdjva8580qvqw2t5gfue6xylvsxljc4j2a7kedsxldcym2uu9q6yqs0ju92", - "is_persistent": true, - "time": "2025-04-10T02:22:19+00:00" - } - ], - "signing_keys": [ - { - "is_persistent": true, - "key_type": "x509", - "key_value": "0x308201fc308201aea0030201020205008d00cd12300506032b6570304231093007060355040613003109300706035504081300310930070603550407130031093007060355040a130031093007060355040b13003109300706035504031300301e170d3235303431303032323134335a170d3939313233313233353935395a304231093007060355040613003109300706035504081300310930070603550407130031093007060355040a130031093007060355040b13003109300706035504031300304a300506032b657003410042149f1a6f1da43fcf066a473e12515b5b6216fedfc52b87bee091456981d9c6d2a76829a3b53e66af79bb0cb1efade075f0ae65eaaabb75f5106bbeef59b866a381a43081a130819e0603551d11048196308193820c6d79646f6d61696e2e636f6d82107777772e6d79646f6d61696e2e636f6d820b6578616d706c652e636f6d820f7777772e6578616d706c652e636f6d86537765622b63617264616e6f3a2f2f616464722f7374616b655f7465737431757268737871383939367979377661727a306b6772306576326539776c74766b6372306b757a643477777a73647a71767430653874300506032b657003410097cdda6815238e059116a6906157d94d93373ac6d6f92649a20446a51f0e6c34f76db1fabbdb20128c32522bcac1522526e360f00160c354e396e5dabc961b07", - "time": "2025-04-10T02:22:19+00:00" - } - ] + "catalyst_id": "preprod.cardano/QhSfGm8dpD_PBmpHPhJRW1tiFv7fxSuHvuCRRWmB2cY", + "last_persistent_txn": "0x95f781a3db75af41d1dde5a997b9f9ab3e20035882d4a2ccafdc81cfda6f52a2", + "last_volatile_txn": "0x95f781a3db75af41d1dde5a997b9f9ab3e20035882d4a2ccafdc81cfda6f52a2", + "purpose": [ + "ca7a1457-ef9f-4c7f-9c74-7f8c4a4cfa6c" + ], + "invalid": [ + { + "previous_txn": "0x95f781a3db75af41d1dde5a997b9f9ab3e20035882d4a2ccafdc81cfda6f52a2", + "purpose": "c9993e54-1ee1-41f7-ab99-3fdec865c744", + "report": "An error has occurred, the details of the error are ...", + "slot": 1234567, + "time": "2024-04-09T15:28:21+00:00", + "txn_id": "0x95f781a3db75af41d1dde5a997b9f9ab3e20035882d4a2ccafdc81cfda6f52a2", + "txn_index": 7 + } + ], + "roles": [ + { + "role_id": 0, + "encryption_keys": [ + { + "is_persistent": true, + "key_type": "x509", + "key_value": { + "pubkey": "0x56CDD154355E078A0990F9E633F9553F7D43A68B2FF9BEF78B9F5C71C808A7C8" + }, + "slot": 1234567, + "time": "2024-04-09T15:28:21+00:00", + "txn_index": 7 + } + ], + "extended_data": [ + { + "key": 10, + "value": "0x6f526567697374657220726f6c652030" + } + ], + "payment_addresses": [ + { + "address": "addr_test1qr3f7dmpr59t8vtp8an9ptrxvetvd4t7mzxwdp9tdjva8580qvqw2t5gfue6xylvsxljc4j2a7kedsxldcym2uu9q6yqs0ju92", + "is_persistent": true, + "time": "2025-04-10T02:22:19+00:00", + "slot": 1234567, + "txn_index": 7 + } + ], + "signing_keys": [ + { + "is_persistent": true, + "key_type": "x509", + "key_value": { + "x509": "-----BEGIN CERTIFICATE-----\nMIIB/DCCAa6gAwIBAgIFAI0AzRIwBQYDK2VwMEIxCTAHBgNVBAYTADEJMAcGA1UE\nCBMAMQkwBwYDVQQHEwAxCTAHBgNVBAoTADEJMAcGA1UECxMAMQkwBwYDVQQDEwAw\nHhcNMjUwNDEwMDIyMTQzWhcNOTkxMjMxMjM1OTU5WjBCMQkwBwYDVQQGEwAxCTAH\nBgNVBAgTADEJMAcGA1UEBxMAMQkwBwYDVQQKEwAxCTAHBgNVBAsTADEJMAcGA1UE\nAxMAMEowBQYDK2VwA0EAQhSfGm8dpD/PBmpHPhJRW1tiFv7fxSuHvuCRRWmB2cbS\np2gpo7U+Zq95uwyx763gdfCuZeqqu3X1EGu+71m4ZqOBpDCBoTCBngYDVR0RBIGW\nMIGTggxteWRvbWFpbi5jb22CEHd3dy5teWRvbWFpbi5jb22CC2V4YW1wbGUuY29t\ngg93d3cuZXhhbXBsZS5jb22GU3dlYitjYXJkYW5vOi8vYWRkci9zdGFrZV90ZXN0\nMXVyaHN4cTg5OTZ5eTd2YXJ6MGtncjBldjJlOXdsdHZrY3Iwa3V6ZDR3d3pzZHpx\ndnQwZTh0MAUGAytlcANBAJfN2mgVI44FkRamkGFX2U2TNzrG1vkmSaIERqUfDmw0\n922x+rvbIBKMMlIrysFSJSbjYPABYMNU45bl2ryWGwc=\n-----END CERTIFICATE-----" + }, + "time": "2025-04-10T02:22:19+00:00", + "slot": 1234567, + "txn_index": 7 + } + ] + }, + { + "role_id": 3, + "encryption_keys": [ + { + "is_persistent": true, + "key_type": "x509", + "key_value": { + "pubkey": "0x56CDD154355E078A0990F9E633F9553F7D43A68B2FF9BEF78B9F5C71C808A7C8" + }, + "slot": 1234567, + "time": "2024-04-09T15:28:21+00:00", + "txn_index": 7 + } + ], + "extended_data": [ + { + "key": 10, + "value": "0x6448696869" + } + ], + "payment_addresses": [ + { + "address": "addr_test1qr3f7dmpr59t8vtp8an9ptrxvetvd4t7mzxwdp9tdjva8580qvqw2t5gfue6xylvsxljc4j2a7kedsxldcym2uu9q6yqs0ju92", + "is_persistent": true, + "time": "2025-04-10T02:22:19+00:00", + "slot": 1234567, + "txn_index": 7 + }, + { + "address": "addr_test1qr4jr9uuq0hdwgrsyze2pdr4vk6647c69suyndv6r75wd30qwklppmzu2aw2l7mgkzxrz3cxvm20uxhw5p7pd4j88yps20uevn", + "is_persistent": true, + "time": "2025-04-11T04:49:07+00:00", + "slot": 1234567, + "txn_index": 7 + } + ], + "signing_keys": [ + { + "is_persistent": true, + "key_type": "pubkey", + "key_value": { + "pubkey": "0xac36a7c87a77de72c3404cca36029e63cdd5cc6e7b2538a52908eee983011b51" + }, + "time": "2025-04-10T02:22:19+00:00", + "slot": 1234567, + "txn_index": 7 }, - "3": { - "extended_data": { - "10": [ - 100, - 72, - 105, - 104, - 105 - ] - }, - "payment_addresses": [ - { - "address": "addr_test1qr3f7dmpr59t8vtp8an9ptrxvetvd4t7mzxwdp9tdjva8580qvqw2t5gfue6xylvsxljc4j2a7kedsxldcym2uu9q6yqs0ju92", - "is_persistent": true, - "time": "2025-04-10T02:22:19+00:00" - }, - { - "address": "addr_test1qr4jr9uuq0hdwgrsyze2pdr4vk6647c69suyndv6r75wd30qwklppmzu2aw2l7mgkzxrz3cxvm20uxhw5p7pd4j88yps20uevn", - "is_persistent": true, - "time": "2025-04-11T04:49:07+00:00" - } - ], - "signing_keys": [ - { - "is_persistent": true, - "key_type": "pubkey", - "key_value": "0xac36a7c87a77de72c3404cca36029e63cdd5cc6e7b2538a52908eee983011b51", - "time": "2025-04-10T02:22:19+00:00" - }, - { - "is_persistent": true, - "key_type": "pubkey", - "key_value": "0xac36a7c87a77de72c3404cca36029e63cdd5cc6e7b2538a52908eee983011b51", - "time": "2025-04-11T04:49:07+00:00" - } - ] + { + "is_persistent": true, + "key_type": "pubkey", + "key_value": { + "pubkey": "0xac36a7c87a77de72c3404cca36029e63cdd5cc6e7b2538a52908eee983011b51" + }, + "time": "2025-04-11T04:49:07+00:00", + "slot": 1234567, + "txn_index": 7 } + ] } + ] } '''; -const _voterJson = ''' +const _voterJson = r''' { - "catalyst_id": "preprod.cardano/QhSfGm8dpD_PBmpHPhJRW1tiFv7fxSuHvuCRRWmB2cY", - "last_persistent_txn": "0x95f781a3db75af41d1dde5a997b9f9ab3e20035882d4a2ccafdc81cfda6f52a2", - "purpose": [ - "ca7a1457-ef9f-4c7f-9c74-7f8c4a4cfa6c" - ], - "roles": { - "0": { - "extended_data": { - "10": [ - 111, - 82, - 101, - 103, - 105, - 115, - 116, - 101, - 114, - 32, - 114, - 111, - 108, - 101, - 32, - 48 - ] - }, - "payment_addresses": [ - { - "address": "addr_test1qr3f7dmpr59t8vtp8an9ptrxvetvd4t7mzxwdp9tdjva8580qvqw2t5gfue6xylvsxljc4j2a7kedsxldcym2uu9q6yqs0ju92", - "is_persistent": true, - "time": "2025-04-10T02:22:19+00:00" - } - ], - "signing_keys": [ - { - "is_persistent": true, - "key_type": "x509", - "key_value": "0x308201fc308201aea0030201020205008d00cd12300506032b6570304231093007060355040613003109300706035504081300310930070603550407130031093007060355040a130031093007060355040b13003109300706035504031300301e170d3235303431303032323134335a170d3939313233313233353935395a304231093007060355040613003109300706035504081300310930070603550407130031093007060355040a130031093007060355040b13003109300706035504031300304a300506032b657003410042149f1a6f1da43fcf066a473e12515b5b6216fedfc52b87bee091456981d9c6d2a76829a3b53e66af79bb0cb1efade075f0ae65eaaabb75f5106bbeef59b866a381a43081a130819e0603551d11048196308193820c6d79646f6d61696e2e636f6d82107777772e6d79646f6d61696e2e636f6d820b6578616d706c652e636f6d820f7777772e6578616d706c652e636f6d86537765622b63617264616e6f3a2f2f616464722f7374616b655f7465737431757268737871383939367979377661727a306b6772306576326539776c74766b6372306b757a643477777a73647a71767430653874300506032b657003410097cdda6815238e059116a6906157d94d93373ac6d6f92649a20446a51f0e6c34f76db1fabbdb20128c32522bcac1522526e360f00160c354e396e5dabc961b07", - "time": "2025-04-10T02:22:19+00:00" - } - ] + "catalyst_id": "preprod.cardano/QhSfGm8dpD_PBmpHPhJRW1tiFv7fxSuHvuCRRWmB2cY", + "last_persistent_txn": "0x95f781a3db75af41d1dde5a997b9f9ab3e20035882d4a2ccafdc81cfda6f52a2", + "purpose": [ + "ca7a1457-ef9f-4c7f-9c74-7f8c4a4cfa6c" + ], + "roles": [ + { + "role_id": 0, + "encryption_keys": [ + { + "is_persistent": true, + "key_type": "x509", + "key_value": { + "pubkey": "0x56CDD154355E078A0990F9E633F9553F7D43A68B2FF9BEF78B9F5C71C808A7C8" + }, + "slot": 1234567, + "time": "2024-04-09T15:28:21+00:00", + "txn_index": 7 + } + ], + "extended_data": [ + { + "key": 10, + "value": "0x6f526567697374657220726f6c652030" + } + ], + "payment_addresses": [ + { + "address": "addr_test1qr3f7dmpr59t8vtp8an9ptrxvetvd4t7mzxwdp9tdjva8580qvqw2t5gfue6xylvsxljc4j2a7kedsxldcym2uu9q6yqs0ju92", + "is_persistent": true, + "time": "2025-04-10T02:22:19+00:00", + "slot": 1234567, + "txn_index": 7 + } + ], + "signing_keys": [ + { + "is_persistent": true, + "key_type": "x509", + "key_value": { + "x509": "-----BEGIN CERTIFICATE-----\nMIIB/DCCAa6gAwIBAgIFAI0AzRIwBQYDK2VwMEIxCTAHBgNVBAYTADEJMAcGA1UE\nCBMAMQkwBwYDVQQHEwAxCTAHBgNVBAoTADEJMAcGA1UECxMAMQkwBwYDVQQDEwAw\nHhcNMjUwNDEwMDIyMTQzWhcNOTkxMjMxMjM1OTU5WjBCMQkwBwYDVQQGEwAxCTAH\nBgNVBAgTADEJMAcGA1UEBxMAMQkwBwYDVQQKEwAxCTAHBgNVBAsTADEJMAcGA1UE\nAxMAMEowBQYDK2VwA0EAQhSfGm8dpD/PBmpHPhJRW1tiFv7fxSuHvuCRRWmB2cbS\np2gpo7U+Zq95uwyx763gdfCuZeqqu3X1EGu+71m4ZqOBpDCBoTCBngYDVR0RBIGW\nMIGTggxteWRvbWFpbi5jb22CEHd3dy5teWRvbWFpbi5jb22CC2V4YW1wbGUuY29t\ngg93d3cuZXhhbXBsZS5jb22GU3dlYitjYXJkYW5vOi8vYWRkci9zdGFrZV90ZXN0\nMXVyaHN4cTg5OTZ5eTd2YXJ6MGtncjBldjJlOXdsdHZrY3Iwa3V6ZDR3d3pzZHpx\ndnQwZTh0MAUGAytlcANBAJfN2mgVI44FkRamkGFX2U2TNzrG1vkmSaIERqUfDmw0\n922x+rvbIBKMMlIrysFSJSbjYPABYMNU45bl2ryWGwc=\n-----END CERTIFICATE-----" + }, + "time": "2025-04-10T02:22:19+00:00", + "slot": 1234567, + "txn_index": 7 } + ] } + ] } '''; /* cSpell:enable */ diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_document_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_document_test.dart index 6215058169f3..95410b119e1f 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_document_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_document_test.dart @@ -28,12 +28,13 @@ void main() { DocumentSchemaDto.fromJson(schemaJson).toModel(), ); final document = documentDto.toModel(); + final categoryRef = DocumentRefFactory.signedDocumentRef(); return ProposalDocument( metadata: ProposalMetadata( selfRef: DocumentRefFactory.draftRef(), templateRef: DocumentRefFactory.signedDocumentRef(), - categoryId: DocumentRefFactory.signedDocumentRef(), + parameters: DocumentParameters({categoryRef}), authors: const [], ), document: document, diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/signed_document/signed_document_manager_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/signed_document/signed_document_manager_test.dart index 2e91d2ec0ea2..f499cc3b2594 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/signed_document/signed_document_manager_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/signed_document/signed_document_manager_test.dart @@ -4,6 +4,9 @@ import 'package:catalyst_voices_repositories/src/signed_document/signed_document import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../../fixture/signed_document/signed_document_test_data.dart'; +import '../utils/test_factories.dart'; + void main() { group(SignedDocumentManager, () { const documentManager = SignedDocumentManager( @@ -40,19 +43,41 @@ void main() { expect(parsedDocument, equals(signedDocument)); expect(parsedDocument.signers, [_catalystId]); }); + + test('parse signed document v0.0.1', () async { + final bytes = await SignedDocumentTestData.signedDocumentV0_0_1Bytes; + final document = await documentManager.parseDocument(bytes); + + expect(document.metadata.type, equals(DocumentType.proposalDocument)); + expect(document.metadata.template, isNotNull); + expect(document.metadata.parameters, isNotEmpty); + }); + + test('parse signed document v0.0.4', () async { + final bytes = await SignedDocumentTestData.signedDocumentV0_0_4Bytes; + final document = await documentManager.parseDocument(bytes); + + expect(document.metadata.type, equals(DocumentType.proposalDocument)); + expect(document.metadata.template, isNotNull); + expect(document.metadata.parameters, isNotEmpty); + }); }); } -const _metadata = SignedDocumentMetadata( - contentType: SignedDocumentContentType.json, - documentType: DocumentType.proposalDocument, -); - final _catalystId = CatalystId( host: CatalystIdHost.cardanoPreprod.host, role0Key: _publicKey.publicKeyBytes, ); +final _categoryRef = DocumentRefFactory.signedDocumentRef(); + +final _metadata = DocumentDataMetadata.proposal( + selfRef: DocumentRefFactory.signedDocumentRef(), + parameters: DocumentParameters({_categoryRef}), + template: DocumentRefFactory.signedDocumentRef(), + authors: [_catalystId], +); + final _privateKey = _FakeCatalystPrivateKey(bytes: _privateKeyBytes); final _privateKeyBytes = Uint8List.fromList(List.filled(32, 0)); final _publicKey = _FakeCatalystPublicKey(bytes: _publicKeyBytes); diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/signed_document/signed_document_mapper_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/signed_document/signed_document_mapper_test.dart new file mode 100644 index 000000000000..3020cf05748a --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/signed_document/signed_document_mapper_test.dart @@ -0,0 +1,249 @@ +// ignore_for_file: avoid_redundant_argument_values + +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:catalyst_cose/catalyst_cose.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:catalyst_voices_repositories/src/document/exception/document_exception.dart'; +import 'package:catalyst_voices_repositories/src/signed_document/signed_document_mapper.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('SignedDocumentMapper', () { + // Test Data Setup + const uuidV4Str = '3e4808cc-c86e-467b-9702-d60baa9d1fca'; + const uuidV7Str = '019273a8-3339-7604-b12e-86625513f0f0'; + + // Catalyst IDs + /* cSpell:disable */ + const catalystIdStr = 'id.catalyst://cardano/FftxFnOrj2qmTuB2oZG2v0YEWJfKvQ9Gg8AgNAhDsKE'; + final catalystId = CatalystId.fromUri(Uri.parse(catalystIdStr)); + final catalystIdKid = CatalystIdKid(Uint8List.fromList(utf8.encode(catalystIdStr))); + /* cSpell:enable */ + + // Common Objects + const signedDocRef = SignedDocumentRef(id: uuidV7Str, version: uuidV7Str); + + group('buildCoseProtectedHeaders', () { + test('maps all fields correctly when fully populated', () { + // Arrange + final metadata = DocumentDataMetadata( + contentType: DocumentContentType.json, + type: DocumentType.proposalDocument, + selfRef: signedDocRef, + ref: signedDocRef, + template: signedDocRef, + reply: signedDocRef, + section: '/payload/title', + collaborators: [catalystId], + parameters: DocumentParameters({signedDocRef}), + authors: [catalystId], + ); + + // Act + final headers = SignedDocumentMapper.buildCoseProtectedHeaders(metadata); + + // Assert + expect(headers.mediaType, CoseMediaType.json); + expect(headers.contentEncoding, CoseHttpContentEncoding.brotli); + expect(headers.id?.value.format(), uuidV7Str); + expect(headers.ver?.value.format(), uuidV7Str); + + // Check Lists mapping (ref, template, reply) + expect(headers.ref?.refs, hasLength(1)); + expect(headers.ref?.refs.first.documentId.format(), uuidV7Str); + + expect(headers.template?.refs, hasLength(1)); + expect(headers.reply?.refs, hasLength(1)); + + // Check Section + expect(headers.section?.value.text, '/payload/title'); + + // Check Collaborators + expect(headers.collaborators?.list, hasLength(1)); + expect(headers.collaborators?.list.first.bytes, catalystIdKid.bytes); + + // Check Parameters + expect(headers.parameters?.refs, hasLength(1)); + }); + + test('handles nullable fields correctly', () { + // Arrange + final metadata = DocumentDataMetadata( + contentType: DocumentContentType.unknown, + type: DocumentType.proposalDocument, + selfRef: signedDocRef, + // All optional fields null + ref: null, + template: null, + reply: null, + section: null, + collaborators: null, + parameters: const DocumentParameters({}), + authors: const [], + ); + + // Act + final headers = SignedDocumentMapper.buildCoseProtectedHeaders(metadata); + + // Assert + expect(headers.mediaType, isNull, reason: 'Unknown content type maps to null'); + expect(headers.ref, isNull); + expect(headers.template, isNull); + expect(headers.reply, isNull); + expect(headers.section, isNull); + expect(headers.collaborators, isNull); + expect(headers.parameters, isNull); + }); + }); + + group('buildMetadata', () { + test('reconstructs metadata correctly from valid COSE headers', () { + // Arrange + final coseRef = CoseDocumentRef.optional( + documentId: CoseUuidV7.fromString(uuidV7Str), + documentVer: CoseUuidV7.fromString(uuidV7Str), + documentLocator: CoseDocumentLocator.fallback(), + ); + + final protectedHeaders = CoseHeaders.protected( + mediaType: CoseMediaType.json, + type: CoseDocumentType(CoseUuidV4.fromString(uuidV4Str)), + id: CoseDocumentId(CoseUuidV7.fromString(uuidV7Str)), + ver: CoseDocumentVer(CoseUuidV7.fromString(uuidV7Str)), + ref: CoseDocumentRefs([coseRef]), + template: CoseDocumentRefs([coseRef]), + reply: CoseDocumentRefs([coseRef]), + section: const CoseSectionRef(CoseJsonPointer('/section')), + collaborators: CoseCollaborators([catalystIdKid]), + parameters: CoseDocumentRefs([coseRef]), + ); + + const unprotectedHeaders = CoseHeaders.unprotected(); + final signers = [catalystIdKid]; + + // Act + final metadata = SignedDocumentMapper.buildMetadata( + protectedHeaders: protectedHeaders, + unprotectedHeaders: unprotectedHeaders, + signers: signers, + ); + + // Assert + expect(metadata.contentType, DocumentContentType.json); + expect(metadata.id, signedDocRef.id); + expect(metadata.version, signedDocRef.version); + + // Verify single item extraction from lists + expect(metadata.ref?.id, signedDocRef.id); + expect(metadata.template?.id, signedDocRef.id); + expect(metadata.reply?.id, signedDocRef.id); + + expect(metadata.section, '/section'); + expect(metadata.collaborators, contains(catalystId)); + expect(metadata.parameters.set, hasLength(1)); + expect(metadata.authors, contains(catalystId)); + }); + + test('throws DocumentMetadataMalformedException when ID is missing', () { + // Arrange + final headers = CoseHeaders.protected( + ver: CoseDocumentVer(CoseUuidV7.fromString(uuidV7Str)), + // Missing ID + ); + + // Act & Assert + expect( + () => SignedDocumentMapper.buildMetadata( + protectedHeaders: headers, + unprotectedHeaders: const CoseHeaders.unprotected(), + signers: [], + ), + throwsA( + isA().having( + (e) => e.reasons, + 'reasons', + contains('id is missing'), + ), + ), + ); + }); + + test('throws DocumentMetadataMalformedException when Version is missing', () { + // Arrange + final headers = CoseHeaders.protected( + id: CoseDocumentId(CoseUuidV7.fromString(uuidV7Str)), + // Missing Version + ); + + // Act & Assert + expect( + () => SignedDocumentMapper.buildMetadata( + protectedHeaders: headers, + unprotectedHeaders: const CoseHeaders.unprotected(), + signers: [], + ), + throwsA( + isA().having( + (e) => e.reasons, + 'reasons', + contains('version is missing'), + ), + ), + ); + }); + + test('maps various CoseMediaTypes to DocumentContentType.unknown', () { + final unsupportedTypes = [ + CoseMediaType.markdown, + CoseMediaType.html, + CoseMediaType.cbor, + null, + ]; + + for (final type in unsupportedTypes) { + final headers = CoseHeaders.protected( + id: CoseDocumentId(CoseUuidV7.fromString(uuidV7Str)), + ver: CoseDocumentVer(CoseUuidV7.fromString(uuidV7Str)), + mediaType: type, + ); + + final metadata = SignedDocumentMapper.buildMetadata( + protectedHeaders: headers, + unprotectedHeaders: const CoseHeaders.unprotected(), + signers: [], + ); + + expect( + metadata.contentType, + DocumentContentType.unknown, + reason: 'Failed to map $type to unknown', + ); + } + }); + + test('filters out invalid CatalystId signers gracefully', () { + // Arrange + final invalidBytes = Uint8List.fromList([0xFF, 0xFE]); // Invalid UTF-8 + final invalidKid = CatalystIdKid(invalidBytes); + + final headers = CoseHeaders.protected( + id: CoseDocumentId(CoseUuidV7.fromString(uuidV7Str)), + ver: CoseDocumentVer(CoseUuidV7.fromString(uuidV7Str)), + ); + + // Act + final metadata = SignedDocumentMapper.buildMetadata( + protectedHeaders: headers, + unprotectedHeaders: const CoseHeaders.unprotected(), + signers: [catalystIdKid, invalidKid], + ); + + // Assert + expect(metadata.authors, hasLength(1)); + expect(metadata.authors?.first, catalystId); + }); + }); + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/utils/test_factories.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/utils/test_factories.dart index bd763e422f05..91d4b231c053 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/utils/test_factories.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/utils/test_factories.dart @@ -1,4 +1,5 @@ import 'dart:math'; +import 'dart:typed_data'; import 'package:catalyst_voices_models/catalyst_voices_models.dart' hide Document; import 'package:catalyst_voices_repositories/src/database/database.dart'; @@ -7,20 +8,71 @@ import 'package:uuid_plus/uuid_plus.dart'; abstract final class DocumentDataFactory { static DocumentData build({ - DocumentType type = DocumentType.proposalDocument, + DocumentDataMetadata? metadata, + DocumentDataContent? content, + }) { + return DocumentData( + metadata: metadata ?? DocumentDataMetadataFactory.proposal(), + content: content ?? const DocumentDataContent({}), + ); + } +} + +abstract final class DocumentDataMetadataFactory { + static final _categoryRef = DocumentRefFactory.signedDocumentRef(); + static final _commentTemplateRef = DocumentRefFactory.signedDocumentRef(); + static final _proposalTemplateRef = DocumentRefFactory.signedDocumentRef(); + static final _catalystId = CatalystId(host: 'test', role0Key: Uint8List(32)); + + static DocumentDataMetadata comment({ + SignedDocumentRef? selfRef, + SignedDocumentRef? proposalRef, + SignedDocumentRef? template, + DocumentParameters? parameters, + List? authors, + }) { + return DocumentDataMetadata.comment( + selfRef: selfRef ?? DocumentRefFactory.signedDocumentRef(), + proposalRef: proposalRef ?? DocumentRefFactory.signedDocumentRef(), + template: template ?? _commentTemplateRef, + parameters: parameters ?? DocumentParameters({_categoryRef}), + authors: authors ?? [_catalystId], + ); + } + + static DocumentDataMetadata proposal({ DocumentRef? selfRef, SignedDocumentRef? template, - SignedDocumentRef? categoryId, - DocumentDataContent content = const DocumentDataContent({}), + DocumentParameters? parameters, + List? authors, }) { - return DocumentData( - metadata: DocumentDataMetadata( - type: type, - selfRef: selfRef ?? DocumentRefFactory.signedDocumentRef(), - template: template, - categoryId: categoryId, - ), - content: content, + return DocumentDataMetadata.proposal( + selfRef: selfRef ?? DocumentRefFactory.signedDocumentRef(), + template: template ?? _proposalTemplateRef, + parameters: parameters ?? DocumentParameters({_categoryRef}), + authors: authors ?? [_catalystId], + ); + } + + static DocumentDataMetadata proposalAction({ + SignedDocumentRef? selfRef, + SignedDocumentRef? proposalRef, + DocumentParameters? parameters, + }) { + return DocumentDataMetadata.proposalAction( + selfRef: selfRef ?? DocumentRefFactory.signedDocumentRef(), + proposalRef: proposalRef ?? DocumentRefFactory.signedDocumentRef(), + parameters: parameters ?? DocumentParameters({_categoryRef}), + ); + } + + static DocumentDataMetadata proposalTemplate({ + DocumentRef? selfRef, + DocumentParameters? parameters, + }) { + return DocumentDataMetadata.proposalTemplate( + selfRef: selfRef ?? DocumentRefFactory.signedDocumentRef(), + parameters: parameters ?? DocumentParameters({_categoryRef}), ); } } @@ -32,11 +84,7 @@ abstract final class DocumentFactory { DateTime? createdAt, }) { content ??= const DocumentDataContent({}); - - metadata ??= DocumentDataMetadata( - type: DocumentType.proposalDocument, - selfRef: DocumentRefFactory.signedDocumentRef(), - ); + metadata ??= DocumentDataMetadataFactory.proposal(); final id = UuidHiLo.from(metadata.id); final ver = UuidHiLo.from(metadata.version); @@ -142,11 +190,7 @@ abstract final class DraftFactory { String? title, }) { content ??= const DocumentDataContent({}); - - metadata ??= DocumentDataMetadata( - type: DocumentType.proposalDocument, - selfRef: DocumentRefFactory.draftRef(), - ); + metadata ??= DocumentDataMetadataFactory.proposal(); title ??= 'Draft[${metadata.id}] title'; diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/campaign/campaign_service.dart b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/campaign/campaign_service.dart index 67815e1a1918..56d7fdae6b3d 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/campaign/campaign_service.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/campaign/campaign_service.dart @@ -35,7 +35,7 @@ abstract interface class CampaignService { Future getCampaignPhaseTimeline(CampaignPhaseType stage); - Future getCategory(SignedDocumentRef ref); + Future getCategory(DocumentParameters parameters); } final class CampaignServiceImpl implements CampaignService { @@ -103,41 +103,45 @@ final class CampaignServiceImpl implements CampaignService { } @override - Future getCategory(SignedDocumentRef ref) async { - final category = await _campaignRepository.getCategory(ref); + Future getCategory(DocumentParameters parameters) async { + final category = await _campaignRepository.getCategory(parameters); if (category == null) { throw NotFoundException( - message: 'Did not find category with ref $ref', + message: 'Did not find category with parameters $parameters', ); } + return _loadCampaignCategoryDetails(category); + } + + MultiCurrencyAmount _calculateTotalAsk(List proposals) { + final totalAmount = MultiCurrencyAmount(); + for (final proposal in proposals) { + final fundsRequested = proposal.document.fundsRequested; + if (fundsRequested != null) { + totalAmount.add(fundsRequested); + } + } + return totalAmount; + } + + Future _loadCampaignCategoryDetails(CampaignCategory base) async { final categoryProposals = await _proposalRepository.getProposals( type: ProposalsFilterType.finals, - categoryRef: ref, + categoryRef: base.selfRef, ); final proposalSubmissionStage = await getCampaignPhaseTimeline( CampaignPhaseType.proposalSubmission, ); final totalAsk = _calculateTotalAsk(categoryProposals); - return category.copyWith( + return base.copyWith( totalAsk: totalAsk, proposalsCount: categoryProposals.length, submissionCloseDate: proposalSubmissionStage.timeline.to, ); } - MultiCurrencyAmount _calculateTotalAsk(List proposals) { - final totalAmount = MultiCurrencyAmount(); - for (final proposal in proposals) { - final fundsRequested = proposal.document.fundsRequested; - if (fundsRequested != null) { - totalAmount.add(fundsRequested); - } - } - return totalAmount; - } - Future> _updateCategories( List categories, DateTime? proposalSubmissionTime, diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/comment/comment_service.dart b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/comment/comment_service.dart index 3fbba444f4f1..160ca8810207 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/comment/comment_service.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/comment/comment_service.dart @@ -51,7 +51,9 @@ final class CommentServiceImpl implements CommentService { ?.comment; if (commentTemplateRef == null) { - throw const ApiErrorResponseException.notFound(); + throw ApiBadResponseException.notFound( + message: 'No comment template for category id ${category.id}', + ); } return _commentRepository.getCommentTemplate(ref: commentTemplateRef); diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/proposal/proposal_service.dart b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/proposal/proposal_service.dart index 9ece65eec2f7..57fc63ddbf96 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/proposal/proposal_service.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/proposal/proposal_service.dart @@ -24,8 +24,8 @@ abstract interface class ProposalService { /// Creates a new proposal draft locally. Future createDraftProposal({ required DocumentDataContent content, - required SignedDocumentRef template, - required SignedDocumentRef categoryId, + required SignedDocumentRef templateRef, + required DocumentParameters parameters, }); /// Delete a draft proposal from local storage. @@ -45,7 +45,7 @@ abstract interface class ProposalService { /// Returns the [SignedDocumentRef] of the created [ProposalSubmissionAction]. Future forgetProposal({ required SignedDocumentRef proposalRef, - required SignedDocumentRef categoryId, + required DocumentParameters proposalParameters, }); /// Similar to [watchFavoritesProposalsIds] stops after first emit. @@ -68,7 +68,7 @@ abstract interface class ProposalService { }); Future getProposalTemplate({ - required DocumentRef ref, + required DocumentRef category, }); /// Imports the proposal from [data] encoded by [encodeProposalForExport]. @@ -102,21 +102,21 @@ abstract interface class ProposalService { /// Returns the [SignedDocumentRef] of the created [ProposalSubmissionAction]. Future submitProposalForReview({ required SignedDocumentRef proposalRef, - required SignedDocumentRef categoryId, + required DocumentParameters proposalParameters, }); /// Returns the [SignedDocumentRef] of the created [ProposalSubmissionAction]. Future unlockProposal({ required SignedDocumentRef proposalRef, - required SignedDocumentRef categoryId, + required DocumentParameters proposalParameters, }); /// Upserts a proposal draft in the local storage. Future upsertDraftProposal({ required DraftRef selfRef, required DocumentDataContent content, - required SignedDocumentRef template, - required SignedDocumentRef categoryId, + required SignedDocumentRef templateRef, + required DocumentParameters parameters, }); /// Fetches favorites proposals ids of the user @@ -174,18 +174,18 @@ final class ProposalServiceImpl implements ProposalService { @override Future createDraftProposal({ required DocumentDataContent content, - required SignedDocumentRef template, - required SignedDocumentRef categoryId, + required SignedDocumentRef templateRef, + required DocumentParameters parameters, }) async { final draftRef = DraftRef.generateFirstRef(); - final catalystId = _getUserCatalystId(); + final catalystId = _userService.activeAccountId; + await _proposalRepository.upsertDraftProposal( document: DocumentData( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadata.proposal( selfRef: draftRef, - template: template, - categoryId: categoryId, + template: templateRef, + parameters: parameters, authors: [catalystId], ), content: content, @@ -212,16 +212,18 @@ final class ProposalServiceImpl implements ProposalService { @override Future forgetProposal({ required SignedDocumentRef proposalRef, - required SignedDocumentRef categoryId, + required DocumentParameters proposalParameters, }) { return _signerService.useProposerCredentials( (catalystId, privateKey) async { final actionRef = SignedDocumentRef.generateFirstRef(); await _proposalRepository.publishProposalAction( - actionRef: actionRef, - proposalRef: proposalRef, - categoryId: categoryId, + metadata: DocumentDataMetadata.proposalAction( + selfRef: actionRef, + proposalRef: proposalRef, + parameters: proposalParameters, + ), action: ProposalSubmissionAction.hide, catalystId: catalystId, privateKey: privateKey, @@ -302,27 +304,14 @@ final class ProposalServiceImpl implements ProposalService { .toList(); } - final categoriesRefs = proposals.map((proposal) => proposal.categoryRef).toSet(); - // If we are getting proposals then campaign needs to be active // Getting whole campaign with list of categories saves time then calling to get each category separately // for each proposal - final activeCampaign = _activeCampaignObserver.campaign; - - final categories = Map.fromEntries( - categoriesRefs.map((ref) { - final category = activeCampaign!.categories.firstWhere( - (category) => category.selfRef == ref, - ); - return MapEntry(ref.id, category); - }), - ); - final proposalsWithContext = proposals .map( (proposal) => ProposalWithContext( proposal: proposal, - category: categories[proposal.categoryRef.id]!, + category: _findActiveCampaignCategory(proposal.parameters), user: const ProposalUserContext(), ), ) @@ -333,20 +322,28 @@ final class ProposalServiceImpl implements ProposalService { @override Future getProposalTemplate({ - required DocumentRef ref, + required DocumentRef category, }) async { - final proposalTemplate = await _proposalRepository.getProposalTemplate( - ref: ref, - ); + final template = await _proposalRepository.getProposalTemplate(category: category); + if (template == null) { + throw ProposalTemplateNotFoundException(category: category); + } - return proposalTemplate; + return template; } @override Future importProposal(Uint8List data) async { - final allowTemplateRefs = - _activeCampaignObserver.campaign?.categories.map((e) => e.proposalTemplateRef).toList() ?? - []; + final activeCampaign = _activeCampaignObserver.campaign; + if (activeCampaign == null) { + throw const ActiveCampaignNotFoundException(); + } + + final campaignFilters = CampaignFilters.from(activeCampaign); + final allowTemplateRefs = await _documentRepository.getRefs( + type: DocumentType.proposalTemplate, + campaign: campaignFilters, + ); final parsedDocument = await _documentRepository.parseDocumentForImport(data: data); @@ -354,11 +351,13 @@ final class ProposalServiceImpl implements ProposalService { // TODO(LynxLynxx): Remove after we support multiple fund templates if (!allowTemplateRefs.contains(parsedDocument.metadata.template)) { throw const DocumentImportInvalidDataException( - SignedDocumentMetadataMalformed(reasons: ['template ref is not allowed to be imported']), + DocumentMetadataMalformedException( + reasons: ['template ref is not allowed to be imported'], + ), ); } - final authorId = _getUserCatalystId(); + final authorId = _userService.activeAccountId; final newRef = await _documentRepository.saveImportedDocument( document: parsedDocument, authorId: authorId, @@ -415,7 +414,7 @@ final class ProposalServiceImpl implements ProposalService { @override Future submitProposalForReview({ required SignedDocumentRef proposalRef, - required SignedDocumentRef categoryId, + required DocumentParameters proposalParameters, }) async { if (await isMaxProposalsLimitReached()) { throw const ProposalLimitReachedException( @@ -428,9 +427,11 @@ final class ProposalServiceImpl implements ProposalService { final actionRef = SignedDocumentRef.generateFirstRef(); await _proposalRepository.publishProposalAction( - actionRef: actionRef, - proposalRef: proposalRef, - categoryId: categoryId, + metadata: DocumentDataMetadata.proposalAction( + selfRef: actionRef, + proposalRef: proposalRef, + parameters: proposalParameters, + ), action: ProposalSubmissionAction.aFinal, catalystId: catalystId, privateKey: privateKey, @@ -444,16 +445,18 @@ final class ProposalServiceImpl implements ProposalService { @override Future unlockProposal({ required SignedDocumentRef proposalRef, - required SignedDocumentRef categoryId, + required DocumentParameters proposalParameters, }) async { return _signerService.useProposerCredentials( (catalystId, privateKey) async { final actionRef = SignedDocumentRef.generateFirstRef(); await _proposalRepository.publishProposalAction( - actionRef: actionRef, - proposalRef: proposalRef, - categoryId: categoryId, + metadata: DocumentDataMetadata.proposalAction( + selfRef: actionRef, + proposalRef: proposalRef, + parameters: proposalParameters, + ), action: ProposalSubmissionAction.draft, catalystId: catalystId, privateKey: privateKey, @@ -468,21 +471,20 @@ final class ProposalServiceImpl implements ProposalService { Future upsertDraftProposal({ required DraftRef selfRef, required DocumentDataContent content, - required SignedDocumentRef template, - required SignedDocumentRef categoryId, + required SignedDocumentRef templateRef, + required DocumentParameters parameters, }) async { // TODO(LynxLynxx): when we start supporting multiple authors // we need to get the list of authors actually stored in the db and // add them to the authors list if they are not already there - final catalystId = _getUserCatalystId(); + final catalystId = _userService.activeAccountId; await _proposalRepository.upsertDraftProposal( document: DocumentData( - metadata: DocumentDataMetadata( - type: DocumentType.proposalDocument, + metadata: DocumentDataMetadata.proposal( selfRef: selfRef, - template: template, - categoryId: categoryId, + template: templateRef, + parameters: parameters, authors: [catalystId], ), content: content, @@ -652,6 +654,13 @@ final class ProposalServiceImpl implements ProposalService { ); } + CampaignCategory _findActiveCampaignCategory(DocumentParameters parameters) { + final activeCampaign = _activeCampaignObserver.campaign; + return activeCampaign!.categories.firstWhere( + (category) => parameters.contains(category.selfRef), + ); + } + // Helper method to fetch versions for a proposal Future> _getDetailVersionsOfProposal(ProposalData proposal) async { final versions = await _proposalRepository.queryVersionsOfId( @@ -680,17 +689,6 @@ final class ProposalServiceImpl implements ProposalService { return versionsData.map((e) => e.toProposalVersion()).toList(); } - CatalystId _getUserCatalystId() { - final account = _userService.user.activeAccount; - if (account == null) { - throw StateError( - 'Cannot obtain proposer credentials, account missing', - ); - } - - return account.catalystId; - } - bool _isProposer(User user) { return user.activeAccount?.roles.contains(AccountRole.proposer) ?? false; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/reporting/noop_reporting_service.dart b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/reporting/noop_reporting_service.dart index 4ebafa27b803..e1a0791f3983 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/reporting/noop_reporting_service.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/reporting/noop_reporting_service.dart @@ -4,9 +4,9 @@ import 'dart:async'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_services/catalyst_voices_services.dart'; import 'package:catalyst_voices_services/src/reporting/database_logging_interceptor.dart'; +import 'package:dio/dio.dart' show Dio; import 'package:drift/drift.dart'; import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; final class NoopReportingService implements ReportingService { const NoopReportingService(); @@ -16,15 +16,15 @@ final class NoopReportingService implements ReportingService { return DatabaseLoggingInterceptor(databaseName: databaseName); } - @override - http.Client? buildHttpClient() => null; - @override NavigatorObserver? buildNavigatorObserver() => null; @override Future init({required ReportingServiceConfig config}) async {} + @override + void registerDio(Dio dio) {} + @override Future reportingAs(Account? account) async {} diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/reporting/reporting_service.dart b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/reporting/reporting_service.dart index c31dee32067b..b8fe00e45709 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/reporting/reporting_service.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/reporting/reporting_service.dart @@ -1,23 +1,23 @@ import 'dart:async'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:dio/dio.dart' show Dio; import 'package:drift/drift.dart' show QueryInterceptor; import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; abstract interface class ReportingService { QueryInterceptor? buildDbInterceptor({ required String databaseName, }); - http.Client? buildHttpClient(); - NavigatorObserver? buildNavigatorObserver(); Future init({ required ReportingServiceConfig config, }); + void registerDio(Dio dio); + Future reportingAs(Account? account); R? runZonedGuarded( diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/reporting/sentry_reporting_service.dart b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/reporting/sentry_reporting_service.dart index 2ae99b6b1810..45a8c0118af9 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/reporting/sentry_reporting_service.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/reporting/sentry_reporting_service.dart @@ -2,9 +2,10 @@ import 'dart:async'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_services/src/reporting/reporting_service.dart'; +import 'package:dio/dio.dart' show Dio; import 'package:drift/drift.dart'; import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; +import 'package:sentry_dio/sentry_dio.dart'; import 'package:sentry_drift/sentry_drift.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_logging/sentry_logging.dart'; @@ -17,11 +18,6 @@ final class SentryReportingService implements ReportingService { return SentryQueryInterceptor(databaseName: databaseName); } - @override - http.Client buildHttpClient() { - return SentryHttpClient(); - } - @override NavigatorObserver buildNavigatorObserver() { return SentryNavigatorObserver(); @@ -60,6 +56,9 @@ final class SentryReportingService implements ReportingService { ); } + @override + void registerDio(Dio dio) => dio.addSentry(); + @override Future reportingAs(Account? account) async { assert(Sentry.isEnabled, 'Sentry not enabled'); diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/user/user_service.dart b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/user/user_service.dart index 15d4d8c2f6ef..564ac9ebaed0 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/user/user_service.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/user/user_service.dart @@ -18,6 +18,9 @@ abstract interface class UserService implements ActiveAware { RegistrationStatusPoller registrationStatusPoller, ) = UserServiceImpl; + /// Returns the active account's id from the current [user]. + CatalystId get activeAccountId; + User get user; /// Returns [Account] when keychain is unlocked, otherwise returns `null`. @@ -110,6 +113,18 @@ final class UserServiceImpl implements UserService { this._registrationStatusPoller, ); + @override + CatalystId get activeAccountId { + final account = user.activeAccount; + if (account == null) { + throw StateError( + 'Cannot obtain activeAccountId , account missing', + ); + } + + return account.catalystId; + } + @override bool get isActive => _userObserver.isActive; diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/voting/voting_service.dart b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/voting/voting_service.dart index 052c59d36d0c..1b425d7a81fb 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/voting/voting_service.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_services/lib/src/voting/voting_service.dart @@ -30,7 +30,7 @@ final class VotingMockService implements VotingService { final lastCastedVote = await getProposalLastCastedVote(proposalRef); final category = _cacheCampaign!.categories.firstWhere( - (category) => category.selfRef == proposal.categoryRef, + (category) => proposal.parameters.contains(category.selfRef), orElse: () => throw StateError('Category not found'), ); diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/pubspec.yaml b/catalyst_voices/packages/internal/catalyst_voices_services/pubspec.yaml index 14fd3aec3446..bd646bf67499 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/pubspec.yaml +++ b/catalyst_voices/packages/internal/catalyst_voices_services/pubspec.yaml @@ -22,6 +22,7 @@ dependencies: cbor: 6.3.7 collection: ^1.19.1 cross_file: ^0.3.4+2 + dio: ^5.9.0 downloadsfolder: ^1.1.0 drift: ^2.28.1 equatable: ^2.0.7 @@ -39,6 +40,7 @@ dependencies: pool: ^1.5.1 result_type: ^1.0.0 rxdart: ^0.28.0 + sentry_dio: ^9.6.0 sentry_drift: ^9.6.0 sentry_flutter: ^9.6.0 sentry_logging: ^9.6.0 @@ -53,4 +55,4 @@ dev_dependencies: catalyst_compression: ^1.0.0 mocktail: ^1.0.4 shared_preferences_platform_interface: ^2.4.1 - test: ^1.25.15 + test: ^1.27.0 diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/test/src/proposal/proposal_service_test.dart b/catalyst_voices/packages/internal/catalyst_voices_services/test/src/proposal/proposal_service_test.dart index 99e5461dd041..9448741ae77d 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/test/src/proposal/proposal_service_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_services/test/src/proposal/proposal_service_test.dart @@ -49,7 +49,7 @@ void main() { test('submitProposalForReview throws ' '$ProposalLimitReachedException when over limit', () async { final proposalRef = SignedDocumentRef.generateFirstRef(); - final categoryId = SignedDocumentRef.generateFirstRef(); + final categoryRef = SignedDocumentRef.generateFirstRef(); final catalystId = DummyCatalystIdFactory.create(); final account = Account.dummy( catalystId: catalystId, @@ -72,7 +72,7 @@ void main() { expect( () async => proposalService.submitProposalForReview( proposalRef: proposalRef, - categoryId: categoryId, + proposalParameters: DocumentParameters({categoryRef}), ), throwsA(isA()), ); diff --git a/catalyst_voices/packages/internal/catalyst_voices_services/test/src/user/user_service_test.dart b/catalyst_voices/packages/internal/catalyst_voices_services/test/src/user/user_service_test.dart index 8f16ce1d1599..b97847282182 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_services/test/src/user/user_service_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_services/test/src/user/user_service_test.dart @@ -3,8 +3,7 @@ import 'dart:typed_data'; import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_repositories/catalyst_voices_repositories.dart'; -import 'package:catalyst_voices_repositories/generated/api/cat_gateway.swagger.dart' - show RbacRegistrationChain; +import 'package:catalyst_voices_repositories/src/api/models/rbac_registration_chain.dart'; import 'package:catalyst_voices_services/src/catalyst_voices_services.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; @@ -99,6 +98,7 @@ void main() { expect(currentAccount?.catalystId, account.catalystId); expect(currentAccount?.isActive, isTrue); + expect(service.activeAccountId, equals(account.catalystId)); }); test('when using a new account with the same catalystId ' @@ -130,6 +130,7 @@ void main() { expect(currentAccount, equals(newAccount)); expect(currentAccount, isNot(oldAccount)); + expect(service.activeAccountId, equals(newAccount.catalystId)); }); test('using different account emits update in stream', () async { @@ -366,11 +367,7 @@ void main() { () => userRepository.getRbacRegistration(catalystId: any(named: 'catalystId')), ).thenAnswer( (_) { - const rbac = RbacRegistrationChain( - catalystId: '', - purpose: [], - roles: '', - ); + const rbac = RbacRegistrationChain(catalystId: ''); return Future.value(rbac); }, ); diff --git a/catalyst_voices/packages/internal/catalyst_voices_view_models/lib/src/api/exception/localized_api_exception.dart b/catalyst_voices/packages/internal/catalyst_voices_view_models/lib/src/api/exception/localized_api_exception.dart index 1927c38084cb..c1391de5aa5c 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_view_models/lib/src/api/exception/localized_api_exception.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_view_models/lib/src/api/exception/localized_api_exception.dart @@ -3,6 +3,33 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_view_models/catalyst_voices_view_models.dart'; import 'package:flutter/widgets.dart'; +/// Exception thrown when an API request fails due to a bad certificate, with localization support. +/// +/// This exception is used to indicate that the application was unable to process an API request +/// and provides a localized error message for display in the UI. +final class BadCertificateApiException extends LocalizedApiException { + const BadCertificateApiException(); + + @override + String message(BuildContext context) { + return context.l10n.apiErrorBadCertificate; + } +} + +/// Exception thrown when an API request fails due to a connection error for example by a `xhr.onError` or +/// SocketExceptions, with localization support. +/// +/// This exception is used to indicate that the application was unable to process an API request +/// and provides a localized error message for display in the UI. +final class ConnectionErrorApiException extends LocalizedApiException { + const ConnectionErrorApiException(); + + @override + String message(BuildContext context) { + return context.l10n.apiErrorConnectionError; + } +} + /// Exception thrown when an API request fails with an error response, with localization support. /// /// This exception is used to indicate that the application was unable to process an API request @@ -39,11 +66,18 @@ sealed class LocalizedApiException extends LocalizedException { factory LocalizedApiException.from(ApiException source) { return switch (source) { - ApiErrorResponseException(:final statusCode, :final error) => ErrorResponseException( + ApiBadResponseException(:final statusCode, :final error) => ErrorResponseException( statusCode: statusCode, error: error, ), ApiMalformedBodyException() => const MalformedBodyApiException(), + ApiBadCertificateException() => const BadCertificateApiException(), + ApiConnectionErrorException() => const ConnectionErrorApiException(), + ApiConnectionTimeoutException() || + ApiReceiveTimeoutException() || + ApiSendTimeoutException() => const TimeoutApiException(), + ApiRequestCancelledException() => const RequestCancelledApiException(), + ApiUnknownException() => const UnknownApiException(), }; } } @@ -61,6 +95,32 @@ final class MalformedBodyApiException extends LocalizedApiException { } } +/// Exception thrown when an API request is cancelled, with localization support. +/// +/// This exception is used to indicate that the application was unable to process an API request +/// and provides a localized error message for display in the UI. +final class RequestCancelledApiException extends LocalizedApiException { + const RequestCancelledApiException(); + + @override + String message(BuildContext context) { + return context.l10n.apiErrorRequestCancelled; + } +} + +/// Exception thrown when an API request times out, with localization support. +/// +/// This exception is used to indicate that the application was unable to process an API request +/// and provides a localized error message for display in the UI. +final class TimeoutApiException extends LocalizedApiException { + const TimeoutApiException(); + + @override + String message(BuildContext context) { + return context.l10n.apiErrorTimeout; + } +} + /// Exception thrown when an API request fails with an unknown error, with localization support. /// /// This exception is used to indicate that the application was unable to process an API request diff --git a/catalyst_voices/packages/internal/catalyst_voices_view_models/lib/src/campaign/campaign_category_view_model.dart b/catalyst_voices/packages/internal/catalyst_voices_view_models/lib/src/campaign/campaign_category_view_model.dart index 72e99290d4c6..58e8312b9955 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_view_models/lib/src/campaign/campaign_category_view_model.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_view_models/lib/src/campaign/campaign_category_view_model.dart @@ -25,7 +25,7 @@ final class CampaignCategoryDetailsViewModel extends CampaignCategoryViewModel { final DateTime submissionCloseDate; const CampaignCategoryDetailsViewModel({ - required super.id, + required super.ref, required super.name, required this.subname, required this.description, @@ -42,7 +42,7 @@ final class CampaignCategoryDetailsViewModel extends CampaignCategoryViewModel { }); factory CampaignCategoryDetailsViewModel.dummy({String? id}) => CampaignCategoryDetailsViewModel( - id: SignedDocumentRef(id: id ?? '1)'), + ref: SignedDocumentRef(id: id ?? '1)'), name: 'Cardano Open:', subname: 'Developers', description: @@ -78,7 +78,7 @@ final class CampaignCategoryDetailsViewModel extends CampaignCategoryViewModel { factory CampaignCategoryDetailsViewModel.fromModel(CampaignCategory model) { return CampaignCategoryDetailsViewModel( - id: model.selfRef, + ref: model.selfRef, name: model.categoryName, subname: model.categorySubname, description: model.description, @@ -124,16 +124,16 @@ final class CampaignCategoryDetailsViewModel extends CampaignCategoryViewModel { } final class CampaignCategoryViewModel extends Equatable { - final SignedDocumentRef id; + final SignedDocumentRef ref; final String name; const CampaignCategoryViewModel({ - required this.id, + required this.ref, required this.name, }); @override - List get props => [id, name]; + List get props => [ref, name]; } final class CategoryImageUrl { diff --git a/catalyst_voices/packages/internal/catalyst_voices_view_models/lib/src/proposal/user_proposal_overview.dart b/catalyst_voices/packages/internal/catalyst_voices_view_models/lib/src/proposal/user_proposal_overview.dart index 7192ea137927..44ce4cf8387d 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_view_models/lib/src/proposal/user_proposal_overview.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_view_models/lib/src/proposal/user_proposal_overview.dart @@ -4,6 +4,7 @@ import 'package:equatable/equatable.dart'; final class UsersProposalOverview extends Equatable { final DocumentRef selfRef; + final DocumentParameters parameters; final String title; final DateTime updateDate; final Money fundsRequested; @@ -11,12 +12,12 @@ final class UsersProposalOverview extends Equatable { final List versions; final int commentsCount; final String category; - final SignedDocumentRef categoryId; final int fundNumber; final bool fromActiveCampaign; const UsersProposalOverview({ required this.selfRef, + required this.parameters, required this.title, required this.updateDate, required this.fundsRequested, @@ -24,7 +25,6 @@ final class UsersProposalOverview extends Equatable { required this.versions, required this.commentsCount, required this.category, - required this.categoryId, required this.fundNumber, required this.fromActiveCampaign, }); @@ -37,6 +37,7 @@ final class UsersProposalOverview extends Equatable { }) { return UsersProposalOverview( selfRef: proposal.selfRef, + parameters: proposal.parameters, title: proposal.title, updateDate: proposal.updateDate, fundsRequested: proposal.fundsRequested, @@ -44,7 +45,6 @@ final class UsersProposalOverview extends Equatable { versions: proposal.versions.toViewModels(), commentsCount: proposal.commentsCount, category: categoryName, - categoryId: proposal.categoryRef, fundNumber: fundNumber, fromActiveCampaign: fromActiveCampaign, ); @@ -64,6 +64,7 @@ final class UsersProposalOverview extends Equatable { @override List get props => [ selfRef, + parameters, title, updateDate, fundsRequested, @@ -71,13 +72,13 @@ final class UsersProposalOverview extends Equatable { versions, commentsCount, category, - categoryId, fundNumber, fromActiveCampaign, ]; UsersProposalOverview copyWith({ DocumentRef? selfRef, + DocumentParameters? parameters, String? title, DateTime? updateDate, Money? fundsRequested, @@ -85,12 +86,12 @@ final class UsersProposalOverview extends Equatable { List? versions, int? commentsCount, String? category, - SignedDocumentRef? categoryId, int? fundNumber, bool? fromActiveCampaign, }) { return UsersProposalOverview( selfRef: selfRef ?? this.selfRef, + parameters: parameters ?? this.parameters, title: title ?? this.title, updateDate: updateDate ?? this.updateDate, fundsRequested: fundsRequested ?? this.fundsRequested, @@ -98,7 +99,6 @@ final class UsersProposalOverview extends Equatable { versions: versions ?? this.versions, commentsCount: commentsCount ?? this.commentsCount, category: category ?? this.category, - categoryId: categoryId ?? this.categoryId, fundNumber: fundNumber ?? this.fundNumber, fromActiveCampaign: fromActiveCampaign ?? this.fromActiveCampaign, ); diff --git a/catalyst_voices/packages/internal/catalyst_voices_view_models/pubspec.yaml b/catalyst_voices/packages/internal/catalyst_voices_view_models/pubspec.yaml index 230b1aa6599b..ab305b61e420 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_view_models/pubspec.yaml +++ b/catalyst_voices/packages/internal/catalyst_voices_view_models/pubspec.yaml @@ -36,4 +36,4 @@ dev_dependencies: catalyst_analysis: ^3.0.0 flutter_test: sdk: flutter - test: ^1.25.15 + test: ^1.27.0 diff --git a/catalyst_voices/packages/libs/catalyst_cardano/catalyst_cardano/example/pubspec.yaml b/catalyst_voices/packages/libs/catalyst_cardano/catalyst_cardano/example/pubspec.yaml index 423840f0776b..ce8d92b9448f 100644 --- a/catalyst_voices/packages/libs/catalyst_cardano/catalyst_cardano/example/pubspec.yaml +++ b/catalyst_voices/packages/libs/catalyst_cardano/catalyst_cardano/example/pubspec.yaml @@ -23,7 +23,7 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: ^1.25.7 + test: ^1.27.0 web: ^1.1.1 webdriver: ^3.1.0 diff --git a/catalyst_voices/packages/libs/catalyst_cardano_serialization/lib/src/rbac/x509_certificate.dart b/catalyst_voices/packages/libs/catalyst_cardano_serialization/lib/src/rbac/x509_certificate.dart index 35bca2632495..b4e71d018749 100644 --- a/catalyst_voices/packages/libs/catalyst_cardano_serialization/lib/src/rbac/x509_certificate.dart +++ b/catalyst_voices/packages/libs/catalyst_cardano_serialization/lib/src/rbac/x509_certificate.dart @@ -61,6 +61,14 @@ class X509Certificate with EquatableMixin { return X509Certificate.fromASN1(asn1); } + /// Decodes the [X509Certificate] from PEM format string. + factory X509Certificate.fromPem(String pem) { + final pemData = extractBase64FromPem(pem); + final certificateBytes = base64Decode(pemData); + final derCertificate = X509DerCertificate.fromBytes(bytes: certificateBytes); + return X509Certificate.fromDer(derCertificate); + } + @override List get props => [tbsCertificate, signature]; @@ -91,6 +99,20 @@ class X509Certificate with EquatableMixin { '-----END $label-----'; } + /// Extracts Base64 data from PEM format by removing formatting elements. + /// + /// Removes the following: + /// - `-----BEGIN [LABEL]-----` headers (e.g., `-----BEGIN CERTIFICATE-----`) + /// - `-----END [LABEL]-----` footers (e.g., `-----END CERTIFICATE-----`) + /// - `-----BEGIN-----` headers without labels + /// - `-----END-----` footers without labels + /// - All whitespace characters (spaces, tabs, newlines, carriage returns) + /// + /// Returns the raw Base64-encoded string without any formatting. + static String extractBase64FromPem(String pem) { + return pem.replaceAll(RegExp(r'-----(?:BEGIN|END)\s*[^-]*-----|\s+'), ''); + } + /// Generates a self-signed [X509Certificate] from [tbsCertificate] /// that is signed using the [privateKey]. static Future generateSelfSigned({ diff --git a/catalyst_voices/packages/libs/catalyst_cardano_serialization/pubspec.yaml b/catalyst_voices/packages/libs/catalyst_cardano_serialization/pubspec.yaml index 4ad16729e685..f01a5c8eed58 100644 --- a/catalyst_voices/packages/libs/catalyst_cardano_serialization/pubspec.yaml +++ b/catalyst_voices/packages/libs/catalyst_cardano_serialization/pubspec.yaml @@ -28,10 +28,10 @@ dependencies: uuid_plus: ^0.1.0 dev_dependencies: - build_runner: ^2.5.4 + build_runner: ^2.10.3 catalyst_analysis: ^3.0.0 flutter_test: sdk: flutter kiri_check: ^1.3.0 mocktail: ^1.0.4 - test: ^1.25.15 + test: ^1.27.0 diff --git a/catalyst_voices/packages/libs/catalyst_cardano_serialization/test/rbac/x509_certificate_test.dart b/catalyst_voices/packages/libs/catalyst_cardano_serialization/test/rbac/x509_certificate_test.dart index 5a228fdf5ef6..bd2e43b65fd4 100644 --- a/catalyst_voices/packages/libs/catalyst_cardano_serialization/test/rbac/x509_certificate_test.dart +++ b/catalyst_voices/packages/libs/catalyst_cardano_serialization/test/rbac/x509_certificate_test.dart @@ -63,7 +63,134 @@ void main() { final derCertificate = certificate.toDer(); final decodedCertificate = X509Certificate.fromDer(derCertificate); - expect(decodedCertificate, equals(decodedCertificate)); + expect(decodedCertificate, equals(certificate)); + }); + + test('fromPem decodes PEM certificate correctly', () async { + final certificate = await X509Certificate.generateSelfSigned( + tbsCertificate: tbs, + privateKey: privateKey, + ); + + final pem = certificate.toPem(); + final decodedCertificate = X509Certificate.fromPem(pem); + + expect(decodedCertificate, equals(certificate)); + }); + + test('fromPem handles custom label', () async { + final certificate = await X509Certificate.generateSelfSigned( + tbsCertificate: tbs, + privateKey: privateKey, + ); + + final pem = certificate.toPem('CUSTOM LABEL'); + final decodedCertificate = X509Certificate.fromPem(pem); + + expect(decodedCertificate, equals(certificate)); + }); + + test('fromPem handles whitespace variations', () async { + final certificate = await X509Certificate.generateSelfSigned( + tbsCertificate: tbs, + privateKey: privateKey, + ); + + final normalPem = certificate.toPem(); + final pemWithWhitespace = normalPem.replaceAll('\n', '\n\t '); + final decodedCertificate = X509Certificate.fromPem(pemWithWhitespace); + + expect(decodedCertificate, equals(certificate)); + }); + + test('extractBase64FromPem removes header and footer', () { + /* cSpell:disable */ + const pem = ''' +-----BEGIN CERTIFICATE----- +MIIB/DCCAa6gAwIBAgIFAI0AzRIwBQYDK2VwMEIxCTAHBgNVBAYTADEJMAcGA1UE +-----END CERTIFICATE----- +'''; + + final base64 = X509Certificate.extractBase64FromPem(pem); + + expect(base64, isNot(contains('-----BEGIN'))); + expect(base64, isNot(contains('-----END'))); + expect(base64, isNot(contains('CERTIFICATE'))); + expect(base64, isNot(contains('\n'))); + expect(base64, isNot(contains(' '))); + expect(base64, equals('MIIB/DCCAa6gAwIBAgIFAI0AzRIwBQYDK2VwMEIxCTAHBgNVBAYTADEJMAcGA1UE')); + /* cSpell:enable */ + }); + + test('extractBase64FromPem handles custom label', () { + /* cSpell:disable */ + const pem = ''' +-----BEGIN CUSTOM LABEL----- +MIIB/DCCAa6gAwIBAgIFAI0AzRIwBQYDK2VwMEIxCTAHBgNVBAYTADEJMAcGA1UE +-----END CUSTOM LABEL----- +'''; + + final base64 = X509Certificate.extractBase64FromPem(pem); + + expect(base64, equals('MIIB/DCCAa6gAwIBAgIFAI0AzRIwBQYDK2VwMEIxCTAHBgNVBAYTADEJMAcGA1UE')); + /* cSpell:enable */ + }); + + test('extractBase64FromPem handles label without spaces', () { + /* cSpell:disable */ + const pem = ''' +-----BEGIN----- +MIIB/DCCAa6gAwIBAgIFAI0AzRIwBQYDK2VwMEIxCTAHBgNVBAYTADEJMAcGA1UE +-----END----- +'''; + + final base64 = X509Certificate.extractBase64FromPem(pem); + + expect(base64, equals('MIIB/DCCAa6gAwIBAgIFAI0AzRIwBQYDK2VwMEIxCTAHBgNVBAYTADEJMAcGA1UE')); + /* cSpell:enable */ + }); + + test('extractBase64FromPem removes all whitespace types', () { + /* cSpell:disable */ + const pem = ''' +-----BEGIN CERTIFICATE----- +MIIB /DCC Aa6g +AwIB AgIF\tAI0A +-----END CERTIFICATE----- +'''; + + final base64 = X509Certificate.extractBase64FromPem(pem); + + expect(base64, equals('MIIB/DCCAa6gAwIBAgIFAI0A')); + expect(base64, isNot(contains(' '))); + expect(base64, isNot(contains('\t'))); + expect(base64, isNot(contains('\n'))); + /* cSpell:enable */ + }); + + test('extractBase64FromPem handles multiple newlines', () { + /* cSpell:disable */ + const pem = ''' +-----BEGIN CERTIFICATE----- + + +MIIB/DCCAa6g + + +AwIBAgIFAI0A +zRIwBQYDK2Vw +MEIxCTAHBgNV +BAYTADEJMAcG + +A1UE + +-----END CERTIFICATE----- +'''; + + final base64 = X509Certificate.extractBase64FromPem(pem); + + expect(base64, equals('MIIB/DCCAa6gAwIBAgIFAI0AzRIwBQYDK2VwMEIxCTAHBgNVBAYTADEJMAcGA1UE')); + /* cSpell:enable */ }); }); } diff --git a/catalyst_voices/packages/libs/catalyst_compression/.earthlyignore b/catalyst_voices/packages/libs/catalyst_compression/.earthlyignore index 0a9505a3048c..cdd029968109 100644 --- a/catalyst_voices/packages/libs/catalyst_compression/.earthlyignore +++ b/catalyst_voices/packages/libs/catalyst_compression/.earthlyignore @@ -16,15 +16,10 @@ # Generated files from code generation tools **/*.g.dart **/*.freezed.dart -**/*.chopper.dart -**/*.swagger.dart -**/*.openapi.dart **/*.gen.dart -**/*.swagger.*.dart **/*.drift.dart -**/openapi/processed/ -**/catalyst_voices_localizations_*.dart -**/catalyst_voices_localizations.dart +**/generated/catalyst_voices_localizations_*.dart +**/generated/catalyst_voices_localizations.dart # node related diff --git a/catalyst_voices/packages/libs/catalyst_compression/cargokit/build_tool/pubspec.yaml b/catalyst_voices/packages/libs/catalyst_compression/cargokit/build_tool/pubspec.yaml index 18c61e3386a6..14ba75ab7554 100644 --- a/catalyst_voices/packages/libs/catalyst_compression/cargokit/build_tool/pubspec.yaml +++ b/catalyst_voices/packages/libs/catalyst_compression/cargokit/build_tool/pubspec.yaml @@ -30,4 +30,4 @@ dependencies: dev_dependencies: lints: ^2.1.0 - test: ^1.24.0 + test: ^1.27.0 diff --git a/catalyst_voices/packages/libs/catalyst_compression/pubspec.yaml b/catalyst_voices/packages/libs/catalyst_compression/pubspec.yaml index f4f850e52e20..4c38e28109aa 100644 --- a/catalyst_voices/packages/libs/catalyst_compression/pubspec.yaml +++ b/catalyst_voices/packages/libs/catalyst_compression/pubspec.yaml @@ -28,7 +28,7 @@ dev_dependencies: ffigen: ^11.0.0 flutter_test: sdk: flutter - test: ^1.25.15 + test: ^1.27.0 flutter: plugin: diff --git a/catalyst_voices/packages/libs/catalyst_cose/README.md b/catalyst_voices/packages/libs/catalyst_cose/README.md index 3b7f365a371f..1c1da8336e17 100644 --- a/catalyst_voices/packages/libs/catalyst_cose/README.md +++ b/catalyst_voices/packages/libs/catalyst_cose/README.md @@ -15,6 +15,9 @@ This package exposes a CBOR Object Signing and Encryption [RFC-9052](https://datatracker.ietf.org/doc/html/rfc9052), [RFC-9053](https://datatracker.ietf.org/doc/html/rfc9053) implementation. +Implements Signed Doc spec +[v0.0.4](https://github.com/input-output-hk/catalyst-libs/pull/341/files#diff-2827956d681587dfd09dc733aca731165ff44812f8322792bf6c4a61cf2d3b85). + ## Requirements * Dart: 3.9.0+ diff --git a/catalyst_voices/packages/libs/catalyst_cose/example/main.dart b/catalyst_voices/packages/libs/catalyst_cose/example/main.dart index b040536070bb..7060ba2d6ed8 100644 --- a/catalyst_voices/packages/libs/catalyst_cose/example/main.dart +++ b/catalyst_voices/packages/libs/catalyst_cose/example/main.dart @@ -74,12 +74,12 @@ final class _SignerVerifier implements CatalystCoseSigner, CatalystCoseVerifier const _SignerVerifier(this._algorithm, this._keyPair); @override - StringOrInt? get alg => const IntValue(CoseValues.eddsaAlg); + CoseStringOrInt? get alg => const CoseIntValue(CoseValues.eddsaAlg); @override - Future get kid async { + Future get kid async { final pk = await _keyPair.extractPublicKey(); - return Uint8List.fromList(pk.bytes); + return CatalystIdKid(Uint8List.fromList(pk.bytes)); } @override diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/catalyst_cose.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/catalyst_cose.dart index 5b124e4669eb..6558d20de550 100644 --- a/catalyst_voices/packages/libs/catalyst_cose/lib/catalyst_cose.dart +++ b/catalyst_voices/packages/libs/catalyst_cose/lib/catalyst_cose.dart @@ -1,6 +1,11 @@ export 'src/cose_constants.dart'; export 'src/cose_sign.dart'; export 'src/cose_sign1.dart'; +export 'src/exception/cose_format_exception.dart'; +export 'src/types/cose_custom_types.dart'; +export 'src/types/cose_document_ref.dart'; export 'src/types/cose_headers.dart'; -export 'src/types/string_or_int.dart'; -export 'src/types/uuid.dart'; +export 'src/types/cose_http_content_encoding.dart'; +export 'src/types/cose_media_type.dart'; +export 'src/types/cose_string_or_int.dart'; +export 'src/types/cose_uuid.dart'; diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/src/cose_constants.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/src/cose_constants.dart index ea415c2022ab..ba38b76b5840 100644 --- a/catalyst_voices/packages/libs/catalyst_cose/lib/src/cose_constants.dart +++ b/catalyst_voices/packages/libs/catalyst_cose/lib/src/cose_constants.dart @@ -1,6 +1,7 @@ import 'dart:typed_data'; -import 'package:catalyst_cose/src/types/string_or_int.dart'; +import 'package:catalyst_cose/src/types/cose_custom_types.dart'; +import 'package:catalyst_cose/src/types/cose_string_or_int.dart'; import 'package:cbor/cbor.dart'; /// The interface for the data signer callback. @@ -8,11 +9,11 @@ import 'package:cbor/cbor.dart'; abstract interface class CatalystCoseSigner { /// Returns the alg identifier that should refer /// to the cryptographic algorithm used to [sign] the data. - StringOrInt? get alg; + CoseStringOrInt? get alg; /// Returns a key identifier that typically should refer to the public key /// of the private key used to sign the data. - Future get kid; + Future get kid; /// The [data] should be signed with a private key /// and the resulting signature returned as [Uint8List]. @@ -24,7 +25,7 @@ abstract interface class CatalystCoseSigner { abstract interface class CatalystCoseVerifier { /// Returns a key identifier that typically should refer to the public key /// of the private key used to sign the data. - Future get kid; + Future get kid; /// The [signature] should be verified against /// a known public/private key over the [data]. @@ -36,8 +37,8 @@ final class CoseHeaderKeys { /// The header key describing the signature algorithm. static const alg = CborSmallInt(1); - /// The header key describing the content-type of the payload. - static const contentType = CborSmallInt(3); + /// The header key describing the media-type of the payload. + static const mediaType = CborSmallInt(3); /// The header key describing the key identifier. static const kid = CborSmallInt(4); @@ -57,9 +58,6 @@ final class CoseHeaderKeys { /// The header key for "ref". static final ref = CborString('ref'); - /// The header key for "ref_hash". - static final refHash = CborString('ref_hash'); - /// The header key for "template". static final template = CborString('template'); @@ -70,20 +68,35 @@ final class CoseHeaderKeys { static final section = CborString('section'); /// The header key for "collabs". + /// + /// Replaced by [collaborators]. static final collabs = CborString('collabs'); + /// The header key for "collaborators". + /// + /// Replaces [collabs]. + static final collaborators = CborString('collaborators'); + /// The header key for "brand_id". + /// + /// Replaced by [parameters]. static final brandId = CborString('brand_id'); /// The header key for "campaign_id". + /// + /// Replaced by [parameters]. static final campaignId = CborString('campaign_id'); - /// The header key for "election_id". - static final electionId = CborString('election_id'); - /// The header key for "category_id". + /// + /// Replaced by [parameters]. static final categoryId = CborString('category_id'); + /// The header key for "parameters". + /// + /// Replaces [brandId], [campaignId], [categoryId]. + static final parameters = CborString('parameters'); + const CoseHeaderKeys._(); } @@ -103,9 +116,6 @@ final class CoseValues { /// The Edwards-Curve Digital Signature Algorithm (EdDSA). static const eddsaAlg = -8; - /// The json content type value. - static const jsonContentType = 50; - /// The brotli compression content encoding. static const brotliContentEncoding = 'br'; diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/src/cose_sign.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/src/cose_sign.dart index 108e7b660c04..c2971d7d3c7e 100644 --- a/catalyst_voices/packages/libs/catalyst_cose/lib/src/cose_sign.dart +++ b/catalyst_voices/packages/libs/catalyst_cose/lib/src/cose_sign.dart @@ -1,6 +1,7 @@ import 'dart:typed_data'; import 'package:catalyst_cose/src/cose_constants.dart'; +import 'package:catalyst_cose/src/exception/cose_format_exception.dart'; import 'package:catalyst_cose/src/types/cose_headers.dart'; import 'package:cbor/cbor.dart'; import 'package:collection/collection.dart'; @@ -36,7 +37,7 @@ final class CoseSign extends Equatable { /// Deserializes the type from cbor. factory CoseSign.fromCbor(CborValue value) { if (value is! CborList || value.length != 4) { - throw FormatException('$value is not a valid COSE_SIGN structure'); + throw CoseFormatException('$value is not a valid COSE_SIGN structure'); } final protectedHeaders = value[0]; @@ -133,12 +134,6 @@ final class CoseSign extends Equatable { required Uint8List payload, required List signers, }) async { - // TODO(dt-iohk): remove when server stops - // requiring alg header in body protected headers. - protectedHeaders = protectedHeaders.copyWith( - alg: () => signers.firstOrNull?.alg, - ); - final signatures = []; for (final signer in signers) { final signatureProtectedHeaders = CoseHeaders.protected( diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/src/cose_sign1.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/src/cose_sign1.dart index 29de1d158198..59225870ecf4 100644 --- a/catalyst_voices/packages/libs/catalyst_cose/lib/src/cose_sign1.dart +++ b/catalyst_voices/packages/libs/catalyst_cose/lib/src/cose_sign1.dart @@ -1,6 +1,7 @@ import 'dart:typed_data'; import 'package:catalyst_cose/src/cose_constants.dart'; +import 'package:catalyst_cose/src/exception/cose_format_exception.dart'; import 'package:catalyst_cose/src/types/cose_headers.dart'; import 'package:cbor/cbor.dart'; import 'package:equatable/equatable.dart'; @@ -33,7 +34,7 @@ final class CoseSign1 extends Equatable { /// Deserializes the type from cbor. factory CoseSign1.fromCbor(CborValue value) { if (value is! CborList || value.length != 4) { - throw FormatException('$value is not a valid COSE_SIGN1 structure'); + throw CoseFormatException('$value is not a valid COSE_SIGN1 structure'); } final protectedHeaders = value[0]; diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/src/exception/cose_format_exception.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/src/exception/cose_format_exception.dart new file mode 100644 index 000000000000..aa003a000175 --- /dev/null +++ b/catalyst_voices/packages/libs/catalyst_cose/lib/src/exception/cose_format_exception.dart @@ -0,0 +1,16 @@ +import 'package:equatable/equatable.dart'; + +/// Exception for invalid cose format detected. +final class CoseFormatException extends Equatable implements Exception { + /// The exception details, human readable. + final String message; + + /// The default constructor for the [CoseFormatException]. + const CoseFormatException(this.message); + + @override + List get props => [message]; + + @override + String toString() => message; +} diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_custom_types.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_custom_types.dart new file mode 100644 index 000000000000..87c25aae8710 --- /dev/null +++ b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_custom_types.dart @@ -0,0 +1,88 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:catalyst_cose/src/types/cose_uuid.dart'; +import 'package:cbor/cbor.dart'; + +/// UTF-8 Catalyst ID URI encoded as a bytes string. +extension type const CatalystIdKid(Uint8List bytes) { + /// Deserializes the type from cbor. + factory CatalystIdKid.fromCbor(CborValue value) { + return CatalystIdKid(Uint8List.fromList((value as CborBytes).bytes)); + } + + /// Creates a new [CatalystIdKid] from [string]. + factory CatalystIdKid.fromString(String string) { + return CatalystIdKid(utf8.encode(string)); + } + + /// Serializes the type as cbor. + CborValue toCbor() => CborBytes(bytes); +} + +/// Allowed Collaborators on the next subsequent version of a document. +extension type const CoseCollaborators(List list) { + /// Deserializes the type from cbor. + factory CoseCollaborators.fromCbor(CborValue value) { + final list = value as CborList; + return CoseCollaborators(list.map(CatalystIdKid.fromCbor).toList()); + } + + /// Serializes the type as cbor. + CborValue toCbor() { + return CborList(list.map((e) => e.toCbor()).toList()); + } +} + +/// Document ID. +extension type const CoseDocumentId(CoseUuidV7 value) { + /// Deserializes the type from cbor. + factory CoseDocumentId.fromCbor(CborValue value) { + return CoseDocumentId(CoseUuidV7.fromCbor(value)); + } + + /// Serializes the type as cbor. + CborValue toCbor() => value.toCbor(); +} + +/// Document Type. +extension type const CoseDocumentType(CoseUuidV4 value) { + /// Deserializes the type from cbor. + factory CoseDocumentType.fromCbor(CborValue value) { + return CoseDocumentType(CoseUuidV4.fromCbor(value)); + } + + /// Serializes the type as cbor. + CborValue toCbor() => value.toCbor(); +} + +/// Document Version. +extension type const CoseDocumentVer(CoseUuidV7 value) { + /// Deserializes the type from cbor. + factory CoseDocumentVer.fromCbor(CborValue value) { + return CoseDocumentVer(CoseUuidV7.fromCbor(value)); + } + + /// Serializes the type as cbor. + CborValue toCbor() { + return value.toCbor(); + } +} + +/// RFC6901 Standard JSON Pointer +extension type const CoseJsonPointer(String text) { + /// Deserializes the type from cbor. + CoseJsonPointer.fromCbor(CborValue value) : this(((value as CborString).toString())); + + /// Serializes the type as cbor. + CborValue toCbor() => CborString(text); +} + +/// Reference to a section in a referenced document. +extension type const CoseSectionRef(CoseJsonPointer value) { + /// Deserializes the type from cbor. + CoseSectionRef.fromCbor(CborValue value) : this(CoseJsonPointer.fromCbor(value)); + + /// Serializes the type as cbor. + CborValue toCbor() => value.toCbor(); +} diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_document_ref.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_document_ref.dart new file mode 100644 index 000000000000..a71f4c192d17 --- /dev/null +++ b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_document_ref.dart @@ -0,0 +1,159 @@ +import 'dart:typed_data'; + +import 'package:catalyst_cose/src/exception/cose_format_exception.dart'; +import 'package:catalyst_cose/src/types/cose_uuid.dart'; +import 'package:catalyst_cose/src/utils/cbor_utils.dart'; +import 'package:cbor/cbor.dart'; +import 'package:equatable/equatable.dart'; + +/// Where a document can be located, must be a unique identifier. +final class CoseDocumentLocator extends Equatable { + /// IPLD content identifier. + final Uint8List cid; + + /// The default constructor for the [CoseDocumentLocator]. + const CoseDocumentLocator({required this.cid}); + + /// A constructor with default values for [CoseDocumentLocator]. + CoseDocumentLocator.fallback() : this(cid: Uint8List(0)); + + /// Deserializes the type from cbor. + factory CoseDocumentLocator.fromCbor(CborValue value) { + final map = value as CborMap; + final cid = map[CborString('cid')]! as CborBytes; + + return CoseDocumentLocator(cid: Uint8List.fromList(cid.bytes)); + } + + @override + List get props => [cid]; + + /// Serializes the type as cbor. + CborValue toCbor() { + return CborMap({ + CborString('cid'): CborBytes(cid, tags: [CborUtils.cidTag]), + }); + } +} + +/// Reference to a single Signed Document. +final class CoseDocumentRef extends Equatable { + /// A document id. + final CoseUuidV7 documentId; + + /// A document version. + /// + /// If the document doesn't have any versions then [documentVer] == [documentId]. + final CoseUuidV7 documentVer; + + /// Where a document can be located, must be a unique identifier. + final CoseDocumentLocator documentLocator; + + /// A latest spec version of the [CoseDocumentRef] constructor. + const CoseDocumentRef({ + required CoseUuidV7 documentId, + required CoseUuidV7 documentVer, + required CoseDocumentLocator documentLocator, + }) : this._( + documentId: documentId, + documentVer: documentVer, + documentLocator: documentLocator, + ); + + /// Deserializes the type from cbor. + factory CoseDocumentRef.fromCbor(CborValue value) { + if (value is! CborList) { + return CoseDocumentRef.optional( + documentId: CoseUuidV7.fromCbor(value), + ); + } else { + final documentId = value.elementAtOrNull(0)!; + final documentVer = value.elementAtOrNull(1); + final documentLocator = value.elementAtOrNull(2); + + return CoseDocumentRef.optional( + documentId: CoseUuidV7.fromCbor(documentId), + documentVer: documentVer != null ? CoseUuidV7.fromCbor(documentVer) : null, + documentLocator: documentLocator != null + ? CoseDocumentLocator.fromCbor(documentLocator) + : null, + ); + } + } + + /// A constructor for [CoseDocumentRef] which assigns default, backward compatible values. + CoseDocumentRef.optional({ + required CoseUuidV7 documentId, + CoseUuidV7? documentVer, + CoseDocumentLocator? documentLocator, + }) : this._( + documentId: documentId, + documentVer: documentVer ?? documentId, + documentLocator: documentLocator ?? CoseDocumentLocator.fallback(), + ); + + const CoseDocumentRef._({ + required this.documentId, + required this.documentVer, + required this.documentLocator, + }); + + @override + List get props => [documentId, documentVer, documentLocator]; + + /// Serializes the type as cbor. + CborValue toCbor() { + return CborList([ + documentId.toCbor(), + documentVer.toCbor(), + documentLocator.toCbor(), + ]); + } +} + +/// A reference to the Parameters Document this document lies under. +extension type const CoseDocumentRefs._(List refs) { + /// The default constructor for the [CoseDocumentRefs]. + factory CoseDocumentRefs(List refs) { + if (refs.isEmpty) { + throw const CoseFormatException('CoseDocumentRefs must contain at least one item'); + } + + return CoseDocumentRefs._(refs); + } + + /// Deserializes the type from cbor. + factory CoseDocumentRefs.fromCbor(CborValue value) { + value = _migrateCbor1(value); + value = _migrateCbor2(value); + + final list = value as CborList; + return CoseDocumentRefs(list.map(CoseDocumentRef.fromCbor).toList()); + } + + /// Serializes the type as cbor. + CborValue toCbor() { + return CborList(refs.map((e) => e.toCbor()).toList()); + } + + /// Pre v0.0.1 spec, the document ref was just a string representing the documentId, not documented. + static CborValue _migrateCbor1(CborValue value) { + if (value is CborBytes) { + final documentId = CoseUuidV7.fromCbor(value); + + return CoseDocumentRef.optional(documentId: documentId).toCbor(); + } + + return value; + } + + /// v0.0.1 -> v0.0.4 spec: https://github.com/input-output-hk/catalyst-libs/pull/341/files#diff-2827956d681587dfd09dc733aca731165ff44812f8322792bf6c4a61cf2d3b85 + static CborValue _migrateCbor2(CborValue value) { + if (value is CborList && value.firstOrNull is CborBytes) { + final documentRef = CoseDocumentRef.fromCbor(value); + return CoseDocumentRefs([documentRef]).toCbor(); + } + + return value; + } +} diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_headers.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_headers.dart index 705255902059..e4163db06db7 100644 --- a/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_headers.dart +++ b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_headers.dart @@ -1,10 +1,7 @@ -import 'dart:typed_data'; - -import 'package:catalyst_cose/src/cose_constants.dart'; -import 'package:catalyst_cose/src/types/string_or_int.dart'; -import 'package:catalyst_cose/src/types/uuid.dart'; +import 'package:catalyst_cose/catalyst_cose.dart'; import 'package:catalyst_cose/src/utils/cbor_utils.dart'; import 'package:cbor/cbor.dart'; +import 'package:collection/collection.dart'; import 'package:equatable/equatable.dart'; /// A callback to get an optional value. @@ -21,58 +18,53 @@ final class CoseHeaders extends Equatable { /// /// Do not set the [alg] directly in the headers, /// it will be auto-populated with [CatalystCoseSigner.alg] value. - final StringOrInt? alg; + final CoseStringOrInt? alg; /// See [CoseHeaderKeys.kid]. /// /// Do not set the [kid] directly in the headers, /// it will be auto-populated with [CatalystCoseSigner.kid] value. - final Uint8List? kid; + final CatalystIdKid? kid; - /// See [CoseHeaderKeys.contentType]. - final StringOrInt? contentType; + /// See [CoseHeaderKeys.mediaType]. + final CoseMediaType? mediaType; /// See [CoseHeaderKeys.contentEncoding]. - final StringOrInt? contentEncoding; + final CoseHttpContentEncoding? contentEncoding; /// See [CoseHeaderKeys.type]. - final Uuid? type; + final CoseDocumentType? type; /// See [CoseHeaderKeys.id]. - final Uuid? id; + final CoseDocumentId? id; /// See [CoseHeaderKeys.ver]. - final Uuid? ver; + final CoseDocumentVer? ver; /// See [CoseHeaderKeys.ref]. - final ReferenceUuid? ref; - - /// See [CoseHeaderKeys.refHash]. - final ReferenceUuidHash? refHash; + final CoseDocumentRefs? ref; /// See [CoseHeaderKeys.template]. - final ReferenceUuid? template; + final CoseDocumentRefs? template; /// See [CoseHeaderKeys.reply]. - final ReferenceUuid? reply; + final CoseDocumentRefs? reply; /// See [CoseHeaderKeys.section]. - final String? section; - - /// See [CoseHeaderKeys.collabs]. - final List? collabs; - - /// See [CoseHeaderKeys.brandId]. - final ReferenceUuid? brandId; - - /// See [CoseHeaderKeys.campaignId]. - final ReferenceUuid? campaignId; + final CoseSectionRef? section; - /// See [CoseHeaderKeys.electionId]. - final String? electionId; + /// See [CoseHeaderKeys.collaborators]. + /// + /// Replaces the old [CoseHeaderKeys.collabs] key. + final CoseCollaborators? collaborators; - /// See [CoseHeaderKeys.categoryId]. - final ReferenceUuid? categoryId; + /// See [CoseHeaderKeys.parameters]. + /// + /// Replaces: + /// - [CoseHeaderKeys.brandId] + /// - [CoseHeaderKeys.campaignId] + /// - [CoseHeaderKeys.categoryId] + final CoseDocumentRefs? parameters; /// Whether the type should be wrapped in extra [CborBytes] /// or be a plain [CborMap], both formats are supported. @@ -85,56 +77,42 @@ final class CoseHeaders extends Equatable { const CoseHeaders({ this.alg, this.kid, - this.contentType, + this.mediaType, this.contentEncoding, this.type, this.id, this.ver, this.ref, - this.refHash, this.template, this.reply, this.section, - this.collabs, - this.brandId, - this.campaignId, - this.electionId, - this.categoryId, + this.collaborators, + this.parameters, required this.encodeAsBytes, }); /// Deserializes the type from cbor. factory CoseHeaders.fromCbor(CborValue value, {bool encodeAsBytes = true}) { - final CborMap map; - - if (value is CborMap) { - // cose headers per specification might be wrapped in extra CborBytes, - // both formats are valid - map = value; - } else { - final cborBytes = value as CborBytes; - final encodedMap = cbor.decode(cborBytes.bytes); - map = encodedMap as CborMap; - } + var map = _decodeCbor(value); + map = _migrateCbor1(map); + map = _migrateCbor2(map); return CoseHeaders( alg: CborUtils.deserializeStringOrInt(map[CoseHeaderKeys.alg]), - kid: CborUtils.deserializeBytes(map[CoseHeaderKeys.kid]), - contentType: CborUtils.deserializeStringOrInt(map[CoseHeaderKeys.contentType]), - contentEncoding: CborUtils.deserializeStringOrInt(map[CoseHeaderKeys.contentEncoding]), - type: CborUtils.deserializeUuid(map[CoseHeaderKeys.type]), - id: CborUtils.deserializeUuid(map[CoseHeaderKeys.id]), - ver: CborUtils.deserializeUuid(map[CoseHeaderKeys.ver]), - ref: CborUtils.deserializeReferenceUuid(map[CoseHeaderKeys.ref]), - refHash: CborUtils.deserializeReferenceUuidHash(map[CoseHeaderKeys.refHash]), - template: CborUtils.deserializeReferenceUuid(map[CoseHeaderKeys.template]), - reply: CborUtils.deserializeReferenceUuid(map[CoseHeaderKeys.reply]), - section: CborUtils.deserializeString(map[CoseHeaderKeys.section]), - collabs: CborUtils.deserializeStringList(map[CoseHeaderKeys.collabs]), - brandId: CborUtils.deserializeReferenceUuid(map[CoseHeaderKeys.brandId]), - campaignId: CborUtils.deserializeReferenceUuid(map[CoseHeaderKeys.campaignId]), - electionId: CborUtils.deserializeString(map[CoseHeaderKeys.electionId]), - categoryId: CborUtils.deserializeReferenceUuid(map[CoseHeaderKeys.categoryId]), + kid: CborUtils.deserializeKid(map[CoseHeaderKeys.kid]), + mediaType: CborUtils.deserializeMediaType(map[CoseHeaderKeys.mediaType]), + contentEncoding: CborUtils.deserializeHttpContentEncoding( + map[CoseHeaderKeys.contentEncoding], + ), + type: CborUtils.deserializeDocumentType(map[CoseHeaderKeys.type]), + id: CborUtils.deserializeDocumentId(map[CoseHeaderKeys.id]), + ver: CborUtils.deserializeDocumentVer(map[CoseHeaderKeys.ver]), + ref: CborUtils.deserializeDocumentRefs(map[CoseHeaderKeys.ref]), + template: CborUtils.deserializeDocumentRefs(map[CoseHeaderKeys.template]), + reply: CborUtils.deserializeDocumentRefs(map[CoseHeaderKeys.reply]), + section: CborUtils.deserializeSectionRef(map[CoseHeaderKeys.section]), + collaborators: CborUtils.deserializeCollaborators(map[CoseHeaderKeys.collaborators]), + parameters: CborUtils.deserializeDocumentRefs(map[CoseHeaderKeys.parameters]), encodeAsBytes: encodeAsBytes, ); } @@ -143,105 +121,85 @@ final class CoseHeaders extends Equatable { const CoseHeaders.protected({ this.alg, this.kid, - this.contentType, + this.mediaType, this.contentEncoding, this.type, this.id, this.ver, this.ref, - this.refHash, this.template, this.reply, this.section, - this.collabs, - this.brandId, - this.campaignId, - this.electionId, - this.categoryId, + this.collaborators, + this.parameters, }) : encodeAsBytes = true; /// The constructor for the unprotected [CoseHeaders]. const CoseHeaders.unprotected({ this.alg, this.kid, - this.contentType, + this.mediaType, this.contentEncoding, this.type, this.id, this.ver, this.ref, - this.refHash, this.template, this.reply, this.section, - this.collabs, - this.brandId, - this.campaignId, - this.electionId, - this.categoryId, + this.collaborators, + this.parameters, }) : encodeAsBytes = false; @override List get props => [ alg, kid, - contentType, + mediaType, contentEncoding, type, id, ver, ref, - refHash, template, reply, section, - collabs, - brandId, - campaignId, - electionId, - categoryId, + collaborators, + parameters, encodeAsBytes, ]; /// Returns a copy of the [CoseHeaders] with overwritten properties. CoseHeaders copyWith({ - OptionalValueGetter? alg, - OptionalValueGetter? kid, - OptionalValueGetter? contentType, - OptionalValueGetter? contentEncoding, - OptionalValueGetter? type, - OptionalValueGetter? id, - OptionalValueGetter? ver, - OptionalValueGetter? ref, - OptionalValueGetter? refHash, - OptionalValueGetter? template, - OptionalValueGetter? reply, - OptionalValueGetter? section, - OptionalValueGetter?>? collabs, - OptionalValueGetter? brandId, - OptionalValueGetter? campaignId, - OptionalValueGetter? electionId, - OptionalValueGetter? categoryId, + OptionalValueGetter? alg, + OptionalValueGetter? kid, + OptionalValueGetter? mediaType, + OptionalValueGetter? contentEncoding, + OptionalValueGetter? type, + OptionalValueGetter? id, + OptionalValueGetter? ver, + OptionalValueGetter? ref, + OptionalValueGetter? template, + OptionalValueGetter? reply, + OptionalValueGetter? section, + OptionalValueGetter? collaborators, + OptionalValueGetter? parameters, bool? encodeAsBytes, }) { return CoseHeaders( alg: alg != null ? alg() : this.alg, kid: kid != null ? kid() : this.kid, - contentType: contentType != null ? contentType() : this.contentType, + mediaType: mediaType != null ? mediaType() : this.mediaType, contentEncoding: contentEncoding != null ? contentEncoding() : this.contentEncoding, type: type != null ? type() : this.type, id: id != null ? id() : this.id, ver: ver != null ? ver() : this.ver, ref: ref != null ? ref() : this.ref, - refHash: refHash != null ? refHash() : this.refHash, template: template != null ? template() : this.template, reply: reply != null ? reply() : this.reply, section: section != null ? section() : this.section, - collabs: collabs != null ? collabs() : this.collabs, - brandId: brandId != null ? brandId() : this.brandId, - campaignId: campaignId != null ? campaignId() : this.campaignId, - electionId: electionId != null ? electionId() : this.electionId, - categoryId: categoryId != null ? categoryId() : this.categoryId, + collaborators: collaborators != null ? collaborators() : this.collaborators, + parameters: parameters != null ? parameters() : this.parameters, encodeAsBytes: encodeAsBytes ?? this.encodeAsBytes, ); } @@ -249,23 +207,21 @@ final class CoseHeaders extends Equatable { /// Serializes the type as cbor. CborValue toCbor() { final map = CborMap({ - if (alg != null) CoseHeaderKeys.alg: alg!.toCbor(), - if (kid != null) CoseHeaderKeys.kid: CborBytes(kid!), - if (contentType != null) CoseHeaderKeys.contentType: contentType!.toCbor(), - if (contentEncoding != null) CoseHeaderKeys.contentEncoding: contentEncoding!.toCbor(), - if (type != null) CoseHeaderKeys.type: type!.toCbor(), - if (id != null) CoseHeaderKeys.id: id!.toCbor(), - if (ver != null) CoseHeaderKeys.ver: ver!.toCbor(), - if (ref != null) CoseHeaderKeys.ref: ref!.toCbor(), - if (refHash != null) CoseHeaderKeys.refHash: refHash!.toCbor(), - if (template != null) CoseHeaderKeys.template: template!.toCbor(), - if (reply != null) CoseHeaderKeys.reply: reply!.toCbor(), - if (section != null) CoseHeaderKeys.section: CborString(section!), - if (brandId != null) CoseHeaderKeys.brandId: brandId!.toCbor(), - if (campaignId != null) CoseHeaderKeys.campaignId: campaignId!.toCbor(), - if (electionId != null) CoseHeaderKeys.electionId: CborString(electionId!), - if (categoryId != null) CoseHeaderKeys.categoryId: categoryId!.toCbor(), - if (collabs != null) CoseHeaderKeys.collabs: CborUtils.serializeStringList(collabs), + if (alg case final alg?) CoseHeaderKeys.alg: alg.toCbor(), + if (kid case final kid?) CoseHeaderKeys.kid: kid.toCbor(), + if (mediaType case final contentType?) CoseHeaderKeys.mediaType: contentType.toCbor(), + if (contentEncoding case final contentEncoding?) + CoseHeaderKeys.contentEncoding: contentEncoding.toCbor(), + if (type case final type?) CoseHeaderKeys.type: type.toCbor(), + if (id case final id?) CoseHeaderKeys.id: id!.toCbor(), + if (ver case final ver?) CoseHeaderKeys.ver: ver!.toCbor(), + if (ref case final ref?) CoseHeaderKeys.ref: ref.toCbor(), + if (template case final template?) CoseHeaderKeys.template: template.toCbor(), + if (reply case final reply?) CoseHeaderKeys.reply: reply.toCbor(), + if (section case final section?) CoseHeaderKeys.section: section.toCbor(), + if (parameters case final parameters?) CoseHeaderKeys.parameters: parameters.toCbor(), + if (collaborators case final collaborators?) + CoseHeaderKeys.collaborators: collaborators.toCbor(), }); if (encodeAsBytes) { @@ -274,4 +230,57 @@ final class CoseHeaders extends Equatable { return map; } } + + static CborMap _decodeCbor(CborValue value) { + if (value is CborMap) { + // cose headers per specification might be wrapped in extra CborBytes, + // both formats are valid + return value; + } else { + final cborBytes = value as CborBytes; + final encodedMap = cbor.decode(cborBytes.bytes); + return encodedMap as CborMap; + } + } + + /// v0.0.1 -> v0.0.4 spec: https://github.com/input-output-hk/catalyst-libs/pull/341/files#diff-2827956d681587dfd09dc733aca731165ff44812f8322792bf6c4a61cf2d3b85 + /// + /// Migrate "brandId", "campaignId" and "categoryId" into "parameters". + static CborMap _migrateCbor1(CborMap map) { + final parametersKeys = [ + CoseHeaderKeys.brandId, + CoseHeaderKeys.campaignId, + CoseHeaderKeys.categoryId, + ]; + + if (parametersKeys.none(map.containsKey)) { + return map; + } else { + final modified = CborMap.fromEntries(map.entries, tags: map.tags, type: map.type); + final parameters = []; + + for (final key in parametersKeys) { + final value = modified.remove(key); + if (value != null) { + parameters.add(CoseDocumentRef.fromCbor(value)); + } + } + + modified[CoseHeaderKeys.parameters] = CoseDocumentRefs(parameters).toCbor(); + return modified; + } + } + + /// v0.0.1 -> v0.0.4 spec: https://github.com/input-output-hk/catalyst-libs/pull/341/files#diff-2827956d681587dfd09dc733aca731165ff44812f8322792bf6c4a61cf2d3b85 + /// + /// Migrate "collabs" into "collaborators". + static CborMap _migrateCbor2(CborMap map) { + if (map.containsKey(CoseHeaderKeys.collabs)) { + final modified = CborMap.fromEntries(map.entries, tags: map.tags, type: map.type); + modified[CoseHeaderKeys.collaborators] = map.remove(CoseHeaderKeys.collabs)!; + return modified; + } else { + return map; + } + } } diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_http_content_encoding.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_http_content_encoding.dart new file mode 100644 index 000000000000..7d0219df2ed9 --- /dev/null +++ b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_http_content_encoding.dart @@ -0,0 +1,29 @@ +import 'package:catalyst_cose/src/exception/cose_format_exception.dart'; +import 'package:cbor/cbor.dart'; + +/// Supported Content Encoding Types +enum CoseHttpContentEncoding { + /// brotli content encoding. + brotli('br'); + + /// The content encoding string representation. + final String tag; + + /// The default constructor for the [CoseHttpContentEncoding]. + const CoseHttpContentEncoding(this.tag); + + /// Deserializes the type from cbor. + factory CoseHttpContentEncoding.fromCbor(CborValue value) { + final string = value as CborString; + for (final item in values) { + if (item.tag.toLowerCase() == string.toString().toLowerCase()) { + return item; + } + } + + throw CoseFormatException('CoseHttpContentEncoding: unknown $value'); + } + + /// Serializes the type as cbor. + CborValue toCbor() => CborString(tag); +} diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_media_type.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_media_type.dart new file mode 100644 index 000000000000..fc79a2e65728 --- /dev/null +++ b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_media_type.dart @@ -0,0 +1,85 @@ +import 'package:catalyst_cose/catalyst_cose.dart'; +import 'package:cbor/cbor.dart'; + +/// Supported Content Media Types. +/// If the Media Type is supported by COAP, then the `uint` CoAP encoded +/// version of the media type must be used, in preference to the string. +enum CoseMediaType { + /// application/cbor + cbor('application/cbor', 60), + + /// application/cddl + cddl('application/cddl'), + + /// application/json + json('application/json', 50), + + /// application/schema+json + schemaJson('application/schema+json'), + + /// text/css; charset=utf-8 + css('text/css; charset=utf-8', 20000), + + /// text/css; charset=utf-8; template=handlebars + cssHandlebars('text/css; charset=utf-8; template=handlebars'), + + /// text/html; charset=utf-8 + html('text/html; charset=utf-8'), + + /// text/html; charset=utf-8; template=handlebars + htmlHandlebars('text/html; charset=utf-8; template=handlebars'), + + /// text/markdown; charset=utf-8 + markdown('text/markdown; charset=utf-8'), + + /// text/markdown; charset=utf-8; template=handlebars + markdownHandlebars('text/markdown; charset=utf-8; template=handlebars'), + + /// text/plain; charset=utf-8 + plain('text/plain; charset=utf-8', 0), + + /// text/plain; charset=utf-8; template=handlebars + plainHandlebars('text/plain; charset=utf-8; template=handlebars'); + + /// The media type string representation. + final String tag; + + /// The coap encoded uint value. + /// + /// Preferred over [tag] if available. + final int? coap; + + /// The default constructor for the [CoseMediaType]. + const CoseMediaType(this.tag, [this.coap]); + + /// Deserializes the type from cbor. + factory CoseMediaType.fromCbor(CborValue value) { + if (value is CborSmallInt) { + for (final item in values) { + if (item.coap == value.value) { + return item; + } + } + } + + if (value is CborString) { + for (final item in values) { + if (item.tag.toLowerCase() == value.toString().toLowerCase()) { + return item; + } + } + } + + throw CoseFormatException('CoseMediaType: unknown $value'); + } + + /// Serializes the type as cbor. + CborValue toCbor() { + final coap = this.coap; + if (coap != null) { + return CborSmallInt(coap); + } else { + return CborString(tag); + } + } +} diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_string_or_int.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_string_or_int.dart new file mode 100644 index 000000000000..816bdaa26d16 --- /dev/null +++ b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_string_or_int.dart @@ -0,0 +1,61 @@ +import 'package:cbor/cbor.dart'; +import 'package:equatable/equatable.dart'; + +/// The int value of [CoseStringOrInt]. +final class CoseIntValue extends CoseStringOrInt { + /// The int value of the [CoseStringOrInt] union. + final int value; + + /// The default constructor for [CoseIntValue]. + const CoseIntValue(this.value); + + /// Deserializes the type from cbor. + factory CoseIntValue.fromCbor(CborValue value) { + return CoseIntValue((value as CborSmallInt).value); + } + + @override + List get props => [value]; + + @override + CborValue toCbor() => CborSmallInt(value); +} + +/// A union type for either a string or int. +/// +/// In CDDL it's defined as (tstr/int) or (int/tstr). +sealed class CoseStringOrInt extends Equatable { + const CoseStringOrInt(); + + /// Deserializes the type from cbor. + factory CoseStringOrInt.fromCbor(CborValue value) { + if (value is CborString) { + return CoseStringValue.fromCbor(value); + } else { + return CoseIntValue.fromCbor(value); + } + } + + /// Serializes the type as cbor. + CborValue toCbor(); +} + +/// The string value of [CoseStringOrInt]. +final class CoseStringValue extends CoseStringOrInt { + /// The string value of the [CoseStringOrInt] union. + final String value; + + /// The default constructor for [CoseStringValue]. + const CoseStringValue(this.value); + + /// Deserializes the type from cbor. + factory CoseStringValue.fromCbor(CborValue value) { + return CoseStringValue((value as CborString).toString()); + } + + @override + List get props => [value]; + + @override + CborValue toCbor() => CborString(value); +} diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_uuid.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_uuid.dart new file mode 100644 index 000000000000..e998511f4c7b --- /dev/null +++ b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/cose_uuid.dart @@ -0,0 +1,91 @@ +import 'dart:typed_data'; + +import 'package:catalyst_cose/src/exception/cose_format_exception.dart'; +import 'package:catalyst_cose/src/utils/cbor_utils.dart'; +import 'package:cbor/cbor.dart'; +import 'package:convert/convert.dart'; +import 'package:uuid_plus/uuid_plus.dart' as uuid; + +/// Represents the Uuid V4 type. +/// +/// The cbor representation is tagged with a tag that defines the uuid type. +extension type const CoseUuidV4._(Uint8List bytes) { + /// Expected length when the uuid is encoded a byte list. + static const int bytesLength = 16; + + /// Creates [CoseUuidV4] from [bytes]. + factory CoseUuidV4.fromBytes(Uint8List bytes) { + if (bytes.length != bytesLength) { + throw CoseFormatException('CoseUuidV4: unexpected bytes: ${hex.encode(bytes)}'); + } else { + return CoseUuidV4._(bytes); + } + } + + /// Deserializes the type from cbor. + factory CoseUuidV4.fromCbor(CborValue value) { + if (value is CborBytes) { + return CoseUuidV4.fromBytes(Uint8List.fromList(value.bytes)); + } else { + throw CoseFormatException('The $value is not a valid uuid!'); + } + } + + /// Creates [CoseUuidV4] from a [string]. + factory CoseUuidV4.fromString(String string) { + final uuidBytes = uuid.Uuid.parse(string); + return CoseUuidV4.fromBytes(Uint8List.fromList(uuidBytes)); + } + + /// Converts the [bytes] into uuid formatted string. + String format() { + return uuid.Uuid.unparse(bytes); + } + + /// Serializes the type as cbor. + CborValue toCbor() { + return CborBytes(bytes, tags: [CborUtils.uuidTag]); + } +} + +/// Represents the Uuid V7 type. +/// +/// The cbor representation is tagged with a tag that defines the uuid type. +extension type const CoseUuidV7._(Uint8List bytes) { + /// Expected length when the uuid is encoded a byte list. + static const int bytesLength = 16; + + /// Creates [CoseUuidV7] from [bytes]. + factory CoseUuidV7.fromBytes(Uint8List bytes) { + if (bytes.length != bytesLength) { + throw CoseFormatException('CoseUuidV7: unexpected bytes: ${hex.encode(bytes)}'); + } else { + return CoseUuidV7._(bytes); + } + } + + /// Deserializes the type from cbor. + factory CoseUuidV7.fromCbor(CborValue value) { + if (value is CborBytes) { + return CoseUuidV7.fromBytes(Uint8List.fromList(value.bytes)); + } else { + throw CoseFormatException('The $value is not a valid uuid!'); + } + } + + /// Creates [CoseUuidV7] from a [string]. + factory CoseUuidV7.fromString(String string) { + final uuidBytes = uuid.Uuid.parse(string); + return CoseUuidV7.fromBytes(Uint8List.fromList(uuidBytes)); + } + + /// Converts the [bytes] into uuid formatted string. + String format() { + return uuid.Uuid.unparse(bytes); + } + + /// Serializes the type as cbor. + CborValue toCbor() { + return CborBytes(bytes, tags: [CborUtils.uuidTag]); + } +} diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/string_or_int.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/string_or_int.dart deleted file mode 100644 index a1e844c61a68..000000000000 --- a/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/string_or_int.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:cbor/cbor.dart'; -import 'package:equatable/equatable.dart'; - -/// The int value of [StringOrInt]. -final class IntValue extends StringOrInt { - /// The int value of the [StringOrInt] union. - final int value; - - /// The default constructor for [IntValue]. - const IntValue(this.value); - - /// Deserializes the type from cbor. - factory IntValue.fromCbor(CborValue value) { - return IntValue((value as CborSmallInt).value); - } - - @override - List get props => [value]; - - @override - CborValue toCbor() => CborSmallInt(value); -} - -/// A union type for either a string or int. -/// -/// In CDDL it's defined as (tstr/int) or (int/tstr). -sealed class StringOrInt extends Equatable { - const StringOrInt(); - - /// Deserializes the type from cbor. - factory StringOrInt.fromCbor(CborValue value) { - if (value is CborString) { - return StringValue.fromCbor(value); - } else { - return IntValue.fromCbor(value); - } - } - - /// Serializes the type as cbor. - CborValue toCbor(); -} - -/// The string value of [StringOrInt]. -final class StringValue extends StringOrInt { - /// The string value of the [StringOrInt] union. - final String value; - - /// The default constructor for [StringValue]. - const StringValue(this.value); - - /// Deserializes the type from cbor. - factory StringValue.fromCbor(CborValue value) { - return StringValue((value as CborString).toString()); - } - - @override - List get props => [value]; - - @override - CborValue toCbor() => CborString(value); -} diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/uuid.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/uuid.dart deleted file mode 100644 index aa3491fda576..000000000000 --- a/catalyst_voices/packages/libs/catalyst_cose/lib/src/types/uuid.dart +++ /dev/null @@ -1,116 +0,0 @@ -import 'dart:typed_data'; - -import 'package:catalyst_cose/src/utils/cbor_utils.dart'; -import 'package:cbor/cbor.dart'; -import 'package:equatable/equatable.dart'; -import 'package:uuid_plus/uuid_plus.dart' as uuid; - -/// A reference to an entity represented by the [id]. -/// Optionally the version of the entity may be specified by the [ver]. -/// -/// What this uuid means depends where and how the class is used. -/// In CDDL it is defined as (UUID / [UUID, UUID]). -final class ReferenceUuid extends Equatable { - /// The referenced entity uuid. - final Uuid id; - - /// The version of the referenced entity. - final Uuid? ver; - - /// The default constructor for the [ReferenceUuid]. - const ReferenceUuid({ - required this.id, - this.ver, - }); - - /// Deserializes the type from cbor. - factory ReferenceUuid.fromCbor(CborValue value) { - if (value is CborList) { - return ReferenceUuid( - id: Uuid.fromCbor(value[0]), - ver: Uuid.fromCbor(value[1]), - ); - } else { - return ReferenceUuid( - id: Uuid.fromCbor(value), - ); - } - } - - @override - List get props => [id, ver]; - - /// Serializes the type as cbor. - CborValue toCbor() { - final ver = this.ver; - if (ver != null) { - return CborList([ - id.toCbor(), - ver.toCbor(), - ]); - } else { - return id.toCbor(); - } - } -} - -/// A reference to an entity represented by the [ref]. -/// Optionally the version of the entity may be specified by the [hash]. -/// -/// What this uuid means depends where and how the class is used. -/// In CDDL it is defined as (UUID / [UUID, UUID]). -final class ReferenceUuidHash extends Equatable { - /// The referenced entity uuid. - final ReferenceUuid ref; - - /// The version of the referenced entity. - final Uint8List hash; - - /// The default constructor for the [ReferenceUuidHash]. - const ReferenceUuidHash({ - required this.ref, - required this.hash, - }); - - /// Deserializes the type from cbor. - factory ReferenceUuidHash.fromCbor(CborValue value) { - final list = value as CborList; - - return ReferenceUuidHash( - ref: ReferenceUuid.fromCbor(list[0]), - hash: Uint8List.fromList((list[1] as CborBytes).bytes), - ); - } - - @override - List get props => [ref, hash]; - - /// Serializes the type as cbor. - CborValue toCbor() { - return CborList([ - ref.toCbor(), - CborBytes(hash), - ]); - } -} - -/// Represents the Uuid type. -/// -/// Uuid v7 is preferred. The cbor representation -/// is tagged with a tag that defines the uuid type. -extension type const Uuid(String value) { - /// Deserializes the type from cbor. - factory Uuid.fromCbor(CborValue value) { - if (value is CborBytes) { - return Uuid(uuid.Uuid.unparse(value.bytes)); - } else { - throw FormatException('The $value is not a valid uuid!'); - } - } - - /// Serializes the type as cbor. - CborValue toCbor() { - final uuidBytes = uuid.Uuid.parse(value); - return CborBytes(uuidBytes, tags: [CborUtils.uuidTag]); - } -} diff --git a/catalyst_voices/packages/libs/catalyst_cose/lib/src/utils/cbor_utils.dart b/catalyst_voices/packages/libs/catalyst_cose/lib/src/utils/cbor_utils.dart index 7297838ef2cc..1ce0936ec84a 100644 --- a/catalyst_voices/packages/libs/catalyst_cose/lib/src/utils/cbor_utils.dart +++ b/catalyst_voices/packages/libs/catalyst_cose/lib/src/utils/cbor_utils.dart @@ -1,8 +1,6 @@ import 'dart:convert'; -import 'dart:typed_data'; -import 'package:catalyst_cose/src/types/string_or_int.dart'; -import 'package:catalyst_cose/src/types/uuid.dart'; +import 'package:catalyst_cose/catalyst_cose.dart'; import 'package:cbor/cbor.dart'; /// A set of utils around cbor encoding/decoding. @@ -10,84 +8,120 @@ final class CborUtils { /// A cbor tag for the UUID type. static const int uuidTag = 37; + /// A cbor tag for content identifiers (IPLD / IPFS). + static const int cidTag = 42; + const CborUtils._(); - /// Deserializes optional [Uint8List] type. - static Uint8List? deserializeBytes(CborValue? value) { + /// Deserializes optional [CoseCollaborators] type. + static CoseCollaborators? deserializeCollaborators(CborValue? value) { if (value == null) { return null; } - if (value is CborString) { - return utf8.encode(value.toString()); + return CoseCollaborators.fromCbor(value); + } + + /// Deserializes optional [CoseDocumentId] type. + static CoseDocumentId? deserializeDocumentId(CborValue? value) { + if (value == null) { + return null; } - return Uint8List.fromList((value as CborBytes).bytes); + return CoseDocumentId.fromCbor(value); } - /// Deserialized optional [ReferenceUuid] type. - static ReferenceUuid? deserializeReferenceUuid(CborValue? value) { + /// Deserializes optional [CoseDocumentRefs] type. + static CoseDocumentRefs? deserializeDocumentRefs(CborValue? value) { if (value == null) { return null; } - return ReferenceUuid.fromCbor(value); + return CoseDocumentRefs.fromCbor(value); } - /// Deserialized optional [ReferenceUuidHash] type. - static ReferenceUuidHash? deserializeReferenceUuidHash(CborValue? value) { + /// Deserializes optional [CoseDocumentType] type. + static CoseDocumentType? deserializeDocumentType(CborValue? value) { if (value == null) { return null; } - return ReferenceUuidHash.fromCbor(value); + return CoseDocumentType.fromCbor(value); } - /// Deserializes optional [String] type. - static String? deserializeString(CborValue? value) { + /// Deserializes optional [CoseDocumentVer] type. + static CoseDocumentVer? deserializeDocumentVer(CborValue? value) { if (value == null) { return null; } - return (value as CborString).toString(); + return CoseDocumentVer.fromCbor(value); } - /// Deserializes optional `List` type. - static List? deserializeStringList(CborValue? value) { + /// Deserializes optional [CoseHttpContentEncoding] type. + static CoseHttpContentEncoding? deserializeHttpContentEncoding(CborValue? value) { if (value == null) { return null; } - final list = value as CborList; - return list.map((e) => (e as CborString).toString()).toList(); + return CoseHttpContentEncoding.fromCbor(value); + } + + /// Deserializes optional [CatalystIdKid] type. + static CatalystIdKid? deserializeKid(CborValue? value) { + if (value == null) { + return null; + } + + if (value is CborString) { + return CatalystIdKid(utf8.encode(value.toString())); + } + + return CatalystIdKid.fromCbor(value); } - /// Deserializes optional [StringOrInt] type. - static StringOrInt? deserializeStringOrInt(CborValue? value) { + /// Deserializes optional [CoseMediaType] type. + static CoseMediaType? deserializeMediaType(CborValue? value) { if (value == null) { return null; } - return StringOrInt.fromCbor(value); + return CoseMediaType.fromCbor(value); } - /// Deserializes optional [Uuid] type. - static Uuid? deserializeUuid(CborValue? value) { + /// Deserializes optional [CoseSectionRef] type. + static CoseSectionRef? deserializeSectionRef(CborValue? value) { if (value == null) { return null; } - return Uuid.fromCbor(value); + return CoseSectionRef.fromCbor(value); } - /// Serializes optional `List` type. - static CborValue serializeStringList(List? values) { - if (values == null) { - return const CborNull(); + /// Deserializes optional [CoseStringOrInt] type. + static CoseStringOrInt? deserializeStringOrInt(CborValue? value) { + if (value == null) { + return null; + } + + return CoseStringOrInt.fromCbor(value); + } + + /// Deserializes optional [CoseUuidV4] type. + static CoseUuidV4? deserializeUuidV4(CborValue? value) { + if (value == null) { + return null; + } + + return CoseUuidV4.fromCbor(value); + } + + /// Deserializes optional [CoseUuidV7] type. + static CoseUuidV7? deserializeUuidV7(CborValue? value) { + if (value == null) { + return null; } - return CborList([ - for (final value in values) CborString(value), - ]); + return CoseUuidV7.fromCbor(value); } } diff --git a/catalyst_voices/packages/libs/catalyst_cose/pubspec.yaml b/catalyst_voices/packages/libs/catalyst_cose/pubspec.yaml index a5c82f8dd795..f266ea295151 100644 --- a/catalyst_voices/packages/libs/catalyst_cose/pubspec.yaml +++ b/catalyst_voices/packages/libs/catalyst_cose/pubspec.yaml @@ -21,4 +21,4 @@ dev_dependencies: catalyst_analysis: ^3.0.0 flutter_test: sdk: flutter - test: ^1.25.15 + test: ^1.27.0 diff --git a/catalyst_voices/packages/libs/catalyst_cose/test/cose_sign1_test.dart b/catalyst_voices/packages/libs/catalyst_cose/test/cose_sign1_test.dart index 825d89bcceac..837a1e09990b 100644 --- a/catalyst_voices/packages/libs/catalyst_cose/test/cose_sign1_test.dart +++ b/catalyst_voices/packages/libs/catalyst_cose/test/cose_sign1_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; void main() { group(CoseSign1, () { + const uuidV4 = 'e9aba14f-d05b-49b2-b5b5-100595853384'; const uuidV7 = '0193b535-7196-7cd1-84e6-ad9c316cf2d2'; late _SignerVerifier signerVerifier; @@ -19,17 +20,23 @@ void main() { test('sign generates a valid COSE_SIGN1 structure', () async { final coseSign1 = await CoseSign1.sign( - protectedHeaders: const CoseHeaders.protected( - contentType: IntValue(CoseValues.jsonContentType), - contentEncoding: StringValue(CoseValues.brotliContentEncoding), - type: Uuid(uuidV7), - id: Uuid(uuidV7), - ver: Uuid(uuidV7), - ref: ReferenceUuid(id: Uuid(uuidV7)), - template: ReferenceUuid(id: Uuid(uuidV7)), - reply: ReferenceUuid(id: Uuid(uuidV7)), - section: 'section_name', - collabs: ['test@domain.com'], + protectedHeaders: CoseHeaders.protected( + mediaType: CoseMediaType.json, + contentEncoding: CoseHttpContentEncoding.brotli, + type: CoseDocumentType(CoseUuidV4.fromString(uuidV4)), + id: CoseDocumentId(CoseUuidV7.fromString(uuidV7)), + ver: CoseDocumentVer(CoseUuidV7.fromString(uuidV7)), + ref: CoseDocumentRefs([ + CoseDocumentRef.optional(documentId: CoseUuidV7.fromString(uuidV7)), + ]), + template: CoseDocumentRefs([ + CoseDocumentRef.optional(documentId: CoseUuidV7.fromString(uuidV7)), + ]), + reply: CoseDocumentRefs([ + CoseDocumentRef.optional(documentId: CoseUuidV7.fromString(uuidV7)), + ]), + section: const CoseSectionRef(CoseJsonPointer('section_name')), + collaborators: CoseCollaborators([CatalystIdKid.fromString('test@domain.com')]), ), unprotectedHeaders: const CoseHeaders.unprotected(), signer: signerVerifier, @@ -72,12 +79,12 @@ final class _SignerVerifier implements CatalystCoseSigner, CatalystCoseVerifier const _SignerVerifier(this._algorithm, this._keyPair); @override - StringOrInt? get alg => const IntValue(CoseValues.eddsaAlg); + CoseStringOrInt? get alg => const CoseIntValue(CoseValues.eddsaAlg); @override - Future get kid async { + Future get kid async { final pk = await _keyPair.extractPublicKey(); - return Uint8List.fromList(pk.bytes); + return CatalystIdKid(Uint8List.fromList(pk.bytes)); } @override diff --git a/catalyst_voices/packages/libs/catalyst_cose/test/cose_sign_test.dart b/catalyst_voices/packages/libs/catalyst_cose/test/cose_sign_test.dart index b641bb78f621..d5e541bc015b 100644 --- a/catalyst_voices/packages/libs/catalyst_cose/test/cose_sign_test.dart +++ b/catalyst_voices/packages/libs/catalyst_cose/test/cose_sign_test.dart @@ -20,17 +20,23 @@ void main() { test('sign generates a valid COSE_SIGN structure', () async { final coseSign = await CoseSign.sign( - protectedHeaders: const CoseHeaders.protected( - contentType: IntValue(CoseValues.jsonContentType), - contentEncoding: StringValue(CoseValues.brotliContentEncoding), - type: Uuid(uuidV4), - id: Uuid(uuidV7), - ver: Uuid(uuidV7), - ref: ReferenceUuid(id: Uuid(uuidV7)), - template: ReferenceUuid(id: Uuid(uuidV7)), - reply: ReferenceUuid(id: Uuid(uuidV7)), - section: 'section_name', - collabs: ['test@domain.com'], + protectedHeaders: CoseHeaders.protected( + mediaType: CoseMediaType.json, + contentEncoding: CoseHttpContentEncoding.brotli, + type: CoseDocumentType(CoseUuidV4.fromString(uuidV4)), + id: CoseDocumentId(CoseUuidV7.fromString(uuidV7)), + ver: CoseDocumentVer(CoseUuidV7.fromString(uuidV7)), + ref: CoseDocumentRefs([ + CoseDocumentRef.optional(documentId: CoseUuidV7.fromString(uuidV7)), + ]), + template: CoseDocumentRefs([ + CoseDocumentRef.optional(documentId: CoseUuidV7.fromString(uuidV7)), + ]), + reply: CoseDocumentRefs([ + CoseDocumentRef.optional(documentId: CoseUuidV7.fromString(uuidV7)), + ]), + section: const CoseSectionRef(CoseJsonPointer('section_name')), + collaborators: CoseCollaborators([CatalystIdKid.fromString('test@domain.com')]), ), unprotectedHeaders: const CoseHeaders.unprotected(), signers: [signerVerifier], @@ -88,12 +94,12 @@ final class _SignerVerifier implements CatalystCoseSigner, CatalystCoseVerifier const _SignerVerifier(this._algorithm, this._keyPair); @override - StringOrInt? get alg => const IntValue(CoseValues.eddsaAlg); + CoseStringOrInt? get alg => const CoseIntValue(CoseValues.eddsaAlg); @override - Future get kid async { + Future get kid async { final pk = await _keyPair.extractPublicKey(); - return Uint8List.fromList(pk.bytes); + return CatalystIdKid(Uint8List.fromList(pk.bytes)); } @override diff --git a/catalyst_voices/packages/libs/catalyst_key_derivation/.earthlyignore b/catalyst_voices/packages/libs/catalyst_key_derivation/.earthlyignore index 0a9505a3048c..cdd029968109 100644 --- a/catalyst_voices/packages/libs/catalyst_key_derivation/.earthlyignore +++ b/catalyst_voices/packages/libs/catalyst_key_derivation/.earthlyignore @@ -16,15 +16,10 @@ # Generated files from code generation tools **/*.g.dart **/*.freezed.dart -**/*.chopper.dart -**/*.swagger.dart -**/*.openapi.dart **/*.gen.dart -**/*.swagger.*.dart **/*.drift.dart -**/openapi/processed/ -**/catalyst_voices_localizations_*.dart -**/catalyst_voices_localizations.dart +**/generated/catalyst_voices_localizations_*.dart +**/generated/catalyst_voices_localizations.dart # node related diff --git a/catalyst_voices/packages/libs/catalyst_key_derivation/cargokit/build_tool/pubspec.yaml b/catalyst_voices/packages/libs/catalyst_key_derivation/cargokit/build_tool/pubspec.yaml index 896182dc4798..657b076da775 100644 --- a/catalyst_voices/packages/libs/catalyst_key_derivation/cargokit/build_tool/pubspec.yaml +++ b/catalyst_voices/packages/libs/catalyst_key_derivation/cargokit/build_tool/pubspec.yaml @@ -30,4 +30,4 @@ dependencies: dev_dependencies: lints: ^2.1.0 - test: ^1.25.15 + test: ^1.27.0 diff --git a/catalyst_voices/packages/libs/catalyst_key_derivation/pubspec.yaml b/catalyst_voices/packages/libs/catalyst_key_derivation/pubspec.yaml index 32d81146a2c0..3c795f5f5ae6 100644 --- a/catalyst_voices/packages/libs/catalyst_key_derivation/pubspec.yaml +++ b/catalyst_voices/packages/libs/catalyst_key_derivation/pubspec.yaml @@ -34,7 +34,7 @@ dev_dependencies: ffigen: ^11.0.0 flutter_test: sdk: flutter - test: ^1.25.15 + test: ^1.27.0 flutter: plugin: diff --git a/catalyst_voices/pubspec.yaml b/catalyst_voices/pubspec.yaml index 69afd0e84639..3237b3fe39f5 100644 --- a/catalyst_voices/pubspec.yaml +++ b/catalyst_voices/pubspec.yaml @@ -39,6 +39,9 @@ dependencies: dev_dependencies: melos: ^7.1.1 +dependency_overrides: + test_api: 0.7.8 + melos: repository: https://github.com/input-output-hk/catalyst-voices @@ -71,6 +74,12 @@ melos: description: | Run `dart analyze` in every package. + flutter-clean: + run: | + melos exec -c 1 -- flutter clean + description: | + Run `flutter clean` sequentially in every Flutter package. + l10n: run: | melos exec --scope="catalyst_voices_localization" -- flutter gen-l10n @@ -91,20 +100,9 @@ melos: build-runner: run: | - melos exec --depends-on="build_runner" --ignore="catalyst_voices_repositories" --order-dependents -- \ - dart run build_runner build --delete-conflicting-outputs + melos exec --depends-on="build_runner" --order-dependents -- dart run build_runner build --delete-conflicting-outputs --force-aot description: | Run `build_runner` in every package which contains the build_runner dependency. - The catalyst_voices_repositories is skipped because to run a build_runner there you - must generate first swagger docs (see related Earthfile). - - build-runner-repository: - run: | - melos exec --scope="catalyst_voices_repositories" -- dart run build_runner clean && \ - melos exec --scope="catalyst_voices_repositories" -- dart run process_openapi.dart && \ - melos exec --scope="catalyst_voices_repositories" -- dart run build_runner build --delete-conflicting-outputs - description: | - Run `build_runner` in catalyst_voices_repositories package db-make-migration: run: | @@ -211,13 +209,10 @@ melos: lcov --remove {} -o {} --ignore-errors unused,unused \ '*.g.dart' \ '*.freezed.dart' \ - '*.chopper.dart' \ - '*.swagger.dart' \ - '*.openapi.dart' \ '*.gen.dart' \ - '*.swagger.*.dart' \ '*.drift.dart' \ - 'lib/generated/**' \; + 'generated/catalyst_voices_localizations_*.dart' \ + 'generated/catalyst_voices_localizations.dart' \; # merges all coverage reports into a single one and puts it in /coverage/lcov.info dart pub global run combine_coverage --repo-path=. @@ -261,13 +256,10 @@ melos: lcov --remove {} -o {} --ignore-errors unused,unused \ '*.g.dart' \ '*.freezed.dart' \ - '*.chopper.dart' \ - '*.swagger.dart' \ - '*.openapi.dart' \ '*.gen.dart' \ - '*.swagger.*.dart' \ '*.drift.dart' \ - 'lib/generated/**' \; + 'generated/catalyst_voices_localizations_*.dart' \ + 'generated/catalyst_voices_localizations.dart' \; # merges all coverage reports into a single one and puts it in /coverage/lcov.info dart pub global run combine_coverage --repo-path=. diff --git a/catalyst_voices/utilities/uikit_example/pubspec.yaml b/catalyst_voices/utilities/uikit_example/pubspec.yaml index 731e91471803..ecbd69d9fce4 100644 --- a/catalyst_voices/utilities/uikit_example/pubspec.yaml +++ b/catalyst_voices/utilities/uikit_example/pubspec.yaml @@ -36,9 +36,9 @@ dependencies: ref: 10be2c8d1fb0d7728183fc883e133b5b48251d62 dev_dependencies: - build_runner: ^2.5.4 + build_runner: ^2.10.3 catalyst_analysis: ^3.0.0 - flutter_gen_runner: ^5.11.0 + flutter_gen_runner: ^5.12.0 flutter_test: sdk: flutter diff --git a/cspell.json b/cspell.json index 5a041ded2db8..6e0a32186bdd 100644 --- a/cspell.json +++ b/cspell.json @@ -175,7 +175,6 @@ "styles.min.css", "web-components.min.js", "**/generated/**", - "**/openapi/**", "**/GeneratedPluginRegistrant.swift", "catalyst_voices/packages/libs/**/cargokit/**", "catalyst_voices/packages/libs/**/lib/src/rust/**", @@ -185,7 +184,7 @@ "**/*.svg", "catalyst_voices/docs/licenses/**", "catalyst_voices/docs/dependency_graph.dot", - "catalyst-gateway/tests/api_tests/test_data/**", + "catalyst-gateway/tests/api_tests/test_data/**" ], "enableFiletypes": [ "earthfile",