progress on reputation service

This commit is contained in:
Chegele 2023-06-27 17:13:32 -04:00
parent da892c0221
commit 667ed43792
7 changed files with 330 additions and 0 deletions

View File

@ -0,0 +1,32 @@
import { randomUUID } from "crypto";
import { Vertex } from "./vertex";
export class Edge {
private id: string;
private category: string;
private directional: boolean;
private parentVertex: Vertex;
private childVertex: Vertex;
constructor(id: null | string, parent: Vertex, child: Vertex, category = "generic", directional = false) {
this.id ? id : randomUUID();
this.parentVertex = parent;
this.childVertex = child;
this.category = category;
this.directional = directional;
}
public getId() { return this.id; }
public getCategory() { return this.category; }
public getDirectional() { return this.directional; }
public getParentVertex() { return this.parentVertex; }
public getChildVertex() { return this.childVertex; }
public getAdjacent(vertex: Vertex) {
if (vertex == this.childVertex) return this.parentVertex;
else if (vertex == this.parentVertex) return this.childVertex;
else throw new Error(`Edge ${this.id} is not connected to vertex ${vertex.getId()}`);
}
}

View File

@ -0,0 +1,55 @@
import { Edge } from "./edge";
import { Vertex } from "./vertex";
export class Graph {
private vertices: Map<string, Vertex>;
private edges: Map<string, Edge>;
constructor(vertices: Vertex[] = [], edges: Edge[] = []) {
this.vertices = new Map();
this.edges = new Map();
vertices.forEach(this.addVertex);
edges.forEach(this.addEdge);
}
public getAllVertices() {
return Array.from(this.vertices.values());
}
public getVertex(id: string) {
return this.vertices.get(id);
}
public addVertex(vertex: Vertex) {
this.vertices.set(vertex.getId(), vertex);
}
public deleteVertex(vertex: string | Vertex) {
if (vertex instanceof Vertex) vertex = vertex.getId();
this.vertices.delete(vertex);
}
public getAllEdges() {
return Array.from(this.edges.values());
}
public getEdge(id: string) {
return this.edges.get(id);
}
public addEdge(edge: Edge) {
edge.getParentVertex().addEdge(edge);
edge.getChildVertex().addEdge(edge);
this.edges.set(edge.getId(), edge);
}
public deleteEdge(edge: string | Edge) {
if (typeof edge == "string") edge = this.edges.get(edge);
if (!edge) throw new Error(`Failed to identify edge with an ID of ${edge.getId()}.`);
edge.getParentVertex().removeEdge(edge);
edge.getChildVertex().removeEdge(edge);
this.edges.delete(edge.getId());
}
}

View File

@ -0,0 +1,39 @@
import { randomUUID } from "crypto";
import { Edge } from "./edge";
export class Vertex {
private id: string
private degree: number;
private edges: Edge[];
private data: any;
constructor(id: null | string, data: any, edges: Edge[] = []) {
this.id = id ? id : randomUUID();
this.data = data;
this.degree = edges.length;
this.edges = edges;
}
public getId() { return this.id; }
public getDegree() { return this.degree; }
public getEdges() { return this.edges; }
public getData() { return this.data; }
public updateData(data: any) {
this.data = data;
}
public addEdge(edge: Edge) {
this.edges.push(edge);
this.degree++;
}
public removeEdge(edge: Edge) {
const index = this.edges.indexOf(edge);
if (index == -1) throw new Error(`Unable to identify edge ${edge.getId()} from vertex ${this.id}.`);
this.edges.splice(index, 1);
this.degree--;
}
}

View File

@ -0,0 +1,4 @@
export class ReputationService {
}

View File

@ -0,0 +1,23 @@
import { Post } from "./post";
export class Citation {
private sourcePost: Post;
private citedPost: Post;
private impact: number
constructor(source: Post, cited:Post, impact: number) {
this.sourcePost = source;
this.citedPost = cited;
this.impact = impact;
}
public getSourcePost() { return this.sourcePost; }
public getCitedPost() { return this.citedPost; }
public getImpact() { return this.impact; }
public isNeutral() { return this.impact == 0; }
public isNegative() { return this.impact < 0; }
public isPositive() { return this.impact > 0; }
}

View File

@ -0,0 +1,65 @@
import { randomUUID } from "crypto";
export interface LedgerEntry {
timestamp: number,
type: ('post' | 'citation'),
postId: string,
citationId: string | null,
change: number,
balance: number
}
export class Member {
static localStore: Map<string, Member>;
private id: string;
private reputation: number;
private ledger: LedgerEntry[];
constructor(id?: string) {
this.id = id ? id : randomUUID();
this.reputation = 0;
this.ledger = [];
Member.localStore.set(this.id, this);
}
public static getAllMembers() {
return Array.from(Member.localStore.values());
}
public static getMember(id: string) {
return Member.localStore.get(id);
}
public getId() { return this.id; }
public getReputation() { return this.reputation; }
public getLedger() { return this.ledger; }
public postReputation(postId: string, amount: number) {
const entry: LedgerEntry = {
timestamp: Date.now(),
type: "post",
postId: postId,
citationId: null,
change: amount,
balance: this.reputation + amount
}
this.reputation = entry.balance;
return entry;
}
public citationReputation(postId: string, citationId: string, amount: number) {
const entry: LedgerEntry = {
timestamp: Date.now(),
type: "citation",
postId: postId,
citationId: citationId,
change: amount,
balance: this.reputation + amount
}
this.reputation = entry.balance;
return entry;
}
}

View File

@ -0,0 +1,112 @@
import { Citation } from "./citation";
import { Member } from "./member";
export interface AuthorWeight {
weight: number;
author: Member
}
export interface CitationWeight {
weight: number;
citation: Citation;
}
export class Post {
private static DEFAULT_WEIGHT = 1000;
private title: string;
private content: string;
private authors: AuthorWeight[];
private citations: CitationWeight[];
private authorsWeightTotal: number;
private citationsWeightTotal: number;
constructor (title: string, content: string, authors: Member | Member[]) {
this.title = title;
this.content = content;
this.authors = [];
this.citations = [];
this.authorsWeightTotal = 0;
this.citationsWeightTotal = 0;
if (!Array.isArray(authors)) authors = [authors];
for (const author of <Member[]> authors) {
this.authorsWeightTotal += Post.DEFAULT_WEIGHT;
this.authors.push({
weight: Post.DEFAULT_WEIGHT,
author: author
});
}
}
public static serialize(post: Post, pretty: boolean = true) {
//TODO: Need to convert citations and authors to IDs.
if (!pretty) return JSON.stringify(Post);
return JSON.stringify(Post, undefined, 2);
}
public static parse(serializedPost: string) {
//TODO: Need to retrieve citations and authors from IDs.
try {
const parsed = JSON.parse(serializedPost);
const title = <string> parsed?.title;
const content = <string> parsed.content;
const authors = <AuthorWeight[]> parsed.authors;
const citations = <CitationWeight[]> parsed.citations;
const post = new Post(title, content, authors[0].author);
for (const author of authors) post.setAuthor(author.author, author.weight);
for (const citation of citations) post.setCitation(citation.citation, citation.weight);
return post;
} catch(err) {
throw new Error("Failed to parse the serialized post. \n - " + err.message);
}
}
public getTitle() { return this.title; }
public getContent() { return this.content; }
public getAuthors() { return this.authors.map(({author}) => author); }
public getCitations() { return this.citations.map(({citation}) => citation); }
public getAuthorsWeightTotal() { return this.authorsWeightTotal; }
public getCitationWeightTotal() { return this.citationsWeightTotal; }
public setAuthor(author: Member, weight: number = Post.DEFAULT_WEIGHT) {
this.removeAuthor(author);
this.authors.push({author, weight});
this.authorsWeightTotal += weight;
}
public removeAuthor(author: Member) {
const index = this.getAuthors().indexOf(author);
if (index != -1) {
const current = this.authors[index];
this.authorsWeightTotal -= current.weight;
this.authors.splice(index, 1);
}
}
public setCitation(citation: Citation, weight: number = Post.DEFAULT_WEIGHT) {
this.removeCitation(citation);
this.citations.push({citation, weight});
this.citationsWeightTotal += weight;
}
public removeCitation(citation: Citation) {
const index = this.getCitations().indexOf(citation);
if (index != -1) {
const current = this.citations[index];
this.citationsWeightTotal -= current.weight;
this.citations.splice(index, 1);
}
}
public getWeight(weighted: Member | Citation) {
const forAuthor = weighted instanceof Member;
const arr = forAuthor ? this.authors : this.citations;
const key = forAuthor ? "author" : "citation";
const index = arr.findIndex(item => item[key] == weighted);
if (index == -1) return -1;
return arr[index].weight;
}
}