Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ import 'package:catalyst_voices/pages/workspace/submission_closing_warning_dialo
import 'package:catalyst_voices/routes/routes.dart';
import 'package:catalyst_voices/routes/routing/proposal_builder_route.dart';
import 'package:catalyst_voices/widgets/modals/comment/submit_comment_error_dialog.dart';
import 'package:catalyst_voices/widgets/modals/proposals/proposal_error_dialog.dart';
import 'package:catalyst_voices/widgets/modals/proposals/proposal_limit_reached_dialog.dart';
import 'package:catalyst_voices/widgets/modals/proposals/publish_proposal_error_dialog.dart';
import 'package:catalyst_voices/widgets/modals/proposals/publish_proposal_iteration_dialog.dart';
import 'package:catalyst_voices/widgets/modals/proposals/submit_proposal_error_dialog.dart';
import 'package:catalyst_voices/widgets/modals/proposals/submit_proposal_for_review_dialog.dart';
import 'package:catalyst_voices/widgets/modals/proposals/unlock_edit_proposal.dart';
import 'package:catalyst_voices/widgets/snackbar/common_snackbars.dart';
Expand Down Expand Up @@ -142,8 +141,14 @@ class _ProposalBuilderBodyState extends State<_ProposalBuilderBody>
unawaited(_showPublishException(error));
case ProposalBuilderSubmitException():
unawaited(_showSubmitException(error));
case ProposalBuilderLimitReachedException():
unawaited(_showLimitReachedException(error));
case ProposalBuilderDocumentSignException():
unawaited(_showDocumentSignException(error));
case LocalizedUnknownPublishCommentException():
unawaited(_showCommentException(error));
case LocalizedException():
unawaited(_showGenericException(error));
default:
super.handleError(error);
}
Expand Down Expand Up @@ -277,6 +282,14 @@ class _ProposalBuilderBodyState extends State<_ProposalBuilderBody>
);
}

Future<void> _showDocumentSignException(ProposalBuilderDocumentSignException error) {
return ProposalErrorDialog.show(
context: context,
title: error.title(context),
message: error.message(context),
);
}

Future<void> _showEmailNotVerifiedDialog() async {
final openAccount = await EmailNotVerifiedDialog.show(context);

Expand Down Expand Up @@ -317,6 +330,22 @@ class _ProposalBuilderBodyState extends State<_ProposalBuilderBody>
});
}

Future<void> _showGenericException(LocalizedException error) {
return ProposalErrorDialog.show(
context: context,
title: context.l10n.somethingWentWrong,
message: error.message(context),
);
}

Future<void> _showLimitReachedException(ProposalBuilderLimitReachedException error) {
return ProposalErrorDialog.show(
context: context,
title: error.title(context),
message: error.message(context),
);
}

Future<void> _showProposalLimitReachedDialog(
MaxProposalsLimitReachedSignal signal,
) {
Expand Down Expand Up @@ -344,9 +373,10 @@ class _ProposalBuilderBodyState extends State<_ProposalBuilderBody>
}

Future<void> _showPublishException(ProposalBuilderPublishException error) {
return PublishProposalErrorDialog.show(
return ProposalErrorDialog.show(
context: context,
exception: error,
title: error.title(context),
message: error.message(context),
);
}

Expand Down Expand Up @@ -380,9 +410,10 @@ class _ProposalBuilderBodyState extends State<_ProposalBuilderBody>
}

Future<void> _showSubmitException(ProposalBuilderSubmitException error) {
return SubmitProposalErrorDialog.show(
return ProposalErrorDialog.show(
context: context,
exception: error,
title: error.title(context),
message: error.message(context),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,27 @@ import 'package:catalyst_voices/widgets/modals/voices_info_dialog.dart';
import 'package:catalyst_voices_assets/catalyst_voices_assets.dart';
import 'package:catalyst_voices_brands/catalyst_voices_brands.dart';
import 'package:catalyst_voices_localization/catalyst_voices_localization.dart';
import 'package:catalyst_voices_view_models/catalyst_voices_view_models.dart';
import 'package:flutter/material.dart';

/// Error dialog when submitting proposal for review fails.
class SubmitProposalErrorDialog {
/// Generic error dialog related to proposal errors.
class ProposalErrorDialog {
static Future<void> show({
required BuildContext context,
required ProposalBuilderSubmitException exception,
required String title,
required String message,
}) {
return VoicesDialog.show(
context: context,
routeSettings: const RouteSettings(
name: '/proposal-builder/submit-error',
name: '/proposal-builder/error',
),
builder: (context) {
return VoicesInfoDialog(
icon: VoicesAssets.icons.exclamation.buildIcon(
color: Theme.of(context).colors.iconsWarning,
),
title: Text(exception.title(context)),
message: Text(exception.message(context)),
title: Text(title),
message: Text(message),
action: VoicesFilledButton(
onTap: () => Navigator.of(context).pop(),
child: Text(context.l10n.okay),
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -790,9 +790,21 @@ final class ProposalBuilderBloc extends Bloc<ProposalBuilderEvent, ProposalBuild
versions: updatedVersions,
);
emitSignal(const PublishedProposalBuilderSignal());
} on ProposalLimitReachedException {
_logger.info('publishProposal: limit reached');
emitError(const ProposalBuilderLimitReachedException());
} on DocumentSignException catch (error, stackTrace) {
_logger.severe('publishProposal: failed to sign the document', error, stackTrace);
emitError(const ProposalBuilderDocumentSignException());
} catch (error, stackTrace) {
_logger.severe('PublishProposal', error, stackTrace);
emitError(const ProposalBuilderPublishException());
_logger.severe('publishProposal', error, stackTrace);

emitError(
LocalizedException.create(
error,
fallback: () => const ProposalBuilderPublishException(),
),
);
} finally {
emit(state.copyWith(isChanging: false));
}
Expand Down Expand Up @@ -1092,9 +1104,21 @@ final class ProposalBuilderBloc extends Bloc<ProposalBuilderEvent, ProposalBuild
// already submitted, do nothing
break;
}
} on ProposalLimitReachedException {
_logger.info('SubmitProposalForReview: limit reached');
emitError(const ProposalBuilderLimitReachedException());
} on DocumentSignException catch (error, stackTrace) {
_logger.severe('publishProposal: failed to sign the document', error, stackTrace);
emitError(const ProposalBuilderDocumentSignException());
} catch (error, stackTrace) {
_logger.severe('SubmitProposalForReview', error, stackTrace);
emitError(const ProposalBuilderSubmitException());

emitError(
LocalizedException.create(
error,
fallback: () => const ProposalBuilderSubmitException(),
),
);
} finally {
emit(state.copyWith(isChanging: false));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2194,6 +2194,22 @@
"@proposalEditorDeleteDialogTitle": {
"description": "A title for the dialog to confirm proposal deletion."
},
"proposalEditorDocumentSignErrorMessage": "We couldn't sign the proposal, please try again later.",
"@proposalEditorDocumentSignErrorMessage": {
"description": "Dialog message in proposal editor when user couldn't sign the proposal."
},
"proposalEditorDocumentSignErrorTitle": "Unable to Sign the Proposal",
"@proposalEditorDocumentSignErrorTitle": {
"description": "Dialog title in proposal editor when user couldn't sign the proposal."
},
"proposalEditorLimitReachedErrorMessage": "You have reached the maximum number of proposals allowed.",
"@proposalEditorLimitReachedErrorMessage": {
"description": "Dialog message in proposal editor when user has reached the max proposals limit."
},
"proposalEditorLimitReachedErrorTitle": "Unable to Publish Proposal",
"@proposalEditorLimitReachedErrorTitle": {
"description": "Dialog title in proposal editor when user has reached the max proposals limit."
},
"proposalEditorNotAnswered": "Not Answered",
"@proposalEditorNotAnswered": {
"description": "Placeholder text when a property has been not filled."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export 'document/enums/document_content_media_type.dart';
export 'document/enums/document_property_format.dart';
export 'document/enums/document_property_type.dart';
export 'document/exception/document_import_invalid_data_exception.dart';
export 'document/exception/document_sign_exception.dart';
export 'document/schema/document_schema.dart';
export 'document/schema/property/document_property_schema.dart';
export 'document/specialized/comment_document.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import 'package:equatable/equatable.dart';

/// An exception denoting a problem with signed document creation.
class DocumentSignException extends Equatable implements Exception {
final String message;

const DocumentSignException(this.message);

@override
List<Object?> get props => [message];
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,25 @@ final class SignedDocumentManagerImpl implements SignedDocumentManager {
required CatalystId catalystId,
required CatalystPrivateKey privateKey,
}) async {
final compressedPayload = await _brotliCompressPayload(document.toBytes());

final coseSign = await CoseSign.sign(
protectedHeaders: metadata.asCoseProtectedHeaders,
unprotectedHeaders: metadata.asCoseUnprotectedHeaders,
payload: compressedPayload,
signers: [_CatalystSigner(catalystId, privateKey)],
);

return _CoseSignedDocument(
coseSign: coseSign,
payload: document,
metadata: metadata,
signers: [catalystId],
);
try {
final compressedPayload = await _brotliCompressPayload(document.toBytes());

final coseSign = await CoseSign.sign(
protectedHeaders: metadata.asCoseProtectedHeaders,
unprotectedHeaders: metadata.asCoseUnprotectedHeaders,
payload: compressedPayload,
signers: [_CatalystSigner(catalystId, privateKey)],
);

return _CoseSignedDocument(
coseSign: coseSign,
payload: document,
metadata: metadata,
signers: [catalystId],
);
} on CoseSignException catch (error) {
throw DocumentSignException('Failed to create a signed document!\nSource: ${error.source}');
}
}

Future<Uint8List> _brotliCompressPayload(Uint8List payload) async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,35 @@ import 'package:catalyst_voices_localization/catalyst_voices_localization.dart';
import 'package:catalyst_voices_view_models/src/exception/localized_exception.dart';
import 'package:flutter/material.dart';

/// An exception thrown when the app cannot sign the document on the user's behalf.
final class ProposalBuilderDocumentSignException extends LocalizedException {
const ProposalBuilderDocumentSignException();

@override
String message(BuildContext context) {
return context.l10n.proposalEditorDocumentSignErrorMessage;
}

String title(BuildContext context) {
return context.l10n.proposalEditorDocumentSignErrorTitle;
}
}

/// An exception thrown attempting to create / import a new
/// proposal when the user has reached the limit.
final class ProposalBuilderLimitReachedException extends LocalizedException {
const ProposalBuilderLimitReachedException();

@override
String message(BuildContext context) {
return context.l10n.proposalEditorLimitReachedErrorMessage;
}

String title(BuildContext context) {
return context.l10n.proposalEditorLimitReachedErrorTitle;
}
}

/// Localized exception thrown when a proposal builder fails to publish a proposal.
final class ProposalBuilderPublishException extends LocalizedException {
const ProposalBuilderPublishException();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export 'src/cose_constants.dart';
export 'src/cose_sign.dart';
export 'src/cose_sign1.dart';
export 'src/exception/cose_exception.dart';
export 'src/types/cose_headers.dart';
export 'src/types/string_or_int.dart';
export 'src/types/uuid.dart';
Loading