progress on reputation service
This commit is contained in:
parent
da892c0221
commit
667ed43792
|
@ -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()}`);
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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--;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
export class ReputationService {
|
||||
|
||||
}
|
|
@ -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; }
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue