Browse Source

Many fixes -- especially and endorserServer

kb/add-usage-guide
Matthew Raymer 1 year ago
parent
commit
5501ac1a2f
  1. 47
      src/components/AlertMessage.vue
  2. 2
      src/components/EntityIcon.vue
  3. 79
      src/libs/endorserServer.ts
  4. 16
      src/views/AccountViewView.vue
  5. 18
      src/views/ContactAmountsView.vue
  6. 23
      src/views/ContactGiftingView.vue
  7. 9
      src/views/ContactQRScanShowView.vue
  8. 18
      src/views/ContactsView.vue
  9. 15
      src/views/DiscoverView.vue
  10. 23
      src/views/HomeView.vue
  11. 19
      src/views/IdentitySwitcherView.vue
  12. 21
      src/views/NewEditProjectView.vue
  13. 61
      src/views/ProjectViewView.vue
  14. 16
      src/views/ProjectsView.vue
  15. 21
      src/views/SeedBackupView.vue
  16. 16
      src/views/StatisticsView.vue
  17. 2
      tsconfig.json

47
src/components/AlertMessage.vue

@ -1,47 +0,0 @@
<template>
<div v-bind:class="computedAlertClassNames()">
<button
class="close-button bg-amber-400 w-8 leading-loose rounded-full absolute top-2 right-2"
@click="onClickClose()"
>
<fa icon="xmark"></fa>
</button>
<h4 class="font-bold pr-5">{{ alertTitle }}</h4>
<p>{{ alertMessage }}</p>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from "vue-facing-decorator";
@Component
export default class AlertMessage extends Vue {
@Prop alertTitle = "";
@Prop alertMessage = "";
isAlertVisible = this.alertMessage;
public onClickClose() {
this.isAlertVisible = false;
}
public computedAlertClassNames() {
return {
hidden: !this.isAlertVisible,
"dismissable-alert": true,
"bg-amber-200": true,
"p-5": true,
rounded: true,
"drop-shadow-lg": true,
fixed: true,
"top-3": true,
"inset-x-3": true,
"transition-transform": true,
"ease-in": true,
"duration-300": true,
};
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>

2
src/components/EntityIcon.vue

@ -8,7 +8,7 @@ import { toSvg } from "jdenticon";
@Component
export default class EntityIcon extends Vue {
@Prop entityId = "";
@Prop iconSize = "";
@Prop iconSize = 0;
generateIdenticon() {
const svgString = toSvg(this.entityId, this.iconSize);

79
src/libs/endorserServer.ts

@ -75,7 +75,7 @@ export interface InternalError {
// See https://github.com/trentlarson/endorser-ch/blob/0cb626f803028e7d9c67f095858a9fc8542e3dbd/server/api/services/util.js#L6
const HIDDEN_DID = "did:none:HIDDEN";
export function isHiddenDid(did) {
export function isHiddenDid(did: string) {
return did === HIDDEN_DID;
}
@ -88,7 +88,7 @@ export function didInfo(
allMyDids: Array<string>,
contacts: Array<Contact>,
): string {
const myId: string | undefined = R.find(R.equals(did), allMyDids, did);
const myId: string | undefined = R.find(R.equals(did), allMyDids);
if (myId) {
return "You" + (myId !== activeDid ? " (Alt ID)" : "");
} else {
@ -105,6 +105,18 @@ export function didInfo(
}
}
interface SuccessResult {
type: "success";
response: AxiosResponse<ClaimResult>;
}
interface ErrorResult {
type: "error";
error: InternalError;
}
type CreateAndSubmitGiveResult = SuccessResult | ErrorResult;
/**
* For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim
*
@ -123,7 +135,8 @@ export async function createAndSubmitGive(
description: string,
hours: number,
fulfillsProjectHandleId?: string,
): Promise<AxiosResponse<ClaimResult> | InternalError> {
): Promise<CreateAndSubmitGiveResult> {
try {
// Make a claim
const vcClaim: GiveVerifiableCredential = {
"@context": "https://schema.org",
@ -153,24 +166,30 @@ export async function createAndSubmitGive(
credentialSubject: vcClaim,
},
};
// Create a signature using private key of identity
if (identity.keys[0].privateKeyHex == null) {
return new Promise<InternalError>((resolve, reject) => {
reject({
const firstKey = identity.keys[0];
if (!firstKey || !firstKey.privateKeyHex) {
throw {
error: "No private key",
message:
"Your identifier " +
identity.did +
" is not configured correctly. Use a different identifier.",
});
});
message: `Your identifier ${identity.did} is not configured correctly. Use a different identifier.`,
};
}
const privateKeyHex = firstKey.privateKeyHex;
if (!privateKeyHex) {
throw {
error: "No private key",
message: `Your identifier ${identity.did} is not configured correctly. Use a different identifier.`,
};
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const privateKeyHex: string = identity.keys[0].privateKeyHex!;
const signer = await SimpleSigner(privateKeyHex);
const alg = undefined;
// Create a JWT for the request
const vcJwt: string = await didJwt.createJWT(vcPayload, {
alg: alg,
issuer: identity.did,
@ -187,7 +206,37 @@ export async function createAndSubmitGive(
Authorization: "Bearer " + token,
};
return axios.post(url, payload, { headers });
const response = await axios.post(url, payload, { headers });
return {
type: "success",
response,
};
} catch (error: unknown) {
let errorMessage: string;
if (error instanceof Error) {
// If it's a JavaScript Error object
errorMessage = error.message;
} else if (
typeof error === "object" &&
error !== null &&
"message" in error
) {
// If it's an object that has a 'message' property
errorMessage = (error as { message: string }).message;
} else {
// Unknown error shape, default message
errorMessage = "Unknown error";
}
return {
type: "error",
error: {
error: errorMessage,
userMessage: "Failed to create and submit the claim",
},
};
}
}
// from https://stackoverflow.com/a/175787/845494

16
src/views/AccountViewView.vue

@ -286,10 +286,6 @@
</button>
</div>
</div>
<AlertMessage
:alertTitle="alertTitle"
:alertMessage="alertMessage"
></AlertMessage>
</section>
</template>
@ -303,15 +299,23 @@ import { db, accountsDB } from "@/db";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto";
import { AxiosError } from "axios/index";
import AlertMessage from "@/components/AlertMessage";
import QuickNav from "@/components/QuickNav";
import { IIdentifier } from "@veramo/core";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Buffer = require("buffer/").Buffer;
@Component({ components: { AlertMessage, QuickNav } })
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({ components: { QuickNav } })
export default class AccountViewView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
Constants = AppString;
activeDid = "";

18
src/views/ContactAmountsView.vue

@ -90,10 +90,6 @@
</tr>
</tbody>
</table>
<AlertMessage
:alertTitle="alertTitle"
:alertMessage="alertMessage"
></AlertMessage>
</section>
</template>
@ -113,17 +109,23 @@ import {
} from "@/libs/endorserServer";
import * as didJwt from "did-jwt";
import { AxiosError } from "axios";
import AlertMessage from "@/components/AlertMessage";
import QuickNav from "@/components/QuickNav";
@Component({ components: { AlertMessage, QuickNav } })
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({ components: { QuickNav } })
export default class ContactsView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
activeDid = "";
apiServer = "";
contact: Contact | null = null;
giveRecords: Array<GiveServerRecord> = [];
alertTitle = "";
alertMessage = "";
numAccounts = 0;
async beforeCreate() {

23
src/views/ContactGiftingView.vue

@ -76,10 +76,6 @@
message="Received from"
>
</GiftedDialog>
<AlertMessage
:alertTitle="alertTitle"
:alertMessage="alertMessage"
></AlertMessage>
</section>
</template>
@ -93,21 +89,27 @@ import { accessToken } from "@/libs/crypto";
import { createAndSubmitGive } from "@/libs/endorserServer";
import { Account } from "@/db/tables/accounts";
import { Contact } from "@/db/tables/contacts";
import AlertMessage from "@/components/AlertMessage";
import QuickNav from "@/components/QuickNav";
import EntityIcon from "@/components/EntityIcon";
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({
components: { GiftedDialog, AlertMessage, QuickNav, EntityIcon },
components: { GiftedDialog, QuickNav, EntityIcon },
})
export default class HomeView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
activeDid = "";
allAccounts: Array<Account> = [];
allContacts: Array<Contact> = [];
apiServer = "";
isHiddenSpinner = true;
alertTitle = "";
alertMessage = "";
accounts: AccountsSchema;
numAccounts = 0;
@ -289,11 +291,6 @@ export default class HomeView extends Vue {
}
}
private setAlert(title, message) {
this.alertTitle = title;
this.alertMessage = message;
}
// Helper functions for readability
isGiveCreationError(result) {

9
src/views/ContactQRScanShowView.vue

@ -34,6 +34,13 @@ import { Account } from "@/db/tables/accounts";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Buffer = require("buffer/").Buffer;
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({
components: {
QRCodeVue3,
@ -41,6 +48,8 @@ const Buffer = require("buffer/").Buffer;
},
})
export default class ContactQRScanShow extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
activeDid = "";
apiServer = "";
qrValue = "";

18
src/views/ContactsView.vue

@ -202,10 +202,6 @@
</li>
</ul>
<p v-else>This identity has no contacts.</p>
<AlertMessage
:alertTitle="alertTitle"
:alertMessage="alertMessage"
></AlertMessage>
</section>
</template>
@ -224,17 +220,25 @@ import {
SERVICE_ID,
} from "@/libs/endorserServer";
import { Component, Vue } from "vue-facing-decorator";
import AlertMessage from "@/components/AlertMessage";
import QuickNav from "@/components/QuickNav";
import EntityIcon from "@/components/EntityIcon";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Buffer = require("buffer/").Buffer;
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({
components: { AlertMessage, QuickNav, EntityIcon },
components: { QuickNav, EntityIcon },
})
export default class ContactsView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
activeDid = "";
apiServer = "";
contacts: Array<Contact> = [];
@ -256,8 +260,6 @@ export default class ContactsView extends Vue {
showGiveNumbers = false;
showGiveTotals = true;
showGiveConfirmed = true;
alertTitle = "";
alertMessage = "";
async created() {
await db.open();

15
src/views/DiscoverView.vue

@ -181,8 +181,6 @@
/>
</l-map>
</div>
<AlertMessage :alertTitle="alertTitle" :alertMessage="alertMessage" />
</section>
</template>
@ -201,7 +199,6 @@ import { Contact } from "@/db/tables/contacts";
import { BoundingBox, MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto";
import { didInfo, ProjectData } from "@/libs/endorserServer";
import AlertMessage from "@/components/AlertMessage";
import QuickNav from "@/components/QuickNav";
import InfiniteScroll from "@/components/InfiniteScroll";
import EntityIcon from "@/components/EntityIcon";
@ -210,10 +207,16 @@ const DEFAULT_LAT_LONG_DIFF = 0.01;
const WORLD_ZOOM = 2;
const DEFAULT_ZOOM = 2;
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({
components: {
LRectangle,
AlertMessage,
QuickNav,
InfiniteScroll,
EntityIcon,
@ -223,13 +226,13 @@ const DEFAULT_ZOOM = 2;
},
})
export default class DiscoverView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
activeDid = "";
allContacts: Array<Contact> = [];
allMyDids: Array<string> = [];
apiServer = "";
searchTerms = "";
alertMessage = "";
alertTitle = "";
projects: ProjectData[] = [];
isChoosingSearchBox = false;
isLocalActive = true;

23
src/views/HomeView.vue

@ -196,10 +196,6 @@
</li>
</ul>
</div>
<AlertMessage
:alertTitle="alertTitle"
:alertMessage="alertMessage"
></AlertMessage>
</section>
</template>
@ -211,14 +207,22 @@ import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto";
import { createAndSubmitGive, didInfo } from "@/libs/endorserServer";
import { Contact } from "@/db/tables/contacts";
import AlertMessage from "@/components/AlertMessage";
import QuickNav from "@/components/QuickNav";
import EntityIcon from "@/components/EntityIcon";
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({
components: { GiftedDialog, AlertMessage, QuickNav, EntityIcon },
components: { GiftedDialog, QuickNav, EntityIcon },
})
export default class HomeView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
activeDid = "";
allContacts: Array<Contact> = [];
allMyDids: Array<string> = [];
@ -228,8 +232,6 @@ export default class HomeView extends Vue {
feedPreviousOldestId = null;
feedLastViewedId = null;
isHiddenSpinner = true;
alertTitle = "";
alertMessage = "";
numAccounts = 0;
async beforeCreate() {
@ -509,11 +511,6 @@ export default class HomeView extends Vue {
}
}
private setAlert(title, message) {
this.alertTitle = title;
this.alertMessage = message;
}
// Helper functions for readability
isGiveCreationError(result) {

19
src/views/IdentitySwitcherView.vue

@ -62,11 +62,6 @@
>
No Identity
</a>
<AlertMessage
:alertTitle="alertTitle"
:alertMessage="alertMessage"
></AlertMessage>
</section>
</template>
<script lang="ts">
@ -75,18 +70,24 @@ import { AppString } from "@/constants/app";
import { db, accountsDB } from "@/db";
import { AccountsSchema } from "@/db/tables/accounts";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import AlertMessage from "@/components/AlertMessage";
import QuickNav from "@/components/QuickNav";
@Component({ components: { AlertMessage, QuickNav } })
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({ components: { QuickNav } })
export default class IdentitySwitcherView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
Constants = AppString;
public accounts: AccountsSchema;
public activeDid;
public firstName;
public lastName;
public alertTitle;
public alertMessage;
public otherIdentities = [];
public async getIdentity(activeDid) {

21
src/views/NewEditProjectView.vue

@ -97,10 +97,6 @@
Cancel
</button>
</div>
<AlertMessage
:alertTitle="alertTitle"
:alertMessage="alertMessage"
></AlertMessage>
</section>
</template>
@ -116,15 +112,21 @@ import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken, SimpleSigner } from "@/libs/crypto";
import { useAppStore } from "@/store/app";
import { IIdentifier } from "@veramo/core";
import AlertMessage from "@/components/AlertMessage";
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({
components: { AlertMessage, LMap, LMarker, LTileLayer },
components: { LMap, LMarker, LTileLayer },
})
export default class NewEditProjectView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
activeDid = "";
alertTitle = "";
alertMessage = "";
apiServer = "";
description = "";
errorMessage = "";
@ -270,8 +272,7 @@ export default class NewEditProjectView extends Vue {
// version shows up here: https://api.endorser.ch/api-docs/
if (resp.data?.success?.handleId || resp.data?.success?.fullIri) {
this.errorMessage = "";
this.alertTitle = "";
this.alertMessage = "";
// handleId is new in server v release-1.6.0; remove fullIri when that
// version shows up here: https://api.endorser.ch/api-docs/
useAppStore().setProjectId(

61
src/views/ProjectViewView.vue

@ -200,10 +200,6 @@
message="Received from"
>
</GiftedDialog>
<AlertMessage
:alertTitle="alertTitle"
:alertMessage="alertMessage"
></AlertMessage>
</section>
</template>
@ -226,10 +222,19 @@ import {
import QuickNav from "@/components/QuickNav";
import EntityIcon from "@/components/EntityIcon";
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({
components: { GiftedDialog, QuickNav, EntityIcon },
})
export default class ProjectViewView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
activeDid = "";
allMyDids: Array<string> = [];
allContacts: Array<Contact> = [];
@ -339,7 +344,7 @@ export default class ProjectViewView extends Vue {
this.longitude = resp.data.claim?.location?.geo?.longitude || 0;
} else if (resp.status === 404) {
// actually, axios throws an error so we never get here
(this as any).$notify(
this.$notify(
{
group: "alert",
type: "danger",
@ -352,7 +357,7 @@ export default class ProjectViewView extends Vue {
} catch (error: unknown) {
const serverError = error as AxiosError;
if (serverError.response?.status === 404) {
(this as any).$notify(
this.$notify(
{
group: "alert",
type: "danger",
@ -362,7 +367,7 @@ export default class ProjectViewView extends Vue {
-1,
);
} else {
(this as any).$notify(
this.$notify(
{
group: "alert",
type: "danger",
@ -384,7 +389,7 @@ export default class ProjectViewView extends Vue {
if (resp.status === 200 && resp.data.data) {
this.givesToThis = resp.data.data;
} else {
(this as any).$notify(
this.$notify(
{
group: "alert",
type: "danger",
@ -396,7 +401,7 @@ export default class ProjectViewView extends Vue {
}
} catch (error: unknown) {
const serverError = error as AxiosError;
(this as any).$notify(
this.$notify(
{
group: "alert",
type: "danger",
@ -420,7 +425,7 @@ export default class ProjectViewView extends Vue {
if (resp.status === 200 && resp.data.data) {
this.givesByThis = resp.data.data;
} else {
(this as any).$notify(
this.$notify(
{
group: "alert",
type: "danger",
@ -432,7 +437,7 @@ export default class ProjectViewView extends Vue {
}
} catch (error: unknown) {
const serverError = error as AxiosError;
(this as any).$notify(
this.$notify(
{
group: "alert",
type: "danger",
@ -485,7 +490,7 @@ export default class ProjectViewView extends Vue {
*/
async recordGive(giverDid, description: string, hours: number) {
if (!this.activeDid) {
(this as any).$notify(
this.$notify(
{
group: "alert",
type: "danger",
@ -498,7 +503,7 @@ export default class ProjectViewView extends Vue {
}
if (!description && !hours) {
(this as any).$notify(
this.$notify(
{
group: "alert",
type: "danger",
@ -507,10 +512,7 @@ export default class ProjectViewView extends Vue {
},
-1,
);
return;
}
try {
} else {
const identity = await this.getIdentity(this.activeDid);
const result = await createAndSubmitGive(
this.axios,
@ -522,10 +524,10 @@ export default class ProjectViewView extends Vue {
hours,
this.projectId,
);
if (result.status !== 201 || result.data?.error) {
if (result.type == "success") {
console.log("Error with give result:", result);
(this as any).$notify(
if ("data" in result) {
this.$notify(
{
group: "alert",
type: "danger",
@ -536,8 +538,9 @@ export default class ProjectViewView extends Vue {
},
-1,
);
} else {
(this as any).$notify(
}
} else if (result.type == "error") {
this.$notify(
{
group: "alert",
type: "success",
@ -547,20 +550,6 @@ export default class ProjectViewView extends Vue {
-1,
);
}
} catch (e) {
console.log("Error with give caught:", e);
(this as any).$notify(
{
group: "alert",
type: "danger",
title: "Error",
text:
e?.userMessage ||
e?.response?.data?.error?.message ||
"There was an error recording the give.",
},
-1,
);
}
}
}

16
src/views/ProjectsView.vue

@ -67,10 +67,6 @@
</li>
</ul>
</InfiniteScroll>
<AlertMessage
:alertTitle="alertTitle"
:alertMessage="alertMessage"
></AlertMessage>
</section>
</template>
@ -81,14 +77,22 @@ import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto";
import { IIdentifier } from "@veramo/core";
import InfiniteScroll from "@/components/InfiniteScroll";
import AlertMessage from "@/components/AlertMessage";
import QuickNav from "@/components/QuickNav";
import EntityIcon from "@/components/EntityIcon";
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({
components: { InfiniteScroll, AlertMessage, QuickNav, EntityIcon },
components: { InfiniteScroll, QuickNav, EntityIcon },
})
export default class ProjectsView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
apiServer = "";
projects: ProjectData[] = [];
current: IIdentifier;

21
src/views/SeedBackupView.vue

@ -50,10 +50,6 @@
</div>
</div>
<div v-else>You do not have an active identity.</div>
<AlertMessage
:alertTitle="alertTitle"
:alertMessage="alertMessage"
></AlertMessage>
</section>
</template>
@ -64,9 +60,22 @@ import * as R from "ramda";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import QuickNav from "@/components/QuickNav.vue";
interface Account {
mnemonic: string;
}
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({ components: { QuickNav } })
export default class SeedBackupView extends Vue {
activeAccount = null;
$notify!: (notification: Notification, timeout?: number) => void;
activeAccount: Account | null | undefined = null;
numAccounts = 0;
showSeed = false;
@ -83,7 +92,7 @@ export default class SeedBackupView extends Vue {
this.activeAccount = R.find((acc) => acc.did === activeDid, accounts);
} catch (err: unknown) {
console.error("Got an error loading an identity:", err);
(this as any).$notify(
this.$notify(
{
group: "alert",
type: "danger",

16
src/views/StatisticsView.vue

@ -39,7 +39,7 @@
<script lang="ts">
import { SVGRenderer } from "three/addons/renderers/SVGRenderer.js";
import { Component, Vue } from "vue-facing-decorator";
import { World } from "components/World/World.js";
import { World } from "@/components/World/World.js";
import QuickNav from "@/components/QuickNav.vue";
interface RendererSVGType {
@ -50,8 +50,17 @@ interface Dictionary<T> {
[key: string]: T;
}
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({ components: { World, QuickNav } })
export default class StatisticsView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
world: World;
worldProperties: Dictionary<number> = {};
@ -61,9 +70,9 @@ export default class StatisticsView extends Vue {
const newWorld = new World(container, this);
newWorld.start();
this.world = newWorld;
} catch (err : unknown) {
} catch (err: unknown) {
const error = err as Error;
(this as any).$notify(
this.$notify(
{
group: "alert",
type: "danger",
@ -91,7 +100,6 @@ export default class StatisticsView extends Vue {
}
}
function ExportToSVG(rendererSVG: RendererSVGType, filename: string) {
const XMLS = new XMLSerializer();
const svgfile = XMLS.serializeToString(rendererSVG.domElement);

2
tsconfig.json

@ -1,8 +1,10 @@
{
"compilerOptions": {
"allowJs": true,
"target": "esnext",
"module": "esnext",
"strict": true,
"strictPropertyInitialization": false,
"jsx": "preserve",
"moduleResolution": "node",
"experimentalDecorators": true,

Loading…
Cancel
Save