import * as mangrove from "mangrove-reviews" import { UIEventSource } from "../UIEventSource" import { Review } from "./Review" import { Utils } from "../../Utils" export class MangroveIdentity { public keypair: any = undefined public readonly kid: UIEventSource = new UIEventSource(undefined) private readonly _mangroveIdentity: UIEventSource constructor(mangroveIdentity: UIEventSource) { const self = this this._mangroveIdentity = mangroveIdentity mangroveIdentity.addCallbackAndRunD((str) => { if (str === "") { return } mangrove.jwkToKeypair(JSON.parse(str)).then((keypair) => { self.keypair = keypair mangrove.publicToPem(keypair.publicKey).then((pem) => { console.log("Identity loaded") self.kid.setData(pem) }) }) }) try { if (!Utils.runningFromConsole && (mangroveIdentity.data ?? "") === "") { this.CreateIdentity() } } catch (e) { console.error("Could not create identity: ", e) } } /** * Creates an identity if none exists already. * Is written into the UIEventsource, which was passed into the constructor * @constructor */ private CreateIdentity() { if ("" !== (this._mangroveIdentity.data ?? "")) { throw "Identity already defined - not creating a new one" } const self = this mangrove.generateKeypair().then((keypair) => { self.keypair = keypair mangrove.keypairToJwk(keypair).then((jwk) => { self._mangroveIdentity.setData(JSON.stringify(jwk)) }) }) } } export default class MangroveReviews { private static _reviewsCache = {} private static didWarn = false private readonly _lon: number private readonly _lat: number private readonly _name: string private readonly _reviews: UIEventSource = new UIEventSource([]) private _dryRun: boolean private _mangroveIdentity: MangroveIdentity private _lastUpdate: Date = undefined private constructor( lon: number, lat: number, name: string, identity: MangroveIdentity, dryRun?: boolean ) { this._lon = lon this._lat = lat this._name = name this._mangroveIdentity = identity this._dryRun = dryRun if (dryRun && !MangroveReviews.didWarn) { MangroveReviews.didWarn = true console.warn("Mangrove reviews will _not_ be saved as dryrun is specified") } } public static Get( lon: number, lat: number, name: string, identity: MangroveIdentity, dryRun?: boolean ) { const newReviews = new MangroveReviews(lon, lat, name, identity, dryRun) const uri = newReviews.GetSubjectUri() const cached = MangroveReviews._reviewsCache[uri] if (cached !== undefined) { return cached } MangroveReviews._reviewsCache[uri] = newReviews return newReviews } /** * Gets an URI which represents the item in a mangrove-compatible way * @constructor */ public GetSubjectUri() { let uri = `geo:${this._lat},${this._lon}?u=50` if (this._name !== undefined && this._name !== null) { uri += "&q=" + this._name } return uri } /** * Gives a UIEVentsource with all reviews. * Note: rating is between 1 and 100 */ public GetReviews(): UIEventSource { if ( this._lastUpdate !== undefined && this._reviews.data !== undefined && new Date().getTime() - this._lastUpdate.getTime() < 15000 ) { // Last update was pretty recent return this._reviews } this._lastUpdate = new Date() const self = this mangrove .getReviews({ sub: this.GetSubjectUri() }) .then((data) => { const reviews = [] const reviewsByUser = [] for (const review of data.reviews) { const r = review.payload console.log( "PublicKey is ", self._mangroveIdentity.kid.data, "reviews.kid is", review.kid ) const byUser = self._mangroveIdentity.kid.map( (data) => data === review.signature ) const rev: Review = { made_by_user: byUser, date: new Date(r.iat * 1000), comment: r.opinion, author: r.metadata.nickname, affiliated: r.metadata.is_affiliated, rating: r.rating, // percentage points } ;(rev.made_by_user ? reviewsByUser : reviews).push(rev) } self._reviews.setData(reviewsByUser.concat(reviews)) }) .catch((e) => { console.error("Could not download review for ", e) }) return this._reviews } AddReview(r: Review, callback?: () => void) { callback = callback ?? (() => { return undefined }) const payload = { sub: this.GetSubjectUri(), rating: r.rating, opinion: r.comment, metadata: { nickname: r.author, }, } if (r.affiliated) { // @ts-ignore payload.metadata.is_affiliated = true } if (this._dryRun) { console.warn("DRYRUNNING mangrove reviews: ", payload) if (callback) { if (callback) { callback() } this._reviews.data.push(r) this._reviews.ping() } } else { mangrove.signAndSubmitReview(this._mangroveIdentity.keypair, payload).then(() => { if (callback) { callback() } this._reviews.data.push(r) this._reviews.ping() }) } } }