Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#617] feat: integrate frontend with metadata validation service #619

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
22 changes: 11 additions & 11 deletions .github/workflows/lighthouse.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,23 @@ jobs:
- name: Run build and lighthouse task
working-directory: ./govtool/frontend
run: |
npm install
VITE_BASE_URL=https://staging.govtool.byron.network/api npm run build
lhci collect
npm install
VITE_BASE_URL=https://staging.govtool.byron.network/ npm run build
lhci collect

- name: Evaluate reports
if: github.repository_owner != 'IntersectMBO'
run: |
lhci assert --preset "lighthouse:recommended"
lhci assert --preset "lighthouse:recommended"

- name: Publish reports
working-directory: ./govtool/frontend
if: github.repository_owner == 'IntersectMBO'
run: |
lhci assert --preset lighthouse:recommended || echo "LightHouse Assertion error ignored ..."
lhci upload --githubAppToken="${{ secrets.LHCI_GITHUB_APP_TOKEN }}" --token="${{ secrets.LHCI_SERVER_TOKEN }}" --serverBaseUrl=https://lighthouse.cardanoapi.io --ignoreDuplicateBuildFailure
curl -X POST https://ligththouse.cardanoapi.io/api/metrics/build-reports \
-d "@./lighthouseci/$(ls ./.lighthouseci |grep 'lhr.*\.json' | head -n 1)" \
-H "commit-hash: $(git rev-parse HEAD)" \
-H "secret-token: ${{ secrets.METRICS_SERVER_SECRET_TOKEN }}" \
-H 'Content-Type: application/json' || echo "Metric Upload error ignored ..."
lhci assert --preset lighthouse:recommended || echo "LightHouse Assertion error ignored ..."
lhci upload --githubAppToken="${{ secrets.LHCI_GITHUB_APP_TOKEN }}" --token="${{ secrets.LHCI_SERVER_TOKEN }}" --serverBaseUrl=https://lighthouse.cardanoapi.io --ignoreDuplicateBuildFailure
curl -X POST https://ligththouse.cardanoapi.io/api/metrics/build-reports \
-d "@./lighthouseci/$(ls ./.lighthouseci |grep 'lhr.*\.json' | head -n 1)" \
-H "commit-hash: $(git rev-parse HEAD)" \
-H "secret-token: ${{ secrets.METRICS_SERVER_SECRET_TOKEN }}" \
-H 'Content-Type: application/json' || echo "Metric Upload error ignored ..."
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ changes.

## [Unreleased]

- Integrate frontend with metadata validation service [Issue 617](https://github.com/IntersectMBO/govtool/issues/617)

### Added

- added `epochNo` and `date` to `drep/getVotes` and `proposal/get`
Expand Down
2 changes: 1 addition & 1 deletion govtool/frontend/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ build-frontend: docker-login
if [[ "$(cardano_network)" = "mainnet" ]]; then NETWORK_FLAG=1; else NETWORK_FLAG=0; fi; \
$(call check_image_on_ecr,frontend,$(frontend_image_tag)) || \
$(docker) build --tag "$(repo_url)/frontend:$(frontend_image_tag)" \
--build-arg VITE_BASE_URL="https://$(domain)/api" \
--build-arg VITE_BASE_URL="https://$(domain)" \
--build-arg VITE_GTM_ID="$${GTM_ID}" \
--build-arg VITE_NETWORK_FLAG="$$NETWORK_FLAG" \
--build-arg VITE_SENTRY_DSN="$${SENTRY_DSN}" \
Expand Down
10 changes: 5 additions & 5 deletions govtool/frontend/src/consts/externalDataModalConfig.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ModalState } from "@/context";
import I18n from "@/i18n";
import { MetadataValidationStatus } from "@/models";

export enum MetadataHashValidationErrors {
INVALID_URL = "Invalid URL",
Expand Down Expand Up @@ -29,13 +30,12 @@ const urlCannotBeFound = {
};

export const storageInformationErrorModals: Record<
MetadataHashValidationErrors,
MetadataValidationStatus,
ModalState<
typeof externalDataDoesntMatchModal | typeof urlCannotBeFound
>["state"]
> = {
[MetadataHashValidationErrors.INVALID_URL]: urlCannotBeFound,
[MetadataHashValidationErrors.FETCH_ERROR]: urlCannotBeFound,
[MetadataHashValidationErrors.INVALID_JSON]: externalDataDoesntMatchModal,
[MetadataHashValidationErrors.INVALID_HASH]: externalDataDoesntMatchModal,
[MetadataValidationStatus.URL_NOT_FOUND]: urlCannotBeFound,
[MetadataValidationStatus.INVALID_JSONLD]: externalDataDoesntMatchModal,
[MetadataValidationStatus.INVALID_HASH]: externalDataDoesntMatchModal,
};
4 changes: 4 additions & 0 deletions govtool/frontend/src/consts/queryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ export const QUERY_KEYS = {
useGetDRepInfoKey: "useGetDRepInfoKey",
useGetVoteContextFromFile: "useGetVoteContextFromFile",
};

export const MUTATION_KEYS = {
postValidateKey: "postValidateKey",
};
32 changes: 18 additions & 14 deletions govtool/frontend/src/hooks/forms/useCreateGovernanceActionForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,19 @@ import {
CIP_100,
CIP_108,
GOVERNANCE_ACTION_CONTEXT,
MetadataHashValidationErrors,
PATHS,
storageInformationErrorModals,
} from "@consts";
import { useCardano, useModal } from "@context";
import {
canonizeJSON,
downloadJson,
generateJsonld,
validateMetadataHash,
} from "@utils";
import { canonizeJSON, downloadJson, generateJsonld } from "@utils";
import { MetadataValidationStatus } from "@models";
import {
GovernanceActionFieldSchemas,
GovernanceActionType,
} from "@/types/governanceAction";

import { useValidateMutation } from "../mutations";

export type CreateGovernanceActionValues = {
links?: { link: string }[];
storeData?: boolean;
Expand All @@ -48,6 +45,7 @@ export const useCreateGovernanceActionForm = (
buildTreasuryGovernanceAction,
buildSignSubmitConwayCertTx,
} = useCardano();
const { validateMetadata } = useValidateMutation();
const { t } = useTranslation();
const [isLoading, setIsLoading] = useState<boolean>(false);
const [hash, setHash] = useState<string | null>(null);
Expand Down Expand Up @@ -120,22 +118,27 @@ export const useCreateGovernanceActionForm = (
}, [govActionType, json]);

const validateHash = useCallback(
async (storingUrl: string, localHash: string | null) => {
async (url: string, localHash: string | null) => {
try {
if (!localHash) {
throw new Error(MetadataHashValidationErrors.INVALID_HASH);
throw new Error(MetadataValidationStatus.INVALID_HASH);
}
await validateMetadataHash(storingUrl, localHash);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
const result = await validateMetadata({ url, hash: localHash });

if (result.status) {
throw result.status;
}
} catch (error) {
if (
Object.values(MetadataHashValidationErrors).includes(error.message)
Object.values(MetadataValidationStatus).includes(
error as MetadataValidationStatus,
)
) {
openModal({
type: "statusModal",
state: {
...storageInformationErrorModals[
error.message as MetadataHashValidationErrors
error as MetadataValidationStatus
],
onSubmit: backToForm,
onCancel: backToDashboard,
Expand Down Expand Up @@ -214,6 +217,7 @@ export const useCreateGovernanceActionForm = (
setIsLoading(true);

await validateHash(data.storingURL, hash);

const govActionBuilder = await buildTransaction(data);
await buildSignSubmitConwayCertTx({
govActionBuilder,
Expand Down
25 changes: 13 additions & 12 deletions govtool/frontend/src/hooks/forms/useEditDRepInfoForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@ import {
storageInformationErrorModals,
} from "@consts";
import { useCardano, useModal } from "@context";
import {
canonizeJSON,
downloadJson,
generateJsonld,
validateMetadataHash,
} from "@utils";
import { canonizeJSON, downloadJson, generateJsonld } from "@utils";
import { MetadataValidationStatus } from "@models";

import { useValidateMutation } from "../mutations";

export type EditDRepInfoValues = {
bio?: string;
Expand All @@ -43,6 +41,7 @@ export const defaultEditDRepInfoValues: EditDRepInfoValues = {
export const useEditDRepInfoForm = (
setStep?: Dispatch<SetStateAction<number>>,
) => {
const { validateMetadata } = useValidateMutation();
const { t } = useTranslation();
const navigate = useNavigate();
const [isLoading, setIsLoading] = useState<boolean>(false);
Expand Down Expand Up @@ -113,21 +112,23 @@ export const useEditDRepInfoForm = (
};

const validateHash = useCallback(
async (storingUrl: string) => {
async (url: string) => {
try {
if (!hash) throw new Error(MetadataHashValidationErrors.INVALID_HASH);

await validateMetadataHash(storingUrl, hash);
const result = await validateMetadata({ url, hash });

if (result.status) {
throw result.status;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
if (
Object.values(MetadataHashValidationErrors).includes(error.message)
) {
if (Object.values(MetadataValidationStatus).includes(error)) {
openModal({
type: "statusModal",
state: {
...storageInformationErrorModals[
error.message as MetadataHashValidationErrors
error as MetadataValidationStatus
],
onSubmit: backToForm,
onCancel: backToDashboard,
Expand Down
28 changes: 16 additions & 12 deletions govtool/frontend/src/hooks/forms/useRegisterAsdRepForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,15 @@ import {
CIP_100,
CIP_QQQ,
DREP_CONTEXT,
MetadataHashValidationErrors,
PATHS,
storageInformationErrorModals,
} from "@consts";
import { useCardano, useModal } from "@context";
import {
canonizeJSON,
downloadJson,
generateJsonld,
validateMetadataHash,
} from "@utils";
import { MetadataValidationStatus } from "@models";
import { canonizeJSON, downloadJson, generateJsonld } from "@utils";

import { useGetVoterInfo } from "..";
import { useValidateMutation } from "../mutations";

export type RegisterAsDRepValues = {
bio?: string;
Expand All @@ -44,6 +41,7 @@ export const defaultRegisterAsDRepValues: RegisterAsDRepValues = {
export const useRegisterAsdRepForm = (
setStep?: Dispatch<SetStateAction<number>>,
) => {
const { validateMetadata } = useValidateMutation();
const { t } = useTranslation();
const navigate = useNavigate();
const [isLoading, setIsLoading] = useState<boolean>(false);
Expand Down Expand Up @@ -116,21 +114,27 @@ export const useRegisterAsdRepForm = (
};

const validateHash = useCallback(
async (storingUrl: string) => {
async (url: string) => {
try {
if (!hash) throw new Error(MetadataHashValidationErrors.INVALID_HASH);
if (!hash) throw new Error(MetadataValidationStatus.INVALID_HASH);

await validateMetadataHash(storingUrl, hash);
const result = await validateMetadata({ url, hash });

if (result.status) {
throw result.status;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
if (
Object.values(MetadataHashValidationErrors).includes(error.message)
Object.values(MetadataValidationStatus).includes(
error as MetadataValidationStatus,
)
) {
openModal({
type: "statusModal",
state: {
...storageInformationErrorModals[
error.message as MetadataHashValidationErrors
error as MetadataValidationStatus
],
onSubmit: backToForm,
onCancel: backToDashboard,
Expand Down
34 changes: 15 additions & 19 deletions govtool/frontend/src/hooks/forms/useVoteContextForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,14 @@ import { Dispatch, SetStateAction, useCallback, useState } from "react";
import { NodeObject } from "jsonld";
import { useFormContext } from "react-hook-form";
import { blake2bHex } from "blakejs";

import {
CIP_108,
MetadataHashValidationErrors,
VOTE_TEST_CONTEXT,
} from "@consts";
import {
canonizeJSON,
downloadJson,
generateJsonld,
validateMetadataHash,
} from "@utils";
import { captureException } from "@sentry/react";

import { CIP_108, VOTE_TEST_CONTEXT } from "@consts";
import { canonizeJSON, downloadJson, generateJsonld } from "@utils";
import { MetadataValidationStatus } from "@models";

import { useValidateMutation } from "../mutations";

export type VoteContextFormValues = {
voteContextText: string;
terms?: boolean;
Expand All @@ -27,6 +21,7 @@ export const useVoteContextForm = (
setStep?: Dispatch<SetStateAction<number>>,
setErrorMessage?: Dispatch<SetStateAction<string | undefined>>,
) => {
const { validateMetadata } = useValidateMutation();
const [hash, setHash] = useState<string | null>(null);
const [json, setJson] = useState<NodeObject | null>(null);

Expand Down Expand Up @@ -71,18 +66,19 @@ export const useVoteContextForm = (
}, [json]);

const validateHash = useCallback(
async (storingUrl: string, localHash: string | null) => {
async (url: string, localHash: string | null) => {
try {
if (!localHash) {
throw new Error(MetadataHashValidationErrors.INVALID_HASH);
throw new Error(MetadataValidationStatus.INVALID_HASH);
}
const result = await validateMetadata({ url, hash: localHash });
if (result.status) {
throw result.status;
}
await validateMetadataHash(storingUrl, localHash);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
if (
Object.values(MetadataHashValidationErrors).includes(error.message)
) {
if (setErrorMessage) setErrorMessage(error.message);
if (Object.values(MetadataValidationStatus).includes(error)) {
if (setErrorMessage) setErrorMessage(error);
if (setStep) setStep(4);
}
throw error;
Expand Down
1 change: 1 addition & 0 deletions govtool/frontend/src/hooks/mutations/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./metadataValidation";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./useValidateMutation";
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useMutation } from "react-query";

import { postValidate } from "@services";
import { MUTATION_KEYS } from "@consts";
import { MetadataValidationDTO } from "@models";

export const useValidateMutation = () => {
const { data, isLoading, mutateAsync } = useMutation({
mutationFn: (body: MetadataValidationDTO) => postValidate(body),
mutationKey: [MUTATION_KEYS.postValidateKey],
});

return {
validateMetadata: mutateAsync,
validationStatus: data,
isValidating: isLoading,
};
};
1 change: 1 addition & 0 deletions govtool/frontend/src/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./api";
export * from "./snackbar";
export * from "./wallet";
export * from "./metadataValidation";
16 changes: 16 additions & 0 deletions govtool/frontend/src/models/metadataValidation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// TODO: Should be taken from @govtool/metadata-validation
export enum MetadataValidationStatus {
URL_NOT_FOUND = "URL_NOT_FOUND",
INVALID_JSONLD = "INVALID_JSONLD",
INVALID_HASH = "INVALID_HASH",
}

export type ValidateMetadataResult = {
status?: MetadataValidationStatus;
valid: boolean;
};

export type MetadataValidationDTO = {
url: string;
hash: string;
};
Loading
Loading