refactor(types): ape keys types

move to shared types (#4774)
add types to ape client (#4786)
This commit is contained in:
Miodec 2024-02-07 23:13:10 +01:00
parent efb972a659
commit 4f5f28a92d
9 changed files with 62 additions and 55 deletions

View file

@ -7,7 +7,7 @@ import { MonkeyResponse } from "../../utils/monkey-response";
import { base64UrlEncode } from "../../utils/misc";
import { ObjectId } from "mongodb";
function cleanApeKey(apeKey: MonkeyTypes.ApeKey): Partial<MonkeyTypes.ApeKey> {
function cleanApeKey(apeKey: MonkeyTypes.ApeKeyDB): SharedTypes.ApeKey {
return _.omit(apeKey, "hash", "_id", "uid", "useCount");
}
@ -39,7 +39,7 @@ export async function generateApeKey(
const apiKey = randomBytes(apeKeyBytes).toString("base64url");
const saltyHash = await hash(apiKey, apeKeySaltRounds);
const apeKey: MonkeyTypes.ApeKey = {
const apeKey: MonkeyTypes.ApeKeyDB = {
_id: new ObjectId(),
name,
enabled,

View file

@ -1,33 +1,36 @@
import _ from "lodash";
import * as db from "../init/db";
import { Filter, ObjectId, MatchKeysAndValues } from "mongodb";
import {
Filter,
ObjectId,
MatchKeysAndValues,
Collection,
WithId,
} from "mongodb";
import MonkeyError from "../utils/error";
const COLLECTION_NAME = "ape-keys";
export const getApeKeysCollection = (): Collection<
WithId<MonkeyTypes.ApeKeyDB>
> => db.collection<MonkeyTypes.ApeKeyDB>("ape-keys");
function getApeKeyFilter(
uid: string,
keyId: string
): Filter<MonkeyTypes.ApeKey> {
): Filter<MonkeyTypes.ApeKeyDB> {
return {
_id: new ObjectId(keyId),
uid,
};
}
export async function getApeKeys(uid: string): Promise<MonkeyTypes.ApeKey[]> {
return await db
.collection<MonkeyTypes.ApeKey>(COLLECTION_NAME)
.find({ uid })
.toArray();
export async function getApeKeys(uid: string): Promise<MonkeyTypes.ApeKeyDB[]> {
return await getApeKeysCollection().find({ uid }).toArray();
}
export async function getApeKey(
keyId: string
): Promise<MonkeyTypes.ApeKey | null> {
return await db
.collection<MonkeyTypes.ApeKey>(COLLECTION_NAME)
.findOne({ _id: new ObjectId(keyId) });
): Promise<MonkeyTypes.ApeKeyDB | null> {
return await getApeKeysCollection().findOne({ _id: new ObjectId(keyId) });
}
export async function countApeKeysForUser(uid: string): Promise<number> {
@ -35,24 +38,23 @@ export async function countApeKeysForUser(uid: string): Promise<number> {
return _.size(apeKeys);
}
export async function addApeKey(apeKey: MonkeyTypes.ApeKey): Promise<string> {
const insertionResult = await db
.collection<MonkeyTypes.ApeKey>(COLLECTION_NAME)
.insertOne(apeKey);
export async function addApeKey(apeKey: MonkeyTypes.ApeKeyDB): Promise<string> {
const insertionResult = await getApeKeysCollection().insertOne(apeKey);
return insertionResult.insertedId.toHexString();
}
async function updateApeKey(
uid: string,
keyId: string,
updates: MatchKeysAndValues<MonkeyTypes.ApeKey>
updates: MatchKeysAndValues<MonkeyTypes.ApeKeyDB>
): Promise<void> {
const updateResult = await db
.collection<MonkeyTypes.ApeKey>(COLLECTION_NAME)
.updateOne(getApeKeyFilter(uid, keyId), {
const updateResult = await getApeKeysCollection().updateOne(
getApeKeyFilter(uid, keyId),
{
$inc: { useCount: _.has(updates, "lastUsedOn") ? 1 : 0 },
$set: _.pickBy(updates, (value) => !_.isNil(value)),
});
}
);
if (updateResult.modifiedCount === 0) {
throw new MonkeyError(404, "ApeKey not found");
@ -86,9 +88,9 @@ export async function updateLastUsedOn(
}
export async function deleteApeKey(uid: string, keyId: string): Promise<void> {
const deletionResult = await db
.collection<MonkeyTypes.ApeKey>(COLLECTION_NAME)
.deleteOne(getApeKeyFilter(uid, keyId));
const deletionResult = await getApeKeysCollection().deleteOne(
getApeKeyFilter(uid, keyId)
);
if (deletionResult.deletedCount === 0) {
throw new MonkeyError(404, "ApeKey not found");
@ -96,5 +98,5 @@ export async function deleteApeKey(uid: string, keyId: string): Promise<void> {
}
export async function deleteAllApeKeys(uid: string): Promise<void> {
await db.collection<MonkeyTypes.ApeKey>(COLLECTION_NAME).deleteMany({ uid });
await getApeKeysCollection().deleteMany({ uid });
}

View file

@ -163,17 +163,12 @@ declare namespace MonkeyTypes {
colors: string[];
}
interface ApeKey {
type ApeKeyDB = SharedTypes.ApeKey & {
_id: ObjectId;
uid: string;
name: string;
hash: string;
createdOn: number;
modifiedOn: number;
lastUsedOn: number;
useCount: number;
enabled: boolean;
}
};
interface NewQuote {
_id: ObjectId;

View file

@ -5,11 +5,14 @@ export default class ApeKeys {
this.httpClient = httpClient;
}
async get(): Ape.EndpointResponse {
async get(): Ape.EndpointResponse<ApeKeysApe.GetApeKeys> {
return await this.httpClient.get(BASE_PATH);
}
async generate(name: string, enabled: boolean): Ape.EndpointResponse {
async generate(
name: string,
enabled: boolean
): Ape.EndpointResponse<ApeKeysApe.GenerateApeKey> {
const payload = { name, enabled };
return await this.httpClient.post(BASE_PATH, { payload });
}
@ -17,12 +20,12 @@ export default class ApeKeys {
async update(
apeKeyId: string,
updates: { name?: string; enabled?: boolean }
): Ape.EndpointResponse {
): Ape.EndpointResponse<null> {
const payload = { ...updates };
return await this.httpClient.patch(`${BASE_PATH}/${apeKeyId}`, { payload });
}
async delete(apeKeyId: string): Ape.EndpointResponse {
async delete(apeKeyId: string): Ape.EndpointResponse<null> {
return await this.httpClient.delete(`${BASE_PATH}/${apeKeyId}`);
}
}

View file

@ -0,0 +1,9 @@
declare namespace ApeKeysApe {
type GetApeKeys = Record<string, SharedTypes.ApeKey>;
type GenerateApeKey = {
apeKey: string;
apeKeyId: string;
apeKeyDetails: SharedTypes.ApeKey;
};
}

View file

@ -6,7 +6,7 @@ import * as ConnectionState from "../states/connection";
import * as Skeleton from "./skeleton";
import { isPopupVisible } from "../utils/misc";
let apeKeys: MonkeyTypes.ApeKeys = {};
let apeKeys: ApeKeysApe.GetApeKeys | null = {};
const wrapperId = "apeKeysPopupWrapper";
@ -20,12 +20,12 @@ async function getData(): Promise<void> {
return undefined;
}
apeKeys = response.data as MonkeyTypes.ApeKeys;
apeKeys = response.data;
}
function refreshList(): void {
const data = apeKeys;
if (data === undefined) return;
if (data === undefined || data === null) return;
const table = $("#apeKeysPopupWrapper table tbody");
table.empty();
const apeKeyIds = Object.keys(data);
@ -36,7 +36,7 @@ function refreshList(): void {
return;
}
apeKeyIds.forEach((apeKeyId) => {
const key = data[apeKeyId] as MonkeyTypes.ApeKey;
const key = data[apeKeyId] as SharedTypes.ApeKey;
table.append(`
<tr keyId="${apeKeyId}">
<td>

View file

@ -1316,7 +1316,8 @@ list["generateApeKey"] = new SimplePopup(
};
}
const data = response.data;
//if response is 200 data is guaranteed to not be null
const data = response.data as ApeKeysApe.GenerateApeKey;
return {
status: 1,

View file

@ -318,18 +318,6 @@ declare namespace MonkeyTypes {
completedTests: number;
}
interface ApeKey {
name: string;
enabled: boolean;
createdOn: number;
modifiedOn: number;
lastUsedOn: number;
}
interface ApeKeys {
[key: string]: ApeKey;
}
interface Config {
theme: string;
themeLight: string;

View file

@ -330,10 +330,19 @@ declare namespace SharedTypes {
interface SpeedHistogram {
[key: string]: number;
}
interface PublicTypingStats {
type: string;
timeTyping: number;
testsCompleted: number;
testsStarted: number;
}
interface ApeKey {
name: string;
enabled: boolean;
createdOn: number;
modifiedOn: number;
lastUsedOn: number;
}
}