You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
236 lines
7.2 KiB
236 lines
7.2 KiB
<template>
|
|
<QuickNav />
|
|
<!-- CONTENT -->
|
|
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
|
|
<!-- Breadcrumb -->
|
|
<div id="ViewBreadcrumb" class="mb-8">
|
|
<h1 class="text-lg text-center font-light relative px-7">
|
|
<!-- Back -->
|
|
<button
|
|
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
|
|
@click="$router.back()"
|
|
>
|
|
<font-awesome icon="chevron-left" class="fa-fw" />
|
|
</button>
|
|
Raw Claim
|
|
</h1>
|
|
</div>
|
|
|
|
<div class="flex">
|
|
<textarea v-model="claimStr" rows="20" class="border-2 w-full"></textarea>
|
|
</div>
|
|
<button
|
|
class="block w-full text-center text-lg font-bold uppercase bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-3 rounded-md"
|
|
@click="submitClaim()"
|
|
>
|
|
Sign & Send
|
|
</button>
|
|
</section>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { Component, Vue } from "vue-facing-decorator";
|
|
import { AxiosResponse } from "axios";
|
|
|
|
import QuickNav from "../components/QuickNav.vue";
|
|
import { NotificationIface } from "../constants/app";
|
|
import * as serverUtil from "../libs/endorserServer";
|
|
import * as libsUtil from "../libs/util";
|
|
import { errorStringForLog } from "../libs/endorserServer";
|
|
import { Router, RouteLocationNormalizedLoaded } from "vue-router";
|
|
import { logger } from "../utils/logger";
|
|
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
|
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
|
|
|
|
// Type guard for API responses
|
|
function isApiResponse(response: unknown): response is AxiosResponse {
|
|
return (
|
|
typeof response === "object" &&
|
|
response !== null &&
|
|
"status" in response &&
|
|
"data" in response
|
|
);
|
|
}
|
|
|
|
// TODO: Testing Required - Database Operations + Logging Migration to PlatformServiceMixin
|
|
// Priority: High | Migrated: 2025-07-06 | Author: Matthew Raymer
|
|
//
|
|
// MIGRATION DETAILS: Migrated from legacy database utilities + logging to PlatformServiceMixin
|
|
// - Replaced legacy logging calls with this.$logAndConsole()
|
|
// - Replaced legacy settings retrieval with this.$accountSettings()
|
|
// - Removed legacy database and logging imports
|
|
//
|
|
// TESTING NEEDED: Raw claim editor functionality
|
|
// 1. Test basic page load: /claim-add-raw (JSON editor displays)
|
|
// 2. Test with sample JSON: /claim-add-raw?claim={"type":"example","data":"test"}
|
|
// 3. Test JSON validation (valid/invalid JSON handling)
|
|
// 4. Test claim submission functionality
|
|
// 5. Test error scenarios: network failure, invalid JSON, server errors
|
|
// 6. Verify error logging appears in console and database
|
|
// 7. Cross-platform testing: web, mobile, desktop
|
|
//
|
|
// Test URLs:
|
|
// /claim-add-raw (basic editor)
|
|
// /claim-add-raw?claim={"type":"test","data":"sample"}
|
|
|
|
/**
|
|
* View component for adding or editing raw claim data
|
|
* Allows direct JSON editing of claim data with validation and submission
|
|
*/
|
|
@Component({
|
|
components: { QuickNav },
|
|
mixins: [PlatformServiceMixin],
|
|
})
|
|
export default class ClaimAddRawView extends Vue {
|
|
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
|
$route!: RouteLocationNormalizedLoaded;
|
|
$router!: Router;
|
|
|
|
notify!: ReturnType<typeof createNotifyHelpers>;
|
|
accountIdentityStr: string = "null";
|
|
activeDid = "";
|
|
apiServer = "";
|
|
claimStr = "";
|
|
|
|
/**
|
|
* Lifecycle hook that initializes the view
|
|
* Workflow:
|
|
* 1. Retrieves active DID and API server from settings
|
|
* 2. Checks for existing claim data from query params:
|
|
* - If "claim" param exists: Parses and formats JSON
|
|
* - If "claimJwtId" param exists: Fetches claim data from API
|
|
* 3. Populates textarea with formatted claim data
|
|
*/
|
|
async mounted() {
|
|
this.notify = createNotifyHelpers(this.$notify);
|
|
|
|
await this.initializeSettings();
|
|
await this.loadClaimData();
|
|
}
|
|
|
|
/**
|
|
* Initialize settings from active account
|
|
*/
|
|
private async initializeSettings() {
|
|
const settings = await this.$accountSettings();
|
|
this.activeDid = settings.activeDid || "";
|
|
this.apiServer = settings.apiServer || "";
|
|
}
|
|
|
|
/**
|
|
* Load claim data from query parameters or API
|
|
*/
|
|
private async loadClaimData() {
|
|
// Try loading from direct claim parameter
|
|
if (await this.loadClaimFromQueryParam()) return;
|
|
|
|
// Try loading from claim JWT ID
|
|
await this.loadClaimFromJwtId();
|
|
}
|
|
|
|
/**
|
|
* Attempt to load claim from query parameter
|
|
* @returns true if claim was loaded successfully
|
|
*/
|
|
private async loadClaimFromQueryParam(): Promise<boolean> {
|
|
this.claimStr = (this.$route.query["claim"] as string) || "";
|
|
if (!this.claimStr) return false;
|
|
|
|
try {
|
|
const veriClaim = JSON.parse(this.claimStr);
|
|
this.claimStr = JSON.stringify(veriClaim, null, 2);
|
|
return true;
|
|
} catch (e) {
|
|
// ignore parse error
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load claim data from JWT ID via API
|
|
*/
|
|
private async loadClaimFromJwtId() {
|
|
const claimJwtId = (this.$route.query["claimJwtId"] as string) || "";
|
|
if (!claimJwtId) return;
|
|
|
|
const urlPath = libsUtil.isGlobalUri(claimJwtId)
|
|
? "/api/claim/byHandle/"
|
|
: "/api/claim/";
|
|
const url = this.apiServer + urlPath + encodeURIComponent(claimJwtId);
|
|
|
|
try {
|
|
const response = await this.fetchClaimData(url);
|
|
this.formatClaimResponse(response, claimJwtId);
|
|
} catch (error: unknown) {
|
|
this.handleClaimError(error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch claim data from API
|
|
*/
|
|
private async fetchClaimData(url: string) {
|
|
const headers = await serverUtil.getHeaders(this.activeDid);
|
|
return await this.axios.get(url, { headers });
|
|
}
|
|
|
|
/**
|
|
* Format successful claim response data
|
|
*/
|
|
private formatClaimResponse(response: unknown, claimJwtId: string) {
|
|
if (isApiResponse(response) && response.status === 200) {
|
|
const claim = response.data?.claim;
|
|
claim.lastClaimId = serverUtil.stripEndorserPrefix(claimJwtId);
|
|
this.claimStr = JSON.stringify(claim, null, 2);
|
|
} else {
|
|
throw {
|
|
message: "Got an error loading that claim.",
|
|
response: isApiResponse(response)
|
|
? {
|
|
status: response.status,
|
|
statusText: response.statusText,
|
|
}
|
|
: { status: 0, statusText: "Unknown response type" },
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle error loading claim data
|
|
*/
|
|
private handleClaimError(error: unknown) {
|
|
this.$logAndConsole(
|
|
"Error retrieving claim: " + errorStringForLog(error),
|
|
true,
|
|
);
|
|
this.notify.error("Got an error retrieving claim data.", TIMEOUTS.STANDARD);
|
|
}
|
|
|
|
/**
|
|
* Submits the edited claim data
|
|
* Workflow:
|
|
* 1. Parses JSON from textarea
|
|
* 2. Sends to server via createAndSubmitClaim
|
|
* 3. Shows success/error notification
|
|
* @throws Will show error notification if submission fails
|
|
*/
|
|
async submitClaim() {
|
|
const fullClaim = JSON.parse(this.claimStr);
|
|
const result = await serverUtil.createAndSubmitClaim(
|
|
fullClaim,
|
|
this.activeDid,
|
|
this.apiServer,
|
|
this.axios,
|
|
);
|
|
if (result.success) {
|
|
this.notify.success("Claim submitted.", TIMEOUTS.LONG);
|
|
} else {
|
|
logger.error("Got error submitting the claim:", result);
|
|
this.notify.error(
|
|
"There was a problem submitting the claim.",
|
|
TIMEOUTS.LONG,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|